add subagent index selectors and session active filters

This commit is contained in:
DBT
2026-02-23 13:45:02 +00:00
parent c86e314d7f
commit f252afab64
3 changed files with 121 additions and 19 deletions

View File

@@ -36,11 +36,12 @@ 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},
"kinds": map[string]interface{}{"type": "array", "items": map[string]interface{}{"type": "string"}, "description": "optional session kinds filter for list"},
"include_tools": map[string]interface{}{"type": "boolean", "description": "include tool role messages in history", "default": false},
"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},
"active_minutes": map[string]interface{}{"type": "integer", "description": "only sessions updated in recent N minutes (list action)"},
"kinds": map[string]interface{}{"type": "array", "items": map[string]interface{}{"type": "string"}, "description": "optional session kinds filter for list"},
"include_tools": map[string]interface{}{"type": "boolean", "description": "include tool role messages in history", "default": false},
},
"required": []string{"action"},
}
@@ -58,6 +59,10 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
if v, ok := args["include_tools"].(bool); ok {
includeTools = v
}
activeMinutes := 0
if v, ok := args["active_minutes"].(float64); ok && int(v) > 0 {
activeMinutes = int(v)
}
kindFilter := map[string]struct{}{}
if rawKinds, ok := args["kinds"].([]interface{}); ok {
for _, it := range rawKinds {
@@ -89,6 +94,16 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
}
items = filtered
}
if activeMinutes > 0 {
cutoff := time.Now().Add(-time.Duration(activeMinutes) * time.Minute)
filtered := make([]SessionInfo, 0, len(items))
for _, s := range items {
if s.UpdatedAt.After(cutoff) {
filtered = append(filtered, s)
}
}
items = filtered
}
if len(items) == 0 {
return "No sessions (after filters).", nil
}

View File

@@ -3,6 +3,8 @@ package tools
import (
"context"
"fmt"
"sort"
"strconv"
"strings"
)
@@ -52,40 +54,48 @@ func (t *SubagentsTool) Execute(ctx context.Context, args map[string]interface{}
}
var sb strings.Builder
sb.WriteString("Subagents:\n")
for _, task := range tasks {
sb.WriteString(fmt.Sprintf("- %s [%s] label=%s\n", task.ID, task.Status, task.Label))
sort.Slice(tasks, func(i, j int) bool { return tasks[i].Created > tasks[j].Created })
for i, task := range tasks {
sb.WriteString(fmt.Sprintf("- #%d %s [%s] label=%s\n", i+1, task.ID, task.Status, task.Label))
}
return strings.TrimSpace(sb.String()), nil
case "info":
if id == "" {
return "id is required for info", nil
resolvedID, err := t.resolveTaskID(id)
if err != nil {
return err.Error(), nil
}
task, ok := t.manager.GetTask(id)
task, ok := t.manager.GetTask(resolvedID)
if !ok {
return "subagent not found", 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
resolvedID, err := t.resolveTaskID(id)
if err != nil {
return err.Error(), nil
}
if !t.manager.KillTask(id) {
if !t.manager.KillTask(resolvedID) {
return "subagent not found", nil
}
return "subagent kill requested", nil
case "steer", "send":
if id == "" || message == "" {
return "id and message are required for steer/send", nil
if message == "" {
return "message is required for steer/send", nil
}
if !t.manager.SteerTask(id, message) {
resolvedID, err := t.resolveTaskID(id)
if err != nil {
return err.Error(), nil
}
if !t.manager.SteerTask(resolvedID, message) {
return "subagent not found", nil
}
return "steering message accepted", nil
case "log":
if id == "" {
return "id is required for log", nil
resolvedID, err := t.resolveTaskID(id)
if err != nil {
return err.Error(), nil
}
task, ok := t.manager.GetTask(id)
task, ok := t.manager.GetTask(resolvedID)
if !ok {
return "subagent not found", nil
}
@@ -110,3 +120,26 @@ func (t *SubagentsTool) Execute(ctx context.Context, args map[string]interface{}
return "unsupported action", nil
}
}
func (t *SubagentsTool) resolveTaskID(idOrIndex string) (string, error) {
idOrIndex = strings.TrimSpace(idOrIndex)
if idOrIndex == "" {
return "", fmt.Errorf("id is required")
}
if strings.HasPrefix(idOrIndex, "#") {
n, err := strconv.Atoi(strings.TrimPrefix(idOrIndex, "#"))
if err != nil || n <= 0 {
return "", fmt.Errorf("invalid subagent index")
}
tasks := t.manager.ListTasks()
if len(tasks) == 0 {
return "", fmt.Errorf("no subagents")
}
sort.Slice(tasks, func(i, j int) bool { return tasks[i].Created > tasks[j].Created })
if n > len(tasks) {
return "", fmt.Errorf("subagent index out of range")
}
return tasks[n-1].ID, nil
}
return idOrIndex, nil
}