From 60eee65fec8a6114a926834b7d9425ee3ea3aadf Mon Sep 17 00:00:00 2001 From: lpf Date: Fri, 13 Mar 2026 16:06:30 +0800 Subject: [PATCH] Remove heuristic subagent config shortcut --- cmd/main.go | 2 +- pkg/agent/loop.go | 19 ---- pkg/agent/subagent_config_intent.go | 106 ------------------ pkg/agent/subagent_config_intent_test.go | 50 --------- pkg/tools/subagent_config_manager.go | 135 ----------------------- 5 files changed, 1 insertion(+), 311 deletions(-) delete mode 100644 pkg/agent/subagent_config_intent.go delete mode 100644 pkg/agent/subagent_config_intent_test.go diff --git a/cmd/main.go b/cmd/main.go index 94acc16..7724daf 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,7 +19,7 @@ import ( //go:embed workspace var embeddedFiles embed.FS -var version = "0.2.1" +var version = "0.0.2" var buildTime = "unknown" const logo = ">" diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 172136b..fbf11d6 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -1201,25 +1201,6 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage) } else { specTaskRef = normalizeSpecCodingTaskRef(taskRef) } - if configAction, handled, configErr := al.maybeHandleSubagentConfigIntent(ctx, msg); handled { - if configErr != nil && specTaskRef.Summary != "" { - if err := al.maybeReopenSpecCodingTask(specTaskRef, msg.Content, configErr.Error()); err != nil { - logger.WarnCF("agent", logger.C0172, map[string]interface{}{ - "session_key": msg.SessionKey, - "error": err.Error(), - }) - } - } - if configErr == nil && specTaskRef.Summary != "" { - if err := al.maybeCompleteSpecCodingTask(specTaskRef, configAction); err != nil { - logger.WarnCF("agent", logger.C0172, map[string]interface{}{ - "session_key": msg.SessionKey, - "error": err.Error(), - }) - } - } - return configAction, configErr - } if routed, ok, routeErr := al.maybeAutoRoute(ctx, msg); ok { if routeErr != nil && specTaskRef.Summary != "" { if err := al.maybeReopenSpecCodingTask(specTaskRef, msg.Content, routeErr.Error()); err != nil { diff --git a/pkg/agent/subagent_config_intent.go b/pkg/agent/subagent_config_intent.go deleted file mode 100644 index 85698b9..0000000 --- a/pkg/agent/subagent_config_intent.go +++ /dev/null @@ -1,106 +0,0 @@ -package agent - -import ( - "context" - "fmt" - "path/filepath" - "strings" - - "github.com/YspCoder/clawgo/pkg/bus" - "github.com/YspCoder/clawgo/pkg/tools" -) - -func (al *AgentLoop) maybeHandleSubagentConfigIntent(ctx context.Context, msg bus.InboundMessage) (string, bool, error) { - _ = ctx - if al == nil { - return "", false, nil - } - if msg.Channel == "system" || msg.Channel == "internal" { - return "", false, nil - } - content := strings.TrimSpace(msg.Content) - if content == "" { - return "", false, nil - } - if !looksLikeSubagentCreateRequest(content) { - return "", false, nil - } - description := extractSubagentDescription(content) - if description == "" { - return "", false, nil - } - draft := tools.DraftConfigSubagent(description, "") - result, err := tools.UpsertConfigSubagent(al.configPath, draft) - if err != nil { - return "", true, fmt.Errorf("persist subagent config to %s failed: %w", al.displayConfigPath(), err) - } - return formatCreatedSubagentForUser(result, al.displayConfigPath()), true, nil -} - -func looksLikeSubagentCreateRequest(content string) bool { - lower := strings.ToLower(strings.TrimSpace(content)) - if lower == "" { - return false - } - createMarkers := []string{ - "创建", "新建", "增加", "添加", "配置一个", "生成一个", - "create", "add", "new", - } - subagentMarkers := []string{ - "subagent", "sub-agent", "agent", "子代理", "子 agent", "工作代理", - } - hasCreate := false - for _, item := range createMarkers { - if strings.Contains(lower, item) { - hasCreate = true - break - } - } - if !hasCreate { - return false - } - for _, item := range subagentMarkers { - if strings.Contains(lower, item) { - return true - } - } - return false -} - -func extractSubagentDescription(content string) string { - content = strings.TrimSpace(content) - replacers := []string{ - "请", "帮我", "给我", "创建", "新建", "增加", "添加", "配置", "生成", - "a ", "an ", "new ", "create ", "add ", - } - out := content - for _, item := range replacers { - out = strings.ReplaceAll(out, item, "") - } - out = strings.ReplaceAll(out, "子代理", "") - out = strings.ReplaceAll(out, "subagent", "") - out = strings.ReplaceAll(out, "sub-agent", "") - out = strings.TrimSpace(out) - if out == "" { - return strings.TrimSpace(content) - } - return out -} - -func formatCreatedSubagentForUser(result map[string]interface{}, configPath string) string { - return fmt.Sprintf( - "subagent 已写入 config.json。\npath: %s\nagent_id: %v", - configPath, - result["agent_id"], - ) -} - -func (al *AgentLoop) displayConfigPath() string { - if al == nil || strings.TrimSpace(al.configPath) == "" { - return "config path not configured" - } - if abs, err := filepath.Abs(al.configPath); err == nil { - return abs - } - return strings.TrimSpace(al.configPath) -} diff --git a/pkg/agent/subagent_config_intent_test.go b/pkg/agent/subagent_config_intent_test.go deleted file mode 100644 index e2b1cee..0000000 --- a/pkg/agent/subagent_config_intent_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package agent - -import ( - "strings" - "testing" -) - -func TestFormatCreatedSubagentForUserReadsNestedFields(t *testing.T) { - t.Parallel() - - out := formatCreatedSubagentForUser(map[string]interface{}{ - "agent_id": "coder", - "subagent": map[string]interface{}{ - "role": "coding", - "display_name": "Code Agent", - "system_prompt_file": "agents/coder/AGENT.md", - "tools": map[string]interface{}{ - "allowlist": []interface{}{"filesystem", "shell"}, - }, - }, - "rules": []interface{}{ - map[string]interface{}{ - "agent_id": "coder", - "keywords": []interface{}{"code", "fix"}, - }, - }, - }, "/tmp/config.json") - - for _, want := range []string{ - "subagent 已写入 config.json。", - "path: /tmp/config.json", - "agent_id: coder", - } { - if !strings.Contains(out, want) { - t.Fatalf("expected output to contain %q, got:\n%s", want, out) - } - } - for _, unwanted := range []string{ - "role:", - "display_name:", - "tool_allowlist:", - "routing_keywords:", - "system_prompt_file:", - "", - } { - if strings.Contains(out, unwanted) { - t.Fatalf("did not expect %q in output, got:\n%s", unwanted, out) - } - } -} diff --git a/pkg/tools/subagent_config_manager.go b/pkg/tools/subagent_config_manager.go index 9aad9f7..07ea39f 100644 --- a/pkg/tools/subagent_config_manager.go +++ b/pkg/tools/subagent_config_manager.go @@ -10,31 +10,6 @@ import ( "github.com/YspCoder/clawgo/pkg/runtimecfg" ) -func DraftConfigSubagent(description, agentIDHint string) map[string]interface{} { - desc := strings.TrimSpace(description) - lower := strings.ToLower(desc) - role := inferDraftRole(lower) - agentID := strings.TrimSpace(agentIDHint) - if agentID == "" { - agentID = inferDraftAgentID(role, lower) - } - displayName := inferDraftDisplayName(role, agentID) - toolAllowlist := inferDraftToolAllowlist(role) - keywords := inferDraftKeywords(role, lower) - return map[string]interface{}{ - "agent_id": agentID, - "role": role, - "display_name": displayName, - "description": desc, - "notify_main_policy": "final_only", - "system_prompt_file": "agents/" + agentID + "/AGENT.md", - "memory_namespace": agentID, - "tool_allowlist": toolAllowlist, - "routing_keywords": keywords, - "type": "worker", - } -} - func UpsertConfigSubagent(configPath string, args map[string]interface{}) (map[string]interface{}, error) { configPath = strings.TrimSpace(configPath) if configPath == "" { @@ -284,113 +259,3 @@ func normalizeKeywords(items []string) []string { } return out } - -func inferDraftRole(lower string) string { - switch { - case containsDraftKeyword(lower, "test", "regression", "qa", "鍥炲綊", "娴嬭瘯", "楠岃瘉"): - return "testing" - case containsDraftKeyword(lower, "doc", "docs", "readme", "鏂囨。", "璇存槑"): - return "docs" - case containsDraftKeyword(lower, "research", "investigate", "analyze", "璋冪爺", "鍒嗘瀽", "鐮旂┒"): - return "research" - default: - return "coding" - } -} - -func inferDraftAgentID(role, lower string) string { - switch role { - case "testing": - if containsDraftKeyword(lower, "review", "瀹℃煡", "reviewer") { - return "reviewer" - } - return "tester" - case "docs": - return "doc_writer" - case "research": - return "researcher" - default: - if containsDraftKeyword(lower, "frontend", "ui", "鍓嶇") { - return "frontend-coder" - } - if containsDraftKeyword(lower, "backend", "api", "鍚庣") { - return "backend-coder" - } - return "coder" - } -} - -func inferDraftDisplayName(role, agentID string) string { - switch role { - case "testing": - return "Test Agent" - case "docs": - return "Docs Agent" - case "research": - return "Research Agent" - default: - if strings.Contains(agentID, "frontend") { - return "Frontend Code Agent" - } - if strings.Contains(agentID, "backend") { - return "Backend Code Agent" - } - return "Code Agent" - } -} - -func inferDraftToolAllowlist(role string) []string { - switch role { - case "testing": - return []string{"shell", "filesystem", "process_manager", "sessions"} - case "docs": - return []string{"filesystem", "read_file", "write_file", "edit_file", "repo_map", "sessions"} - case "research": - return []string{"web_search", "web_fetch", "repo_map", "sessions", "memory_search"} - default: - return []string{"filesystem", "shell", "repo_map", "sessions"} - } -} - -func inferDraftKeywords(role, lower string) []string { - seed := []string{} - switch role { - case "testing": - seed = []string{"test", "regression", "verify", "鍥炲綊", "娴嬭瘯", "楠岃瘉"} - case "docs": - seed = []string{"docs", "readme", "document", "鏂囨。", "璇存槑"} - case "research": - seed = []string{"research", "analyze", "investigate", "璋冪爺", "鍒嗘瀽", "鐮旂┒"} - default: - seed = []string{"code", "implement", "fix", "refactor", "浠g爜", "瀹炵幇", "淇", "閲嶆瀯"} - } - if containsDraftKeyword(lower, "frontend", "鍓嶇", "ui") { - seed = append(seed, "frontend", "ui", "鍓嶇") - } - if containsDraftKeyword(lower, "backend", "鍚庣", "api") { - seed = append(seed, "backend", "api", "鍚庣") - } - return normalizeKeywords(seed) -} - -func inferDraftSystemPrompt(role, description string) string { - switch role { - case "testing": - return "浣犺礋璐f祴璇曘€侀獙璇併€佸洖褰掓鏌ヤ笌椋庨櫓鍙嶉銆備换鍔℃弿杩帮細" + description - case "docs": - return "浣犺礋璐f枃妗g紪鍐欍€佺粨鏋勬暣鐞嗗拰璇存槑琛ュ叏銆備换鍔℃弿杩帮細" + description - case "research": - return "浣犺礋璐h皟鐮斻€佸垎鏋愩€佹瘮杈冩柟妗堬紝骞惰緭鍑虹粨璁轰笌渚濇嵁銆備换鍔℃弿杩帮細" + description - default: - return "浣犺礋璐d唬鐮佸疄鐜颁笌閲嶆瀯锛岃緭鍑哄叿浣撲慨鏀瑰缓璁拰鍙樻洿缁撴灉銆備换鍔℃弿杩帮細" + description - } -} - -func containsDraftKeyword(text string, items ...string) bool { - for _, item := range items { - if strings.Contains(text, strings.ToLower(strings.TrimSpace(item))) { - return true - } - } - return false -}