From 196b05aa49c8b54ece4b500caa5f1ff790e413db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=BE=E6=96=87=E9=94=8B0668000834?= Date: Thu, 12 Mar 2026 21:00:20 +0800 Subject: [PATCH] fix(spawn): use target agent model instead of caller model When spawn is called with agent_id parameter, the subagent now uses the target agent's configured model instead of always using the caller's model. Changes: - Add modelResolver field to SubagentManager - Add SetModelResolver method to configure the resolver - In runTask, resolve target model using the resolver when agent_id is specified - Set up model resolver in registerSharedTools to lookup agent from registry Fixes #1322 --- pkg/agent/loop.go | 7 +++++++ pkg/tools/subagent.go | 23 ++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 235d42fcc..fb78d11ad 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -224,6 +224,13 @@ func registerSharedTools( if cfg.Tools.IsToolEnabled("subagent") { subagentManager := tools.NewSubagentManager(provider, agent.Model, agent.Workspace) subagentManager.SetLLMOptions(agent.MaxTokens, agent.Temperature) + // Set up model resolver to use target agent's configured model + subagentManager.SetModelResolver(func(targetAgentID string) string { + if targetAgent, ok := registry.GetAgent(targetAgentID); ok { + return targetAgent.Model + } + return "" + }) spawnTool := tools.NewSpawnTool(subagentManager) currentAgentID := agentID spawnTool.SetAllowlistChecker(func(targetAgentID string) bool { diff --git a/pkg/tools/subagent.go b/pkg/tools/subagent.go index e51cbaafa..7cb468fc0 100644 --- a/pkg/tools/subagent.go +++ b/pkg/tools/subagent.go @@ -34,6 +34,9 @@ type SubagentManager struct { hasMaxTokens bool hasTemperature bool nextID int + // modelResolver is called to resolve the target model for a given agent ID. + // If nil or returns empty string, defaultModel is used. + modelResolver func(agentID string) string } func NewSubagentManager( @@ -61,6 +64,14 @@ func (sm *SubagentManager) SetLLMOptions(maxTokens int, temperature float64) { sm.hasTemperature = true } +// SetModelResolver sets a function to resolve the target model for a given agent ID. +// This allows subagent to use the target agent's configured model instead of the caller's model. +func (sm *SubagentManager) SetModelResolver(resolver func(agentID string) string) { + sm.mu.Lock() + defer sm.mu.Unlock() + sm.modelResolver = resolver +} + // SetTools sets the tool registry for subagent execution. // If not set, subagent will have access to the provided tools. func (sm *SubagentManager) SetTools(tools *ToolRegistry) { @@ -147,8 +158,18 @@ After completing the task, provide a clear summary of what was done.` temperature := sm.temperature hasMaxTokens := sm.hasMaxTokens hasTemperature := sm.hasTemperature + modelResolver := sm.modelResolver + defaultModel := sm.defaultModel sm.mu.RUnlock() + // Resolve target model: use target agent's model if agent_id is specified and resolver is available + targetModel := defaultModel + if task.AgentID != "" && modelResolver != nil { + if resolvedModel := modelResolver(task.AgentID); resolvedModel != "" { + targetModel = resolvedModel + } + } + var llmOptions map[string]any if hasMaxTokens || hasTemperature { llmOptions = map[string]any{} @@ -162,7 +183,7 @@ After completing the task, provide a clear summary of what was done.` loopResult, err := RunToolLoop(ctx, ToolLoopConfig{ Provider: sm.provider, - Model: sm.defaultModel, + Model: targetModel, Tools: tools, MaxIterations: maxIter, LLMOptions: llmOptions,