diff --git a/pkg/tools/sessions_tool.go b/pkg/tools/sessions_tool.go index 1caf8d1..e4ef767 100644 --- a/pkg/tools/sessions_tool.go +++ b/pkg/tools/sessions_tool.go @@ -36,9 +36,10 @@ func (t *SessionsTool) Parameters() map[string]interface{} { return map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ - "action": map[string]interface{}{"type": "string", "description": "list|history"}, - "key": map[string]interface{}{"type": "string", "description": "session key for history"}, - "limit": map[string]interface{}{"type": "integer", "description": "max items", "default": 20}, + "action": map[string]interface{}{"type": "string", "description": "list|history"}, + "key": map[string]interface{}{"type": "string", "description": "session key for history"}, + "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"}, } @@ -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 { limit = int(v) } + includeTools := false + if v, ok := args["include_tools"].(bool); ok { + includeTools = v + } switch action { case "list": @@ -78,10 +83,23 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{}) if key == "" { return "key is required for history", nil } - h := t.historyFn(key, limit) + h := t.historyFn(key, limit*3) if len(h) == 0 { 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 { h = h[len(h)-limit:] } diff --git a/pkg/tools/subagent.go b/pkg/tools/subagent.go index f29c81e..bc401e4 100644 --- a/pkg/tools/subagent.go +++ b/pkg/tools/subagent.go @@ -29,26 +29,28 @@ type SubagentTask struct { } type SubagentManager struct { - tasks map[string]*SubagentTask - cancelFuncs map[string]context.CancelFunc - mu sync.RWMutex - provider providers.LLMProvider - bus *bus.MessageBus - orc *Orchestrator - workspace string - nextID int - runFunc SubagentRunFunc + tasks map[string]*SubagentTask + cancelFuncs map[string]context.CancelFunc + archiveAfterMinute int64 + mu sync.RWMutex + provider providers.LLMProvider + bus *bus.MessageBus + orc *Orchestrator + workspace string + nextID int + runFunc SubagentRunFunc } func NewSubagentManager(provider providers.LLMProvider, workspace string, bus *bus.MessageBus, orc *Orchestrator) *SubagentManager { return &SubagentManager{ - tasks: make(map[string]*SubagentTask), - cancelFuncs: make(map[string]context.CancelFunc), - provider: provider, - bus: bus, - orc: orc, - workspace: workspace, - nextID: 1, + tasks: make(map[string]*SubagentTask), + cancelFuncs: make(map[string]context.CancelFunc), + archiveAfterMinute: 60, + provider: provider, + bus: bus, + orc: orc, + workspace: workspace, + nextID: 1, } } @@ -198,15 +200,17 @@ func (sm *SubagentManager) SetRunFunc(f SubagentRunFunc) { } func (sm *SubagentManager) GetTask(taskID string) (*SubagentTask, bool) { - sm.mu.RLock() - defer sm.mu.RUnlock() + sm.mu.Lock() + defer sm.mu.Unlock() + sm.pruneArchivedLocked() task, ok := sm.tasks[taskID] return task, ok } func (sm *SubagentManager) ListTasks() []*SubagentTask { - sm.mu.RLock() - defer sm.mu.RUnlock() + sm.mu.Lock() + defer sm.mu.Unlock() + sm.pruneArchivedLocked() tasks := make([]*SubagentTask, 0, len(sm.tasks)) for _, task := range sm.tasks { @@ -248,3 +252,19 @@ func (sm *SubagentManager) SteerTask(taskID, message string) bool { t.Updated = time.Now().UnixMilli() 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) + } + } +} diff --git a/pkg/tools/subagents_tool.go b/pkg/tools/subagents_tool.go index b18debc..0359766 100644 --- a/pkg/tools/subagents_tool.go +++ b/pkg/tools/subagents_tool.go @@ -64,7 +64,7 @@ func (t *SubagentsTool) Execute(ctx context.Context, args map[string]interface{} if !ok { 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": if id == "" { return "id is required for kill", nil