enhance sessions history filters and subagent steer lifecycle

This commit is contained in:
DBT
2026-02-23 13:20:09 +00:00
parent 5f8678f091
commit 68afec08d0
3 changed files with 63 additions and 25 deletions

View File

@@ -36,9 +36,10 @@ func (t *SessionsTool) Parameters() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"type": "object", "type": "object",
"properties": map[string]interface{}{ "properties": map[string]interface{}{
"action": map[string]interface{}{"type": "string", "description": "list|history"}, "action": map[string]interface{}{"type": "string", "description": "list|history"},
"key": map[string]interface{}{"type": "string", "description": "session key for history"}, "key": map[string]interface{}{"type": "string", "description": "session key for history"},
"limit": map[string]interface{}{"type": "integer", "description": "max items", "default": 20}, "limit": map[string]interface{}{"type": "integer", "description": "max items", "default": 20},
"include_tools": map[string]interface{}{"type": "boolean", "description": "include tool role messages in history", "default": false},
}, },
"required": []string{"action"}, "required": []string{"action"},
} }
@@ -52,6 +53,10 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
if v, ok := args["limit"].(float64); ok && int(v) > 0 { if v, ok := args["limit"].(float64); ok && int(v) > 0 {
limit = int(v) limit = int(v)
} }
includeTools := false
if v, ok := args["include_tools"].(bool); ok {
includeTools = v
}
switch action { switch action {
case "list": case "list":
@@ -78,10 +83,23 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
if key == "" { if key == "" {
return "key is required for history", nil return "key is required for history", nil
} }
h := t.historyFn(key, limit) h := t.historyFn(key, limit*3)
if len(h) == 0 { if len(h) == 0 {
return "No history.", nil return "No history.", nil
} }
if !includeTools {
filtered := make([]providers.Message, 0, len(h))
for _, m := range h {
if strings.TrimSpace(strings.ToLower(m.Role)) == "tool" {
continue
}
filtered = append(filtered, m)
}
h = filtered
}
if len(h) == 0 {
return "No history (after filters).", nil
}
if len(h) > limit { if len(h) > limit {
h = h[len(h)-limit:] h = h[len(h)-limit:]
} }

View File

@@ -29,26 +29,28 @@ type SubagentTask struct {
} }
type SubagentManager struct { type SubagentManager struct {
tasks map[string]*SubagentTask tasks map[string]*SubagentTask
cancelFuncs map[string]context.CancelFunc cancelFuncs map[string]context.CancelFunc
mu sync.RWMutex archiveAfterMinute int64
provider providers.LLMProvider mu sync.RWMutex
bus *bus.MessageBus provider providers.LLMProvider
orc *Orchestrator bus *bus.MessageBus
workspace string orc *Orchestrator
nextID int workspace string
runFunc SubagentRunFunc nextID int
runFunc SubagentRunFunc
} }
func NewSubagentManager(provider providers.LLMProvider, workspace string, bus *bus.MessageBus, orc *Orchestrator) *SubagentManager { func NewSubagentManager(provider providers.LLMProvider, workspace string, bus *bus.MessageBus, orc *Orchestrator) *SubagentManager {
return &SubagentManager{ return &SubagentManager{
tasks: make(map[string]*SubagentTask), tasks: make(map[string]*SubagentTask),
cancelFuncs: make(map[string]context.CancelFunc), cancelFuncs: make(map[string]context.CancelFunc),
provider: provider, archiveAfterMinute: 60,
bus: bus, provider: provider,
orc: orc, bus: bus,
workspace: workspace, orc: orc,
nextID: 1, workspace: workspace,
nextID: 1,
} }
} }
@@ -198,15 +200,17 @@ func (sm *SubagentManager) SetRunFunc(f SubagentRunFunc) {
} }
func (sm *SubagentManager) GetTask(taskID string) (*SubagentTask, bool) { func (sm *SubagentManager) GetTask(taskID string) (*SubagentTask, bool) {
sm.mu.RLock() sm.mu.Lock()
defer sm.mu.RUnlock() defer sm.mu.Unlock()
sm.pruneArchivedLocked()
task, ok := sm.tasks[taskID] task, ok := sm.tasks[taskID]
return task, ok return task, ok
} }
func (sm *SubagentManager) ListTasks() []*SubagentTask { func (sm *SubagentManager) ListTasks() []*SubagentTask {
sm.mu.RLock() sm.mu.Lock()
defer sm.mu.RUnlock() defer sm.mu.Unlock()
sm.pruneArchivedLocked()
tasks := make([]*SubagentTask, 0, len(sm.tasks)) tasks := make([]*SubagentTask, 0, len(sm.tasks))
for _, task := range sm.tasks { for _, task := range sm.tasks {
@@ -248,3 +252,19 @@ func (sm *SubagentManager) SteerTask(taskID, message string) bool {
t.Updated = time.Now().UnixMilli() t.Updated = time.Now().UnixMilli()
return true return true
} }
func (sm *SubagentManager) pruneArchivedLocked() {
if sm.archiveAfterMinute <= 0 {
return
}
cutoff := time.Now().Add(-time.Duration(sm.archiveAfterMinute) * time.Minute).UnixMilli()
for id, t := range sm.tasks {
if t.Status == "running" {
continue
}
if t.Updated > 0 && t.Updated < cutoff {
delete(sm.tasks, id)
delete(sm.cancelFuncs, id)
}
}
}

View File

@@ -64,7 +64,7 @@ func (t *SubagentsTool) Execute(ctx context.Context, args map[string]interface{}
if !ok { if !ok {
return "subagent not found", nil return "subagent not found", nil
} }
return fmt.Sprintf("ID: %s\nStatus: %s\nLabel: %s\nTask: %s\nResult:\n%s", task.ID, task.Status, task.Label, task.Task, task.Result), nil return fmt.Sprintf("ID: %s\nStatus: %s\nLabel: %s\nCreated: %d\nUpdated: %d\nSteering Count: %d\nTask: %s\nResult:\n%s", task.ID, task.Status, task.Label, task.Created, task.Updated, len(task.Steering), task.Task, task.Result), nil
case "kill": case "kill":
if id == "" { if id == "" {
return "id is required for kill", nil return "id is required for kill", nil