Callback Events
The Go-AI SDK fires structured lifecycle events during text generation and agent execution. Each event is a typed struct delivered via callback fields on GenerateTextOptions, StreamTextOptions, and AgentConfig.
GenerateTextOptions, StreamTextOptions, AgentGenerateOptions, and AgentConfig use the TypeScript-aligned tool callback names OnToolExecutionStart and OnToolExecutionEnd. The event structs keep their Go names, OnToolCallStartEvent and OnToolCallFinishEvent.
All callbacks are optional and panic-safe — a panicking callback never aborts generation.
Event Types
OnStartEvent
Fired once at the beginning of a GenerateText or StreamText call, before any LLM request is made. Each struct below shows selected fields; see go doc ./pkg/ai <Type> for the complete list.
type OnStartEvent struct {
CallID string // correlates this event with other events for the same call
ModelProvider string
ModelID string
Prompt string
System string // Deprecated: use Instructions
Messages []types.Message
Tools []types.Tool
// ... generation parameters, ProviderOptions, RuntimeContext, etc.
}
| Field | Description |
|---|---|
| CallID | Unique ID for this generation call; correlates OnStart/OnStepStart/OnStepFinish/OnFinish events |
| ModelProvider | Provider name (e.g., "openai", "anthropic") |
| ModelID | Model identifier (e.g., "gpt-4o") |
| Prompt | The user prompt string |
| System | The system prompt string (deprecated alias for Instructions) |
| Messages | Initial conversation messages |
| Tools | Tools available for the call |
OnStepStartEvent
Fired at the beginning of each generation step (each LLM call in a multi-step tool loop).
type OnStepStartEvent struct {
CallID string
StepNumber int // 0-indexed
Messages []types.Message
Tools []types.Tool
// ... ToolChoice, ActiveTools, Steps (prior step results), etc.
}
| Field | Description |
|---|---|
| CallID | Correlates this event with the other events for this call |
| StepNumber | 0-indexed step counter |
| Messages | Messages sent to the LLM for this step |
| Tools | Tools available for this step |
OnToolCallStartEvent
Fired before each individual tool is executed. Use this event with OnToolExecutionStart.
type OnToolCallStartEvent struct {
CallID string
ToolCallID string
ToolName string
ToolCall types.ToolCall
Messages []types.Message
// Args and StepNumber are deprecated; use ToolCall.Arguments and
// correlate with step events via CallID instead.
}
| Field | Description |
|---|---|
| CallID | Correlates this event with the generation call that triggered it |
| ToolCallID | Unique identifier for this tool call |
| ToolName | Name of the tool being called |
| ToolCall | The full tool call, including Arguments |
OnToolCallFinishEvent
Fired after each tool completes (success or failure). Use this event with OnToolExecutionEnd.
type OnToolCallFinishEvent struct {
CallID string
ToolCallID string
ToolName string
ToolCall types.ToolCall
ToolOutput types.ToolResult // exactly one of ToolOutput.Result / ToolOutput.Error is meaningful
ToolExecutionMs int64
Messages []types.Message
// Result, Error, Args, StepNumber, DurationMs are deprecated aliases
// for ToolOutput.Result, ToolOutput.Error, ToolCall.Arguments,
// CallID-based correlation, and ToolExecutionMs respectively.
}
| Field | Description |
|---|---|
| ToolOutput | Tool result; ToolOutput.Result is non-nil on success, ToolOutput.Error on failure |
| ToolExecutionMs | Tool execution time in milliseconds |
| Result (deprecated) | Tool output on success (nil on failure) |
| Error (deprecated) | Execution error on failure (nil on success) |
OnStepFinishEvent
Fired after each generation step completes, including after all tools for that step have been executed.
type OnStepFinishEvent struct {
CallID string
StepNumber int // 0-indexed
Text string
ToolCalls []types.ToolCall
ToolResults []types.ToolResult
FinishReason types.FinishReason
Usage types.Usage
Warnings []types.Warning
// ... Reasoning, Sources, Files, ProviderMetadata, Request, Response, etc.
}
| Field | Description |
|---|---|
| StepNumber | 0-indexed step counter |
| Text | LLM text output for this step |
| ToolCalls | Tool calls made during this step |
| ToolResults | Results from tool executions in this step |
| FinishReason | Why the LLM stopped (e.g., ToolCalls, Stop) |
| Usage | Token usage for this step |
OnFinishEvent
Fired once when generation completes (after all steps).
type OnFinishEvent struct {
CallID string
Text string
ToolCalls []types.ToolCall
ToolResults []types.ToolResult
FinishReason types.FinishReason
Steps []types.StepResult
Usage types.Usage // usage of the final step
TotalUsage types.Usage // sum across all steps
Output interface{} // parsed structured output, if configured
// ... Reasoning, Sources, Files, Warnings, ProviderMetadata, etc.
}
| Field | Description |
|---|---|
| Text | Final generated text |
| ToolResults | Tool results from the final step |
| FinishReason | Final finish reason |
| Steps | All steps taken during generation |
| TotalUsage | Aggregated token usage across all steps |
Notify Utility
The SDK exposes the Notify function used internally for safe event dispatch:
// Listener is a function that receives a typed event.
type Listener[E any] func(ctx context.Context, event E)
// Notify safely dispatches event to each listener.
// Panics in any listener are recovered and do not propagate.
func Notify[E any](ctx context.Context, event E, listeners ...Listener[E])
Notify is useful for fan-out scenarios where you want to dispatch the same event to multiple independent listeners.
Usage
With GenerateText
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "What is 2+2?",
Tools: []types.Tool{calculatorTool},
StopWhen: []ai.StopCondition{ai.IsStepCount(5)},
OnStart: func(ctx context.Context, e ai.OnStartEvent) {
log.Printf("[start] model=%s/%s prompt=%q", e.ModelProvider, e.ModelID, e.Prompt)
},
OnStepStart: func(ctx context.Context, e ai.OnStepStartEvent) {
log.Printf("[step %d start] messages=%d", e.StepNumber, len(e.Messages))
},
OnToolExecutionStart: func(ctx context.Context, e ai.OnToolCallStartEvent) {
log.Printf("[tool start] %s args=%v", e.ToolName, e.Args)
},
OnToolExecutionEnd: func(ctx context.Context, e ai.OnToolCallFinishEvent) {
if e.Error != nil {
log.Printf("[tool error] %s: %v", e.ToolName, e.Error)
} else {
log.Printf("[tool finish] %s result=%v", e.ToolName, e.Result)
}
},
OnStepFinishEvent: func(ctx context.Context, e ai.OnStepFinishEvent) {
log.Printf("[step %d finish] finish_reason=%s tokens=%d",
e.StepNumber, e.FinishReason, safeTokens(e.Usage.TotalTokens))
},
OnFinishEvent: func(ctx context.Context, e ai.OnFinishEvent) {
log.Printf("[finish] steps=%d total_tokens=%d text=%q",
len(e.Steps), safeTokens(e.TotalUsage.TotalTokens), e.Text)
},
})
With AgentConfig (ToolLoopAgent)
Callbacks on AgentConfig fire for every call to Execute. They are merged with any per-call callbacks:
agent := agent.NewToolLoopAgent(agent.AgentConfig{
Model: model,
Tools: tools,
StopWhen: []ai.StopCondition{ai.IsStepCount(10)},
OnStart: func(ctx context.Context, e ai.OnStartEvent) {
log.Printf("Agent starting: model=%s", e.ModelID)
},
OnToolExecutionStart: func(ctx context.Context, e ai.OnToolCallStartEvent) {
log.Printf("Tool call: %s", e.ToolName)
},
OnToolExecutionEnd: func(ctx context.Context, e ai.OnToolCallFinishEvent) {
if e.Error != nil {
log.Printf("Tool failed: %s: %v", e.ToolName, e.Error)
}
},
OnFinishEvent: func(ctx context.Context, e ai.OnFinishEvent) {
log.Printf("Agent done: %d steps", len(e.Steps))
},
})
Event Ordering
For a single GenerateText call with one tool call, the event order is:
OnStart
└── Step 1
├── OnStepStart
├── OnToolExecutionStart (for each tool execution)
├── OnToolExecutionEnd (for each tool execution)
└── OnStepFinish
└── Step 2
├── OnStepStart
└── OnStepFinish
OnFinish
Callback Merging in Agents
When using ToolLoopAgent, callbacks set in AgentConfig are merged with any per-call callbacks. Both fire in order: settings-level first, then call-level.
This is useful for attaching persistent observability (logging, metrics) at the agent level while allowing per-request overrides.
See Also
- GenerateText — Full reference for
GenerateText - StreamText — Full reference for
StreamText - ToolLoopAgent — Full reference for
ToolLoopAgent