From 7b3df059c40a34866eaf7972f24aeb90ebd35c2c Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 27 Dec 2025 16:51:49 +0800 Subject: [PATCH] Add Delegation Support in Create Hook for Agent Routing - Introduced delegation functionality in the Create hook, allowing agents to route requests to sub-agents without invoking LLM processing. - Updated the HookCreateResponse structure to include a Delegate field, enabling immediate delegation to another agent. - Enhanced the Stream method to handle delegation responses, ensuring proper stream closure and error handling for delegated agents. - Improved logging for delegation actions to facilitate debugging and traceability in agent interactions. --- agent/assistant/agent.go | 30 ++++++++++++++++++++++++++++++ agent/context/types.go | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/agent/assistant/agent.go b/agent/assistant/agent.go index 546617d3..dcdb15b5 100644 --- a/agent/assistant/agent.go +++ b/agent/assistant/agent.go @@ -169,6 +169,36 @@ func (ast *Assistant) Stream(ctx *context.Context, inputMessages []context.Messa // Log the create response ast.traceCreateHook(agentNode, createResponse) ctx.Logger.HookComplete("Create") + + // Check if Create hook wants to delegate to another agent + // This allows early routing to sub-agents without LLM call + if createResponse != nil && createResponse.Delegate != nil { + ctx.Logger.Debug("Create hook delegating to agent: %s", createResponse.Delegate.AgentID) + + // Delegate to target agent (reuse existing delegation logic from next.go) + delegateResponse, err := ast.handleDelegation(ctx, createResponse.Delegate, streamHandler) + if err != nil { + finalStatus = context.ResumeStatusFailed + finalError = err + ast.traceAgentFail(agentNode, err) + ast.sendStreamEndOnError(ctx, streamHandler, streamStartTime, err) + return nil, err + } + + // For root stack, send stream_end and close output + // (delegated agent handles its own stream events, but root needs to close) + if ctx.Stack != nil && ctx.Stack.IsRoot() { + ast.sendAgentStreamEnd(ctx, streamHandler, streamStartTime, "completed", nil, nil) + if err := ctx.CloseOutput(); err != nil { + if trace, _ := ctx.Trace(); trace != nil { + trace.Error(i18n.Tr(ast.ID, ctx.Locale, "assistant.agent.stream.close_error"), map[string]any{"error": err.Error()}) + } + } + } + + // Return delegated response directly (skip LLM call and Next hook) + return delegateResponse, nil + } } // ================================================ diff --git a/agent/context/types.go b/agent/context/types.go index f5cbb372..3f501a66 100644 --- a/agent/context/types.go +++ b/agent/context/types.go @@ -391,6 +391,10 @@ type HookCreateResponse struct { // - SearchIntent: fine-grained control with specific types, confidence, etc. // - nil: use default behavior (determined by __yao.needsearch agent) Search any `json:"search,omitempty"` // Search mode: bool | SearchIntent | nil + + // Delegate: if provided, delegate to another agent immediately (skip LLM call) + // This allows Create hook to route to sub-agents before any LLM processing + Delegate *DelegateConfig `json:"delegate,omitempty"` } // NextHookPayload payload for the next hook