Files
2026-07-13 12:49:10 +08:00

121 lines
5.0 KiB
Go

/*
* Copyright 2025 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Package supervisor implements the supervisor pattern for multi-agent systems,
// where a central agent coordinates a set of sub-agents.
//
// # Unified Tracing
//
// The supervisor pattern provides unified tracing support through an internal container.
// When using callbacks (e.g., for tracing or observability), the entire supervisor structure
// (supervisor agent + all sub-agents) shares a single trace root. This means:
// - OnStart is invoked once at the supervisor container level
// - The callback-enriched context (containing parent span info) is propagated to all agents
// - All agents within the supervisor appear as children of the same trace root
//
// This is achieved by wrapping the supervisor structure in an internal container that acts
// as the single entry point for tracing. The container delegates all execution to the
// underlying agents while providing a unified identity for callbacks.
package supervisor
import (
"context"
"github.com/cloudwego/eino/adk"
)
// Config is the configuration for creating a supervisor-based multi-agent system.
//
// NOT RECOMMENDED: Supervisor is built on agent transfer with full context sharing,
// which has not proven to be more effective empirically. Consider using
// ChatModelAgent with AgentTool or DeepAgent instead for most multi-agent scenarios.
type Config struct {
// Supervisor specifies the agent that will act as the supervisor, coordinating and managing the sub-agents.
Supervisor adk.Agent
// SubAgents specifies the list of agents that will be supervised and coordinated by the supervisor agent.
SubAgents []adk.Agent
}
// supervisorContainer wraps the entire supervisor structure to provide unified tracing.
// When callbacks are registered (e.g., via Runner.Query with WithCallbacks), OnStart/OnEnd
// are invoked once for this container, creating a single trace root. The callback-enriched
// context is then propagated to the supervisor and all sub-agents, ensuring they share
// the same trace parent.
//
// This container implements Agent and ResumableAgent by delegating to the inner agent.
// It provides its own Name and GetType for callback identification.
type supervisorContainer struct {
name string
inner adk.ResumableAgent
}
func (s *supervisorContainer) Name(_ context.Context) string {
return s.name
}
func (s *supervisorContainer) Description(ctx context.Context) string {
return s.inner.Description(ctx)
}
func (s *supervisorContainer) GetType() string {
return "Supervisor"
}
func (s *supervisorContainer) Run(ctx context.Context, input *adk.AgentInput, opts ...adk.AgentRunOption) *adk.AsyncIterator[*adk.AgentEvent] {
return s.inner.Run(ctx, input, opts...)
}
func (s *supervisorContainer) Resume(ctx context.Context, info *adk.ResumeInfo, opts ...adk.AgentRunOption) *adk.AsyncIterator[*adk.AgentEvent] {
return s.inner.Resume(ctx, info, opts...)
}
// New creates a supervisor-based multi-agent system with the given configuration.
//
// In the supervisor pattern, a designated supervisor agent coordinates multiple sub-agents.
// The supervisor can delegate tasks to sub-agents and receive their responses, while
// sub-agents can only communicate with the supervisor (not with each other directly).
// This hierarchical structure enables complex problem-solving through coordinated agent interactions.
//
// The returned agent is wrapped in an internal container that provides unified tracing.
// When used with Runner and callbacks, all agents within the supervisor structure will
// share the same trace root, making it easy to observe the entire multi-agent execution
// as a single logical unit.
//
// NOT RECOMMENDED: Supervisor is built on agent transfer with full context sharing,
// which has not proven to be more effective empirically. Consider using
// ChatModelAgent with AgentTool or DeepAgent instead for most multi-agent scenarios.
func New(ctx context.Context, conf *Config) (adk.ResumableAgent, error) {
subAgents := make([]adk.Agent, 0, len(conf.SubAgents))
supervisorName := conf.Supervisor.Name(ctx)
for _, subAgent := range conf.SubAgents {
subAgents = append(subAgents, adk.AgentWithDeterministicTransferTo(ctx, &adk.DeterministicTransferConfig{
Agent: subAgent,
ToAgentNames: []string{supervisorName},
}))
}
inner, err := adk.SetSubAgents(ctx, conf.Supervisor, subAgents)
if err != nil {
return nil, err
}
return &supervisorContainer{
name: supervisorName,
inner: inner,
}, nil
}