Documentation
¶
Index ¶
- Constants
- Variables
- func AttachImage(ctx context.Context, img ImageBlock)
- func GetState[T any](s *Session, key string) (T, error)
- func JSONResult(v any) (string, error)
- func NewTypedTool[Input any](name, description string, schema InputSchema, ...) (Tool, ToolFunc)
- func RenderForSummary(msgs []Message, maxToolBytes int) string
- func Save(ctx context.Context, store Store, s *Session) error
- func SessionExists(id string) error
- func SessionNotFound(id string) error
- func SetState[T any](s *Session, key string, val T) error
- func TextContent(msg Message) string
- func WithImageSink(parent context.Context) (context.Context, func() []ImageBlock)
- type APIError
- type Agent
- type CacheControl
- type Client
- func (c *Client) Ask(ctx context.Context, system string, history []Message) (Message, Usage, error)
- func (c *Client) AskStream(ctx context.Context, system string, history []Message, ...) (Message, Usage, error)
- func (c *Client) Loop(ctx context.Context, system string, history []Message, tools Toolset, ...) (LoopResult, error)
- func (c *Client) LoopStream(ctx context.Context, system string, history []Message, tools Toolset, ...) (LoopResult, error)
- func (c *Client) WithModel(model string) *Client
- func (c *Client) WithRecorder(rec Recorder) *Client
- type Config
- type ContentBlock
- type ContextManager
- type Event
- type EventType
- type ExtractParams
- type Hooks
- type ImageBlock
- type InputSchema
- type JSONLRecorder
- type Logger
- type LoopError
- type LoopResult
- type MemoryRecorder
- type Message
- type Middleware
- type MultiRecorder
- type Option
- type Property
- func Array(name, description string, items SchemaProperty, opts ...Option) Property
- func Boolean(name, description string, opts ...Option) Property
- func Integer(name, description string, opts ...Option) Property
- func Number(name, description string, opts ...Option) Property
- func String(name, description string, opts ...Option) Property
- type Provider
- type ProviderRequest
- type ProviderResponse
- type ProviderTool
- type Recorder
- type Result
- type RetryConfig
- type RetryExhaustedError
- type SchemaProperty
- type Session
- type StepFunc
- type Store
- type StreamBuffer
- type Tool
- type ToolBinding
- type ToolError
- type ToolFunc
- type ToolMetadata
- type ToolResult
- type ToolUse
- type Toolset
- type Usage
Constants ¶
const ( ModelOpus = "claude-opus-4-7" ModelSonnet = "claude-sonnet-4-6" ModelHaiku = "claude-haiku-4-5-20251001" )
Well-known Anthropic model identifiers.
const ( RoleUser = "user" RoleAssistant = "assistant" )
Role constants for Message.
const ( TypeText = "text" TypeToolUse = "tool_use" TypeToolResult = "tool_result" TypeImage = "image" )
Type constants for ContentBlock.
Variables ¶
var ( // ErrMaxIter is wrapped in a LoopError when Loop exhausts its iteration budget. ErrMaxIter = errors.New("gocode: loop exceeded maxIter") // ErrMissingTool is wrapped in a ToolError when the model calls a tool // that is not present in the dispatch map. ErrMissingTool = errors.New("gocode: model called unknown tool") // ErrRetryExhausted is wrapped in a RetryExhaustedError when all retry // attempts have been consumed without a successful response. ErrRetryExhausted = errors.New("gocode: retry exhausted") )
Sentinel errors for use with errors.Is.
var ( // ErrSessionNotFound is returned by Get, Update, and Delete when no // session with the requested ID exists. ErrSessionNotFound = errors.New("gocode: session not found") // ErrSessionExists is returned by Create when a session with the given // ID already exists. ErrSessionExists = errors.New("gocode: session already exists") )
Sentinel errors for Store operations.
Functions ¶
func AttachImage ¶ added in v0.1.2
func AttachImage(ctx context.Context, img ImageBlock)
AttachImage attaches an image to the current tool call's result. It is the mechanism by which a ToolFunc — whose return type is just a string — can ride image bytes back to the model alongside its textual output.
Pass a base64 data URI ("data:image/png;base64,...") for portability; remote http URLs are accepted but not all backends will fetch them.
AttachImage is a no-op when called outside the agent loop (e.g. in a unit test that invokes a ToolFunc directly with a vanilla context).
func GetState ¶
GetState unmarshals the JSON value stored under key in s.State into a value of type T. Returns an error if the key is absent or the value cannot be decoded into T.
func JSONResult ¶
JSONResult marshals v to a JSON string. It is the recommended helper for typed tool handlers that want to return structured data the model can reliably parse. Marshal errors are wrapped with context.
func NewTypedTool ¶
func NewTypedTool[Input any]( name, description string, schema InputSchema, f func(context.Context, Input) (string, error), ) (Tool, ToolFunc)
NewTypedTool combines NewTool + TypedToolFunc into a single call that returns both the Tool (for your tools []Tool slice) and the wrapped ToolFunc (for your dispatch map). This is the most ergonomic path shown in the roadmap while still letting you inspect everything.
Panics if schema cannot be marshalled to JSON; in practice InputSchema always marshals successfully, so this is a programmer-error indicator.
func RenderForSummary ¶
RenderForSummary flattens a slice of messages into a plain-text transcript suitable for passing to a summarizer model. Each message is rendered as labeled lines (USER, ASSISTANT, ASSISTANT_TOOL_USE, TOOL_RESULT) that preserve the structure without paying the full token cost of large tool outputs: tool_use inputs and tool_result contents are abbreviated to maxToolBytes characters with a "...[truncated]" marker. Pass 0 for maxToolBytes to use the default of 400.
This is the rendering most ContextManager.Summarizer implementations want. If you need different formatting (different abbreviation thresholds, JSON output, redaction), write your own — the message structures are public.
func Save ¶
Save updates s if it already exists, or creates it if not. It is a convenience wrapper for callers that do not need to distinguish between first use and subsequent calls.
func SessionExists ¶
SessionExists returns an error that wraps ErrSessionExists with the offending ID, the create-side counterpart to SessionNotFound.
func SessionNotFound ¶
SessionNotFound returns an error that wraps ErrSessionNotFound with the offending ID. Store implementations use this to produce errors that match errors.Is(err, ErrSessionNotFound) while still naming the missing ID.
func TextContent ¶
TextContent extracts and concatenates all text blocks from a message.
func WithImageSink ¶ added in v0.1.2
func WithImageSink(parent context.Context) (context.Context, func() []ImageBlock)
WithImageSink installs a fresh image sink on parent and returns the derived context plus a drain function that yields (and clears) any images attached during the call. This is a testing aid: image-emitting ToolFuncs can be exercised without standing up a full Loop. The agent loop installs an equivalent sink implicitly per tool dispatch.
Types ¶
type APIError ¶
type APIError struct {
StatusCode int
Type string
Message string
// RetryAfter, when non-zero, carries the duration requested by the API via
// a Retry-After header (e.g. on a 429 Too Many Requests response).
RetryAfter time.Duration
}
APIError is returned when the LLM API responds with a non-2xx status.
type Agent ¶
type Agent struct {
// Client is the LLM client used for all model calls. Required.
Client *Client
// System is the system prompt passed to every model call.
System string
// Tools is the set of tools advertised to the model and dispatched when
// called. A zero-value Toolset means no tools are offered.
Tools Toolset
// Context trims history before the first model call and again before each
// subsequent model call inside the loop. A zero-value ContextManager
// (MaxTokens == 0) disables trimming entirely.
Context ContextManager
// MaxIter caps the number of model calls per Step. Zero means no limit.
MaxIter int
// Hooks contains optional observer callbacks. A zero-value Hooks is safe.
Hooks Hooks
}
Agent is an assembled primitive: a Client, system prompt, Toolset, ContextManager, and optional Hooks wired together into a single Step call. It is the practical assembly point for a tool-using agent — for one-shot autonomous tasks pass a single user message containing the goal; for multi-turn conversations call Step once per human turn.
Step trims history before the loop and again before every model call inside the loop (when ContextManager.MaxTokens > 0), so long autonomous runs do not blow the context window. Tool-use / tool-result integrity is preserved by ContextManager.Trim.
A zero-value Agent is not valid — Client must be set. All other fields have safe zero values (no tools, no context trimming, no iteration limit, no hooks).
Usage:
a := gocode.Agent{
Client: client,
System: "You are a helpful assistant.",
Tools: myToolset,
Context: gocode.ContextManager{MaxTokens: 8000, KeepRecent: 20},
MaxIter: 10,
}
// One-shot task: pass a single user message with the goal.
result, err := a.Step(ctx, []gocode.Message{gocode.NewUserMessage("do the thing")})
fmt.Println(result.FinalText())
// Multi-turn: call Step once per human turn, threading history.
history := []gocode.Message{gocode.NewUserMessage("first question")}
result, err = a.Step(ctx, history)
history = result.Messages
func (Agent) Step ¶
Step runs one user request through the agent loop. history is the conversation so far; it is not modified. The returned LoopResult contains the full updated conversation (trimmed history + new turns) and aggregate token usage for this step.
Step trims history once up front (so OnStep sees the iter-0 history) and then again before every model call inside the loop when a ContextManager is configured. The primitives Loop and ContextManager.Trim remain available for callers who want a different policy.
func (Agent) StepStream ¶
func (a Agent) StepStream( ctx context.Context, history []Message, onToken func(ContentBlock), onToolResult func([]ToolResult), ) (LoopResult, error)
StepStream is the streaming variant of Step. It delivers token deltas via onToken and tool results via onToolResult as they arrive. Both callbacks may be nil.
Retry interaction: onToken may fire for partial content on a failed attempt before a successful retry. Wire a StreamBuffer via RetryConfig.OnRetry to reset partial output between attempts.
type CacheControl ¶
type CacheControl struct {
Type string `json:"type"` // always "ephemeral"
TTL string `json:"ttl,omitempty"` // "" (default 5m) or "1h"
}
CacheControl marks a content block, tool definition, or system prompt as a cache breakpoint. The semantics are Anthropic's: caching is cumulative — a marker on, say, the last tool definition caches the system prompt and every preceding tool. Up to 4 markers per request.
Providers translate this marker as appropriate:
- AnthropicProvider emits native cache_control blocks.
- OpenRouterProvider serializes content as a typed-parts array with cache_control fields; works for Anthropic-backed routes.
- OpenAIProvider and OpenAIResponsesProvider ignore the marker — OpenAI caches automatically for prefixes ≥1024 tokens.
Set TTL to "1h" for the extended (more expensive write, longer-lived) tier; leave empty for the default 5-minute window.
func Ephemeral ¶
func Ephemeral() *CacheControl
Ephemeral returns the standard 5-minute cache marker. It is a thin constructor that documents intent at call sites.
func EphemeralExtended ¶
func EphemeralExtended() *CacheControl
EphemeralExtended returns a 1-hour cache marker. Cache writes cost more at this tier but reads remain cheap, so it pays off for prompts reused across long sessions or many users.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a stateless API facade. It holds configuration but no conversation state — history is owned by the caller. The same Client is safe for concurrent use across goroutines.
func New ¶
New creates a Client from cfg, filling in defaults for zero-value fields. Returns an error if Provider or Model is empty.
func (*Client) Ask ¶
Ask makes a single LLM call and returns the model's reply along with token usage for the call.
system sets the system prompt; pass "" to omit it. history is the conversation so far and is not modified by Ask. Append the returned Message to your history slice to continue the conversation.
Token usage is reported separately so callers can aggregate cost across multiple Ask calls without paying for a Loop. Pre-1.0 note: Ask previously returned (Message, error); the Usage return was added so cost-conscious callers don't have to fall back to Loop with an empty toolset.
func (*Client) AskStream ¶
func (c *Client) AskStream(ctx context.Context, system string, history []Message, onToken func(ContentBlock)) (Message, Usage, error)
AskStream is the streaming variant of Ask. It invokes the onToken callback for every ContentBlock delta delivered by the provider (typically incremental TypeText blocks). The final assembled Message is returned once the stream completes. history is not modified by this call.
Retry interaction: callWithRetry wraps the stream call, so onToken may fire for partial content on a failed attempt before a successful retry begins. Use StreamBuffer with RetryConfig.OnRetry to react to retries and clear partial output before the next attempt starts.
onToken may be nil, in which case token deltas are discarded.
Pre-1.0 note: AskStream previously returned (Message, error); Usage was added so streaming callers don't have to drop down to Loop for cost tracking.
func (*Client) Loop ¶
func (c *Client) Loop( ctx context.Context, system string, history []Message, tools Toolset, maxIter int, ) (LoopResult, error)
Loop runs the agent in a tool-use loop until the model signals end_turn or an error occurs. It returns the full conversation including all new turns.
tools is the Toolset advertised to the model on every call. A tool name that appears in a model response but is absent from the toolset's dispatch map causes an immediate LoopError wrapping ErrMissingTool. maxIter caps the total number of API calls; 0 means no limit.
The Toolset is read once: its Tools() and Dispatch() are computed at the start of the loop. Mutating the underlying Bindings during the loop has no effect on iterations already in flight.
func (*Client) LoopStream ¶
func (c *Client) LoopStream( ctx context.Context, system string, history []Message, tools Toolset, maxIter int, onToken func(ContentBlock), onToolResult func([]ToolResult), ) (LoopResult, error)
LoopStream is the streaming variant of Loop. It mirrors Loop's structure, control flow, error handling, stop-reason switching, maxIter limiting, and history/usage accumulation but invokes Provider.Stream (wrapped by callWithRetry) on every iteration so that onToken receives each ContentBlock delta as it arrives. After runTools completes, onToolResult is called with the results (allowing live UI updates or logging) before the tool results are appended and the loop continues.
Retry interaction: onToken may fire multiple times for a given turn if retries occur. Use StreamBuffer with RetryConfig.OnRetry to react to retries and clear partial output before the next attempt starts.
Both callbacks may be nil, in which case their respective events are discarded.
func (*Client) WithModel ¶
WithModel returns a new Client that shares the provider, MaxTokens, and Retry config with c, but uses a different model. Useful for cost-tiering — a cheap summarizer alongside a smart loop, for example. The returned Client is independent: mutations to one do not affect the other.
For more elaborate derivation (different MaxTokens, different Retry), construct a fresh Client with gocode.New.
func (*Client) WithRecorder ¶
WithRecorder returns a new Client that shares the rest of c's config but replaces the Recorder. Pass nil to disable recording on the derived Client. The returned Client is independent of c.
type Config ¶
type Config struct {
Provider Provider // required — the LLM backend to use
Model string // required — provider-specific model identifier
MaxTokens int // max tokens per response; defaults to 1024
Retry RetryConfig // controls automatic retry behaviour for transient API errors
// Recorder, if non-nil, receives Events as Loop / LoopStream runs:
// turn start/end, model request/response, retry attempts, and tool
// call start/end. See recorder.go for event semantics. Recording is
// best-effort and must not block the loop; implementations should be
// fast and non-blocking. Ask and AskStream do not emit events.
Recorder Recorder
// SystemCache, when set, marks the system prompt as a cache breakpoint
// on every API call this Client makes via Ask, AskStream, Loop, and
// LoopStream. The most useful single cache placement when the system
// text is long and stable across turns.
SystemCache *CacheControl
}
Config holds everything needed to create a Client.
type ContentBlock ¶
type ContentBlock struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Input json.RawMessage `json:"input,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
Content string `json:"content,omitempty"`
IsError bool `json:"is_error,omitempty"`
// Image fields. Populated when Type=="image". Source is either a
// base64 data URI ("data:image/png;base64,...") or an http(s) URL;
// MediaType is the IANA media type ("image/png", "image/jpeg", ...).
// Caller is responsible for pre-encoding bytes; gocode does not
// downsample or re-encode.
Source string `json:"source,omitempty"`
MediaType string `json:"media_type,omitempty"`
// CacheControl, if set, marks this block as a cache breakpoint. Caching
// is cumulative — see the CacheControl docs. Currently honored by
// AnthropicProvider and OpenRouterProvider; ignored by other providers.
CacheControl *CacheControl `json:"cache_control,omitempty"`
// Raw, if non-empty, is the verbatim JSON for this block. Set by
// UnmarshalJSON for unknown (provider-specific) types so they can be
// resent on the next request without loss. When set, MarshalJSON emits
// Raw and ignores all other fields.
Raw json.RawMessage `json:"-"`
}
ContentBlock is one element in a message's content array. Each block has a Type that determines which other fields are populated:
- "text": Text is the response string
- "tool_use": ID, Name, and Input carry the model's tool call
- "tool_result": ToolUseID and Content carry the tool's return value
Provider-specific block types (e.g. Anthropic's "server_tool_use" or "web_search_tool_result", emitted when category-1 provider tools run) are preserved opaquely in Raw and round-trip verbatim. The agent loop ignores them — only Type=="tool_use" is dispatched locally.
func (ContentBlock) MarshalJSON ¶
func (b ContentBlock) MarshalJSON() ([]byte, error)
MarshalJSON emits Raw verbatim if set; otherwise emits the standard fields.
func (*ContentBlock) UnmarshalJSON ¶
func (b *ContentBlock) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes known block types into typed fields. For unknown types it captures the entire JSON object into Raw so the block can be re-sent verbatim on subsequent requests (Anthropic requires server-tool result blocks to round-trip exactly).
type ContextManager ¶
type ContextManager struct {
// MaxTokens is the token budget. Trim returns history unchanged if it
// fits within this budget. Zero disables trimming entirely.
MaxTokens int
// KeepFirst is the number of messages to always retain from the start of
// history regardless of token budget — useful for preserving an initial
// instruction or persistent context. The actual number kept may be larger
// when preserving tool-use/tool-result integrity requires it.
KeepFirst int
// KeepRecent is the number of messages to always retain from the end of
// history. The actual number kept may be larger when integrity requires
// including the full tool cycle that contains the boundary message.
KeepRecent int
// TokenCounter estimates the token count of a message slice. If nil, a
// character-based heuristic (4 chars ≈ 1 token) is used. Provide a
// model-specific counter for accurate budget enforcement.
TokenCounter func([]Message) (int, error)
// Summarizer condenses trimmed messages into a single string. When set,
// the trimmed portion is replaced by a user message containing that string.
// When nil, trimmed messages are dropped without replacement.
//
// The summarizer typically calls the LLM. That call is caller-owned and
// visible: no hidden model calls occur inside Trim.
Summarizer func(ctx context.Context, trimmed []Message) (string, error)
}
ContextManager trims conversation history to keep it within a token budget. A zero-value ContextManager is a no-op: MaxTokens == 0 disables trimming.
Typical usage:
cm := gocode.ContextManager{
MaxTokens: 8000,
KeepFirst: 1, // always keep the initial user message
KeepRecent: 10, // always keep the last 10 messages
}
trimmed, err := cm.Trim(ctx, history)
result, err := client.Loop(ctx, system, trimmed, tools, 10)
func (ContextManager) Trim ¶
Trim returns a copy of history that fits within MaxTokens. The original slice is never modified. If MaxTokens is zero or history is already within budget, history is returned as-is.
Trimming always preserves tool-use/tool-result integrity: an assistant message that contains tool_use blocks and the user message that carries the corresponding tool_results are always kept or dropped as a unit — the model must never see one without the other.
If KeepFirst > 0, the first KeepFirst messages are pinned. If KeepRecent > 0, the last KeepRecent messages are pinned. Both boundaries are expanded as needed to land on a clean cut point. Everything between the two pinned regions is the trim zone.
If Summarizer is set, the trim zone is passed to it and the returned string becomes a single user message inserted in place of the trimmed content. Otherwise the trim zone is dropped entirely.
Trim does not iterate: it removes the trim zone in one pass. If the result is still over budget (because KeepFirst + KeepRecent alone exceeds MaxTokens), the history is returned as trimmed without error — the caller will encounter a max_tokens API error and can decide how to respond.
type Event ¶
type Event struct {
Seq int64 `json:"seq"`
TurnID string `json:"turn_id"`
Iter int `json:"iter"`
Type EventType `json:"type"`
Time time.Time `json:"time"`
History []Message `json:"history,omitempty"` // TurnStart
Message *Message `json:"message,omitempty"` // ModelResponse
Usage *Usage `json:"usage,omitempty"` // ModelResponse, TurnEnd
StopReason string `json:"stop_reason,omitempty"` // ModelResponse
ToolUseID string `json:"tool_use_id,omitempty"` // ToolCallStart, ToolCallEnd
ToolName string `json:"tool_name,omitempty"` // ToolCallStart, ToolCallEnd
ToolInput json.RawMessage `json:"tool_input,omitempty"` // ToolCallStart
ToolOutput string `json:"tool_output,omitempty"` // ToolCallEnd
ToolError string `json:"tool_error,omitempty"` // ToolCallEnd (when IsError)
IsError bool `json:"is_error,omitempty"` // ToolCallEnd
Attempt int `json:"attempt,omitempty"` // RetryAttempt
Wait time.Duration `json:"wait,omitempty"` // RetryAttempt
Err string `json:"err,omitempty"` // TurnError
}
Event is one record in a turn's activity log. Fields are populated based on Type — see EventType constants for which fields are set when. Event is designed to be JSON-friendly so a Recorder can serialize it directly.
Seq is assigned by the Recorder when Record is called and is monotonic per Recorder. TurnID is stable for all events in a single Loop / LoopStream invocation so events from concurrent turns can be separated. Iter is the 0-based iteration within the turn (the i-th model call). For tool events Iter matches the iteration whose tool_use block produced the call, so all tool events from one parallel batch share Iter and are ordered by Seq.
type EventType ¶
type EventType string
EventType identifies what happened in an Event. The set is closed: every event emitted by Loop, LoopStream, runTools, and callWithRetry has one of these types.
const ( // EventTurnStart is emitted once at the beginning of Loop / LoopStream, // before any model call. History carries the trimmed history about to be // sent. EventTurnStart EventType = "turn_start" // EventModelRequest is emitted before each model call. Iter is the 0-based // iteration within the turn. EventModelRequest EventType = "model_request" // EventModelResponse is emitted after each successful model call (after // retries, if any). Message holds the assistant content; Usage holds the // per-call token usage; StopReason carries the model's stop reason. EventModelResponse EventType = "model_response" // EventRetryAttempt is emitted before each retry sleep, mirroring // RetryConfig.OnRetry but routed through the Recorder. Attempt is the // 1-based retry number; Wait is the computed backoff. EventRetryAttempt EventType = "retry_attempt" // EventToolCallStart is emitted just before a tool dispatch begins. // Concurrent tool calls share the same Iter; Seq orders them. EventToolCallStart EventType = "tool_call_start" // EventToolCallEnd is emitted after a tool dispatch returns. ToolOutput // carries the result string; if the tool returned an error, ToolError // holds the error message and IsError is true. EventToolCallEnd EventType = "tool_call_end" // EventTurnEnd is emitted on successful turn completion (model returned // end_turn). EventTurnEnd EventType = "turn_end" // EventTurnError is emitted when Loop / LoopStream returns a non-nil // error. Err carries the error message. EventTurnError EventType = "turn_error" )
type ExtractParams ¶
type ExtractParams[T any] struct { // Description is the submit tool's description shown to the model. It is // the model-facing instruction for what value to produce. Required. Description string // Schema describes the shape of T. Required. Construct with the schema // helpers (Object, Array, ObjectOf, ...) or hand-roll JSON via // InputSchema literals. Schema InputSchema // Tools are additional tools the model may call before submitting (e.g. // search, retrieval). Pass a zero-value Toolset for pure structured output. Tools Toolset // Name is the submit tool's name. Defaults to "submit". Name string // MaxIter caps the number of model turns. Defaults to 8. MaxIter int // Validate, if non-nil, is called with the model's submitted value before // Extract accepts it. Returning a non-nil error marks the submit as failed: // the model sees an is_error=true tool result with the error message and // may retry within the iteration budget. Use this to enforce constraints // the schema cannot express (length caps, cross-field invariants, etc.). Validate func(T) error }
ExtractParams configures Extract. Description and Schema are required; the rest have sensible defaults.
The struct is generic over T so Validate can take a typed argument without the caller writing assertions. Most call sites pass a single literal:
gocode.Extract(ctx, client, system, history, gocode.ExtractParams[MyPlan]{
Description: "Submit the final plan",
Schema: planSchema,
})
type Hooks ¶
type Hooks struct {
// OnStep is called once per Step / StepStream, after the initial context
// trim and before the loop, with the trimmed history that will be sent
// to the model on the first iteration. Useful for logging effective
// context size or recording that a step started. Not called when Trim
// returns an error.
OnStep func(ctx context.Context, history []Message)
// OnIteration is called before every model call inside the loop, with
// the zero-based iteration index and the history that will actually be
// sent (post-trim, when a ContextManager is configured). Useful for
// observing long autonomous runs without dropping to Recorder.
OnIteration func(ctx context.Context, iter int, history []Message)
// OnStepDone is called after the loop returns, with the full LoopResult
// and any error. Called even when the loop returns an error so callers
// can record failures uniformly. Not called when the initial Trim fails.
OnStepDone func(ctx context.Context, result LoopResult, err error)
}
Hooks contains optional observer callbacks for an Agent step. All fields are nil by default and are safe to leave unset. A zero-value Hooks struct disables all observation.
Call order within a Step or StepStream call:
- Context.Trim is called once on the input history.
- OnStep is called with the trimmed history (skipped if Trim fails).
- The internal loop runs. Before every model call inside the loop, Context.Trim is re-applied (when MaxTokens > 0) and then OnIteration is invoked with the iteration index and the trimmed history.
- OnStepDone is called with the result and any error from the loop.
OnStepDone is NOT called when the initial Trim fails — only when the loop itself returns. Per-tool-call observation is available via Config.Recorder (see EventToolCallStart / EventToolCallEnd).
type ImageBlock ¶ added in v0.1.2
ImageBlock is the caller-facing representation of an image attachment. Source is either a base64 data URI ("data:image/png;base64,...") or an http(s) URL; MediaType is the IANA media type ("image/png", ...).
type InputSchema ¶
type InputSchema struct {
Type string `json:"type"`
Properties map[string]SchemaProperty `json:"properties"`
Required []string `json:"required,omitempty"`
}
InputSchema is the JSON Schema object describing a tool's input parameters. The Anthropic API requires Type to be "object". Use the schema builder helpers below for ergonomic construction; the output is identical to a hand-written literal.
func Object ¶
func Object(fields ...Property) InputSchema
Object builds an InputSchema from Properties. This is the main entry point for ergonomic tool schemas. The result is identical to a manual InputSchema literal and works with NewTool/NewTypedTool.
type JSONLRecorder ¶
type JSONLRecorder struct {
// contains filtered or unexported fields
}
JSONLRecorder writes one JSON object per line to the underlying writer. Errors from Write are silently dropped — recording is best-effort and must not interfere with the agent's main control flow. Wrap the writer yourself if you want error visibility.
func NewJSONLRecorder ¶
func NewJSONLRecorder(w io.Writer) *JSONLRecorder
NewJSONLRecorder returns a JSONLRecorder writing to w.
type Logger ¶
Logger is the logging interface used by WithLogging. *slog.Logger satisfies it. Applications may supply any compatible implementation.
type LoopError ¶
LoopError is returned when Loop exits without reaching end_turn. Iter is the loop iteration count at the point of failure.
type LoopResult ¶
type LoopResult struct {
Messages []Message // full conversation: original history + all new turns
Usage Usage // total tokens consumed across all iterations
}
LoopResult is returned by Loop and carries the complete updated history together with aggregate token usage across all API calls in the run.
func Extract ¶
func Extract[T any]( ctx context.Context, client *Client, system string, history []Message, params ExtractParams[T], ) (T, LoopResult, error)
Extract runs a tool-use loop in which the model is required to call a single terminal "submit" tool whose typed argument becomes the return value.
This collapses the "submit_X" structured-output pattern into one call. Both pure structured output (no other tools) and structured output via tool use (e.g. search-then-submit) are expressed by setting Params.Tools.
On success, the returned T is the accepted value and LoopResult contains the full conversation (including the terminal tool call) and aggregate usage.
Errors:
- The underlying loop fails (network, max_tokens, max_iter, etc.).
- The model ends its turn without ever calling the submit tool — Extract returns the zero value of T and an error mentioning the tool name.
Validation failures are NOT errors — they are surfaced to the model as retriable tool errors. Only when the loop ultimately ends without an accepted submission does Extract return an error.
func (LoopResult) Final ¶
func (r LoopResult) Final() Message
Final returns the last message in Messages, which is conventionally the final assistant reply. Returns the zero Message if Messages is empty.
func (LoopResult) FinalText ¶
func (r LoopResult) FinalText() string
FinalText returns the concatenated text of the final assistant message. Equivalent to TextContent(r.Final()). Returns "" if no messages are present.
type MemoryRecorder ¶
type MemoryRecorder struct {
// contains filtered or unexported fields
}
MemoryRecorder collects events in memory. Useful for tests and for the open-or-create chat pattern where events round-trip through Session.Events.
func NewMemoryRecorder ¶
func NewMemoryRecorder() *MemoryRecorder
NewMemoryRecorder returns an empty MemoryRecorder.
func (*MemoryRecorder) Events ¶
func (r *MemoryRecorder) Events() []Event
Events returns a copy of the recorded events in order.
func (*MemoryRecorder) Record ¶
func (r *MemoryRecorder) Record(_ context.Context, ev Event)
Record appends ev to the in-memory log, assigning a monotonic Seq.
func (*MemoryRecorder) Reset ¶
func (r *MemoryRecorder) Reset()
Reset clears the recorder. Seq numbering restarts at 1.
type Message ¶
type Message struct {
Role string `json:"role"`
Content []ContentBlock `json:"content"`
}
Message is one turn in a conversation.
func NewToolResultMessage ¶
func NewToolResultMessage(results []ToolResult) Message
NewToolResultMessage builds the user-role turn that returns tool outputs to the model after a tool_use response. Image attachments collected on any ToolResult are flattened onto the same canonical message after the tool_result blocks; the wire serializer splits them into a sibling role="user" message when sending.
func NewUserMessage ¶
NewUserMessage creates a plain-text user turn.
func NewUserMessageWithImages ¶ added in v0.1.2
func NewUserMessageWithImages(text string, images []ImageBlock) Message
NewUserMessageWithImages builds a user-role turn carrying a text block followed by one image content block per image. Pass an empty text to emit an image-only turn (the leading text block is skipped).
type Middleware ¶
type Middleware func(binding ToolBinding) ToolFunc
Middleware is a function that wraps a ToolBinding's Func with additional behaviour. The full ToolBinding (including Tool, Meta, and the current Func) is passed so wrappers can use the tool name, metadata, and safety notes. The wrapper must return a new ToolFunc; it must not mutate the binding.
func WithConfirmation ¶
func WithConfirmation(prompt func(ctx context.Context, binding ToolBinding, input json.RawMessage) (bool, error)) Middleware
WithConfirmation returns a Middleware that calls prompt before each tool invocation. If prompt returns false the tool is skipped and a descriptive message is returned to the model instead of executing the tool. If prompt returns an error that error becomes a hard tool error and is surfaced to the caller as usual.
func WithLogging ¶
func WithLogging(logger Logger) Middleware
WithLogging returns a Middleware that logs each tool call and its result at Info level, or Error level on failure, using the supplied Logger. Pass a *slog.Logger (or any Logger-compatible value) as the argument.
func WithPanicRecovery ¶
func WithPanicRecovery() Middleware
WithPanicRecovery returns a Middleware that recovers from panics inside a ToolFunc, converting them into ordinary errors so the agent loop can continue. This is useful when wrapping untrusted or third-party tool implementations.
func WithResultLimit ¶
func WithResultLimit(maxBytes int) Middleware
WithResultLimit returns a Middleware that truncates tool output to at most maxBytes bytes. This prevents unexpectedly large tool results from filling the model's context window.
func WithTimeout ¶
func WithTimeout(d time.Duration) Middleware
WithTimeout returns a Middleware that cancels a tool call if it exceeds d.
type MultiRecorder ¶
type MultiRecorder []Recorder
MultiRecorder fans Record calls out to several recorders in order. Each child assigns its own Seq independently.
type Option ¶
type Option func(*Property)
Schema builder helpers follow the design principles (explicit core, simple assembly, progressive disclosure, Lego-like tools, agent-legible by design). They are pure convenience: no reflection, no hidden state, fully inspectable output (Property and InputSchema are plain structs). Users can always fall back to writing InputSchema by hand. Matches the ROADMAP.md examples and compiles down to the primitives.
Example:
schema := Object(
String("path", "Path to read", Required()),
Number("limit", "Max items to return", Enum(10, 25, 50)),
)
type Property ¶
type Property struct {
Name string
SchemaProperty
Required bool
}
Property represents one field for Object(). All fields are exported so the constructed schema remains fully transparent and inspectable.
func Array ¶
func Array(name, description string, items SchemaProperty, opts ...Option) Property
Array returns a Property with type "array". items describes the element schema; use a primitive SchemaProperty (e.g. {Type: "string"}) for arrays of scalars or ObjectOf(...) for arrays of objects.
Example:
Array("tags", "Free-form tags", SchemaProperty{Type: "string"})
Array("steps", "Pipeline steps", ObjectOf(
String("name", "Step name", Required()),
Integer("retries", "Retry count"),
), Required())
type Provider ¶
type Provider interface {
// Call sends a single request and returns a normalised response.
Call(ctx context.Context, req ProviderRequest) (ProviderResponse, error)
// Stream sends the request and invokes onDelta for every incremental
// ContentBlock (typically text deltas; also partial tool_use blocks
// when supported by the backend). It returns the final aggregated
// ProviderResponse (complete Content, StopReason, and Usage) once
// the stream ends. The callback is invoked synchronously as data
// arrives. Retries (if configured) may cause multiple callback
// invocations across attempts.
Stream(ctx context.Context, req ProviderRequest, onDelta func(ContentBlock)) (ProviderResponse, error)
}
Provider is the abstraction over an LLM API backend. Implementations translate between the canonical ProviderRequest / ProviderResponse types and their own wire formats.
type ProviderRequest ¶
type ProviderRequest struct {
Model string
MaxTokens int
System string
Messages []Message
Tools []Tool
ProviderTools []ProviderTool
// SystemCache, if set, marks the system prompt as a cache breakpoint.
// This is the most useful single cache placement when the system text
// is large and stable across turns. Honored by AnthropicProvider and
// OpenRouterProvider; ignored elsewhere (OpenAI caches automatically).
SystemCache *CacheControl
}
ProviderRequest is the canonical request passed to every Provider.
Tools are local (category-2 included) tool declarations the model may call; the provider translates them to its native wire format and the agent loop dispatches via ToolFunc when the model emits a tool_use block.
ProviderTools are server-executed (category-1) tools — the provider runs them and returns inline result blocks. The loop never inspects them; they are passed straight through and spliced verbatim into the provider's tools array. Each entry is tagged with a Provider string so providers can reject mismatched entries at request build time.
type ProviderResponse ¶
type ProviderResponse struct {
Content []ContentBlock
StopReason string
Usage Usage
}
ProviderResponse is the normalised response every Provider must return.
type ProviderTool ¶
type ProviderTool struct {
Provider string // e.g. "anthropic"
Raw json.RawMessage // verbatim JSON spliced into the provider's tools array
}
ProviderTool is a server-executed (category-1) tool advertised to the model. The provider runs it; no Go ToolFunc is needed. The agent loop never inspects ProviderTools — they pass through ProviderRequest to the provider, which splices Raw verbatim into its native tools array. Provider tags the entry to a specific provider so misuse fails at request-build time.
Use the typed constructors (AnthropicWebSearch, AnthropicCodeExecution, ...) to build these rather than instantiating the struct directly.
type Recorder ¶
Recorder receives Events as they happen during Loop / LoopStream. Implementations must be safe for concurrent use because runTools dispatches tool calls in parallel and each goroutine emits its own start/end events.
The Seq field on the incoming event is ignored; the Recorder assigns its own monotonic Seq before storing or forwarding. This keeps Seq meaningful even when multiple Loops share one Recorder.
func RecorderToSession ¶
RecorderToSession returns a Recorder that appends to sess.Events. The returned Recorder is safe for concurrent use; events accumulate on the session in record order so a subsequent Save persists the full log.
type Result ¶
Result carries the outcome of one parallel step.
func Parallel ¶
Parallel runs all steps concurrently and waits for all to finish. The returned slice is index-aligned: results[i] corresponds to steps[i].
No step is cancelled if another fails — cancellation policy is the caller's responsibility. Callers who want fail-fast behaviour should pass a derived context with a cancel func and call it after checking results for errors.
type RetryConfig ¶
type RetryConfig struct {
MaxRetries int // max attempts after the first; 0 → use default (3)
InitialWait time.Duration // first back-off interval; 0 → use default (1s)
MaxWait time.Duration // back-off ceiling; 0 → use default (30s)
Disabled bool // set true to disable all retrying
// OnRetry, when non-nil, is called before each retry sleep with the
// 1-based retry attempt number and the computed backoff duration.
// Use this to log retries or reset streaming state (see StreamBuffer).
OnRetry func(attempt int, wait time.Duration)
}
RetryConfig controls automatic retry behaviour for transient API errors. The zero value enables retrying with sensible defaults.
type RetryExhaustedError ¶
RetryExhaustedError is returned by callWithRetry when every attempt has failed and no more retries remain. Attempts is the total number of calls that were made (including the initial attempt). Cause is the last error returned by the underlying function.
func (*RetryExhaustedError) Error ¶
func (e *RetryExhaustedError) Error() string
func (*RetryExhaustedError) Unwrap ¶
func (e *RetryExhaustedError) Unwrap() []error
Unwrap returns the last error that caused retries to be exhausted, enabling errors.Is / errors.As to inspect the underlying failure. It also chains ErrRetryExhausted so callers can match on errors.Is(err, ErrRetryExhausted).
type SchemaProperty ¶
type SchemaProperty struct {
Type string `json:"type"`
Description string `json:"description,omitempty"`
Enum []any `json:"enum,omitempty"`
Items *SchemaProperty `json:"items,omitempty"` // for type:"array"
Properties map[string]SchemaProperty `json:"properties,omitempty"` // for type:"object"
Required []string `json:"required,omitempty"` // for type:"object"
}
SchemaProperty describes one parameter within an InputSchema. The schema builder helpers (below) populate these fields; Enum supports constrained values; Items, Properties, and Required let arrays and nested objects round-trip without dropping to hand-written JSON.
For schemas richer than these fields express (oneOf, $ref, patternProperties, etc.) construct a Tool directly with a json.RawMessage InputSchema — see the "Hand-rolled schemas" section in RECIPES.md.
func ObjectOf ¶
func ObjectOf(fields ...Property) SchemaProperty
ObjectOf builds a nested-object SchemaProperty, suitable for passing as the item type to Array or as a child of a parent ObjectOf. Use Object at the top level (it returns InputSchema, the type tools require); use ObjectOf anywhere a SchemaProperty is expected.
Example:
Array("subtasks", "List of sub-questions",
ObjectOf(
String("question", "Sub-question to research", Required()),
String("rationale", "Why this matters"),
),
Required())
type Session ¶
type Session struct {
ID string `json:"id"`
History []Message `json:"history,omitempty"`
State map[string]json.RawMessage `json:"state,omitempty"`
// Events is an append-only activity log populated when a Recorder is
// attached to the session via RecorderToSession. It records intermediate
// turn activity — model calls, tool calls, retries — that does not
// appear in History. Persisted by Store implementations as plain JSON.
Events []Event `json:"events,omitempty"`
}
Session holds a conversation and optional caller-owned metadata.
A Session is plain data. It does not call models, run tools, trim context, schedule work, or manage application lifecycle. The caller decides when to load a session, pass History to a model call, and persist the result.
State holds arbitrary caller-owned metadata encoded as JSON values. Use the SetState and GetState helpers to read and write typed values:
gocode.SetState(sess, "user_id", "u-123") gocode.SetState(sess, "turn", 7) id, _ := gocode.GetState[string](sess, "user_id") turn, _ := gocode.GetState[int](sess, "turn")
Using json.RawMessage as the value type means State survives JSON round-trips without type loss — MemoryStore and FileStore behave identically for all value types.
Typical usage:
sess, err := store.Get(ctx, id)
if errors.Is(err, gocode.ErrSessionNotFound) {
sess = &gocode.Session{ID: id}
} else if err != nil {
return err
}
sess.History = append(sess.History, gocode.NewUserMessage(input))
result, err := assistant.Step(ctx, sess.History)
if err != nil {
return err
}
sess.History = result.Messages
return gocode.Save(ctx, store, sess) // creates or updates as needed
func Load ¶
Load returns the session with the given ID, or a fresh &Session{ID: id} if no session with that ID exists. It is the read-side symmetry of Save: callers that don't need to distinguish first use from subsequent use can rely on it for the open-or-create pattern. Other errors are returned as-is.
type StepFunc ¶
StepFunc is a unit of work in a directed workflow. It accepts the shared context and returns a typed result.
type Store ¶
type Store interface {
// Create persists a new Session. Returns ErrSessionExists if the ID is
// already present.
Create(ctx context.Context, session *Session) error
// Get loads a Session by ID. Returns ErrSessionNotFound if the ID is
// absent.
Get(ctx context.Context, id string) (*Session, error)
// Update overwrites an existing Session. Returns ErrSessionNotFound if
// the ID is absent.
Update(ctx context.Context, session *Session) error
// Delete removes a Session. Returns ErrSessionNotFound if the ID is
// absent.
Delete(ctx context.Context, id string) error
// List returns Sessions whose IDs have the given prefix, up to limit
// entries sorted by ID. An empty prefix matches all IDs. A limit of 0
// means no limit.
List(ctx context.Context, prefix string, limit int) ([]*Session, error)
}
Store persists and retrieves Sessions. All implementations must be safe for concurrent use.
Create and Update are intentionally separate: Create fails if the ID already exists, Update fails if it does not. This makes the caller's intent explicit and avoids silent overwrites. Use Save when you do not need that distinction.
type StreamBuffer ¶
type StreamBuffer struct {
// contains filtered or unexported fields
}
StreamBuffer provides reset-aware token delivery for streaming calls with retries. When callWithRetry retries a failed stream, the onToken callback may fire again for the new attempt, causing partial output from the failed attempt to appear before the successful attempt's output. StreamBuffer lets callers react to each retry by calling an onReset function, which can clear a display buffer, send an SSE reset event, or take any other corrective action.
Wire StreamBuffer to a streaming call like this:
sb := gocode.NewStreamBuffer(
func(b gocode.ContentBlock) { fmt.Print(b.Text) }, // forward tokens live
func() { fmt.Print("\n[retrying…]\n") }, // reset partial output
)
cfg := gocode.RetryConfig{OnRetry: sb.OnRetry}
client, _ := gocode.New(gocode.Config{..., Retry: cfg})
msg, err := client.AskStream(ctx, system, history, sb.OnToken)
Either argument to NewStreamBuffer may be nil, in which case that half of the wiring is silently skipped.
func NewStreamBuffer ¶
func NewStreamBuffer(onToken func(ContentBlock), onReset func()) *StreamBuffer
NewStreamBuffer returns a StreamBuffer that forwards tokens to onToken and calls onReset before each retry attempt. Either argument may be nil.
func (*StreamBuffer) OnRetry ¶
func (b *StreamBuffer) OnRetry(attempt int, wait time.Duration)
OnRetry satisfies the RetryConfig.OnRetry signature. It calls the onReset handler so callers can clear any partial output before the next stream attempt begins. attempt is the 1-based retry number; wait is the computed backoff duration.
func (*StreamBuffer) OnToken ¶
func (b *StreamBuffer) OnToken(cb ContentBlock)
OnToken is the onToken callback to pass to AskStream, LoopStream, or StepStream. It forwards each ContentBlock to the underlying onToken handler.
type Tool ¶
type Tool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
InputSchema json.RawMessage `json:"input_schema,omitempty"`
// Provider, if set, restricts this tool to a specific provider tag
// (e.g. "anthropic"). Providers reject mismatched tools at request
// build time so misuse fails loudly rather than silently dropping the
// declaration.
Provider string `json:"-"`
// CacheControl, if set, marks this tool as a cache breakpoint in the
// request. Caching is cumulative; placing the marker on the last tool
// in a stable toolset caches the system prompt and all earlier tools.
// Currently honored by AnthropicProvider and OpenRouterProvider.
// Ignored when Raw is set (the verbatim JSON wins).
CacheControl *CacheControl `json:"cache_control,omitempty"`
// Raw, if set, replaces the wire serialization of this tool. Used by
// provider-defined tools whose declaration form is not the standard
// {name, description, input_schema}. The agent loop never inspects Raw.
Raw json.RawMessage `json:"-"`
}
Tool defines a capability available to the agent during a Loop. InputSchema is stored as pre-serialized JSON so callers can supply schemas richer than InputSchema expresses (nested objects, arrays, $defs) without the library needing to understand them.
For provider-defined client-executed tools (category 2 — e.g. Anthropic's bash_20250124, text_editor_20250124, computer_20250124) the wire shape is {"type": "...", "name": "..."} rather than {name, description, input_schema}. Such tools set Provider and Raw: Provider tags the binding to one provider, and Raw is the verbatim JSON declaration spliced into the wire tools array. Name remains populated so the agent loop can dispatch tool_use blocks returned by the model.
func NewTool ¶
func NewTool(name, description string, schema InputSchema) Tool
NewTool constructs a Tool from a typed InputSchema.
Panics if schema cannot be marshalled to JSON. InputSchema is a plain Go struct of strings, maps, and slices — marshal cannot fail in practice, so the panic is a programmer-error indicator (corrupt unsafe.Pointer, etc.) rather than a runtime condition callers should handle.
func (Tool) MarshalJSON ¶
MarshalJSON emits Raw verbatim when set (category-2 provider-defined tools have a non-standard wire form). Otherwise it emits the standard {name, description, input_schema} object.
type ToolBinding ¶
type ToolBinding struct {
Tool Tool
Func ToolFunc
Meta ToolMetadata
}
ToolBinding pairs a Tool definition with its ToolFunc implementation and optional advisory metadata. It is the unit of composition for Toolset.
func Bind ¶
func Bind(t Tool, fn ToolFunc) ToolBinding
Bind is the one-line constructor for a ToolBinding with no metadata. Equivalent to ToolBinding{Tool: t, Func: fn}.
type ToolError ¶
ToolError is returned when a dispatch lookup fails (tool missing from map). Individual tool execution errors are soft-faulted into is_error results and are never wrapped in ToolError.
type ToolFunc ¶
ToolFunc is the signature every tool implementation must satisfy. input is the raw JSON the model produced as arguments for this call. Return the result as a plain string, or an error if the tool failed. Errors are fed back to the model as is_error=true results so it can recover; they do not abort the loop.
func TypedToolFunc ¶
TypedToolFunc returns a ToolFunc that automatically unmarshals the raw JSON input into the generic Input type before calling the provided handler. This removes the repetitive json.Unmarshal + error handling boilerplate while producing an ordinary ToolFunc that works with any dispatch map and preserves all existing error/inspectability behavior.
For struct Input types, empty input (nil, zero-length, or JSON "null") is treated as `{}` to avoid unmarshal errors on tools with no params. Other types (string, int, etc.) unmarshal strictly.
See NewTypedTool(...) for a one-line way to obtain both a Tool and the corresponding ToolFunc. Example (from the roadmap):
type CalculatorInput struct {
Operation string `json:"operation"`
A float64 `json:"a"`
B float64 `json:"b"`
}
fn := TypedToolFunc(func(ctx context.Context, in CalculatorInput) (string, error) {
switch in.Operation {
case "add":
return fmt.Sprintf("%f", in.A+in.B), nil
case "subtract":
return fmt.Sprintf("%f", in.A-in.B), nil
case "multiply":
return fmt.Sprintf("%f", in.A*in.B), nil
default:
return "", fmt.Errorf("unknown operation: %s", in.Operation)
}
})
The resulting fn can be used directly in a dispatch map[string]ToolFunc.
type ToolMetadata ¶
type ToolMetadata struct {
Source string
ReadOnly bool
Destructive bool
Network bool
Filesystem bool
Shell bool
RequiresConfirmation bool
SafetyNotes []string
Terminal bool
}
ToolMetadata carries advisory annotations about a bound tool.
Most fields are informational only; the library does not enforce policy based on them. Applications may inspect them to build confirmation wrappers, audit logs, or permission checks.
Terminal is the one field with semantic effect: when a tool with Meta.Terminal == true is invoked successfully (no IsError result), Loop and LoopStream return after appending the tool result message, without asking the model for a final text turn. This is the primitive behind Extract — it lets a "submit_X" style tool double as the loop's exit signal.
type ToolResult ¶
type ToolResult struct {
ToolUseID string // matches ContentBlock.ID from the corresponding tool_use block
Content string // the string returned by ToolFunc, or the error message
IsError bool
// Images, if non-empty, are image attachments produced by the tool.
// The agent loop populates this from any AttachImage calls a tool
// made during its run. NewToolResultMessage flattens them onto the
// canonical user-role message; the OpenAI wire serializer emits them
// as image_url parts on a sibling user message.
Images []ImageBlock
}
ToolResult is the output of one ToolFunc execution.
type ToolUse ¶
type ToolUse struct {
ID string
Name string
Input json.RawMessage
}
ToolUse is extracted from an assistant ContentBlock and passed to dispatch.
type Toolset ¶
type Toolset struct {
Bindings []ToolBinding
ProviderTools []ProviderTool
}
Toolset is an ordered collection of ToolBindings. It is the input shape for Client.Loop and Client.LoopStream. Tools() and Dispatch() expose the raw slice and map for callers that want to inspect or use them directly.
ProviderTools holds server-executed (category-1) tools advertised to the provider — e.g. Anthropic's web_search, code_execution. They have no Go implementation; the provider runs them and returns inline result blocks. The agent loop never inspects them: Tools() and Dispatch() ignore the slot and only describe local Bindings. Use the typed provider constructors (AnthropicWebSearch, etc.) and attach them via WithProviderTools or by setting the field directly.
func Join ¶
Join merges multiple Toolset values into one, preserving order. Returns an error if any tool name appears more than once across the sets. ProviderTools are concatenated without deduplication (each entry is opaque JSON; collision is ill-defined).
func MustJoin ¶
MustJoin is like Join but panics on duplicate tool names. It is intended for static composition of toolsets at program startup, where a duplicate is a programmer error rather than a runtime condition. Follows the regexp.MustCompile / template.Must convention.
func Tools ¶
func Tools(bindings ...ToolBinding) Toolset
Tools is a variadic constructor for a Toolset. It is the most ergonomic way to build a small toolset literally:
tools := gocode.Tools(
gocode.Bind(searchTool, searchFn),
gocode.Bind(submitTool, submitFn),
)
Equivalent to Toolset{Bindings: []ToolBinding{...}}.
func (Toolset) CacheLast ¶
func (t Toolset) CacheLast(cache *CacheControl) Toolset
CacheLast returns a copy of t with the last tool binding marked as a cache breakpoint. Anthropic cache markers are cumulative — a marker on the last tool caches the system prompt and every preceding tool — so this is the standard "cache the stable prefix" pattern.
No-op for empty toolsets. Honored only by providers that support cache markers (AnthropicProvider, OpenRouterProvider routing to Anthropic); other providers ignore it.
func (Toolset) Tools ¶
Tools returns the Tool slice — the model-facing definitions — derived from the bindings. Useful for inspection or for callers building their own loop on top of the primitive provider interfaces.
func (Toolset) WithProviderTools ¶
func (t Toolset) WithProviderTools(pt ...ProviderTool) Toolset
WithProviderTools returns a copy of t with the supplied ProviderTools appended to the existing slot. Useful for fluent composition:
tools := agent.Tools(localBinding).
WithProviderTools(agent.AnthropicWebSearch(agent.WebSearchOpts{MaxUses: 5}))
func (Toolset) Wrap ¶
func (t Toolset) Wrap(middlewares ...Middleware) Toolset
Wrap applies each Middleware to every binding in the Toolset, returning a new Toolset with the decorated functions. Middlewares are applied in order, so the first one listed is outermost (executes first and last). ProviderTools (category-1) carry through unchanged — middleware applies only to local Bindings.
type Usage ¶
type Usage struct {
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheCreationTokens int `json:"cache_creation_input_tokens,omitempty"`
CacheReadTokens int `json:"cache_read_input_tokens,omitempty"`
}
Usage records token consumption for one API call.
CacheCreationTokens and CacheReadTokens carry prompt-cache statistics from providers that report them (Anthropic and OpenRouter today). CacheCreationTokens are billed input tokens that wrote a fresh cache entry; CacheReadTokens are input tokens served from cache at a discount. Providers that don't surface cache info leave both fields zero.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
gocode
command
gocode is a CLI coding agent built on the gocode toolkit.
|
gocode is a CLI coding agent built on the gocode toolkit. |
|
examples
|
|
|
agent
command
Tier 3 example: a full agentic loop with tool use.
|
Tier 3 example: a full agentic loop with tool use. |
|
ask
command
Tier 1 example: a single LLM call.
|
Tier 1 example: a single LLM call. |
|
pipeline
command
Tier 2 example: parallel steps feeding a sequential step.
|
Tier 2 example: parallel steps feeding a sequential step. |
|
recipes/01-minimal
command
Recipe 01-minimal: the smallest tool-using agent gocode can express with primitives alone.
|
Recipe 01-minimal: the smallest tool-using agent gocode can express with primitives alone. |
|
recipes/02-agent-with-tools
command
Recipe 01: a single Agent with a curated toolset and streaming output.
|
Recipe 01: a single Agent with a curated toolset and streaming output. |
|
recipes/03-repo-explainer
command
Recipe 02: repo-explainer.
|
Recipe 02: repo-explainer. |
|
recipes/04-router-subagents
command
Recipe 04: a router orchestrator that delegates to specialist subagents.
|
Recipe 04: a router orchestrator that delegates to specialist subagents. |
|
recipes/05-persistent-chat
command
Recipe 05: persistent chat with a per-turn activity log.
|
Recipe 05: persistent chat with a per-turn activity log. |
|
recipes/06-parallel-pipeline
command
Recipe 06: parallel steps feeding a sequential step.
|
Recipe 06: parallel steps feeding a sequential step. |
|
recipes/07-web-service
command
Recipe 07-web-service: the smallest deploy-shaped HTTP server that fronts a gocode Agent.
|
Recipe 07-web-service: the smallest deploy-shaped HTTP server that fronts a gocode Agent. |
|
stream
command
Streaming demo: live CLI output using AskStream (and LoopStream is similar).
|
Streaming demo: live CLI output using AskStream (and LoopStream is similar). |
|
Package mcp provides a client for the Model Context Protocol (MCP).
|
Package mcp provides a client for the Model Context Protocol (MCP). |
|
providers
|
|
|
tools
|
|
|
bash
Package bash provides a sandboxed shell tool for the coding agent.
|
Package bash provides a sandboxed shell tool for the coding agent. |
|
batch
Package batch provides a single tool, "batch", that runs N other tool calls concurrently in one model turn.
|
Package batch provides a single tool, "batch", that runs N other tool calls concurrently in one model turn. |
|
clock
Package clock provides a safe, read-only tool that returns the current UTC time.
|
Package clock provides a safe, read-only tool that returns the current UTC time. |
|
editor
Package editor implements the handlers for Anthropic's str_replace_based_edit_tool (text_editor_20250728) sandboxed to a workspace root.
|
Package editor implements the handlers for Anthropic's str_replace_based_edit_tool (text_editor_20250728) sandboxed to a workspace root. |
|
math
Package math provides a safe calculator tool for basic arithmetic.
|
Package math provides a safe calculator tool for basic arithmetic. |
|
subagent
Package subagent packages an Agent (client + system prompt + toolset) as a single tool the parent agent can call.
|
Package subagent packages an Agent (client + system prompt + toolset) as a single tool the parent agent can call. |
|
todo
Package todo provides an in-memory todo list as a pair of tools.
|
Package todo provides an in-memory todo list as a pair of tools. |
|
web
Package web implements a stdlib-only web_fetch tool: download a URL, convert HTML to plain text, and return a slice of the result with optional pagination.
|
Package web implements a stdlib-only web_fetch tool: download a URL, convert HTML to plain text, and return a slice of the result with optional pagination. |
|
workspace
Package workspace provides a safe, sandboxed set of filesystem tools rooted at a configurable directory.
|
Package workspace provides a safe, sandboxed set of filesystem tools rooted at a configurable directory. |