From b7e93b2fb1eeae83478ce548739cf3a21fde0987 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Sat, 18 Apr 2026 07:58:52 +0000 Subject: [PATCH] refactor(memo): simplify memo tool argument/scope helpers Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: Yumiue <188874804+Yumiue@users.noreply.github.com> --- internal/tools/memo/common.go | 39 +++++++++++++++++++++++++++++++++ internal/tools/memo/list.go | 9 ++------ internal/tools/memo/recall.go | 9 ++------ internal/tools/memo/remember.go | 3 +-- internal/tools/memo/remove.go | 31 ++------------------------ 5 files changed, 46 insertions(+), 45 deletions(-) diff --git a/internal/tools/memo/common.go b/internal/tools/memo/common.go index 5534b3d5..18a83fd4 100644 --- a/internal/tools/memo/common.go +++ b/internal/tools/memo/common.go @@ -2,7 +2,9 @@ package memo import ( "fmt" + "strings" + "neo-code/internal/memo" "neo-code/internal/tools" ) @@ -11,3 +13,40 @@ func nilServiceError(toolName string) (tools.ToolResult, error) { err := fmt.Errorf("%s: service is nil", toolName) return tools.NewErrorResult(toolName, tools.NormalizeErrorReason(toolName, err), "", nil), err } + +// invalidArgumentsError 构造 memo 工具参数解析失败时的统一错误结果。 +func invalidArgumentsError(toolName string, err error) (tools.ToolResult, error) { + wrappedErr := fmt.Errorf("%s: %w", toolName, err) + return tools.NewErrorResult(toolName, "invalid arguments", wrappedErr.Error(), nil), wrappedErr +} + +// memoScopePropertySchema 返回 memo 工具统一的 scope 参数 schema 描述。 +func memoScopePropertySchema() map[string]any { + return map[string]any{ + "type": "string", + "description": "Optional scope filter: all, user, or project.", + "enum": []string{"all", "user", "project"}, + } +} + +// parseMemoScope 解析 memo scope,并根据 allowAll 决定是否接受 all。 +func parseMemoScope(raw string, allowAll bool) (memo.Scope, error) { + normalized := strings.ToLower(strings.TrimSpace(raw)) + if normalized == "" { + if allowAll { + return memo.ScopeAll, nil + } + return memo.ScopeProject, fmt.Errorf("memo: scope is required") + } + switch memo.Scope(normalized) { + case memo.ScopeUser: + return memo.ScopeUser, nil + case memo.ScopeProject: + return memo.ScopeProject, nil + case memo.ScopeAll: + if allowAll { + return memo.ScopeAll, nil + } + } + return "", fmt.Errorf("memo: unsupported scope %q", raw) +} diff --git a/internal/tools/memo/list.go b/internal/tools/memo/list.go index 99fd78c3..72b2676e 100644 --- a/internal/tools/memo/list.go +++ b/internal/tools/memo/list.go @@ -39,11 +39,7 @@ func (t *ListTool) Schema() map[string]any { return map[string]any{ "type": "object", "properties": map[string]any{ - "scope": map[string]any{ - "type": "string", - "description": "Optional scope filter: all, user, or project.", - "enum": []string{"all", "user", "project"}, - }, + "scope": memoScopePropertySchema(), }, } } @@ -62,8 +58,7 @@ func (t *ListTool) Execute(ctx context.Context, call tools.ToolCallInput) (tools var args listInput if len(call.Arguments) > 0 { if err := json.Unmarshal(call.Arguments, &args); err != nil { - err = fmt.Errorf("%s: %w", listToolName, err) - return tools.NewErrorResult(listToolName, "invalid arguments", err.Error(), nil), err + return invalidArgumentsError(listToolName, err) } } diff --git a/internal/tools/memo/recall.go b/internal/tools/memo/recall.go index 9a7eb561..dfcc2cdf 100644 --- a/internal/tools/memo/recall.go +++ b/internal/tools/memo/recall.go @@ -50,11 +50,7 @@ func (t *RecallTool) Schema() map[string]any { "type": "string", "description": "Search keyword to find matching memory entries (searches title, type, content, and keywords).", }, - "scope": map[string]any{ - "type": "string", - "description": "Optional scope filter: all, user, or project.", - "enum": []string{"all", "user", "project"}, - }, + "scope": memoScopePropertySchema(), }, "required": []string{"keyword"}, } @@ -69,8 +65,7 @@ func (t *RecallTool) MicroCompactPolicy() tools.MicroCompactPolicy { func (t *RecallTool) Execute(ctx context.Context, call tools.ToolCallInput) (tools.ToolResult, error) { var args recallInput if err := json.Unmarshal(call.Arguments, &args); err != nil { - wrappedErr := fmt.Errorf("%s: %w", recallToolName, err) - return tools.NewErrorResult(recallToolName, "invalid arguments", wrappedErr.Error(), nil), wrappedErr + return invalidArgumentsError(recallToolName, err) } args.Keyword = strings.TrimSpace(args.Keyword) diff --git a/internal/tools/memo/remember.go b/internal/tools/memo/remember.go index d6cac2db..5009ef01 100644 --- a/internal/tools/memo/remember.go +++ b/internal/tools/memo/remember.go @@ -78,8 +78,7 @@ func (t *RememberTool) MicroCompactPolicy() tools.MicroCompactPolicy { func (t *RememberTool) Execute(ctx context.Context, call tools.ToolCallInput) (tools.ToolResult, error) { var args rememberInput if err := json.Unmarshal(call.Arguments, &args); err != nil { - err = fmt.Errorf("%s: %w", rememberToolName, err) - return tools.NewErrorResult(rememberToolName, "invalid arguments", err.Error(), nil), err + return invalidArgumentsError(rememberToolName, err) } args.Type = strings.TrimSpace(args.Type) diff --git a/internal/tools/memo/remove.go b/internal/tools/memo/remove.go index 01a2d1e4..6f5e0c81 100644 --- a/internal/tools/memo/remove.go +++ b/internal/tools/memo/remove.go @@ -44,11 +44,7 @@ func (t *RemoveTool) Schema() map[string]any { "type": "string", "description": "Keyword to match against memory title, type, keywords, or content.", }, - "scope": map[string]any{ - "type": "string", - "description": "Optional scope filter: all, user, or project.", - "enum": []string{"all", "user", "project"}, - }, + "scope": memoScopePropertySchema(), }, "required": []string{"keyword"}, } @@ -63,8 +59,7 @@ func (t *RemoveTool) MicroCompactPolicy() tools.MicroCompactPolicy { func (t *RemoveTool) Execute(ctx context.Context, call tools.ToolCallInput) (tools.ToolResult, error) { var args removeInput if err := json.Unmarshal(call.Arguments, &args); err != nil { - err = fmt.Errorf("%s: %w", removeToolName, err) - return tools.NewErrorResult(removeToolName, "invalid arguments", err.Error(), nil), err + return invalidArgumentsError(removeToolName, err) } if t.svc == nil { return nilServiceError(removeToolName) @@ -96,25 +91,3 @@ func (t *RemoveTool) Execute(ctx context.Context, call tools.ToolCallInput) (too Content: fmt.Sprintf("Removed %d memo(s) matching %q.", removed, args.Keyword), }, nil } - -// parseMemoScope 解析 memo scope,并根据 allowAll 决定是否接受 all。 -func parseMemoScope(raw string, allowAll bool) (memo.Scope, error) { - normalized := strings.ToLower(strings.TrimSpace(raw)) - if normalized == "" { - if allowAll { - return memo.ScopeAll, nil - } - return memo.ScopeProject, fmt.Errorf("memo: scope is required") - } - switch memo.Scope(normalized) { - case memo.ScopeUser: - return memo.ScopeUser, nil - case memo.ScopeProject: - return memo.ScopeProject, nil - case memo.ScopeAll: - if allowAll { - return memo.ScopeAll, nil - } - } - return "", fmt.Errorf("memo: unsupported scope %q", raw) -}