From d456e5a5f0e88177d228e791d06055d9ff206441 Mon Sep 17 00:00:00 2001 From: Alix-007 <267018309+Alix-007@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:58:12 +0800 Subject: [PATCH] fix(agent): normalize subagent openrouter model ids --- pkg/agent/loop.go | 16 ++++++++++- pkg/agent/subagent_default_model_test.go | 36 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 pkg/agent/subagent_default_model_test.go diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index ef2951365..ee0d9d371 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -285,7 +285,11 @@ func registerSharedTools( spawnEnabled := cfg.Tools.IsToolEnabled("spawn") spawnStatusEnabled := cfg.Tools.IsToolEnabled("spawn_status") if (spawnEnabled || spawnStatusEnabled) && cfg.Tools.IsToolEnabled("subagent") { - subagentManager := tools.NewSubagentManager(provider, agent.Model, agent.Workspace) + subagentManager := tools.NewSubagentManager( + provider, + resolveSubagentDefaultModel(agent), + agent.Workspace, + ) subagentManager.SetLLMOptions(agent.MaxTokens, agent.Temperature) // Set the spawner that links into AgentLoop's turnState @@ -377,6 +381,16 @@ func registerSharedTools( } } +func resolveSubagentDefaultModel(agent *AgentInstance) string { + if agent == nil { + return "" + } + if len(agent.Candidates) > 0 && strings.TrimSpace(agent.Candidates[0].Model) != "" { + return strings.TrimSpace(agent.Candidates[0].Model) + } + return agent.Model +} + func (al *AgentLoop) Run(ctx context.Context) error { al.running.Store(true) diff --git a/pkg/agent/subagent_default_model_test.go b/pkg/agent/subagent_default_model_test.go new file mode 100644 index 000000000..237dfec09 --- /dev/null +++ b/pkg/agent/subagent_default_model_test.go @@ -0,0 +1,36 @@ +package agent + +import ( + "testing" + + "github.com/sipeed/picoclaw/pkg/providers" +) + +func TestResolveSubagentDefaultModel(t *testing.T) { + t.Run("prefers resolved candidate model", func(t *testing.T) { + agent := &AgentInstance{ + Model: "openrouter/minimax/minimax-m2.5", + Candidates: []providers.FallbackCandidate{ + {Provider: "openrouter", Model: "minimax/minimax-m2.5"}, + }, + } + + if got := resolveSubagentDefaultModel(agent); got != "minimax/minimax-m2.5" { + t.Fatalf("resolveSubagentDefaultModel() = %q, want %q", got, "minimax/minimax-m2.5") + } + }) + + t.Run("falls back to raw agent model when no candidates exist", func(t *testing.T) { + agent := &AgentInstance{Model: "claude-sonnet-4.6"} + + if got := resolveSubagentDefaultModel(agent); got != "claude-sonnet-4.6" { + t.Fatalf("resolveSubagentDefaultModel() = %q, want %q", got, "claude-sonnet-4.6") + } + }) + + t.Run("returns empty string for nil agent", func(t *testing.T) { + if got := resolveSubagentDefaultModel(nil); got != "" { + t.Fatalf("resolveSubagentDefaultModel(nil) = %q, want empty string", got) + } + }) +}