From d224397f40a798ae9ddf4e7a9f00aaf3d62620dd Mon Sep 17 00:00:00 2001 From: winterfx Date: Sat, 21 Feb 2026 23:29:40 +0800 Subject: [PATCH 01/55] fix: preserve reasoning_content for OpenAI-compatible reasoning models Models like Moonshot kimi-k2.5 and DeepSeek-R1 return a reasoning_content field in assistant messages. When thinking is enabled, the API requires this field to be echoed back in subsequent requests. PicoClaw was silently dropping it, causing 400 errors on tool-call round-trips. - Add ReasoningContent to Message and LLMResponse types - Parse reasoning_content in openai_compat parseResponse() - Carry reasoning_content through assistant tool-call messages - Add unit test for reasoning_content parsing Fixes #588 --- pkg/agent/loop.go | 5 ++- pkg/providers/openai_compat/provider.go | 14 ++++--- pkg/providers/openai_compat/provider_test.go | 44 ++++++++++++++++++++ pkg/providers/protocoltypes/types.go | 18 ++++---- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index b36f4a0c4..92cede616 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -622,8 +622,9 @@ func (al *AgentLoop) runLLMIteration( // Build assistant message with tool calls assistantMsg := providers.Message{ - Role: "assistant", - Content: response.Content, + Role: "assistant", + Content: response.Content, + ReasoningContent: response.ReasoningContent, } for _, tc := range normalizedToolCalls { argumentsJSON, _ := json.Marshal(tc.Arguments) diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index b8528953a..f35d89c85 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -148,8 +148,9 @@ func parseResponse(body []byte) (*LLMResponse, error) { var apiResponse struct { Choices []struct { Message struct { - Content string `json:"content"` - ToolCalls []struct { + Content string `json:"content"` + ReasoningContent string `json:"reasoning_content"` + ToolCalls []struct { ID string `json:"id"` Type string `json:"type"` Function *struct { @@ -221,10 +222,11 @@ func parseResponse(body []byte) (*LLMResponse, error) { } return &LLMResponse{ - Content: choice.Message.Content, - ToolCalls: toolCalls, - FinishReason: choice.FinishReason, - Usage: apiResponse.Usage, + Content: choice.Message.Content, + ReasoningContent: choice.Message.ReasoningContent, + ToolCalls: toolCalls, + FinishReason: choice.FinishReason, + Usage: apiResponse.Usage, }, nil } diff --git a/pkg/providers/openai_compat/provider_test.go b/pkg/providers/openai_compat/provider_test.go index 42f9d42ab..594a48213 100644 --- a/pkg/providers/openai_compat/provider_test.go +++ b/pkg/providers/openai_compat/provider_test.go @@ -101,6 +101,50 @@ func TestProviderChat_ParsesToolCalls(t *testing.T) { } } +func TestProviderChat_ParsesReasoningContent(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + resp := map[string]any{ + "choices": []map[string]any{ + { + "message": map[string]any{ + "content": "The answer is 2", + "reasoning_content": "Let me think step by step... 1+1=2", + "tool_calls": []map[string]any{ + { + "id": "call_1", + "type": "function", + "function": map[string]any{ + "name": "calculator", + "arguments": "{\"expr\":\"1+1\"}", + }, + }, + }, + }, + "finish_reason": "tool_calls", + }, + }, + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(resp) + })) + defer server.Close() + + p := NewProvider("key", server.URL, "") + out, err := p.Chat(t.Context(), []Message{{Role: "user", Content: "1+1=?"}}, nil, "kimi-k2.5", nil) + if err != nil { + t.Fatalf("Chat() error = %v", err) + } + if out.ReasoningContent != "Let me think step by step... 1+1=2" { + t.Fatalf("ReasoningContent = %q, want %q", out.ReasoningContent, "Let me think step by step... 1+1=2") + } + if out.Content != "The answer is 2" { + t.Fatalf("Content = %q, want %q", out.Content, "The answer is 2") + } + if len(out.ToolCalls) != 1 { + t.Fatalf("len(ToolCalls) = %d, want 1", len(out.ToolCalls)) + } +} + func TestProviderChat_HTTPError(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "bad request", http.StatusBadRequest) diff --git a/pkg/providers/protocoltypes/types.go b/pkg/providers/protocoltypes/types.go index 3a089ca47..d6928e1ed 100644 --- a/pkg/providers/protocoltypes/types.go +++ b/pkg/providers/protocoltypes/types.go @@ -25,10 +25,11 @@ type FunctionCall struct { } type LLMResponse struct { - Content string `json:"content"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` - FinishReason string `json:"finish_reason"` - Usage *UsageInfo `json:"usage,omitempty"` + Content string `json:"content"` + ReasoningContent string `json:"reasoning_content,omitempty"` + ToolCalls []ToolCall `json:"tool_calls,omitempty"` + FinishReason string `json:"finish_reason"` + Usage *UsageInfo `json:"usage,omitempty"` } type UsageInfo struct { @@ -38,10 +39,11 @@ type UsageInfo struct { } type Message struct { - Role string `json:"role"` - Content string `json:"content"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` - ToolCallID string `json:"tool_call_id,omitempty"` + Role string `json:"role"` + Content string `json:"content"` + ReasoningContent string `json:"reasoning_content,omitempty"` + ToolCalls []ToolCall `json:"tool_calls,omitempty"` + ToolCallID string `json:"tool_call_id,omitempty"` } type ToolDefinition struct { From a849e02917e6c3c6a52a0e2c27e19552cc91f88d Mon Sep 17 00:00:00 2001 From: Lixeer <1612655510@qq.com> Date: Sun, 22 Feb 2026 22:30:53 +0800 Subject: [PATCH 02/55] fix: better session management for `github_copilot_provider` --- cmd/picoclaw/cmd_gateway.go | 3 + pkg/providers/github_copilot_provider.go | 74 ++++++++++++++++-------- pkg/providers/types.go | 5 ++ 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/cmd/picoclaw/cmd_gateway.go b/cmd/picoclaw/cmd_gateway.go index 28ef76ad3..30d61aec3 100644 --- a/cmd/picoclaw/cmd_gateway.go +++ b/cmd/picoclaw/cmd_gateway.go @@ -212,6 +212,9 @@ func gatewayCmd() { fmt.Println("\nShutting down...") cancel() + if cp, ok := provider.(providers.SessionProvider); ok { + cp.Close() + } healthServer.Stop(context.Background()) deviceService.Stop() heartbeatService.Stop() diff --git a/pkg/providers/github_copilot_provider.go b/pkg/providers/github_copilot_provider.go index 6124881f7..8131b76fc 100644 --- a/pkg/providers/github_copilot_provider.go +++ b/pkg/providers/github_copilot_provider.go @@ -4,60 +4,75 @@ import ( "context" "encoding/json" "fmt" + "sync" copilot "github.com/github/copilot-sdk/go" ) type GitHubCopilotProvider struct { uri string - connectMode string // `stdio` or `grpc`` + connectMode string // "stdio" or "grpc" + client *copilot.Client session *copilot.Session + + mu sync.Mutex } func NewGitHubCopilotProvider(uri string, connectMode string, model string) (*GitHubCopilotProvider, error) { - var session *copilot.Session if connectMode == "" { connectMode = "grpc" } - switch connectMode { + switch connectMode { case "stdio": - // todo + // TODO: + return nil, fmt.Errorf("stdio mode not implemented") case "grpc": client := copilot.NewClient(&copilot.ClientOptions{ CLIUrl: uri, }) if err := client.Start(context.Background()); err != nil { - return nil, fmt.Errorf( - "Can't connect to Github Copilot, https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md#connecting-to-an-external-cli-server for details", - ) + return nil, fmt.Errorf("can't connect to Github Copilot: %w; `https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md#connecting-to-an-external-cli-server` for details", err) } - defer client.Stop() - session, _ = client.CreateSession(context.Background(), &copilot.SessionConfig{ + + session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{ Model: model, Hooks: &copilot.SessionHooks{}, }) + if err != nil { + client.Stop() + return nil, fmt.Errorf("create session failed: %w", err) + } + + return &GitHubCopilotProvider{ + uri: uri, + connectMode: connectMode, + client: client, + session: session, + }, nil + default: + return nil, fmt.Errorf("unknown connect mode: %s", connectMode) } - - return &GitHubCopilotProvider{ - uri: uri, - connectMode: connectMode, - session: session, - }, nil } -// Chat sends a chat request to GitHub Copilot -func (p *GitHubCopilotProvider) Chat( - ctx context.Context, messages []Message, tools []ToolDefinition, model string, options map[string]any, -) (*LLMResponse, error) { +func (p *GitHubCopilotProvider) Close() { + p.mu.Lock() + defer p.mu.Unlock() + if p.client != nil { + p.client.Stop() + p.client = nil + p.session = nil + } +} + +func (p *GitHubCopilotProvider) Chat(ctx context.Context, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (*LLMResponse, error) { type tempMessage struct { Role string `json:"role"` Content string `json:"content"` } out := make([]tempMessage, 0, len(messages)) - for _, msg := range messages { out = append(out, tempMessage{ Role: msg.Role, @@ -65,18 +80,31 @@ func (p *GitHubCopilotProvider) Chat( }) } - fullcontent, _ := json.Marshal(out) + fullcontent, err := json.Marshal(out) + if err != nil { + return nil, fmt.Errorf("marshal messages: %w", err) + } + p.mu.Lock() + defer p.mu.Unlock() - content, _ := p.session.Send(ctx, copilot.MessageOptions{ + resp, err := p.session.SendAndWait(ctx, copilot.MessageOptions{ Prompt: string(fullcontent), }) + if err != nil { + return nil, err + } + + var content string + if resp != nil && resp.Data.Content != nil { + content = *resp.Data.Content + } return &LLMResponse{ FinishReason: "stop", Content: content, }, nil } - func (p *GitHubCopilotProvider) GetDefaultModel() string { + return "gpt-4.1" } diff --git a/pkg/providers/types.go b/pkg/providers/types.go index f711e7803..40ff6f7c8 100644 --- a/pkg/providers/types.go +++ b/pkg/providers/types.go @@ -30,6 +30,11 @@ type LLMProvider interface { GetDefaultModel() string } +type SessionProvider interface { + LLMProvider + Close() +} + // FailoverReason classifies why an LLM request failed for fallback decisions. type FailoverReason string From 3d605a4f537507713706aa626b74ad8506e6e12a Mon Sep 17 00:00:00 2001 From: Lixeer <1612655510@qq.com> Date: Sun, 22 Feb 2026 23:02:29 +0800 Subject: [PATCH 03/55] fix: run fmt and lint --- pkg/providers/github_copilot_provider.go | 15 ++++++++++++--- pkg/tools/registry_test.go | 20 ++++++++++---------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/pkg/providers/github_copilot_provider.go b/pkg/providers/github_copilot_provider.go index 8131b76fc..c69658b44 100644 --- a/pkg/providers/github_copilot_provider.go +++ b/pkg/providers/github_copilot_provider.go @@ -33,7 +33,10 @@ func NewGitHubCopilotProvider(uri string, connectMode string, model string) (*Gi CLIUrl: uri, }) if err := client.Start(context.Background()); err != nil { - return nil, fmt.Errorf("can't connect to Github Copilot: %w; `https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md#connecting-to-an-external-cli-server` for details", err) + return nil, fmt.Errorf( + "can't connect to Github Copilot: %w; `https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md#connecting-to-an-external-cli-server` for details", + err, + ) } session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{ @@ -67,7 +70,13 @@ func (p *GitHubCopilotProvider) Close() { } } -func (p *GitHubCopilotProvider) Chat(ctx context.Context, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (*LLMResponse, error) { +func (p *GitHubCopilotProvider) Chat( + ctx context.Context, + messages []Message, + tools []ToolDefinition, + model string, + options map[string]any, +) (*LLMResponse, error) { type tempMessage struct { Role string `json:"role"` Content string `json:"content"` @@ -104,7 +113,7 @@ func (p *GitHubCopilotProvider) Chat(ctx context.Context, messages []Message, to Content: content, }, nil } -func (p *GitHubCopilotProvider) GetDefaultModel() string { +func (p *GitHubCopilotProvider) GetDefaultModel() string { return "gpt-4.1" } diff --git a/pkg/tools/registry_test.go b/pkg/tools/registry_test.go index 33978e543..8ae13b20c 100644 --- a/pkg/tools/registry_test.go +++ b/pkg/tools/registry_test.go @@ -14,14 +14,14 @@ import ( type mockRegistryTool struct { name string desc string - params map[string]interface{} + params map[string]any result *ToolResult } -func (m *mockRegistryTool) Name() string { return m.name } -func (m *mockRegistryTool) Description() string { return m.desc } -func (m *mockRegistryTool) Parameters() map[string]interface{} { return m.params } -func (m *mockRegistryTool) Execute(_ context.Context, _ map[string]interface{}) *ToolResult { +func (m *mockRegistryTool) Name() string { return m.name } +func (m *mockRegistryTool) Description() string { return m.desc } +func (m *mockRegistryTool) Parameters() map[string]any { return m.params } +func (m *mockRegistryTool) Execute(_ context.Context, _ map[string]any) *ToolResult { return m.result } @@ -51,7 +51,7 @@ func newMockTool(name, desc string) *mockRegistryTool { return &mockRegistryTool{ name: name, desc: desc, - params: map[string]interface{}{"type": "object"}, + params: map[string]any{"type": "object"}, result: SilentResult("ok"), } } @@ -109,7 +109,7 @@ func TestToolRegistry_Execute_Success(t *testing.T) { r.Register(&mockRegistryTool{ name: "greet", desc: "says hello", - params: map[string]interface{}{}, + params: map[string]any{}, result: SilentResult("hello"), }) @@ -203,7 +203,7 @@ func TestToolRegistry_GetDefinitions(t *testing.T) { if defs[0]["type"] != "function" { t.Errorf("expected type 'function', got %v", defs[0]["type"]) } - fn, ok := defs[0]["function"].(map[string]interface{}) + fn, ok := defs[0]["function"].(map[string]any) if !ok { t.Fatal("expected 'function' key to be a map") } @@ -217,7 +217,7 @@ func TestToolRegistry_GetDefinitions(t *testing.T) { func TestToolRegistry_ToProviderDefs(t *testing.T) { r := NewToolRegistry() - params := map[string]interface{}{"type": "object", "properties": map[string]interface{}{}} + params := map[string]any{"type": "object", "properties": map[string]any{}} r.Register(&mockRegistryTool{ name: "beta", desc: "tool B", @@ -310,7 +310,7 @@ func TestToolToSchema(t *testing.T) { if schema["type"] != "function" { t.Errorf("expected type 'function', got %v", schema["type"]) } - fn, ok := schema["function"].(map[string]interface{}) + fn, ok := schema["function"].(map[string]any) if !ok { t.Fatal("expected 'function' to be a map") } From 712f5a8300f0ce9d9d22352a1bc92bed3a0c8b88 Mon Sep 17 00:00:00 2001 From: yinwm Date: Mon, 23 Feb 2026 16:55:06 +0800 Subject: [PATCH 04/55] refactor(config): rename model field to model_name The configuration field for specifying the model has been renamed from "model" to "model_name" for better clarity and consistency with the model_list configuration. A GetModelName() accessor method has been added to maintain backward compatibility. Existing configurations using the old "model" field will continue to work correctly. This change affects: - Configuration structure (AgentDefaults struct) - All references across the codebase - Documentation in all language variants - Example configuration files --- README.fr.md | 2 +- README.ja.md | 2 +- README.md | 2 +- README.pt-br.md | 2 +- README.vi.md | 2 +- README.zh.md | 2 +- cmd/picoclaw/cmd_agent.go | 4 +- cmd/picoclaw/cmd_auth.go | 10 +-- cmd/picoclaw/cmd_gateway.go | 2 +- cmd/picoclaw/cmd_status.go | 2 +- config/config.example.json | 2 +- pkg/agent/instance.go | 2 +- pkg/channels/telegram_commands.go | 4 +- pkg/config/config.go | 12 ++- pkg/config/migration.go | 2 +- pkg/config/model_config_test.go | 132 ++++++++++++++++++++++++++++++ pkg/migrate/config.go | 5 +- pkg/providers/factory.go | 2 +- pkg/providers/legacy_provider.go | 2 +- 19 files changed, 169 insertions(+), 24 deletions(-) diff --git a/README.fr.md b/README.fr.md index 7199f7098..04f40e022 100644 --- a/README.fr.md +++ b/README.fr.md @@ -222,7 +222,7 @@ picoclaw onboard ], "agents": { "defaults": { - "model": "gpt4" + "model_name": "gpt4" } }, "channels": { diff --git a/README.ja.md b/README.ja.md index bb0bdfb28..b379bc2a7 100644 --- a/README.ja.md +++ b/README.ja.md @@ -184,7 +184,7 @@ picoclaw onboard ], "agents": { "defaults": { - "model": "gpt4" + "model_name": "gpt4" } }, "channels": { diff --git a/README.md b/README.md index 7bc7b1089..058e16a2b 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,7 @@ picoclaw onboard "agents": { "defaults": { "workspace": "~/.picoclaw/workspace", - "model": "gpt4", + "model_name": "gpt4", "max_tokens": 8192, "temperature": 0.7, "max_tool_iterations": 20 diff --git a/README.pt-br.md b/README.pt-br.md index ec8fe8e1c..cfa5b801b 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -223,7 +223,7 @@ picoclaw onboard ], "agents": { "defaults": { - "model": "gpt4" + "model_name": "gpt4" } }, "tools": { diff --git a/README.vi.md b/README.vi.md index 161842933..1d0084aa3 100644 --- a/README.vi.md +++ b/README.vi.md @@ -203,7 +203,7 @@ picoclaw onboard ], "agents": { "defaults": { - "model": "gpt4" + "model_name": "gpt4" } }, "channels": { diff --git a/README.zh.md b/README.zh.md index 4d739c5eb..dca149fa9 100644 --- a/README.zh.md +++ b/README.zh.md @@ -221,7 +221,7 @@ picoclaw onboard "agents": { "defaults": { "workspace": "~/.picoclaw/workspace", - "model": "gpt4", + "model_name": "gpt4", "max_tokens": 8192, "temperature": 0.7, "max_tool_iterations": 20 diff --git a/cmd/picoclaw/cmd_agent.go b/cmd/picoclaw/cmd_agent.go index 6d6ff935f..6331fdd4a 100644 --- a/cmd/picoclaw/cmd_agent.go +++ b/cmd/picoclaw/cmd_agent.go @@ -56,7 +56,7 @@ func agentCmd() { } if modelOverride != "" { - cfg.Agents.Defaults.Model = modelOverride + cfg.Agents.Defaults.ModelName = modelOverride } provider, modelID, err := providers.CreateProvider(cfg) @@ -66,7 +66,7 @@ func agentCmd() { } // Use the resolved model ID from provider creation if modelID != "" { - cfg.Agents.Defaults.Model = modelID + cfg.Agents.Defaults.ModelName = modelID } msgBus := bus.NewMessageBus() diff --git a/cmd/picoclaw/cmd_auth.go b/cmd/picoclaw/cmd_auth.go index 729c56177..55eb3cec3 100644 --- a/cmd/picoclaw/cmd_auth.go +++ b/cmd/picoclaw/cmd_auth.go @@ -144,7 +144,7 @@ func authLoginOpenAI(useDeviceCode bool) { } // Update default model to use OpenAI - appCfg.Agents.Defaults.Model = "gpt-5.2" + appCfg.Agents.Defaults.ModelName = "gpt-5.2" if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { fmt.Printf("Warning: could not update config: %v\n", err) @@ -218,7 +218,7 @@ func authLoginGoogleAntigravity() { } // Update default model - appCfg.Agents.Defaults.Model = "gemini-flash" + appCfg.Agents.Defaults.ModelName = "gemini-flash" if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { fmt.Printf("Warning: could not update config: %v\n", err) @@ -292,7 +292,7 @@ func authLoginPasteToken(provider string) { }) } // Update default model - appCfg.Agents.Defaults.Model = "claude-sonnet-4.6" + appCfg.Agents.Defaults.ModelName = "claude-sonnet-4.6" case "openai": appCfg.Providers.OpenAI.AuthMethod = "token" // Update ModelList @@ -312,7 +312,7 @@ func authLoginPasteToken(provider string) { }) } // Update default model - appCfg.Agents.Defaults.Model = "gpt-5.2" + appCfg.Agents.Defaults.ModelName = "gpt-5.2" } if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { fmt.Printf("Warning: could not update config: %v\n", err) @@ -320,7 +320,7 @@ func authLoginPasteToken(provider string) { } fmt.Printf("Token saved for %s!\n", provider) - fmt.Printf("Default model set to: %s\n", appCfg.Agents.Defaults.Model) + fmt.Printf("Default model set to: %s\n", appCfg.Agents.Defaults.GetModelName()) } func authLogoutCmd() { diff --git a/cmd/picoclaw/cmd_gateway.go b/cmd/picoclaw/cmd_gateway.go index 9a3b6aa19..bd1cdd7a8 100644 --- a/cmd/picoclaw/cmd_gateway.go +++ b/cmd/picoclaw/cmd_gateway.go @@ -51,7 +51,7 @@ func gatewayCmd() { } // Use the resolved model ID from provider creation if modelID != "" { - cfg.Agents.Defaults.Model = modelID + cfg.Agents.Defaults.ModelName = modelID } msgBus := bus.NewMessageBus() diff --git a/cmd/picoclaw/cmd_status.go b/cmd/picoclaw/cmd_status.go index 07296784e..6a117bd17 100644 --- a/cmd/picoclaw/cmd_status.go +++ b/cmd/picoclaw/cmd_status.go @@ -41,7 +41,7 @@ func statusCmd() { } if _, err := os.Stat(configPath); err == nil { - fmt.Printf("Model: %s\n", cfg.Agents.Defaults.Model) + fmt.Printf("Model: %s\n", cfg.Agents.Defaults.GetModelName()) hasOpenRouter := cfg.Providers.OpenRouter.APIKey != "" hasAnthropic := cfg.Providers.Anthropic.APIKey != "" diff --git a/config/config.example.json b/config/config.example.json index 77a8c0683..1795fed9f 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -3,7 +3,7 @@ "defaults": { "workspace": "~/.picoclaw/workspace", "restrict_to_workspace": true, - "model": "gpt4", + "model_name": "gpt4", "max_tokens": 8192, "temperature": 0.7, "max_tool_iterations": 20 diff --git a/pkg/agent/instance.go b/pkg/agent/instance.go index dfbef9fbc..c6a54c7d2 100644 --- a/pkg/agent/instance.go +++ b/pkg/agent/instance.go @@ -133,7 +133,7 @@ func resolveAgentModel(agentCfg *config.AgentConfig, defaults *config.AgentDefau if agentCfg != nil && agentCfg.Model != nil && strings.TrimSpace(agentCfg.Model.Primary) != "" { return strings.TrimSpace(agentCfg.Model.Primary) } - return defaults.Model + return defaults.GetModelName() } // resolveAgentFallbacks resolves the fallback models for an agent. diff --git a/pkg/channels/telegram_commands.go b/pkg/channels/telegram_commands.go index a084b641b..f28434f46 100644 --- a/pkg/channels/telegram_commands.go +++ b/pkg/channels/telegram_commands.go @@ -81,7 +81,7 @@ func (c *cmd) Show(ctx context.Context, message telego.Message) error { switch args { case "model": response = fmt.Sprintf("Current Model: %s (Provider: %s)", - c.config.Agents.Defaults.Model, + c.config.Agents.Defaults.GetModelName(), c.config.Agents.Defaults.Provider) case "channel": response = "Current Channel: telegram" @@ -120,7 +120,7 @@ func (c *cmd) List(ctx context.Context, message telego.Message) error { provider = "configured default" } response = fmt.Sprintf("Configured Model: %s\nProvider: %s\n\nTo change models, update config.yaml", - c.config.Agents.Defaults.Model, provider) + c.config.Agents.Defaults.GetModelName(), provider) case "channels": var enabled []string diff --git a/pkg/config/config.go b/pkg/config/config.go index 20556011a..c103963c8 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -170,7 +170,8 @@ type AgentDefaults struct { Workspace string `json:"workspace" env:"PICOCLAW_AGENTS_DEFAULTS_WORKSPACE"` RestrictToWorkspace bool `json:"restrict_to_workspace" env:"PICOCLAW_AGENTS_DEFAULTS_RESTRICT_TO_WORKSPACE"` Provider string `json:"provider" env:"PICOCLAW_AGENTS_DEFAULTS_PROVIDER"` - Model string `json:"model" env:"PICOCLAW_AGENTS_DEFAULTS_MODEL"` + ModelName string `json:"model_name,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_MODEL_NAME"` + Model string `json:"model,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_MODEL"` // Deprecated: use model_name instead ModelFallbacks []string `json:"model_fallbacks,omitempty"` ImageModel string `json:"image_model,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_IMAGE_MODEL"` ImageModelFallbacks []string `json:"image_model_fallbacks,omitempty"` @@ -179,6 +180,15 @@ type AgentDefaults struct { MaxToolIterations int `json:"max_tool_iterations" env:"PICOCLAW_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"` } +// GetModelName returns the effective model name for the agent defaults. +// It prefers the new "model_name" field but falls back to "model" for backward compatibility. +func (d *AgentDefaults) GetModelName() string { + if d.ModelName != "" { + return d.ModelName + } + return d.Model +} + type ChannelsConfig struct { WhatsApp WhatsAppConfig `json:"whatsapp"` Telegram TelegramConfig `json:"telegram"` diff --git a/pkg/config/migration.go b/pkg/config/migration.go index 689e2312f..e51d4efb2 100644 --- a/pkg/config/migration.go +++ b/pkg/config/migration.go @@ -41,7 +41,7 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { // Get user's configured provider and model userProvider := strings.ToLower(cfg.Agents.Defaults.Provider) - userModel := cfg.Agents.Defaults.Model + userModel := cfg.Agents.Defaults.GetModelName() p := cfg.Providers diff --git a/pkg/config/model_config_test.go b/pkg/config/model_config_test.go index 3c411dc0f..c89029e8c 100644 --- a/pkg/config/model_config_test.go +++ b/pkg/config/model_config_test.go @@ -6,6 +6,7 @@ package config import ( + "encoding/json" "strings" "sync" "testing" @@ -114,6 +115,137 @@ func TestGetModelConfig_Concurrent(t *testing.T) { } } +func TestAgentDefaults_GetModelName_BackwardCompat(t *testing.T) { + tests := []struct { + name string + defaults AgentDefaults + wantName string + }{ + { + name: "new model_name field only", + defaults: AgentDefaults{ModelName: "new-model"}, + wantName: "new-model", + }, + { + name: "old model field only", + defaults: AgentDefaults{Model: "legacy-model"}, + wantName: "legacy-model", + }, + { + name: "both fields - model_name takes precedence", + defaults: AgentDefaults{ModelName: "new-model", Model: "old-model"}, + wantName: "new-model", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.defaults.GetModelName(); got != tt.wantName { + t.Errorf("GetModelName() = %q, want %q", got, tt.wantName) + } + }) + } +} + +func TestAgentDefaults_JSON_BackwardCompat(t *testing.T) { + tests := []struct { + name string + json string + wantName string + }{ + { + name: "new model_name field", + json: `{"model_name": "gpt4"}`, + wantName: "gpt4", + }, + { + name: "old model field", + json: `{"model": "gpt4"}`, + wantName: "gpt4", + }, + { + name: "both fields - model_name wins", + json: `{"model_name": "new", "model": "old"}`, + wantName: "new", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var defaults AgentDefaults + if err := json.Unmarshal([]byte(tt.json), &defaults); err != nil { + t.Fatalf("Unmarshal error: %v", err) + } + if got := defaults.GetModelName(); got != tt.wantName { + t.Errorf("GetModelName() = %q, want %q", got, tt.wantName) + } + }) + } +} + +func TestFullConfig_JSON_BackwardCompat(t *testing.T) { + // Test complete config with both old and new formats + oldFormat := `{ + "agents": { + "defaults": { + "workspace": "~/.picoclaw/workspace", + "model": "gpt4", + "max_tokens": 4096 + } + }, + "model_list": [ + { + "model_name": "gpt4", + "model": "openai/gpt-4o", + "api_key": "test-key" + } + ] + }` + + newFormat := `{ + "agents": { + "defaults": { + "workspace": "~/.picoclaw/workspace", + "model_name": "gpt4", + "max_tokens": 4096 + } + }, + "model_list": [ + { + "model_name": "gpt4", + "model": "openai/gpt-4o", + "api_key": "test-key" + } + ] + }` + + for name, jsonStr := range map[string]string{ + "old format (model)": oldFormat, + "new format (model_name)": newFormat, + } { + t.Run(name, func(t *testing.T) { + cfg := &Config{} + if err := json.Unmarshal([]byte(jsonStr), cfg); err != nil { + t.Fatalf("Unmarshal error: %v", err) + } + + // Check that GetModelName returns correct value + if got := cfg.Agents.Defaults.GetModelName(); got != "gpt4" { + t.Errorf("GetModelName() = %q, want %q", got, "gpt4") + } + + // Check that GetModelConfig works + modelCfg, err := cfg.GetModelConfig("gpt4") + if err != nil { + t.Fatalf("GetModelConfig error: %v", err) + } + if modelCfg.Model != "openai/gpt-4o" { + t.Errorf("Model = %q, want %q", modelCfg.Model, "openai/gpt-4o") + } + }) + } +} + func TestModelConfig_Validate(t *testing.T) { tests := []struct { name string diff --git a/pkg/migrate/config.go b/pkg/migrate/config.go index 2237a1429..d9552db9f 100644 --- a/pkg/migrate/config.go +++ b/pkg/migrate/config.go @@ -72,7 +72,10 @@ func ConvertConfig(data map[string]any) (*config.Config, []string, error) { if agents, ok := getMap(data, "agents"); ok { if defaults, ok := getMap(agents, "defaults"); ok { - if v, ok := getString(defaults, "model"); ok { + // Prefer model_name, fallback to model for backward compatibility + if v, ok := getString(defaults, "model_name"); ok { + cfg.Agents.Defaults.ModelName = v + } else if v, ok := getString(defaults, "model"); ok { cfg.Agents.Defaults.Model = v } if v, ok := getFloat(defaults, "max_tokens"); ok { diff --git a/pkg/providers/factory.go b/pkg/providers/factory.go index b6f1b5e21..b9abfdc61 100644 --- a/pkg/providers/factory.go +++ b/pkg/providers/factory.go @@ -36,7 +36,7 @@ type providerSelection struct { } func resolveProviderSelection(cfg *config.Config) (providerSelection, error) { - model := cfg.Agents.Defaults.Model + model := cfg.Agents.Defaults.GetModelName() providerName := strings.ToLower(cfg.Agents.Defaults.Provider) lowerModel := strings.ToLower(model) diff --git a/pkg/providers/legacy_provider.go b/pkg/providers/legacy_provider.go index eb13cec65..23f137538 100644 --- a/pkg/providers/legacy_provider.go +++ b/pkg/providers/legacy_provider.go @@ -16,7 +16,7 @@ import ( // The old providers config is automatically converted to model_list during config loading. // Returns the provider, the model ID to use, and any error. func CreateProvider(cfg *config.Config) (LLMProvider, string, error) { - model := cfg.Agents.Defaults.Model + model := cfg.Agents.Defaults.GetModelName() // Ensure model_list is populated (should be done by LoadConfig, but handle edge cases) if len(cfg.ModelList) == 0 && cfg.HasProvidersConfig() { From 8a53cb96651fad13c665417aadbedddf3e14a284 Mon Sep 17 00:00:00 2001 From: Chujiang <110hqc@gmail.com> Date: Tue, 24 Feb 2026 05:52:16 +0800 Subject: [PATCH 05/55] fix: align Docker Go version with go.mod and optimize logger (#596) - Update Dockerfile to use golang:1.25-alpine to match go.mod (go 1.25.7) - Optimize logger by avoiding string concatenation in file writes - Add explicit empty string assignment for fieldStr when no fields These changes improve build consistency and reduce memory allocations in the hot logging path, which is important for the project's goal of running on resource-constrained devices (<10MB RAM). Co-authored-by: Claude Sonnet 4.6 --- Dockerfile | 2 +- pkg/logger/logger.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0360cfda6..480244127 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # ============================================================ # Stage 1: Build the picoclaw binary # ============================================================ -FROM golang:1.26.0-alpine AS builder +FROM golang:1.25-alpine AS builder RUN apk add --no-cache git make diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 54de66bf9..c14fbd464 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -119,13 +119,15 @@ func logMessage(level LogLevel, component string, message string, fields map[str if logger.file != nil { jsonData, err := json.Marshal(entry) if err == nil { - logger.file.WriteString(string(jsonData) + "\n") + logger.file.Write(append(jsonData, '\n')) } } var fieldStr string if len(fields) > 0 { fieldStr = " " + formatFields(fields) + } else { + fieldStr = "" } logLine := fmt.Sprintf("[%s] [%s]%s %s%s", From 2fa51d7b868672ab2fd054396216fa68184b3ad6 Mon Sep 17 00:00:00 2001 From: 0x5487 Date: Tue, 24 Feb 2026 05:54:10 +0800 Subject: [PATCH 06/55] fix(security): change gateway default bind to 127.0.0.1 (#393) * chore: Update default host bindings from 0.0.0.0 to 127.0.0.1 for various services and examples. * config: Update default host bindings to 0.0.0.0 for improved Docker accessibility and add related documentation. * chore: resolve conflict * chore: remove link * docs: Add a tip for Docker users regarding gateway host configuration to the French and Vietnamese READMEs. * fix: typo issue * docs: Update Chinese README.zh.md. --- README.fr.md | 4 ++++ README.ja.md | 4 ++++ README.md | 4 ++++ README.pt-br.md | 4 ++++ README.vi.md | 4 ++++ README.zh.md | 3 +++ config/config.example.json | 2 +- pkg/config/config_test.go | 4 ++-- pkg/config/defaults.go | 2 +- 9 files changed, 27 insertions(+), 4 deletions(-) diff --git a/README.fr.md b/README.fr.md index a762870ff..d09276c27 100644 --- a/README.fr.md +++ b/README.fr.md @@ -171,6 +171,10 @@ vim config/config.json # Configurez DISCORD_BOT_TOKEN, clés API, etc. # 3. Compiler & Démarrer docker compose --profile gateway up -d +> [!TIP] +> **Utilisateurs Docker** : Par défaut, le Gateway écoute sur `127.0.0.1`, ce qui n'est pas accessible depuis l'hôte. Si vous avez besoin d'accéder aux endpoints de santé ou d'exposer des ports, définissez `PICOCLAW_GATEWAY_HOST=0.0.0.0` dans votre environnement ou mettez à jour `config.json`. + + # 4. Voir les logs docker compose logs -f picoclaw-gateway diff --git a/README.ja.md b/README.ja.md index 3506c77c2..67eccddc2 100644 --- a/README.ja.md +++ b/README.ja.md @@ -133,6 +133,10 @@ vim config/config.json # DISCORD_BOT_TOKEN, プロバイダーの API キ # 3. ビルドと起動 docker compose --profile gateway up -d +> [!TIP] +> **Docker ユーザー**: デフォルトでは、Gateway は `127.0.0.1` でリッスンしており、ホストからアクセスできません。ヘルスチェックエンドポイントにアクセスしたり、ポートを公開したりする必要がある場合は、環境変数で `PICOCLAW_GATEWAY_HOST=0.0.0.0` を設定するか、`config.json` を更新してください。 + + # 4. ログ確認 docker compose logs -f picoclaw-gateway diff --git a/README.md b/README.md index 955255f2e..84d92115b 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,10 @@ vim config/config.json # Set DISCORD_BOT_TOKEN, API keys, etc. # 3. Build & Start docker compose --profile gateway up -d +> [!TIP] +> **Docker Users**: By default, the Gateway listens on `127.0.0.1` which is not accessible from the host. If you need to access the health endpoints or expose ports, set `PICOCLAW_GATEWAY_HOST=0.0.0.0` in your environment or update `config.json`. + + # 4. Check logs docker compose logs -f picoclaw-gateway diff --git a/README.pt-br.md b/README.pt-br.md index 900ee7932..8d87333bc 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -172,6 +172,10 @@ vim config/config.json # Configure DISCORD_BOT_TOKEN, API keys, etc. # 3. Build & Iniciar docker compose --profile gateway up -d +> [!TIP] +> **Usuários Docker**: Por padrão, o Gateway ouve em `127.0.0.1`, o que não é acessível a partir do host. Se você precisar acessar os endpoints de integridade ou expor portas, defina `PICOCLAW_GATEWAY_HOST=0.0.0.0` em seu ambiente ou atualize o `config.json`. + + # 4. Ver logs docker compose logs -f picoclaw-gateway diff --git a/README.vi.md b/README.vi.md index 29ff12bb0..1be58d9f6 100644 --- a/README.vi.md +++ b/README.vi.md @@ -152,6 +152,10 @@ vim config/config.json # Thiết lập DISCORD_BOT_TOKEN, API keys, v.v. # 3. Build & Khởi động docker compose --profile gateway up -d +> [!TIP] +> **Người dùng Docker**: Theo mặc định, Gateway lắng nghe trên `127.0.0.1`, không thể truy cập từ máy chủ. Nếu bạn cần truy cập các endpoint kiểm tra sức khỏe hoặc mở cổng, hãy đặt `PICOCLAW_GATEWAY_HOST=0.0.0.0` trong môi trường của bạn hoặc cập nhật `config.json`. + + # 4. Xem logs docker compose logs -f picoclaw-gateway diff --git a/README.zh.md b/README.zh.md index 17a736fec..74760b3b1 100644 --- a/README.zh.md +++ b/README.zh.md @@ -173,6 +173,9 @@ vim config/config.json # 设置 DISCORD_BOT_TOKEN, API keys 等 # 3. 构建并启动 docker compose --profile gateway up -d +> [!TIP] +**Docker 用户**: 默认情况下, Gateway监听 `127.0.0.1`,这使得这个端口未暴露到容器外。如果你需要通过端口映射访问健康检查接口, 请在环境变量中设置 `PICOCLAW_GATEWAY_HOST=0.0.0.0` 或修改 `config.json`。 + # 4. 查看日志 docker compose logs -f picoclaw-gateway diff --git a/config/config.example.json b/config/config.example.json index e814fcbb8..555509732 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -247,7 +247,7 @@ "monitor_usb": true }, "gateway": { - "host": "0.0.0.0", + "host": "127.0.0.1", "port": 18790 } } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 0898217d6..f88c0269c 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -246,7 +246,7 @@ func TestDefaultConfig_Temperature(t *testing.T) { func TestDefaultConfig_Gateway(t *testing.T) { cfg := DefaultConfig() - if cfg.Gateway.Host != "0.0.0.0" { + if cfg.Gateway.Host != "127.0.0.1" { t.Error("Gateway host should have default value") } if cfg.Gateway.Port == 0 { @@ -343,7 +343,7 @@ func TestConfig_Complete(t *testing.T) { if cfg.Agents.Defaults.MaxToolIterations == 0 { t.Error("MaxToolIterations should not be zero") } - if cfg.Gateway.Host != "0.0.0.0" { + if cfg.Gateway.Host != "127.0.0.1" { t.Error("Gateway host should have default value") } if cfg.Gateway.Port == 0 { diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 065273c28..b96ee4d89 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -272,7 +272,7 @@ func DefaultConfig() *Config { }, }, Gateway: GatewayConfig{ - Host: "0.0.0.0", + Host: "127.0.0.1", Port: 18790, }, Tools: ToolsConfig{ From 09b1992dd79cac46b7a48176074eabae36b9c1bc Mon Sep 17 00:00:00 2001 From: Goksu Ceylan <79890826+GoCeylan@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:02:44 -0500 Subject: [PATCH 07/55] fix(security): ensure custom deny patterns extend defaults instead of replacing them (#479) * fix (security): custom deny patterns denying default patterns * fix formatting whitespace --- pkg/tools/shell.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index a1ee0b6e1..6883172cd 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -81,6 +81,7 @@ func NewExecToolWithConfig(workingDir string, restrict bool, config *config.Conf execConfig := config.Tools.Exec enableDenyPatterns = execConfig.EnableDenyPatterns if enableDenyPatterns { + denyPatterns = append(denyPatterns, defaultDenyPatterns...) if len(execConfig.CustomDenyPatterns) > 0 { fmt.Printf("Using custom deny patterns: %v\n", execConfig.CustomDenyPatterns) for _, pattern := range execConfig.CustomDenyPatterns { @@ -91,8 +92,6 @@ func NewExecToolWithConfig(workingDir string, restrict bool, config *config.Conf } denyPatterns = append(denyPatterns, re) } - } else { - denyPatterns = append(denyPatterns, defaultDenyPatterns...) } } else { // If deny patterns are disabled, we won't add any patterns, allowing all commands. From 6fe3920a4d836b97c838fd39874cc6a5d07d1d40 Mon Sep 17 00:00:00 2001 From: mattn Date: Tue, 24 Feb 2026 08:07:09 +0900 Subject: [PATCH 08/55] perf: refactoring collecting skills (#688) * perf: refactoring collecting skills * Fix order to store dir.Name() * Add tests --- pkg/skills/loader.go | 140 +++++++++++--------------------------- pkg/skills/loader_test.go | 131 +++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 101 deletions(-) diff --git a/pkg/skills/loader.go b/pkg/skills/loader.go index eb0d5f322..f4f55a698 100644 --- a/pkg/skills/loader.go +++ b/pkg/skills/loader.go @@ -71,112 +71,50 @@ func NewSkillsLoader(workspace string, globalSkills string, builtinSkills string func (sl *SkillsLoader) ListSkills() []SkillInfo { skills := make([]SkillInfo, 0) + seen := make(map[string]bool) - if sl.workspaceSkills != "" { - if dirs, err := os.ReadDir(sl.workspaceSkills); err == nil { - for _, dir := range dirs { - if dir.IsDir() { - skillFile := filepath.Join(sl.workspaceSkills, dir.Name(), "SKILL.md") - if _, err := os.Stat(skillFile); err == nil { - info := SkillInfo{ - Name: dir.Name(), - Path: skillFile, - Source: "workspace", - } - metadata := sl.getSkillMetadata(skillFile) - if metadata != nil { - info.Description = metadata.Description - info.Name = metadata.Name - } - if err := info.validate(); err != nil { - slog.Warn("invalid skill from workspace", "name", info.Name, "error", err) - continue - } - skills = append(skills, info) - } - } + addSkills := func(dir, source string) { + if dir == "" { + return + } + dirs, err := os.ReadDir(dir) + if err != nil { + return + } + for _, d := range dirs { + if !d.IsDir() { + continue } + skillFile := filepath.Join(dir, d.Name(), "SKILL.md") + if _, err := os.Stat(skillFile); err != nil { + continue + } + info := SkillInfo{ + Name: d.Name(), + Path: skillFile, + Source: source, + } + metadata := sl.getSkillMetadata(skillFile) + if metadata != nil { + info.Description = metadata.Description + info.Name = metadata.Name + } + if err := info.validate(); err != nil { + slog.Warn("invalid skill from "+source, "name", info.Name, "error", err) + continue + } + if seen[info.Name] { + continue + } + seen[info.Name] = true + skills = append(skills, info) } } - // 全局 skills (~/.picoclaw/skills) - 被 workspace skills 覆盖 - if sl.globalSkills != "" { - if dirs, err := os.ReadDir(sl.globalSkills); err == nil { - for _, dir := range dirs { - if dir.IsDir() { - skillFile := filepath.Join(sl.globalSkills, dir.Name(), "SKILL.md") - if _, err := os.Stat(skillFile); err == nil { - // 检查是否已被 workspace skills 覆盖 - exists := false - for _, s := range skills { - if s.Name == dir.Name() && s.Source == "workspace" { - exists = true - break - } - } - if exists { - continue - } - - info := SkillInfo{ - Name: dir.Name(), - Path: skillFile, - Source: "global", - } - metadata := sl.getSkillMetadata(skillFile) - if metadata != nil { - info.Description = metadata.Description - info.Name = metadata.Name - } - if err := info.validate(); err != nil { - slog.Warn("invalid skill from global", "name", info.Name, "error", err) - continue - } - skills = append(skills, info) - } - } - } - } - } - - if sl.builtinSkills != "" { - if dirs, err := os.ReadDir(sl.builtinSkills); err == nil { - for _, dir := range dirs { - if dir.IsDir() { - skillFile := filepath.Join(sl.builtinSkills, dir.Name(), "SKILL.md") - if _, err := os.Stat(skillFile); err == nil { - // 检查是否已被 workspace 或 global skills 覆盖 - exists := false - for _, s := range skills { - if s.Name == dir.Name() && (s.Source == "workspace" || s.Source == "global") { - exists = true - break - } - } - if exists { - continue - } - - info := SkillInfo{ - Name: dir.Name(), - Path: skillFile, - Source: "builtin", - } - metadata := sl.getSkillMetadata(skillFile) - if metadata != nil { - info.Description = metadata.Description - info.Name = metadata.Name - } - if err := info.validate(); err != nil { - slog.Warn("invalid skill from builtin", "name", info.Name, "error", err) - continue - } - skills = append(skills, info) - } - } - } - } - } + // Priority: workspace > global > builtin + addSkills(sl.workspaceSkills, "workspace") + addSkills(sl.globalSkills, "global") + addSkills(sl.builtinSkills, "builtin") return skills } diff --git a/pkg/skills/loader_test.go b/pkg/skills/loader_test.go index aca901d33..9428bea62 100644 --- a/pkg/skills/loader_test.go +++ b/pkg/skills/loader_test.go @@ -1,9 +1,12 @@ package skills import ( + "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSkillsInfoValidate(t *testing.T) { @@ -135,6 +138,134 @@ func TestExtractFrontmatter(t *testing.T) { } } +// createSkillDir creates a skill directory with a SKILL.md file containing the given frontmatter. +func createSkillDir(t *testing.T, base, dirName, name, description string) { + t.Helper() + dir := filepath.Join(base, dirName) + require.NoError(t, os.MkdirAll(dir, 0o755)) + content := "---\nname: " + name + "\ndescription: " + description + "\n---\n\n# " + name + require.NoError(t, os.WriteFile(filepath.Join(dir, "SKILL.md"), []byte(content), 0o644)) +} + +func TestListSkillsWorkspaceOverridesGlobal(t *testing.T) { + tmp := t.TempDir() + ws := filepath.Join(tmp, "workspace") + global := filepath.Join(tmp, "global") + + createSkillDir(t, filepath.Join(ws, "skills"), "my-skill", "my-skill", "workspace version") + createSkillDir(t, global, "my-skill", "my-skill", "global version") + + sl := NewSkillsLoader(ws, global, "") + skills := sl.ListSkills() + + assert.Len(t, skills, 1) + assert.Equal(t, "workspace", skills[0].Source) + assert.Equal(t, "workspace version", skills[0].Description) +} + +func TestListSkillsGlobalOverridesBuiltin(t *testing.T) { + tmp := t.TempDir() + ws := filepath.Join(tmp, "workspace") + global := filepath.Join(tmp, "global") + builtin := filepath.Join(tmp, "builtin") + + createSkillDir(t, global, "my-skill", "my-skill", "global version") + createSkillDir(t, builtin, "my-skill", "my-skill", "builtin version") + + sl := NewSkillsLoader(ws, global, builtin) + skills := sl.ListSkills() + + assert.Len(t, skills, 1) + assert.Equal(t, "global", skills[0].Source) + assert.Equal(t, "global version", skills[0].Description) +} + +func TestListSkillsMetadataNameDedup(t *testing.T) { + tmp := t.TempDir() + ws := filepath.Join(tmp, "workspace") + global := filepath.Join(tmp, "global") + + // Different directory names but same metadata name + createSkillDir(t, filepath.Join(ws, "skills"), "dir-a", "shared-name", "workspace version") + createSkillDir(t, global, "dir-b", "shared-name", "global version") + + sl := NewSkillsLoader(ws, global, "") + skills := sl.ListSkills() + + assert.Len(t, skills, 1) + assert.Equal(t, "shared-name", skills[0].Name) + assert.Equal(t, "workspace", skills[0].Source) +} + +func TestListSkillsMultipleDistinctSkills(t *testing.T) { + tmp := t.TempDir() + ws := filepath.Join(tmp, "workspace") + global := filepath.Join(tmp, "global") + builtin := filepath.Join(tmp, "builtin") + + createSkillDir(t, filepath.Join(ws, "skills"), "skill-a", "skill-a", "desc a") + createSkillDir(t, global, "skill-b", "skill-b", "desc b") + createSkillDir(t, builtin, "skill-c", "skill-c", "desc c") + + sl := NewSkillsLoader(ws, global, builtin) + skills := sl.ListSkills() + + assert.Len(t, skills, 3) + names := map[string]string{} + for _, s := range skills { + names[s.Name] = s.Source + } + assert.Equal(t, "workspace", names["skill-a"]) + assert.Equal(t, "global", names["skill-b"]) + assert.Equal(t, "builtin", names["skill-c"]) +} + +func TestListSkillsInvalidSkillSkipped(t *testing.T) { + tmp := t.TempDir() + ws := filepath.Join(tmp, "workspace") + global := filepath.Join(tmp, "global") + + // Invalid name (underscore) + createSkillDir(t, filepath.Join(ws, "skills"), "bad_skill", "bad_skill", "desc") + // Valid skill + createSkillDir(t, global, "good-skill", "good-skill", "desc") + + sl := NewSkillsLoader(ws, global, "") + skills := sl.ListSkills() + + assert.Len(t, skills, 1) + assert.Equal(t, "good-skill", skills[0].Name) +} + +func TestListSkillsEmptyAndNonexistentDirs(t *testing.T) { + tmp := t.TempDir() + ws := filepath.Join(tmp, "workspace") + emptyDir := filepath.Join(tmp, "empty") + require.NoError(t, os.MkdirAll(emptyDir, 0o755)) + + sl := NewSkillsLoader(ws, emptyDir, filepath.Join(tmp, "nonexistent")) + skills := sl.ListSkills() + + assert.Empty(t, skills) +} + +func TestListSkillsDirWithoutSkillMD(t *testing.T) { + tmp := t.TempDir() + ws := filepath.Join(tmp, "workspace") + global := filepath.Join(tmp, "global") + + // Directory exists but has no SKILL.md + require.NoError(t, os.MkdirAll(filepath.Join(global, "no-skillmd"), 0o755)) + // Valid skill alongside + createSkillDir(t, global, "real-skill", "real-skill", "desc") + + sl := NewSkillsLoader(ws, global, "") + skills := sl.ListSkills() + + assert.Len(t, skills, 1) + assert.Equal(t, "real-skill", skills[0].Name) +} + func TestStripFrontmatter(t *testing.T) { sl := &SkillsLoader{} From 6fb61539d779dd155ba82422fe7d0f1094f0893e Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Tue, 24 Feb 2026 10:27:49 +1100 Subject: [PATCH 09/55] translate Chinese comments Signed-off-by: Kai Xia --- cmd/picoclaw/main.go | 2 +- pkg/channels/qq.go | 46 ++++++++++++++++++++-------------------- pkg/channels/slack.go | 6 +++--- pkg/channels/telegram.go | 6 +++--- pkg/skills/loader.go | 12 +++++------ 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index 1e4b393f8..25ad701ca 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -131,7 +131,7 @@ func main() { workspace := cfg.WorkspacePath() installer := skills.NewSkillInstaller(workspace) - // 获取全局配置目录和内置 skills 目录 + // get global config directory and builtin skills directory globalDir := filepath.Dir(getConfigPath()) globalSkillsDir := filepath.Join(globalDir, "skills") builtinSkillsDir := filepath.Join(globalDir, "picoclaw", "skills") diff --git a/pkg/channels/qq.go b/pkg/channels/qq.go index e66cac533..b10776db6 100644 --- a/pkg/channels/qq.go +++ b/pkg/channels/qq.go @@ -47,31 +47,31 @@ func (c *QQChannel) Start(ctx context.Context) error { logger.InfoC("qq", "Starting QQ bot (WebSocket mode)") - // 创建 token source + // create token source credentials := &token.QQBotCredentials{ AppID: c.config.AppID, AppSecret: c.config.AppSecret, } c.tokenSource = token.NewQQBotTokenSource(credentials) - // 创建子 context + // create child context c.ctx, c.cancel = context.WithCancel(ctx) - // 启动自动刷新 token 协程 + // start auto-refresh token goroutine if err := token.StartRefreshAccessToken(c.ctx, c.tokenSource); err != nil { return fmt.Errorf("failed to start token refresh: %w", err) } - // 初始化 OpenAPI 客户端 + // initialize OpenAPI client c.api = botgo.NewOpenAPI(c.config.AppID, c.tokenSource).WithTimeout(5 * time.Second) - // 注册事件处理器 + // register event handlers intent := event.RegisterHandlers( c.handleC2CMessage(), c.handleGroupATMessage(), ) - // 获取 WebSocket 接入点 + // get WebSocket endpoint wsInfo, err := c.api.WS(c.ctx, nil, "") if err != nil { return fmt.Errorf("failed to get websocket info: %w", err) @@ -81,10 +81,10 @@ func (c *QQChannel) Start(ctx context.Context) error { "shards": wsInfo.Shards, }) - // 创建并保存 sessionManager + // create and save sessionManager c.sessionManager = botgo.NewSessionManager() - // 在 goroutine 中启动 WebSocket 连接,避免阻塞 + // start WebSocket connection in goroutine to avoid blocking go func() { if err := c.sessionManager.Start(wsInfo, c.tokenSource, &intent); err != nil { logger.ErrorCF("qq", "WebSocket session error", map[string]any{ @@ -116,12 +116,12 @@ func (c *QQChannel) Send(ctx context.Context, msg bus.OutboundMessage) error { return fmt.Errorf("QQ bot not running") } - // 构造消息 + // construct message msgToCreate := &dto.MessageToCreate{ Content: msg.Content, } - // C2C 消息发送 + // send C2C message _, err := c.api.PostC2CMessage(ctx, msg.ChatID, msgToCreate) if err != nil { logger.ErrorCF("qq", "Failed to send C2C message", map[string]any{ @@ -133,15 +133,15 @@ func (c *QQChannel) Send(ctx context.Context, msg bus.OutboundMessage) error { return nil } -// handleC2CMessage 处理 QQ 私聊消息 +// handleC2CMessage handles QQ private messages func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler { return func(event *dto.WSPayload, data *dto.WSC2CMessageData) error { - // 去重检查 + // deduplication check if c.isDuplicate(data.ID) { return nil } - // 提取用户信息 + // extract user info var senderID string if data.Author != nil && data.Author.ID != "" { senderID = data.Author.ID @@ -150,7 +150,7 @@ func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler { return nil } - // 提取消息内容 + // extract message content content := data.Content if content == "" { logger.DebugC("qq", "Received empty message, ignoring") @@ -162,7 +162,7 @@ func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler { "length": len(content), }) - // 转发到消息总线 + // forward to message bus metadata := map[string]string{ "message_id": data.ID, "peer_kind": "direct", @@ -175,15 +175,15 @@ func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler { } } -// handleGroupATMessage 处理群@消息 +// handleGroupATMessage handles group @messages func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler { return func(event *dto.WSPayload, data *dto.WSGroupATMessageData) error { - // 去重检查 + // deduplication check if c.isDuplicate(data.ID) { return nil } - // 提取用户信息 + // extract user info var senderID string if data.Author != nil && data.Author.ID != "" { senderID = data.Author.ID @@ -192,7 +192,7 @@ func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler { return nil } - // 提取消息内容(去掉 @ 机器人部分) + // extract message content (remove @bot part) content := data.Content if content == "" { logger.DebugC("qq", "Received empty group message, ignoring") @@ -205,7 +205,7 @@ func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler { "length": len(content), }) - // 转发到消息总线(使用 GroupID 作为 ChatID) + // forward to message bus (use GroupID as ChatID) metadata := map[string]string{ "message_id": data.ID, "group_id": data.GroupID, @@ -219,7 +219,7 @@ func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler { } } -// isDuplicate 检查消息是否重复 +// isDuplicate checks if message is duplicate func (c *QQChannel) isDuplicate(messageID string) bool { c.mu.Lock() defer c.mu.Unlock() @@ -230,9 +230,9 @@ func (c *QQChannel) isDuplicate(messageID string) bool { c.processedIDs[messageID] = true - // 简单清理:限制 map 大小 + // simple cleanup: limit map size if len(c.processedIDs) > 10000 { - // 清空一半 + // clear half count := 0 for id := range c.processedIDs { if count >= 5000 { diff --git a/pkg/channels/slack.go b/pkg/channels/slack.go index f7359cd6d..f087aa8da 100644 --- a/pkg/channels/slack.go +++ b/pkg/channels/slack.go @@ -200,7 +200,7 @@ func (c *SlackChannel) handleMessageEvent(ev *slackevents.MessageEvent) { return } - // 检查白名单,避免为被拒绝的用户下载附件 + // check allowlist to avoid downloading attachments for rejected users if !c.IsAllowed(ev.User) { logger.DebugCF("slack", "Message rejected by allowlist", map[string]any{ "user_id": ev.User, @@ -232,9 +232,9 @@ func (c *SlackChannel) handleMessageEvent(ev *slackevents.MessageEvent) { content = c.stripBotMention(content) var mediaPaths []string - localFiles := []string{} // 跟踪需要清理的本地文件 + localFiles := []string{} // track local files that need cleanup - // 确保临时文件在函数返回时被清理 + // ensure temp files are cleaned up when function returns defer func() { for _, file := range localFiles { if err := os.Remove(file); err != nil { diff --git a/pkg/channels/telegram.go b/pkg/channels/telegram.go index a0a1c8d0a..5cd51e8bc 100644 --- a/pkg/channels/telegram.go +++ b/pkg/channels/telegram.go @@ -208,7 +208,7 @@ func (c *TelegramChannel) handleMessage(ctx context.Context, message *telego.Mes senderID = fmt.Sprintf("%d|%s", user.ID, user.Username) } - // 检查白名单,避免为被拒绝的用户下载附件 + // check allowlist to avoid downloading attachments for rejected users if !c.IsAllowed(senderID) { logger.DebugCF("telegram", "Message rejected by allowlist", map[string]any{ "user_id": senderID, @@ -221,9 +221,9 @@ func (c *TelegramChannel) handleMessage(ctx context.Context, message *telego.Mes content := "" mediaPaths := []string{} - localFiles := []string{} // 跟踪需要清理的本地文件 + localFiles := []string{} // track local files that need cleanup - // 确保临时文件在函数返回时被清理 + // ensure temp files are cleaned up when function returns defer func() { for _, file := range localFiles { if err := os.Remove(file); err != nil { diff --git a/pkg/skills/loader.go b/pkg/skills/loader.go index f4f55a698..5749d8983 100644 --- a/pkg/skills/loader.go +++ b/pkg/skills/loader.go @@ -55,9 +55,9 @@ func (info SkillInfo) validate() error { type SkillsLoader struct { workspace string - workspaceSkills string // workspace skills (项目级别) - globalSkills string // 全局 skills (~/.picoclaw/skills) - builtinSkills string // 内置 skills + workspaceSkills string // workspace skills (project-level) + globalSkills string // global skills (~/.picoclaw/skills) + builtinSkills string // builtin skills } func NewSkillsLoader(workspace string, globalSkills string, builtinSkills string) *SkillsLoader { @@ -120,7 +120,7 @@ func (sl *SkillsLoader) ListSkills() []SkillInfo { } func (sl *SkillsLoader) LoadSkill(name string) (string, bool) { - // 1. 优先从 workspace skills 加载(项目级别) + // 1. load from workspace skills first (project-level) if sl.workspaceSkills != "" { skillFile := filepath.Join(sl.workspaceSkills, name, "SKILL.md") if content, err := os.ReadFile(skillFile); err == nil { @@ -128,7 +128,7 @@ func (sl *SkillsLoader) LoadSkill(name string) (string, bool) { } } - // 2. 其次从全局 skills 加载 (~/.picoclaw/skills) + // 2. then load from global skills (~/.picoclaw/skills) if sl.globalSkills != "" { skillFile := filepath.Join(sl.globalSkills, name, "SKILL.md") if content, err := os.ReadFile(skillFile); err == nil { @@ -136,7 +136,7 @@ func (sl *SkillsLoader) LoadSkill(name string) (string, bool) { } } - // 3. 最后从内置 skills 加载 + // 3. finally load from builtin skills if sl.builtinSkills != "" { skillFile := filepath.Join(sl.builtinSkills, name, "SKILL.md") if content, err := os.ReadFile(skillFile); err == nil { From 0434b49e8d9f85ae52b9b68efddd1147afd54d30 Mon Sep 17 00:00:00 2001 From: Guoguo <16666742+imguoguo@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:58:54 +0800 Subject: [PATCH 10/55] docs: update wechat qrcode (#705) --- assets/wechat.png | Bin 144045 -> 150574 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/wechat.png b/assets/wechat.png index a34217c335542a13aace2103bd15ccebf94acde2..e30c34e4ed81210338d63ee4486c4356d01ae30b 100644 GIT binary patch literal 150574 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 [中文](README.zh.md) | [日本語](README.ja.md) | [Português](README.pt-br.md) | [Tiếng Việt](README.vi.md) | [Français](README.fr.md) | **English** From 76f2b42d5b88bebec2a247b180cf1f19bc69464c Mon Sep 17 00:00:00 2001 From: nayihz Date: Tue, 24 Feb 2026 17:16:16 +0800 Subject: [PATCH 12/55] feat: improve web proxy handling and coverage --- config/config.example.json | 3 +- pkg/agent/loop.go | 3 +- pkg/config/config.go | 3 + pkg/config/config_test.go | 21 +++++ pkg/tools/web.go | 101 +++++++++++++++++----- pkg/tools/web_test.go | 167 +++++++++++++++++++++++++++++++++++++ 6 files changed, 275 insertions(+), 23 deletions(-) diff --git a/config/config.example.json b/config/config.example.json index 555509732..c73d327d6 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -217,7 +217,8 @@ "enabled": false, "api_key": "pplx-xxx", "max_results": 5 - } + }, + "proxy": "" }, "cron": { "exec_timeout_minutes": 5 diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 9a2bb1198..dbc4a9b87 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -106,10 +106,11 @@ func registerSharedTools( PerplexityAPIKey: cfg.Tools.Web.Perplexity.APIKey, PerplexityMaxResults: cfg.Tools.Web.Perplexity.MaxResults, PerplexityEnabled: cfg.Tools.Web.Perplexity.Enabled, + Proxy: cfg.Tools.Web.Proxy, }); searchTool != nil { agent.Tools.Register(searchTool) } - agent.Tools.Register(tools.NewWebFetchTool(50000)) + agent.Tools.Register(tools.NewWebFetchToolWithProxy(50000, cfg.Tools.Web.Proxy)) // Hardware tools (I2C, SPI) - Linux only, returns error on other platforms agent.Tools.Register(tools.NewI2CTool()) diff --git a/pkg/config/config.go b/pkg/config/config.go index 2595398c7..67adca5c3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -443,6 +443,9 @@ type WebToolsConfig struct { Tavily TavilyConfig `json:"tavily"` DuckDuckGo DuckDuckGoConfig `json:"duckduckgo"` Perplexity PerplexityConfig `json:"perplexity"` + // Proxy is an optional proxy URL for web tools (http/https/socks5/socks5h). + // For authenticated proxies, prefer HTTP_PROXY/HTTPS_PROXY env vars instead of embedding credentials in config. + Proxy string `json:"proxy,omitempty" env:"PICOCLAW_TOOLS_WEB_PROXY"` } type CronToolsConfig struct { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index f88c0269c..223ac798d 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -392,3 +392,24 @@ func TestLoadConfig_OpenAIWebSearchCanBeDisabled(t *testing.T) { t.Fatal("OpenAI codex web search should be false when disabled in config file") } } + +func TestLoadConfig_WebToolsProxy(t *testing.T) { + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "config.json") + configJSON := `{ + "agents": {"defaults":{"workspace":"./workspace","model":"gpt4","max_tokens":8192,"max_tool_iterations":20}}, + "model_list": [{"model_name":"gpt4","model":"openai/gpt-5.2","api_key":"x"}], + "tools": {"web":{"proxy":"http://127.0.0.1:7890"}} +}` + if err := os.WriteFile(configPath, []byte(configJSON), 0o600); err != nil { + t.Fatalf("os.WriteFile() error: %v", err) + } + + cfg, err := LoadConfig(configPath) + if err != nil { + t.Fatalf("LoadConfig() error: %v", err) + } + if cfg.Tools.Web.Proxy != "http://127.0.0.1:7890" { + t.Fatalf("Tools.Web.Proxy = %q, want %q", cfg.Tools.Web.Proxy, "http://127.0.0.1:7890") + } +} diff --git a/pkg/tools/web.go b/pkg/tools/web.go index 452e95e0f..968579dea 100644 --- a/pkg/tools/web.go +++ b/pkg/tools/web.go @@ -17,12 +17,50 @@ const ( userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" ) +// createHTTPClient creates an HTTP client with optional proxy support +func createHTTPClient(proxyURL string, timeout time.Duration) (*http.Client, error) { + client := &http.Client{ + Timeout: timeout, + Transport: &http.Transport{ + MaxIdleConns: 10, + IdleConnTimeout: 30 * time.Second, + DisableCompression: false, + TLSHandshakeTimeout: 15 * time.Second, + }, + } + + if proxyURL != "" { + proxy, err := url.Parse(proxyURL) + if err != nil { + return nil, fmt.Errorf("invalid proxy URL: %w", err) + } + scheme := strings.ToLower(proxy.Scheme) + switch scheme { + case "http", "https", "socks5", "socks5h": + default: + return nil, fmt.Errorf( + "unsupported proxy scheme %q (supported: http, https, socks5, socks5h)", + proxy.Scheme, + ) + } + if proxy.Host == "" { + return nil, fmt.Errorf("invalid proxy URL: missing host") + } + client.Transport.(*http.Transport).Proxy = http.ProxyURL(proxy) + } else { + client.Transport.(*http.Transport).Proxy = http.ProxyFromEnvironment + } + + return client, nil +} + type SearchProvider interface { Search(ctx context.Context, query string, count int) (string, error) } type BraveSearchProvider struct { apiKey string + proxy string } func (p *BraveSearchProvider) Search(ctx context.Context, query string, count int) (string, error) { @@ -37,7 +75,10 @@ func (p *BraveSearchProvider) Search(ctx context.Context, query string, count in req.Header.Set("Accept", "application/json") req.Header.Set("X-Subscription-Token", p.apiKey) - client := &http.Client{Timeout: 10 * time.Second} + client, err := createHTTPClient(p.proxy, 10*time.Second) + if err != nil { + return "", fmt.Errorf("failed to create HTTP client: %w", err) + } resp, err := client.Do(req) if err != nil { return "", fmt.Errorf("request failed: %w", err) @@ -167,7 +208,9 @@ func (p *TavilySearchProvider) Search(ctx context.Context, query string, count i return strings.Join(lines, "\n"), nil } -type DuckDuckGoSearchProvider struct{} +type DuckDuckGoSearchProvider struct { + proxy string +} func (p *DuckDuckGoSearchProvider) Search(ctx context.Context, query string, count int) (string, error) { searchURL := fmt.Sprintf("https://html.duckduckgo.com/html/?q=%s", url.QueryEscape(query)) @@ -179,7 +222,10 @@ func (p *DuckDuckGoSearchProvider) Search(ctx context.Context, query string, cou req.Header.Set("User-Agent", userAgent) - client := &http.Client{Timeout: 10 * time.Second} + client, err := createHTTPClient(p.proxy, 10*time.Second) + if err != nil { + return "", fmt.Errorf("failed to create HTTP client: %w", err) + } resp, err := client.Do(req) if err != nil { return "", fmt.Errorf("request failed: %w", err) @@ -261,6 +307,7 @@ func stripTags(content string) string { type PerplexitySearchProvider struct { apiKey string + proxy string } func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, count int) (string, error) { @@ -295,7 +342,10 @@ func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, cou req.Header.Set("Authorization", "Bearer "+p.apiKey) req.Header.Set("User-Agent", userAgent) - client := &http.Client{Timeout: 30 * time.Second} + client, err := createHTTPClient(p.proxy, 30*time.Second) + if err != nil { + return "", fmt.Errorf("failed to create HTTP client: %w", err) + } resp, err := client.Do(req) if err != nil { return "", fmt.Errorf("request failed: %w", err) @@ -348,6 +398,7 @@ type WebSearchToolOptions struct { PerplexityAPIKey string PerplexityMaxResults int PerplexityEnabled bool + Proxy string } func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool { @@ -356,12 +407,12 @@ func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool { // Priority: Perplexity > Brave > Tavily > DuckDuckGo if opts.PerplexityEnabled && opts.PerplexityAPIKey != "" { - provider = &PerplexitySearchProvider{apiKey: opts.PerplexityAPIKey} + provider = &PerplexitySearchProvider{apiKey: opts.PerplexityAPIKey, proxy: opts.Proxy} if opts.PerplexityMaxResults > 0 { maxResults = opts.PerplexityMaxResults } } else if opts.BraveEnabled && opts.BraveAPIKey != "" { - provider = &BraveSearchProvider{apiKey: opts.BraveAPIKey} + provider = &BraveSearchProvider{apiKey: opts.BraveAPIKey, proxy: opts.Proxy} if opts.BraveMaxResults > 0 { maxResults = opts.BraveMaxResults } @@ -374,7 +425,7 @@ func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool { maxResults = opts.TavilyMaxResults } } else if opts.DuckDuckGoEnabled { - provider = &DuckDuckGoSearchProvider{} + provider = &DuckDuckGoSearchProvider{proxy: opts.Proxy} if opts.DuckDuckGoMaxResults > 0 { maxResults = opts.DuckDuckGoMaxResults } @@ -441,6 +492,7 @@ func (t *WebSearchTool) Execute(ctx context.Context, args map[string]any) *ToolR type WebFetchTool struct { maxChars int + proxy string } func NewWebFetchTool(maxChars int) *WebFetchTool { @@ -452,6 +504,16 @@ func NewWebFetchTool(maxChars int) *WebFetchTool { } } +func NewWebFetchToolWithProxy(maxChars int, proxy string) *WebFetchTool { + if maxChars <= 0 { + maxChars = 50000 + } + return &WebFetchTool{ + maxChars: maxChars, + proxy: proxy, + } +} + func (t *WebFetchTool) Name() string { return "web_fetch" } @@ -511,20 +573,17 @@ func (t *WebFetchTool) Execute(ctx context.Context, args map[string]any) *ToolRe req.Header.Set("User-Agent", userAgent) - client := &http.Client{ - Timeout: 60 * time.Second, - Transport: &http.Transport{ - MaxIdleConns: 10, - IdleConnTimeout: 30 * time.Second, - DisableCompression: false, - TLSHandshakeTimeout: 15 * time.Second, - }, - CheckRedirect: func(req *http.Request, via []*http.Request) error { - if len(via) >= 5 { - return fmt.Errorf("stopped after 5 redirects") - } - return nil - }, + client, err := createHTTPClient(t.proxy, 60*time.Second) + if err != nil { + return ErrorResult(fmt.Sprintf("failed to create HTTP client: %v", err)) + } + + // Configure redirect handling + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if len(via) >= 5 { + return fmt.Errorf("stopped after 5 redirects") + } + return nil } resp, err := client.Do(req) diff --git a/pkg/tools/web_test.go b/pkg/tools/web_test.go index 75e0d8d16..2cd79eb24 100644 --- a/pkg/tools/web_test.go +++ b/pkg/tools/web_test.go @@ -7,6 +7,7 @@ import ( "net/http/httptest" "strings" "testing" + "time" ) // TestWebTool_WebFetch_Success verifies successful URL fetching @@ -334,6 +335,172 @@ func TestWebTool_WebFetch_MissingDomain(t *testing.T) { } } +func TestCreateHTTPClient_ProxyConfigured(t *testing.T) { + client, err := createHTTPClient("http://127.0.0.1:7890", 12*time.Second) + if err != nil { + t.Fatalf("createHTTPClient() error: %v", err) + } + if client.Timeout != 12*time.Second { + t.Fatalf("client.Timeout = %v, want %v", client.Timeout, 12*time.Second) + } + + tr, ok := client.Transport.(*http.Transport) + if !ok { + t.Fatalf("client.Transport type = %T, want *http.Transport", client.Transport) + } + if tr.Proxy == nil { + t.Fatal("transport.Proxy is nil, want non-nil") + } + + req, err := http.NewRequest("GET", "https://example.com", nil) + if err != nil { + t.Fatalf("http.NewRequest() error: %v", err) + } + proxyURL, err := tr.Proxy(req) + if err != nil { + t.Fatalf("transport.Proxy(req) error: %v", err) + } + if proxyURL == nil || proxyURL.String() != "http://127.0.0.1:7890" { + t.Fatalf("proxy URL = %v, want %q", proxyURL, "http://127.0.0.1:7890") + } +} + +func TestCreateHTTPClient_InvalidProxy(t *testing.T) { + _, err := createHTTPClient("://bad-proxy", 10*time.Second) + if err == nil { + t.Fatal("createHTTPClient() expected error for invalid proxy URL, got nil") + } +} + +func TestCreateHTTPClient_Socks5ProxyConfigured(t *testing.T) { + client, err := createHTTPClient("socks5://127.0.0.1:1080", 8*time.Second) + if err != nil { + t.Fatalf("createHTTPClient() error: %v", err) + } + + tr, ok := client.Transport.(*http.Transport) + if !ok { + t.Fatalf("client.Transport type = %T, want *http.Transport", client.Transport) + } + req, err := http.NewRequest("GET", "https://example.com", nil) + if err != nil { + t.Fatalf("http.NewRequest() error: %v", err) + } + proxyURL, err := tr.Proxy(req) + if err != nil { + t.Fatalf("transport.Proxy(req) error: %v", err) + } + if proxyURL == nil || proxyURL.String() != "socks5://127.0.0.1:1080" { + t.Fatalf("proxy URL = %v, want %q", proxyURL, "socks5://127.0.0.1:1080") + } +} + +func TestCreateHTTPClient_UnsupportedProxyScheme(t *testing.T) { + _, err := createHTTPClient("ftp://127.0.0.1:21", 10*time.Second) + if err == nil { + t.Fatal("createHTTPClient() expected error for unsupported scheme, got nil") + } + if !strings.Contains(err.Error(), "unsupported proxy scheme") { + t.Fatalf("error = %q, want to contain %q", err.Error(), "unsupported proxy scheme") + } +} + +func TestCreateHTTPClient_ProxyFromEnvironmentWhenConfigEmpty(t *testing.T) { + t.Setenv("HTTP_PROXY", "http://127.0.0.1:8888") + t.Setenv("http_proxy", "http://127.0.0.1:8888") + t.Setenv("HTTPS_PROXY", "http://127.0.0.1:8888") + t.Setenv("https_proxy", "http://127.0.0.1:8888") + t.Setenv("ALL_PROXY", "") + t.Setenv("all_proxy", "") + t.Setenv("NO_PROXY", "") + t.Setenv("no_proxy", "") + + client, err := createHTTPClient("", 10*time.Second) + if err != nil { + t.Fatalf("createHTTPClient() error: %v", err) + } + + tr, ok := client.Transport.(*http.Transport) + if !ok { + t.Fatalf("client.Transport type = %T, want *http.Transport", client.Transport) + } + if tr.Proxy == nil { + t.Fatal("transport.Proxy is nil, want proxy function from environment") + } + + req, err := http.NewRequest("GET", "https://example.com", nil) + if err != nil { + t.Fatalf("http.NewRequest() error: %v", err) + } + if _, err := tr.Proxy(req); err != nil { + t.Fatalf("transport.Proxy(req) error: %v", err) + } +} + +func TestNewWebFetchToolWithProxy(t *testing.T) { + tool := NewWebFetchToolWithProxy(1024, "http://127.0.0.1:7890") + if tool.maxChars != 1024 { + t.Fatalf("maxChars = %d, want %d", tool.maxChars, 1024) + } + if tool.proxy != "http://127.0.0.1:7890" { + t.Fatalf("proxy = %q, want %q", tool.proxy, "http://127.0.0.1:7890") + } + + tool = NewWebFetchToolWithProxy(0, "http://127.0.0.1:7890") + if tool.maxChars != 50000 { + t.Fatalf("default maxChars = %d, want %d", tool.maxChars, 50000) + } +} + +func TestNewWebSearchTool_PropagatesProxy(t *testing.T) { + t.Run("perplexity", func(t *testing.T) { + tool := NewWebSearchTool(WebSearchToolOptions{ + PerplexityEnabled: true, + PerplexityAPIKey: "k", + PerplexityMaxResults: 3, + Proxy: "http://127.0.0.1:7890", + }) + p, ok := tool.provider.(*PerplexitySearchProvider) + if !ok { + t.Fatalf("provider type = %T, want *PerplexitySearchProvider", tool.provider) + } + if p.proxy != "http://127.0.0.1:7890" { + t.Fatalf("provider proxy = %q, want %q", p.proxy, "http://127.0.0.1:7890") + } + }) + + t.Run("brave", func(t *testing.T) { + tool := NewWebSearchTool(WebSearchToolOptions{ + BraveEnabled: true, + BraveAPIKey: "k", + BraveMaxResults: 3, + Proxy: "http://127.0.0.1:7890", + }) + p, ok := tool.provider.(*BraveSearchProvider) + if !ok { + t.Fatalf("provider type = %T, want *BraveSearchProvider", tool.provider) + } + if p.proxy != "http://127.0.0.1:7890" { + t.Fatalf("provider proxy = %q, want %q", p.proxy, "http://127.0.0.1:7890") + } + }) + + t.Run("duckduckgo", func(t *testing.T) { + tool := NewWebSearchTool(WebSearchToolOptions{ + DuckDuckGoEnabled: true, + DuckDuckGoMaxResults: 3, + Proxy: "http://127.0.0.1:7890", + }) + p, ok := tool.provider.(*DuckDuckGoSearchProvider) + if !ok { + t.Fatalf("provider type = %T, want *DuckDuckGoSearchProvider", tool.provider) + } + if p.proxy != "http://127.0.0.1:7890" { + t.Fatalf("provider proxy = %q, want %q", p.proxy, "http://127.0.0.1:7890") + } + }) +} + // TestWebTool_TavilySearch_Success verifies successful Tavily search func TestWebTool_TavilySearch_Success(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { From 8405d390dfaca26fba80fd63728d5f87353e1b92 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 24 Feb 2026 04:19:18 -0500 Subject: [PATCH 13/55] fix: add CGO_ENABLED=0 for static build to fix cross-platform GLIBC errors --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 29e2fc964..111908a79 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ GO_VERSION=$(shell $(GO) version | awk '{print $$3}') LDFLAGS=-ldflags "-X main.version=$(VERSION) -X main.gitCommit=$(GIT_COMMIT) -X main.buildTime=$(BUILD_TIME) -X main.goVersion=$(GO_VERSION) -s -w" # Go variables -GO?=go +GO?=CGO_ENABLED=0 go GOFLAGS?=-v -tags stdjson # Golangci-lint From 0d761ca6084efb1344591870ce58d96b6a9be051 Mon Sep 17 00:00:00 2001 From: yangmanqing Date: Tue, 24 Feb 2026 17:57:28 +0800 Subject: [PATCH 14/55] fix: prevent DefaultConfig template values from leaking into user model_list entries --- pkg/config/config.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/config/config.go b/pkg/config/config.go index 2595398c7..a15a19b91 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -499,6 +499,20 @@ func LoadConfig(path string) (*Config, error) { return nil, err } + // Pre-scan the JSON to check how many model_list entries the user provided. + // Go's JSON decoder reuses existing slice backing-array elements rather than + // zero-initializing them, so fields absent from the user's JSON (e.g. api_base) + // would silently inherit values from the DefaultConfig template at the same + // index position. We only reset cfg.ModelList when the user actually provides + // entries; when count is 0 we keep DefaultConfig's built-in list as fallback. + var tmp Config + if err := json.Unmarshal(data, &tmp); err != nil { + return nil, err + } + if len(tmp.ModelList) > 0 { + cfg.ModelList = nil + } + if err := json.Unmarshal(data, cfg); err != nil { return nil, err } From 78e5bdad29c9c927b72b99b40b3da87d5dc28431 Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Tue, 24 Feb 2026 22:04:23 +1100 Subject: [PATCH 15/55] minor improvements in Makefile Signed-off-by: Kai Xia --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 29e2fc964..30522e7b9 100644 --- a/Makefile +++ b/Makefile @@ -144,6 +144,10 @@ fmt: lint: @$(GOLANGCI_LINT) run +## fix: Fix linting issues +fix: + @$(GOLANGCI_LINT) run --fix + ## deps: Download dependencies deps: @$(GO) mod download @@ -169,7 +173,7 @@ help: @echo " make [target]" @echo "" @echo "Targets:" - @grep -E '^## ' $(MAKEFILE_LIST) | sed 's/## / /' + @grep -E '^## ' $(MAKEFILE_LIST) | sort | awk -F': ' '{printf " %-16s %s\n", substr($$1, 4), $$2}' @echo "" @echo "Examples:" @echo " make build # Build for current platform" From 01e2354b977d580679871379beef24f371bf521e Mon Sep 17 00:00:00 2001 From: yinwm Date: Tue, 24 Feb 2026 19:04:38 +0800 Subject: [PATCH 16/55] fix: align map values for proper formatting --- pkg/config/model_config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/model_config_test.go b/pkg/config/model_config_test.go index c89029e8c..99eea2782 100644 --- a/pkg/config/model_config_test.go +++ b/pkg/config/model_config_test.go @@ -220,7 +220,7 @@ func TestFullConfig_JSON_BackwardCompat(t *testing.T) { }` for name, jsonStr := range map[string]string{ - "old format (model)": oldFormat, + "old format (model)": oldFormat, "new format (model_name)": newFormat, } { t.Run(name, func(t *testing.T) { From b47a39af9cbbdf9cdc0ebe2a9ed3607c9d260596 Mon Sep 17 00:00:00 2001 From: winterfx Date: Tue, 24 Feb 2026 21:35:15 +0800 Subject: [PATCH 17/55] fix: handle multi-tool-call orphan detection in sanitizeHistoryForProvider Walk backwards over preceding tool messages to find the nearest assistant with ToolCalls, instead of only checking the immediate predecessor. Add unit tests for sanitizeHistoryForProvider covering key edge cases. --- pkg/agent/context.go | 15 ++- pkg/agent/context_test.go | 209 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 pkg/agent/context_test.go diff --git a/pkg/agent/context.go b/pkg/agent/context.go index a9db5afdd..7bd55d4ab 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -229,8 +229,19 @@ func sanitizeHistoryForProvider(history []providers.Message) []providers.Message logger.DebugCF("agent", "Dropping orphaned leading tool message", map[string]any{}) continue } - last := sanitized[len(sanitized)-1] - if last.Role != "assistant" || len(last.ToolCalls) == 0 { + // Walk backwards to find the nearest assistant message, + // skipping over any preceding tool messages (multi-tool-call case). + foundAssistant := false + for i := len(sanitized) - 1; i >= 0; i-- { + if sanitized[i].Role == "tool" { + continue + } + if sanitized[i].Role == "assistant" && len(sanitized[i].ToolCalls) > 0 { + foundAssistant = true + } + break + } + if !foundAssistant { logger.DebugCF("agent", "Dropping orphaned tool message", map[string]any{}) continue } diff --git a/pkg/agent/context_test.go b/pkg/agent/context_test.go new file mode 100644 index 000000000..e023c9c30 --- /dev/null +++ b/pkg/agent/context_test.go @@ -0,0 +1,209 @@ +package agent + +import ( + "testing" + + "github.com/sipeed/picoclaw/pkg/providers" +) + +func msg(role, content string) providers.Message { + return providers.Message{Role: role, Content: content} +} + +func assistantWithTools(toolIDs ...string) providers.Message { + calls := make([]providers.ToolCall, len(toolIDs)) + for i, id := range toolIDs { + calls[i] = providers.ToolCall{ID: id, Type: "function"} + } + return providers.Message{Role: "assistant", ToolCalls: calls} +} + +func toolResult(id string) providers.Message { + return providers.Message{Role: "tool", Content: "result", ToolCallID: id} +} + +func TestSanitizeHistoryForProvider_EmptyHistory(t *testing.T) { + result := sanitizeHistoryForProvider(nil) + if len(result) != 0 { + t.Fatalf("expected empty, got %d messages", len(result)) + } + + result = sanitizeHistoryForProvider([]providers.Message{}) + if len(result) != 0 { + t.Fatalf("expected empty, got %d messages", len(result)) + } +} + +func TestSanitizeHistoryForProvider_SingleToolCall(t *testing.T) { + history := []providers.Message{ + msg("user", "hello"), + assistantWithTools("A"), + toolResult("A"), + msg("assistant", "done"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 4 { + t.Fatalf("expected 4 messages, got %d", len(result)) + } + assertRoles(t, result, "user", "assistant", "tool", "assistant") +} + +func TestSanitizeHistoryForProvider_MultiToolCalls(t *testing.T) { + history := []providers.Message{ + msg("user", "do two things"), + assistantWithTools("A", "B"), + toolResult("A"), + toolResult("B"), + msg("assistant", "both done"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 5 { + t.Fatalf("expected 5 messages, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user", "assistant", "tool", "tool", "assistant") +} + +func TestSanitizeHistoryForProvider_AssistantToolCallAfterPlainAssistant(t *testing.T) { + history := []providers.Message{ + msg("user", "hi"), + msg("assistant", "thinking"), + assistantWithTools("A"), + toolResult("A"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 2 { + t.Fatalf("expected 2 messages, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user", "assistant") +} + +func TestSanitizeHistoryForProvider_OrphanedLeadingTool(t *testing.T) { + history := []providers.Message{ + toolResult("A"), + msg("user", "hello"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 1 { + t.Fatalf("expected 1 message, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user") +} + +func TestSanitizeHistoryForProvider_ToolAfterUserDropped(t *testing.T) { + history := []providers.Message{ + msg("user", "hello"), + toolResult("A"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 1 { + t.Fatalf("expected 1 message, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user") +} + +func TestSanitizeHistoryForProvider_ToolAfterAssistantNoToolCalls(t *testing.T) { + history := []providers.Message{ + msg("user", "hello"), + msg("assistant", "hi"), + toolResult("A"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 2 { + t.Fatalf("expected 2 messages, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user", "assistant") +} + +func TestSanitizeHistoryForProvider_AssistantToolCallAtStart(t *testing.T) { + history := []providers.Message{ + assistantWithTools("A"), + toolResult("A"), + msg("user", "hello"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 1 { + t.Fatalf("expected 1 message, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user") +} + +func TestSanitizeHistoryForProvider_MultiToolCallsThenNewRound(t *testing.T) { + history := []providers.Message{ + msg("user", "do two things"), + assistantWithTools("A", "B"), + toolResult("A"), + toolResult("B"), + msg("assistant", "done"), + msg("user", "hi"), + assistantWithTools("C"), + toolResult("C"), + msg("assistant", "done again"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 9 { + t.Fatalf("expected 9 messages, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user", "assistant", "tool", "tool", "assistant", "user", "assistant", "tool", "assistant") +} + +func TestSanitizeHistoryForProvider_ConsecutiveMultiToolRounds(t *testing.T) { + history := []providers.Message{ + msg("user", "start"), + assistantWithTools("A", "B"), + toolResult("A"), + toolResult("B"), + assistantWithTools("C", "D"), + toolResult("C"), + toolResult("D"), + msg("assistant", "all done"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 8 { + t.Fatalf("expected 8 messages, got %d: %+v", len(result), roles(result)) + } + assertRoles(t, result, "user", "assistant", "tool", "tool", "assistant", "tool", "tool", "assistant") +} + +func TestSanitizeHistoryForProvider_PlainConversation(t *testing.T) { + history := []providers.Message{ + msg("user", "hello"), + msg("assistant", "hi"), + msg("user", "how are you"), + msg("assistant", "fine"), + } + + result := sanitizeHistoryForProvider(history) + if len(result) != 4 { + t.Fatalf("expected 4 messages, got %d", len(result)) + } + assertRoles(t, result, "user", "assistant", "user", "assistant") +} + +func roles(msgs []providers.Message) []string { + r := make([]string, len(msgs)) + for i, m := range msgs { + r[i] = m.Role + } + return r +} + +func assertRoles(t *testing.T, msgs []providers.Message, expected ...string) { + t.Helper() + if len(msgs) != len(expected) { + t.Fatalf("role count mismatch: got %v, want %v", roles(msgs), expected) + } + for i, exp := range expected { + if msgs[i].Role != exp { + t.Errorf("message[%d]: got role %q, want %q", i, msgs[i].Role, exp) + } + } +} From 100356e8ec029f689a6b43363ada3556a2163365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20Xia=28=E5=A4=8F=E6=81=BA=29?= Date: Wed, 25 Feb 2026 00:52:25 +1100 Subject: [PATCH 18/55] refactor: cleanup dead code and turn on dead code detection in CI (#515) * cleanup dead code. Signed-off-by: Kai Xia * add these two back with flag. Signed-off-by: Kai Xia * fix ci Signed-off-by: Kai Xia * remove this confusing line Signed-off-by: Kai Xia * make fmt Signed-off-by: Kai Xia * remove unused method. picked up by golangci-lint run Signed-off-by: Kai Xia --------- Signed-off-by: Kai Xia --- .golangci.yaml | 4 +- pkg/agent/context.go | 19 --------- pkg/channels/wecom_app.go | 55 ------------------------- pkg/devices/sources/usb_linux.go | 5 +-- pkg/providers/antigravity_provider.go | 58 --------------------------- pkg/providers/fallback_test.go | 6 --- pkg/tools/i2c.go | 8 ++++ pkg/tools/spi.go | 4 ++ 8 files changed, 17 insertions(+), 142 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index d45d69e67..dd3cbae19 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -66,7 +66,6 @@ linters: - testifylint - thelper - unparam - - unused - usestdlibvars - usetesting - wastedassign @@ -152,6 +151,9 @@ linters: - gocognit - gocyclo path: _test\.go$ + - linters: + - nolintlint + path: 'pkg/tools/(i2c\.go|spi\.go)$' issues: max-issues-per-linter: 0 diff --git a/pkg/agent/context.go b/pkg/agent/context.go index a9db5afdd..ba07e33d3 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -288,25 +288,6 @@ func (cb *ContextBuilder) AddAssistantMessage( return messages } -func (cb *ContextBuilder) loadSkills() string { - allSkills := cb.skillsLoader.ListSkills() - if len(allSkills) == 0 { - return "" - } - - var skillNames []string - for _, s := range allSkills { - skillNames = append(skillNames, s.Name) - } - - content := cb.skillsLoader.LoadSkillsForContext(skillNames) - if content == "" { - return "" - } - - return "# Skill Definitions\n\n" + content -} - // GetSkillsInfo returns information about loaded skills. func (cb *ContextBuilder) GetSkillsInfo() map[string]any { allSkills := cb.skillsLoader.ListSkills() diff --git a/pkg/channels/wecom_app.go b/pkg/channels/wecom_app.go index 715c48707..302603445 100644 --- a/pkg/channels/wecom_app.go +++ b/pkg/channels/wecom_app.go @@ -571,61 +571,6 @@ func (c *WeComAppChannel) sendTextMessage(ctx context.Context, accessToken, user return nil } -// sendMarkdownMessage sends a markdown message to a user -func (c *WeComAppChannel) sendMarkdownMessage(ctx context.Context, accessToken, userID, content string) error { - apiURL := fmt.Sprintf("%s/cgi-bin/message/send?access_token=%s", wecomAPIBase, accessToken) - - msg := WeComMarkdownMessage{ - ToUser: userID, - MsgType: "markdown", - AgentID: c.config.AgentID, - } - msg.Markdown.Content = content - - jsonData, err := json.Marshal(msg) - if err != nil { - return fmt.Errorf("failed to marshal message: %w", err) - } - - // Use configurable timeout (default 5 seconds) - timeout := c.config.ReplyTimeout - if timeout <= 0 { - timeout = 5 - } - - reqCtx, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second) - defer cancel() - - req, err := http.NewRequestWithContext(reqCtx, http.MethodPost, apiURL, bytes.NewBuffer(jsonData)) - if err != nil { - return fmt.Errorf("failed to create request: %w", err) - } - req.Header.Set("Content-Type", "application/json") - - client := &http.Client{Timeout: time.Duration(timeout) * time.Second} - resp, err := client.Do(req) - if err != nil { - return fmt.Errorf("failed to send message: %w", err) - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("failed to read response: %w", err) - } - - var sendResp WeComSendMessageResponse - if err := json.Unmarshal(body, &sendResp); err != nil { - return fmt.Errorf("failed to parse response: %w", err) - } - - if sendResp.ErrCode != 0 { - return fmt.Errorf("API error: %s (code: %d)", sendResp.ErrMsg, sendResp.ErrCode) - } - - return nil -} - // handleHealth handles health check requests func (c *WeComAppChannel) handleHealth(w http.ResponseWriter, r *http.Request) { status := map[string]any{ diff --git a/pkg/devices/sources/usb_linux.go b/pkg/devices/sources/usb_linux.go index be0193cfb..2bb38941f 100644 --- a/pkg/devices/sources/usb_linux.go +++ b/pkg/devices/sources/usb_linux.go @@ -35,9 +35,8 @@ var usbClassToCapability = map[string]string{ } type USBMonitor struct { - cmd *exec.Cmd - cancel context.CancelFunc - mu sync.Mutex + cmd *exec.Cmd + mu sync.Mutex } func NewUSBMonitor() *USBMonitor { diff --git a/pkg/providers/antigravity_provider.go b/pkg/providers/antigravity_provider.go index cff67c88c..d4ee528b7 100644 --- a/pkg/providers/antigravity_provider.go +++ b/pkg/providers/antigravity_provider.go @@ -404,64 +404,6 @@ type antigravityJSONResponse struct { } `json:"usageMetadata"` } -func (p *AntigravityProvider) parseJSONResponse(body []byte) (*LLMResponse, error) { - var resp antigravityJSONResponse - if err := json.Unmarshal(body, &resp); err != nil { - return nil, fmt.Errorf("parsing antigravity response: %w", err) - } - - if len(resp.Candidates) == 0 { - return nil, fmt.Errorf("antigravity: no candidates in response") - } - - candidate := resp.Candidates[0] - var contentParts []string - var toolCalls []ToolCall - - for _, part := range candidate.Content.Parts { - if part.Text != "" { - contentParts = append(contentParts, part.Text) - } - if part.FunctionCall != nil { - argumentsJSON, _ := json.Marshal(part.FunctionCall.Args) - toolCalls = append(toolCalls, ToolCall{ - ID: fmt.Sprintf("call_%s_%d", part.FunctionCall.Name, time.Now().UnixNano()), - Name: part.FunctionCall.Name, - Arguments: part.FunctionCall.Args, - Function: &FunctionCall{ - Name: part.FunctionCall.Name, - Arguments: string(argumentsJSON), - ThoughtSignature: extractPartThoughtSignature(part.ThoughtSignature, part.ThoughtSignatureSnake), - }, - }) - } - } - - finishReason := "stop" - if len(toolCalls) > 0 { - finishReason = "tool_calls" - } - if candidate.FinishReason == "MAX_TOKENS" { - finishReason = "length" - } - - var usage *UsageInfo - if resp.UsageMetadata.TotalTokenCount > 0 { - usage = &UsageInfo{ - PromptTokens: resp.UsageMetadata.PromptTokenCount, - CompletionTokens: resp.UsageMetadata.CandidatesTokenCount, - TotalTokens: resp.UsageMetadata.TotalTokenCount, - } - } - - return &LLMResponse{ - Content: strings.Join(contentParts, ""), - ToolCalls: toolCalls, - FinishReason: finishReason, - Usage: usage, - }, nil -} - func (p *AntigravityProvider) parseSSEResponse(body string) (*LLMResponse, error) { var contentParts []string var toolCalls []ToolCall diff --git a/pkg/providers/fallback_test.go b/pkg/providers/fallback_test.go index e872c672e..ebba054ef 100644 --- a/pkg/providers/fallback_test.go +++ b/pkg/providers/fallback_test.go @@ -17,12 +17,6 @@ func successRun(content string) func(ctx context.Context, provider, model string } } -func failRun(err error) func(ctx context.Context, provider, model string) (*LLMResponse, error) { - return func(ctx context.Context, provider, model string) (*LLMResponse, error) { - return nil, err - } -} - func TestFallback_SingleCandidate_Success(t *testing.T) { ct := NewCooldownTracker() fc := NewFallbackChain(ct) diff --git a/pkg/tools/i2c.go b/pkg/tools/i2c.go index 0387a26d3..779b1d5a7 100644 --- a/pkg/tools/i2c.go +++ b/pkg/tools/i2c.go @@ -117,13 +117,19 @@ func (t *I2CTool) detect() *ToolResult { return SilentResult(fmt.Sprintf("Found %d I2C bus(es):\n%s", len(buses), string(result))) } +// Helper functions for I2C operations (used by platform-specific implementations) + // isValidBusID checks that a bus identifier is a simple number (prevents path injection) +// +//nolint:unused // Used by i2c_linux.go func isValidBusID(id string) bool { matched, _ := regexp.MatchString(`^\d+$`, id) return matched } // parseI2CAddress extracts and validates an I2C address from args +// +//nolint:unused // Used by i2c_linux.go func parseI2CAddress(args map[string]any) (int, *ToolResult) { addrFloat, ok := args["address"].(float64) if !ok { @@ -137,6 +143,8 @@ func parseI2CAddress(args map[string]any) (int, *ToolResult) { } // parseI2CBus extracts and validates an I2C bus from args +// +//nolint:unused // Used by i2c_linux.go func parseI2CBus(args map[string]any) (string, *ToolResult) { bus, ok := args["bus"].(string) if !ok || bus == "" { diff --git a/pkg/tools/spi.go b/pkg/tools/spi.go index d6a88a5b0..0ca17e84f 100644 --- a/pkg/tools/spi.go +++ b/pkg/tools/spi.go @@ -119,7 +119,11 @@ func (t *SPITool) list() *ToolResult { return SilentResult(fmt.Sprintf("Found %d SPI device(s):\n%s", len(devices), string(result))) } +// Helper function for SPI operations (used by platform-specific implementations) + // parseSPIArgs extracts and validates common SPI parameters +// +//nolint:unused // Used by spi_linux.go func parseSPIArgs(args map[string]any) (device string, speed uint32, mode uint8, bits uint8, errMsg string) { dev, ok := args["device"].(string) if !ok || dev == "" { From d09c64fcee20e9eabb13ca9c8de483747aafa930 Mon Sep 17 00:00:00 2001 From: Lixeer <1612655510@qq.com> Date: Tue, 24 Feb 2026 22:33:04 +0800 Subject: [PATCH 19/55] fix: implement code review suggestions Address all feedback from PR review: - Lock granularity - Empty response handling - Shutdown race condition - Interface naming --- cmd/picoclaw/cmd_gateway.go | 4 ++-- pkg/providers/github_copilot_provider.go | 21 +++++++++++++-------- pkg/providers/types.go | 2 +- pkg/tools/registry_test.go | 20 ++++++++++---------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/cmd/picoclaw/cmd_gateway.go b/cmd/picoclaw/cmd_gateway.go index 30d61aec3..fea569381 100644 --- a/cmd/picoclaw/cmd_gateway.go +++ b/cmd/picoclaw/cmd_gateway.go @@ -211,10 +211,10 @@ func gatewayCmd() { <-sigChan fmt.Println("\nShutting down...") - cancel() - if cp, ok := provider.(providers.SessionProvider); ok { + if cp, ok := provider.(providers.StatefulProvider); ok { cp.Close() } + cancel() healthServer.Stop(context.Background()) deviceService.Stop() heartbeatService.Stop() diff --git a/pkg/providers/github_copilot_provider.go b/pkg/providers/github_copilot_provider.go index c69658b44..9210021e1 100644 --- a/pkg/providers/github_copilot_provider.go +++ b/pkg/providers/github_copilot_provider.go @@ -94,19 +94,24 @@ func (p *GitHubCopilotProvider) Chat( return nil, fmt.Errorf("marshal messages: %w", err) } p.mu.Lock() - defer p.mu.Unlock() + session := p.session + p.mu.Unlock() - resp, err := p.session.SendAndWait(ctx, copilot.MessageOptions{ + if session == nil { + return nil, fmt.Errorf("provider closed") + } + + resp, err := session.SendAndWait(ctx, copilot.MessageOptions{ Prompt: string(fullcontent), }) - if err != nil { - return nil, err - } - var content string - if resp != nil && resp.Data.Content != nil { - content = *resp.Data.Content + if resp == nil { + return nil, fmt.Errorf("empty response from copilot") } + if resp.Data.Content == nil { + return nil, fmt.Errorf("no content in copilot response") + } + content := *resp.Data.Content return &LLMResponse{ FinishReason: "stop", diff --git a/pkg/providers/types.go b/pkg/providers/types.go index 40ff6f7c8..b2dda04a5 100644 --- a/pkg/providers/types.go +++ b/pkg/providers/types.go @@ -30,7 +30,7 @@ type LLMProvider interface { GetDefaultModel() string } -type SessionProvider interface { +type StatefulProvider interface { LLMProvider Close() } diff --git a/pkg/tools/registry_test.go b/pkg/tools/registry_test.go index 8ae13b20c..33978e543 100644 --- a/pkg/tools/registry_test.go +++ b/pkg/tools/registry_test.go @@ -14,14 +14,14 @@ import ( type mockRegistryTool struct { name string desc string - params map[string]any + params map[string]interface{} result *ToolResult } -func (m *mockRegistryTool) Name() string { return m.name } -func (m *mockRegistryTool) Description() string { return m.desc } -func (m *mockRegistryTool) Parameters() map[string]any { return m.params } -func (m *mockRegistryTool) Execute(_ context.Context, _ map[string]any) *ToolResult { +func (m *mockRegistryTool) Name() string { return m.name } +func (m *mockRegistryTool) Description() string { return m.desc } +func (m *mockRegistryTool) Parameters() map[string]interface{} { return m.params } +func (m *mockRegistryTool) Execute(_ context.Context, _ map[string]interface{}) *ToolResult { return m.result } @@ -51,7 +51,7 @@ func newMockTool(name, desc string) *mockRegistryTool { return &mockRegistryTool{ name: name, desc: desc, - params: map[string]any{"type": "object"}, + params: map[string]interface{}{"type": "object"}, result: SilentResult("ok"), } } @@ -109,7 +109,7 @@ func TestToolRegistry_Execute_Success(t *testing.T) { r.Register(&mockRegistryTool{ name: "greet", desc: "says hello", - params: map[string]any{}, + params: map[string]interface{}{}, result: SilentResult("hello"), }) @@ -203,7 +203,7 @@ func TestToolRegistry_GetDefinitions(t *testing.T) { if defs[0]["type"] != "function" { t.Errorf("expected type 'function', got %v", defs[0]["type"]) } - fn, ok := defs[0]["function"].(map[string]any) + fn, ok := defs[0]["function"].(map[string]interface{}) if !ok { t.Fatal("expected 'function' key to be a map") } @@ -217,7 +217,7 @@ func TestToolRegistry_GetDefinitions(t *testing.T) { func TestToolRegistry_ToProviderDefs(t *testing.T) { r := NewToolRegistry() - params := map[string]any{"type": "object", "properties": map[string]any{}} + params := map[string]interface{}{"type": "object", "properties": map[string]interface{}{}} r.Register(&mockRegistryTool{ name: "beta", desc: "tool B", @@ -310,7 +310,7 @@ func TestToolToSchema(t *testing.T) { if schema["type"] != "function" { t.Errorf("expected type 'function', got %v", schema["type"]) } - fn, ok := schema["function"].(map[string]any) + fn, ok := schema["function"].(map[string]interface{}) if !ok { t.Fatal("expected 'function' to be a map") } From ec6da7a530ce5da48df422b38be697afad36192b Mon Sep 17 00:00:00 2001 From: Achton Smidt Winther Date: Tue, 24 Feb 2026 21:39:49 +0100 Subject: [PATCH 20/55] fix: reject empty task in spawn tool (#740) The spawn tool accepts empty strings as valid task arguments, which causes a subagent to run with no meaningful work. The subagent's completion message is then routed back to the originating channel (e.g. Signal, Discord), where the main agent processes it and may hallucinate an unrelated response that gets sent to users. Validate that the task parameter is non-empty after trimming whitespace. Related: #545 Co-authored-by: Claude Opus 4.6 --- pkg/tools/spawn.go | 5 +-- pkg/tools/spawn_test.go | 79 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 pkg/tools/spawn_test.go diff --git a/pkg/tools/spawn.go b/pkg/tools/spawn.go index 73d385cb0..8b166b41f 100644 --- a/pkg/tools/spawn.go +++ b/pkg/tools/spawn.go @@ -3,6 +3,7 @@ package tools import ( "context" "fmt" + "strings" ) type SpawnTool struct { @@ -66,8 +67,8 @@ func (t *SpawnTool) SetAllowlistChecker(check func(targetAgentID string) bool) { func (t *SpawnTool) Execute(ctx context.Context, args map[string]any) *ToolResult { task, ok := args["task"].(string) - if !ok { - return ErrorResult("task is required") + if !ok || strings.TrimSpace(task) == "" { + return ErrorResult("task is required and must be a non-empty string") } label, _ := args["label"].(string) diff --git a/pkg/tools/spawn_test.go b/pkg/tools/spawn_test.go new file mode 100644 index 000000000..0646c82a9 --- /dev/null +++ b/pkg/tools/spawn_test.go @@ -0,0 +1,79 @@ +package tools + +import ( + "context" + "strings" + "testing" +) + +func TestSpawnTool_Execute_EmptyTask(t *testing.T) { + provider := &MockLLMProvider{} + manager := NewSubagentManager(provider, "test-model", "/tmp/test", nil) + tool := NewSpawnTool(manager) + + ctx := context.Background() + + tests := []struct { + name string + args map[string]any + }{ + {"empty string", map[string]any{"task": ""}}, + {"whitespace only", map[string]any{"task": " "}}, + {"tabs and newlines", map[string]any{"task": "\t\n "}}, + {"missing task key", map[string]any{"label": "test"}}, + {"wrong type", map[string]any{"task": 123}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tool.Execute(ctx, tt.args) + if result == nil { + t.Fatal("Result should not be nil") + } + if !result.IsError { + t.Error("Expected error for invalid task parameter") + } + if !strings.Contains(result.ForLLM, "task is required") { + t.Errorf("Error message should mention 'task is required', got: %s", result.ForLLM) + } + }) + } +} + +func TestSpawnTool_Execute_ValidTask(t *testing.T) { + provider := &MockLLMProvider{} + manager := NewSubagentManager(provider, "test-model", "/tmp/test", nil) + tool := NewSpawnTool(manager) + + ctx := context.Background() + args := map[string]any{ + "task": "Write a haiku about coding", + "label": "haiku-task", + } + + result := tool.Execute(ctx, args) + if result == nil { + t.Fatal("Result should not be nil") + } + if result.IsError { + t.Errorf("Expected success for valid task, got error: %s", result.ForLLM) + } + if !result.Async { + t.Error("SpawnTool should return async result") + } +} + +func TestSpawnTool_Execute_NilManager(t *testing.T) { + tool := NewSpawnTool(nil) + + ctx := context.Background() + args := map[string]any{"task": "test task"} + + result := tool.Execute(ctx, args) + if !result.IsError { + t.Error("Expected error for nil manager") + } + if !strings.Contains(result.ForLLM, "Subagent manager not configured") { + t.Errorf("Error message should mention manager not configured, got: %s", result.ForLLM) + } +} From 19c6890807a7d9a9d46201fcd0b6e9775bf1a37d Mon Sep 17 00:00:00 2001 From: avaksru <33891999+avaksru@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:46:42 +0300 Subject: [PATCH 21/55] Add ARMv7 build target to Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 576152f40..f99c7712e 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,7 @@ build-all: generate GOOS=linux GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(CMD_DIR) GOOS=linux GOARCH=loong64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-loong64 ./$(CMD_DIR) GOOS=linux GOARCH=riscv64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-riscv64 ./$(CMD_DIR) + GOOS=linux GOARCH=arm GOARM=7 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-armv7l ./$(CMD_DIR) GOOS=darwin GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 ./$(CMD_DIR) GOOS=windows GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe ./$(CMD_DIR) @echo "All builds complete" From 14cb16f113702ad9420ead54a77908a0460567af Mon Sep 17 00:00:00 2001 From: avaksru <33891999+avaksru@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:02:15 +0300 Subject: [PATCH 22/55] Add goarm versions for ARM architecture in config --- .goreleaser.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 2c47f7d86..2fcc43b8c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -31,6 +31,10 @@ builds: - s390x - mips64 - arm + goarm: + - "7" + - "6" + - "5" main: ./cmd/picoclaw ignore: - goos: windows From 7de75192b81306085544ce7fe123da82732af90d Mon Sep 17 00:00:00 2001 From: avaksru <33891999+avaksru@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:10:44 +0300 Subject: [PATCH 23/55] Disable Docker Hub login in release.yml Comment out Docker Hub login steps in release workflow. --- .github/workflows/release.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 786c893ef..6ebd75c13 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -73,12 +73,12 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - registry: docker.io - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} +# - name: Login to Docker Hub +# uses: docker/login-action@v3 +# with: +# registry: docker.io +# username: ${{ secrets.DOCKERHUB_USERNAME }} +# password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 From 1f7cbd916490ba39eda9edc6037bf13044eb4494 Mon Sep 17 00:00:00 2001 From: Zhaoyikaiii Date: Wed, 25 Feb 2026 10:34:54 +0800 Subject: [PATCH 24/55] fix: cache system prompt with mtime-based auto-invalidation (#607) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid rebuilding the entire system prompt on every BuildMessages() call by caching the static portion (identity, bootstrap, skills summary, memory) and only recomputing it when workspace source files change. Key changes: - ContextBuilder caches the static prompt behind an RWMutex with double-checked locking. Source file changes are detected via cheap os.Stat mtime checks so no explicit invalidation is needed. - Track file existence at cache time (existedAtCache map) so that newly created or deleted bootstrap/memory files also trigger a rebuild — the old modifiedSince() silently returned false on os.IsNotExist. - Walk the skills directory recursively with filepath.WalkDir to catch content-only edits at any nesting depth; directory mtime alone misses in-place file modifications on most filesystems. - ToolRegistry.sortedToolNames() sorts tool names before iteration, ensuring deterministic tool definition order across calls — a prerequisite for LLM-side prefix/KV cache reuse. - Merge all context (static + dynamic + summary) into a single system message for provider compatibility: the Anthropic adapter extracts messages[0] as the top-level system parameter, and Codex reads only the first system message as instructions. - Fix a data race in BuildMessages() where cachedSystemPrompt was read without holding the lock in a debug log statement. - Add tests: single system message invariant, mtime auto-invalidation, new-file creation detection, skill file content change, explicit InvalidateCache, cache stability, concurrent access (20 goroutines x 50 iterations, passes go test -race), and a benchmark. --- pkg/agent/context.go | 354 ++++++++++++++-- pkg/agent/context_cache_test.go | 513 ++++++++++++++++++++++++ pkg/agent/loop.go | 20 +- pkg/providers/anthropic/provider.go | 15 +- pkg/providers/codex_provider.go | 12 + pkg/providers/openai_compat/provider.go | 36 +- pkg/providers/protocoltypes/types.go | 26 +- pkg/providers/types.go | 2 + pkg/tools/registry.go | 39 +- 9 files changed, 965 insertions(+), 52 deletions(-) create mode 100644 pkg/agent/context_cache_test.go diff --git a/pkg/agent/context.go b/pkg/agent/context.go index ba07e33d3..a727cc833 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -1,11 +1,14 @@ package agent import ( + "errors" "fmt" + "io/fs" "os" "path/filepath" "runtime" "strings" + "sync" "time" "github.com/sipeed/picoclaw/pkg/logger" @@ -19,6 +22,19 @@ type ContextBuilder struct { skillsLoader *skills.SkillsLoader memory *MemoryStore tools *tools.ToolRegistry // Direct reference to tool registry + + // Cache for system prompt to avoid rebuilding on every call. + // This fixes issue #607: repeated reprocessing of the entire context. + // The cache auto-invalidates when workspace source files change (mtime check). + systemPromptMutex sync.RWMutex + cachedSystemPrompt string + cachedAt time.Time // max observed mtime across tracked paths at cache build time + + // existedAtCache tracks which source file paths existed the last time the + // cache was built. This lets sourceFilesChanged detect files that are newly + // created (didn't exist at cache time, now exist) or deleted (existed at + // cache time, now gone) — both of which should trigger a cache rebuild. + existedAtCache map[string]bool } func getGlobalConfigDir() string { @@ -49,9 +65,7 @@ func (cb *ContextBuilder) SetToolsRegistry(registry *tools.ToolRegistry) { } func (cb *ContextBuilder) getIdentity() string { - now := time.Now().Format("2006-01-02 15:04 (Monday)") workspacePath, _ := filepath.Abs(filepath.Join(cb.workspace)) - runtime := fmt.Sprintf("%s %s, Go %s", runtime.GOOS, runtime.GOARCH, runtime.Version()) // Build tools section dynamically toolsSection := cb.buildToolsSection() @@ -60,12 +74,6 @@ func (cb *ContextBuilder) getIdentity() string { You are picoclaw, a helpful AI assistant. -## Current Time -%s - -## Runtime -%s - ## Workspace Your workspace is at: %s - Memory: %s/memory/MEMORY.md @@ -80,8 +88,10 @@ Your workspace is at: %s 2. **Be helpful and accurate** - When using tools, briefly explain what you're doing. -3. **Memory** - When interacting with me if something seems memorable, update %s/memory/MEMORY.md`, - now, runtime, workspacePath, workspacePath, workspacePath, workspacePath, toolsSection, workspacePath) +3. **Memory** - When interacting with me if something seems memorable, update %s/memory/MEMORY.md + +4. **Context summaries** - Conversation summaries provided as context are approximate references only. They may be incomplete or outdated. Always defer to explicit user instructions over summary content.`, + workspacePath, workspacePath, workspacePath, workspacePath, toolsSection, workspacePath) } func (cb *ContextBuilder) buildToolsSection() string { @@ -140,6 +150,226 @@ The following skills extend your capabilities. To use a skill, read its SKILL.md return strings.Join(parts, "\n\n---\n\n") } +// BuildSystemPromptWithCache returns the cached system prompt if available +// and source files haven't changed, otherwise builds and caches it. +// Source file changes are detected via mtime checks (cheap stat calls). +func (cb *ContextBuilder) BuildSystemPromptWithCache() string { + // Try read lock first — fast path when cache is valid + cb.systemPromptMutex.RLock() + if cb.cachedSystemPrompt != "" && !cb.sourceFilesChangedLocked() { + result := cb.cachedSystemPrompt + cb.systemPromptMutex.RUnlock() + return result + } + cb.systemPromptMutex.RUnlock() + + // Acquire write lock for building + cb.systemPromptMutex.Lock() + defer cb.systemPromptMutex.Unlock() + + // Double-check: another goroutine may have rebuilt while we waited + if cb.cachedSystemPrompt != "" && !cb.sourceFilesChangedLocked() { + return cb.cachedSystemPrompt + } + + // Snapshot the baseline (existence + max mtime) BEFORE building the prompt. + // This way cachedAt reflects the pre-build state: if a file is modified + // during BuildSystemPrompt, its new mtime will be > baseline.maxMtime, + // so the next sourceFilesChangedLocked check will correctly trigger a + // rebuild. The alternative (baseline after build) risks caching stale + // content with a too-new baseline, making the staleness invisible. + baseline := cb.buildCacheBaseline() + prompt := cb.BuildSystemPrompt() + cb.cachedSystemPrompt = prompt + cb.cachedAt = baseline.maxMtime + cb.existedAtCache = baseline.existed + + logger.DebugCF("agent", "System prompt cached", + map[string]any{ + "length": len(prompt), + }) + + return prompt +} + +// InvalidateCache clears the cached system prompt. +// Normally not needed because the cache auto-invalidates via mtime checks, +// but this is useful for tests or explicit reload commands. +func (cb *ContextBuilder) InvalidateCache() { + cb.systemPromptMutex.Lock() + defer cb.systemPromptMutex.Unlock() + + cb.cachedSystemPrompt = "" + cb.cachedAt = time.Time{} + cb.existedAtCache = nil + + logger.DebugCF("agent", "System prompt cache invalidated", nil) +} + +// sourcePaths returns the workspace source file paths tracked for cache +// invalidation (bootstrap files + memory). The skills directory is handled +// separately in sourceFilesChangedLocked because it requires both directory- +// level and recursive file-level mtime checks. +func (cb *ContextBuilder) sourcePaths() []string { + return []string{ + filepath.Join(cb.workspace, "AGENTS.md"), + filepath.Join(cb.workspace, "SOUL.md"), + filepath.Join(cb.workspace, "USER.md"), + filepath.Join(cb.workspace, "IDENTITY.md"), + filepath.Join(cb.workspace, "memory", "MEMORY.md"), + } +} + +// cacheBaseline holds the file existence snapshot and the latest observed +// mtime across all tracked paths. Used as the cache reference point. +type cacheBaseline struct { + existed map[string]bool + maxMtime time.Time +} + +// buildCacheBaseline records which tracked paths currently exist and computes +// the latest mtime across all tracked files + skills directory contents. +// Called under write lock when the cache is built. +func (cb *ContextBuilder) buildCacheBaseline() cacheBaseline { + skillsDir := filepath.Join(cb.workspace, "skills") + + // All paths whose existence we track: source files + skills dir. + allPaths := append(cb.sourcePaths(), skillsDir) + + existed := make(map[string]bool, len(allPaths)) + var maxMtime time.Time + + for _, p := range allPaths { + info, err := os.Stat(p) + existed[p] = err == nil + if err == nil && info.ModTime().After(maxMtime) { + maxMtime = info.ModTime() + } + } + + // Walk skills files to capture their mtimes too. + // Use os.Stat (not d.Info) to match the stat method used in + // fileChangedSince / skillFilesModifiedSince for consistency. + _ = filepath.WalkDir(skillsDir, func(path string, d fs.DirEntry, walkErr error) error { + if walkErr == nil && !d.IsDir() { + if info, err := os.Stat(path); err == nil && info.ModTime().After(maxMtime) { + maxMtime = info.ModTime() + } + } + return nil + }) + + // If no tracked files exist yet (empty workspace), maxMtime is zero. + // Use a very old non-zero time so that: + // 1. cachedAt.IsZero() won't trigger perpetual rebuilds. + // 2. Any real file created afterwards has mtime > cachedAt, so it + // will be detected by fileChangedSince (unlike time.Now() which + // could race with a file whose mtime <= Now). + if maxMtime.IsZero() { + maxMtime = time.Unix(1, 0) + } + + return cacheBaseline{existed: existed, maxMtime: maxMtime} +} + +// sourceFilesChangedLocked checks whether any workspace source file has been +// modified, created, or deleted since the cache was last built. +// +// IMPORTANT: The caller MUST hold at least a read lock on systemPromptMutex. +// Go's sync.RWMutex is not reentrant, so this function must NOT acquire the +// lock itself (it would deadlock when called from BuildSystemPromptWithCache +// which already holds RLock or Lock). +func (cb *ContextBuilder) sourceFilesChangedLocked() bool { + if cb.cachedAt.IsZero() { + return true + } + + // Check tracked source files (bootstrap + memory). + for _, p := range cb.sourcePaths() { + if cb.fileChangedSince(p) { + return true + } + } + + // --- Skills directory (handled separately from sourcePaths) --- + // + // 1. Creation/deletion: tracked via existedAtCache, same as bootstrap files. + skillsDir := filepath.Join(cb.workspace, "skills") + if cb.fileChangedSince(skillsDir) { + return true + } + + // 2. Structural changes (add/remove entries inside the dir) are reflected + // in the directory's own mtime, which fileChangedSince already checks. + // + // 3. Content-only edits to files inside skills/ do NOT update the parent + // directory mtime on most filesystems, so we recursively walk to check + // individual file mtimes at any nesting depth. + if skillFilesModifiedSince(skillsDir, cb.cachedAt) { + return true + } + + return false +} + +// fileChangedSince returns true if a tracked source file has been modified, +// newly created, or deleted since the cache was built. +// +// Four cases: +// - existed at cache time, exists now -> check mtime +// - existed at cache time, gone now -> changed (deleted) +// - absent at cache time, exists now -> changed (created) +// - absent at cache time, gone now -> no change +func (cb *ContextBuilder) fileChangedSince(path string) bool { + // Defensive: if existedAtCache was never initialised, treat as changed + // so the cache rebuilds rather than silently serving stale data. + if cb.existedAtCache == nil { + return true + } + + existedBefore := cb.existedAtCache[path] + info, err := os.Stat(path) + existsNow := err == nil + + if existedBefore != existsNow { + return true // file was created or deleted + } + if !existsNow { + return false // didn't exist before, doesn't exist now + } + return info.ModTime().After(cb.cachedAt) +} + +// errWalkStop is a sentinel error used to stop filepath.WalkDir early. +// Using a dedicated error (instead of fs.SkipAll) makes the early-exit +// intent explicit and avoids the nilerr linter warning that would fire +// if the callback returned nil when its err parameter is non-nil. +var errWalkStop = errors.New("walk stop") + +// skillFilesModifiedSince recursively walks the skills directory and checks +// whether any file was modified after t. This catches content-only edits at +// any nesting depth (e.g. skills/name/docs/extra.md) that don't update +// parent directory mtimes. +func skillFilesModifiedSince(skillsDir string, t time.Time) bool { + changed := false + err := filepath.WalkDir(skillsDir, func(path string, d fs.DirEntry, walkErr error) error { + if walkErr == nil && !d.IsDir() { + if info, statErr := os.Stat(path); statErr == nil && info.ModTime().After(t) { + changed = true + return errWalkStop // stop walking + } + } + return nil + }) + // errWalkStop is expected (early exit on first changed file). + // os.IsNotExist means the skills dir doesn't exist yet — not an error. + // Any other error is unexpected and worth logging. + if err != nil && !errors.Is(err, errWalkStop) && !os.IsNotExist(err) { + logger.DebugCF("agent", "skills walk error", map[string]any{"error": err.Error()}) + } + return changed +} + func (cb *ContextBuilder) LoadBootstrapFiles() string { bootstrapFiles := []string{ "AGENTS.md", @@ -159,6 +389,28 @@ func (cb *ContextBuilder) LoadBootstrapFiles() string { return sb.String() } +// buildDynamicContext returns a short dynamic context string with per-request info. +// This changes every request (time, session) so it is NOT part of the cached prompt. +// LLM-side KV cache reuse is achieved by each provider adapter's native mechanism: +// - Anthropic: per-block cache_control (ephemeral) on the static SystemParts block +// - OpenAI / Codex: prompt_cache_key for prefix-based caching +// +// See: https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching +// See: https://platform.openai.com/docs/guides/prompt-caching +func (cb *ContextBuilder) buildDynamicContext(channel, chatID string) string { + now := time.Now().Format("2006-01-02 15:04 (Monday)") + rt := fmt.Sprintf("%s %s, Go %s", runtime.GOOS, runtime.GOARCH, runtime.Version()) + + var sb strings.Builder + fmt.Fprintf(&sb, "## Current Time\n%s\n\n## Runtime\n%s", now, rt) + + if channel != "" && chatID != "" { + fmt.Fprintf(&sb, "\n\n## Current Session\nChannel: %s\nChat ID: %s", channel, chatID) + } + + return sb.String() +} + func (cb *ContextBuilder) BuildMessages( history []providers.Message, summary string, @@ -168,23 +420,65 @@ func (cb *ContextBuilder) BuildMessages( ) []providers.Message { messages := []providers.Message{} - systemPrompt := cb.BuildSystemPrompt() + // The static part (identity, bootstrap, skills, memory) is cached locally to + // avoid repeated file I/O and string building on every call (fixes issue #607). + // Dynamic parts (time, session, summary) are appended per request. + // Everything is sent as a single system message for provider compatibility: + // - Anthropic adapter extracts messages[0] (Role=="system") and maps its content + // to the top-level "system" parameter in the Messages API request. A single + // contiguous system block makes this extraction straightforward. + // - Codex maps only the first system message to its instructions field. + // - OpenAI-compat passes messages through as-is. + staticPrompt := cb.BuildSystemPromptWithCache() - // Add Current Session info if provided - if channel != "" && chatID != "" { - systemPrompt += fmt.Sprintf("\n\n## Current Session\nChannel: %s\nChat ID: %s", channel, chatID) + // Build short dynamic context (time, runtime, session) — changes per request + dynamicCtx := cb.buildDynamicContext(channel, chatID) + + // Compose a single system message: static (cached) + dynamic + optional summary. + // Keeping all system content in one message ensures every provider adapter can + // extract it correctly (Anthropic adapter -> top-level system param, + // Codex -> instructions field). + // + // SystemParts carries the same content as structured blocks so that + // cache-aware adapters (Anthropic) can set per-block cache_control. + // The static block is marked "ephemeral" — its prefix hash is stable + // across requests, enabling LLM-side KV cache reuse. + stringParts := []string{staticPrompt, dynamicCtx} + + contentBlocks := []providers.ContentBlock{ + {Type: "text", Text: staticPrompt, CacheControl: &providers.CacheControl{Type: "ephemeral"}}, + {Type: "text", Text: dynamicCtx}, } - // Log system prompt summary for debugging (debug mode only) + if summary != "" { + summaryText := fmt.Sprintf( + "CONTEXT_SUMMARY: The following is an approximate summary of prior conversation "+ + "for reference only. It may be incomplete or outdated — always defer to explicit instructions.\n\n%s", + summary) + stringParts = append(stringParts, summaryText) + contentBlocks = append(contentBlocks, providers.ContentBlock{Type: "text", Text: summaryText}) + } + + fullSystemPrompt := strings.Join(stringParts, "\n\n---\n\n") + + // Log system prompt summary for debugging (debug mode only). + // Read cachedSystemPrompt under lock to avoid a data race with + // concurrent InvalidateCache / BuildSystemPromptWithCache writes. + cb.systemPromptMutex.RLock() + isCached := cb.cachedSystemPrompt != "" + cb.systemPromptMutex.RUnlock() + logger.DebugCF("agent", "System prompt built", map[string]any{ - "total_chars": len(systemPrompt), - "total_lines": strings.Count(systemPrompt, "\n") + 1, - "section_count": strings.Count(systemPrompt, "\n\n---\n\n") + 1, + "static_chars": len(staticPrompt), + "dynamic_chars": len(dynamicCtx), + "total_chars": len(fullSystemPrompt), + "has_summary": summary != "", + "cached": isCached, }) // Log preview of system prompt (avoid logging huge content) - preview := systemPrompt + preview := fullSystemPrompt if len(preview) > 500 { preview = preview[:500] + "... (truncated)" } @@ -193,19 +487,21 @@ func (cb *ContextBuilder) BuildMessages( "preview": preview, }) - if summary != "" { - systemPrompt += "\n\n## Summary of Previous Conversation\n\n" + summary - } - history = sanitizeHistoryForProvider(history) + // Single system message containing all context — compatible with all providers. + // SystemParts enables cache-aware adapters to set per-block cache_control; + // Content is the concatenated fallback for adapters that don't read SystemParts. messages = append(messages, providers.Message{ - Role: "system", - Content: systemPrompt, + Role: "system", + Content: fullSystemPrompt, + SystemParts: contentBlocks, }) + // Add conversation history messages = append(messages, history...) + // Add current user message if strings.TrimSpace(currentMessage) != "" { messages = append(messages, providers.Message{ Role: "user", @@ -224,6 +520,14 @@ func sanitizeHistoryForProvider(history []providers.Message) []providers.Message sanitized := make([]providers.Message, 0, len(history)) for _, msg := range history { switch msg.Role { + case "system": + // Drop system messages from history. BuildMessages always + // constructs its own single system message (static + dynamic + + // summary); extra system messages would break providers that + // only accept one (Anthropic, Codex). + logger.DebugCF("agent", "Dropping system message from history", map[string]any{}) + continue + case "tool": if len(sanitized) == 0 { logger.DebugCF("agent", "Dropping orphaned leading tool message", map[string]any{}) diff --git a/pkg/agent/context_cache_test.go b/pkg/agent/context_cache_test.go new file mode 100644 index 000000000..ba70d4c0d --- /dev/null +++ b/pkg/agent/context_cache_test.go @@ -0,0 +1,513 @@ +package agent + +import ( + "os" + "path/filepath" + "strings" + "sync" + "testing" + "time" + + "github.com/sipeed/picoclaw/pkg/providers" +) + +// setupWorkspace creates a temporary workspace with standard directories and optional files. +// Returns the tmpDir path; caller should defer os.RemoveAll(tmpDir). +func setupWorkspace(t *testing.T, files map[string]string) string { + t.Helper() + tmpDir, err := os.MkdirTemp("", "picoclaw-test-*") + if err != nil { + t.Fatal(err) + } + os.MkdirAll(filepath.Join(tmpDir, "memory"), 0o755) + os.MkdirAll(filepath.Join(tmpDir, "skills"), 0o755) + for name, content := range files { + dir := filepath.Dir(filepath.Join(tmpDir, name)) + os.MkdirAll(dir, 0o755) + if err := os.WriteFile(filepath.Join(tmpDir, name), []byte(content), 0o644); err != nil { + t.Fatal(err) + } + } + return tmpDir +} + +// TestSingleSystemMessage verifies that BuildMessages always produces exactly one +// system message regardless of summary/history variations. +// Fix: multiple system messages break Anthropic (top-level system param) and +// Codex (only reads last system message as instructions). +func TestSingleSystemMessage(t *testing.T) { + tmpDir := setupWorkspace(t, map[string]string{ + "IDENTITY.md": "# Identity\nTest agent.", + }) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + tests := []struct { + name string + history []providers.Message + summary string + message string + }{ + { + name: "no summary, no history", + summary: "", + message: "hello", + }, + { + name: "with summary", + summary: "Previous conversation discussed X", + message: "hello", + }, + { + name: "with history and summary", + history: []providers.Message{ + {Role: "user", Content: "hi"}, + {Role: "assistant", Content: "hello"}, + }, + summary: strings.Repeat("Long summary text. ", 50), + message: "new message", + }, + { + name: "system message in history is filtered", + history: []providers.Message{ + {Role: "system", Content: "stale system prompt from previous session"}, + {Role: "user", Content: "hi"}, + {Role: "assistant", Content: "hello"}, + }, + summary: "", + message: "new message", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msgs := cb.BuildMessages(tt.history, tt.summary, tt.message, nil, "test", "chat1") + + systemCount := 0 + for _, m := range msgs { + if m.Role == "system" { + systemCount++ + } + } + if systemCount != 1 { + t.Errorf("expected exactly 1 system message, got %d", systemCount) + } + if msgs[0].Role != "system" { + t.Errorf("first message should be system, got %s", msgs[0].Role) + } + if msgs[len(msgs)-1].Role != "user" { + t.Errorf("last message should be user, got %s", msgs[len(msgs)-1].Role) + } + + // System message must contain identity (static) and time (dynamic) + sys := msgs[0].Content + if !strings.Contains(sys, "picoclaw") { + t.Error("system message missing identity") + } + if !strings.Contains(sys, "Current Time") { + t.Error("system message missing dynamic time context") + } + + // Summary handling + if tt.summary != "" { + if !strings.Contains(sys, "CONTEXT_SUMMARY:") { + t.Error("summary present but CONTEXT_SUMMARY prefix missing") + } + if !strings.Contains(sys, tt.summary[:20]) { + t.Error("summary content not found in system message") + } + } else { + if strings.Contains(sys, "CONTEXT_SUMMARY:") { + t.Error("CONTEXT_SUMMARY should not appear without summary") + } + } + }) + } +} + +// TestMtimeAutoInvalidation verifies that the cache detects source file changes +// via mtime without requiring explicit InvalidateCache(). +// Fix: original implementation had no auto-invalidation — edits to bootstrap files, +// memory, or skills were invisible until process restart. +func TestMtimeAutoInvalidation(t *testing.T) { + tests := []struct { + name string + file string // relative path inside workspace + contentV1 string + contentV2 string + checkField string // substring to verify in rebuilt prompt + }{ + { + name: "bootstrap file change", + file: "IDENTITY.md", + contentV1: "# Original Identity", + contentV2: "# Updated Identity", + checkField: "Updated Identity", + }, + { + name: "memory file change", + file: "memory/MEMORY.md", + contentV1: "# Memory\nUser likes Go.", + contentV2: "# Memory\nUser likes Rust.", + checkField: "User likes Rust", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := setupWorkspace(t, map[string]string{tt.file: tt.contentV1}) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + sp1 := cb.BuildSystemPromptWithCache() + + // Overwrite file and set future mtime to ensure detection. + // Use 2s offset for filesystem mtime resolution safety (some FS + // have 1s or coarser granularity, especially in CI containers). + fullPath := filepath.Join(tmpDir, tt.file) + os.WriteFile(fullPath, []byte(tt.contentV2), 0o644) + future := time.Now().Add(2 * time.Second) + os.Chtimes(fullPath, future, future) + + // Verify sourceFilesChangedLocked detects the mtime change + cb.systemPromptMutex.RLock() + changed := cb.sourceFilesChangedLocked() + cb.systemPromptMutex.RUnlock() + if !changed { + t.Fatalf("sourceFilesChangedLocked() should detect %s change", tt.file) + } + + // Should auto-rebuild without explicit InvalidateCache() + sp2 := cb.BuildSystemPromptWithCache() + if sp1 == sp2 { + t.Errorf("cache not rebuilt after %s change", tt.file) + } + if !strings.Contains(sp2, tt.checkField) { + t.Errorf("rebuilt prompt missing expected content %q", tt.checkField) + } + }) + } + + // Skills directory mtime change + t.Run("skills dir change", func(t *testing.T) { + tmpDir := setupWorkspace(t, nil) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + _ = cb.BuildSystemPromptWithCache() // populate cache + + // Touch skills directory (simulate new skill installed) + skillsDir := filepath.Join(tmpDir, "skills") + future := time.Now().Add(2 * time.Second) + os.Chtimes(skillsDir, future, future) + + // Verify sourceFilesChangedLocked detects it (cache is rebuilt) + // We confirm by checking internal state: a second call should rebuild. + cb.systemPromptMutex.RLock() + changed := cb.sourceFilesChangedLocked() + cb.systemPromptMutex.RUnlock() + if !changed { + t.Error("sourceFilesChangedLocked() should detect skills dir mtime change") + } + }) +} + +// TestExplicitInvalidateCache verifies that InvalidateCache() forces a rebuild +// even when source files haven't changed (useful for tests and reload commands). +func TestExplicitInvalidateCache(t *testing.T) { + tmpDir := setupWorkspace(t, map[string]string{ + "IDENTITY.md": "# Test Identity", + }) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + sp1 := cb.BuildSystemPromptWithCache() + cb.InvalidateCache() + sp2 := cb.BuildSystemPromptWithCache() + + if sp1 != sp2 { + t.Error("prompt should be identical after invalidate+rebuild when files unchanged") + } + + // Verify cachedAt was reset + cb.InvalidateCache() + cb.systemPromptMutex.RLock() + if !cb.cachedAt.IsZero() { + t.Error("cachedAt should be zero after InvalidateCache()") + } + cb.systemPromptMutex.RUnlock() +} + +// TestCacheStability verifies that the static prompt is stable across repeated calls +// when no files change (regression test for issue #607). +func TestCacheStability(t *testing.T) { + tmpDir := setupWorkspace(t, map[string]string{ + "IDENTITY.md": "# Identity\nContent", + "SOUL.md": "# Soul\nContent", + }) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + results := make([]string, 5) + for i := range results { + results[i] = cb.BuildSystemPromptWithCache() + } + for i := 1; i < len(results); i++ { + if results[i] != results[0] { + t.Errorf("cached prompt changed between call 0 and %d", i) + } + } + + // Static prompt must NOT contain per-request data + if strings.Contains(results[0], "Current Time") { + t.Error("static cached prompt should not contain time (added dynamically)") + } +} + +// TestNewFileCreationInvalidatesCache verifies that creating a source file that +// did not exist when the cache was built triggers a cache rebuild. +// This catches the "from nothing to something" edge case that the old +// modifiedSince (return false on stat error) would miss. +func TestNewFileCreationInvalidatesCache(t *testing.T) { + tests := []struct { + name string + file string // relative path inside workspace + content string + checkField string // substring to verify in rebuilt prompt + }{ + { + name: "new bootstrap file", + file: "SOUL.md", + content: "# Soul\nBe kind and helpful.", + checkField: "Be kind and helpful", + }, + { + name: "new memory file", + file: "memory/MEMORY.md", + content: "# Memory\nUser prefers dark mode.", + checkField: "User prefers dark mode", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Start with an empty workspace (no bootstrap/memory files) + tmpDir := setupWorkspace(t, nil) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + // Populate cache — file does not exist yet + sp1 := cb.BuildSystemPromptWithCache() + if strings.Contains(sp1, tt.checkField) { + t.Fatalf("prompt should not contain %q before file is created", tt.checkField) + } + + // Create the file after cache was built + fullPath := filepath.Join(tmpDir, tt.file) + os.MkdirAll(filepath.Dir(fullPath), 0o755) + if err := os.WriteFile(fullPath, []byte(tt.content), 0o644); err != nil { + t.Fatal(err) + } + // Set future mtime to guarantee detection + future := time.Now().Add(2 * time.Second) + os.Chtimes(fullPath, future, future) + + // Cache should auto-invalidate because file went from absent -> present + sp2 := cb.BuildSystemPromptWithCache() + if !strings.Contains(sp2, tt.checkField) { + t.Errorf("cache not invalidated on new file creation: expected %q in prompt", tt.checkField) + } + }) + } +} + +// TestSkillFileContentChange verifies that modifying a skill file's content +// (not just the directory structure) invalidates the cache. +// This is the scenario where directory mtime alone is insufficient — on most +// filesystems, editing a file inside a directory does NOT update the parent +// directory's mtime. +func TestSkillFileContentChange(t *testing.T) { + skillMD := `--- +name: test-skill +description: "A test skill" +--- +# Test Skill v1 +Original content.` + + tmpDir := setupWorkspace(t, map[string]string{ + "skills/test-skill/SKILL.md": skillMD, + }) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + // Populate cache + sp1 := cb.BuildSystemPromptWithCache() + _ = sp1 // cache is warm + + // Modify the skill file content (without touching the skills/ directory) + updatedSkillMD := `--- +name: test-skill +description: "An updated test skill" +--- +# Test Skill v2 +Updated content.` + + skillPath := filepath.Join(tmpDir, "skills", "test-skill", "SKILL.md") + if err := os.WriteFile(skillPath, []byte(updatedSkillMD), 0o644); err != nil { + t.Fatal(err) + } + // Set future mtime on the skill file only (NOT the directory) + future := time.Now().Add(2 * time.Second) + os.Chtimes(skillPath, future, future) + + // Verify that sourceFilesChangedLocked detects the content change + cb.systemPromptMutex.RLock() + changed := cb.sourceFilesChangedLocked() + cb.systemPromptMutex.RUnlock() + if !changed { + t.Error("sourceFilesChangedLocked() should detect skill file content change") + } + + // Verify cache is actually rebuilt with new content + sp2 := cb.BuildSystemPromptWithCache() + if sp1 == sp2 && strings.Contains(sp1, "test-skill") { + // If the skill appeared in the prompt and the prompt didn't change, + // the cache was not invalidated. + t.Error("cache should be invalidated when skill file content changes") + } +} + +// TestConcurrentBuildSystemPromptWithCache verifies that multiple goroutines +// can safely call BuildSystemPromptWithCache concurrently without producing +// empty results, panics, or data races. +// Run with: go test -race ./pkg/agent/ -run TestConcurrentBuildSystemPromptWithCache +func TestConcurrentBuildSystemPromptWithCache(t *testing.T) { + tmpDir := setupWorkspace(t, map[string]string{ + "IDENTITY.md": "# Identity\nConcurrency test agent.", + "SOUL.md": "# Soul\nBe helpful.", + "memory/MEMORY.md": "# Memory\nUser prefers Go.", + "skills/demo/SKILL.md": "---\nname: demo\ndescription: \"demo skill\"\n---\n# Demo", + }) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + const goroutines = 20 + const iterations = 50 + + var wg sync.WaitGroup + errs := make(chan string, goroutines*iterations) + + for g := 0; g < goroutines; g++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for i := 0; i < iterations; i++ { + result := cb.BuildSystemPromptWithCache() + if result == "" { + errs <- "empty prompt returned" + return + } + if !strings.Contains(result, "picoclaw") { + errs <- "prompt missing identity" + return + } + + // Also exercise BuildMessages concurrently + msgs := cb.BuildMessages(nil, "", "hello", nil, "test", "chat") + if len(msgs) < 2 { + errs <- "BuildMessages returned fewer than 2 messages" + return + } + if msgs[0].Role != "system" { + errs <- "first message not system" + return + } + + // Occasionally invalidate to exercise the write path + if i%10 == 0 { + cb.InvalidateCache() + } + } + }(g) + } + + wg.Wait() + close(errs) + + for errMsg := range errs { + t.Errorf("concurrent access error: %s", errMsg) + } +} + +// BenchmarkBuildMessagesWithCache measures caching performance. + +// TestEmptyWorkspaceBaselineDetectsNewFiles verifies that when the cache is +// built on an empty workspace (no tracked files exist), creating a file +// afterwards still triggers cache invalidation. This validates the +// time.Unix(1, 0) fallback for maxMtime: any real file's mtime is after epoch, +// so fileChangedSince correctly detects the absent -> present transition AND +// the mtime comparison succeeds even without artificially inflated Chtimes. +func TestEmptyWorkspaceBaselineDetectsNewFiles(t *testing.T) { + // Empty workspace: no bootstrap files, no memory, no skills content. + tmpDir := setupWorkspace(t, nil) + defer os.RemoveAll(tmpDir) + + cb := NewContextBuilder(tmpDir) + + // Build cache — all tracked files are absent, maxMtime falls back to epoch. + sp1 := cb.BuildSystemPromptWithCache() + + // Create a bootstrap file with natural mtime (no Chtimes manipulation). + // The file's mtime should be the current wall-clock time, which is + // strictly after time.Unix(1, 0). + soulPath := filepath.Join(tmpDir, "SOUL.md") + if err := os.WriteFile(soulPath, []byte("# Soul\nNewly created."), 0o644); err != nil { + t.Fatal(err) + } + + // Cache should detect the new file via existedAtCache (absent -> present). + cb.systemPromptMutex.RLock() + changed := cb.sourceFilesChangedLocked() + cb.systemPromptMutex.RUnlock() + if !changed { + t.Fatal("sourceFilesChangedLocked should detect newly created file on empty workspace") + } + + sp2 := cb.BuildSystemPromptWithCache() + if !strings.Contains(sp2, "Newly created") { + t.Error("rebuilt prompt should contain new file content") + } + if sp1 == sp2 { + t.Error("cache should have been invalidated after file creation") + } +} + +// BenchmarkBuildMessagesWithCache measures caching performance. +func BenchmarkBuildMessagesWithCache(b *testing.B) { + tmpDir, _ := os.MkdirTemp("", "picoclaw-bench-*") + defer os.RemoveAll(tmpDir) + + os.MkdirAll(filepath.Join(tmpDir, "memory"), 0o755) + os.MkdirAll(filepath.Join(tmpDir, "skills"), 0o755) + for _, name := range []string{"IDENTITY.md", "SOUL.md", "USER.md"} { + os.WriteFile(filepath.Join(tmpDir, name), []byte(strings.Repeat("Content.\n", 10)), 0o644) + } + + cb := NewContextBuilder(tmpDir) + history := []providers.Message{ + {Role: "user", Content: "previous message"}, + {Role: "assistant", Content: "previous response"}, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = cb.BuildMessages(history, "summary", "new message", nil, "cli", "test") + } +} diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index dbc4a9b87..c40d46ef5 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -524,8 +524,9 @@ func (al *AgentLoop) runLLMIteration( fbResult, fbErr := al.fallback.Execute(ctx, agent.Candidates, func(ctx context.Context, provider, model string) (*providers.LLMResponse, error) { return agent.Provider.Chat(ctx, messages, providerToolDefs, model, map[string]any{ - "max_tokens": agent.MaxTokens, - "temperature": agent.Temperature, + "max_tokens": agent.MaxTokens, + "temperature": agent.Temperature, + "prompt_cache_key": agent.ID, }) }, ) @@ -540,8 +541,9 @@ func (al *AgentLoop) runLLMIteration( return fbResult.Response, nil } return agent.Provider.Chat(ctx, messages, providerToolDefs, agent.Model, map[string]any{ - "max_tokens": agent.MaxTokens, - "temperature": agent.Temperature, + "max_tokens": agent.MaxTokens, + "temperature": agent.Temperature, + "prompt_cache_key": agent.ID, }) } @@ -962,8 +964,9 @@ func (al *AgentLoop) summarizeSession(agent *AgentInstance, sessionKey string) { nil, agent.Model, map[string]any{ - "max_tokens": 1024, - "temperature": 0.3, + "max_tokens": 1024, + "temperature": 0.3, + "prompt_cache_key": agent.ID, }, ) if err == nil { @@ -1012,8 +1015,9 @@ func (al *AgentLoop) summarizeBatch( nil, agent.Model, map[string]any{ - "max_tokens": 1024, - "temperature": 0.3, + "max_tokens": 1024, + "temperature": 0.3, + "prompt_cache_key": agent.ID, }, ) if err != nil { diff --git a/pkg/providers/anthropic/provider.go b/pkg/providers/anthropic/provider.go index 35f6b8f62..9162174c9 100644 --- a/pkg/providers/anthropic/provider.go +++ b/pkg/providers/anthropic/provider.go @@ -113,7 +113,20 @@ func buildParams( for _, msg := range messages { switch msg.Role { case "system": - system = append(system, anthropic.TextBlockParam{Text: msg.Content}) + // Prefer structured SystemParts for per-block cache_control. + // This enables LLM-side KV cache reuse: the static block's prefix + // hash stays stable across requests while dynamic parts change freely. + if len(msg.SystemParts) > 0 { + for _, part := range msg.SystemParts { + block := anthropic.TextBlockParam{Text: part.Text} + if part.CacheControl != nil && part.CacheControl.Type == "ephemeral" { + block.CacheControl = anthropic.NewCacheControlEphemeralParam() + } + system = append(system, block) + } + } else { + system = append(system, anthropic.TextBlockParam{Text: msg.Content}) + } case "user": if msg.ToolCallID != "" { anthropicMessages = append(anthropicMessages, diff --git a/pkg/providers/codex_provider.go b/pkg/providers/codex_provider.go index ecc983642..ae261710b 100644 --- a/pkg/providers/codex_provider.go +++ b/pkg/providers/codex_provider.go @@ -208,6 +208,11 @@ func buildCodexParams( for _, msg := range messages { switch msg.Role { case "system": + // Use the full concatenated system prompt (static + dynamic + summary) + // as instructions. This keeps behavior consistent with Anthropic and + // OpenAI-compat adapters where the complete system context lives in + // one place. Prefix caching is handled by prompt_cache_key below, + // not by splitting content across instructions vs input messages. instructions = msg.Content case "user": if msg.ToolCallID != "" { @@ -289,6 +294,13 @@ func buildCodexParams( params.Instructions = openai.Opt(defaultCodexInstructions) } + // Prompt caching: pass a stable cache key so OpenAI can bucket requests + // and reuse prefix KV cache across calls with the same key. + // See: https://platform.openai.com/docs/guides/prompt-caching + if cacheKey, ok := options["prompt_cache_key"].(string); ok && cacheKey != "" { + params.PromptCacheKey = openai.Opt(cacheKey) + } + if len(tools) > 0 || enableWebSearch { params.Tools = translateToolsForCodex(tools, enableWebSearch) } diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index d2412ae1b..a8d244d4a 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -77,7 +77,7 @@ func (p *Provider) Chat( requestBody := map[string]any{ "model": model, - "messages": messages, + "messages": stripSystemParts(messages), } if len(tools) > 0 { @@ -111,6 +111,14 @@ func (p *Provider) Chat( } } + // Prompt caching: pass a stable cache key so OpenAI can bucket requests + // with the same key and reuse prefix KV cache across calls. + // The key is typically the agent ID — stable per agent, shared across requests. + // See: https://platform.openai.com/docs/guides/prompt-caching + if cacheKey, ok := options["prompt_cache_key"].(string); ok && cacheKey != "" { + requestBody["prompt_cache_key"] = cacheKey + } + jsonData, err := json.Marshal(requestBody) if err != nil { return nil, fmt.Errorf("failed to marshal request: %w", err) @@ -230,6 +238,32 @@ func parseResponse(body []byte) (*LLMResponse, error) { }, nil } +// openaiMessage is the wire-format message for OpenAI-compatible APIs. +// It mirrors protocoltypes.Message but omits SystemParts, which is an +// internal field that would be unknown to third-party endpoints. +type openaiMessage struct { + Role string `json:"role"` + Content string `json:"content"` + ToolCalls []ToolCall `json:"tool_calls,omitempty"` + ToolCallID string `json:"tool_call_id,omitempty"` +} + +// stripSystemParts converts []Message to []openaiMessage, dropping the +// SystemParts field so it doesn't leak into the JSON payload sent to +// OpenAI-compatible APIs (some strict endpoints reject unknown fields). +func stripSystemParts(messages []Message) []openaiMessage { + out := make([]openaiMessage, len(messages)) + for i, m := range messages { + out[i] = openaiMessage{ + Role: m.Role, + Content: m.Content, + ToolCalls: m.ToolCalls, + ToolCallID: m.ToolCallID, + } + } + return out +} + func normalizeModel(model, apiBase string) string { idx := strings.Index(model, "/") if idx == -1 { diff --git a/pkg/providers/protocoltypes/types.go b/pkg/providers/protocoltypes/types.go index 1d0ea6edd..4d927cde4 100644 --- a/pkg/providers/protocoltypes/types.go +++ b/pkg/providers/protocoltypes/types.go @@ -38,12 +38,28 @@ type UsageInfo struct { TotalTokens int `json:"total_tokens"` } +// CacheControl marks a content block for LLM-side prefix caching. +// Currently only "ephemeral" is supported (used by Anthropic). +type CacheControl struct { + Type string `json:"type"` // "ephemeral" +} + +// ContentBlock represents a structured segment of a system message. +// Adapters that understand SystemParts can use these blocks to set +// per-block cache control (e.g. Anthropic's cache_control: ephemeral). +type ContentBlock struct { + Type string `json:"type"` // "text" + Text string `json:"text"` + CacheControl *CacheControl `json:"cache_control,omitempty"` +} + type Message struct { - Role string `json:"role"` - Content string `json:"content"` - ReasoningContent string `json:"reasoning_content,omitempty"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` - ToolCallID string `json:"tool_call_id,omitempty"` + Role string `json:"role"` + Content string `json:"content"` + ReasoningContent string `json:"reasoning_content,omitempty"` + SystemParts []ContentBlock `json:"system_parts,omitempty"` // structured system blocks for cache-aware adapters + ToolCalls []ToolCall `json:"tool_calls,omitempty"` + ToolCallID string `json:"tool_call_id,omitempty"` } type ToolDefinition struct { diff --git a/pkg/providers/types.go b/pkg/providers/types.go index b2dda04a5..f0c168bc6 100644 --- a/pkg/providers/types.go +++ b/pkg/providers/types.go @@ -17,6 +17,8 @@ type ( ToolFunctionDefinition = protocoltypes.ToolFunctionDefinition ExtraContent = protocoltypes.ExtraContent GoogleExtra = protocoltypes.GoogleExtra + ContentBlock = protocoltypes.ContentBlock + CacheControl = protocoltypes.CacheControl ) type LLMProvider interface { diff --git a/pkg/tools/registry.go b/pkg/tools/registry.go index 6ecb8ae7c..d37a093a8 100644 --- a/pkg/tools/registry.go +++ b/pkg/tools/registry.go @@ -3,6 +3,7 @@ package tools import ( "context" "fmt" + "sort" "sync" "time" @@ -107,13 +108,27 @@ func (r *ToolRegistry) ExecuteWithContext( return result } +// sortedToolNames returns tool names in sorted order for deterministic iteration. +// This is critical for KV cache stability: non-deterministic map iteration would +// produce different system prompts and tool definitions on each call, invalidating +// the LLM's prefix cache even when no tools have changed. +func (r *ToolRegistry) sortedToolNames() []string { + names := make([]string, 0, len(r.tools)) + for name := range r.tools { + names = append(names, name) + } + sort.Strings(names) + return names +} + func (r *ToolRegistry) GetDefinitions() []map[string]any { r.mu.RLock() defer r.mu.RUnlock() - definitions := make([]map[string]any, 0, len(r.tools)) - for _, tool := range r.tools { - definitions = append(definitions, ToolToSchema(tool)) + sorted := r.sortedToolNames() + definitions := make([]map[string]any, 0, len(sorted)) + for _, name := range sorted { + definitions = append(definitions, ToolToSchema(r.tools[name])) } return definitions } @@ -124,8 +139,10 @@ func (r *ToolRegistry) ToProviderDefs() []providers.ToolDefinition { r.mu.RLock() defer r.mu.RUnlock() - definitions := make([]providers.ToolDefinition, 0, len(r.tools)) - for _, tool := range r.tools { + sorted := r.sortedToolNames() + definitions := make([]providers.ToolDefinition, 0, len(sorted)) + for _, name := range sorted { + tool := r.tools[name] schema := ToolToSchema(tool) // Safely extract nested values with type checks @@ -155,11 +172,7 @@ func (r *ToolRegistry) List() []string { r.mu.RLock() defer r.mu.RUnlock() - names := make([]string, 0, len(r.tools)) - for name := range r.tools { - names = append(names, name) - } - return names + return r.sortedToolNames() } // Count returns the number of registered tools. @@ -175,8 +188,10 @@ func (r *ToolRegistry) GetSummaries() []string { r.mu.RLock() defer r.mu.RUnlock() - summaries := make([]string, 0, len(r.tools)) - for _, tool := range r.tools { + sorted := r.sortedToolNames() + summaries := make([]string, 0, len(sorted)) + for _, name := range sorted { + tool := r.tools[name] summaries = append(summaries, fmt.Sprintf("- `%s` - %s", tool.Name(), tool.Description())) } return summaries From 85276057a0b1ef392062c74725f565bb35b4ce6b Mon Sep 17 00:00:00 2001 From: avaksru <33891999+avaksru@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:32:50 +0300 Subject: [PATCH 25/55] Disable dockers_v2 section in goreleaser config Comment out dockers_v2 configuration in .goreleaser.yaml --- .goreleaser.yaml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 2fcc43b8c..e3e64c4c8 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -40,21 +40,21 @@ builds: - goos: windows goarch: arm -dockers_v2: - - id: picoclaw - dockerfile: Dockerfile.goreleaser - ids: - - picoclaw - images: - - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/picoclaw" - - "docker.io/{{ .Env.DOCKERHUB_IMAGE_NAME }}" - tags: - - "{{ .Tag }}" - - "latest" - platforms: - - linux/amd64 - - linux/arm64 - - linux/riscv64 +#dockers_v2: +# - id: picoclaw +# dockerfile: Dockerfile.goreleaser +# ids: +# - picoclaw +# images: +# - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/picoclaw" +# - "docker.io/{{ .Env.DOCKERHUB_IMAGE_NAME }}" +# tags: +# - "{{ .Tag }}" +# - "latest" +# platforms: +# - linux/amd64 +# - linux/arm64 +# - linux/riscv64 archives: - formats: [tar.gz] From edc78191c9e5b233395d24acf3fdbda02e762eef Mon Sep 17 00:00:00 2001 From: Zhaoyikaiii Date: Wed, 25 Feb 2026 15:36:54 +0800 Subject: [PATCH 26/55] style: fix gci formatting in protocoltypes/types.go --- pkg/providers/protocoltypes/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/providers/protocoltypes/types.go b/pkg/providers/protocoltypes/types.go index 4d927cde4..33f052c5a 100644 --- a/pkg/providers/protocoltypes/types.go +++ b/pkg/providers/protocoltypes/types.go @@ -48,7 +48,7 @@ type CacheControl struct { // Adapters that understand SystemParts can use these blocks to set // per-block cache control (e.g. Anthropic's cache_control: ephemeral). type ContentBlock struct { - Type string `json:"type"` // "text" + Type string `json:"type"` // "text" Text string `json:"text"` CacheControl *CacheControl `json:"cache_control,omitempty"` } From 73f27803d4b573541f2df6631d4569e149a7753a Mon Sep 17 00:00:00 2001 From: Ruslan Semagin Date: Wed, 25 Feb 2026 10:47:45 +0300 Subject: [PATCH 27/55] refactor(cli): migrate to Cobra-based command structure (#429) * refactor(cli): migrate to Cobra-based command structure Refactor CLI to use Cobra instead of manual os.Args parsing. - Introduce root command and structured subcommands under cmd/picoclaw/internal - Convert agent, auth, cron, gateway, migrate, onboard, skills, status and version to Cobra commands - Replace manual flag parsing with Cobra flags - Remove direct os.Args usage from command handlers - Keep existing command behavior and output semantics This change focuses on CLI structure and maintainability. No business logic changes intended. * chore(cli): remove version2 alias and make cobra a direct dependency * test(cli): add basic command tests - Add tests for CLI command tree and flag parsing - Align LDFLAGS injection path for version info - Remove unused manual help function * test: migrate command tests to testify assertions Replace standard library testing error checks (t.Error*, t.Fatalf) with assert/require from stretchr/testify across all cobra command tests for improved readability and consistency. * fix(cli): make linter happy * test: avoid duplication in windows config path test * test: simplify allowed command checks using slices.Contains * fix(skills): register subcommands during command construction - Move subcommand registration out of PersistentPreRunE - Ensure `picoclaw skills ` resolves correctly - Minor install command and test cleanups * refactor(cli): address review feedback and improve command clarity * fix(authLogoutCmd): rm os.Exit --- .gitignore | 2 +- .goreleaser.yaml | 8 +- Makefile | 3 +- cmd/picoclaw/cmd_cron.go | 227 ------------------ cmd/picoclaw/cmd_migrate.go | 81 ------- cmd/picoclaw/internal/agent/command.go | 30 +++ cmd/picoclaw/internal/agent/command_test.go | 33 +++ .../agent/helpers.go} | 76 +++--- cmd/picoclaw/internal/auth/command.go | 22 ++ cmd/picoclaw/internal/auth/command_test.go | 55 +++++ .../{cmd_auth.go => internal/auth/helpers.go} | 223 ++++++----------- cmd/picoclaw/internal/auth/login.go | 25 ++ cmd/picoclaw/internal/auth/login_test.go | 29 +++ cmd/picoclaw/internal/auth/logout.go | 20 ++ cmd/picoclaw/internal/auth/logout_test.go | 20 ++ cmd/picoclaw/internal/auth/models.go | 15 ++ cmd/picoclaw/internal/auth/models_test.go | 19 ++ cmd/picoclaw/internal/auth/status.go | 16 ++ cmd/picoclaw/internal/auth/status_test.go | 18 ++ cmd/picoclaw/internal/cron/add.go | 64 +++++ cmd/picoclaw/internal/cron/add_test.go | 57 +++++ cmd/picoclaw/internal/cron/command.go | 44 ++++ cmd/picoclaw/internal/cron/command_test.go | 58 +++++ cmd/picoclaw/internal/cron/disable.go | 16 ++ cmd/picoclaw/internal/cron/disable_test.go | 20 ++ cmd/picoclaw/internal/cron/enable.go | 16 ++ cmd/picoclaw/internal/cron/enable_test.go | 20 ++ cmd/picoclaw/internal/cron/helpers.go | 66 +++++ cmd/picoclaw/internal/cron/list.go | 17 ++ cmd/picoclaw/internal/cron/list_test.go | 17 ++ cmd/picoclaw/internal/cron/remove.go | 18 ++ cmd/picoclaw/internal/cron/remove_test.go | 19 ++ cmd/picoclaw/internal/gateway/command.go | 23 ++ cmd/picoclaw/internal/gateway/command_test.go | 31 +++ .../gateway/helpers.go} | 36 ++- cmd/picoclaw/internal/helpers.go | 54 +++++ cmd/picoclaw/internal/helpers_test.go | 97 ++++++++ cmd/picoclaw/internal/migrate/command.go | 48 ++++ cmd/picoclaw/internal/migrate/command_test.go | 38 +++ cmd/picoclaw/internal/onboard/command.go | 24 ++ cmd/picoclaw/internal/onboard/command_test.go | 29 +++ .../onboard/helpers.go} | 29 +-- cmd/picoclaw/internal/skills/command.go | 79 ++++++ cmd/picoclaw/internal/skills/command_test.go | 28 +++ .../skills/helpers.go} | 116 ++++----- cmd/picoclaw/internal/skills/install.go | 58 +++++ cmd/picoclaw/internal/skills/install_test.go | 28 +++ .../internal/skills/installbuiltin.go | 21 ++ .../internal/skills/installbuiltin_test.go | 27 +++ cmd/picoclaw/internal/skills/list.go | 25 ++ cmd/picoclaw/internal/skills/list_test.go | 27 +++ cmd/picoclaw/internal/skills/listbuiltin.go | 16 ++ .../internal/skills/listbuiltin_test.go | 26 ++ cmd/picoclaw/internal/skills/remove.go | 27 +++ cmd/picoclaw/internal/skills/remove_test.go | 29 +++ cmd/picoclaw/internal/skills/search.go | 24 ++ cmd/picoclaw/internal/skills/search_test.go | 25 ++ cmd/picoclaw/internal/skills/show.go | 26 ++ cmd/picoclaw/internal/skills/show_test.go | 27 +++ cmd/picoclaw/internal/status/command.go | 18 ++ cmd/picoclaw/internal/status/command_test.go | 29 +++ .../status/helpers.go} | 16 +- cmd/picoclaw/internal/version/command.go | 33 +++ cmd/picoclaw/internal/version/command_test.go | 31 +++ cmd/picoclaw/main.go | 207 +++------------- cmd/picoclaw/main_test.go | 56 +++++ go.mod | 3 + go.sum | 10 + 68 files changed, 1978 insertions(+), 797 deletions(-) delete mode 100644 cmd/picoclaw/cmd_cron.go delete mode 100644 cmd/picoclaw/cmd_migrate.go create mode 100644 cmd/picoclaw/internal/agent/command.go create mode 100644 cmd/picoclaw/internal/agent/command_test.go rename cmd/picoclaw/{cmd_agent.go => internal/agent/helpers.go} (70%) create mode 100644 cmd/picoclaw/internal/auth/command.go create mode 100644 cmd/picoclaw/internal/auth/command_test.go rename cmd/picoclaw/{cmd_auth.go => internal/auth/helpers.go} (67%) create mode 100644 cmd/picoclaw/internal/auth/login.go create mode 100644 cmd/picoclaw/internal/auth/login_test.go create mode 100644 cmd/picoclaw/internal/auth/logout.go create mode 100644 cmd/picoclaw/internal/auth/logout_test.go create mode 100644 cmd/picoclaw/internal/auth/models.go create mode 100644 cmd/picoclaw/internal/auth/models_test.go create mode 100644 cmd/picoclaw/internal/auth/status.go create mode 100644 cmd/picoclaw/internal/auth/status_test.go create mode 100644 cmd/picoclaw/internal/cron/add.go create mode 100644 cmd/picoclaw/internal/cron/add_test.go create mode 100644 cmd/picoclaw/internal/cron/command.go create mode 100644 cmd/picoclaw/internal/cron/command_test.go create mode 100644 cmd/picoclaw/internal/cron/disable.go create mode 100644 cmd/picoclaw/internal/cron/disable_test.go create mode 100644 cmd/picoclaw/internal/cron/enable.go create mode 100644 cmd/picoclaw/internal/cron/enable_test.go create mode 100644 cmd/picoclaw/internal/cron/helpers.go create mode 100644 cmd/picoclaw/internal/cron/list.go create mode 100644 cmd/picoclaw/internal/cron/list_test.go create mode 100644 cmd/picoclaw/internal/cron/remove.go create mode 100644 cmd/picoclaw/internal/cron/remove_test.go create mode 100644 cmd/picoclaw/internal/gateway/command.go create mode 100644 cmd/picoclaw/internal/gateway/command_test.go rename cmd/picoclaw/{cmd_gateway.go => internal/gateway/helpers.go} (91%) create mode 100644 cmd/picoclaw/internal/helpers.go create mode 100644 cmd/picoclaw/internal/helpers_test.go create mode 100644 cmd/picoclaw/internal/migrate/command.go create mode 100644 cmd/picoclaw/internal/migrate/command_test.go create mode 100644 cmd/picoclaw/internal/onboard/command.go create mode 100644 cmd/picoclaw/internal/onboard/command_test.go rename cmd/picoclaw/{cmd_onboard.go => internal/onboard/helpers.go} (90%) create mode 100644 cmd/picoclaw/internal/skills/command.go create mode 100644 cmd/picoclaw/internal/skills/command_test.go rename cmd/picoclaw/{cmd_skills.go => internal/skills/helpers.go} (72%) create mode 100644 cmd/picoclaw/internal/skills/install.go create mode 100644 cmd/picoclaw/internal/skills/install_test.go create mode 100644 cmd/picoclaw/internal/skills/installbuiltin.go create mode 100644 cmd/picoclaw/internal/skills/installbuiltin_test.go create mode 100644 cmd/picoclaw/internal/skills/list.go create mode 100644 cmd/picoclaw/internal/skills/list_test.go create mode 100644 cmd/picoclaw/internal/skills/listbuiltin.go create mode 100644 cmd/picoclaw/internal/skills/listbuiltin_test.go create mode 100644 cmd/picoclaw/internal/skills/remove.go create mode 100644 cmd/picoclaw/internal/skills/remove_test.go create mode 100644 cmd/picoclaw/internal/skills/search.go create mode 100644 cmd/picoclaw/internal/skills/search_test.go create mode 100644 cmd/picoclaw/internal/skills/show.go create mode 100644 cmd/picoclaw/internal/skills/show_test.go create mode 100644 cmd/picoclaw/internal/status/command.go create mode 100644 cmd/picoclaw/internal/status/command_test.go rename cmd/picoclaw/{cmd_status.go => internal/status/helpers.go} (90%) create mode 100644 cmd/picoclaw/internal/version/command.go create mode 100644 cmd/picoclaw/internal/version/command_test.go create mode 100644 cmd/picoclaw/main_test.go diff --git a/.gitignore b/.gitignore index ce30d749e..3ff195fbf 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ build/ *.out /picoclaw /picoclaw-test -cmd/picoclaw/workspace +cmd/**/workspace # Picoclaw specific diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 2c47f7d86..b9357aa2e 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -15,10 +15,10 @@ builds: - stdjson ldflags: - -s -w - - -X main.version={{ .Version }} - - -X main.gitCommit={{ .ShortCommit }} - - -X main.buildTime={{ .Date }} - - -X main.goVersion={{ .Env.GOVERSION }} + - -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.version={{ .Version }} + - -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.gitCommit={{ .ShortCommit }} + - -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.buildTime={{ .Date }} + - -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.goVersion={{ .Env.GOVERSION }} goos: - linux - windows diff --git a/Makefile b/Makefile index 576152f40..7bf05a2eb 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,8 @@ VERSION?=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") GIT_COMMIT=$(shell git rev-parse --short=8 HEAD 2>/dev/null || echo "dev") BUILD_TIME=$(shell date +%FT%T%z) GO_VERSION=$(shell $(GO) version | awk '{print $$3}') -LDFLAGS=-ldflags "-X main.version=$(VERSION) -X main.gitCommit=$(GIT_COMMIT) -X main.buildTime=$(BUILD_TIME) -X main.goVersion=$(GO_VERSION) -s -w" +INTERNAL=github.com/sipeed/picoclaw/cmd/picoclaw/internal +LDFLAGS=-ldflags "-X $(INTERNAL).version=$(VERSION) -X $(INTERNAL).gitCommit=$(GIT_COMMIT) -X $(INTERNAL).buildTime=$(BUILD_TIME) -X $(INTERNAL).goVersion=$(GO_VERSION) -s -w" # Go variables GO?=CGO_ENABLED=0 go diff --git a/cmd/picoclaw/cmd_cron.go b/cmd/picoclaw/cmd_cron.go deleted file mode 100644 index 8c42bde06..000000000 --- a/cmd/picoclaw/cmd_cron.go +++ /dev/null @@ -1,227 +0,0 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main - -import ( - "fmt" - "os" - "path/filepath" - "time" - - "github.com/sipeed/picoclaw/pkg/cron" -) - -func cronCmd() { - if len(os.Args) < 3 { - cronHelp() - return - } - - subcommand := os.Args[2] - - // Load config to get workspace path - cfg, err := loadConfig() - if err != nil { - fmt.Printf("Error loading config: %v\n", err) - return - } - - cronStorePath := filepath.Join(cfg.WorkspacePath(), "cron", "jobs.json") - - switch subcommand { - case "list": - cronListCmd(cronStorePath) - case "add": - cronAddCmd(cronStorePath) - case "remove": - if len(os.Args) < 4 { - fmt.Println("Usage: picoclaw cron remove ") - return - } - cronRemoveCmd(cronStorePath, os.Args[3]) - case "enable": - cronEnableCmd(cronStorePath, false) - case "disable": - cronEnableCmd(cronStorePath, true) - default: - fmt.Printf("Unknown cron command: %s\n", subcommand) - cronHelp() - } -} - -func cronHelp() { - fmt.Println("\nCron commands:") - fmt.Println(" list List all scheduled jobs") - fmt.Println(" add Add a new scheduled job") - fmt.Println(" remove Remove a job by ID") - fmt.Println(" enable Enable a job") - fmt.Println(" disable Disable a job") - fmt.Println() - fmt.Println("Add options:") - fmt.Println(" -n, --name Job name") - fmt.Println(" -m, --message Message for agent") - fmt.Println(" -e, --every Run every N seconds") - fmt.Println(" -c, --cron Cron expression (e.g. '0 9 * * *')") - fmt.Println(" -d, --deliver Deliver response to channel") - fmt.Println(" --to Recipient for delivery") - fmt.Println(" --channel Channel for delivery") -} - -func cronListCmd(storePath string) { - cs := cron.NewCronService(storePath, nil) - jobs := cs.ListJobs(true) // Show all jobs, including disabled - - if len(jobs) == 0 { - fmt.Println("No scheduled jobs.") - return - } - - fmt.Println("\nScheduled Jobs:") - fmt.Println("----------------") - for _, job := range jobs { - var schedule string - if job.Schedule.Kind == "every" && job.Schedule.EveryMS != nil { - schedule = fmt.Sprintf("every %ds", *job.Schedule.EveryMS/1000) - } else if job.Schedule.Kind == "cron" { - schedule = job.Schedule.Expr - } else { - schedule = "one-time" - } - - nextRun := "scheduled" - if job.State.NextRunAtMS != nil { - nextTime := time.UnixMilli(*job.State.NextRunAtMS) - nextRun = nextTime.Format("2006-01-02 15:04") - } - - status := "enabled" - if !job.Enabled { - status = "disabled" - } - - fmt.Printf(" %s (%s)\n", job.Name, job.ID) - fmt.Printf(" Schedule: %s\n", schedule) - fmt.Printf(" Status: %s\n", status) - fmt.Printf(" Next run: %s\n", nextRun) - } -} - -func cronAddCmd(storePath string) { - name := "" - message := "" - var everySec *int64 - cronExpr := "" - deliver := false - channel := "" - to := "" - - args := os.Args[3:] - for i := 0; i < len(args); i++ { - switch args[i] { - case "-n", "--name": - if i+1 < len(args) { - name = args[i+1] - i++ - } - case "-m", "--message": - if i+1 < len(args) { - message = args[i+1] - i++ - } - case "-e", "--every": - if i+1 < len(args) { - var sec int64 - fmt.Sscanf(args[i+1], "%d", &sec) - everySec = &sec - i++ - } - case "-c", "--cron": - if i+1 < len(args) { - cronExpr = args[i+1] - i++ - } - case "-d", "--deliver": - deliver = true - case "--to": - if i+1 < len(args) { - to = args[i+1] - i++ - } - case "--channel": - if i+1 < len(args) { - channel = args[i+1] - i++ - } - } - } - - if name == "" { - fmt.Println("Error: --name is required") - return - } - - if message == "" { - fmt.Println("Error: --message is required") - return - } - - if everySec == nil && cronExpr == "" { - fmt.Println("Error: Either --every or --cron must be specified") - return - } - - var schedule cron.CronSchedule - if everySec != nil { - everyMS := *everySec * 1000 - schedule = cron.CronSchedule{ - Kind: "every", - EveryMS: &everyMS, - } - } else { - schedule = cron.CronSchedule{ - Kind: "cron", - Expr: cronExpr, - } - } - - cs := cron.NewCronService(storePath, nil) - job, err := cs.AddJob(name, schedule, message, deliver, channel, to) - if err != nil { - fmt.Printf("Error adding job: %v\n", err) - return - } - - fmt.Printf("✓ Added job '%s' (%s)\n", job.Name, job.ID) -} - -func cronRemoveCmd(storePath, jobID string) { - cs := cron.NewCronService(storePath, nil) - if cs.RemoveJob(jobID) { - fmt.Printf("✓ Removed job %s\n", jobID) - } else { - fmt.Printf("✗ Job %s not found\n", jobID) - } -} - -func cronEnableCmd(storePath string, disable bool) { - if len(os.Args) < 4 { - fmt.Println("Usage: picoclaw cron enable/disable ") - return - } - - jobID := os.Args[3] - cs := cron.NewCronService(storePath, nil) - enabled := !disable - - job := cs.EnableJob(jobID, enabled) - if job != nil { - status := "enabled" - if disable { - status = "disabled" - } - fmt.Printf("✓ Job '%s' %s\n", job.Name, status) - } else { - fmt.Printf("✗ Job %s not found\n", jobID) - } -} diff --git a/cmd/picoclaw/cmd_migrate.go b/cmd/picoclaw/cmd_migrate.go deleted file mode 100644 index 86d4903ef..000000000 --- a/cmd/picoclaw/cmd_migrate.go +++ /dev/null @@ -1,81 +0,0 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main - -import ( - "fmt" - "os" - - "github.com/sipeed/picoclaw/pkg/migrate" -) - -func migrateCmd() { - if len(os.Args) > 2 && (os.Args[2] == "--help" || os.Args[2] == "-h") { - migrateHelp() - return - } - - opts := migrate.Options{} - - args := os.Args[2:] - for i := 0; i < len(args); i++ { - switch args[i] { - case "--dry-run": - opts.DryRun = true - case "--config-only": - opts.ConfigOnly = true - case "--workspace-only": - opts.WorkspaceOnly = true - case "--force": - opts.Force = true - case "--refresh": - opts.Refresh = true - case "--openclaw-home": - if i+1 < len(args) { - opts.OpenClawHome = args[i+1] - i++ - } - case "--picoclaw-home": - if i+1 < len(args) { - opts.PicoClawHome = args[i+1] - i++ - } - default: - fmt.Printf("Unknown flag: %s\n", args[i]) - migrateHelp() - os.Exit(1) - } - } - - result, err := migrate.Run(opts) - if err != nil { - fmt.Printf("Error: %v\n", err) - os.Exit(1) - } - - if !opts.DryRun { - migrate.PrintSummary(result) - } -} - -func migrateHelp() { - fmt.Println("\nMigrate from OpenClaw to PicoClaw") - fmt.Println() - fmt.Println("Usage: picoclaw migrate [options]") - fmt.Println() - fmt.Println("Options:") - fmt.Println(" --dry-run Show what would be migrated without making changes") - fmt.Println(" --refresh Re-sync workspace files from OpenClaw (repeatable)") - fmt.Println(" --config-only Only migrate config, skip workspace files") - fmt.Println(" --workspace-only Only migrate workspace files, skip config") - fmt.Println(" --force Skip confirmation prompts") - fmt.Println(" --openclaw-home Override OpenClaw home directory (default: ~/.openclaw)") - fmt.Println(" --picoclaw-home Override PicoClaw home directory (default: ~/.picoclaw)") - fmt.Println() - fmt.Println("Examples:") - fmt.Println(" picoclaw migrate Detect and migrate from OpenClaw") - fmt.Println(" picoclaw migrate --dry-run Show what would be migrated") - fmt.Println(" picoclaw migrate --refresh Re-sync workspace files") - fmt.Println(" picoclaw migrate --force Migrate without confirmation") -} diff --git a/cmd/picoclaw/internal/agent/command.go b/cmd/picoclaw/internal/agent/command.go new file mode 100644 index 000000000..47262fc85 --- /dev/null +++ b/cmd/picoclaw/internal/agent/command.go @@ -0,0 +1,30 @@ +package agent + +import ( + "github.com/spf13/cobra" +) + +func NewAgentCommand() *cobra.Command { + var ( + message string + sessionKey string + model string + debug bool + ) + + cmd := &cobra.Command{ + Use: "agent", + Short: "Interact with the agent directly", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return agentCmd(message, sessionKey, model, debug) + }, + } + + cmd.Flags().BoolVarP(&debug, "debug", "d", false, "Enable debug logging") + cmd.Flags().StringVarP(&message, "message", "m", "", "Send a single message (non-interactive mode)") + cmd.Flags().StringVarP(&sessionKey, "session", "s", "cli:default", "Session key") + cmd.Flags().StringVarP(&model, "model", "", "", "Model to use") + + return cmd +} diff --git a/cmd/picoclaw/internal/agent/command_test.go b/cmd/picoclaw/internal/agent/command_test.go new file mode 100644 index 000000000..1457d6a49 --- /dev/null +++ b/cmd/picoclaw/internal/agent/command_test.go @@ -0,0 +1,33 @@ +package agent + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewAgentCommand(t *testing.T) { + cmd := NewAgentCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "agent", cmd.Use) + assert.Equal(t, "Interact with the agent directly", cmd.Short) + + assert.Len(t, cmd.Aliases, 0) + assert.False(t, cmd.HasSubCommands()) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) + + assert.True(t, cmd.HasFlags()) + + assert.NotNil(t, cmd.Flags().Lookup("debug")) + assert.NotNil(t, cmd.Flags().Lookup("message")) + assert.NotNil(t, cmd.Flags().Lookup("session")) + assert.NotNil(t, cmd.Flags().Lookup("model")) +} diff --git a/cmd/picoclaw/cmd_agent.go b/cmd/picoclaw/internal/agent/helpers.go similarity index 70% rename from cmd/picoclaw/cmd_agent.go rename to cmd/picoclaw/internal/agent/helpers.go index 98ea51103..746e9755e 100644 --- a/cmd/picoclaw/cmd_agent.go +++ b/cmd/picoclaw/internal/agent/helpers.go @@ -1,7 +1,4 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main +package agent import ( "bufio" @@ -14,56 +11,37 @@ import ( "github.com/chzyer/readline" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/pkg/agent" "github.com/sipeed/picoclaw/pkg/bus" "github.com/sipeed/picoclaw/pkg/logger" "github.com/sipeed/picoclaw/pkg/providers" ) -func agentCmd() { - message := "" - sessionKey := "cli:default" - modelOverride := "" - - args := os.Args[2:] - for i := 0; i < len(args); i++ { - switch args[i] { - case "--debug", "-d": - logger.SetLevel(logger.DEBUG) - fmt.Println("🔍 Debug mode enabled") - case "-m", "--message": - if i+1 < len(args) { - message = args[i+1] - i++ - } - case "-s", "--session": - if i+1 < len(args) { - sessionKey = args[i+1] - i++ - } - case "--model", "-model": - if i+1 < len(args) { - modelOverride = args[i+1] - i++ - } - } +func agentCmd(message, sessionKey, model string, debug bool) error { + if sessionKey == "" { + sessionKey = "cli:default" } - cfg, err := loadConfig() + if debug { + logger.SetLevel(logger.DEBUG) + fmt.Println("🔍 Debug mode enabled") + } + + cfg, err := internal.LoadConfig() if err != nil { - fmt.Printf("Error loading config: %v\n", err) - os.Exit(1) + return fmt.Errorf("error loading config: %w", err) } - if modelOverride != "" { - cfg.Agents.Defaults.ModelName = modelOverride + if model != "" { + cfg.Agents.Defaults.ModelName = model } provider, modelID, err := providers.CreateProvider(cfg) if err != nil { - fmt.Printf("Error creating provider: %v\n", err) - os.Exit(1) + return fmt.Errorf("error creating provider: %w", err) } + // Use the resolved model ID from provider creation if modelID != "" { cfg.Agents.Defaults.ModelName = modelID @@ -85,18 +63,20 @@ func agentCmd() { ctx := context.Background() response, err := agentLoop.ProcessDirect(ctx, message, sessionKey) if err != nil { - fmt.Printf("Error: %v\n", err) - os.Exit(1) + return fmt.Errorf("error processing message: %w", err) } - fmt.Printf("\n%s %s\n", logo, response) - } else { - fmt.Printf("%s Interactive mode (Ctrl+C to exit)\n\n", logo) - interactiveMode(agentLoop, sessionKey) + fmt.Printf("\n%s %s\n", internal.Logo, response) + return nil } + + fmt.Printf("%s Interactive mode (Ctrl+C to exit)\n\n", internal.Logo) + interactiveMode(agentLoop, sessionKey) + + return nil } func interactiveMode(agentLoop *agent.AgentLoop, sessionKey string) { - prompt := fmt.Sprintf("%s You: ", logo) + prompt := fmt.Sprintf("%s You: ", internal.Logo) rl, err := readline.NewEx(&readline.Config{ Prompt: prompt, @@ -141,14 +121,14 @@ func interactiveMode(agentLoop *agent.AgentLoop, sessionKey string) { continue } - fmt.Printf("\n%s %s\n\n", logo, response) + fmt.Printf("\n%s %s\n\n", internal.Logo, response) } } func simpleInteractiveMode(agentLoop *agent.AgentLoop, sessionKey string) { reader := bufio.NewReader(os.Stdin) for { - fmt.Printf("%s You: ", logo) + fmt.Print(fmt.Sprintf("%s You: ", internal.Logo)) line, err := reader.ReadString('\n') if err != nil { if err == io.EOF { @@ -176,6 +156,6 @@ func simpleInteractiveMode(agentLoop *agent.AgentLoop, sessionKey string) { continue } - fmt.Printf("\n%s %s\n\n", logo, response) + fmt.Printf("\n%s %s\n\n", internal.Logo, response) } } diff --git a/cmd/picoclaw/internal/auth/command.go b/cmd/picoclaw/internal/auth/command.go new file mode 100644 index 000000000..12a0a3a8c --- /dev/null +++ b/cmd/picoclaw/internal/auth/command.go @@ -0,0 +1,22 @@ +package auth + +import "github.com/spf13/cobra" + +func NewAuthCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "auth", + Short: "Manage authentication (login, logout, status)", + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() + }, + } + + cmd.AddCommand( + newLoginCommand(), + newLogoutCommand(), + newStatusCommand(), + newModelsCommand(), + ) + + return cmd +} diff --git a/cmd/picoclaw/internal/auth/command_test.go b/cmd/picoclaw/internal/auth/command_test.go new file mode 100644 index 000000000..48dc704dd --- /dev/null +++ b/cmd/picoclaw/internal/auth/command_test.go @@ -0,0 +1,55 @@ +package auth + +import ( + "slices" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewAuthCommand(t *testing.T) { + cmd := NewAuthCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "auth", cmd.Use) + assert.Equal(t, "Manage authentication (login, logout, status)", cmd.Short) + + assert.Len(t, cmd.Aliases, 0) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) + + assert.False(t, cmd.HasFlags()) + assert.True(t, cmd.HasSubCommands()) + + allowedCommands := []string{ + "login", + "logout", + "status", + "models", + } + + subcommands := cmd.Commands() + assert.Len(t, subcommands, len(allowedCommands)) + + for _, subcmd := range subcommands { + found := slices.Contains(allowedCommands, subcmd.Name()) + assert.True(t, found, "unexpected subcommand %q", subcmd.Name()) + + assert.Len(t, subcmd.Aliases, 0) + assert.False(t, subcmd.Hidden) + + assert.False(t, subcmd.HasSubCommands()) + + assert.Nil(t, subcmd.Run) + assert.NotNil(t, subcmd.RunE) + + assert.Nil(t, subcmd.PersistentPreRun) + assert.Nil(t, subcmd.PersistentPostRun) + } +} diff --git a/cmd/picoclaw/cmd_auth.go b/cmd/picoclaw/internal/auth/helpers.go similarity index 67% rename from cmd/picoclaw/cmd_auth.go rename to cmd/picoclaw/internal/auth/helpers.go index 55eb3cec3..633ce8740 100644 --- a/cmd/picoclaw/cmd_auth.go +++ b/cmd/picoclaw/internal/auth/helpers.go @@ -1,7 +1,4 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main +package auth import ( "encoding/json" @@ -12,92 +9,28 @@ import ( "strings" "time" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/pkg/auth" "github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/providers" ) -const supportedProvidersMsg = "Supported providers: openai, anthropic, google-antigravity" - -func authCmd() { - if len(os.Args) < 3 { - authHelp() - return - } - - switch os.Args[2] { - case "login": - authLoginCmd() - case "logout": - authLogoutCmd() - case "status": - authStatusCmd() - case "models": - authModelsCmd() - default: - fmt.Printf("Unknown auth command: %s\n", os.Args[2]) - authHelp() - } -} - -func authHelp() { - fmt.Println("\nAuth commands:") - fmt.Println(" login Login via OAuth or paste token") - fmt.Println(" logout Remove stored credentials") - fmt.Println(" status Show current auth status") - fmt.Println(" models List available Antigravity models") - fmt.Println() - fmt.Println("Login options:") - fmt.Println(" --provider Provider to login with (openai, anthropic, google-antigravity)") - fmt.Println(" --device-code Use device code flow (for headless environments)") - fmt.Println() - fmt.Println("Examples:") - fmt.Println(" picoclaw auth login --provider openai") - fmt.Println(" picoclaw auth login --provider openai --device-code") - fmt.Println(" picoclaw auth login --provider anthropic") - fmt.Println(" picoclaw auth login --provider google-antigravity") - fmt.Println(" picoclaw auth models") - fmt.Println(" picoclaw auth logout --provider openai") - fmt.Println(" picoclaw auth status") -} - -func authLoginCmd() { - provider := "" - useDeviceCode := false - - args := os.Args[3:] - for i := 0; i < len(args); i++ { - switch args[i] { - case "--provider", "-p": - if i+1 < len(args) { - provider = args[i+1] - i++ - } - case "--device-code": - useDeviceCode = true - } - } - - if provider == "" { - fmt.Println("Error: --provider is required") - fmt.Println(supportedProvidersMsg) - return - } +const supportedProvidersMsg = "supported providers: openai, anthropic, google-antigravity" +func authLoginCmd(provider string, useDeviceCode bool) error { switch provider { case "openai": - authLoginOpenAI(useDeviceCode) + return authLoginOpenAI(useDeviceCode) case "anthropic": - authLoginPasteToken(provider) + return authLoginPasteToken(provider) case "google-antigravity", "antigravity": - authLoginGoogleAntigravity() + return authLoginGoogleAntigravity() default: - fmt.Printf("Unsupported provider: %s\n", provider) - fmt.Println(supportedProvidersMsg) + return fmt.Errorf("unsupported provider: %s (%s)", provider, supportedProvidersMsg) } } -func authLoginOpenAI(useDeviceCode bool) { +func authLoginOpenAI(useDeviceCode bool) error { cfg := auth.OpenAIOAuthConfig() var cred *auth.AuthCredential @@ -110,16 +43,14 @@ func authLoginOpenAI(useDeviceCode bool) { } if err != nil { - fmt.Printf("Login failed: %v\n", err) - os.Exit(1) + return fmt.Errorf("login failed: %w", err) } if err = auth.SetCredential("openai", cred); err != nil { - fmt.Printf("Failed to save credentials: %v\n", err) - os.Exit(1) + return fmt.Errorf("failed to save credentials: %w", err) } - appCfg, err := loadConfig() + appCfg, err := internal.LoadConfig() if err == nil { // Update Providers (legacy format) appCfg.Providers.OpenAI.AuthMethod = "oauth" @@ -146,8 +77,8 @@ func authLoginOpenAI(useDeviceCode bool) { // Update default model to use OpenAI appCfg.Agents.Defaults.ModelName = "gpt-5.2" - if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { - fmt.Printf("Warning: could not update config: %v\n", err) + if err = config.SaveConfig(internal.GetConfigPath(), appCfg); err != nil { + return fmt.Errorf("could not update config: %w", err) } } @@ -156,15 +87,16 @@ func authLoginOpenAI(useDeviceCode bool) { fmt.Printf("Account: %s\n", cred.AccountID) } fmt.Println("Default model set to: gpt-5.2") + + return nil } -func authLoginGoogleAntigravity() { +func authLoginGoogleAntigravity() error { cfg := auth.GoogleAntigravityOAuthConfig() cred, err := auth.LoginBrowser(cfg) if err != nil { - fmt.Printf("Login failed: %v\n", err) - os.Exit(1) + return fmt.Errorf("login failed: %w", err) } cred.Provider = "google-antigravity" @@ -189,11 +121,10 @@ func authLoginGoogleAntigravity() { } if err = auth.SetCredential("google-antigravity", cred); err != nil { - fmt.Printf("Failed to save credentials: %v\n", err) - os.Exit(1) + return fmt.Errorf("failed to save credentials: %w", err) } - appCfg, err := loadConfig() + appCfg, err := internal.LoadConfig() if err == nil { // Update Providers (legacy format, for backward compatibility) appCfg.Providers.Antigravity.AuthMethod = "oauth" @@ -220,7 +151,7 @@ func authLoginGoogleAntigravity() { // Update default model appCfg.Agents.Defaults.ModelName = "gemini-flash" - if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { + if err := config.SaveConfig(internal.GetConfigPath(), appCfg); err != nil { fmt.Printf("Warning: could not update config: %v\n", err) } } @@ -228,6 +159,8 @@ func authLoginGoogleAntigravity() { fmt.Println("\n✓ Google Antigravity login successful!") fmt.Println("Default model set to: gemini-flash") fmt.Println("Try it: picoclaw agent -m \"Hello world\"") + + return nil } func fetchGoogleUserEmail(accessToken string) (string, error) { @@ -258,19 +191,17 @@ func fetchGoogleUserEmail(accessToken string) (string, error) { return userInfo.Email, nil } -func authLoginPasteToken(provider string) { +func authLoginPasteToken(provider string) error { cred, err := auth.LoginPasteToken(provider, os.Stdin) if err != nil { - fmt.Printf("Login failed: %v\n", err) - os.Exit(1) + return fmt.Errorf("login failed: %w", err) } if err = auth.SetCredential(provider, cred); err != nil { - fmt.Printf("Failed to save credentials: %v\n", err) - os.Exit(1) + return fmt.Errorf("failed to save credentials: %w", err) } - appCfg, err := loadConfig() + appCfg, err := internal.LoadConfig() if err == nil { switch provider { case "anthropic": @@ -314,36 +245,27 @@ func authLoginPasteToken(provider string) { // Update default model appCfg.Agents.Defaults.ModelName = "gpt-5.2" } - if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { - fmt.Printf("Warning: could not update config: %v\n", err) + if err := config.SaveConfig(internal.GetConfigPath(), appCfg); err != nil { + return fmt.Errorf("could not update config: %w", err) } } fmt.Printf("Token saved for %s!\n", provider) - fmt.Printf("Default model set to: %s\n", appCfg.Agents.Defaults.GetModelName()) -} -func authLogoutCmd() { - provider := "" - - args := os.Args[3:] - for i := 0; i < len(args); i++ { - switch args[i] { - case "--provider", "-p": - if i+1 < len(args) { - provider = args[i+1] - i++ - } - } + if appCfg != nil { + fmt.Printf("Default model set to: %s\n", appCfg.Agents.Defaults.GetModelName()) } + return nil +} + +func authLogoutCmd(provider string) error { if provider != "" { if err := auth.DeleteCredential(provider); err != nil { - fmt.Printf("Failed to remove credentials: %v\n", err) - os.Exit(1) + return fmt.Errorf("failed to remove credentials: %w", err) } - appCfg, err := loadConfig() + appCfg, err := internal.LoadConfig() if err == nil { // Clear AuthMethod in ModelList for i := range appCfg.ModelList { @@ -371,44 +293,46 @@ func authLogoutCmd() { case "google-antigravity", "antigravity": appCfg.Providers.Antigravity.AuthMethod = "" } - config.SaveConfig(getConfigPath(), appCfg) + config.SaveConfig(internal.GetConfigPath(), appCfg) } fmt.Printf("Logged out from %s\n", provider) - } else { - if err := auth.DeleteAllCredentials(); err != nil { - fmt.Printf("Failed to remove credentials: %v\n", err) - os.Exit(1) - } - appCfg, err := loadConfig() - if err == nil { - // Clear all AuthMethods in ModelList - for i := range appCfg.ModelList { - appCfg.ModelList[i].AuthMethod = "" - } - // Clear all AuthMethods in Providers (legacy) - appCfg.Providers.OpenAI.AuthMethod = "" - appCfg.Providers.Anthropic.AuthMethod = "" - appCfg.Providers.Antigravity.AuthMethod = "" - config.SaveConfig(getConfigPath(), appCfg) - } - - fmt.Println("Logged out from all providers") + return nil } + + if err := auth.DeleteAllCredentials(); err != nil { + return fmt.Errorf("failed to remove credentials: %w", err) + } + + appCfg, err := internal.LoadConfig() + if err == nil { + // Clear all AuthMethods in ModelList + for i := range appCfg.ModelList { + appCfg.ModelList[i].AuthMethod = "" + } + // Clear all AuthMethods in Providers (legacy) + appCfg.Providers.OpenAI.AuthMethod = "" + appCfg.Providers.Anthropic.AuthMethod = "" + appCfg.Providers.Antigravity.AuthMethod = "" + config.SaveConfig(internal.GetConfigPath(), appCfg) + } + + fmt.Println("Logged out from all providers") + + return nil } -func authStatusCmd() { +func authStatusCmd() error { store, err := auth.LoadStore() if err != nil { - fmt.Printf("Error loading auth store: %v\n", err) - return + return fmt.Errorf("failed to load auth store: %w", err) } if len(store.Credentials) == 0 { fmt.Println("No authenticated providers.") fmt.Println("Run: picoclaw auth login --provider ") - return + return nil } fmt.Println("\nAuthenticated Providers:") @@ -437,14 +361,16 @@ func authStatusCmd() { fmt.Printf(" Expires: %s\n", cred.ExpiresAt.Format("2006-01-02 15:04")) } } + + return nil } -func authModelsCmd() { +func authModelsCmd() error { cred, err := auth.GetCredential("google-antigravity") if err != nil || cred == nil { - fmt.Println("Not logged in to Google Antigravity.") - fmt.Println("Run: picoclaw auth login --provider google-antigravity") - return + return fmt.Errorf( + "not logged in to Google Antigravity.\nrun: picoclaw auth login --provider google-antigravity", + ) } // Refresh token if needed @@ -459,21 +385,18 @@ func authModelsCmd() { projectID := cred.ProjectID if projectID == "" { - fmt.Println("No project ID stored. Try logging in again.") - return + return fmt.Errorf("no project id stored. Try logging in again") } fmt.Printf("Fetching models for project: %s\n\n", projectID) models, err := providers.FetchAntigravityModels(cred.AccessToken, projectID) if err != nil { - fmt.Printf("Error fetching models: %v\n", err) - return + return fmt.Errorf("error fetching models: %w", err) } if len(models) == 0 { - fmt.Println("No models available.") - return + return fmt.Errorf("no models available") } fmt.Println("Available Antigravity Models:") @@ -489,6 +412,8 @@ func authModelsCmd() { } fmt.Printf(" %s %s\n", status, name) } + + return nil } // isAntigravityModel checks if a model string belongs to antigravity provider diff --git a/cmd/picoclaw/internal/auth/login.go b/cmd/picoclaw/internal/auth/login.go new file mode 100644 index 000000000..9a6d28d2f --- /dev/null +++ b/cmd/picoclaw/internal/auth/login.go @@ -0,0 +1,25 @@ +package auth + +import "github.com/spf13/cobra" + +func newLoginCommand() *cobra.Command { + var ( + provider string + useDeviceCode bool + ) + + cmd := &cobra.Command{ + Use: "login", + Short: "Login via OAuth or paste token", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return authLoginCmd(provider, useDeviceCode) + }, + } + + cmd.Flags().StringVarP(&provider, "provider", "p", "", "Provider to login with (openai, anthropic)") + cmd.Flags().BoolVar(&useDeviceCode, "device-code", false, "Use device code flow (for headless environments)") + _ = cmd.MarkFlagRequired("provider") + + return cmd +} diff --git a/cmd/picoclaw/internal/auth/login_test.go b/cmd/picoclaw/internal/auth/login_test.go new file mode 100644 index 000000000..d6a03c25b --- /dev/null +++ b/cmd/picoclaw/internal/auth/login_test.go @@ -0,0 +1,29 @@ +package auth + +import ( + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewLoginSubCommand(t *testing.T) { + cmd := newLoginCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "Login via OAuth or paste token", cmd.Short) + + assert.True(t, cmd.HasFlags()) + + assert.NotNil(t, cmd.Flags().Lookup("device-code")) + + providerFlag := cmd.Flags().Lookup("provider") + require.NotNil(t, providerFlag) + + val, found := providerFlag.Annotations[cobra.BashCompOneRequiredFlag] + require.True(t, found) + require.NotEmpty(t, val) + assert.Equal(t, "true", val[0]) +} diff --git a/cmd/picoclaw/internal/auth/logout.go b/cmd/picoclaw/internal/auth/logout.go new file mode 100644 index 000000000..384667524 --- /dev/null +++ b/cmd/picoclaw/internal/auth/logout.go @@ -0,0 +1,20 @@ +package auth + +import "github.com/spf13/cobra" + +func newLogoutCommand() *cobra.Command { + var provider string + + cmd := &cobra.Command{ + Use: "logout", + Short: "Remove stored credentials", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return authLogoutCmd(provider) + }, + } + + cmd.Flags().StringVarP(&provider, "provider", "p", "", "Provider to logout from (openai, anthropic); empty = all") + + return cmd +} diff --git a/cmd/picoclaw/internal/auth/logout_test.go b/cmd/picoclaw/internal/auth/logout_test.go new file mode 100644 index 000000000..c0f3a5e92 --- /dev/null +++ b/cmd/picoclaw/internal/auth/logout_test.go @@ -0,0 +1,20 @@ +package auth + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewLogoutSubcommand(t *testing.T) { + cmd := newLogoutCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "Remove stored credentials", cmd.Short) + + assert.True(t, cmd.HasFlags()) + + assert.NotNil(t, cmd.Flags().Lookup("provider")) +} diff --git a/cmd/picoclaw/internal/auth/models.go b/cmd/picoclaw/internal/auth/models.go new file mode 100644 index 000000000..cabe6822c --- /dev/null +++ b/cmd/picoclaw/internal/auth/models.go @@ -0,0 +1,15 @@ +package auth + +import "github.com/spf13/cobra" + +func newModelsCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "models", + Short: "Show available models", + RunE: func(_ *cobra.Command, _ []string) error { + return authModelsCmd() + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/auth/models_test.go b/cmd/picoclaw/internal/auth/models_test.go new file mode 100644 index 000000000..26ca67787 --- /dev/null +++ b/cmd/picoclaw/internal/auth/models_test.go @@ -0,0 +1,19 @@ +package auth + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewModelsCommand(t *testing.T) { + cmd := newModelsCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "models", cmd.Use) + assert.Equal(t, "Show available models", cmd.Short) + + assert.False(t, cmd.HasFlags()) +} diff --git a/cmd/picoclaw/internal/auth/status.go b/cmd/picoclaw/internal/auth/status.go new file mode 100644 index 000000000..ca3007d12 --- /dev/null +++ b/cmd/picoclaw/internal/auth/status.go @@ -0,0 +1,16 @@ +package auth + +import "github.com/spf13/cobra" + +func newStatusCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "status", + Short: "Show current auth status", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return authStatusCmd() + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/auth/status_test.go b/cmd/picoclaw/internal/auth/status_test.go new file mode 100644 index 000000000..7748ba502 --- /dev/null +++ b/cmd/picoclaw/internal/auth/status_test.go @@ -0,0 +1,18 @@ +package auth + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewStatusSubcommand(t *testing.T) { + cmd := newStatusCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "Show current auth status", cmd.Short) + + assert.False(t, cmd.HasFlags()) +} diff --git a/cmd/picoclaw/internal/cron/add.go b/cmd/picoclaw/internal/cron/add.go new file mode 100644 index 000000000..947557d5a --- /dev/null +++ b/cmd/picoclaw/internal/cron/add.go @@ -0,0 +1,64 @@ +package cron + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/pkg/cron" +) + +func newAddCommand(storePath func() string) *cobra.Command { + var ( + name string + message string + every int64 + cronExp string + deliver bool + channel string + to string + ) + + cmd := &cobra.Command{ + Use: "add", + Short: "Add a new scheduled job", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + if every <= 0 && cronExp == "" { + return fmt.Errorf("either --every or --cron must be specified") + } + + var schedule cron.CronSchedule + if every > 0 { + everyMS := every * 1000 + schedule = cron.CronSchedule{Kind: "every", EveryMS: &everyMS} + } else { + schedule = cron.CronSchedule{Kind: "cron", Expr: cronExp} + } + + cs := cron.NewCronService(storePath(), nil) + job, err := cs.AddJob(name, schedule, message, deliver, channel, to) + if err != nil { + return fmt.Errorf("error adding job: %w", err) + } + + fmt.Printf("✓ Added job '%s' (%s)\n", job.Name, job.ID) + + return nil + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "Job name") + cmd.Flags().StringVarP(&message, "message", "m", "", "Message for agent") + cmd.Flags().Int64VarP(&every, "every", "e", 0, "Run every N seconds") + cmd.Flags().StringVarP(&cronExp, "cron", "c", "", "Cron expression (e.g. '0 9 * * *')") + cmd.Flags().BoolVarP(&deliver, "deliver", "d", false, "Deliver response to channel") + cmd.Flags().StringVar(&to, "to", "", "Recipient for delivery") + cmd.Flags().StringVar(&channel, "channel", "", "Channel for delivery") + + _ = cmd.MarkFlagRequired("name") + _ = cmd.MarkFlagRequired("message") + cmd.MarkFlagsMutuallyExclusive("every", "cron") + + return cmd +} diff --git a/cmd/picoclaw/internal/cron/add_test.go b/cmd/picoclaw/internal/cron/add_test.go new file mode 100644 index 000000000..09701fab5 --- /dev/null +++ b/cmd/picoclaw/internal/cron/add_test.go @@ -0,0 +1,57 @@ +package cron + +import ( + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewAddSubcommand(t *testing.T) { + fn := func() string { return "" } + cmd := newAddCommand(fn) + + require.NotNil(t, cmd) + + assert.Equal(t, "add", cmd.Use) + assert.Equal(t, "Add a new scheduled job", cmd.Short) + + assert.True(t, cmd.HasFlags()) + + assert.NotNil(t, cmd.Flags().Lookup("every")) + assert.NotNil(t, cmd.Flags().Lookup("cron")) + assert.NotNil(t, cmd.Flags().Lookup("deliver")) + assert.NotNil(t, cmd.Flags().Lookup("to")) + assert.NotNil(t, cmd.Flags().Lookup("channel")) + + nameFlag := cmd.Flags().Lookup("name") + require.NotNil(t, nameFlag) + + messageFlag := cmd.Flags().Lookup("message") + require.NotNil(t, messageFlag) + + val, found := nameFlag.Annotations[cobra.BashCompOneRequiredFlag] + require.True(t, found) + require.NotEmpty(t, val) + assert.Equal(t, "true", val[0]) + + val, found = messageFlag.Annotations[cobra.BashCompOneRequiredFlag] + require.True(t, found) + require.NotEmpty(t, val) + assert.Equal(t, "true", val[0]) +} + +func TestNewAddCommandEveryAndCronMutuallyExclusive(t *testing.T) { + cmd := newAddCommand(func() string { return "testing" }) + + cmd.SetArgs([]string{ + "--name", "job", + "--message", "hello", + "--every", "10", + "--cron", "0 9 * * *", + }) + + err := cmd.Execute() + require.Error(t, err) +} diff --git a/cmd/picoclaw/internal/cron/command.go b/cmd/picoclaw/internal/cron/command.go new file mode 100644 index 000000000..39f8ccf28 --- /dev/null +++ b/cmd/picoclaw/internal/cron/command.go @@ -0,0 +1,44 @@ +package cron + +import ( + "fmt" + "path/filepath" + + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" +) + +func NewCronCommand() *cobra.Command { + var storePath string + + cmd := &cobra.Command{ + Use: "cron", + Aliases: []string{"c"}, + Short: "Manage scheduled tasks", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() + }, + // Resolve storePath at execution time so it reflects the current config + // and is shared across all subcommands. + PersistentPreRunE: func(_ *cobra.Command, _ []string) error { + cfg, err := internal.LoadConfig() + if err != nil { + return fmt.Errorf("error loading config: %w", err) + } + storePath = filepath.Join(cfg.WorkspacePath(), "cron", "jobs.json") + return nil + }, + } + + cmd.AddCommand( + newListCommand(func() string { return storePath }), + newAddCommand(func() string { return storePath }), + newRemoveCommand(func() string { return storePath }), + newEnableCommand(func() string { return storePath }), + newDisableCommand(func() string { return storePath }), + ) + + return cmd +} diff --git a/cmd/picoclaw/internal/cron/command_test.go b/cmd/picoclaw/internal/cron/command_test.go new file mode 100644 index 000000000..af2ac83ae --- /dev/null +++ b/cmd/picoclaw/internal/cron/command_test.go @@ -0,0 +1,58 @@ +package cron + +import ( + "slices" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewCronCommand(t *testing.T) { + cmd := NewCronCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "Manage scheduled tasks", cmd.Short) + + assert.Len(t, cmd.Aliases, 1) + assert.True(t, cmd.HasAlias("c")) + + assert.False(t, cmd.HasFlags()) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.NotNil(t, cmd.PersistentPreRunE) + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) + + assert.True(t, cmd.HasSubCommands()) + + allowedCommands := []string{ + "list", + "add", + "remove", + "enable", + "disable", + } + + subcommands := cmd.Commands() + assert.Len(t, subcommands, len(allowedCommands)) + + for _, subcmd := range subcommands { + found := slices.Contains(allowedCommands, subcmd.Name()) + assert.True(t, found, "unexpected subcommand %q", subcmd.Name()) + + assert.Len(t, subcmd.Aliases, 0) + assert.False(t, subcmd.Hidden) + + assert.False(t, subcmd.HasSubCommands()) + + assert.Nil(t, subcmd.Run) + assert.NotNil(t, subcmd.RunE) + + assert.Nil(t, subcmd.PersistentPreRun) + assert.Nil(t, subcmd.PersistentPostRun) + } +} diff --git a/cmd/picoclaw/internal/cron/disable.go b/cmd/picoclaw/internal/cron/disable.go new file mode 100644 index 000000000..a3670fd50 --- /dev/null +++ b/cmd/picoclaw/internal/cron/disable.go @@ -0,0 +1,16 @@ +package cron + +import "github.com/spf13/cobra" + +func newDisableCommand(storePath func() string) *cobra.Command { + return &cobra.Command{ + Use: "disable", + Short: "Disable a job", + Args: cobra.ExactArgs(1), + Example: `picoclaw cron disable 1`, + RunE: func(_ *cobra.Command, args []string) error { + cronSetJobEnabled(storePath(), args[0], false) + return nil + }, + } +} diff --git a/cmd/picoclaw/internal/cron/disable_test.go b/cmd/picoclaw/internal/cron/disable_test.go new file mode 100644 index 000000000..e5d2ff844 --- /dev/null +++ b/cmd/picoclaw/internal/cron/disable_test.go @@ -0,0 +1,20 @@ +package cron + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDisableSubcommand(t *testing.T) { + fn := func() string { return "" } + cmd := newDisableCommand(fn) + + require.NotNil(t, cmd) + + assert.Equal(t, "disable", cmd.Use) + assert.Equal(t, "Disable a job", cmd.Short) + + assert.True(t, cmd.HasExample()) +} diff --git a/cmd/picoclaw/internal/cron/enable.go b/cmd/picoclaw/internal/cron/enable.go new file mode 100644 index 000000000..7f8b05233 --- /dev/null +++ b/cmd/picoclaw/internal/cron/enable.go @@ -0,0 +1,16 @@ +package cron + +import "github.com/spf13/cobra" + +func newEnableCommand(storePath func() string) *cobra.Command { + return &cobra.Command{ + Use: "enable", + Short: "Enable a job", + Args: cobra.ExactArgs(1), + Example: `picoclaw cron enable 1`, + RunE: func(_ *cobra.Command, args []string) error { + cronSetJobEnabled(storePath(), args[0], true) + return nil + }, + } +} diff --git a/cmd/picoclaw/internal/cron/enable_test.go b/cmd/picoclaw/internal/cron/enable_test.go new file mode 100644 index 000000000..85a2e01aa --- /dev/null +++ b/cmd/picoclaw/internal/cron/enable_test.go @@ -0,0 +1,20 @@ +package cron + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestEnableSubcommand(t *testing.T) { + fn := func() string { return "" } + cmd := newEnableCommand(fn) + + require.NotNil(t, cmd) + + assert.Equal(t, "enable", cmd.Use) + assert.Equal(t, "Enable a job", cmd.Short) + + assert.True(t, cmd.HasExample()) +} diff --git a/cmd/picoclaw/internal/cron/helpers.go b/cmd/picoclaw/internal/cron/helpers.go new file mode 100644 index 000000000..88bdf1bf7 --- /dev/null +++ b/cmd/picoclaw/internal/cron/helpers.go @@ -0,0 +1,66 @@ +package cron + +import ( + "fmt" + "time" + + "github.com/sipeed/picoclaw/pkg/cron" +) + +func cronListCmd(storePath string) { + cs := cron.NewCronService(storePath, nil) + jobs := cs.ListJobs(true) // Show all jobs, including disabled + + if len(jobs) == 0 { + fmt.Println("No scheduled jobs.") + return + } + + fmt.Println("\nScheduled Jobs:") + fmt.Println("----------------") + for _, job := range jobs { + var schedule string + if job.Schedule.Kind == "every" && job.Schedule.EveryMS != nil { + schedule = fmt.Sprintf("every %ds", *job.Schedule.EveryMS/1000) + } else if job.Schedule.Kind == "cron" { + schedule = job.Schedule.Expr + } else { + schedule = "one-time" + } + + nextRun := "scheduled" + if job.State.NextRunAtMS != nil { + nextTime := time.UnixMilli(*job.State.NextRunAtMS) + nextRun = nextTime.Format("2006-01-02 15:04") + } + + status := "enabled" + if !job.Enabled { + status = "disabled" + } + + fmt.Printf(" %s (%s)\n", job.Name, job.ID) + fmt.Printf(" Schedule: %s\n", schedule) + fmt.Printf(" Status: %s\n", status) + fmt.Printf(" Next run: %s\n", nextRun) + } +} + +func cronRemoveCmd(storePath, jobID string) { + cs := cron.NewCronService(storePath, nil) + if cs.RemoveJob(jobID) { + fmt.Printf("✓ Removed job %s\n", jobID) + } else { + fmt.Printf("✗ Job %s not found\n", jobID) + } +} + +func cronSetJobEnabled(storePath, jobID string, enabled bool) { + cs := cron.NewCronService(storePath, nil) + job := cs.EnableJob(jobID, enabled) + if job != nil { + fmt.Printf("✓ Job '%s' enabled\n", job.Name) + } else { + fmt.Printf("✗ Job %s not found\n", jobID) + } +} diff --git a/cmd/picoclaw/internal/cron/list.go b/cmd/picoclaw/internal/cron/list.go new file mode 100644 index 000000000..854eb1a44 --- /dev/null +++ b/cmd/picoclaw/internal/cron/list.go @@ -0,0 +1,17 @@ +package cron + +import "github.com/spf13/cobra" + +func newListCommand(storePath func() string) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List all scheduled jobs", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, _ []string) error { + cronListCmd(storePath()) + return nil + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/cron/list_test.go b/cmd/picoclaw/internal/cron/list_test.go new file mode 100644 index 000000000..0b9d1bd59 --- /dev/null +++ b/cmd/picoclaw/internal/cron/list_test.go @@ -0,0 +1,17 @@ +package cron + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewListSubcommand(t *testing.T) { + fn := func() string { return "" } + cmd := newListCommand(fn) + + require.NotNil(t, cmd) + + assert.Equal(t, "List all scheduled jobs", cmd.Short) +} diff --git a/cmd/picoclaw/internal/cron/remove.go b/cmd/picoclaw/internal/cron/remove.go new file mode 100644 index 000000000..5f1d1a04b --- /dev/null +++ b/cmd/picoclaw/internal/cron/remove.go @@ -0,0 +1,18 @@ +package cron + +import "github.com/spf13/cobra" + +func newRemoveCommand(storePath func() string) *cobra.Command { + cmd := &cobra.Command{ + Use: "remove", + Short: "Remove a job by ID", + Args: cobra.ExactArgs(1), + Example: `picoclaw cron remove 1`, + RunE: func(_ *cobra.Command, args []string) error { + cronRemoveCmd(storePath(), args[0]) + return nil + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/cron/remove_test.go b/cmd/picoclaw/internal/cron/remove_test.go new file mode 100644 index 000000000..36121f370 --- /dev/null +++ b/cmd/picoclaw/internal/cron/remove_test.go @@ -0,0 +1,19 @@ +package cron + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewRemoveSubcommand(t *testing.T) { + fn := func() string { return "" } + cmd := newRemoveCommand(fn) + + require.NotNil(t, cmd) + + assert.Equal(t, "Remove a job by ID", cmd.Short) + + assert.True(t, cmd.HasExample()) +} diff --git a/cmd/picoclaw/internal/gateway/command.go b/cmd/picoclaw/internal/gateway/command.go new file mode 100644 index 000000000..66a56f9ce --- /dev/null +++ b/cmd/picoclaw/internal/gateway/command.go @@ -0,0 +1,23 @@ +package gateway + +import ( + "github.com/spf13/cobra" +) + +func NewGatewayCommand() *cobra.Command { + var debug bool + + cmd := &cobra.Command{ + Use: "gateway", + Aliases: []string{"g"}, + Short: "Start picoclaw gateway", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, _ []string) error { + return gatewayCmd(debug) + }, + } + + cmd.Flags().BoolVarP(&debug, "debug", "d", false, "Enable debug logging") + + return cmd +} diff --git a/cmd/picoclaw/internal/gateway/command_test.go b/cmd/picoclaw/internal/gateway/command_test.go new file mode 100644 index 000000000..4d591ea67 --- /dev/null +++ b/cmd/picoclaw/internal/gateway/command_test.go @@ -0,0 +1,31 @@ +package gateway + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewGatewayCommand(t *testing.T) { + cmd := NewGatewayCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "gateway", cmd.Use) + assert.Equal(t, "Start picoclaw gateway", cmd.Short) + + assert.Len(t, cmd.Aliases, 1) + assert.True(t, cmd.HasAlias("g")) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) + + assert.False(t, cmd.HasSubCommands()) + + assert.True(t, cmd.HasFlags()) + assert.NotNil(t, cmd.Flags().Lookup("debug")) +} diff --git a/cmd/picoclaw/cmd_gateway.go b/cmd/picoclaw/internal/gateway/helpers.go similarity index 91% rename from cmd/picoclaw/cmd_gateway.go rename to cmd/picoclaw/internal/gateway/helpers.go index 3010c1451..a06625dc9 100644 --- a/cmd/picoclaw/cmd_gateway.go +++ b/cmd/picoclaw/internal/gateway/helpers.go @@ -1,10 +1,8 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main +package gateway import ( "context" + "errors" "fmt" "net/http" "os" @@ -13,6 +11,7 @@ import ( "strings" "time" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/pkg/agent" "github.com/sipeed/picoclaw/pkg/bus" "github.com/sipeed/picoclaw/pkg/channels" @@ -28,28 +27,22 @@ import ( "github.com/sipeed/picoclaw/pkg/voice" ) -func gatewayCmd() { - // Check for --debug flag - args := os.Args[2:] - for _, arg := range args { - if arg == "--debug" || arg == "-d" { - logger.SetLevel(logger.DEBUG) - fmt.Println("🔍 Debug mode enabled") - break - } +func gatewayCmd(debug bool) error { + if debug { + logger.SetLevel(logger.DEBUG) + fmt.Println("🔍 Debug mode enabled") } - cfg, err := loadConfig() + cfg, err := internal.LoadConfig() if err != nil { - fmt.Printf("Error loading config: %v\n", err) - os.Exit(1) + return fmt.Errorf("error loading config: %w", err) } provider, modelID, err := providers.CreateProvider(cfg) if err != nil { - fmt.Printf("Error creating provider: %v\n", err) - os.Exit(1) + return fmt.Errorf("error creating provider: %w", err) } + // Use the resolved model ID from provider creation if modelID != "" { cfg.Agents.Defaults.ModelName = modelID @@ -114,8 +107,7 @@ func gatewayCmd() { channelManager, err := channels.NewManager(cfg, msgBus) if err != nil { - fmt.Printf("Error creating channel manager: %v\n", err) - os.Exit(1) + return fmt.Errorf("error creating channel manager: %w", err) } // Inject channel manager into agent loop for command handling @@ -198,7 +190,7 @@ func gatewayCmd() { healthServer := health.NewServer(cfg.Gateway.Host, cfg.Gateway.Port) go func() { - if err := healthServer.Start(); err != nil && err != http.ErrServerClosed { + if err := healthServer.Start(); err != nil && !errors.Is(err, http.ErrServerClosed) { logger.ErrorCF("health", "Health server error", map[string]any{"error": err.Error()}) } }() @@ -222,6 +214,8 @@ func gatewayCmd() { agentLoop.Stop() channelManager.StopAll(ctx) fmt.Println("✓ Gateway stopped") + + return nil } func setupCronTool( diff --git a/cmd/picoclaw/internal/helpers.go b/cmd/picoclaw/internal/helpers.go new file mode 100644 index 000000000..a084dc1be --- /dev/null +++ b/cmd/picoclaw/internal/helpers.go @@ -0,0 +1,54 @@ +package internal + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + + "github.com/sipeed/picoclaw/pkg/config" +) + +const Logo = "🦞" + +var ( + version = "dev" + gitCommit string + buildTime string + goVersion string +) + +func GetConfigPath() string { + home, _ := os.UserHomeDir() + return filepath.Join(home, ".picoclaw", "config.json") +} + +func LoadConfig() (*config.Config, error) { + return config.LoadConfig(GetConfigPath()) +} + +// FormatVersion returns the version string with optional git commit +func FormatVersion() string { + v := version + if gitCommit != "" { + v += fmt.Sprintf(" (git: %s)", gitCommit) + } + return v +} + +// FormatBuildInfo returns build time and go version info +func FormatBuildInfo() (build string, goVer string) { + if buildTime != "" { + build = buildTime + } + goVer = goVersion + if goVer == "" { + goVer = runtime.Version() + } + return +} + +// GetVersion returns the version string +func GetVersion() string { + return version +} diff --git a/cmd/picoclaw/internal/helpers_test.go b/cmd/picoclaw/internal/helpers_test.go new file mode 100644 index 000000000..9342d141d --- /dev/null +++ b/cmd/picoclaw/internal/helpers_test.go @@ -0,0 +1,97 @@ +package internal + +import ( + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetConfigPath(t *testing.T) { + t.Setenv("HOME", "/tmp/home") + + got := GetConfigPath() + want := filepath.Join("/tmp/home", ".picoclaw", "config.json") + + assert.Equal(t, want, got) +} + +func TestFormatVersion_NoGitCommit(t *testing.T) { + oldVersion, oldGit := version, gitCommit + t.Cleanup(func() { version, gitCommit = oldVersion, oldGit }) + + version = "1.2.3" + gitCommit = "" + + assert.Equal(t, "1.2.3", FormatVersion()) +} + +func TestFormatVersion_WithGitCommit(t *testing.T) { + oldVersion, oldGit := version, gitCommit + t.Cleanup(func() { version, gitCommit = oldVersion, oldGit }) + + version = "1.2.3" + gitCommit = "abc123" + + assert.Equal(t, "1.2.3 (git: abc123)", FormatVersion()) +} + +func TestFormatBuildInfo_UsesBuildTimeAndGoVersion_WhenSet(t *testing.T) { + oldBuildTime, oldGoVersion := buildTime, goVersion + t.Cleanup(func() { buildTime, goVersion = oldBuildTime, oldGoVersion }) + + buildTime = "2026-02-20T00:00:00Z" + goVersion = "go1.23.0" + + build, goVer := FormatBuildInfo() + + assert.Equal(t, buildTime, build) + assert.Equal(t, goVersion, goVer) +} + +func TestFormatBuildInfo_EmptyBuildTime_ReturnsEmptyBuild(t *testing.T) { + oldBuildTime, oldGoVersion := buildTime, goVersion + t.Cleanup(func() { buildTime, goVersion = oldBuildTime, oldGoVersion }) + + buildTime = "" + goVersion = "go1.23.0" + + build, goVer := FormatBuildInfo() + + assert.Empty(t, build) + assert.Equal(t, goVersion, goVer) +} + +func TestFormatBuildInfo_EmptyGoVersion_FallsBackToRuntimeVersion(t *testing.T) { + oldBuildTime, oldGoVersion := buildTime, goVersion + t.Cleanup(func() { buildTime, goVersion = oldBuildTime, oldGoVersion }) + + buildTime = "x" + goVersion = "" + + build, goVer := FormatBuildInfo() + + assert.Equal(t, "x", build) + assert.Equal(t, runtime.Version(), goVer) +} + +func TestGetConfigPath_Windows(t *testing.T) { + if runtime.GOOS != "windows" { + t.Skip("windows-specific HOME behavior varies; run on windows") + } + + testUserProfilePath := `C:\Users\Test` + t.Setenv("USERPROFILE", testUserProfilePath) + + got := GetConfigPath() + want := filepath.Join(testUserProfilePath, ".picoclaw", "config.json") + + require.True(t, strings.EqualFold(got, want), "GetConfigPath() = %q, want %q", got, want) +} + +func TestGetVersion(t *testing.T) { + assert.Equal(t, "dev", GetVersion()) +} diff --git a/cmd/picoclaw/internal/migrate/command.go b/cmd/picoclaw/internal/migrate/command.go new file mode 100644 index 000000000..fb1cee164 --- /dev/null +++ b/cmd/picoclaw/internal/migrate/command.go @@ -0,0 +1,48 @@ +package migrate + +import ( + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/pkg/migrate" +) + +func NewMigrateCommand() *cobra.Command { + var opts migrate.Options + + cmd := &cobra.Command{ + Use: "migrate", + Short: "Migrate from OpenClaw to PicoClaw", + Args: cobra.NoArgs, + Example: ` picoclaw migrate + picoclaw migrate --dry-run + picoclaw migrate --refresh + picoclaw migrate --force`, + RunE: func(cmd *cobra.Command, _ []string) error { + result, err := migrate.Run(opts) + if err != nil { + return err + } + if !opts.DryRun { + migrate.PrintSummary(result) + } + return nil + }, + } + + cmd.Flags().BoolVar(&opts.DryRun, "dry-run", false, + "Show what would be migrated without making changes") + cmd.Flags().BoolVar(&opts.Refresh, "refresh", false, + "Re-sync workspace files from OpenClaw (repeatable)") + cmd.Flags().BoolVar(&opts.ConfigOnly, "config-only", false, + "Only migrate config, skip workspace files") + cmd.Flags().BoolVar(&opts.WorkspaceOnly, "workspace-only", false, + "Only migrate workspace files, skip config") + cmd.Flags().BoolVar(&opts.Force, "force", false, + "Skip confirmation prompts") + cmd.Flags().StringVar(&opts.OpenClawHome, "openclaw-home", "", + "Override OpenClaw home directory (default: ~/.openclaw)") + cmd.Flags().StringVar(&opts.PicoClawHome, "picoclaw-home", "", + "Override PicoClaw home directory (default: ~/.picoclaw)") + + return cmd +} diff --git a/cmd/picoclaw/internal/migrate/command_test.go b/cmd/picoclaw/internal/migrate/command_test.go new file mode 100644 index 000000000..1948aa327 --- /dev/null +++ b/cmd/picoclaw/internal/migrate/command_test.go @@ -0,0 +1,38 @@ +package migrate + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewMigrateCommand(t *testing.T) { + cmd := NewMigrateCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "migrate", cmd.Use) + assert.Equal(t, "Migrate from OpenClaw to PicoClaw", cmd.Short) + + assert.Len(t, cmd.Aliases, 0) + + assert.True(t, cmd.HasExample()) + assert.False(t, cmd.HasSubCommands()) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) + + assert.True(t, cmd.HasFlags()) + + assert.NotNil(t, cmd.Flags().Lookup("dry-run")) + assert.NotNil(t, cmd.Flags().Lookup("refresh")) + assert.NotNil(t, cmd.Flags().Lookup("config-only")) + assert.NotNil(t, cmd.Flags().Lookup("workspace-only")) + assert.NotNil(t, cmd.Flags().Lookup("force")) + assert.NotNil(t, cmd.Flags().Lookup("openclaw-home")) + assert.NotNil(t, cmd.Flags().Lookup("picoclaw-home")) +} diff --git a/cmd/picoclaw/internal/onboard/command.go b/cmd/picoclaw/internal/onboard/command.go new file mode 100644 index 000000000..ec1012959 --- /dev/null +++ b/cmd/picoclaw/internal/onboard/command.go @@ -0,0 +1,24 @@ +package onboard + +import ( + "embed" + + "github.com/spf13/cobra" +) + +//go:generate cp -r ../../../../workspace . +//go:embed workspace +var embeddedFiles embed.FS + +func NewOnboardCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "onboard", + Aliases: []string{"o"}, + Short: "Initialize picoclaw configuration and workspace", + Run: func(cmd *cobra.Command, args []string) { + onboard() + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/onboard/command_test.go b/cmd/picoclaw/internal/onboard/command_test.go new file mode 100644 index 000000000..bc799a079 --- /dev/null +++ b/cmd/picoclaw/internal/onboard/command_test.go @@ -0,0 +1,29 @@ +package onboard + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewOnboardCommand(t *testing.T) { + cmd := NewOnboardCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "onboard", cmd.Use) + assert.Equal(t, "Initialize picoclaw configuration and workspace", cmd.Short) + + assert.Len(t, cmd.Aliases, 1) + assert.True(t, cmd.HasAlias("o")) + + assert.NotNil(t, cmd.Run) + assert.Nil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) + + assert.False(t, cmd.HasFlags()) + assert.False(t, cmd.HasSubCommands()) +} diff --git a/cmd/picoclaw/cmd_onboard.go b/cmd/picoclaw/internal/onboard/helpers.go similarity index 90% rename from cmd/picoclaw/cmd_onboard.go rename to cmd/picoclaw/internal/onboard/helpers.go index 1a9ebad61..4db8bdc8b 100644 --- a/cmd/picoclaw/cmd_onboard.go +++ b/cmd/picoclaw/internal/onboard/helpers.go @@ -1,24 +1,17 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main +package onboard import ( - "embed" "fmt" "io/fs" "os" "path/filepath" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/pkg/config" ) -//go:generate cp -r ../../workspace . -//go:embed workspace -var embeddedFiles embed.FS - func onboard() { - configPath := getConfigPath() + configPath := internal.GetConfigPath() if _, err := os.Stat(configPath); err == nil { fmt.Printf("Config already exists at %s\n", configPath) @@ -40,7 +33,7 @@ func onboard() { workspace := cfg.WorkspacePath() createWorkspaceTemplates(workspace) - fmt.Printf("%s picoclaw is ready!\n", logo) + fmt.Printf("%s picoclaw is ready!\n", internal.Logo) fmt.Println("\nNext steps:") fmt.Println(" 1. Add your API key to", configPath) fmt.Println("") @@ -53,6 +46,13 @@ func onboard() { fmt.Println(" 2. Chat: picoclaw agent -m \"Hello!\"") } +func createWorkspaceTemplates(workspace string) { + err := copyEmbeddedToTarget(workspace) + if err != nil { + fmt.Printf("Error copying workspace templates: %v\n", err) + } +} + func copyEmbeddedToTarget(targetDir string) error { // Ensure target directory exists if err := os.MkdirAll(targetDir, 0o755); err != nil { @@ -99,10 +99,3 @@ func copyEmbeddedToTarget(targetDir string) error { return err } - -func createWorkspaceTemplates(workspace string) { - err := copyEmbeddedToTarget(workspace) - if err != nil { - fmt.Printf("Error copying workspace templates: %v\n", err) - } -} diff --git a/cmd/picoclaw/internal/skills/command.go b/cmd/picoclaw/internal/skills/command.go new file mode 100644 index 000000000..7f8bd011d --- /dev/null +++ b/cmd/picoclaw/internal/skills/command.go @@ -0,0 +1,79 @@ +package skills + +import ( + "fmt" + "path/filepath" + + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" + "github.com/sipeed/picoclaw/pkg/skills" +) + +type deps struct { + workspace string + installer *skills.SkillInstaller + skillsLoader *skills.SkillsLoader +} + +func NewSkillsCommand() *cobra.Command { + var d deps + + cmd := &cobra.Command{ + Use: "skills", + Short: "Manage skills", + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + cfg, err := internal.LoadConfig() + if err != nil { + return fmt.Errorf("error loading config: %w", err) + } + + d.workspace = cfg.WorkspacePath() + d.installer = skills.NewSkillInstaller(d.workspace) + + // get global config directory and builtin skills directory + globalDir := filepath.Dir(internal.GetConfigPath()) + globalSkillsDir := filepath.Join(globalDir, "skills") + builtinSkillsDir := filepath.Join(globalDir, "picoclaw", "skills") + d.skillsLoader = skills.NewSkillsLoader(d.workspace, globalSkillsDir, builtinSkillsDir) + + return nil + }, + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() + }, + } + + installerFn := func() (*skills.SkillInstaller, error) { + if d.installer == nil { + return nil, fmt.Errorf("skills installer is not initialized") + } + return d.installer, nil + } + + loaderFn := func() (*skills.SkillsLoader, error) { + if d.skillsLoader == nil { + return nil, fmt.Errorf("skills loader is not initialized") + } + return d.skillsLoader, nil + } + + workspaceFn := func() (string, error) { + if d.workspace == "" { + return "", fmt.Errorf("workspace is not initialized") + } + return d.workspace, nil + } + + cmd.AddCommand( + newListCommand(loaderFn), + newInstallCommand(installerFn), + newInstallBuiltinCommand(workspaceFn), + newListBuiltinCommand(), + newRemoveCommand(installerFn), + newSearchCommand(installerFn), + newShowCommand(loaderFn), + ) + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/command_test.go b/cmd/picoclaw/internal/skills/command_test.go new file mode 100644 index 000000000..0917d1384 --- /dev/null +++ b/cmd/picoclaw/internal/skills/command_test.go @@ -0,0 +1,28 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewSkillsCommand(t *testing.T) { + cmd := NewSkillsCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "skills", cmd.Use) + assert.Equal(t, "Manage skills", cmd.Short) + + assert.Len(t, cmd.Aliases, 0) + + assert.False(t, cmd.HasFlags()) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.NotNil(t, cmd.PersistentPreRunE) + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) +} diff --git a/cmd/picoclaw/cmd_skills.go b/cmd/picoclaw/internal/skills/helpers.go similarity index 72% rename from cmd/picoclaw/cmd_skills.go rename to cmd/picoclaw/internal/skills/helpers.go index 0814494b3..439b81a4f 100644 --- a/cmd/picoclaw/cmd_skills.go +++ b/cmd/picoclaw/internal/skills/helpers.go @@ -1,40 +1,20 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main +package skills import ( "context" "fmt" + "io" "os" "path/filepath" "strings" "time" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/skills" "github.com/sipeed/picoclaw/pkg/utils" ) -func skillsHelp() { - fmt.Println("\nSkills commands:") - fmt.Println(" list List installed skills") - fmt.Println(" install Install skill from GitHub") - fmt.Println(" install-builtin Install all builtin skills to workspace") - fmt.Println(" list-builtin List available builtin skills") - fmt.Println(" remove Remove installed skill") - fmt.Println(" search Search available skills") - fmt.Println(" show Show skill details") - fmt.Println() - fmt.Println("Examples:") - fmt.Println(" picoclaw skills list") - fmt.Println(" picoclaw skills install sipeed/picoclaw-skills/weather") - fmt.Println(" picoclaw skills install-builtin") - fmt.Println(" picoclaw skills list-builtin") - fmt.Println(" picoclaw skills remove weather") - fmt.Println(" picoclaw skills install --registry clawhub github") -} - func skillsListCmd(loader *skills.SkillsLoader) { allSkills := loader.ListSkills() @@ -53,53 +33,31 @@ func skillsListCmd(loader *skills.SkillsLoader) { } } -func skillsInstallCmd(installer *skills.SkillInstaller, cfg *config.Config) { - if len(os.Args) < 4 { - fmt.Println("Usage: picoclaw skills install ") - fmt.Println(" picoclaw skills install --registry ") - return - } - - // Check for --registry flag. - if os.Args[3] == "--registry" { - if len(os.Args) < 6 { - fmt.Println("Usage: picoclaw skills install --registry ") - fmt.Println("Example: picoclaw skills install --registry clawhub github") - return - } - registryName := os.Args[4] - slug := os.Args[5] - skillsInstallFromRegistry(cfg, registryName, slug) - return - } - - // Default: install from GitHub (backward compatible). - repo := os.Args[3] +func skillsInstallCmd(installer *skills.SkillInstaller, repo string) error { fmt.Printf("Installing skill from %s...\n", repo) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := installer.InstallFromGitHub(ctx, repo); err != nil { - fmt.Printf("\u2717 Failed to install skill: %v\n", err) - os.Exit(1) + return fmt.Errorf("failed to install skill: %w", err) } fmt.Printf("\u2713 Skill '%s' installed successfully!\n", filepath.Base(repo)) + + return nil } // skillsInstallFromRegistry installs a skill from a named registry (e.g. clawhub). -func skillsInstallFromRegistry(cfg *config.Config, registryName, slug string) { +func skillsInstallFromRegistry(cfg *config.Config, registryName, slug string) error { err := utils.ValidateSkillIdentifier(registryName) if err != nil { - fmt.Printf("\u2717 Invalid registry name: %v\n", err) - os.Exit(1) + return fmt.Errorf("✗ invalid registry name: %w", err) } err = utils.ValidateSkillIdentifier(slug) if err != nil { - fmt.Printf("\u2717 Invalid slug: %v\n", err) - os.Exit(1) + return fmt.Errorf("✗ invalid slug: %w", err) } fmt.Printf("Installing skill '%s' from %s registry...\n", slug, registryName) @@ -111,24 +69,21 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, slug string) { registry := registryMgr.GetRegistry(registryName) if registry == nil { - fmt.Printf("\u2717 Registry '%s' not found or not enabled. Check your config.json.\n", registryName) - os.Exit(1) + return fmt.Errorf("✗ registry '%s' not found or not enabled. check your config.json.", registryName) } workspace := cfg.WorkspacePath() targetDir := filepath.Join(workspace, "skills", slug) if _, err = os.Stat(targetDir); err == nil { - fmt.Printf("\u2717 Skill '%s' already installed at %s\n", slug, targetDir) - os.Exit(1) + return fmt.Errorf("\u2717 skill '%s' already installed at %s", slug, targetDir) } ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() if err = os.MkdirAll(filepath.Join(workspace, "skills"), 0o755); err != nil { - fmt.Printf("\u2717 Failed to create skills directory: %v\n", err) - os.Exit(1) + return fmt.Errorf("\u2717 failed to create skills directory: %v", err) } result, err := registry.DownloadAndInstall(ctx, slug, "", targetDir) @@ -137,8 +92,7 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, slug string) { if rmErr != nil { fmt.Printf("\u2717 Failed to remove partial install: %v\n", rmErr) } - fmt.Printf("\u2717 Failed to install skill: %v\n", err) - os.Exit(1) + return fmt.Errorf("✗ failed to install skill: %w", err) } if result.IsMalwareBlocked { @@ -146,8 +100,8 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, slug string) { if rmErr != nil { fmt.Printf("\u2717 Failed to remove partial install: %v\n", rmErr) } - fmt.Printf("\u2717 Skill '%s' is flagged as malicious and cannot be installed.\n", slug) - os.Exit(1) + + return fmt.Errorf("\u2717 Skill '%s' is flagged as malicious and cannot be installed.\n", slug) } if result.IsSuspicious { @@ -158,6 +112,8 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, slug string) { if result.Summary != "" { fmt.Printf(" %s\n", result.Summary) } + + return nil } func skillsRemoveCmd(installer *skills.SkillInstaller, skillName string) { @@ -208,7 +164,7 @@ func skillsInstallBuiltinCmd(workspace string) { } func skillsListBuiltinCmd() { - cfg, err := loadConfig() + cfg, err := internal.LoadConfig() if err != nil { fmt.Printf("Error loading config: %v\n", err) return @@ -303,3 +259,37 @@ func skillsShowCmd(loader *skills.SkillsLoader, skillName string) { fmt.Println("----------------------") fmt.Println(content) } + +func copyDirectory(src, dst string) error { + return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + relPath, err := filepath.Rel(src, path) + if err != nil { + return err + } + + dstPath := filepath.Join(dst, relPath) + + if info.IsDir() { + return os.MkdirAll(dstPath, info.Mode()) + } + + srcFile, err := os.Open(path) + if err != nil { + return err + } + defer srcFile.Close() + + dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, info.Mode()) + if err != nil { + return err + } + defer dstFile.Close() + + _, err = io.Copy(dstFile, srcFile) + return err + }) +} diff --git a/cmd/picoclaw/internal/skills/install.go b/cmd/picoclaw/internal/skills/install.go new file mode 100644 index 000000000..a30f68632 --- /dev/null +++ b/cmd/picoclaw/internal/skills/install.go @@ -0,0 +1,58 @@ +package skills + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" + "github.com/sipeed/picoclaw/pkg/skills" +) + +func newInstallCommand(installerFn func() (*skills.SkillInstaller, error)) *cobra.Command { + var registry string + + cmd := &cobra.Command{ + Use: "install", + Short: "Install skill from GitHub", + Example: ` +picoclaw skills install sipeed/picoclaw-skills/weather +picoclaw skills install --registry clawhub github +`, + Args: func(cmd *cobra.Command, args []string) error { + if registry != "" { + if len(args) != 2 { + return fmt.Errorf("when --registry is set, exactly 2 arguments are required: ") + } + return nil + } + + if len(args) != 1 { + return fmt.Errorf("exactly 1 argument is required: ") + } + + return nil + }, + RunE: func(_ *cobra.Command, args []string) error { + installer, err := installerFn() + if err != nil { + return err + } + + if registry != "" { + cfg, err := internal.LoadConfig() + if err != nil { + return err + } + + return skillsInstallFromRegistry(cfg, args[0], args[1]) + } + + return skillsInstallCmd(installer, args[0]) + }, + } + + cmd.Flags().StringVar(®istry, "registry", "", "Install from registry: --registry ") + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/install_test.go b/cmd/picoclaw/internal/skills/install_test.go new file mode 100644 index 000000000..97787a986 --- /dev/null +++ b/cmd/picoclaw/internal/skills/install_test.go @@ -0,0 +1,28 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewInstallSubcommand(t *testing.T) { + cmd := newInstallCommand(nil) + + require.NotNil(t, cmd) + + assert.Equal(t, "install", cmd.Use) + assert.Equal(t, "Install skill from GitHub", cmd.Short) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.True(t, cmd.HasExample()) + assert.False(t, cmd.HasSubCommands()) + + assert.True(t, cmd.HasFlags()) + assert.NotNil(t, cmd.Flags().Lookup("registry")) + + assert.Len(t, cmd.Aliases, 0) +} diff --git a/cmd/picoclaw/internal/skills/installbuiltin.go b/cmd/picoclaw/internal/skills/installbuiltin.go new file mode 100644 index 000000000..d4b7c6a9f --- /dev/null +++ b/cmd/picoclaw/internal/skills/installbuiltin.go @@ -0,0 +1,21 @@ +package skills + +import "github.com/spf13/cobra" + +func newInstallBuiltinCommand(workspaceFn func() (string, error)) *cobra.Command { + cmd := &cobra.Command{ + Use: "install-builtin", + Short: "Install all builtin skills to workspace", + Example: `picoclaw skills install-builtin`, + RunE: func(_ *cobra.Command, _ []string) error { + workspace, err := workspaceFn() + if err != nil { + return err + } + skillsInstallBuiltinCmd(workspace) + return nil + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/installbuiltin_test.go b/cmd/picoclaw/internal/skills/installbuiltin_test.go new file mode 100644 index 000000000..ea65907e3 --- /dev/null +++ b/cmd/picoclaw/internal/skills/installbuiltin_test.go @@ -0,0 +1,27 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewInstallbuiltinSubcommand(t *testing.T) { + cmd := newInstallBuiltinCommand(nil) + + require.NotNil(t, cmd) + + assert.Equal(t, "install-builtin", cmd.Use) + assert.Equal(t, "Install all builtin skills to workspace", cmd.Short) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.True(t, cmd.HasExample()) + assert.False(t, cmd.HasSubCommands()) + + assert.False(t, cmd.HasFlags()) + + assert.Len(t, cmd.Aliases, 0) +} diff --git a/cmd/picoclaw/internal/skills/list.go b/cmd/picoclaw/internal/skills/list.go new file mode 100644 index 000000000..7d89ff8ed --- /dev/null +++ b/cmd/picoclaw/internal/skills/list.go @@ -0,0 +1,25 @@ +package skills + +import ( + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/pkg/skills" +) + +func newListCommand(loaderFn func() (*skills.SkillsLoader, error)) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List installed skills", + Example: `picoclaw skills list`, + RunE: func(_ *cobra.Command, _ []string) error { + loader, err := loaderFn() + if err != nil { + return err + } + skillsListCmd(loader) + return nil + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/list_test.go b/cmd/picoclaw/internal/skills/list_test.go new file mode 100644 index 000000000..9947ce7aa --- /dev/null +++ b/cmd/picoclaw/internal/skills/list_test.go @@ -0,0 +1,27 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewListSubcommand(t *testing.T) { + cmd := newListCommand(nil) + + require.NotNil(t, cmd) + + assert.Equal(t, "list", cmd.Use) + assert.Equal(t, "List installed skills", cmd.Short) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.True(t, cmd.HasExample()) + assert.False(t, cmd.HasSubCommands()) + + assert.False(t, cmd.HasFlags()) + + assert.Len(t, cmd.Aliases, 0) +} diff --git a/cmd/picoclaw/internal/skills/listbuiltin.go b/cmd/picoclaw/internal/skills/listbuiltin.go new file mode 100644 index 000000000..a3efb8d83 --- /dev/null +++ b/cmd/picoclaw/internal/skills/listbuiltin.go @@ -0,0 +1,16 @@ +package skills + +import "github.com/spf13/cobra" + +func newListBuiltinCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-builtin", + Short: "List available builtin skills", + Example: `picoclaw skills list-builtin`, + Run: func(_ *cobra.Command, _ []string) { + skillsListBuiltinCmd() + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/listbuiltin_test.go b/cmd/picoclaw/internal/skills/listbuiltin_test.go new file mode 100644 index 000000000..d4f45a436 --- /dev/null +++ b/cmd/picoclaw/internal/skills/listbuiltin_test.go @@ -0,0 +1,26 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewListbuiltinSubcommand(t *testing.T) { + cmd := newListBuiltinCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "list-builtin", cmd.Use) + assert.Equal(t, "List available builtin skills", cmd.Short) + + assert.NotNil(t, cmd.Run) + + assert.True(t, cmd.HasExample()) + assert.False(t, cmd.HasSubCommands()) + + assert.False(t, cmd.HasFlags()) + + assert.Len(t, cmd.Aliases, 0) +} diff --git a/cmd/picoclaw/internal/skills/remove.go b/cmd/picoclaw/internal/skills/remove.go new file mode 100644 index 000000000..cd7d3a8b4 --- /dev/null +++ b/cmd/picoclaw/internal/skills/remove.go @@ -0,0 +1,27 @@ +package skills + +import ( + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/pkg/skills" +) + +func newRemoveCommand(installerFn func() (*skills.SkillInstaller, error)) *cobra.Command { + cmd := &cobra.Command{ + Use: "remove", + Aliases: []string{"rm", "uninstall"}, + Short: "Remove installed skill", + Args: cobra.ExactArgs(1), + Example: `picoclaw skills remove weather`, + RunE: func(_ *cobra.Command, args []string) error { + installer, err := installerFn() + if err != nil { + return err + } + skillsRemoveCmd(installer, args[0]) + return nil + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/remove_test.go b/cmd/picoclaw/internal/skills/remove_test.go new file mode 100644 index 000000000..b4c79760c --- /dev/null +++ b/cmd/picoclaw/internal/skills/remove_test.go @@ -0,0 +1,29 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewRemoveSubcommand(t *testing.T) { + cmd := newRemoveCommand(nil) + + require.NotNil(t, cmd) + + assert.Equal(t, "remove", cmd.Use) + assert.Equal(t, "Remove installed skill", cmd.Short) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.True(t, cmd.HasExample()) + assert.False(t, cmd.HasSubCommands()) + + assert.False(t, cmd.HasFlags()) + + assert.Len(t, cmd.Aliases, 2) + assert.True(t, cmd.HasAlias("rm")) + assert.True(t, cmd.HasAlias("uninstall")) +} diff --git a/cmd/picoclaw/internal/skills/search.go b/cmd/picoclaw/internal/skills/search.go new file mode 100644 index 000000000..53bc99109 --- /dev/null +++ b/cmd/picoclaw/internal/skills/search.go @@ -0,0 +1,24 @@ +package skills + +import ( + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/pkg/skills" +) + +func newSearchCommand(installerFn func() (*skills.SkillInstaller, error)) *cobra.Command { + cmd := &cobra.Command{ + Use: "search", + Short: "Search available skills", + RunE: func(_ *cobra.Command, _ []string) error { + installer, err := installerFn() + if err != nil { + return err + } + skillsSearchCmd(installer) + return nil + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/search_test.go b/cmd/picoclaw/internal/skills/search_test.go new file mode 100644 index 000000000..19f63a9ff --- /dev/null +++ b/cmd/picoclaw/internal/skills/search_test.go @@ -0,0 +1,25 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewSearchSubcommand(t *testing.T) { + cmd := newSearchCommand(nil) + + require.NotNil(t, cmd) + + assert.Equal(t, "search", cmd.Use) + assert.Equal(t, "Search available skills", cmd.Short) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.False(t, cmd.HasSubCommands()) + assert.False(t, cmd.HasFlags()) + + assert.Len(t, cmd.Aliases, 0) +} diff --git a/cmd/picoclaw/internal/skills/show.go b/cmd/picoclaw/internal/skills/show.go new file mode 100644 index 000000000..e484f3f28 --- /dev/null +++ b/cmd/picoclaw/internal/skills/show.go @@ -0,0 +1,26 @@ +package skills + +import ( + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/pkg/skills" +) + +func newShowCommand(loaderFn func() (*skills.SkillsLoader, error)) *cobra.Command { + cmd := &cobra.Command{ + Use: "show", + Short: "Show skill details", + Args: cobra.ExactArgs(1), + Example: `picoclaw skills show weather`, + RunE: func(_ *cobra.Command, args []string) error { + loader, err := loaderFn() + if err != nil { + return err + } + skillsShowCmd(loader, args[0]) + return nil + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/skills/show_test.go b/cmd/picoclaw/internal/skills/show_test.go new file mode 100644 index 000000000..5858d2790 --- /dev/null +++ b/cmd/picoclaw/internal/skills/show_test.go @@ -0,0 +1,27 @@ +package skills + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewShowSubcommand(t *testing.T) { + cmd := newShowCommand(nil) + + require.NotNil(t, cmd) + + assert.Equal(t, "show", cmd.Use) + assert.Equal(t, "Show skill details", cmd.Short) + + assert.Nil(t, cmd.Run) + assert.NotNil(t, cmd.RunE) + + assert.True(t, cmd.HasExample()) + assert.False(t, cmd.HasSubCommands()) + + assert.False(t, cmd.HasFlags()) + + assert.Len(t, cmd.Aliases, 0) +} diff --git a/cmd/picoclaw/internal/status/command.go b/cmd/picoclaw/internal/status/command.go new file mode 100644 index 000000000..9303ae2ec --- /dev/null +++ b/cmd/picoclaw/internal/status/command.go @@ -0,0 +1,18 @@ +package status + +import ( + "github.com/spf13/cobra" +) + +func NewStatusCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "status", + Aliases: []string{"s"}, + Short: "Show picoclaw status", + Run: func(cmd *cobra.Command, args []string) { + statusCmd() + }, + } + + return cmd +} diff --git a/cmd/picoclaw/internal/status/command_test.go b/cmd/picoclaw/internal/status/command_test.go new file mode 100644 index 000000000..974b4ea3d --- /dev/null +++ b/cmd/picoclaw/internal/status/command_test.go @@ -0,0 +1,29 @@ +package status + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewStatusCommand(t *testing.T) { + cmd := NewStatusCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "status", cmd.Use) + + assert.Len(t, cmd.Aliases, 1) + assert.True(t, cmd.HasAlias("s")) + + assert.Equal(t, "Show picoclaw status", cmd.Short) + + assert.False(t, cmd.HasSubCommands()) + + assert.NotNil(t, cmd.Run) + assert.Nil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) +} diff --git a/cmd/picoclaw/cmd_status.go b/cmd/picoclaw/internal/status/helpers.go similarity index 90% rename from cmd/picoclaw/cmd_status.go rename to cmd/picoclaw/internal/status/helpers.go index 6a117bd17..ab28f4885 100644 --- a/cmd/picoclaw/cmd_status.go +++ b/cmd/picoclaw/internal/status/helpers.go @@ -1,27 +1,25 @@ -// PicoClaw - Ultra-lightweight personal AI agent -// License: MIT - -package main +package status import ( "fmt" "os" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" "github.com/sipeed/picoclaw/pkg/auth" ) func statusCmd() { - cfg, err := loadConfig() + cfg, err := internal.LoadConfig() if err != nil { fmt.Printf("Error loading config: %v\n", err) return } - configPath := getConfigPath() + configPath := internal.GetConfigPath() - fmt.Printf("%s picoclaw Status\n", logo) - fmt.Printf("Version: %s\n", formatVersion()) - build, _ := formatBuildInfo() + fmt.Printf("%s picoclaw Status\n", internal.Logo) + fmt.Printf("Version: %s\n", internal.FormatVersion()) + build, _ := internal.FormatBuildInfo() if build != "" { fmt.Printf("Build: %s\n", build) } diff --git a/cmd/picoclaw/internal/version/command.go b/cmd/picoclaw/internal/version/command.go new file mode 100644 index 000000000..1cf686671 --- /dev/null +++ b/cmd/picoclaw/internal/version/command.go @@ -0,0 +1,33 @@ +package version + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" +) + +func NewVersionCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "version", + Aliases: []string{"v"}, + Short: "Show version information", + Run: func(_ *cobra.Command, _ []string) { + printVersion() + }, + } + + return cmd +} + +func printVersion() { + fmt.Printf("%s picoclaw %s\n", internal.Logo, internal.FormatVersion()) + build, goVer := internal.FormatBuildInfo() + if build != "" { + fmt.Printf(" Build: %s\n", build) + } + if goVer != "" { + fmt.Printf(" Go: %s\n", goVer) + } +} diff --git a/cmd/picoclaw/internal/version/command_test.go b/cmd/picoclaw/internal/version/command_test.go new file mode 100644 index 000000000..f08a4d1ea --- /dev/null +++ b/cmd/picoclaw/internal/version/command_test.go @@ -0,0 +1,31 @@ +package version + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewVersionCommand(t *testing.T) { + cmd := NewVersionCommand() + + require.NotNil(t, cmd) + + assert.Equal(t, "version", cmd.Use) + + assert.Len(t, cmd.Aliases, 1) + assert.True(t, cmd.HasAlias("v")) + + assert.False(t, cmd.HasFlags()) + + assert.Equal(t, "Show version information", cmd.Short) + + assert.False(t, cmd.HasSubCommands()) + + assert.NotNil(t, cmd.Run) + assert.Nil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) +} diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index 25ad701ca..6db69c990 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -8,192 +8,49 @@ package main import ( "fmt" - "io" "os" - "path/filepath" - "runtime" - "github.com/sipeed/picoclaw/pkg/config" - "github.com/sipeed/picoclaw/pkg/skills" + "github.com/spf13/cobra" + + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/agent" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/auth" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/cron" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/gateway" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/migrate" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/onboard" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/skills" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/status" + "github.com/sipeed/picoclaw/cmd/picoclaw/internal/version" ) -var ( - version = "dev" - gitCommit string - buildTime string - goVersion string -) +func NewPicoclawCommand() *cobra.Command { + short := fmt.Sprintf("%s picoclaw - Personal AI Assistant v%s\n\n", internal.Logo, internal.GetVersion()) -const logo = "🦞" - -// formatVersion returns the version string with optional git commit -func formatVersion() string { - v := version - if gitCommit != "" { - v += fmt.Sprintf(" (git: %s)", gitCommit) + cmd := &cobra.Command{ + Use: "picoclaw", + Short: short, + Example: "picoclaw list", } - return v -} -// formatBuildInfo returns build time and go version info -func formatBuildInfo() (build string, goVer string) { - if buildTime != "" { - build = buildTime - } - goVer = goVersion - if goVer == "" { - goVer = runtime.Version() - } - return -} + cmd.AddCommand( + onboard.NewOnboardCommand(), + agent.NewAgentCommand(), + auth.NewAuthCommand(), + gateway.NewGatewayCommand(), + status.NewStatusCommand(), + cron.NewCronCommand(), + migrate.NewMigrateCommand(), + skills.NewSkillsCommand(), + version.NewVersionCommand(), + ) -func printVersion() { - fmt.Printf("%s picoclaw %s\n", logo, formatVersion()) - build, goVer := formatBuildInfo() - if build != "" { - fmt.Printf(" Build: %s\n", build) - } - if goVer != "" { - fmt.Printf(" Go: %s\n", goVer) - } -} - -func copyDirectory(src, dst string) error { - return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - relPath, err := filepath.Rel(src, path) - if err != nil { - return err - } - - dstPath := filepath.Join(dst, relPath) - - if info.IsDir() { - return os.MkdirAll(dstPath, info.Mode()) - } - - srcFile, err := os.Open(path) - if err != nil { - return err - } - defer srcFile.Close() - - dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, info.Mode()) - if err != nil { - return err - } - defer dstFile.Close() - - _, err = io.Copy(dstFile, srcFile) - return err - }) + return cmd } func main() { - if len(os.Args) < 2 { - printHelp() - os.Exit(1) - } - - command := os.Args[1] - - switch command { - case "onboard": - onboard() - case "agent": - agentCmd() - case "gateway": - gatewayCmd() - case "status": - statusCmd() - case "migrate": - migrateCmd() - case "auth": - authCmd() - case "cron": - cronCmd() - case "skills": - if len(os.Args) < 3 { - skillsHelp() - return - } - - subcommand := os.Args[2] - - cfg, err := loadConfig() - if err != nil { - fmt.Printf("Error loading config: %v\n", err) - os.Exit(1) - } - - workspace := cfg.WorkspacePath() - installer := skills.NewSkillInstaller(workspace) - // get global config directory and builtin skills directory - globalDir := filepath.Dir(getConfigPath()) - globalSkillsDir := filepath.Join(globalDir, "skills") - builtinSkillsDir := filepath.Join(globalDir, "picoclaw", "skills") - skillsLoader := skills.NewSkillsLoader(workspace, globalSkillsDir, builtinSkillsDir) - - switch subcommand { - case "list": - skillsListCmd(skillsLoader) - case "install": - skillsInstallCmd(installer, cfg) - case "remove", "uninstall": - if len(os.Args) < 4 { - fmt.Println("Usage: picoclaw skills remove ") - return - } - skillsRemoveCmd(installer, os.Args[3]) - case "install-builtin": - skillsInstallBuiltinCmd(workspace) - case "list-builtin": - skillsListBuiltinCmd() - case "search": - skillsSearchCmd(installer) - case "show": - if len(os.Args) < 4 { - fmt.Println("Usage: picoclaw skills show ") - return - } - skillsShowCmd(skillsLoader, os.Args[3]) - default: - fmt.Printf("Unknown skills command: %s\n", subcommand) - skillsHelp() - } - case "version", "--version", "-v": - printVersion() - default: - fmt.Printf("Unknown command: %s\n", command) - printHelp() + cmd := NewPicoclawCommand() + if err := cmd.Execute(); err != nil { os.Exit(1) } } - -func printHelp() { - fmt.Printf("%s picoclaw - Personal AI Assistant v%s\n\n", logo, version) - fmt.Println("Usage: picoclaw ") - fmt.Println() - fmt.Println("Commands:") - fmt.Println(" onboard Initialize picoclaw configuration and workspace") - fmt.Println(" agent Interact with the agent directly") - fmt.Println(" auth Manage authentication (login, logout, status)") - fmt.Println(" gateway Start picoclaw gateway") - fmt.Println(" status Show picoclaw status") - fmt.Println(" cron Manage scheduled tasks") - fmt.Println(" migrate Migrate from OpenClaw to PicoClaw") - fmt.Println(" skills Manage skills (install, list, remove)") - fmt.Println(" version Show version information") -} - -func getConfigPath() string { - home, _ := os.UserHomeDir() - return filepath.Join(home, ".picoclaw", "config.json") -} - -func loadConfig() (*config.Config, error) { - return config.LoadConfig(getConfigPath()) -} diff --git a/cmd/picoclaw/main_test.go b/cmd/picoclaw/main_test.go new file mode 100644 index 000000000..3740ba358 --- /dev/null +++ b/cmd/picoclaw/main_test.go @@ -0,0 +1,56 @@ +package main + +import ( + "fmt" + "slices" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/sipeed/picoclaw/cmd/picoclaw/internal" +) + +func TestNewPicoclawCommand(t *testing.T) { + cmd := NewPicoclawCommand() + + require.NotNil(t, cmd) + + short := fmt.Sprintf("%s picoclaw - Personal AI Assistant v%s\n\n", internal.Logo, internal.GetVersion()) + + assert.Equal(t, "picoclaw", cmd.Use) + assert.Equal(t, short, cmd.Short) + + assert.True(t, cmd.HasSubCommands()) + assert.True(t, cmd.HasAvailableSubCommands()) + + assert.False(t, cmd.HasFlags()) + + assert.Nil(t, cmd.Run) + assert.Nil(t, cmd.RunE) + + assert.Nil(t, cmd.PersistentPreRun) + assert.Nil(t, cmd.PersistentPostRun) + + allowedCommands := []string{ + "agent", + "auth", + "cron", + "gateway", + "migrate", + "onboard", + "skills", + "status", + "version", + } + + subcommands := cmd.Commands() + assert.Len(t, subcommands, len(allowedCommands)) + + for _, subcmd := range subcommands { + found := slices.Contains(allowedCommands, subcmd.Name()) + assert.True(t, found, "unexpected subcommand %q", subcmd.Name()) + + assert.False(t, subcmd.Hidden) + } +} diff --git a/go.mod b/go.mod index 1f88639c8..98e20d07d 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1 github.com/openai/openai-go/v3 v3.22.0 github.com/slack-go/slack v0.17.3 + github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 github.com/tencent-connect/botgo v0.2.1 golang.org/x/oauth2 v0.35.0 @@ -22,7 +23,9 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 0e95bf5cd..abbb11cd6 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,7 @@ github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -72,6 +73,8 @@ github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/grbit/go-json v0.11.0 h1:bAbyMdYrYl/OjYsSqLH99N2DyQ291mHy726Mx+sYrnc= github.com/grbit/go-json v0.11.0/go.mod h1:IYpHsdybQ386+6g3VE6AXQ3uTGa5mquBme5/ZWmtzek= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= @@ -108,8 +111,14 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/slack-go/slack v0.17.3 h1:zV5qO3Q+WJAQ/XwbGfNFrRMaJ5T/naqaonyPV/1TP4g= github.com/slack-go/slack v0.17.3/go.mod h1:X+UqOufi3LYQHDnMG1vxf0J8asC6+WllXrVrhl8/Prk= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -151,6 +160,7 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.24.0 h1:qlJ3M9upxvFfwRM51tTg3Yl+8CP9vCC1E7vlFpgv99Y= golang.org/x/arch v0.24.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= From a527976e68d17ba82f18ac4c3482e99adabbd624 Mon Sep 17 00:00:00 2001 From: avaksru <33891999+avaksru@users.noreply.github.com> Date: Wed, 25 Feb 2026 11:01:33 +0300 Subject: [PATCH 28/55] Restore dockers_v2 configuration for picoclaw Re-enable dockers_v2 configuration for picoclaw with specified details. --- .goreleaser.yaml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e3e64c4c8..2fcc43b8c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -40,21 +40,21 @@ builds: - goos: windows goarch: arm -#dockers_v2: -# - id: picoclaw -# dockerfile: Dockerfile.goreleaser -# ids: -# - picoclaw -# images: -# - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/picoclaw" -# - "docker.io/{{ .Env.DOCKERHUB_IMAGE_NAME }}" -# tags: -# - "{{ .Tag }}" -# - "latest" -# platforms: -# - linux/amd64 -# - linux/arm64 -# - linux/riscv64 +dockers_v2: + - id: picoclaw + dockerfile: Dockerfile.goreleaser + ids: + - picoclaw + images: + - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/picoclaw" + - "docker.io/{{ .Env.DOCKERHUB_IMAGE_NAME }}" + tags: + - "{{ .Tag }}" + - "latest" + platforms: + - linux/amd64 + - linux/arm64 + - linux/riscv64 archives: - formats: [tar.gz] From f7d487ea3077f362a4494802558842403cb9025a Mon Sep 17 00:00:00 2001 From: avaksru <33891999+avaksru@users.noreply.github.com> Date: Wed, 25 Feb 2026 11:02:09 +0300 Subject: [PATCH 29/55] Enable Docker Hub login in release workflow --- .github/workflows/release.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ebd75c13..786c893ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -73,12 +73,12 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} -# - name: Login to Docker Hub -# uses: docker/login-action@v3 -# with: -# registry: docker.io -# username: ${{ secrets.DOCKERHUB_USERNAME }} -# password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + registry: docker.io + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 From 43611e2c4e4dd7a13de5c7b0aba2e1ad6768efeb Mon Sep 17 00:00:00 2001 From: Guoguo Date: Tue, 24 Feb 2026 19:09:30 -0800 Subject: [PATCH 30/55] ci: add loongarch64, remove s390x and mips64 support in goreleaser Signed-off-by: Guoguo --- .goreleaser.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index b9357aa2e..9b319f350 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -28,8 +28,7 @@ builds: - amd64 - arm64 - riscv64 - - s390x - - mips64 + - loong64 - arm main: ./cmd/picoclaw ignore: From 974337f4abcbb830db049671ec5c6512f8846e82 Mon Sep 17 00:00:00 2001 From: Guoguo Date: Tue, 24 Feb 2026 19:42:39 -0800 Subject: [PATCH 31/55] ci: add rpm and deb support in goreleaser Signed-off-by: Guoguo --- .goreleaser.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 9b319f350..b864485d3 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -66,6 +66,26 @@ archives: - goos: windows formats: [zip] +nfpms: + - id: picoclaw + package_name: picoclaw + file_name_template: >- + {{ .PackageName }}_ + {{- .Version }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "arm64" }}aarch64 + {{- else if eq .Arch "arm" }}armv{{ .Arm }} + {{- else }}{{ .Arch }}{{ end }} + vendor: picoclaw + homepage: https://github.com/{{ .Env.GITHUB_REPOSITORY_OWNER }}/picoclaw + maintainer: picoclaw contributors + description: picoclaw - a tool for managing and running tasks + license: MIT + formats: + - rpm + - deb + bindir: /usr/bin + changelog: sort: asc filters: From 95f22bc07bfc26c7562bd349d5535fd41b3d7d07 Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 20:43:45 +1100 Subject: [PATCH 32/55] enable bodyclose Checks whether HTTP response body is closed successfully. Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/channels/onebot.go | 5 ++++- pkg/channels/whatsapp.go | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index dd3cbae19..36b8c2832 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -28,7 +28,6 @@ linters: - wsl_v5 # TODO: Disabled, because they are failing at the moment, we should fix them and enable (step by step) - - bodyclose - contextcheck - dogsled - embeddedstructfieldcheck diff --git a/pkg/channels/onebot.go b/pkg/channels/onebot.go index cee8ad9d3..3e26ec943 100644 --- a/pkg/channels/onebot.go +++ b/pkg/channels/onebot.go @@ -174,7 +174,10 @@ func (c *OneBotChannel) connect() error { header["Authorization"] = []string{"Bearer " + c.config.AccessToken} } - conn, _, err := dialer.Dial(c.config.WSUrl, header) + conn, resp, err := dialer.Dial(c.config.WSUrl, header) + if resp != nil { + resp.Body.Close() + } if err != nil { return err } diff --git a/pkg/channels/whatsapp.go b/pkg/channels/whatsapp.go index 958d850bb..2dc4017ac 100644 --- a/pkg/channels/whatsapp.go +++ b/pkg/channels/whatsapp.go @@ -41,7 +41,10 @@ func (c *WhatsAppChannel) Start(ctx context.Context) error { dialer := websocket.DefaultDialer dialer.HandshakeTimeout = 10 * time.Second - conn, _, err := dialer.Dial(c.url, nil) + conn, resp, err := dialer.Dial(c.url, nil) + if resp != nil { + resp.Body.Close() + } if err != nil { return fmt.Errorf("failed to connect to WhatsApp bridge: %w", err) } From 06daa30e75492badef24eaff60e2004661f470c9 Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 20:44:52 +1100 Subject: [PATCH 33/55] enable dogsled Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()). Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/providers/codex_cli_credentials_test.go | 16 ++++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 36b8c2832..26c07200d 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -29,7 +29,6 @@ linters: # TODO: Disabled, because they are failing at the moment, we should fix them and enable (step by step) - contextcheck - - dogsled - embeddedstructfieldcheck - errcheck - errchkjson diff --git a/pkg/providers/codex_cli_credentials_test.go b/pkg/providers/codex_cli_credentials_test.go index 43b21700a..1e88c1120 100644 --- a/pkg/providers/codex_cli_credentials_test.go +++ b/pkg/providers/codex_cli_credentials_test.go @@ -43,12 +43,18 @@ func TestReadCodexCliCredentials_Valid(t *testing.T) { } } +// readCodexCliCredentialsErr calls ReadCodexCliCredentials and returns only the +// error, for tests that only need to assert on failure. +func readCodexCliCredentialsErr() error { + _, _, _, err := ReadCodexCliCredentials() //nolint:dogsled + return err +} + func TestReadCodexCliCredentials_MissingFile(t *testing.T) { tmpDir := t.TempDir() t.Setenv("CODEX_HOME", tmpDir) - _, _, _, err := ReadCodexCliCredentials() - if err == nil { + if err := readCodexCliCredentialsErr(); err == nil { t.Fatal("expected error for missing auth.json") } } @@ -64,8 +70,7 @@ func TestReadCodexCliCredentials_EmptyToken(t *testing.T) { t.Setenv("CODEX_HOME", tmpDir) - _, _, _, err := ReadCodexCliCredentials() - if err == nil { + if err := readCodexCliCredentialsErr(); err == nil { t.Fatal("expected error for empty access_token") } } @@ -80,8 +85,7 @@ func TestReadCodexCliCredentials_InvalidJSON(t *testing.T) { t.Setenv("CODEX_HOME", tmpDir) - _, _, _, err := ReadCodexCliCredentials() - if err == nil { + if err := readCodexCliCredentialsErr(); err == nil { t.Fatal("expected error for invalid JSON") } } From 1fab1967d200fd6ed9bd6b731b6192c20cb30113 Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 20:56:18 +1100 Subject: [PATCH 34/55] enable goprintffuncname Checks that printf-like functions are named with `f` at the end. Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/heartbeat/service.go | 46 +++++++++++++++++------------------ pkg/heartbeat/service_test.go | 2 +- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 26c07200d..0362c1a6f 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -43,7 +43,6 @@ linters: - gocritic - gocyclo - godox - - goprintffuncname - gosec - ineffassign - lll diff --git a/pkg/heartbeat/service.go b/pkg/heartbeat/service.go index 75d6248b9..e05a9fdbf 100644 --- a/pkg/heartbeat/service.go +++ b/pkg/heartbeat/service.go @@ -166,7 +166,7 @@ func (hs *HeartbeatService) executeHeartbeat() { } if handler == nil { - hs.logError("Heartbeat handler not configured") + hs.logErrorf("Heartbeat handler not configured") return } @@ -175,23 +175,23 @@ func (hs *HeartbeatService) executeHeartbeat() { channel, chatID := hs.parseLastChannel(lastChannel) // Debug log for channel resolution - hs.logInfo("Resolved channel: %s, chatID: %s (from lastChannel: %s)", channel, chatID, lastChannel) + hs.logInfof("Resolved channel: %s, chatID: %s (from lastChannel: %s)", channel, chatID, lastChannel) result := handler(prompt, channel, chatID) if result == nil { - hs.logInfo("Heartbeat handler returned nil result") + hs.logInfof("Heartbeat handler returned nil result") return } // Handle different result types if result.IsError { - hs.logError("Heartbeat error: %s", result.ForLLM) + hs.logErrorf("Heartbeat error: %s", result.ForLLM) return } if result.Async { - hs.logInfo("Async task started: %s", result.ForLLM) + hs.logInfof("Async task started: %s", result.ForLLM) logger.InfoCF("heartbeat", "Async heartbeat task started", map[string]any{ "message": result.ForLLM, @@ -201,7 +201,7 @@ func (hs *HeartbeatService) executeHeartbeat() { // Check if silent if result.Silent { - hs.logInfo("Heartbeat OK - silent") + hs.logInfof("Heartbeat OK - silent") return } @@ -212,7 +212,7 @@ func (hs *HeartbeatService) executeHeartbeat() { hs.sendResponse(result.ForLLM) } - hs.logInfo("Heartbeat completed: %s", result.ForLLM) + hs.logInfof("Heartbeat completed: %s", result.ForLLM) } // buildPrompt builds the heartbeat prompt from HEARTBEAT.md @@ -225,7 +225,7 @@ func (hs *HeartbeatService) buildPrompt() string { hs.createDefaultHeartbeatTemplate() return "" } - hs.logError("Error reading HEARTBEAT.md: %v", err) + hs.logErrorf("Error reading HEARTBEAT.md: %v", err) return "" } @@ -276,9 +276,9 @@ Add your heartbeat tasks below this line: ` if err := os.WriteFile(heartbeatPath, []byte(defaultContent), 0o644); err != nil { - hs.logError("Failed to create default HEARTBEAT.md: %v", err) + hs.logErrorf("Failed to create default HEARTBEAT.md: %v", err) } else { - hs.logInfo("Created default HEARTBEAT.md template") + hs.logInfof("Created default HEARTBEAT.md template") } } @@ -289,14 +289,14 @@ func (hs *HeartbeatService) sendResponse(response string) { hs.mu.RUnlock() if msgBus == nil { - hs.logInfo("No message bus configured, heartbeat result not sent") + hs.logInfof("No message bus configured, heartbeat result not sent") return } // Get last channel from state lastChannel := hs.state.GetLastChannel() if lastChannel == "" { - hs.logInfo("No last channel recorded, heartbeat result not sent") + hs.logInfof("No last channel recorded, heartbeat result not sent") return } @@ -313,7 +313,7 @@ func (hs *HeartbeatService) sendResponse(response string) { Content: response, }) - hs.logInfo("Heartbeat result sent to %s", platform) + hs.logInfof("Heartbeat result sent to %s", platform) } // parseLastChannel parses the last channel string into platform and userID. @@ -326,7 +326,7 @@ func (hs *HeartbeatService) parseLastChannel(lastChannel string) (platform, user // Parse channel format: "platform:user_id" (e.g., "telegram:123456") parts := strings.SplitN(lastChannel, ":", 2) if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - hs.logError("Invalid last channel format: %s", lastChannel) + hs.logErrorf("Invalid last channel format: %s", lastChannel) return "", "" } @@ -334,25 +334,25 @@ func (hs *HeartbeatService) parseLastChannel(lastChannel string) (platform, user // Skip internal channels if constants.IsInternalChannel(platform) { - hs.logInfo("Skipping internal channel: %s", platform) + hs.logInfof("Skipping internal channel: %s", platform) return "", "" } return platform, userID } -// logInfo logs an informational message to the heartbeat log -func (hs *HeartbeatService) logInfo(format string, args ...any) { - hs.log("INFO", format, args...) +// logInfof logs an informational message to the heartbeat log +func (hs *HeartbeatService) logInfof(format string, args ...any) { + hs.logf("INFO", format, args...) } -// logError logs an error message to the heartbeat log -func (hs *HeartbeatService) logError(format string, args ...any) { - hs.log("ERROR", format, args...) +// logErrorf logs an error message to the heartbeat log +func (hs *HeartbeatService) logErrorf(format string, args ...any) { + hs.logf("ERROR", format, args...) } -// log writes a message to the heartbeat log file -func (hs *HeartbeatService) log(level, format string, args ...any) { +// logf writes a message to the heartbeat log file +func (hs *HeartbeatService) logf(level, format string, args ...any) { logFile := filepath.Join(hs.workspace, "heartbeat.log") f, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { diff --git a/pkg/heartbeat/service_test.go b/pkg/heartbeat/service_test.go index a4dfa7a72..a7aef8c3a 100644 --- a/pkg/heartbeat/service_test.go +++ b/pkg/heartbeat/service_test.go @@ -191,7 +191,7 @@ func TestLogPath(t *testing.T) { hs := NewHeartbeatService(tmpDir, 30, true) // Write a log entry - hs.log("INFO", "Test log entry") + hs.logf("INFO", "Test log entry") // Verify log file exists at workspace root expectedLogPath := filepath.Join(tmpDir, "heartbeat.log") From c5e8e19f54843d5461a8fada9f0df477e18e6ad2 Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 20:58:49 +1100 Subject: [PATCH 35/55] enable misspell Finds commonly misspelled English words. Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/auth/oauth.go | 2 +- pkg/channels/onebot.go | 2 +- pkg/tools/subagent.go | 12 ++++++------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 0362c1a6f..5fea4a994 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -47,7 +47,6 @@ linters: - ineffassign - lll - maintidx - - misspell - mnd - modernize - nakedret diff --git a/pkg/auth/oauth.go b/pkg/auth/oauth.go index cf8c1c9c4..ba757ffd4 100644 --- a/pkg/auth/oauth.go +++ b/pkg/auth/oauth.go @@ -156,7 +156,7 @@ func LoginBrowser(cfg OAuthProviderConfig) (*AuthCredential, error) { return exchangeCodeForTokens(cfg, result.code, pkce.CodeVerifier, redirectURI) case manualInput := <-manualCh: if manualInput == "" { - return nil, fmt.Errorf("manual input cancelled") + return nil, fmt.Errorf("manual input canceled") } // Extract code from URL if it's a full URL code := manualInput diff --git a/pkg/channels/onebot.go b/pkg/channels/onebot.go index 3e26ec943..7238c7fe8 100644 --- a/pkg/channels/onebot.go +++ b/pkg/channels/onebot.go @@ -313,7 +313,7 @@ func (c *OneBotChannel) sendAPIRequest(action string, params any, timeout time.D case <-time.After(timeout): return nil, fmt.Errorf("API request %s timed out after %v", action, timeout) case <-c.ctx.Done(): - return nil, fmt.Errorf("context cancelled") + return nil, fmt.Errorf("context canceled") } } diff --git a/pkg/tools/subagent.go b/pkg/tools/subagent.go index 91ebff636..ad371a649 100644 --- a/pkg/tools/subagent.go +++ b/pkg/tools/subagent.go @@ -132,12 +132,12 @@ After completing the task, provide a clear summary of what was done.` }, } - // Check if context is already cancelled before starting + // Check if context is already canceled before starting select { case <-ctx.Done(): sm.mu.Lock() - task.Status = "cancelled" - task.Result = "Task cancelled before execution" + task.Status = "canceled" + task.Result = "Task canceled before execution" sm.mu.Unlock() return default: @@ -185,10 +185,10 @@ After completing the task, provide a clear summary of what was done.` if err != nil { task.Status = "failed" task.Result = fmt.Sprintf("Error: %v", err) - // Check if it was cancelled + // Check if it was canceled if ctx.Err() != nil { - task.Status = "cancelled" - task.Result = "Task cancelled during execution" + task.Status = "canceled" + task.Result = "Task canceled during execution" } result = &ToolResult{ ForLLM: task.Result, From 09cf8efde6159f9d8daffa27a89baf898b97b4bc Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 21:00:56 +1100 Subject: [PATCH 36/55] enable nakedret Checks that functions with naked returns are not longer than a maximum size (can be zero). Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/channels/slack.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 5fea4a994..8dca46c15 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -49,7 +49,6 @@ linters: - maintidx - mnd - modernize - - nakedret - nestif - nilnil - paralleltest diff --git a/pkg/channels/slack.go b/pkg/channels/slack.go index f087aa8da..cfb731b16 100644 --- a/pkg/channels/slack.go +++ b/pkg/channels/slack.go @@ -439,5 +439,5 @@ func parseSlackChatID(chatID string) (channelID, threadTS string) { if len(parts) > 1 { threadTS = parts[1] } - return + return channelID, threadTS } From 4e6589d51f1a4ffddc320ceb55c281c884122c7d Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 21:07:28 +1100 Subject: [PATCH 37/55] enable prealloc Find slice declarations that could potentially be pre-allocated. Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/agent/loop.go | 2 +- pkg/logger/logger.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 8dca46c15..ec17cb00e 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -53,7 +53,6 @@ linters: - nilnil - paralleltest - perfsprint - - prealloc - predeclared - revive - staticcheck diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index dbc4a9b87..540563b07 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -800,7 +800,7 @@ func (al *AgentLoop) forceCompression(agent *AgentInstance, sessionKey string) { droppedCount := mid keptConversation := conversation[mid:] - newHistory := make([]providers.Message, 0) + newHistory := make([]providers.Message, 0, 1+len(keptConversation)+1) // Append compression note to the original system prompt instead of adding a new system message // This avoids having two consecutive system messages which some APIs (like Zhipu) reject diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index c14fbd464..56dc87a53 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -153,7 +153,7 @@ func formatComponent(component string) string { } func formatFields(fields map[string]any) string { - var parts []string + parts := make([]string, 0, len(fields)) for k, v := range fields { parts = append(parts, fmt.Sprintf("%s=%v", k, v)) } From 6830790692f2721703c48588b39e02ab72dbc67b Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 21:08:35 +1100 Subject: [PATCH 38/55] enable predeclared Find code that shadows one of Go's predeclared identifiers. Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/providers/codex_provider.go | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index ec17cb00e..efd460e92 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -53,7 +53,6 @@ linters: - nilnil - paralleltest - perfsprint - - predeclared - revive - staticcheck - tagalign diff --git a/pkg/providers/codex_provider.go b/pkg/providers/codex_provider.go index ecc983642..195374bea 100644 --- a/pkg/providers/codex_provider.go +++ b/pkg/providers/codex_provider.go @@ -106,8 +106,8 @@ func (p *CodexProvider) Chat( if evt.Type == "response.completed" || evt.Type == "response.failed" || evt.Type == "response.incomplete" { evtResp := evt.Response if evtResp.ID != "" { - copy := evtResp - resp = © + evtRespCopy := evtResp + resp = &evtRespCopy } } } From d8b164b3d43dc50cae9269d472fec7992b71f0ce Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 21:12:12 +1100 Subject: [PATCH 39/55] enable wastedassign Finds wasted assignment statements. Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/channels/discord.go | 2 +- pkg/channels/telegram.go | 2 +- pkg/providers/github_copilot_provider.go | 2 +- pkg/tools/shell.go | 3 +-- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index efd460e92..e4c41518f 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -61,7 +61,6 @@ linters: - unparam - usestdlibvars - usetesting - - wastedassign - whitespace settings: errcheck: diff --git a/pkg/channels/discord.go b/pkg/channels/discord.go index 20f3b267c..f6faa3373 100644 --- a/pkg/channels/discord.go +++ b/pkg/channels/discord.go @@ -233,7 +233,7 @@ func (c *DiscordChannel) handleMessage(s *discordgo.Session, m *discordgo.Messag if localPath != "" { localFiles = append(localFiles, localPath) - transcribedText := "" + var transcribedText string if c.transcriber != nil && c.transcriber.IsAvailable() { ctx, cancel := context.WithTimeout(c.getContext(), transcriptionTimeout) result, err := c.transcriber.Transcribe(ctx, localPath) diff --git a/pkg/channels/telegram.go b/pkg/channels/telegram.go index 5cd51e8bc..524494849 100644 --- a/pkg/channels/telegram.go +++ b/pkg/channels/telegram.go @@ -265,7 +265,7 @@ func (c *TelegramChannel) handleMessage(ctx context.Context, message *telego.Mes localFiles = append(localFiles, voicePath) mediaPaths = append(mediaPaths, voicePath) - transcribedText := "" + var transcribedText string if c.transcriber != nil && c.transcriber.IsAvailable() { transcriberCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() diff --git a/pkg/providers/github_copilot_provider.go b/pkg/providers/github_copilot_provider.go index 9210021e1..4faa9bddb 100644 --- a/pkg/providers/github_copilot_provider.go +++ b/pkg/providers/github_copilot_provider.go @@ -101,7 +101,7 @@ func (p *GitHubCopilotProvider) Chat( return nil, fmt.Errorf("provider closed") } - resp, err := session.SendAndWait(ctx, copilot.MessageOptions{ + resp, _ := session.SendAndWait(ctx, copilot.MessageOptions{ Prompt: string(fullcontent), }) diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index 6883172cd..ad1664b5b 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -76,10 +76,9 @@ func NewExecTool(workingDir string, restrict bool) *ExecTool { func NewExecToolWithConfig(workingDir string, restrict bool, config *config.Config) *ExecTool { denyPatterns := make([]*regexp.Regexp, 0) - enableDenyPatterns := true if config != nil { execConfig := config.Tools.Exec - enableDenyPatterns = execConfig.EnableDenyPatterns + enableDenyPatterns := execConfig.EnableDenyPatterns if enableDenyPatterns { denyPatterns = append(denyPatterns, defaultDenyPatterns...) if len(execConfig.CustomDenyPatterns) > 0 { From b190e6e9107313d557220191841141c83766a548 Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 21:13:22 +1100 Subject: [PATCH 40/55] enable whitespace Whitespace is a linter that checks for unnecessary newlines at the start and end of functions, if, for, etc. Signed-off-by: Kai Xia --- .golangci.yaml | 1 - pkg/channels/onebot.go | 1 - pkg/providers/github_copilot_provider.go | 1 - 3 files changed, 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index e4c41518f..d0ba90716 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -61,7 +61,6 @@ linters: - unparam - usestdlibvars - usetesting - - whitespace settings: errcheck: check-type-assertions: true diff --git a/pkg/channels/onebot.go b/pkg/channels/onebot.go index 7238c7fe8..4576a11ce 100644 --- a/pkg/channels/onebot.go +++ b/pkg/channels/onebot.go @@ -698,7 +698,6 @@ func (c *OneBotChannel) parseMessageSegments(raw json.RawMessage, selfID int64) textParts = append(textParts, "[forward message]") default: - } } diff --git a/pkg/providers/github_copilot_provider.go b/pkg/providers/github_copilot_provider.go index 4faa9bddb..3fb15db2f 100644 --- a/pkg/providers/github_copilot_provider.go +++ b/pkg/providers/github_copilot_provider.go @@ -44,7 +44,6 @@ func NewGitHubCopilotProvider(uri string, connectMode string, model string) (*Gi Hooks: &copilot.SessionHooks{}, }) if err != nil { - client.Stop() return nil, fmt.Errorf("create session failed: %w", err) } From 9be1cd6277bdcce85c15cdcd692283fba2302b9e Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Wed, 25 Feb 2026 21:32:57 +1100 Subject: [PATCH 41/55] a moved case of nakedret Signed-off-by: Kai Xia --- cmd/picoclaw/internal/helpers.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmd/picoclaw/internal/helpers.go b/cmd/picoclaw/internal/helpers.go index a084dc1be..1f52df5dd 100644 --- a/cmd/picoclaw/internal/helpers.go +++ b/cmd/picoclaw/internal/helpers.go @@ -37,15 +37,13 @@ func FormatVersion() string { } // FormatBuildInfo returns build time and go version info -func FormatBuildInfo() (build string, goVer string) { - if buildTime != "" { - build = buildTime - } - goVer = goVersion +func FormatBuildInfo() (string, string) { + build := buildTime + goVer := goVersion if goVer == "" { goVer = runtime.Version() } - return + return build, goVer } // GetVersion returns the version string From d1d19b12ce3b817524382f32b827e0bdb917f3cd Mon Sep 17 00:00:00 2001 From: Guoguo <16666742+imguoguo@users.noreply.github.com> Date: Wed, 25 Feb 2026 19:19:55 +0800 Subject: [PATCH 42/55] docs: update wechat qrcode (#767) Signed-off-by: Guoguo --- assets/wechat.png | Bin 150574 -> 143877 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/wechat.png b/assets/wechat.png index e30c34e4ed81210338d63ee4486c4356d01ae30b..776c07885dc495cb25e0b43c18f4e94b23b98511 100644 GIT binary patch literal 143877 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
2JA~)ZE}P+I0<7b%`D8TU5P6?<3PC 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%0Al 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 Date: Wed, 25 Feb 2026 20:44:07 +0800 Subject: [PATCH 43/55] fix: remove redundant tools definitions from system prompt (#771) * fix: remove redundant tools definitions from system prompt Tools are already provided to the LLM via JSON schema through ToProviderDefs(), so the text-based tools section in the system prompt is redundant. This removes the buildToolsSection() logic and the tools field from ContextBuilder, reducing system prompt length while maintaining the "ALWAYS use tools" rule reminder. Fixes #731 Co-Authored-By: Claude Opus 4.5 * fix: correct spelling 'initialized' (was 'initialised') --------- Co-authored-by: Claude Opus 4.5 --- pkg/agent/context.go | 40 ++-------------------------------------- pkg/agent/instance.go | 1 - pkg/agent/loop.go | 3 --- 3 files changed, 2 insertions(+), 42 deletions(-) diff --git a/pkg/agent/context.go b/pkg/agent/context.go index 7d6f2762b..b7c6e1108 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -14,14 +14,12 @@ import ( "github.com/sipeed/picoclaw/pkg/logger" "github.com/sipeed/picoclaw/pkg/providers" "github.com/sipeed/picoclaw/pkg/skills" - "github.com/sipeed/picoclaw/pkg/tools" ) type ContextBuilder struct { workspace string skillsLoader *skills.SkillsLoader memory *MemoryStore - tools *tools.ToolRegistry // Direct reference to tool registry // Cache for system prompt to avoid rebuilding on every call. // This fixes issue #607: repeated reprocessing of the entire context. @@ -59,17 +57,9 @@ func NewContextBuilder(workspace string) *ContextBuilder { } } -// SetToolsRegistry sets the tools registry for dynamic tool summary generation. -func (cb *ContextBuilder) SetToolsRegistry(registry *tools.ToolRegistry) { - cb.tools = registry -} - func (cb *ContextBuilder) getIdentity() string { workspacePath, _ := filepath.Abs(filepath.Join(cb.workspace)) - // Build tools section dynamically - toolsSection := cb.buildToolsSection() - return fmt.Sprintf(`# picoclaw 🦞 You are picoclaw, a helpful AI assistant. @@ -80,8 +70,6 @@ Your workspace is at: %s - Daily Notes: %s/memory/YYYYMM/YYYYMMDD.md - Skills: %s/skills/{skill-name}/SKILL.md -%s - ## Important Rules 1. **ALWAYS use tools** - When you need to perform an action (schedule reminders, send messages, execute commands, etc.), you MUST call the appropriate tool. Do NOT just say you'll do it or pretend to do it. @@ -91,31 +79,7 @@ Your workspace is at: %s 3. **Memory** - When interacting with me if something seems memorable, update %s/memory/MEMORY.md 4. **Context summaries** - Conversation summaries provided as context are approximate references only. They may be incomplete or outdated. Always defer to explicit user instructions over summary content.`, - workspacePath, workspacePath, workspacePath, workspacePath, toolsSection, workspacePath) -} - -func (cb *ContextBuilder) buildToolsSection() string { - if cb.tools == nil { - return "" - } - - summaries := cb.tools.GetSummaries() - if len(summaries) == 0 { - return "" - } - - var sb strings.Builder - sb.WriteString("## Available Tools\n\n") - sb.WriteString( - "**CRITICAL**: You MUST use tools to perform actions. Do NOT pretend to execute commands or schedule tasks.\n\n", - ) - sb.WriteString("You have access to the following tools:\n\n") - for _, s := range summaries { - sb.WriteString(s) - sb.WriteString("\n") - } - - return sb.String() + workspacePath, workspacePath, workspacePath, workspacePath, workspacePath) } func (cb *ContextBuilder) BuildSystemPrompt() string { @@ -321,7 +285,7 @@ func (cb *ContextBuilder) sourceFilesChangedLocked() bool { // - absent at cache time, exists now -> changed (created) // - absent at cache time, gone now -> no change func (cb *ContextBuilder) fileChangedSince(path string) bool { - // Defensive: if existedAtCache was never initialised, treat as changed + // Defensive: if existedAtCache was never initialized, treat as changed // so the cache rebuilds rather than silently serving stale data. if cb.existedAtCache == nil { return true diff --git a/pkg/agent/instance.go b/pkg/agent/instance.go index c6a54c7d2..a6fd365c7 100644 --- a/pkg/agent/instance.go +++ b/pkg/agent/instance.go @@ -59,7 +59,6 @@ func NewAgentInstance( sessionsManager := session.NewSessionManager(sessionsDir) contextBuilder := NewContextBuilder(workspace) - contextBuilder.SetToolsRegistry(toolsRegistry) agentID := routing.DefaultAgentID agentName := "" diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index dea30218e..5558f7c0e 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -149,9 +149,6 @@ func registerSharedTools( return registry.CanSpawnSubagent(currentAgentID, targetAgentID) }) agent.Tools.Register(spawnTool) - - // Update context builder with the complete tools registry - agent.ContextBuilder.SetToolsRegistry(agent.Tools) } } From 162f38cd4f544c66991202799ce3b7d5bc8c873c Mon Sep 17 00:00:00 2001 From: avaksru <33891999+avaksru@users.noreply.github.com> Date: Wed, 25 Feb 2026 16:29:04 +0300 Subject: [PATCH 44/55] fix Code Review: PR #768 --- .goreleaser.yaml | 4 +--- Makefile | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 2fcc43b8c..3b3cbbfa3 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -32,9 +32,7 @@ builds: - mips64 - arm goarm: - - "7" - - "6" - - "5" + - "7" main: ./cmd/picoclaw ignore: - goos: windows diff --git a/Makefile b/Makefile index f99c7712e..0caaf78db 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,7 @@ build-all: generate GOOS=linux GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(CMD_DIR) GOOS=linux GOARCH=loong64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-loong64 ./$(CMD_DIR) GOOS=linux GOARCH=riscv64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-riscv64 ./$(CMD_DIR) - GOOS=linux GOARCH=arm GOARM=7 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-armv7l ./$(CMD_DIR) + GOOS=linux GOARCH=arm GOARM=7 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-armv7 ./$(CMD_DIR) GOOS=darwin GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 ./$(CMD_DIR) GOOS=windows GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe ./$(CMD_DIR) @echo "All builds complete" From c8a553f109793bc73cef24a955ca0ef895597838 Mon Sep 17 00:00:00 2001 From: George Wang Date: Mon, 23 Feb 2026 16:23:10 +0800 Subject: [PATCH 45/55] add proxy support for TavilySearchProvider --- pkg/config/defaults.go | 1 + pkg/tools/web.go | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index b96ee4d89..cc6de9399 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -277,6 +277,7 @@ func DefaultConfig() *Config { }, Tools: ToolsConfig{ Web: WebToolsConfig{ + Proxy: "", Brave: BraveConfig{ Enabled: false, APIKey: "", diff --git a/pkg/tools/web.go b/pkg/tools/web.go index 968579dea..edf9531ad 100644 --- a/pkg/tools/web.go +++ b/pkg/tools/web.go @@ -129,6 +129,7 @@ func (p *BraveSearchProvider) Search(ctx context.Context, query string, count in type TavilySearchProvider struct { apiKey string baseURL string + proxy string } func (p *TavilySearchProvider) Search(ctx context.Context, query string, count int) (string, error) { @@ -160,7 +161,10 @@ func (p *TavilySearchProvider) Search(ctx context.Context, query string, count i req.Header.Set("Content-Type", "application/json") req.Header.Set("User-Agent", userAgent) - client := &http.Client{Timeout: 10 * time.Second} + client, err := createHTTPClient(p.proxy, 10*time.Second) + if err != nil { + return "", fmt.Errorf("failed to create http client: %w", err) + } resp, err := client.Do(req) if err != nil { return "", fmt.Errorf("request failed: %w", err) @@ -420,6 +424,7 @@ func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool { provider = &TavilySearchProvider{ apiKey: opts.TavilyAPIKey, baseURL: opts.TavilyBaseURL, + proxy: opts.Proxy, } if opts.TavilyMaxResults > 0 { maxResults = opts.TavilyMaxResults From ef1989f12eed8c9be31427d68d303dfa85820d5c Mon Sep 17 00:00:00 2001 From: George Wang Date: Wed, 25 Feb 2026 23:04:41 +0800 Subject: [PATCH 46/55] Update pkg/tools/web.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- pkg/tools/web.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tools/web.go b/pkg/tools/web.go index edf9531ad..44df28215 100644 --- a/pkg/tools/web.go +++ b/pkg/tools/web.go @@ -163,7 +163,7 @@ func (p *TavilySearchProvider) Search(ctx context.Context, query string, count i client, err := createHTTPClient(p.proxy, 10*time.Second) if err != nil { - return "", fmt.Errorf("failed to create http client: %w", err) + return "", fmt.Errorf("failed to create HTTP client: %w", err) } resp, err := client.Do(req) if err != nil { From ea902429f2c3ce6be60e8e925a49d777527d950c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=B0=BD=EC=9A=B1?= Date: Wed, 25 Feb 2026 07:09:46 -0800 Subject: [PATCH 47/55] fix: exclude prompt_cache_key for Gemini API requests Gemini's OpenAI-compat endpoint rejects unknown fields. Only send prompt_cache_key to OpenAI-native endpoints. --- pkg/providers/openai_compat/provider.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index a8d244d4a..087d3506e 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -115,8 +115,12 @@ func (p *Provider) Chat( // with the same key and reuse prefix KV cache across calls. // The key is typically the agent ID — stable per agent, shared across requests. // See: https://platform.openai.com/docs/guides/prompt-caching + // Prompt caching is only supported by OpenAI-native endpoints. + // Gemini and other providers reject unknown fields, so skip for non-OpenAI APIs. if cacheKey, ok := options["prompt_cache_key"].(string); ok && cacheKey != "" { - requestBody["prompt_cache_key"] = cacheKey + if !strings.Contains(p.apiBase, "generativelanguage.googleapis.com") { + requestBody["prompt_cache_key"] = cacheKey + } } jsonData, err := json.Marshal(requestBody) From 851920d4b0958d3b26771c0205cfa31881ad7427 Mon Sep 17 00:00:00 2001 From: lxowalle <83055338+lxowalle@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:54:05 +0800 Subject: [PATCH 48/55] docs: fix readme typo (#798) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b770f215..aa7b0719a 100644 --- a/README.md +++ b/README.md @@ -1143,7 +1143,7 @@ discord: ## 🐛 Troubleshooting -### Web search says "API 配置问题" +### Web search says "API key configuration issue" This is normal if you haven't configured a search API key yet. PicoClaw will provide helpful links for manual searching. From 8f606733a2b6e208dc3fe799122774b3fa39c011 Mon Sep 17 00:00:00 2001 From: lxowalle <83055338+lxowalle@users.noreply.github.com> Date: Thu, 26 Feb 2026 12:36:19 +0800 Subject: [PATCH 49/55] fix: hide compressed historical messages notification (#799) --- pkg/agent/loop.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 5558f7c0e..693f2227b 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -759,13 +759,7 @@ func (al *AgentLoop) maybeSummarize(agent *AgentInstance, sessionKey, channel, c if _, loading := al.summarizing.LoadOrStore(summarizeKey, true); !loading { go func() { defer al.summarizing.Delete(summarizeKey) - if !constants.IsInternalChannel(channel) { - al.bus.PublishOutbound(bus.OutboundMessage{ - Channel: channel, - ChatID: chatID, - Content: "Memory threshold reached. Optimizing conversation history...", - }) - } + logger.Debug("Memory threshold reached. Optimizing conversation history...") al.summarizeSession(agent, sessionKey) }() } From a5cc4db5149e6493fe432076cbd9d46e9f4ca3f1 Mon Sep 17 00:00:00 2001 From: Guoguo <16666742+imguoguo@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:53:10 +0800 Subject: [PATCH 50/55] ci: remove version from rpm and deb file name (#804) Signed-off-by: Guoguo --- .goreleaser.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 23e422ab1..69bf1fae3 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -73,7 +73,6 @@ nfpms: package_name: picoclaw file_name_template: >- {{ .PackageName }}_ - {{- .Version }}_ {{- if eq .Arch "amd64" }}x86_64 {{- else if eq .Arch "arm64" }}aarch64 {{- else if eq .Arch "arm" }}armv{{ .Arm }} From 6a4116b8a0953ed21ecd8714189e86abc4f99275 Mon Sep 17 00:00:00 2001 From: Guoguo <16666742+imguoguo@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:03:58 +0800 Subject: [PATCH 51/55] ci: fix go generate not running in subdirectories (#807) Changed `go generate ./cmd/picoclaw` to `go generate ./cmd/picoclaw/...` so that the workspace embed in cmd/picoclaw/internal/onboard is correctly generated before building. Co-authored-by: Claude Sonnet 4.6 --- .goreleaser.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 69bf1fae3..af26509e6 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -5,7 +5,7 @@ version: 2 before: hooks: - go mod tidy - - go generate ./cmd/picoclaw + - go generate ./cmd/picoclaw/... builds: - id: picoclaw From 438f764c7ac0d7aa851bae45b04d2fdf5299f257 Mon Sep 17 00:00:00 2001 From: Yiliu <3838688+0xYiliu@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:08:19 +0800 Subject: [PATCH 52/55] fix(providers): support per-model request_timeout in model_list (#733) * fix(providers): support per-model request_timeout in model_list * fix(lint): format provider constructors for golines * refactor(providers): adopt functional options and preserve timeout migration * docs(readme): sync request_timeout guidance across translated docs --------- Co-authored-by: Yiliu --- README.fr.md | 15 ++ README.ja.md | 15 ++ README.md | 7 +- README.pt-br.md | 15 ++ README.vi.md | 15 ++ README.zh.md | 7 +- docs/migration/model-list-migration.md | 1 + pkg/config/config.go | 12 +- pkg/config/migration.go | 180 ++++++++++--------- pkg/config/migration_test.go | 21 +++ pkg/config/model_config_test.go | 35 ++++ pkg/providers/factory_provider.go | 24 ++- pkg/providers/factory_provider_test.go | 43 +++++ pkg/providers/http_provider.go | 16 +- pkg/providers/openai_compat/provider.go | 56 +++++- pkg/providers/openai_compat/provider_test.go | 36 ++++ 16 files changed, 394 insertions(+), 104 deletions(-) diff --git a/README.fr.md b/README.fr.md index f59807739..f1d4f848e 100644 --- a/README.fr.md +++ b/README.fr.md @@ -221,6 +221,7 @@ picoclaw onboard "model_name": "gpt4", "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key", + "request_timeout": 300, "api_base": "https://api.openai.com/v1" } ], @@ -252,6 +253,9 @@ picoclaw onboard } ``` +> **Nouveau** : Le format de configuration `model_list` permet d'ajouter des fournisseurs sans modifier le code. Voir [Configuration de Modèle](#configuration-de-modèle-model_list) pour plus de détails. +> `request_timeout` est optionnel et s'exprime en secondes. S'il est omis ou défini à `<= 0`, PicoClaw utilise le délai d'expiration par défaut (120s). + **3. Obtenir des Clés API** * **Fournisseur LLM** : [OpenRouter](https://openrouter.ai/keys) · [Zhipu](https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys) · [Anthropic](https://console.anthropic.com) · [OpenAI](https://platform.openai.com) · [Gemini](https://aistudio.google.com/api-keys) @@ -979,6 +983,17 @@ Cette conception permet également le **support multi-agent** avec une sélectio ``` > Exécutez `picoclaw auth login --provider anthropic` pour configurer les identifiants OAuth. +**Proxy/API personnalisée** +```json +{ + "model_name": "my-custom-model", + "model": "openai/custom-model", + "api_base": "https://my-proxy.com/v1", + "api_key": "sk-...", + "request_timeout": 300 +} +``` + #### Équilibrage de Charge Configurez plusieurs points de terminaison pour le même nom de modèle—PicoClaw utilisera automatiquement le round-robin entre eux : diff --git a/README.ja.md b/README.ja.md index 5a7bb8542..48fb89fe3 100644 --- a/README.ja.md +++ b/README.ja.md @@ -183,6 +183,7 @@ picoclaw onboard "model_name": "gpt4", "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key", + "request_timeout": 300, "api_base": "https://api.openai.com/v1" } ], @@ -221,6 +222,9 @@ picoclaw onboard } ``` +> **新機能**: `model_list` 形式により、プロバイダーをコード変更なしで追加できます。詳細は [モデル設定](#モデル設定-model_list) を参照してください。 +> `request_timeout` は任意の秒単位設定です。省略または `<= 0` の場合、PicoClaw はデフォルトのタイムアウト(120秒)を使用します。 + **3. API キーの取得** - **LLM プロバイダー**: [OpenRouter](https://openrouter.ai/keys) · [Zhipu](https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys) · [Anthropic](https://console.anthropic.com) · [OpenAI](https://platform.openai.com) · [Gemini](https://aistudio.google.com/api-keys) @@ -918,6 +922,17 @@ HEARTBEAT_OK 応答 ユーザーが直接結果を受け取る ``` > OAuth認証を設定するには、`picoclaw auth login --provider anthropic` を実行してください。 +**カスタムプロキシ/API** +```json +{ + "model_name": "my-custom-model", + "model": "openai/custom-model", + "api_base": "https://my-proxy.com/v1", + "api_key": "sk-...", + "request_timeout": 300 +} +``` + #### ロードバランシング 同じモデル名で複数のエンドポイントを設定すると、PicoClaw が自動的にラウンドロビンで分散します: diff --git a/README.md b/README.md index aa7b0719a..72a933b6f 100644 --- a/README.md +++ b/README.md @@ -232,7 +232,8 @@ picoclaw onboard { "model_name": "gpt4", "model": "openai/gpt-5.2", - "api_key": "your-api-key" + "api_key": "your-api-key", + "request_timeout": 300 }, { "model_name": "claude-sonnet-4.6", @@ -262,6 +263,7 @@ picoclaw onboard ``` > **New**: The `model_list` configuration format allows zero-code provider addition. See [Model Configuration](#model-configuration-model_list) for details. +> `request_timeout` is optional and uses seconds. If omitted or set to `<= 0`, PicoClaw uses the default timeout (120s). **3. Get API Keys** @@ -915,7 +917,8 @@ This design also enables **multi-agent support** with flexible provider selectio "model_name": "my-custom-model", "model": "openai/custom-model", "api_base": "https://my-proxy.com/v1", - "api_key": "sk-..." + "api_key": "sk-...", + "request_timeout": 300 } ``` diff --git a/README.pt-br.md b/README.pt-br.md index 0115b7f89..1dbee5201 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -222,6 +222,7 @@ picoclaw onboard "model_name": "gpt4", "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key", + "request_timeout": 300, "api_base": "https://api.openai.com/v1" } ], @@ -246,6 +247,9 @@ picoclaw onboard } ``` +> **Novo**: O formato de configuração `model_list` permite adicionar provedores sem alterar código. Veja [Configuração de Modelo](#configuração-de-modelo-model_list) para detalhes. +> `request_timeout` é opcional e usa segundos. Se omitido ou definido como `<= 0`, o PicoClaw usa o timeout padrão (120s). + **3. Obter API Keys** * **Provedor de LLM**: [OpenRouter](https://openrouter.ai/keys) · [Zhipu](https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys) · [Anthropic](https://console.anthropic.com) · [OpenAI](https://platform.openai.com) · [Gemini](https://aistudio.google.com/api-keys) @@ -973,6 +977,17 @@ Este design também possibilita o **suporte multi-agent** com seleção flexíve ``` > Execute `picoclaw auth login --provider anthropic` para configurar credenciais OAuth. +**Proxy/API personalizada** +```json +{ + "model_name": "my-custom-model", + "model": "openai/custom-model", + "api_base": "https://my-proxy.com/v1", + "api_key": "sk-...", + "request_timeout": 300 +} +``` + #### Balanceamento de Carga Configure vários endpoints para o mesmo nome de modelo—PicoClaw fará round-robin automaticamente entre eles: diff --git a/README.vi.md b/README.vi.md index 015bc264e..0dd4994c2 100644 --- a/README.vi.md +++ b/README.vi.md @@ -202,6 +202,7 @@ picoclaw onboard "model_name": "gpt4", "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key", + "request_timeout": 300, "api_base": "https://api.openai.com/v1" } ], @@ -220,6 +221,9 @@ picoclaw onboard } ``` +> **Mới**: Định dạng cấu hình `model_list` cho phép thêm nhà cung cấp mà không cần thay đổi mã nguồn. Xem [Cấu hình Mô hình](#cấu-hình-mô-hình-model_list) để biết chi tiết. +> `request_timeout` là tùy chọn và dùng đơn vị giây. Nếu bỏ qua hoặc đặt `<= 0`, PicoClaw sẽ dùng timeout mặc định (120s). + **3. Lấy API Key** * **Nhà cung cấp LLM**: [OpenRouter](https://openrouter.ai/keys) · [Zhipu](https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys) · [Anthropic](https://console.anthropic.com) · [OpenAI](https://platform.openai.com) · [Gemini](https://aistudio.google.com/api-keys) @@ -944,6 +948,17 @@ Thiết kế này cũng cho phép **hỗ trợ đa tác nhân** với lựa ch ``` > Chạy `picoclaw auth login --provider anthropic` để thiết lập thông tin xác thực OAuth. +**Proxy/API tùy chỉnh** +```json +{ + "model_name": "my-custom-model", + "model": "openai/custom-model", + "api_base": "https://my-proxy.com/v1", + "api_key": "sk-...", + "request_timeout": 300 +} +``` + #### Cân bằng Tải tải Định cấu hình nhiều endpoint cho cùng một tên mô hình—PicoClaw sẽ tự động phân phối round-robin giữa chúng: diff --git a/README.zh.md b/README.zh.md index 4f4bde46a..8ce1ad2ee 100644 --- a/README.zh.md +++ b/README.zh.md @@ -234,7 +234,8 @@ picoclaw onboard { "model_name": "gpt4", "model": "openai/gpt-5.2", - "api_key": "your-api-key" + "api_key": "your-api-key", + "request_timeout": 300 }, { "model_name": "claude-sonnet-4.6", @@ -263,6 +264,7 @@ picoclaw onboard ``` > **新功能**: `model_list` 配置格式支持零代码添加 provider。详见[模型配置](#模型配置-model_list)章节。 +> `request_timeout` 为可选项,单位为秒。若省略或设置为 `<= 0`,PicoClaw 使用默认超时(120 秒)。 **3. 获取 API Key** @@ -550,7 +552,8 @@ Agent 读取 HEARTBEAT.md "model_name": "my-custom-model", "model": "openai/custom-model", "api_base": "https://my-proxy.com/v1", - "api_key": "sk-..." + "api_key": "sk-...", + "request_timeout": 300 } ``` diff --git a/docs/migration/model-list-migration.md b/docs/migration/model-list-migration.md index 589dfc043..0d4af719c 100644 --- a/docs/migration/model-list-migration.md +++ b/docs/migration/model-list-migration.md @@ -117,6 +117,7 @@ The `model` field uses a protocol prefix format: `[protocol/]model-identifier` | `connect_mode` | No | Connection mode for CLI providers: `stdio`, `grpc` | | `rpm` | No | Requests per minute limit | | `max_tokens_field` | No | Field name for max tokens | +| `request_timeout` | No | HTTP request timeout in seconds; `<=0` uses default `120s` | *`api_key` is required for HTTP-based protocols unless `api_base` points to a local server. diff --git a/pkg/config/config.go b/pkg/config/config.go index 6f76614cf..16559a2df 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -371,11 +371,12 @@ func (p ProvidersConfig) MarshalJSON() ([]byte, error) { } type ProviderConfig struct { - APIKey string `json:"api_key" env:"PICOCLAW_PROVIDERS_{{.Name}}_API_KEY"` - APIBase string `json:"api_base" env:"PICOCLAW_PROVIDERS_{{.Name}}_API_BASE"` - Proxy string `json:"proxy,omitempty" env:"PICOCLAW_PROVIDERS_{{.Name}}_PROXY"` - AuthMethod string `json:"auth_method,omitempty" env:"PICOCLAW_PROVIDERS_{{.Name}}_AUTH_METHOD"` - ConnectMode string `json:"connect_mode,omitempty" env:"PICOCLAW_PROVIDERS_{{.Name}}_CONNECT_MODE"` // only for Github Copilot, `stdio` or `grpc` + APIKey string `json:"api_key" env:"PICOCLAW_PROVIDERS_{{.Name}}_API_KEY"` + APIBase string `json:"api_base" env:"PICOCLAW_PROVIDERS_{{.Name}}_API_BASE"` + Proxy string `json:"proxy,omitempty" env:"PICOCLAW_PROVIDERS_{{.Name}}_PROXY"` + RequestTimeout int `json:"request_timeout,omitempty" env:"PICOCLAW_PROVIDERS_{{.Name}}_REQUEST_TIMEOUT"` + AuthMethod string `json:"auth_method,omitempty" env:"PICOCLAW_PROVIDERS_{{.Name}}_AUTH_METHOD"` + ConnectMode string `json:"connect_mode,omitempty" env:"PICOCLAW_PROVIDERS_{{.Name}}_CONNECT_MODE"` // only for Github Copilot, `stdio` or `grpc` } type OpenAIProviderConfig struct { @@ -406,6 +407,7 @@ type ModelConfig struct { // Optional optimizations RPM int `json:"rpm,omitempty"` // Requests per minute limit MaxTokensField string `json:"max_tokens_field,omitempty"` // Field name for max tokens (e.g., "max_completion_tokens") + RequestTimeout int `json:"request_timeout,omitempty"` } // Validate checks if the ModelConfig has all required fields. diff --git a/pkg/config/migration.go b/pkg/config/migration.go index 70e1de438..5deb09270 100644 --- a/pkg/config/migration.go +++ b/pkg/config/migration.go @@ -60,12 +60,13 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "openai", - Model: "openai/gpt-5.2", - APIKey: p.OpenAI.APIKey, - APIBase: p.OpenAI.APIBase, - Proxy: p.OpenAI.Proxy, - AuthMethod: p.OpenAI.AuthMethod, + ModelName: "openai", + Model: "openai/gpt-5.2", + APIKey: p.OpenAI.APIKey, + APIBase: p.OpenAI.APIBase, + Proxy: p.OpenAI.Proxy, + RequestTimeout: p.OpenAI.RequestTimeout, + AuthMethod: p.OpenAI.AuthMethod, }, true }, }, @@ -77,12 +78,13 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "anthropic", - Model: "anthropic/claude-sonnet-4.6", - APIKey: p.Anthropic.APIKey, - APIBase: p.Anthropic.APIBase, - Proxy: p.Anthropic.Proxy, - AuthMethod: p.Anthropic.AuthMethod, + ModelName: "anthropic", + Model: "anthropic/claude-sonnet-4.6", + APIKey: p.Anthropic.APIKey, + APIBase: p.Anthropic.APIBase, + Proxy: p.Anthropic.Proxy, + RequestTimeout: p.Anthropic.RequestTimeout, + AuthMethod: p.Anthropic.AuthMethod, }, true }, }, @@ -94,11 +96,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "openrouter", - Model: "openrouter/auto", - APIKey: p.OpenRouter.APIKey, - APIBase: p.OpenRouter.APIBase, - Proxy: p.OpenRouter.Proxy, + ModelName: "openrouter", + Model: "openrouter/auto", + APIKey: p.OpenRouter.APIKey, + APIBase: p.OpenRouter.APIBase, + Proxy: p.OpenRouter.Proxy, + RequestTimeout: p.OpenRouter.RequestTimeout, }, true }, }, @@ -110,11 +113,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "groq", - Model: "groq/llama-3.1-70b-versatile", - APIKey: p.Groq.APIKey, - APIBase: p.Groq.APIBase, - Proxy: p.Groq.Proxy, + ModelName: "groq", + Model: "groq/llama-3.1-70b-versatile", + APIKey: p.Groq.APIKey, + APIBase: p.Groq.APIBase, + Proxy: p.Groq.Proxy, + RequestTimeout: p.Groq.RequestTimeout, }, true }, }, @@ -126,11 +130,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "zhipu", - Model: "zhipu/glm-4", - APIKey: p.Zhipu.APIKey, - APIBase: p.Zhipu.APIBase, - Proxy: p.Zhipu.Proxy, + ModelName: "zhipu", + Model: "zhipu/glm-4", + APIKey: p.Zhipu.APIKey, + APIBase: p.Zhipu.APIBase, + Proxy: p.Zhipu.Proxy, + RequestTimeout: p.Zhipu.RequestTimeout, }, true }, }, @@ -142,11 +147,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "vllm", - Model: "vllm/auto", - APIKey: p.VLLM.APIKey, - APIBase: p.VLLM.APIBase, - Proxy: p.VLLM.Proxy, + ModelName: "vllm", + Model: "vllm/auto", + APIKey: p.VLLM.APIKey, + APIBase: p.VLLM.APIBase, + Proxy: p.VLLM.Proxy, + RequestTimeout: p.VLLM.RequestTimeout, }, true }, }, @@ -158,11 +164,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "gemini", - Model: "gemini/gemini-pro", - APIKey: p.Gemini.APIKey, - APIBase: p.Gemini.APIBase, - Proxy: p.Gemini.Proxy, + ModelName: "gemini", + Model: "gemini/gemini-pro", + APIKey: p.Gemini.APIKey, + APIBase: p.Gemini.APIBase, + Proxy: p.Gemini.Proxy, + RequestTimeout: p.Gemini.RequestTimeout, }, true }, }, @@ -174,11 +181,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "nvidia", - Model: "nvidia/meta/llama-3.1-8b-instruct", - APIKey: p.Nvidia.APIKey, - APIBase: p.Nvidia.APIBase, - Proxy: p.Nvidia.Proxy, + ModelName: "nvidia", + Model: "nvidia/meta/llama-3.1-8b-instruct", + APIKey: p.Nvidia.APIKey, + APIBase: p.Nvidia.APIBase, + Proxy: p.Nvidia.Proxy, + RequestTimeout: p.Nvidia.RequestTimeout, }, true }, }, @@ -190,11 +198,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "ollama", - Model: "ollama/llama3", - APIKey: p.Ollama.APIKey, - APIBase: p.Ollama.APIBase, - Proxy: p.Ollama.Proxy, + ModelName: "ollama", + Model: "ollama/llama3", + APIKey: p.Ollama.APIKey, + APIBase: p.Ollama.APIBase, + Proxy: p.Ollama.Proxy, + RequestTimeout: p.Ollama.RequestTimeout, }, true }, }, @@ -206,11 +215,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "moonshot", - Model: "moonshot/kimi", - APIKey: p.Moonshot.APIKey, - APIBase: p.Moonshot.APIBase, - Proxy: p.Moonshot.Proxy, + ModelName: "moonshot", + Model: "moonshot/kimi", + APIKey: p.Moonshot.APIKey, + APIBase: p.Moonshot.APIBase, + Proxy: p.Moonshot.Proxy, + RequestTimeout: p.Moonshot.RequestTimeout, }, true }, }, @@ -222,11 +232,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "shengsuanyun", - Model: "shengsuanyun/auto", - APIKey: p.ShengSuanYun.APIKey, - APIBase: p.ShengSuanYun.APIBase, - Proxy: p.ShengSuanYun.Proxy, + ModelName: "shengsuanyun", + Model: "shengsuanyun/auto", + APIKey: p.ShengSuanYun.APIKey, + APIBase: p.ShengSuanYun.APIBase, + Proxy: p.ShengSuanYun.Proxy, + RequestTimeout: p.ShengSuanYun.RequestTimeout, }, true }, }, @@ -238,11 +249,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "deepseek", - Model: "deepseek/deepseek-chat", - APIKey: p.DeepSeek.APIKey, - APIBase: p.DeepSeek.APIBase, - Proxy: p.DeepSeek.Proxy, + ModelName: "deepseek", + Model: "deepseek/deepseek-chat", + APIKey: p.DeepSeek.APIKey, + APIBase: p.DeepSeek.APIBase, + Proxy: p.DeepSeek.Proxy, + RequestTimeout: p.DeepSeek.RequestTimeout, }, true }, }, @@ -254,11 +266,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "cerebras", - Model: "cerebras/llama-3.3-70b", - APIKey: p.Cerebras.APIKey, - APIBase: p.Cerebras.APIBase, - Proxy: p.Cerebras.Proxy, + ModelName: "cerebras", + Model: "cerebras/llama-3.3-70b", + APIKey: p.Cerebras.APIKey, + APIBase: p.Cerebras.APIBase, + Proxy: p.Cerebras.Proxy, + RequestTimeout: p.Cerebras.RequestTimeout, }, true }, }, @@ -270,11 +283,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "volcengine", - Model: "volcengine/doubao-pro", - APIKey: p.VolcEngine.APIKey, - APIBase: p.VolcEngine.APIBase, - Proxy: p.VolcEngine.Proxy, + ModelName: "volcengine", + Model: "volcengine/doubao-pro", + APIKey: p.VolcEngine.APIKey, + APIBase: p.VolcEngine.APIBase, + Proxy: p.VolcEngine.Proxy, + RequestTimeout: p.VolcEngine.RequestTimeout, }, true }, }, @@ -316,11 +330,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "qwen", - Model: "qwen/qwen-max", - APIKey: p.Qwen.APIKey, - APIBase: p.Qwen.APIBase, - Proxy: p.Qwen.Proxy, + ModelName: "qwen", + Model: "qwen/qwen-max", + APIKey: p.Qwen.APIKey, + APIBase: p.Qwen.APIBase, + Proxy: p.Qwen.Proxy, + RequestTimeout: p.Qwen.RequestTimeout, }, true }, }, @@ -332,11 +347,12 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { return ModelConfig{}, false } return ModelConfig{ - ModelName: "mistral", - Model: "mistral/mistral-small-latest", - APIKey: p.Mistral.APIKey, - APIBase: p.Mistral.APIBase, - Proxy: p.Mistral.Proxy, + ModelName: "mistral", + Model: "mistral/mistral-small-latest", + APIKey: p.Mistral.APIKey, + APIBase: p.Mistral.APIBase, + Proxy: p.Mistral.Proxy, + RequestTimeout: p.Mistral.RequestTimeout, }, true }, }, diff --git a/pkg/config/migration_test.go b/pkg/config/migration_test.go index 42165cb71..db8f4657d 100644 --- a/pkg/config/migration_test.go +++ b/pkg/config/migration_test.go @@ -166,6 +166,27 @@ func TestConvertProvidersToModelList_Proxy(t *testing.T) { } } +func TestConvertProvidersToModelList_RequestTimeout(t *testing.T) { + cfg := &Config{ + Providers: ProvidersConfig{ + Ollama: ProviderConfig{ + APIKey: "ollama-key", + RequestTimeout: 300, + }, + }, + } + + result := ConvertProvidersToModelList(cfg) + + if len(result) != 1 { + t.Fatalf("len(result) = %d, want 1", len(result)) + } + + if result[0].RequestTimeout != 300 { + t.Errorf("RequestTimeout = %d, want %d", result[0].RequestTimeout, 300) + } +} + func TestConvertProvidersToModelList_AuthMethod(t *testing.T) { cfg := &Config{ Providers: ProvidersConfig{ diff --git a/pkg/config/model_config_test.go b/pkg/config/model_config_test.go index 99eea2782..084f50a82 100644 --- a/pkg/config/model_config_test.go +++ b/pkg/config/model_config_test.go @@ -365,3 +365,38 @@ func TestConfig_ValidateModelList(t *testing.T) { }) } } + +func TestModelConfig_RequestTimeoutParsing(t *testing.T) { + jsonData := `{ + "model_name": "slow-local", + "model": "openai/local-model", + "api_base": "http://localhost:11434/v1", + "request_timeout": 300 + }` + + var cfg ModelConfig + if err := json.Unmarshal([]byte(jsonData), &cfg); err != nil { + t.Fatalf("Unmarshal() error = %v", err) + } + + if cfg.RequestTimeout != 300 { + t.Fatalf("RequestTimeout = %d, want 300", cfg.RequestTimeout) + } +} + +func TestModelConfig_RequestTimeoutDefaultZeroValue(t *testing.T) { + jsonData := `{ + "model_name": "default-timeout", + "model": "openai/gpt-4o", + "api_key": "test-key" + }` + + var cfg ModelConfig + if err := json.Unmarshal([]byte(jsonData), &cfg); err != nil { + t.Fatalf("Unmarshal() error = %v", err) + } + + if cfg.RequestTimeout != 0 { + t.Fatalf("RequestTimeout = %d, want 0", cfg.RequestTimeout) + } +} diff --git a/pkg/providers/factory_provider.go b/pkg/providers/factory_provider.go index 7d5566eef..53f7a08a0 100644 --- a/pkg/providers/factory_provider.go +++ b/pkg/providers/factory_provider.go @@ -84,7 +84,13 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err if apiBase == "" { apiBase = getDefaultAPIBase(protocol) } - return NewHTTPProviderWithMaxTokensField(cfg.APIKey, apiBase, cfg.Proxy, cfg.MaxTokensField), modelID, nil + return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( + cfg.APIKey, + apiBase, + cfg.Proxy, + cfg.MaxTokensField, + cfg.RequestTimeout, + ), modelID, nil case "openrouter", "groq", "zhipu", "gemini", "nvidia", "ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras", @@ -97,7 +103,13 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err if apiBase == "" { apiBase = getDefaultAPIBase(protocol) } - return NewHTTPProviderWithMaxTokensField(cfg.APIKey, apiBase, cfg.Proxy, cfg.MaxTokensField), modelID, nil + return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( + cfg.APIKey, + apiBase, + cfg.Proxy, + cfg.MaxTokensField, + cfg.RequestTimeout, + ), modelID, nil case "anthropic": if cfg.AuthMethod == "oauth" || cfg.AuthMethod == "token" { @@ -116,7 +128,13 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err if cfg.APIKey == "" { return nil, "", fmt.Errorf("api_key is required for anthropic protocol (model: %s)", cfg.Model) } - return NewHTTPProviderWithMaxTokensField(cfg.APIKey, apiBase, cfg.Proxy, cfg.MaxTokensField), modelID, nil + return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( + cfg.APIKey, + apiBase, + cfg.Proxy, + cfg.MaxTokensField, + cfg.RequestTimeout, + ), modelID, nil case "antigravity": return NewAntigravityProvider(), modelID, nil diff --git a/pkg/providers/factory_provider_test.go b/pkg/providers/factory_provider_test.go index 6b133101a..e0c0eddef 100644 --- a/pkg/providers/factory_provider_test.go +++ b/pkg/providers/factory_provider_test.go @@ -6,7 +6,11 @@ package providers import ( + "net/http" + "net/http/httptest" + "strings" "testing" + "time" "github.com/sipeed/picoclaw/pkg/config" ) @@ -247,3 +251,42 @@ func TestCreateProviderFromConfig_EmptyModel(t *testing.T) { t.Fatal("CreateProviderFromConfig() expected error for empty model") } } + +func TestCreateProviderFromConfig_RequestTimeoutPropagation(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(1500 * time.Millisecond) + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"choices":[{"message":{"content":"ok"},"finish_reason":"stop"}]}`)) + })) + defer server.Close() + + cfg := &config.ModelConfig{ + ModelName: "test-timeout", + Model: "openai/gpt-4o", + APIBase: server.URL, + RequestTimeout: 1, + } + + provider, modelID, err := CreateProviderFromConfig(cfg) + if err != nil { + t.Fatalf("CreateProviderFromConfig() error = %v", err) + } + if modelID != "gpt-4o" { + t.Fatalf("modelID = %q, want %q", modelID, "gpt-4o") + } + + _, err = provider.Chat( + t.Context(), + []Message{{Role: "user", Content: "hi"}}, + nil, + modelID, + nil, + ) + if err == nil { + t.Fatal("Chat() expected timeout error, got nil") + } + errMsg := err.Error() + if !strings.Contains(errMsg, "context deadline exceeded") && !strings.Contains(errMsg, "Client.Timeout exceeded") { + t.Fatalf("Chat() error = %q, want timeout-related error", errMsg) + } +} diff --git a/pkg/providers/http_provider.go b/pkg/providers/http_provider.go index d0c4344f3..5c328f418 100644 --- a/pkg/providers/http_provider.go +++ b/pkg/providers/http_provider.go @@ -8,6 +8,7 @@ package providers import ( "context" + "time" "github.com/sipeed/picoclaw/pkg/providers/openai_compat" ) @@ -23,8 +24,21 @@ func NewHTTPProvider(apiKey, apiBase, proxy string) *HTTPProvider { } func NewHTTPProviderWithMaxTokensField(apiKey, apiBase, proxy, maxTokensField string) *HTTPProvider { + return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(apiKey, apiBase, proxy, maxTokensField, 0) +} + +func NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( + apiKey, apiBase, proxy, maxTokensField string, + requestTimeoutSeconds int, +) *HTTPProvider { return &HTTPProvider{ - delegate: openai_compat.NewProviderWithMaxTokensField(apiKey, apiBase, proxy, maxTokensField), + delegate: openai_compat.NewProvider( + apiKey, + apiBase, + proxy, + openai_compat.WithMaxTokensField(maxTokensField), + openai_compat.WithRequestTimeout(time.Duration(requestTimeoutSeconds)*time.Second), + ), } } diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index 087d3506e..7dace71f2 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -34,13 +34,27 @@ type Provider struct { httpClient *http.Client } -func NewProvider(apiKey, apiBase, proxy string) *Provider { - return NewProviderWithMaxTokensField(apiKey, apiBase, proxy, "") +type Option func(*Provider) + +const defaultRequestTimeout = 120 * time.Second + +func WithMaxTokensField(maxTokensField string) Option { + return func(p *Provider) { + p.maxTokensField = maxTokensField + } } -func NewProviderWithMaxTokensField(apiKey, apiBase, proxy, maxTokensField string) *Provider { +func WithRequestTimeout(timeout time.Duration) Option { + return func(p *Provider) { + if timeout > 0 { + p.httpClient.Timeout = timeout + } + } +} + +func NewProvider(apiKey, apiBase, proxy string, opts ...Option) *Provider { client := &http.Client{ - Timeout: 120 * time.Second, + Timeout: defaultRequestTimeout, } if proxy != "" { @@ -54,12 +68,36 @@ func NewProviderWithMaxTokensField(apiKey, apiBase, proxy, maxTokensField string } } - return &Provider{ - apiKey: apiKey, - apiBase: strings.TrimRight(apiBase, "/"), - maxTokensField: maxTokensField, - httpClient: client, + p := &Provider{ + apiKey: apiKey, + apiBase: strings.TrimRight(apiBase, "/"), + httpClient: client, } + + for _, opt := range opts { + if opt != nil { + opt(p) + } + } + + return p +} + +func NewProviderWithMaxTokensField(apiKey, apiBase, proxy, maxTokensField string) *Provider { + return NewProvider(apiKey, apiBase, proxy, WithMaxTokensField(maxTokensField)) +} + +func NewProviderWithMaxTokensFieldAndTimeout( + apiKey, apiBase, proxy, maxTokensField string, + requestTimeoutSeconds int, +) *Provider { + return NewProvider( + apiKey, + apiBase, + proxy, + WithMaxTokensField(maxTokensField), + WithRequestTimeout(time.Duration(requestTimeoutSeconds)*time.Second), + ) } func (p *Provider) Chat( diff --git a/pkg/providers/openai_compat/provider_test.go b/pkg/providers/openai_compat/provider_test.go index 594a48213..7247fea3e 100644 --- a/pkg/providers/openai_compat/provider_test.go +++ b/pkg/providers/openai_compat/provider_test.go @@ -6,6 +6,7 @@ import ( "net/http/httptest" "net/url" "testing" + "time" ) func TestProviderChat_UsesMaxCompletionTokensForGLM(t *testing.T) { @@ -325,3 +326,38 @@ func TestNormalizeModel_UsesAPIBase(t *testing.T) { t.Fatalf("normalizeModel(openrouter) = %q, want %q", got, "openrouter/auto") } } + +func TestProvider_RequestTimeoutDefault(t *testing.T) { + p := NewProviderWithMaxTokensFieldAndTimeout("key", "https://example.com/v1", "", "", 0) + if p.httpClient.Timeout != defaultRequestTimeout { + t.Fatalf("http timeout = %v, want %v", p.httpClient.Timeout, defaultRequestTimeout) + } +} + +func TestProvider_RequestTimeoutOverride(t *testing.T) { + p := NewProviderWithMaxTokensFieldAndTimeout("key", "https://example.com/v1", "", "", 300) + if p.httpClient.Timeout != 300*time.Second { + t.Fatalf("http timeout = %v, want %v", p.httpClient.Timeout, 300*time.Second) + } +} + +func TestProvider_FunctionalOptionMaxTokensField(t *testing.T) { + p := NewProvider("key", "https://example.com/v1", "", WithMaxTokensField("max_completion_tokens")) + if p.maxTokensField != "max_completion_tokens" { + t.Fatalf("maxTokensField = %q, want %q", p.maxTokensField, "max_completion_tokens") + } +} + +func TestProvider_FunctionalOptionRequestTimeout(t *testing.T) { + p := NewProvider("key", "https://example.com/v1", "", WithRequestTimeout(45*time.Second)) + if p.httpClient.Timeout != 45*time.Second { + t.Fatalf("http timeout = %v, want %v", p.httpClient.Timeout, 45*time.Second) + } +} + +func TestProvider_FunctionalOptionRequestTimeoutNonPositive(t *testing.T) { + p := NewProvider("key", "https://example.com/v1", "", WithRequestTimeout(-1*time.Second)) + if p.httpClient.Timeout != defaultRequestTimeout { + t.Fatalf("http timeout = %v, want %v", p.httpClient.Timeout, defaultRequestTimeout) + } +} From 21654f1335aa8039edbacc8ed84a9cd4c04793b2 Mon Sep 17 00:00:00 2001 From: Hoshina Date: Thu, 26 Feb 2026 16:51:11 +0800 Subject: [PATCH 53/55] config: change default dm_scope to per-channel-peer Change the default value of session.dm_scope from "main" to "per-channel-peer" to provide better conversation isolation by default. This prevents context leakage between different users and channels. --- pkg/config/config_test.go | 9 +++++++++ pkg/config/defaults.go | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 223ac798d..bf56b7f34 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -413,3 +413,12 @@ func TestLoadConfig_WebToolsProxy(t *testing.T) { t.Fatalf("Tools.Web.Proxy = %q, want %q", cfg.Tools.Web.Proxy, "http://127.0.0.1:7890") } } + +// TestDefaultConfig_DMScope verifies the default dm_scope value +func TestDefaultConfig_DMScope(t *testing.T) { + cfg := DefaultConfig() + + if cfg.Session.DMScope != "per-channel-peer" { + t.Errorf("Session.DMScope = %q, want 'per-channel-peer'", cfg.Session.DMScope) + } +} diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index cc6de9399..cf799140d 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -21,7 +21,7 @@ func DefaultConfig() *Config { }, Bindings: []AgentBinding{}, Session: SessionConfig{ - DMScope: "main", + DMScope: "per-channel-peer", }, Channels: ChannelsConfig{ WhatsApp: WhatsAppConfig{ From f3c1162001fd2562e9f75024d9e33120d753d709 Mon Sep 17 00:00:00 2001 From: ian <141902143+yumosx@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:35:26 +0800 Subject: [PATCH 54/55] feat(skills): add retry for HTTP requests in skill installer (#261) * feat(skills): add retry mechanism for HTTP requests Implement a retry mechanism with exponential backoff for HTTP requests in the skill installer. This improves reliability when fetching skills from GitHub by automatically retrying failed requests up to 3 times. Add comprehensive tests to verify retry behavior under different scenarios including success on different attempts and proper delay between retries. * fix: improve http request retry logic with status code checks Add shouldRetry helper function to determine retryable status codes. Close response body between retry attempts and break early for non-retryable status codes. * refactor: remove unused BuiltinSkill struct The struct was not being used anywhere in the codebase, so it's safe to remove it to reduce clutter and improve maintainability. * refactor(http): move retry logic to utils package Extract HTTP retry functionality from skills package to utils for better reusability Add context-aware sleep function and comprehensive tests * refactor(http): extract retry delay unit to variable Extract hardcoded retry delay unit to a variable for better testability and flexibility. Update tests to use milliseconds for faster execution while maintaining the same behavior. * test(http_retry): remove t.Parallel from test cases * test(http_retry): remove redundant test cases for retry success The removed test cases for success on second and third attempts were redundant since the retry logic is already covered by other tests. This simplifies the test suite while maintaining coverage. --- pkg/skills/installer.go | 6 +- pkg/utils/http_retry.go | 57 +++++++++++++++++ pkg/utils/http_retry_test.go | 118 +++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 pkg/utils/http_retry.go create mode 100644 pkg/utils/http_retry_test.go diff --git a/pkg/skills/installer.go b/pkg/skills/installer.go index 3210509df..f9b5705f1 100644 --- a/pkg/skills/installer.go +++ b/pkg/skills/installer.go @@ -9,6 +9,8 @@ import ( "os" "path/filepath" "time" + + "github.com/sipeed/picoclaw/pkg/utils" ) type SkillInstaller struct { @@ -44,7 +46,7 @@ func (si *SkillInstaller) InstallFromGitHub(ctx context.Context, repo string) er return fmt.Errorf("failed to create request: %w", err) } - resp, err := client.Do(req) + resp, err := utils.DoRequestWithRetry(client, req) if err != nil { return fmt.Errorf("failed to fetch skill: %w", err) } @@ -94,7 +96,7 @@ func (si *SkillInstaller) ListAvailableSkills(ctx context.Context) ([]AvailableS return nil, fmt.Errorf("failed to create request: %w", err) } - resp, err := client.Do(req) + resp, err := utils.DoRequestWithRetry(client, req) if err != nil { return nil, fmt.Errorf("failed to fetch skills list: %w", err) } diff --git a/pkg/utils/http_retry.go b/pkg/utils/http_retry.go new file mode 100644 index 000000000..e90fa2129 --- /dev/null +++ b/pkg/utils/http_retry.go @@ -0,0 +1,57 @@ +package utils + +import ( + "context" + "fmt" + "net/http" + "time" +) + +const maxRetries = 3 + +var retryDelayUnit = time.Second + +func shouldRetry(statusCode int) bool { + return statusCode == http.StatusTooManyRequests || + statusCode >= 500 +} + +func DoRequestWithRetry(client *http.Client, req *http.Request) (*http.Response, error) { + var resp *http.Response + var err error + + for i := range maxRetries { + if i > 0 && resp != nil { + resp.Body.Close() + } + + resp, err = client.Do(req) + if err == nil { + if resp.StatusCode == http.StatusOK { + break + } + if !shouldRetry(resp.StatusCode) { + break + } + } + + if i < maxRetries-1 { + if err = sleepWithCtx(req.Context(), retryDelayUnit*time.Duration(i+1)); err != nil { + return nil, fmt.Errorf("failed to sleep: %w", err) + } + } + } + return resp, err +} + +func sleepWithCtx(ctx context.Context, d time.Duration) error { + timer := time.NewTimer(d) + defer timer.Stop() + + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + return nil + } +} diff --git a/pkg/utils/http_retry_test.go b/pkg/utils/http_retry_test.go new file mode 100644 index 000000000..1c2dbe115 --- /dev/null +++ b/pkg/utils/http_retry_test.go @@ -0,0 +1,118 @@ +package utils + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDoRequestWithRetry(t *testing.T) { + retryDelayUnit = time.Millisecond + t.Cleanup(func() { retryDelayUnit = time.Second }) + + testcases := []struct { + name string + serverBehavior func(*httptest.Server) int + wantSuccess bool + wantAttempts int + }{ + { + name: "success-on-first-attempt", + serverBehavior: func(server *httptest.Server) int { + return 0 + }, + wantSuccess: true, + wantAttempts: 1, + }, + { + name: "fail-all-attempts", + serverBehavior: func(server *httptest.Server) int { + return 4 + }, + wantSuccess: false, + wantAttempts: 3, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + attempts := 0 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + attempts++ + if attempts <= tc.serverBehavior(nil) { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + w.Write([]byte("success")) + })) + + t.Cleanup(func() { + server.Close() + }) + + client := &http.Client{Timeout: 5 * time.Second} + req, err := http.NewRequest(http.MethodGet, server.URL, nil) + require.NoError(t, err) + + resp, err := DoRequestWithRetry(client, req) + + if tc.wantSuccess { + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusOK, resp.StatusCode) + resp.Body.Close() + } else { + require.NotNil(t, resp) + assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) + resp.Body.Close() + } + + assert.Equal(t, tc.wantAttempts, attempts) + }) + } +} + +func TestDoRequestWithRetry_Delay(t *testing.T) { + retryDelayUnit = time.Millisecond + t.Cleanup(func() { retryDelayUnit = time.Second }) + + var start time.Time + delays := []time.Duration{} + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if len(delays) == 0 { + delays = append(delays, 0) + w.WriteHeader(http.StatusInternalServerError) + return + } + if len(delays) == 1 { + start = time.Now() + delays = append(delays, 0) + w.WriteHeader(http.StatusInternalServerError) + return + } + if len(delays) == 2 { + elapsed := time.Since(start) + delays = append(delays, elapsed) + w.WriteHeader(http.StatusOK) + w.Write([]byte("success")) + } + })) + defer server.Close() + + client := &http.Client{Timeout: 10 * time.Second} + req, err := http.NewRequest(http.MethodGet, server.URL, nil) + require.NoError(t, err) + + resp, err := DoRequestWithRetry(client, req) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusOK, resp.StatusCode) + resp.Body.Close() + + assert.GreaterOrEqual(t, delays[2], time.Millisecond) +} From cb3191c8c129250103c75fae626e218296a183d0 Mon Sep 17 00:00:00 2001 From: ztechenbo <39621703+ztechenbo@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:41:01 +0800 Subject: [PATCH 55/55] build: support armv81 arch in Makefile (#776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 陈波0668000637 --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index c59c414f3..a14723616 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,8 @@ ifeq ($(UNAME_S),Linux) ARCH=amd64 else ifeq ($(UNAME_M),aarch64) ARCH=arm64 + else ifeq ($(UNAME_M),armv81) + ARCH=arm64 else ifeq ($(UNAME_M),loongarch64) ARCH=loong64 else ifeq ($(UNAME_M),riscv64)

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 Date: Tue, 24 Feb 2026 14:47:40 +0800 Subject: [PATCH 11/55] docs: add wechat and discord badge (#707) Signed-off-by: Guoguo --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 84d92115b..778530db5 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,9 @@
Website Twitter +
+ + Discord