Skip to content

Events & Errors

Events

The engine exposes the internal event bus. Subscribe with a topic and a handler whose single parameter matches the payload type (dispatched by reflection), then defer the returned unsubscribe function.

unsub, err := eng.OnAgentFinished(func(ev sdk.AgentFinished) {
    fmt.Println("finished:", ev.AgentName, ev.Output)
})
if err != nil {
    return err
}
defer unsub()

Typed helpers

Method Payload
OnAgentToken(fn func(AgentToken)) Streamed token (Content, Reasoning)
OnAgentToolCall(fn func(AgentToolCall)) A tool call about to run (Call)
OnAgentToolResult(fn func(AgentToolResult)) A tool result (Output, Err)
OnAgentFinished(fn func(AgentFinished)) Successful run completion
OnAgentError(fn func(AgentError)) Any run failure

Generic subscription

unsub, err := eng.Subscribe(sdk.TopicAgentToken, func(ev sdk.AgentToken) { ... })
unsub, err = eng.SubscribeOnce(sdk.TopicSessionCreated, func(ev sdk.SessionCreated) { ... })

Available topics:

  • Agent: TopicAgentStarted, TopicAgentInput, TopicAgentMessage, TopicAgentToken, TopicAgentToolCall, TopicAgentToolResult, TopicAgentUsage, TopicAgentFinished, TopicAgentError, TopicAgentAsk, TopicAgentAskAnswer.
  • Session: TopicSessionCreated, TopicSessionDeleted, TopicSessionUpdated, TopicSessionMessageAdded, TopicSessionForked, TopicSessionReverted, TopicSessionRestored, TopicSessionCurrentChanged, TopicSessionResume, TopicSessionAttached.
  • Engine: app.mounted is published at Open with the resolved config.

ChatStream already maps the same events into ChatEvents, so prefer it when you only need run telemetry. Use the bus for cross-cutting concerns (logging, metrics, custom middlewares).

Errors

Engine errors

Sentinel When
sdk.ErrAlreadyOpen A second Open call in the same process
sdk.ErrClosed Any method after Close
sdk.ErrNotConfigured Chat/Complete with no configured providers
sdk.ErrNoModels Provider has no models for the requested model
sdk.ErrNoSession Session not found (GetSession, Chat with a bad SessionID)
sdk.ErrModelTimeout Timed out selecting a model

Aliased errors

These are the same values as the internal sentinels, so errors.Is works:

Sentinel Value
sdk.ErrAgentEmptyInput agent: input must not be empty
sdk.ErrAgentMaxIterations agent: max iterations reached
sdk.ErrAgentNoProvider agent: provider is not set
sdk.ErrAgentToolExecFailed agent: tool execution failed
sdk.ErrToolNil / ErrToolEmpty / ErrToolDuplicate / ErrToolNotFound tool registry errors
sdk.ErrMiddlewareNil / ErrMiddlewareDuplicate / ErrMiddlewareNotFound middleware registry errors
sdk.ErrSessionNotFound / ErrSessionDuplicate / ErrSessionMessageNotFound / ErrSessionEmptyTitle session store errors
sdk.ErrCacheNotFound cache miss

Provider errors

Drivers return *sdk.ProviderError with a status code:

var perr *sdk.ProviderError
if errors.As(err, &perr) {
    switch {
    case perr.RateLimited():
        // HTTP 429
    case perr.Temporary():
        // 429 or 5xx — the engine retries these automatically
    }
}

Checking errors

if sdk.Is(err, sdk.ErrNoSession, sdk.ErrNotFound) {
    // matches any of the targets
}

Chat/Complete failures are wrapped (sdk: run: ..., sdk: select model: ...), so unwrap with errors.Is / errors.As against the sentinels above.