mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-19 02:37:29 +08:00
add query/history window filters and subagent summary controls
This commit is contained in:
@@ -41,6 +41,7 @@ func (t *SessionsTool) Parameters() map[string]interface{} {
|
|||||||
"limit": map[string]interface{}{"type": "integer", "description": "max items", "default": 20},
|
"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)"},
|
"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"},
|
"kinds": map[string]interface{}{"type": "array", "items": map[string]interface{}{"type": "string"}, "description": "optional session kinds filter for list"},
|
||||||
|
"query": map[string]interface{}{"type": "string", "description": "optional text query for list or history"},
|
||||||
"include_tools": map[string]interface{}{"type": "boolean", "description": "include tool role messages in history", "default": false},
|
"include_tools": map[string]interface{}{"type": "boolean", "description": "include tool role messages in history", "default": false},
|
||||||
"around": map[string]interface{}{"type": "integer", "description": "1-indexed message index center for history window"},
|
"around": map[string]interface{}{"type": "integer", "description": "1-indexed message index center for history window"},
|
||||||
"before": map[string]interface{}{"type": "integer", "description": "1-indexed message index upper bound (exclusive)"},
|
"before": map[string]interface{}{"type": "integer", "description": "1-indexed message index upper bound (exclusive)"},
|
||||||
@@ -78,6 +79,8 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
|
|||||||
if v, ok := args["active_minutes"].(float64); ok && int(v) > 0 {
|
if v, ok := args["active_minutes"].(float64); ok && int(v) > 0 {
|
||||||
activeMinutes = int(v)
|
activeMinutes = int(v)
|
||||||
}
|
}
|
||||||
|
query, _ := args["query"].(string)
|
||||||
|
query = strings.ToLower(strings.TrimSpace(query))
|
||||||
kindFilter := map[string]struct{}{}
|
kindFilter := map[string]struct{}{}
|
||||||
if rawKinds, ok := args["kinds"].([]interface{}); ok {
|
if rawKinds, ok := args["kinds"].([]interface{}); ok {
|
||||||
for _, it := range rawKinds {
|
for _, it := range rawKinds {
|
||||||
@@ -119,6 +122,16 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
|
|||||||
}
|
}
|
||||||
items = filtered
|
items = filtered
|
||||||
}
|
}
|
||||||
|
if query != "" {
|
||||||
|
filtered := make([]SessionInfo, 0, len(items))
|
||||||
|
for _, s := range items {
|
||||||
|
blob := strings.ToLower(strings.TrimSpace(s.Key + "\n" + s.Kind + "\n" + s.Summary))
|
||||||
|
if strings.Contains(blob, query) {
|
||||||
|
filtered = append(filtered, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items = filtered
|
||||||
|
}
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
return "No sessions (after filters).", nil
|
return "No sessions (after filters).", nil
|
||||||
}
|
}
|
||||||
@@ -202,6 +215,16 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
|
|||||||
}
|
}
|
||||||
h = filtered
|
h = filtered
|
||||||
}
|
}
|
||||||
|
if query != "" {
|
||||||
|
filtered := make([]providers.Message, 0, len(h))
|
||||||
|
for _, m := range h {
|
||||||
|
blob := strings.ToLower(strings.TrimSpace(m.Role + "\n" + m.Content))
|
||||||
|
if strings.Contains(blob, query) {
|
||||||
|
filtered = append(filtered, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h = filtered
|
||||||
|
}
|
||||||
if len(h) == 0 {
|
if len(h) == 0 {
|
||||||
return "No history (after filters).", nil
|
return "No history (after filters).", nil
|
||||||
}
|
}
|
||||||
|
|||||||
52
pkg/tools/sessions_tool_test.go
Normal file
52
pkg/tools/sessions_tool_test.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"clawgo/pkg/providers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSessionsToolListWithKindsAndQuery(t *testing.T) {
|
||||||
|
tool := NewSessionsTool(func(limit int) []SessionInfo {
|
||||||
|
return []SessionInfo{
|
||||||
|
{Key: "telegram:1", Kind: "main", Summary: "project alpha", UpdatedAt: time.Now()},
|
||||||
|
{Key: "cron:1", Kind: "cron", Summary: "nightly sync", UpdatedAt: time.Now()},
|
||||||
|
}
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
out, err := tool.Execute(context.Background(), map[string]interface{}{
|
||||||
|
"action": "list",
|
||||||
|
"kinds": []interface{}{"main"},
|
||||||
|
"query": "alpha",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(out, "telegram:1") || strings.Contains(out, "cron:1") {
|
||||||
|
t.Fatalf("unexpected output: %s", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSessionsToolHistoryWithoutTools(t *testing.T) {
|
||||||
|
tool := NewSessionsTool(nil, func(key string, limit int) []providers.Message {
|
||||||
|
return []providers.Message{
|
||||||
|
{Role: "user", Content: "hello"},
|
||||||
|
{Role: "tool", Content: "tool output"},
|
||||||
|
{Role: "assistant", Content: "ok"},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
out, err := tool.Execute(context.Background(), map[string]interface{}{
|
||||||
|
"action": "history",
|
||||||
|
"key": "telegram:1",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.ToLower(out), "tool output") {
|
||||||
|
t.Fatalf("tool message should be filtered: %s", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,19 @@ func (t *SubagentsTool) Execute(ctx context.Context, args map[string]interface{}
|
|||||||
}
|
}
|
||||||
return strings.TrimSpace(sb.String()), nil
|
return strings.TrimSpace(sb.String()), nil
|
||||||
case "info":
|
case "info":
|
||||||
|
if strings.EqualFold(strings.TrimSpace(id), "all") {
|
||||||
|
tasks := t.manager.ListTasks()
|
||||||
|
if len(tasks) == 0 {
|
||||||
|
return "No subagents.", nil
|
||||||
|
}
|
||||||
|
sort.Slice(tasks, func(i, j int) bool { return tasks[i].Created > tasks[j].Created })
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("Subagents Summary:\n")
|
||||||
|
for i, task := range tasks {
|
||||||
|
sb.WriteString(fmt.Sprintf("- #%d %s [%s] label=%s steering=%d\n", i+1, task.ID, task.Status, task.Label, len(task.Steering)))
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(sb.String()), nil
|
||||||
|
}
|
||||||
resolvedID, err := t.resolveTaskID(id)
|
resolvedID, err := t.resolveTaskID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Error(), nil
|
return err.Error(), nil
|
||||||
|
|||||||
22
pkg/tools/subagents_tool_test.go
Normal file
22
pkg/tools/subagents_tool_test.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSubagentsInfoAll(t *testing.T) {
|
||||||
|
m := NewSubagentManager(nil, ".", nil, nil)
|
||||||
|
m.tasks["subagent-1"] = &SubagentTask{ID: "subagent-1", Status: "completed", Label: "a", Created: 2}
|
||||||
|
m.tasks["subagent-2"] = &SubagentTask{ID: "subagent-2", Status: "running", Label: "b", Created: 3}
|
||||||
|
|
||||||
|
tool := NewSubagentsTool(m)
|
||||||
|
out, err := tool.Execute(context.Background(), map[string]interface{}{"action": "info", "id": "all"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(out, "Subagents Summary") || !strings.Contains(out, "subagent-2") {
|
||||||
|
t.Fatalf("unexpected output: %s", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user