Documentation
¶
Overview ¶
Package agentgo is a minimal, composable toolkit for building AI agent applications in Go. It provides the execution kernel — the agent loop, tool dispatch, context management, and a single event stream — and leaves policy (which model, which tools, when to stop, how to render) to the caller.
Two entry points, one for each level of control:
AgentLoop is a pure function: given prompts, context, and a LoopConfig, it runs the loop and returns a <-chan Event. It holds no state of its own — every dependency is injected and every result is an event. Use it when you want to own the state and drive the loop directly.
Agent wraps the loop with conversation state, message queues, and listener dispatch. Construct it with NewAgent and the With* options, register a callback with Agent.Subscribe, then call Agent.Prompt. This is the common case.
Every lifecycle signal — streamed text, tool execution, retries, the final summary — flows through the one Event channel. Context-aware application messages may expose ContextItem values; each model call then emits the projected inventory so trajectory evaluators can correlate it with application-defined ContextDemand values without moving interpretation policy into the kernel. A single consumer can drive any front end (TUI, web, Slack, logs) without the kernel knowing which.
A small, stable surface carries most uses: Agent, AgentLoop, Event, Tool, AgentMessage, and Message. AgentMessage is the application transcript type; Message is the model protocol type produced only at the call boundary. The rest is opt-in — context strategies, stop guards, sub-agents, middleware — reached only when a use case needs it.
Models are adapters behind the ChatModel interface; the kernel imports no LLM SDK. Provider errors are classified through the RetryableError and RetryHinter interfaces plus the ErrProvider* sentinels, so any backend can take part in retries and failover. The bundled llm adapter (agentgo/llm) covers OpenAI, Anthropic, and Gemini via litellm.
See the examples directory for runnable single- and multi-agent programs.
Index ¶
- Constants
- Variables
- func AgentLoop(ctx context.Context, prompts []AgentMessage, agentCtx AgentContext, ...) <-chan Event
- func AgentLoopContinue(ctx context.Context, agentCtx AgentContext, config LoopConfig) <-chan Event
- func AssertMessageSequence(msgs []Message) error
- func ClassifyProvider(err error) error
- func ErrorKind(err error) string
- func FailoverReason(err error) string
- func IsContextOverflow(err error) bool
- func IsFailoverEligible(err error) bool
- func IsStreamIdleMessage(s string) bool
- func ReactivateDeferred(tools []Tool, msgs []AgentMessage)
- func ReportToolProgress(ctx context.Context, progress ProgressPayload)
- func WithToolProgress(ctx context.Context, fn ToolProgressFunc) context.Context
- type ActivityDescriber
- type AfterTurnContext
- type AfterTurnHook
- type Agent
- func (a *Agent) Abort()
- func (a *Agent) AbortSilent()
- func (a *Agent) BaselineContextUsage() *ContextUsage
- func (a *Agent) BuildLLMMessages() ([]Message, error)
- func (a *Agent) BuildLLMTools() []ToolSpec
- func (a *Agent) ClearAllQueues()
- func (a *Agent) ClearFollowUpQueue()
- func (a *Agent) ClearSteeringQueue()
- func (a *Agent) ContextSnapshot() *ContextSnapshot
- func (a *Agent) ContextUsage() *ContextUsage
- func (a *Agent) Continue(ctx context.Context) error
- func (a *Agent) ExportMessages() []Message
- func (a *Agent) FollowUp(msg AgentMessage)
- func (a *Agent) HasFollowUps() bool
- func (a *Agent) HasQueuedMessages() bool
- func (a *Agent) HoldRuns() (release func())
- func (a *Agent) ImportMessages(msgs []Message) error
- func (a *Agent) Inject(ctx context.Context, msg AgentMessage) (InjectResult, error)
- func (a *Agent) Messages() []AgentMessage
- func (a *Agent) Prompt(ctx context.Context, input string) error
- func (a *Agent) PromptMessages(ctx context.Context, msgs ...AgentMessage) error
- func (a *Agent) Reset()
- func (a *Agent) SetContextWindow(n int)
- func (a *Agent) SetMessageCommitter(fn func(AgentMessage) error)
- func (a *Agent) SetMessages(msgs []AgentMessage) error
- func (a *Agent) SetModel(m ChatModel)
- func (a *Agent) SetPromptCacheKey(key string)
- func (a *Agent) SetSystemBlocks(blocks []SystemBlock)
- func (a *Agent) SetSystemPrompt(s string)
- func (a *Agent) SetThinkingLevel(level ThinkingLevel)
- func (a *Agent) SetTools(tools ...Tool)
- func (a *Agent) State() AgentState
- func (a *Agent) Steer(msg AgentMessage)
- func (a *Agent) Subscribe(fn func(Event)) func()
- func (a *Agent) TotalUsage() Usage
- func (a *Agent) WaitForIdle()
- type AgentContext
- type AgentMessage
- type AgentOption
- func WithAbortMarkerText(inference, toolUse string) AgentOption
- func WithAfterTurn(hook AfterTurnHook) AgentOption
- func WithBeforeTurn(hook BeforeTurnHook) AgentOption
- func WithCacheLastMessage(cacheControl string) AgentOption
- func WithContextManager(mgr ContextManager) AgentOption
- func WithLengthRecoveryPrompt(prompt string) AgentOption
- func WithMaxRetries(n int) AgentOption
- func WithMaxToolConcurrency(n int) AgentOption
- func WithMaxToolErrors(n int) AgentOption
- func WithMaxTurns(n int) AgentOption
- func WithMessageCommitter(fn func(AgentMessage) error) AgentOption
- func WithMiddlewares(mw ...ToolMiddleware) AgentOption
- func WithModel(model ChatModel) AgentOption
- func WithOnMessage(fn func(AgentMessage)) AgentOption
- func WithPromptCacheKey(key string) AgentOption
- func WithStopGuard(guard StopGuard) AgentOption
- func WithSystemBlocks(blocks []SystemBlock) AgentOption
- func WithSystemPrompt(prompt string) AgentOption
- func WithThinkingLevel(level ThinkingLevel) AgentOption
- func WithToolGate(gate ToolGate) AgentOption
- func WithToolResultMessageFactory(factory func(ToolCall, ToolResult) AgentMessage) AgentOption
- func WithTools(tools ...Tool) AgentOption
- type AgentState
- type BeforeTurnContext
- type BeforeTurnHook
- type CallConfig
- type CallOption
- func WithAPIKey(key string) CallOption
- func WithCallPromptCacheKey(key string) CallOption
- func WithCallSessionID(id string) CallOption
- func WithJSONMode() CallOption
- func WithJSONSchema(name, description string, schema any, strict bool) CallOption
- func WithMaxTokens(tokens int) CallOption
- func WithResponseFormat(format *ResponseFormat) CallOption
- func WithThinking(level ThinkingLevel) CallOption
- func WithThinkingBudget(tokens int) CallOption
- func WithToolChoice(choice any) CallOption
- type ChatModel
- type CompactReason
- type CompactionInfo
- type ConcurrencySafeTool
- type ContentBlock
- type ContentTool
- type ContentType
- type ContextCommitResult
- type ContextDemand
- type ContextDemandProvider
- type ContextEstimateFn
- type ContextEstimator
- type ContextItem
- type ContextItemProvider
- type ContextKey
- type ContextManager
- type ContextOverflowError
- type ContextProjection
- type ContextRecoveryResult
- type ContextSnapshot
- type ContextUsage
- type ContextWindowProvider
- type ContextWindowSetter
- type Cost
- type DeferActivator
- type DeferFilter
- type DeltaKind
- type EndReason
- type Event
- type EventStream
- type EventType
- type FuncTool
- type GateDecision
- type GateRequest
- type ImageData
- type InjectDisposition
- type InjectResult
- type InterruptBehavior
- type InterruptBehaviorTool
- type JSONSchema
- type LLMRequest
- type LLMResponse
- type LoopConfig
- type MaxTurnsError
- type Message
- func AbortMsg(text, phase string) Message
- func CollectMessages(msgs []AgentMessage) []Message
- func RepairMessageSequence(msgs []Message) []Message
- func SystemMsg(text string) Message
- func ToMessages(messages []AgentMessage) []Message
- func ToolResultMsg(toolCallID string, content json.RawMessage, isError bool) Message
- func UserMsg(text string) Message
- func (m Message) Compact(float64) (AgentMessage, float64)
- func (m Message) GetRole() Role
- func (m Message) GetTimestamp() time.Time
- func (m Message) HasToolCalls() bool
- func (m Message) IsEmpty() bool
- func (m Message) Priority() int
- func (m Message) Raw() AgentMessage
- func (m Message) TextContent() string
- func (m Message) ThinkingContent() string
- func (m Message) ToMessage() (Message, bool)
- func (m Message) ToolCalls() []ToolCall
- type MessageSequenceIssue
- type MessageSequenceIssueKind
- type ModelNamer
- type PartialStreamError
- type Previewer
- type ProgressPayload
- type ProgressPayloadKind
- type ProviderNamer
- type ReadOnlyTool
- type ResponseFormat
- type RetryHinter
- type RetryInfo
- type RetryableError
- type Role
- type RunSummary
- type StopDecision
- type StopGuard
- type StopInfo
- type StopReason
- type StopTrigger
- type StreamEvent
- type StreamEventType
- type StrictSchemaTool
- type SwappableModel
- func (m *SwappableModel) Current() ChatModel
- func (m *SwappableModel) Generate(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (*LLMResponse, error)
- func (m *SwappableModel) GenerateStream(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (<-chan StreamEvent, error)
- func (m *SwappableModel) ModelName() string
- func (m *SwappableModel) ProviderName() string
- func (m *SwappableModel) SupportsTools() bool
- func (m *SwappableModel) Swap(next ChatModel)
- type SystemBlock
- type ThinkingLevel
- type Tool
- type ToolCall
- type ToolExecUpdateKind
- type ToolExecuteFunc
- type ToolGate
- type ToolLabeler
- type ToolMiddleware
- type ToolProgressFunc
- type ToolResult
- type ToolSpec
- type ToolValidationError
- type Usage
- type ValidationIssue
- type ValidationResult
- type Validator
Constants ¶
const ( IssueMissing = "missing" IssueType = "type" IssueValue = "value" IssueUnknown = "unknown" )
const ( ResponseFormatText = "text" ResponseFormatJSONObject = "json_object" ResponseFormatJSONSchema = "json_schema" )
Variables ¶
var ( ErrMaxTurns = errors.New("max turns reached") ErrNoModel = errors.New("no model configured") ErrNoMessages = errors.New("cannot continue: no messages in context") ErrAlreadyRunning = errors.New("agent is already running") ErrBadContinuation = errors.New("cannot continue from this message role without queued messages") ErrStopGuard = errors.New("stop guard escalated: run terminated") ErrContextOverflow = errors.New("context window overflow") ErrStreamPartial = errors.New("stream closed without done event") ErrToolValidation = errors.New("tool argument validation failed") ErrInjectNilMessage = errors.New("inject message is nil") ErrRunsHeld = errors.New("agent runs are held") )
Sentinel errors. Use with errors.Is.
var ( ErrProviderRateLimit = errors.New("provider rate limit") ErrProviderQuota = errors.New("provider quota exhausted") ErrProviderTimeout = errors.New("provider timeout") ErrProviderStreamIdle = errors.New("provider stream idle") ErrProviderNetwork = errors.New("provider network") ErrProviderAuth = errors.New("provider auth") ErrProviderOverloaded = errors.New("provider overloaded") ErrProviderContentFilter = errors.New("provider content filter") )
Provider runtime sentinels. These categorize errors returned by the model adapter at call time (provider API errors, network failures, server responses). Use ClassifyProvider to derive the most specific sentinel from an error chain, or match directly with errors.Is.
Functions ¶
func AgentLoop ¶
func AgentLoop(ctx context.Context, prompts []AgentMessage, agentCtx AgentContext, config LoopConfig) <-chan Event
AgentLoop starts an agent loop with new prompt messages. Prompts are added to context and events are emitted for them.
The returned channel MUST be consumed until it closes: while the run is live the loop blocks on a full channel (backpressure, no event loss), so abandoning the channel without canceling ctx leaks the loop goroutine. To stop early, cancel ctx and keep draining — after cancellation delivery degrades to best-effort and the loop is guaranteed to exit and close the channel even if no one is reading.
func AgentLoopContinue ¶
func AgentLoopContinue(ctx context.Context, agentCtx AgentContext, config LoopConfig) <-chan Event
AgentLoopContinue continues from existing context without adding new messages. The last message in context must convert to user or tool role via ToMessage.
The returned channel follows the same consumption contract as AgentLoop: drain until close, or cancel ctx and keep draining to stop early.
func AssertMessageSequence ¶
AssertMessageSequence returns an error when the transcript would require synthetic repair before being sent to an LLM provider.
func ClassifyProvider ¶
ClassifyProvider inspects an LLM/provider error and returns the most specific matching sentinel from this package's Err* variables. Returns nil when err is nil; returns err unchanged when no classification applies, so callers can wrap with their own context.
Stream-idle is checked before generic timeout: it is a stuck connection that failover can typically rescue, whereas a generic timeout may just be a slow model. Both error-chain matching (adapters map stream-idle onto ErrProviderStreamIdle) and message pattern matching are supported because sub-agent JSON results flatten the original error to a plain string.
Context overflow is intentionally not returned here — use IsContextOverflow, which covers both the agentgo wrapper and adapter-classified errors.
func ErrorKind ¶
ErrorKind returns a stable, log-friendly label for err: "canceled", "stop_guard", "max_turns", "context_overflow", "stream_partial", "tool_validation", "stream_idle", "quota", "rate_limit", "timeout", "auth", "network", "overloaded", "content_filter". Returns "" for nil and "unknown" when nothing matches.
Labels are part of the public API contract — they will not change between minor versions, so harnesses can key alert routing and log filters on them instead of matching error strings.
func FailoverReason ¶
FailoverReason returns a stable short label ("rate_limit" / "timeout" / "stream_idle" / "network" / "overloaded") suitable for structured logging. Returns "" when err is not failover-eligible.
func IsContextOverflow ¶
IsContextOverflow reports whether err indicates a context-overflow condition. Both the agentgo wrapper (*ContextOverflowError) and adapter-classified provider errors map onto ErrContextOverflow, so a single errors.Is covers both layers. Convenience for callers that want to detect "request too big" without caring where it surfaced.
func IsFailoverEligible ¶
IsFailoverEligible reports whether err matches a transient provider error suitable for cross-provider failover: rate_limit, timeout, network, or stream_idle. Returns false for auth errors, content filters, context_overflow, user cancellation, or unclassified errors.
func IsStreamIdleMessage ¶
IsStreamIdleMessage reports whether s contains the rendered marker of a stream idle-timeout abort. Useful when only the error string survives (sub-agent JSON results, structured event payloads that flatten the chain).
func ReactivateDeferred ¶
func ReactivateDeferred(tools []Tool, msgs []AgentMessage)
ReactivateDeferred scans restored messages for tool_reference blocks and pre-activates them via the DeferActivator found in tools. This must be called after restoring a session to avoid "Tool reference not found" errors.
func ReportToolProgress ¶
func ReportToolProgress(ctx context.Context, progress ProgressPayload)
ReportToolProgress reports structured progress during tool execution. Silently ignored if no callback is registered in the context.
func WithToolProgress ¶
func WithToolProgress(ctx context.Context, fn ToolProgressFunc) context.Context
WithToolProgress injects a progress callback into the context.
Types ¶
type ActivityDescriber ¶
type ActivityDescriber interface {
ActivityDescription(args json.RawMessage) string
}
ActivityDescriber is an optional interface for tools that provide a human-readable activity description for UI display.
type AfterTurnContext ¶
type AfterTurnContext struct {
TurnIndex int
Message AgentMessage
ToolResults []ToolResult
Context AgentContext
}
AfterTurnContext describes one normally completed model/tool turn. Context includes the assistant message and all tool results from that turn.
type AfterTurnHook ¶
type AfterTurnHook func(context.Context, AfterTurnContext) error
AfterTurnHook runs after a normal turn's assistant message and tool results have been committed. It may update application state consumed by the next BeforeTurnHook. Returning an error stops the run.
type Agent ¶
type Agent struct {
// contains filtered or unexported fields
}
Agent is a stateful wrapper around the agent loop. It consumes loop events to update internal state, just like any external listener.
func NewAgent ¶
func NewAgent(opts ...AgentOption) *Agent
NewAgent creates a new Agent with the given options.
When a ContextManager is set, the agent auto-wires the context-token estimator and context window when the manager implements the optional ContextEstimator / ContextWindowProvider interfaces.
func (*Agent) Abort ¶
func (a *Agent) Abort()
Abort cancels the current execution and emits an abort marker message so the LLM knows the user interrupted.
Abort does not touch the steering/follow-up queues: messages queued before the cancellation stay queued and are replayed by the next run (see Continue). Harnesses that treat queued input as stale after an abort must clear it explicitly.
func (*Agent) AbortSilent ¶
func (a *Agent) AbortSilent()
AbortSilent cancels the current execution without emitting an abort marker. Use for programmatic cancellation (e.g. plan mode transitions) where the cancellation is not a user interruption.
func (*Agent) BaselineContextUsage ¶
func (a *Agent) BaselineContextUsage() *ContextUsage
BaselineContextUsage returns the current runtime baseline occupancy. Unlike ContextUsage, this never reports a transient projected view.
func (*Agent) BuildLLMMessages ¶
BuildLLMMessages constructs the message list with the same system-blocks / converted-history layout the agent loop uses for its primary LLM call.
Loop-scoped concerns are deliberately omitted: per-turn reminders are not appended, and no last-user cache_control marker is added. External callers (e.g., prompt suggestion) use this to share a stable prefix with the main conversation for prompt cache reads without writing new breakpoints of their own — the main loop's marker remains the sole writer.
Malformed tool-call / result transcripts are repaired via RepairMessageSequence.
func (*Agent) BuildLLMTools ¶
BuildLLMTools returns the ToolSpec list this agent would send to the LLM on its next turn — the exact same conversion buildToolSpecs runs inside the agent loop, including DeferFilter handling.
Side-channel callers (the /btw side-question path, prompt suggestion) need this to keep their request's `tools` field byte-identical to the main agent's last request — Anthropic's prompt cache rejects any prefix difference, and `tools` precedes the system-block cache breakpoint. Without this method, those callers send `tools: nil` and miss the system cache.
func (*Agent) ClearAllQueues ¶
func (a *Agent) ClearAllQueues()
ClearAllQueues removes all queued steering and follow-up messages.
func (*Agent) ClearFollowUpQueue ¶
func (a *Agent) ClearFollowUpQueue()
ClearFollowUpQueue removes all queued follow-up messages.
func (*Agent) ClearSteeringQueue ¶
func (a *Agent) ClearSteeringQueue()
ClearSteeringQueue removes all queued steering messages.
func (*Agent) ContextSnapshot ¶
func (a *Agent) ContextSnapshot() *ContextSnapshot
ContextSnapshot returns the latest context-manager snapshot for observability. Returns nil when no ContextManager is configured or no snapshot is available.
func (*Agent) ContextUsage ¶
func (a *Agent) ContextUsage() *ContextUsage
ContextUsage returns an estimate of the current context window occupancy. Returns nil if contextWindow or contextEstimateFn is not configured.
func (*Agent) Continue ¶
Continue resumes from the current context without adding new messages. If the last message is from assistant, it dequeues steering/follow-up messages (steering first) and replays them as the new prompt.
Queue retention caveat: messages queued via Steer/FollowUp survive an aborted run — Abort cancels execution but never consumes or clears the queues, so the next Continue (including any automatic resume the harness performs) replays them. If a queued directive must not outlive the run it was meant for, clear it on your abort path via ClearSteeringQueue / ClearFollowUpQueue / ClearAllQueues; agentgo cannot decide this — some harnesses queue droppable steering text, others queue task-completion notifications that must never be lost.
func (*Agent) ExportMessages ¶
ExportMessages returns only concrete model Messages. Use Messages with an application codec when custom AgentMessage values must survive persistence.
func (*Agent) FollowUp ¶
func (a *Agent) FollowUp(msg AgentMessage)
FollowUp queues a message for the next natural continuation point. An active run consumes follow-ups when it reaches that point; an idle Agent retains them until the harness calls Continue.
func (*Agent) HasFollowUps ¶
HasFollowUps reports whether follow-up messages are waiting to be consumed.
func (*Agent) HasQueuedMessages ¶
HasQueuedMessages reports whether any steering or follow-up messages are queued.
func (*Agent) HoldRuns ¶
func (a *Agent) HoldRuns() (release func())
HoldRuns stops the world for state surgery: it silently cancels any in-flight run, waits for it to drain, and rejects new run starts (PromptMessages / Continue / InjectContext return ErrRunsHeld) until the returned release is called. Use it to make multi-step mutations — swap the conversation, clear history, retarget stores — atomic with respect to the run lifecycle, including auto-continues a listener may attempt mid-surgery.
release := agent.HoldRuns() defer release() // no run is in flight and none can start
Semantics:
- Counting: concurrent holders each get their own release (idempotent); runs stay rejected until every release has been called. The hold only freezes the run lifecycle — it does NOT mutually exclude two holders' state mutations; serialize holders on the host side.
- The cancel is silent: HoldRuns itself never requests an abort marker. (A concurrent Abort can still mark the dying run — the hold does not suppress user interruptions.)
- Queues are untouched: like Abort, a hold never consumes or clears Steer/FollowUp messages — clear them explicitly if they must not outlive the held run (see Continue's queue-retention caveat).
- WaitForIdle after HoldRuns returns immediately: "no run in flight" is guaranteed, but that does not mean starts are allowed again.
- MUST NOT be called from an event listener: the drained run's done channel closes only after its listeners return, so a listener waiting on HoldRuns deadlocks itself. (The same restriction applies to Reset.)
func (*Agent) ImportMessages ¶
ImportMessages replaces message history from deserialized Messages.
func (*Agent) Inject ¶
func (a *Agent) Inject(ctx context.Context, msg AgentMessage) (InjectResult, error)
Inject delivers a message as soon as the current agent state allows. An idle resume runs under ctx, so values threaded onto it (cwd override, deadlines) reach the resumed run's tools just as they would on PromptMessages/Continue.
Outcomes:
- runs held (HoldRuns) → ErrRunsHeld, nothing queued
- running → steer into current run (ctx unused; the live run keeps its own)
- idle + assistant tail → enqueue and resume, atomically
- idle + no assistant tail → enqueue for next run
func (*Agent) Messages ¶
func (a *Agent) Messages() []AgentMessage
Messages returns the current message history.
func (*Agent) Prompt ¶
Prompt starts a new conversation turn with the given input. The ctx scopes the run: its deadline, trace values, and cancellation propagate into the loop, and cancelling it aborts the run just like Abort.
func (*Agent) PromptMessages ¶
func (a *Agent) PromptMessages(ctx context.Context, msgs ...AgentMessage) error
PromptMessages starts a new conversation turn with arbitrary AgentMessages. See Prompt for ctx semantics.
func (*Agent) Reset ¶
func (a *Agent) Reset()
Reset clears all state and queues. A run already in flight is silently cancelled, drained, and wiped with the rest of the state; a run start attempted after the drain begins fails with ErrRunsHeld instead of being silently clobbered. Must not be called from an event listener (see HoldRuns).
func (*Agent) SetContextWindow ¶
SetContextWindow updates the context window size (in tokens). The new value is also pushed to the ContextManager when it implements ContextWindowSetter, so a model hot-switch needs exactly one call to keep agent-side usage reporting and engine-side compaction thresholds in agreement.
func (*Agent) SetMessageCommitter ¶
func (a *Agent) SetMessageCommitter(fn func(AgentMessage) error)
SetMessageCommitter replaces the durable message callback used by subsequent runs. Returning an error stops the run before the message enters context.
func (*Agent) SetMessages ¶
func (a *Agent) SetMessages(msgs []AgentMessage) error
SetMessages replaces the message history — restore a previous conversation, or clear it with nil. Refused while a run is in flight (ErrAlreadyRunning): the loop's context commit would resurrect the replaced history as silent corruption. Hold the lifecycle first (HoldRuns) when mutating around live runs.
func (*Agent) SetModel ¶
SetModel changes the LLM provider. Takes effect on the next turn.
Purity contract (stable API guarantee, shared by SetThinkingLevel, SetTools, SetSystemPrompt and SetSystemBlocks): a pure field assignment under the agent's internal mutex — no events emitted, no callbacks invoked — so it is safe to call from event listeners and while holding host locks. SetContextWindow is NOT part of this contract: it calls back into the ContextManager outside the lock.
func (*Agent) SetPromptCacheKey ¶
SetPromptCacheKey changes the prompt-cache routing identity at runtime. Takes effect on the next turn. Hosts that reuse one Agent across logical conversations (session switch / reset) must update the key so a new conversation doesn't inherit the previous one's cache lineage. See WithPromptCacheKey for semantics.
func (*Agent) SetSystemBlocks ¶
func (a *Agent) SetSystemBlocks(blocks []SystemBlock)
SetSystemBlocks sets a multi-block system prompt with per-block cache control. Takes precedence over SetSystemPrompt. Clears the single-string prompt. Purity contract: see SetModel.
func (*Agent) SetSystemPrompt ¶
SetSystemPrompt changes the system prompt (single-string mode). Clears any multi-block system prompt set via SetSystemBlocks. Purity contract: see SetModel.
func (*Agent) SetThinkingLevel ¶
func (a *Agent) SetThinkingLevel(level ThinkingLevel)
SetThinkingLevel changes the reasoning depth. Takes effect on the next turn. Purity contract: see SetModel.
func (*Agent) SetTools ¶
SetTools replaces the tool set. Takes effect on the next turn. Purity contract: see SetModel.
func (*Agent) State ¶
func (a *Agent) State() AgentState
State returns a snapshot of the agent's current state.
func (*Agent) Steer ¶
func (a *Agent) Steer(msg AgentMessage)
Steer queues a steering message to interrupt the agent mid-run. Delivered after the current tool execution; remaining tools are skipped.
func (*Agent) Subscribe ¶
Subscribe registers a listener for agent events. Returns an unsubscribe function.
Dispatch contract (stable API guarantee): listeners are invoked synchronously, in registration order, on the agent's event-consumption goroutine. A listener registered before another always observes each event first — ordering-sensitive consumers (e.g. a budget sentinel that must veto before a dispatcher reacts) may rely on this. The flip side: a slow listener delays event delivery to all later listeners and backpressures the loop's event channel; offload heavy work to your own goroutine.
Lifecycle contract (stable API guarantee):
- When EventAgentEnd listeners run, isRunning is already false — a listener may start the next run (Continue / InjectContext) directly.
- The run's done channel — what WaitForIdle and HoldRuns wait on — closes only after all listeners for the final event have returned.
- Therefore a listener must never call HoldRuns or Reset, and must never block on a lock that may be held by a goroutine waiting on WaitForIdle/HoldRuns: both are self-deadlocks.
func (*Agent) TotalUsage ¶
TotalUsage returns the cumulative token usage across all turns.
func (*Agent) WaitForIdle ¶
func (a *Agent) WaitForIdle()
WaitForIdle blocks until the agent finishes the current run.
type AgentContext ¶
type AgentContext struct {
SystemPrompt string // single-string system prompt (legacy)
SystemBlocks []SystemBlock // multi-block system prompt with cache control (takes precedence)
Messages []AgentMessage
Tools []Tool
}
AgentContext holds the immutable context for a single agent loop invocation.
type AgentMessage ¶
type AgentMessage interface {
GetRole() Role
GetTimestamp() time.Time
Raw() AgentMessage
Priority() int
Compact(expect float64) (next AgentMessage, actual float64)
TextContent() string
ThinkingContent() string
HasToolCalls() bool
ToMessage() (message Message, include bool)
}
AgentMessage is the application-layer message abstraction used by the agent loop, context management, events, and persistence. Message implements this interface; applications can add richer message types without lowering them to the model protocol until ToMessage is called.
Raw returns the original domain message regardless of the current compacted representation. Compact asks the message for the highest-fidelity representation that fits expect, where 1 is the raw size and 0 means the smallest representation the domain can provide. actual is the size ratio the returned value reached, always relative to Raw. Compact must be monotonic and must not mutate the receiver.
Priority is application information importance: higher values are preserved longer by context policies and are not part of the model-level Message.
func Collect ¶
func Collect(events <-chan Event) ([]AgentMessage, error)
Collect consumes all events from the channel and returns the final messages. Blocks until the channel is closed. Returns any error from EventError events.
func ToAgentMessages ¶
func ToAgentMessages(msgs []Message) []AgentMessage
ToAgentMessages converts a Message slice to AgentMessage slice. Use this to restore conversation history from deserialized Messages.
type AgentOption ¶
type AgentOption func(*Agent)
AgentOption configures an Agent.
func WithAbortMarkerText ¶
func WithAbortMarkerText(inference, toolUse string) AgentOption
WithAbortMarkerText overrides the marker messages recorded when a run is cancelled: inference is used mid-inference, toolUse during tool execution. Either empty keeps that built-in default. Lets non-English harnesses localize the markers that get written into conversation history.
func WithAfterTurn ¶
func WithAfterTurn(hook AfterTurnHook) AgentOption
WithAfterTurn installs a hook that runs after every normally completed assistant/tool turn and before the loop continues or stops.
func WithBeforeTurn ¶
func WithBeforeTurn(hook BeforeTurnHook) AgentOption
WithBeforeTurn installs a hook that runs before every model call. Messages returned by the hook are committed before that request.
func WithCacheLastMessage ¶
func WithCacheLastMessage(cacheControl string) AgentOption
WithCacheLastMessage tags the last non-system message with cache_control before every LLM call. Providers that support prompt caching (Anthropic, Bedrock) place a write breakpoint at that position, covering the entire preceding prefix (system blocks + conversation history + tools).
The marker lands on whichever turn is freshest — user input, tool_result, or assistant — and skips trailing per-turn system reminders. Inside a tool loop this means each LLM call writes a cache entry covering the latest tool_use+tool_result, so the next call reads them from cache instead of re-uploading.
When the agent uses a plain SystemPrompt (not SystemBlocks), the loop also pins the system message with the same cache_control as a stable floor, so fresh sessions sharing the prompt reuse the system+tools prefix. SystemBlocks users keep explicit control via SystemBlock.CacheControl.
Pass "" (default) to leave messages untouched. Pass "ephemeral" for the standard 5-minute TTL, or "ephemeral:1h" for the extended TTL where the provider supports it (use for conversations whose turn gaps regularly exceed 5 minutes). Use this when the application — not the LLM library — owns cache placement.
func WithContextManager ¶
func WithContextManager(mgr ContextManager) AgentOption
WithContextManager sets the context lifecycle manager. When configured, it drives prompt projection, overflow recovery, and usage reporting. The agent auto-wires context-token estimation and the context window from the manager when it implements the optional ContextEstimator / ContextWindowProvider interfaces.
func WithLengthRecoveryPrompt ¶
func WithLengthRecoveryPrompt(prompt string) AgentOption
WithLengthRecoveryPrompt overrides the user message injected when output is truncated (max_tokens) with no completed tool calls. Empty keeps the built-in default prompt.
func WithMaxRetries ¶
func WithMaxRetries(n int) AgentOption
WithMaxRetries sets the LLM call retry limit for retryable errors.
func WithMaxToolConcurrency ¶
func WithMaxToolConcurrency(n int) AgentOption
WithMaxToolConcurrency sets the maximum number of tools executed in parallel. 0 or 1 = sequential (default). >1 enables concurrent tool execution.
func WithMaxToolErrors ¶
func WithMaxToolErrors(n int) AgentOption
WithMaxToolErrors sets the consecutive failure threshold per tool. After reaching this limit, the tool is disabled for the rest of the loop. 0 means unlimited (no circuit breaker).
func WithMaxTurns ¶
func WithMaxTurns(n int) AgentOption
WithMaxTurns sets the max turns safety limit. n <= 0 falls back to the built-in default (100).
Accounting note: a "turn" is one LLM call. Length-recovery (automatic resume after a max_tokens truncation) injects extra calls that count toward this limit, so budget recoveries into tight limits.
func WithMessageCommitter ¶
func WithMessageCommitter(fn func(AgentMessage) error) AgentOption
WithMessageCommitter installs a synchronous durable-message callback. Returning an error stops the run before the message enters context or starts requested tools.
func WithMiddlewares ¶
func WithMiddlewares(mw ...ToolMiddleware) AgentOption
WithMiddlewares sets tool execution middlewares. Each middleware wraps the tool.Execute call. First middleware is outermost.
func WithOnMessage ¶
func WithOnMessage(fn func(AgentMessage)) AgentOption
WithOnMessage registers a callback invoked after each message is appended to the agent's context. Use it for observation; durable persistence should use WithMessageCommitter so write errors can stop execution.
func WithPromptCacheKey ¶
func WithPromptCacheKey(key string) AgentOption
WithPromptCacheKey sets the prompt-cache routing identity attached to every LLM request of this agent (e.g. OpenAI prompt_cache_key). Keep one key per long-lived conversation: requests sharing a key are routed to the same provider cache shard, so each turn can read the previous turn's prefix from cache. The adapter drops the hint for providers without key-routed caching. Empty (default) sends no hint.
func WithStopGuard ¶
func WithStopGuard(guard StopGuard) AgentOption
WithStopGuard installs a guard that decides whether the agent may stop when the LLM emits end_turn without tool calls. Nil guard (default) means every stop is allowed — legacy behavior.
func WithSystemBlocks ¶
func WithSystemBlocks(blocks []SystemBlock) AgentOption
WithSystemBlocks sets a multi-block system prompt with per-block cache control. Takes precedence over WithSystemPrompt.
func WithSystemPrompt ¶
func WithSystemPrompt(prompt string) AgentOption
WithSystemPrompt sets the system prompt (single-string mode).
func WithThinkingLevel ¶
func WithThinkingLevel(level ThinkingLevel) AgentOption
WithThinkingLevel sets the reasoning depth for models that support it.
func WithToolGate ¶
func WithToolGate(gate ToolGate) AgentOption
WithToolGate installs a hook called once per tool call after argument validation and the optional Previewer pass. Returning Allowed=false rejects the call (Reason becomes the tool result error). The kernel does not implement permission reasoning of its own — gates are user-supplied.
func WithToolResultMessageFactory ¶
func WithToolResultMessageFactory(factory func(ToolCall, ToolResult) AgentMessage) AgentOption
WithToolResultMessageFactory converts raw tool results into application AgentMessage values before they enter the transcript. The default keeps the built-in model Message representation. The returned message must project to a tool Message with the matching tool_call_id.
type AgentState ¶
type AgentState struct {
SystemPrompt string
Messages []AgentMessage
Tools []Tool
IsRunning bool
StreamMessage AgentMessage // partial message being streamed, nil when idle
PendingToolCalls map[string]struct{} // tool call IDs currently executing
TotalUsage Usage // cumulative token usage across all turns
Error string
}
AgentState is a snapshot of the agent's current state.
type BeforeTurnContext ¶
type BeforeTurnContext struct {
TurnIndex int
Context AgentContext
}
BeforeTurnContext describes the runtime immediately before one model call. TurnIndex is one-based. Context is a snapshot; mutating it does not change the running loop.
type BeforeTurnHook ¶
type BeforeTurnHook func(context.Context, BeforeTurnContext) ([]AgentMessage, error)
BeforeTurnHook runs before each model call. Returned messages are committed to the transcript before the request, allowing applications to prepare or steer the next turn without teaching the loop about business phases.
type CallConfig ¶
type CallConfig struct {
ThinkingLevel ThinkingLevel
ThinkingBudget int // max thinking tokens, 0 = use provider default
APIKey string // per-call API key override, empty = use model default
SessionID string // provider session caching identifier
PromptCacheKey string // prompt-cache routing identity, empty = no hint
MaxTokens int // per-call max tokens override, 0 = use model default
ToolChoice any // "auto" / "required" / "none" / {"type":"tool","name":"xxx"}, nil = provider default
ResponseFormat *ResponseFormat
}
CallConfig holds per-call configuration resolved from CallOptions.
func ResolveCallConfig ¶
func ResolveCallConfig(opts []CallOption) CallConfig
ResolveCallConfig applies options and returns the resolved config.
type CallOption ¶
type CallOption func(*CallConfig)
CallOption configures per-call LLM parameters.
func WithAPIKey ¶
func WithAPIKey(key string) CallOption
WithAPIKey overrides the API key for a single LLM call. Enables key rotation, OAuth short-lived tokens, and multi-tenant scenarios.
func WithCallPromptCacheKey ¶
func WithCallPromptCacheKey(key string) CallOption
WithCallPromptCacheKey sets the prompt-cache routing identity for a single LLM call. Providers with key-routed prefix caching (OpenAI prompt_cache_key) route requests sharing a key to the same cache shard; the adapter drops the hint for providers without support.
func WithCallSessionID ¶
func WithCallSessionID(id string) CallOption
WithCallSessionID sets a session identifier for a single LLM call.
func WithJSONMode ¶
func WithJSONMode() CallOption
WithJSONMode requests valid JSON output without enforcing a specific schema.
func WithJSONSchema ¶
func WithJSONSchema(name, description string, schema any, strict bool) CallOption
WithJSONSchema requests structured JSON output constrained by a JSON Schema.
func WithMaxTokens ¶
func WithMaxTokens(tokens int) CallOption
WithMaxTokens overrides the max output tokens for a single LLM call.
func WithResponseFormat ¶
func WithResponseFormat(format *ResponseFormat) CallOption
WithResponseFormat sets a provider-native response format explicitly.
func WithThinking ¶
func WithThinking(level ThinkingLevel) CallOption
WithThinking sets the thinking level for a single LLM call.
func WithThinkingBudget ¶
func WithThinkingBudget(tokens int) CallOption
WithThinkingBudget sets the max thinking tokens for a single LLM call.
func WithToolChoice ¶
func WithToolChoice(choice any) CallOption
WithToolChoice controls whether the model must call a tool. Accepted values: "auto" (default), "required" (must call a tool), "none" (no tools).
type ChatModel ¶
type ChatModel interface {
Generate(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (*LLMResponse, error)
GenerateStream(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (<-chan StreamEvent, error)
SupportsTools() bool
}
ChatModel is the LLM provider interface.
type CompactReason ¶
type CompactReason string
CompactReason identifies why context compaction was requested.
const ( CompactReasonManual CompactReason = "manual" CompactReasonOverflow CompactReason = "overflow" CompactReasonThreshold CompactReason = "threshold" )
type CompactionInfo ¶
type CompactionInfo struct {
Reason CompactReason
Committed bool
TokensBefore int
TokensAfter int
MessagesBefore int
MessagesAfter int
Summarized bool
}
CompactionInfo describes one completed context compaction transaction. It reports the aggregate effect of the configured compactor; individual strategies remain an implementation detail. A nil Compaction means no compaction changed the context.
type ConcurrencySafeTool ¶
type ConcurrencySafeTool interface {
ConcurrencySafe(args json.RawMessage) bool
}
ConcurrencySafeTool is an optional interface for tools that declare whether they can safely execute concurrently with other tools. Takes precedence over ReadOnlyTool for concurrency scheduling.
type ContentBlock ¶
type ContentBlock struct {
Type ContentType `json:"type"`
Text string `json:"text,omitempty"`
Thinking string `json:"thinking,omitempty"`
ToolCall *ToolCall `json:"tool_call,omitempty"`
Image *ImageData `json:"image,omitempty"`
ToolName string `json:"tool_name,omitempty"` // tool_reference: referenced tool name
}
ContentBlock is a tagged union for message content. Exactly one payload field is populated, matching the Type value.
func ImageBlock ¶
func ImageBlock(data, mimeType string) ContentBlock
func ImageURLBlock ¶
func ImageURLBlock(url string) ContentBlock
func TextBlock ¶
func TextBlock(text string) ContentBlock
func ThinkingBlock ¶
func ThinkingBlock(thinking string) ContentBlock
func ToolCallBlock ¶
func ToolCallBlock(tc ToolCall) ContentBlock
func ToolRefBlock ¶
func ToolRefBlock(toolName string) ContentBlock
type ContentTool ¶
type ContentTool interface {
ExecuteContent(ctx context.Context, args json.RawMessage) ([]ContentBlock, error)
}
ContentTool is an optional interface for tools that return rich content (e.g., images). When a tool implements ContentTool, the agent loop calls ExecuteContent instead of Execute, enabling multi-block responses with text + image content blocks.
type ContentType ¶
type ContentType string
ContentType identifies the kind of content in a ContentBlock.
const ( ContentText ContentType = "text" ContentThinking ContentType = "thinking" ContentToolCall ContentType = "toolCall" ContentImage ContentType = "image" ContentToolRef ContentType = "tool_reference" )
type ContextCommitResult ¶
type ContextCommitResult struct {
Messages []AgentMessage
Usage *ContextUsage
Changed bool
Compaction *CompactionInfo
CompactedCount int
KeptCount int
SplitTurn bool
}
ContextCommitResult is the result of an explicit committed rewrite. The returned Messages should replace the runtime baseline when Changed is true, for example after a manual /compact command.
type ContextDemand ¶
type ContextDemand struct {
ContextKey
Signal string `json:"signal"`
}
ContextDemand is the protocol-level counterpart of ContextItem. It records that a trajectory exposed demand for the same ContextKey through an application-defined Signal. AgentGo defines the shape only; applications and evaluators decide how demands are derived and what they mean.
func CollectContextDemands ¶
func CollectContextDemands(messages []AgentMessage) []ContextDemand
CollectContextDemands returns explicit demands exposed by messages in message order. Evaluators may combine these with demands inferred from the raw event trajectory.
type ContextDemandProvider ¶
type ContextDemandProvider interface {
ContextDemands() []ContextDemand
}
ContextDemandProvider is an optional capability for messages or trajectory artifacts that can state demands explicitly. Demand inferred from raw tool or model events remains the evaluator's responsibility.
type ContextEstimateFn ¶
type ContextEstimateFn func(msgs []AgentMessage) (tokens, usageTokens, trailingTokens int)
ContextEstimateFn estimates the current context token consumption from messages. Returns total tokens, tokens from LLM Usage, and estimated trailing tokens.
type ContextEstimator ¶
type ContextEstimator interface {
EstimateContext([]AgentMessage) (tokens, usageTokens, trailingTokens int)
}
ContextEstimator is an optional interface a ContextManager can implement to provide token estimation. When implemented, NewAgent auto-wires it.
type ContextItem ¶
type ContextItem struct {
ContextKey
Representation string `json:"representation"`
Reason string `json:"reason,omitempty"`
Ref string `json:"ref,omitempty"`
}
ContextItem describes one identifiable piece of information present in an AgentMessage. Representation, Reason, and Ref are open application labels; AgentGo records them but does not rank or interpret them.
func CollectContextItems ¶
func CollectContextItems(messages []AgentMessage) []ContextItem
CollectContextItems returns the item inventory exposed by messages in message order. It deliberately does not validate, deduplicate, rank, or otherwise interpret application identities.
type ContextItemProvider ¶
type ContextItemProvider interface {
AgentMessage
ContextItems() []ContextItem
}
ContextItemProvider is an optional AgentMessage capability. A message may expose zero, one, or many identifiable context items without changing its model projection.
type ContextKey ¶
ContextKey is the shared identity used to correlate information present in an agent context with information later demanded by the trajectory. Kind and Identity are application-defined; AgentGo assigns them no semantics.
type ContextManager ¶
type ContextManager interface {
// Project builds the prompt view for a single model call without mutating
// the caller's runtime baseline.
Project(ctx context.Context, msgs []AgentMessage) (ContextProjection, error)
// Compact performs an explicit committed rewrite of msgs. The caller is
// responsible for replacing its runtime baseline with the returned Messages
// when Changed is true.
Compact(ctx context.Context, msgs []AgentMessage, reason CompactReason) (ContextCommitResult, error)
// RecoverOverflow produces a retryable view after a provider reports
// context overflow. When ShouldCommit is true, CommitMessages should replace
// the runtime baseline before continuing.
RecoverOverflow(ctx context.Context, msgs []AgentMessage, cause error) (ContextRecoveryResult, error)
// Sync tells the manager what the current runtime baseline is after restore,
// clear, import, or any other external replacement of messages.
Sync(msgs []AgentMessage)
// Usage returns the latest effective context usage remembered by the
// manager. It may reflect a projected or recovered view rather than the raw
// runtime baseline.
Usage() *ContextUsage
// Snapshot returns the latest active view snapshot remembered by the
// manager. It is intended for observability and may be nil before the
// manager has seen any messages.
Snapshot() *ContextSnapshot
}
ContextManager owns prompt projection, committed rewrites, overflow recovery, and usage reporting for long-running agent sessions.
The manager deliberately distinguishes between transient prompt projection and explicit baseline rewrites:
- Project builds a prompt view for one LLM call without committing it.
- Compact performs an explicit committed rewrite such as /compact.
- RecoverOverflow produces a retryable prompt view after context overflow and may optionally return a new committed baseline.
- Sync updates the manager with the current runtime baseline after external message replacement, session restore, or clear.
- Usage reports the latest effective usage remembered by the manager.
- Snapshot reports the current active view and recent rewrite details for debugging and UI surfaces.
type ContextOverflowError ¶
type ContextOverflowError struct {
Cause error
}
ContextOverflowError wraps an underlying context-overflow cause (typically a provider error). errors.Is matches ErrContextOverflow; Unwrap reaches the raw cause so callers can extract provider-specific details if needed.
func (*ContextOverflowError) Error ¶
func (e *ContextOverflowError) Error() string
func (*ContextOverflowError) Is ¶
func (e *ContextOverflowError) Is(target error) bool
func (*ContextOverflowError) Unwrap ¶
func (e *ContextOverflowError) Unwrap() error
type ContextProjection ¶
type ContextProjection struct {
Messages []AgentMessage
Usage *ContextUsage
CommitMessages []AgentMessage
ShouldCommit bool
Compaction *CompactionInfo
}
ContextProjection is the prompt view projected for a single LLM call. By default the projection does not modify the runtime message baseline. When ShouldCommit is true, CommitMessages should replace the runtime baseline before continuing the current call.
type ContextRecoveryResult ¶
type ContextRecoveryResult struct {
View []AgentMessage
CommitMessages []AgentMessage
Usage *ContextUsage
Changed bool
ShouldCommit bool
Compaction *CompactionInfo
CompactedCount int
KeptCount int
SplitTurn bool
}
ContextRecoveryResult is the result of overflow recovery.
View is always the retryable prompt view. CommitMessages is optional and, when ShouldCommit is true, should replace the runtime message baseline so future usage reporting and turns start from the recovered state.
type ContextSnapshot ¶
type ContextSnapshot struct {
Items []ContextItem
BaselineUsage *ContextUsage
Usage *ContextUsage
Scope string
TranscriptMessages int
ActiveMessages int
SummaryMessages int
ToolMessages int
ClearedToolResults int
TrimmedTextBlocks int
LastChanged bool
LastCompactedCount int
LastKeptCount int
LastSplitTurn bool
}
ContextSnapshot describes both the runtime baseline and the current active context view, including its identifiable Items, plus the most recent rewrite details remembered by the manager.
Snapshot is meant for debugging, observability, and UI surfaces such as /context. BaselineUsage always reflects the caller's current runtime message baseline. Usage reports the active view currently remembered by the manager, which may be the baseline runtime messages, a projected prompt view, or a recovered/committed view depending on the most recent operation.
type ContextUsage ¶
type ContextUsage struct {
Tokens int `json:"tokens"` // estimated total tokens in context
ContextWindow int `json:"context_window"` // model's context window size
Percent float64 `json:"percent"` // tokens / contextWindow * 100
UsageTokens int `json:"usage_tokens"` // from last LLM-reported Usage
TrailingTokens int `json:"trailing_tokens"` // chars/4 estimate for trailing messages
}
ContextUsage represents the current context window occupancy estimate.
type ContextWindowProvider ¶
type ContextWindowProvider interface {
ContextWindow() int
}
ContextWindowProvider is an optional interface a ContextManager can implement to report its configured context window size.
type ContextWindowSetter ¶
type ContextWindowSetter interface {
SetContextWindow(n int)
}
ContextWindowSetter is an optional interface a ContextManager can implement to receive window updates pushed through Agent.SetContextWindow. When implemented, the agent and its context manager can never disagree on the window size after a model hot-switch — without it, callers had to update both sides manually and a missed call silently skewed compaction thresholds.
type Cost ¶
type Cost struct {
Input float64 `json:"input"`
Output float64 `json:"output"`
CacheRead float64 `json:"cache_read"`
CacheWrite float64 `json:"cache_write"`
Total float64 `json:"total"`
}
Cost tracks monetary cost for a single LLM call in USD.
type DeferActivator ¶
type DeferActivator interface {
DeferFilter
Activate(names ...string)
}
DeferActivator is an optional extension of DeferFilter that supports pre-activating deferred tools (e.g. when restoring a session whose history contains tool_reference blocks for previously activated tools).
type DeferFilter ¶
type DeferFilter interface {
// IsDeferred reports whether the tool is deferred and not yet activated.
// Unactivated deferred tools are excluded from the API request entirely.
IsDeferred(toolName string) bool
// WasDeferred reports whether the tool was originally in the deferred set
// (regardless of activation). Activated deferred tools are sent with
// defer_loading: true.
WasDeferred(toolName string) bool
}
DeferFilter controls deferred tool loading for the LLM. When a tool in the agent's tool list implements DeferFilter:
- IsDeferred returns true → tool schema is excluded from the API request
- WasDeferred returns true → tool schema is sent with defer_loading: true
Unactivated deferred tools are excluded entirely. Once activated via tool_reference, they are sent with defer_loading: true so the API server manages their context loading. Tools remain registered for execution regardless — only their API visibility changes.
IsDeferred is also used by the system prompt builder to exclude unactivated tools from the tool description section (they appear in <available-deferred-tools> by name only).
type DeltaKind ¶
type DeltaKind string
DeltaKind identifies what kind of content a message_update delta carries.
type Event ¶
type Event struct {
Type EventType
Message AgentMessage // for message_start/update/end, turn_end
Delta string // text delta for message_update
DeltaKind DeltaKind // for message_update: what kind of delta
ToolID string // for tool_exec_*
Tool string // tool name for tool_exec_*
ToolLabel string // human-readable tool label (from ToolLabeler)
Args json.RawMessage // tool args for tool_exec_start/tool_exec_update
Result json.RawMessage // tool result for tool_exec_end and preview updates
Progress *ProgressPayload
UpdateKind ToolExecUpdateKind
IsError bool // tool error flag for tool_exec_end
Preview json.RawMessage
ToolResults []ToolResult // for turn_end: all tool results from this turn
Err error // for error events
NewMessages []AgentMessage // for agent_end: messages added during this loop
RetryInfo *RetryInfo // for retry events
ContextItems []ContextItem // for context_projected
Compaction *CompactionInfo // for context_compacted
Summary *RunSummary // for agent_end: factual run summary
}
Event is a lifecycle event emitted by the agent loop. This is the single output channel for all lifecycle information.
type EventStream ¶
type EventStream struct {
// contains filtered or unexported fields
}
EventStream wraps an event channel to provide both real-time iteration and deferred result collection.
Usage:
stream := agentgo.NewEventStream(AgentLoop(...))
for ev := range stream.Events() {
// handle real-time events
}
msgs, err := stream.Result()
func NewEventStream ¶
func NewEventStream(source <-chan Event) *EventStream
NewEventStream creates an EventStream that reads from the source channel. Events are forwarded to an internal channel for iteration. The final result is captured from EventAgentEnd.
Events() carries the same consumption contract as the source: iterate until it closes. Abandoning it mid-stream leaks the forwarding goroutine — the wrapper has no context to detect an absent reader.
func (*EventStream) Done ¶
func (s *EventStream) Done() <-chan struct{}
Done returns a channel that is closed when the stream finishes.
func (*EventStream) Events ¶
func (s *EventStream) Events() <-chan Event
Events returns the event channel for real-time iteration. The channel is closed when the source is exhausted.
func (*EventStream) Result ¶
func (s *EventStream) Result() ([]AgentMessage, error)
Result blocks until the stream is done and returns the final messages. Returns the error from the last EventError, if any.
type EventType ¶
type EventType string
EventType identifies agent lifecycle event types.
const ( EventAgentStart EventType = "agent_start" EventAgentEnd EventType = "agent_end" EventTurnStart EventType = "turn_start" EventTurnEnd EventType = "turn_end" // EventModelResponse fires after every model call completes, including any // tool executions it triggered. One model invocation produces one event — // not one logical user exchange — so steering injections and length // recoveries each produce additional ones within the same run. EventModelResponse EventType = "model_response" EventMessageStart EventType = "message_start" EventMessageUpdate EventType = "message_update" EventMessageEnd EventType = "message_end" EventToolExecStart EventType = "tool_exec_start" EventToolExecUpdate EventType = "tool_exec_update" EventToolExecEnd EventType = "tool_exec_end" // EventContextProjected fires before each model call with the identifiable // items exposed by the actual projected AgentMessage context. It is a trace // fact, not a judgment that any item was useful or sufficient. EventContextProjected EventType = "context_projected" // EventContextCompacted fires once after a ContextManager completes a // context compaction transaction and before the compacted view is sent to // the model. Internal compactor stages do not emit separate events. EventContextCompacted EventType = "context_compacted" EventRetry EventType = "retry" EventError EventType = "error" )
type FuncTool ¶
type FuncTool struct {
// contains filtered or unexported fields
}
FuncTool wraps a function as a Tool (convenience helper).
func NewFuncTool ¶
func (*FuncTool) Description ¶
func (*FuncTool) Execute ¶
func (t *FuncTool) Execute(ctx context.Context, args json.RawMessage) (json.RawMessage, error)
type GateDecision ¶
type GateDecision struct {
Allowed bool
Reason string
UpdatedArgs json.RawMessage
}
GateDecision is the gate's verdict for one tool call.
Allowed=true => execute the tool with Call.Args, or with UpdatedArgs when set — the gate's way to return a policy-side rewrite (hook updated_input, interactive data backfill) so the tool executes exactly what was approved. Allowed=false => return Reason as the tool result error; do not execute. UpdatedArgs is ignored on a denial.
A nil decision is treated as Allowed=true (the gate has no opinion).
type GateRequest ¶
type GateRequest struct {
Tool Tool
Call ToolCall
ToolLabel string // resolved via ToolLabeler when available
Preview json.RawMessage // resolved via Previewer when available; may be nil
}
GateRequest carries the inputs that a ToolGate sees for one tool call. Tool exposes the underlying tool instance so gates can typeswitch against any tool-specific marker interfaces they care about (e.g. capability hints) without the kernel needing to know those interfaces.
type ImageData ¶
type ImageData struct {
Data string `json:"data,omitempty"`
URL string `json:"url,omitempty"`
MimeType string `json:"mime_type,omitempty"`
}
ImageData holds image content as base64 data or a URL. When URL is set, providers pass it directly (no download/encoding needed). When Data is set, it is sent as a base64 data URL with MimeType. MimeType is required for base64 mode, optional for URL mode (provider infers it).
type InjectDisposition ¶
type InjectDisposition string
InjectDisposition describes how an injected message was delivered.
const ( InjectSteeredCurrentRun InjectDisposition = "steered_current_run" InjectResumedIdleRun InjectDisposition = "resumed_idle_run" InjectQueued InjectDisposition = "queued" )
type InjectResult ¶
type InjectResult struct {
Disposition InjectDisposition
}
InjectResult reports the delivery outcome of Agent.Inject.
type InterruptBehavior ¶
type InterruptBehavior string
InterruptBehavior controls what happens when a queued user message arrives while a tool is still running.
const ( InterruptBehaviorBlock InterruptBehavior = "block" InterruptBehaviorCancel InterruptBehavior = "cancel" )
type InterruptBehaviorTool ¶
type InterruptBehaviorTool interface {
InterruptBehavior(args json.RawMessage) InterruptBehavior
}
InterruptBehaviorTool is an optional interface for tools that declare whether they should be cancelled or allowed to finish when a steering message arrives. Defaults to InterruptBehaviorBlock when not implemented.
type JSONSchema ¶
type JSONSchema struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Schema any `json:"schema"`
Strict *bool `json:"strict,omitempty"`
}
JSONSchema describes the provider-native JSON schema response format.
type LLMRequest ¶
LLMRequest carries the inputs to a single LLM call.
type LLMResponse ¶
type LLMResponse struct {
Message Message
}
LLMResponse carries the result of a single LLM call.
type LoopConfig ¶
type LoopConfig struct {
Model ChatModel
MaxTurns int // safety limit, default 100
MaxRetries int // LLM call retry limit for retryable errors, default 3
MaxToolErrors int // consecutive tool failure threshold per tool, 0 = unlimited
ThinkingLevel ThinkingLevel // reasoning depth
// BeforeTurn runs before each model call. Messages it returns are committed
// before the request. AfterTurn runs after a normal assistant/tool turn has
// been committed and before the loop decides whether to continue or stop.
BeforeTurn BeforeTurnHook
AfterTurn AfterTurnHook
// Context lifecycle. ContextManager drives prompt projection, overflow
// recovery, and usage reporting. AgentMessage values lower themselves to
// Message only at the model-call boundary.
ContextManager ContextManager
// ToolResultMessageFactory optionally lifts a raw tool result into an
// application-specific message before it enters the transcript. Nil keeps
// the built-in model Message representation. The returned message's model
// projection must preserve the tool role and tool_call_id pairing.
ToolResultMessageFactory func(ToolCall, ToolResult) AgentMessage
// CommitContext replaces the runtime message baseline after an explicit
// committed compaction, a committed projection rewrite, or committed
// overflow recovery.
CommitContext func(msgs []AgentMessage, usage *ContextUsage) error
// CommitMessage durably records a message before it enters runtime context.
// Returning an error stops the run; tools requested by that message are not
// executed. OnMessage remains the post-commit observer hook.
CommitMessage func(msg AgentMessage) error
// ToolGate, when non-nil, is called once per tool call after argument
// validation and the optional Previewer pass. Allowed=false rejects the
// call (Reason becomes the tool result). The kernel does no permission
// reasoning of its own.
ToolGate ToolGate
// Steering: called after each tool execution to check for user interruptions.
GetSteeringMessages func() []AgentMessage
// FollowUp: called when the agent would otherwise stop.
GetFollowUpMessages func() []AgentMessage
// Middlewares are applied around each tool execution (outermost first).
// Use for logging, timing, argument/result modification, etc.
Middlewares []ToolMiddleware
// MaxToolConcurrency limits parallel tool execution.
// 0 or 1 = sequential (default, backward compatible).
// >1 = up to N tools execute concurrently within a single turn.
MaxToolConcurrency int
// ShouldEmitAbortMarker reports whether an abort marker message should be
// emitted when the context is cancelled. When nil or returns false, the
// cancellation is silent (legacy behavior). Set by Agent.Abort().
ShouldEmitAbortMarker func() bool
// StopAfterTool, if non-nil, is called after each successful (non-error)
// tool execution. If it returns true, the loop exits with EndReasonStop.
// Use this to let a terminal tool (e.g. commit_chapter) end the loop
// without wasting turns. The exit passes through StopGuard (with
// Trigger=StopTriggerAfterTool) like any other normal stop, so a guard
// can veto a premature terminal-tool exit.
StopAfterTool func(toolName string) bool
// StopAfterToolResult is the result-aware variant of StopAfterTool. It is
// useful when the same tool can be an intermediate step or a terminal step
// depending on its structured result.
StopAfterToolResult func(toolName string, result json.RawMessage) bool
// OnMessage, if non-nil, is called after each committed message is appended
// to context (assistant, tool result, steering). It is observational; use
// CommitMessage when persistence failure must stop execution.
OnMessage func(msg AgentMessage)
// StopGuard is consulted on every normal stop (end_turn and
// StopAfterTool exits). Nil (default) means every stop is allowed.
StopGuard StopGuard
// LengthRecoveryPrompt overrides the user message injected when the
// model's output is truncated (max_tokens) with no completed tool calls.
// Empty uses a built-in default. Each recovery is an extra LLM call on
// top of normal turn accounting, bounded by an internal cap.
LengthRecoveryPrompt string
// AbortMarkerText overrides the marker message recorded when a run is
// cancelled mid-inference (only when ShouldEmitAbortMarker returns true).
// Empty uses a built-in default. Lets non-English harnesses localize it.
AbortMarkerText string
// AbortMarkerToolText overrides the marker message recorded when
// cancellation lands during tool execution. Empty uses a built-in default.
AbortMarkerToolText string
// CacheLastMessage, when non-empty, instructs the loop to tag the last
// non-system message in every LLM request with this cache_control value
// (e.g. "ephemeral"). Providers that support prompt caching place a write
// breakpoint at that position covering the entire preceding prefix. Empty
// string (default) leaves messages untouched — keep cache placement under
// application control.
//
// The breakpoint follows the freshest turn (user input, tool_result, or
// assistant) and skips trailing per-turn system reminders.
CacheLastMessage string
// PromptCacheKey, when non-empty, is attached to every LLM request as the
// provider's prompt-cache routing identity (e.g. OpenAI prompt_cache_key).
// Use one key per conversation so all requests of a session land on the
// same cache shard. The adapter drops the hint for providers without
// key-routed caching. Empty (default) sends nothing.
PromptCacheKey string
}
LoopConfig configures the agent loop.
type MaxTurnsError ¶
type MaxTurnsError struct {
Limit int
}
MaxTurnsError carries the configured turn limit. errors.Is matches ErrMaxTurns.
func (*MaxTurnsError) Error ¶
func (e *MaxTurnsError) Error() string
func (*MaxTurnsError) Is ¶
func (e *MaxTurnsError) Is(target error) bool
type Message ¶
type Message struct {
Role Role `json:"role"`
Content []ContentBlock `json:"content"`
StopReason StopReason `json:"stop_reason,omitempty"`
Usage *Usage `json:"usage,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
Message is an LLM-level message with structured content blocks.
func AbortMsg ¶
AbortMsg creates an assistant abort marker message. phase is "inference" or "tool_execution".
func CollectMessages ¶
func CollectMessages(msgs []AgentMessage) []Message
CollectMessages extracts concrete model Messages from an AgentMessage slice, dropping application-specific types.
func RepairMessageSequence ¶
RepairMessageSequence ensures tool call / tool result pairs are complete. Orphaned tool calls (no matching result) get a synthetic error result inserted. Orphaned tool results (no matching call) are removed. This prevents LLM providers from rejecting malformed message sequences.
func ToMessages ¶
func ToMessages(messages []AgentMessage) []Message
ToMessages lowers application messages to the model protocol at the LLM call boundary. Messages may opt out, for example when they only exist for persistence or UI display.
func ToolResultMsg ¶
func ToolResultMsg(toolCallID string, content json.RawMessage, isError bool) Message
ToolResultMsg creates a tool result message.
func (Message) GetTimestamp ¶
func (Message) HasToolCalls ¶
HasToolCalls reports whether any tool call blocks exist.
func (Message) Raw ¶
func (m Message) Raw() AgentMessage
func (Message) TextContent ¶
TextContent returns the concatenated text from all text blocks.
func (Message) ThinkingContent ¶
ThinkingContent returns the concatenated thinking text.
type MessageSequenceIssue ¶
type MessageSequenceIssue struct {
Kind MessageSequenceIssueKind
MessageIndex int
AssistantIndex int
ToolCallID string
ToolName string
}
MessageSequenceIssue describes a structural problem in a tool call / tool result transcript. The current validator intentionally stays narrow and focuses on the two invariants the loop already repairs today:
- every tool call should have a following tool result
- every tool result should reference a known tool call
func ValidateMessageSequence ¶
func ValidateMessageSequence(msgs []Message) []MessageSequenceIssue
ValidateMessageSequence reports message-sequence issues that could cause provider rejections or inconsistent replay.
type MessageSequenceIssueKind ¶
type MessageSequenceIssueKind string
const ( MessageSequenceIssueMissingToolResult MessageSequenceIssueKind = "missing_tool_result" MessageSequenceIssueOrphanToolResult MessageSequenceIssueKind = "orphan_tool_result" )
type ModelNamer ¶
type ModelNamer interface {
ModelName() string
}
ModelNamer is an optional interface for ChatModel implementations to expose their model identifier (e.g. "claude-sonnet-4-6"). Harnesses need this for display and telemetry; without it they fall back to concrete-type assertions.
type PartialStreamError ¶
type PartialStreamError struct {
Partial Message
}
PartialStreamError indicates a stream closed without a terminal done event. Partial carries any content received before truncation; callers can inspect it for diagnostics but MUST NOT persist it as a completed message — the stream did not finish cleanly (missing StopReason, possibly truncated tool_call args, unclosed thinking blocks).
func (*PartialStreamError) Error ¶
func (e *PartialStreamError) Error() string
func (*PartialStreamError) Is ¶
func (e *PartialStreamError) Is(target error) bool
type Previewer ¶
type Previewer interface {
Preview(ctx context.Context, args json.RawMessage) (json.RawMessage, error)
}
Previewer is an optional interface for tools that can compute a preview (e.g., diff) before execution. The agent loop calls Preview and emits the result as EventToolExecUpdate so the UI can display it before the tool runs. A preview error is returned to the model and prevents tool execution.
type ProgressPayload ¶
type ProgressPayload struct {
Kind ProgressPayloadKind `json:"kind"`
Agent string `json:"agent,omitempty"`
Tool string `json:"tool,omitempty"`
Summary string `json:"summary,omitempty"`
Delta string `json:"delta,omitempty"`
Thinking string `json:"thinking,omitempty"`
Message string `json:"message,omitempty"`
Turn int `json:"turn,omitempty"`
Attempt int `json:"attempt,omitempty"`
MaxRetries int `json:"max_retries,omitempty"`
IsError bool `json:"is_error,omitempty"`
Args json.RawMessage `json:"args,omitempty"`
Meta json.RawMessage `json:"meta,omitempty"`
// DeltaKind distinguishes what kind of content Delta carries when Kind is
// ProgressToolDelta. Consumers can use this to filter/render text vs
// tool-call argument JSON differently.
DeltaKind DeltaKind `json:"delta_kind,omitempty"`
}
ProgressPayload is the structured progress envelope emitted by tools.
type ProgressPayloadKind ¶
type ProgressPayloadKind string
ProgressPayloadKind distinguishes structured progress update semantics.
const ( ProgressToolStart ProgressPayloadKind = "tool_start" ProgressToolEnd ProgressPayloadKind = "tool_end" ProgressToolDelta ProgressPayloadKind = "tool_delta" ProgressThinking ProgressPayloadKind = "thinking" ProgressSummary ProgressPayloadKind = "summary" ProgressToolError ProgressPayloadKind = "tool_error" ProgressTurnCounter ProgressPayloadKind = "turn_counter" ProgressRetry ProgressPayloadKind = "retry" ProgressContext ProgressPayloadKind = "context" )
type ProviderNamer ¶
type ProviderNamer interface {
ProviderName() string
}
ProviderNamer is an optional interface for ChatModel implementations to expose their provider name (e.g. "openai", "anthropic", "gemini"). Used by the agent loop to pass provider context to GetApiKey callbacks.
type ReadOnlyTool ¶
type ReadOnlyTool interface {
ReadOnly(args json.RawMessage) bool
}
ReadOnlyTool is an optional interface for tools that declare read-only behavior. Read-only tools are eligible for concurrent execution by default. The args parameter allows input-dependent classification (e.g., bash is read-only for "ls" but not for "rm").
type ResponseFormat ¶
type ResponseFormat struct {
Type string `json:"type"`
JSONSchema *JSONSchema `json:"json_schema,omitempty"`
}
ResponseFormat controls provider-native structured output.
JSON object mode asks the model to return valid JSON. JSON schema mode asks compatible providers to constrain the final response to the supplied schema. Callers should still unmarshal and validate model output like any external input.
type RetryHinter ¶
RetryHinter when implemented, supplies a provider-specified backoff hint (e.g. a Retry-After header). The loop honors it for the next retry delay, capped at its own maximum. A zero duration means "no hint, use backoff".
type RetryableError ¶
type RetryableError interface {
Retryable() bool
}
RetryableError when implemented by an error in the chain, tells the loop whether re-issuing the identical request may succeed. Model adapters implement it so the kernel decides same-provider retries without importing any LLM SDK. Errors that do not implement it are treated as non-retryable (the loop still has its own message-pattern classification as a fallback).
type RunSummary ¶
RunSummary captures loop facts that are known at the end of a run. It intentionally excludes higher-level policy judgments.
type StopDecision ¶
type StopDecision struct {
// Allow=true lets the stop proceed; Allow=false keeps the loop alive.
Allow bool
// InjectMessage is delivered as a user message on the next turn when
// Allow=false && !Escalate. Empty InjectMessage with Allow=false is
// treated as Allow=true (safe default — never stall silently).
InjectMessage string
// Escalate=true ends the run immediately with an error.
Escalate bool
}
StopDecision is the guard's verdict.
type StopGuard ¶
type StopGuard func(ctx context.Context, stop StopInfo) StopDecision
StopGuard is the single arbiter for every normal stop of a run. It is consulted on both stop paths:
- StopTriggerEndTurn: the LLM produced a final text response with no tool calls and no queued follow-up messages.
- StopTriggerAfterTool: a StopAfterTool / StopAfterToolResult hook requested an early exit after a successful terminal tool.
Error paths never consult the guard: context cancellation (Abort), StopReasonError/StopReasonAborted from the provider, and the MaxTurns safety valve all terminate directly — a guard must not be able to override user aborts or safety limits.
Return Allow=true to let the agent stop normally. Return Allow=false with an InjectMessage to keep the agent running for another turn — the message is delivered as a user message on the next LLM call. Set Escalate=true to force the run to end with a guard-escalation error (used when the guard has repeatedly blocked stops and suspects a prompt bug).
Guard state (e.g. consecutive-block counters) is the guard's own responsibility; agentgo passes only the current turn index, the stopping assistant message, and which path triggered the check.
type StopInfo ¶
type StopInfo struct {
// TurnIndex is the index of the turn that just produced the stopping message.
TurnIndex int
// Message is the assistant message whose StopReason triggered this check.
Message Message
// Trigger reports which stop path is consulting the guard.
Trigger StopTrigger
}
StopInfo carries the information a StopGuard needs to decide.
type StopReason ¶
type StopReason string
StopReason indicates why the LLM stopped generating.
const ( StopReasonStop StopReason = "stop" StopReasonLength StopReason = "length" StopReasonToolUse StopReason = "toolUse" StopReasonError StopReason = "error" StopReasonSafety StopReason = "safety" StopReasonAborted StopReason = "aborted" )
type StopTrigger ¶
type StopTrigger string
StopTrigger identifies which stop path is consulting the guard.
const ( // StopTriggerEndTurn is the natural stop: final assistant response, // no tool calls, no queued follow-ups. StopTriggerEndTurn StopTrigger = "end_turn" // StopTriggerAfterTool is an early exit requested by the harness via // StopAfterTool / StopAfterToolResult. StopTriggerAfterTool StopTrigger = "stop_after_tool" )
type StreamEvent ¶
type StreamEvent struct {
Type StreamEventType
ContentIndex int // which content block is being updated
Delta string // text/thinking/toolcall argument delta
Message Message // partial (during streaming) or final (done)
// CompletedToolCall is populated on StreamEventToolCallEnd with the fully
// reconstructed tool call. It lets the loop start execution immediately
// without re-parsing the partial assistant message.
CompletedToolCall *ToolCall
StopReason StopReason // finish reason (for done events)
Err error // for error events
}
StreamEvent is a streaming event from the LLM.
type StreamEventType ¶
type StreamEventType string
StreamEventType identifies LLM streaming event types.
const ( // Text content streaming StreamEventTextStart StreamEventType = "text_start" StreamEventTextDelta StreamEventType = "text_delta" StreamEventTextEnd StreamEventType = "text_end" // Thinking/reasoning streaming StreamEventThinkingStart StreamEventType = "thinking_start" StreamEventThinkingDelta StreamEventType = "thinking_delta" StreamEventThinkingEnd StreamEventType = "thinking_end" // Tool call streaming StreamEventToolCallStart StreamEventType = "toolcall_start" StreamEventToolCallDelta StreamEventType = "toolcall_delta" StreamEventToolCallEnd StreamEventType = "toolcall_end" // Terminal events StreamEventDone StreamEventType = "done" StreamEventError StreamEventType = "error" )
type StrictSchemaTool ¶
type StrictSchemaTool interface {
StrictSchema() bool
}
StrictSchemaTool is an optional interface for tools that want provider-side strict schema enforcement on their arguments (e.g. OpenAI's strict tool calling). Returning true forwards `strict: true` and triggers schema normalisation in compatible providers; returning false explicitly disables strict on providers that default to it (e.g. OpenAI Responses API).
Provider adapters own strict-schema normalization and validation because the supported subset differs by provider. Tool authors should consult the adapter documentation for provider-specific restrictions.
type SwappableModel ¶
type SwappableModel struct {
// contains filtered or unexported fields
}
SwappableModel wraps a ChatModel and allows replacing the underlying model at runtime. Swaps take effect on the next call.
func NewSwappableModel ¶
func NewSwappableModel(initial ChatModel) *SwappableModel
func (*SwappableModel) Current ¶
func (m *SwappableModel) Current() ChatModel
func (*SwappableModel) Generate ¶
func (m *SwappableModel) Generate(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (*LLMResponse, error)
func (*SwappableModel) GenerateStream ¶
func (m *SwappableModel) GenerateStream(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (<-chan StreamEvent, error)
func (*SwappableModel) ModelName ¶
func (m *SwappableModel) ModelName() string
func (*SwappableModel) ProviderName ¶
func (m *SwappableModel) ProviderName() string
func (*SwappableModel) SupportsTools ¶
func (m *SwappableModel) SupportsTools() bool
func (*SwappableModel) Swap ¶
func (m *SwappableModel) Swap(next ChatModel)
type SystemBlock ¶
type SystemBlock struct {
Text string `json:"text"`
CacheControl string `json:"cache_control,omitempty"` // e.g. "ephemeral"
}
SystemBlock is one segment of a multi-part system prompt. Use with AgentContext.SystemBlocks for per-block cache control.
type ThinkingLevel ¶
type ThinkingLevel string
ThinkingLevel configures the reasoning depth for models that support it.
const ( // ThinkingAuto leaves thinking/reasoning behavior to the provider/model default. ThinkingAuto ThinkingLevel = "" ThinkingOff ThinkingLevel = "off" ThinkingMinimal ThinkingLevel = "minimal" ThinkingLow ThinkingLevel = "low" ThinkingMedium ThinkingLevel = "medium" ThinkingHigh ThinkingLevel = "high" ThinkingXHigh ThinkingLevel = "xhigh" ThinkingMax ThinkingLevel = "max" )
func NormalizeThinkingLevel ¶
func NormalizeThinkingLevel(level ThinkingLevel) ThinkingLevel
NormalizeThinkingLevel returns the canonical level used internally. Empty and "auto" both mean "do not send a thinking override".
type Tool ¶
type Tool interface {
Name() string
Description() string
Schema() map[string]any
Execute(ctx context.Context, args json.RawMessage) (json.RawMessage, error)
}
Tool defines the minimal tool interface. Timeout control goes through context.Context. Tools can report execution progress via ReportToolProgress(ctx, payload).
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
Name string `json:"name"`
Args json.RawMessage `json:"args"`
ArgsInvalid bool `json:"args_invalid,omitempty"`
ArgsRawText string `json:"args_raw_text,omitempty"`
ArgsParseError string `json:"args_parse_error,omitempty"`
// ThoughtSignature is an opaque provider reasoning signature (Gemini 3) that
// must be persisted and replayed verbatim across turns. Empty when absent.
ThoughtSignature string `json:"thought_signature,omitempty"`
}
ToolCall represents a tool invocation request from the LLM.
When the LLM emits args that don't parse as JSON (common cause: stream truncation, provider format bug), Args is replaced with "{}" so the surrounding Message stays JSON-serializable for persistence; the original payload and parser diagnostic are preserved in ArgsRawText / ArgsParseError. Downstream schema validation short-circuits on ArgsInvalid and surfaces the captured raw text — pointing at the real root cause instead of running "missing field" checks against the {} placeholder.
type ToolExecUpdateKind ¶
type ToolExecUpdateKind string
ToolExecUpdateKind distinguishes update payload semantics for tool_exec_update events.
const ( ToolExecUpdatePreview ToolExecUpdateKind = "preview" ToolExecUpdateProgress ToolExecUpdateKind = "progress" )
type ToolExecuteFunc ¶
type ToolExecuteFunc func(ctx context.Context, args json.RawMessage) (json.RawMessage, error)
ToolExecuteFunc is the function signature for tool execution. Used as the "next" parameter in middleware chains.
type ToolGate ¶
type ToolGate func(ctx context.Context, req GateRequest) (*GateDecision, error)
ToolGate is the pluggable hook called once per tool call, after argument validation and after the optional Previewer pass, but before tool execution. Returning a non-nil error is treated as deny with the error message as the reason. The kernel does not perform any permission reasoning of its own; install a gate (or leave it nil) to control policy.
type ToolLabeler ¶
type ToolLabeler interface {
Label() string
}
ToolLabeler is an optional interface for tools to provide a human-readable label.
type ToolMiddleware ¶
type ToolMiddleware func(ctx context.Context, call ToolCall, next ToolExecuteFunc) (json.RawMessage, error)
ToolMiddleware wraps tool execution with cross-cutting concerns. Call next to continue the chain; skip next to short-circuit execution. Example: logging, timing, argument/result modification, audit.
type ToolProgressFunc ¶
type ToolProgressFunc func(progress ProgressPayload)
ToolProgressFunc is a callback for reporting tool execution progress. Tools call ReportToolProgress to emit partial results during long operations.
type ToolResult ¶
type ToolResult struct {
ToolCallID string `json:"tool_call_id"`
ToolName string `json:"-"` // internal: for toolErrors tracking
Content json.RawMessage `json:"content,omitempty"`
ContentBlocks []ContentBlock `json:"-"` // rich content (images); not serialized
IsError bool `json:"is_error,omitempty"`
Details any `json:"details,omitempty"` // optional metadata for UI display/logging
}
ToolResult represents a tool execution outcome.
type ToolSpec ¶
type ToolSpec struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters any `json:"parameters"`
DeferLoading bool `json:"defer_loading,omitempty"`
// Strict enables provider-side strict schema enforcement (OpenAI strict
// tool calling / Structured Outputs for arguments). nil leaves the
// provider default. Set via the optional StrictSchemaTool interface.
Strict *bool `json:"strict,omitempty"`
}
ToolSpec describes a tool for the LLM (name + description + JSON schema).
type ToolValidationError ¶
type ToolValidationError struct {
ToolName string
Issues []ValidationIssue
}
ToolValidationError is returned when tool call arguments fail schema validation. The agent loop surfaces it as a tool_result with IsError=true, not as a fatal loop error, so the model can self-correct on the next turn. errors.Is matches ErrToolValidation.
func (*ToolValidationError) Error ¶
func (e *ToolValidationError) Error() string
func (*ToolValidationError) Is ¶
func (e *ToolValidationError) Is(target error) bool
type Usage ¶
type Usage struct {
Provider string `json:"provider,omitempty"`
Model string `json:"model,omitempty"`
Input int `json:"input"`
Output int `json:"output"`
CacheRead int `json:"cache_read"`
CacheWrite int `json:"cache_write"`
TotalTokens int `json:"total_tokens"`
Cost *Cost `json:"cost,omitempty"`
}
Usage tracks token consumption for a single LLM call.
Field semantics:
- Input: prompt tokens sent to the model (includes cached tokens for some providers)
- Output: completion tokens generated (includes reasoning tokens if applicable)
- CacheRead: tokens served from prompt cache (Anthropic: cache_read_input_tokens)
- CacheWrite: tokens written to prompt cache (Anthropic: cache_creation_input_tokens)
- TotalTokens: provider-reported total, typically Input + Output
- Provider/Model: actual provider/model that produced this call, if reported
- Cost: monetary cost computed from model pricing (nil if pricing unavailable)
type ValidationIssue ¶
type ValidationIssue struct {
Kind string
Path string
Expected string
Received string
Hint string // optional fix hint, appended to the rendered message
}
ValidationIssue describes a single schema mismatch from tool arg validation.
type ValidationResult ¶
ValidationResult is the verdict from a Validator.
A failure (OK=false) is surfaced to the LLM as a normal tool_result with IsError=true. The intent is "input is structurally legal but semantically wrong" — e.g. write before read, mtime drift, deny rule. The LLM reads Message and self-corrects (typically by issuing the right tool first and retrying), without prompting the user.
ErrorCode is optional, intended for stable identification by tests and prompts; it is not interpreted by the kernel.
type Validator ¶
type Validator interface {
Validate(ctx context.Context, args json.RawMessage) ValidationResult
}
Validator is an optional interface for tools that want to short-circuit before Preview / ToolGate / Execute when the input is structurally legal but semantically wrong. Validators MUST NOT prompt the user, MUST NOT mutate persistent state, and SHOULD be cheap (read-only lookups, stat).
Returning OK=false produces a tool_result the LLM can act on; returning OK=true continues the normal pipeline.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package context provides message-native context compression for agentgo: prompt projection, summary checkpoints, overflow recovery, and usage estimation.
|
Package context provides message-native context compression for agentgo: prompt projection, summary checkpoints, overflow recovery, and usage estimation. |
|
examples
|
|
|
multi
command
|
|
|
single
command
|
|
|
Package llm adapts LLM providers to the agentgo.ChatModel interface.
|
Package llm adapts LLM providers to the agentgo.ChatModel interface. |
|
Package permission is an optional policy engine for gating tool execution.
|
Package permission is an optional policy engine for gating tool execution. |
|
Package proxy provides a ChatModel adapter that forwards LLM calls to a remote proxy server.
|
Package proxy provides a ChatModel adapter that forwards LLM calls to a remote proxy server. |
|
Package schema provides a fluent builder for JSON Schema objects.
|
Package schema provides a fluent builder for JSON Schema objects. |
|
Package subagent runs specialized agents with isolated contexts.
|
Package subagent runs specialized agents with isolated contexts. |
|
Package task is a unified registry for background tasks.
|
Package task is a unified registry for background tasks. |
|
Package team implements Team — multi-agent peer-to-peer collaboration on top of the Subagent foundation.
|
Package team implements Team — multi-agent peer-to-peer collaboration on top of the Subagent foundation. |
|
Package tools provides the built-in agent tools — read, write, edit, and bash.
|
Package tools provides the built-in agent tools — read, write, edit, and bash. |