mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat(agent): add TargetAgentID to SubTurnConfig for cross-agent delegation
When TargetAgentID is set, spawnSubTurn resolves the target AgentInstance from the registry and uses it as the base for the child turn. This gives the child turn the target's workspace, model, tools, and system prompt instead of inheriting from the caller. Model validation is relaxed: empty Model is accepted when TargetAgentID provides the model implicitly via the resolved agent instance. Ref: #2148
This commit is contained in:
+24
-9
@@ -172,7 +172,10 @@ type SubTurnConfig struct {
|
||||
// Used by team tool to enforce token limits across all team members.
|
||||
InitialTokenBudget *atomic.Int64
|
||||
|
||||
// Can be extended with temperature, topP, etc.
|
||||
// TargetAgentID, when set, runs the sub-turn as the specified agent.
|
||||
// The target agent's workspace, model, tools, and system prompt are used
|
||||
// instead of the caller's. If empty, the sub-turn runs as the parent agent.
|
||||
TargetAgentID string
|
||||
}
|
||||
|
||||
// ====================== Context Keys ======================
|
||||
@@ -230,6 +233,7 @@ func (s *AgentLoopSpawner) SpawnSubTurn(
|
||||
Critical: cfg.Critical,
|
||||
Timeout: cfg.Timeout,
|
||||
MaxContextRunes: cfg.MaxContextRunes,
|
||||
TargetAgentID: cfg.TargetAgentID,
|
||||
}
|
||||
|
||||
return spawnSubTurn(ctx, s.al, parentTS, agentCfg)
|
||||
@@ -312,8 +316,9 @@ func spawnSubTurn(
|
||||
return nil, ErrDepthLimitExceeded
|
||||
}
|
||||
|
||||
// 2. Config validation
|
||||
if cfg.Model == "" {
|
||||
// 2. Config validation: Model is required unless TargetAgentID is set
|
||||
// (the target agent provides its own model).
|
||||
if cfg.Model == "" && cfg.TargetAgentID == "" {
|
||||
return nil, ErrInvalidSubTurnConfig
|
||||
}
|
||||
|
||||
@@ -331,12 +336,22 @@ func spawnSubTurn(
|
||||
|
||||
childID := al.generateSubTurnID()
|
||||
|
||||
// Get the agent instance from parent, falling back to the default agent.
|
||||
// Wrap it in a shallow copy that uses an ephemeral (in-memory only) session store
|
||||
// so that child turns never pollute or persist to the parent's session history.
|
||||
baseAgent := parentTS.agent
|
||||
if baseAgent == nil {
|
||||
baseAgent = al.registry.GetDefaultAgent()
|
||||
// Resolve the agent instance for the child turn.
|
||||
// When TargetAgentID is set, look up that agent from the registry so the
|
||||
// child runs with the target's workspace, model, tools, and system prompt.
|
||||
// Otherwise fall back to the parent's agent (existing behavior).
|
||||
var baseAgent *AgentInstance
|
||||
if cfg.TargetAgentID != "" {
|
||||
var ok bool
|
||||
baseAgent, ok = al.registry.GetAgent(cfg.TargetAgentID)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("target agent %q not found in registry", cfg.TargetAgentID)
|
||||
}
|
||||
} else {
|
||||
baseAgent = parentTS.agent
|
||||
if baseAgent == nil {
|
||||
baseAgent = al.registry.GetDefaultAgent()
|
||||
}
|
||||
}
|
||||
if baseAgent == nil {
|
||||
return nil, errors.New("parent turnState has no agent instance")
|
||||
|
||||
@@ -30,6 +30,7 @@ type SubTurnConfig struct {
|
||||
ActualSystemPrompt string
|
||||
InitialMessages []providers.Message
|
||||
InitialTokenBudget *atomic.Int64 // Shared token budget for team members; nil if no budget
|
||||
TargetAgentID string // If set, run as this agent (its workspace, model, tools)
|
||||
}
|
||||
|
||||
type SubagentTask struct {
|
||||
|
||||
Reference in New Issue
Block a user