Eino ADK: Agent Interface
Agent Definition
Implementing the following interface makes a struct an agent:
// github.com/cloudwego/eino/adk/interface.go
type Agent interface {
Name(ctx context.Context) string
Description(ctx context.Context) string
Run(ctx context.Context, input *AgentInput, opts ...AgentRunOption) *AsyncIterator[*AgentEvent]
}
| Method | Description |
| Name | Agent identifier (name) |
| Description | Capabilities description to help other agents understand its role |
| Run | Core execution method; returns an iterator to continuously receive Agent events |
AgentInput
type AgentInput struct {
Messages []Message
EnableStreaming bool
}
type Message = *schema.Message
Agents typically center around a chat model, so input uses Messages compatible with Eino ChatModel. Include user instructions, dialogue history, background knowledge, examples, etc.
import (
"github.com/cloudwego/eino/adk"
"github.com/cloudwego/eino/schema"
)
input := &adk.AgentInput{
Messages: []adk.Message{
schema.UserMessage("What's the capital of France?"),
schema.AssistantMessage("The capital of France is Paris.", nil),
schema.UserMessage("How far is it from London? "),
},
}
EnableStreaming suggests output mode for components that support both streaming and non‑streaming (e.g., ChatModel). It is not a hard constraint. The actual output type is indicated by AgentOutput.IsStreaming.
- When
EnableStreaming=false: for components that support both, prefer non‑streaming (return full result at once). - When
EnableStreaming=true: components capable of streaming should stream; components that do not support streaming continue non‑streaming.
As shown below, ChatModel may stream or not, while Tool outputs non‑stream only:
EnableStreaming=false: both output non‑streamEnableStreaming=true: ChatModel streams; Tool remains non‑stream
AgentRunOption
Options can adjust configuration or behavior per request. ADK provides common options:
WithSessionValues— set cross‑agent KV stateWithSkipTransferMessages— when transferring, do not append transfer event messages to history
Wrapping and reading implementation‑specific options:
// github.com/cloudwego/eino/adk/call_option.go
// func WrapImplSpecificOptFn[T any](optFn func(*T)) AgentRunOption
// func GetImplSpecificOptions[T any](base *T, opts ...AgentRunOption) *T
type options struct { modelName string }
func WithModelName(name string) adk.AgentRunOption {
return adk.WrapImplSpecificOptFn(func(t *options) { t.modelName = name })
}
func (m *MyAgent) Run(ctx context.Context, input *adk.AgentInput, opts ...adk.AgentRunOption) *adk.AsyncIterator[*adk.AgentEvent] {
o := &options{}
o = adk.GetImplSpecificOptions(o, opts...)
// run code...
}
Designate option targets for specific agents in a multi‑agent system:
opt := adk.WithSessionValues(map[string]any{}).DesignateAgent("agent_1", "agent_2")
AsyncIterator
Agent.Run returns AsyncIterator[*AgentEvent], an asynchronous iterator (production and consumption are decoupled) for consuming events in order:
// github.com/cloudwego/eino/adk/utils.go
type AsyncIterator[T any] struct { /* ... */ }
func (ai *AsyncIterator[T]) Next() (T, bool) { /* ... */ }
Consume with a blocking Next() loop until closed:
iter := myAgent.Run(xxx)
for {
event, ok := iter.Next()
if !ok { break }
// handle event
}
Create with NewAsyncIteratorPair and produce via AsyncGenerator:
func NewAsyncIteratorPair[T any]() (*AsyncIterator[T], *AsyncGenerator[T])
Agents usually run in a goroutine and return the iterator immediately, so the caller can start consuming events in real time:
import "github.com/cloudwego/eino/adk"
func (m *MyAgent) Run(ctx context.Context, input *adk.AgentInput, opts ...adk.AgentRunOption) *adk.AsyncIterator[*adk.AgentEvent] {
// handle input
iter, gen := adk.NewAsyncIteratorPair[*adk.AgentEvent]()
go func() {
defer func() {
// recover code
gen.Close()
}()
// agent run code
// gen.Send(event)
}()
return iter
}
AgentWithOptions
Configure common behaviors before running via AgentWithOptions:
// github.com/cloudwego/eino/adk/flow.go
func AgentWithOptions(ctx context.Context, agent Agent, opts ...AgentOption) Agent
Built‑in options:
WithDisallowTransferToParent— disallow transferring to parent; triggersOnDisallowTransferToParentWithHistoryRewriter— rewrite history into input messages before execution
AgentEvent
Core event structure produced by agents:
// github.com/cloudwego/eino/adk/interface.go
type AgentEvent struct {
AgentName string
RunPath []RunStep
Output *AgentOutput
Action *AgentAction
Err error
}
// EventFromMessage builds a standard event
func EventFromMessage(msg Message, msgStream MessageStream, role schema.RoleType, toolName string) *AgentEvent
AgentName & RunPath
Filled by the framework to provide event provenance in multi‑agent systems:
type RunStep struct { agentName string }
AgentName— which agent produced the eventRunPath— chain from entry agent to current agent
AgentOutput
Encapsulates agent output:
type AgentOutput struct {
MessageOutput *MessageVariant
CustomizedOutput any
}
type MessageVariant struct {
IsStreaming bool
Message Message
MessageStream MessageStream
Role schema.RoleType
ToolName string // when Role is Tool
}
MessageVariant:
- Unifies streaming vs non‑streaming messages via
IsStreaming:- Streaming: return chunks over time that form a complete message (read from
MessageStream). - Non‑streaming: return a complete message at once (read from
Message).
- Streaming: return chunks over time that form a complete message (read from
- Surfaces convenient metadata at top level:
Role: Assistant or ToolToolName: whenRoleis Tool, provide the tool’s name
AgentAction
Control multi‑agent collaboration: exit, interrupt, transfer, or custom:
type AgentAction struct {
Exit bool
Interrupted *InterruptInfo
TransferToAgent *TransferToAgentAction
BreakLoop *BreakLoopAction
CustomizedAction any
}
type InterruptInfo struct { Data any }
type TransferToAgentAction struct { DestAgentName string }
Prebuilt actions:
func NewExitAction() *AgentAction { return &AgentAction{Exit: true} }
func NewTransferToAgentAction(dest string) *AgentAction {
return &AgentAction{TransferToAgent: &TransferToAgentAction{DestAgentName: dest}}
}
Interrupt sends custom info for checkpoint/resume flows (see Runner docs). For example, ChatModelAgent sends an interrupt event as:
// e.g., when ChatModelAgent interrupts, it emits:
h.Send(&AgentEvent{AgentName: h.agentName, Action: &AgentAction{
Interrupted: &InterruptInfo{
Data: &ChatModelAgentInterruptInfo{Data: data, Info: info},
},
}})
