mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-18 03:37:33 +08:00
add advanced session/subagent filters and trigger error summaries
This commit is contained in:
@@ -164,10 +164,18 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
|
||||
if key == "" {
|
||||
return "key is required for history", nil
|
||||
}
|
||||
h := t.historyFn(key, 0)
|
||||
if len(h) == 0 {
|
||||
raw := t.historyFn(key, 0)
|
||||
if len(raw) == 0 {
|
||||
return "No history.", nil
|
||||
}
|
||||
type indexedMsg struct {
|
||||
idx int
|
||||
msg providers.Message
|
||||
}
|
||||
window := make([]indexedMsg, 0, len(raw))
|
||||
for i, m := range raw {
|
||||
window = append(window, indexedMsg{idx: i + 1, msg: m})
|
||||
}
|
||||
|
||||
// Window selectors are 1-indexed (human-friendly)
|
||||
if around > 0 {
|
||||
@@ -175,8 +183,8 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
|
||||
if center < 0 {
|
||||
center = 0
|
||||
}
|
||||
if center >= len(h) {
|
||||
center = len(h) - 1
|
||||
if center >= len(window) {
|
||||
center = len(window) - 1
|
||||
}
|
||||
half := limit / 2
|
||||
if half < 1 {
|
||||
@@ -187,17 +195,17 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
|
||||
start = 0
|
||||
}
|
||||
end := center + half + 1
|
||||
if end > len(h) {
|
||||
end = len(h)
|
||||
if end > len(window) {
|
||||
end = len(window)
|
||||
}
|
||||
h = h[start:end]
|
||||
window = window[start:end]
|
||||
} else {
|
||||
start := 0
|
||||
end := len(h)
|
||||
end := len(window)
|
||||
if after > 0 {
|
||||
start = after
|
||||
if start > len(h) {
|
||||
start = len(h)
|
||||
if start > len(window) {
|
||||
start = len(window)
|
||||
}
|
||||
}
|
||||
if before > 0 {
|
||||
@@ -205,72 +213,72 @@ func (t *SessionsTool) Execute(ctx context.Context, args map[string]interface{})
|
||||
if end < 0 {
|
||||
end = 0
|
||||
}
|
||||
if end > len(h) {
|
||||
end = len(h)
|
||||
if end > len(window) {
|
||||
end = len(window)
|
||||
}
|
||||
}
|
||||
if start > end {
|
||||
start = end
|
||||
}
|
||||
h = h[start:end]
|
||||
window = window[start:end]
|
||||
}
|
||||
|
||||
if !includeTools {
|
||||
filtered := make([]providers.Message, 0, len(h))
|
||||
for _, m := range h {
|
||||
if strings.TrimSpace(strings.ToLower(m.Role)) == "tool" {
|
||||
filtered := make([]indexedMsg, 0, len(window))
|
||||
for _, m := range window {
|
||||
if strings.TrimSpace(strings.ToLower(m.msg.Role)) == "tool" {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, m)
|
||||
}
|
||||
h = filtered
|
||||
window = filtered
|
||||
}
|
||||
if roleFilter != "" {
|
||||
filtered := make([]providers.Message, 0, len(h))
|
||||
for _, m := range h {
|
||||
if strings.ToLower(strings.TrimSpace(m.Role)) == roleFilter {
|
||||
filtered := make([]indexedMsg, 0, len(window))
|
||||
for _, m := range window {
|
||||
if strings.ToLower(strings.TrimSpace(m.msg.Role)) == roleFilter {
|
||||
filtered = append(filtered, m)
|
||||
}
|
||||
}
|
||||
h = filtered
|
||||
window = filtered
|
||||
}
|
||||
if fromMeSet {
|
||||
targetRole := "user"
|
||||
if fromMe {
|
||||
targetRole = "assistant"
|
||||
}
|
||||
filtered := make([]providers.Message, 0, len(h))
|
||||
for _, m := range h {
|
||||
if strings.ToLower(strings.TrimSpace(m.Role)) == targetRole {
|
||||
filtered := make([]indexedMsg, 0, len(window))
|
||||
for _, m := range window {
|
||||
if strings.ToLower(strings.TrimSpace(m.msg.Role)) == targetRole {
|
||||
filtered = append(filtered, m)
|
||||
}
|
||||
}
|
||||
h = filtered
|
||||
window = filtered
|
||||
}
|
||||
if query != "" {
|
||||
filtered := make([]providers.Message, 0, len(h))
|
||||
for _, m := range h {
|
||||
blob := strings.ToLower(strings.TrimSpace(m.Role + "\n" + m.Content))
|
||||
filtered := make([]indexedMsg, 0, len(window))
|
||||
for _, m := range window {
|
||||
blob := strings.ToLower(strings.TrimSpace(m.msg.Role + "\n" + m.msg.Content))
|
||||
if strings.Contains(blob, query) {
|
||||
filtered = append(filtered, m)
|
||||
}
|
||||
}
|
||||
h = filtered
|
||||
window = filtered
|
||||
}
|
||||
if len(h) == 0 {
|
||||
if len(window) == 0 {
|
||||
return "No history (after filters).", nil
|
||||
}
|
||||
if len(h) > limit {
|
||||
h = h[len(h)-limit:]
|
||||
if len(window) > limit {
|
||||
window = window[len(window)-limit:]
|
||||
}
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf("History for %s:\n", key))
|
||||
for _, m := range h {
|
||||
content := strings.TrimSpace(m.Content)
|
||||
for _, item := range window {
|
||||
content := strings.TrimSpace(item.msg.Content)
|
||||
if len(content) > 180 {
|
||||
content = content[:180] + "..."
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("- [%s] %s\n", m.Role, content))
|
||||
sb.WriteString(fmt.Sprintf("- [#%d][%s] %s\n", item.idx, item.msg.Role, content))
|
||||
}
|
||||
return strings.TrimSpace(sb.String()), nil
|
||||
default:
|
||||
|
||||
@@ -253,6 +253,29 @@ func (sm *SubagentManager) SteerTask(taskID, message string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (sm *SubagentManager) ResumeTask(ctx context.Context, taskID string) (string, bool) {
|
||||
sm.mu.RLock()
|
||||
t, ok := sm.tasks[taskID]
|
||||
sm.mu.RUnlock()
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
if strings.TrimSpace(t.Task) == "" {
|
||||
return "", false
|
||||
}
|
||||
label := strings.TrimSpace(t.Label)
|
||||
if label == "" {
|
||||
label = "resumed"
|
||||
} else {
|
||||
label = label + "-resumed"
|
||||
}
|
||||
_, err := sm.Spawn(ctx, t.Task, label, t.OriginChannel, t.OriginChatID, t.PipelineID, t.PipelineTask)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
return label, true
|
||||
}
|
||||
|
||||
func (sm *SubagentManager) pruneArchivedLocked() {
|
||||
if sm.archiveAfterMinute <= 0 {
|
||||
return
|
||||
|
||||
@@ -27,7 +27,7 @@ func (t *SubagentsTool) Parameters() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"action": map[string]interface{}{"type": "string", "description": "list|info|kill|steer|send|log"},
|
||||
"action": map[string]interface{}{"type": "string", "description": "list|info|kill|steer|send|log|resume"},
|
||||
"id": map[string]interface{}{"type": "string", "description": "subagent id/#index/all for info/kill/steer/send/log"},
|
||||
"message": map[string]interface{}{"type": "string", "description": "steering message for steer/send action"},
|
||||
"recent_minutes": map[string]interface{}{"type": "integer", "description": "optional list/info all filter by recent updated minutes"},
|
||||
@@ -148,6 +148,16 @@ func (t *SubagentsTool) Execute(ctx context.Context, args map[string]interface{}
|
||||
sb.WriteString("Result Preview:\n" + result)
|
||||
}
|
||||
return strings.TrimSpace(sb.String()), nil
|
||||
case "resume":
|
||||
resolvedID, err := t.resolveTaskID(id)
|
||||
if err != nil {
|
||||
return err.Error(), nil
|
||||
}
|
||||
label, ok := t.manager.ResumeTask(ctx, resolvedID)
|
||||
if !ok {
|
||||
return "subagent resume failed", nil
|
||||
}
|
||||
return fmt.Sprintf("subagent resumed as %s", label), nil
|
||||
default:
|
||||
return "unsupported action", nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user