Help us shape the future of Go! Take the 2026 Go Developer Survey

agent

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

Agent Runtime for Go

English | 简体中文

CI Go Reference Go Report Card License

A composable, provider-agnostic agent runtime for Go.

The runtime executes the model/tool loop reliably; your application owns model adapters, prompts, tools, permissions, storage, and business APIs. Use just the root package for a single run, or add Session, Durable, MCP, Skills, and Sub-Agent capabilities as you need them.

The project is currently at v0.x and the API may still change. Pin a version when depending on it.

What it does

  • Unified contracts for messages, images, models, streamed responses, and usage
  • Multi-step model/tool loop with JSON Schema validation and tool allowlists
  • Max steps, stop conditions, context budgets, and tool loop detection
  • Optional Session, Durable, Permission, Event, MCP, Skills, and Sub-Agent packages
  • Immutable runtime definitions and reproducible artifact digests
  • Testable provider/tool ports with no coupling to OpenAI, Anthropic, or any database

Installation

go get github.com/iceymoss/agent-runtime-go
import agent "github.com/iceymoss/agent-runtime-go"

Two-minute run

The repository ships a deterministic example that needs no API key:

go run ./examples/hello

Output:

Hello from Agent Runtime for Go.

A minimal call takes three steps:

runner, err := agent.New(agent.Config{
	Key:          "example.hello",
	ModelName:    "my-model",
	MaxSteps:     4,
	AllowedTools: []string{},
}, model, agent.NewRegistry())
if err != nil {
	return err
}

result, err := runner.Run(ctx, agent.RunRequest{Messages: []agent.Message{
	agent.NewSystemMessage("Answer clearly."),
	agent.NewUserMessage("Say hello."),
}})
if err != nil {
	return err
}
fmt.Println(result.Text)

Here model implements the root package's single model port:

type Model interface {
	Name() string
	Capabilities() agent.Capabilities
	Stream(context.Context, *agent.GenerateRequest) (<-chan agent.StreamChunk, error)
}

A provider adapter projects GenerateRequest into the upstream protocol and converts upstream responses into canonical StreamChunk values. See examples/hello for a complete minimal implementation.

Connecting a real model

Any OpenAI-compatible API (OpenAI, DeepSeek, Qwen, Kimi, vLLM, Ollama, ...) works out of the box with the official providers/openaicompat adapter — no need to implement Model yourself:

import "github.com/iceymoss/agent-runtime-go/providers/openaicompat"

model := openaicompat.New("https://api.deepseek.com/v1", os.Getenv("DEEPSEEK_API_KEY"))

runner, err := agent.New(agent.Config{
	Key:       "example.assistant",
	ModelName: "deepseek-chat",
	MaxSteps:  8,
}, model, agent.NewRegistry())

The adapter streams over SSE by default, assembles tool call fragments, normalizes usage (including cache tokens), and classifies failures as agent.ModelError. Options:

  • openaicompat.WithoutStreaming(): use non-streaming requests for providers with unreliable SSE
  • openaicompat.WithCapabilities(...): declare capabilities that differ from the defaults
  • openaicompat.WithHeader(k, v): attach custom request headers (for example OpenRouter attribution)
  • openaicompat.WithHTTPClient(...): customize timeouts, proxies, and the transport

A runnable example that works with any OpenAI-compatible endpoint:

OPENAI_API_KEY=sk-... go run ./examples/openai-compat

Other protocols (such as the Anthropic Messages API) are integrated by implementing the Model interface.

Model/tool loop

Run the complete example with tools:

go run ./examples/tool-agent

Execution flow:

user message
  -> model requests get_weather
  -> runtime validates JSON Schema
  -> runtime executes get_weather
  -> tool result is appended to messages
  -> model returns the final answer

The easiest way to define a tool is the generic helper agent.NewTool, which generates the JSON Schema from a struct:

type WeatherInput struct {
	City string `json:"city" description:"City name"`
	Days int    `json:"days,omitempty" description:"Forecast days"`
}

tool := agent.MustNewTool("get_weather", "Get the current weather for a city.",
	func(ctx context.Context, input WeatherInput) (agent.ToolResult, error) {
		return agent.ToolResult{Content: lookupWeather(input.City)}, nil
	})

registry := agent.NewRegistry()
_ = registry.Register(tool)

Non-pointer fields without omitempty become required automatically; the schema is strict by default (undeclared properties are rejected and fed back to the model for repair). When you need full control over the schema, implement the Tool interface directly:

type Tool interface {
	Definition() agent.ToolDefinition
	ReplayPolicy() agent.ReplayPolicy
	Execute(context.Context, agent.ToolInvocation) (agent.ToolResult, error)
}

See examples/tool-agent for the full code. The example uses a deterministic model so the two-step loop is easy to observe; swap in a real agent.Model implementation to go live.

Wrapping your own agent

Do not let HTTP handlers, CLIs, or business services assemble prompts and tools everywhere. Provide a purpose-built facade instead:

type SupportAgent struct {
	runner *agent.Agent
}

type SupportAgentConfig struct {
	Model agent.Model
	CRM   CRM
}

func NewSupportAgent(cfg SupportAgentConfig) (*SupportAgent, error) {
	registry := agent.NewRegistry()
	if err := registry.Register(newFindOrderTool(cfg.CRM)); err != nil {
		return nil, err
	}

	runner, err := agent.New(agent.Config{
		Key:          "support.assistant",
		ModelName:    cfg.Model.Name(),
		MaxSteps:     8,
		AllowedTools: []string{"find_order"},
	}, cfg.Model, registry)
	if err != nil {
		return nil, err
	}
	return &SupportAgent{runner: runner}, nil
}

func (a *SupportAgent) Reply(ctx context.Context, input string, history []agent.Message) (*agent.RunResult, error) {
	messages := make([]agent.Message, 0, len(history)+2)
	messages = append(messages, agent.NewSystemMessage(
		"You are a support assistant. Confirm facts with tools before answering.",
	))
	messages = append(messages, history...)
	messages = append(messages, agent.NewUserMessage(input))
	return a.runner.Run(ctx, agent.RunRequest{Messages: messages})
}

Recommended boundary:

HTTP / CLI / Worker
        |
        v
Your Agent facade
  - Prompt and policy
  - Tool selection
  - Domain ports
  - History mapping
        |
        v
agent-runtime-go
  - Model/tool loop
  - Validation
  - Stop and recovery semantics

The application persists the current user message and RunResult.Messages. The root Agent holds no session state and can be shared concurrently across requests.

See the Quick Start for the full walkthrough, and demo/icoder for a runnable code-agent reference application.

Choosing subpackages

Import only what your current requirements need.

Requirement Use
One model/tool loop root package agent
OpenAI-compatible model integration providers/openaicompat
Multi-model catalog and factory provider
Prompt templates and versions prompt
History normalization and token budgets context
Message aggregation and revision CAS message
Session, branch, claim/resume session
Checkpoints, leases, fences, recovery durable
allow/deny/ask and authorization permission
Advanced tool lifecycle and effect ledger tool
Reliable events, outbox, and replay event
Untrusted instruction catalog skills
MCP discovery and invocation mcp
Immutable capability composition coordinator
Independent child runs subagent
Readiness and bounded shutdown app
Adapter conformance tests agenttest, test-only

See the subpackage guide for responsibilities, rationale, and minimal compositions.

How it works

RunRequest.Messages
        |
        v
build GenerateRequest -> agent.Model.Stream
        |                       |
        |                  canonical chunks
        v                       v
validate response <- aggregate one model step
        |
        +-- final text -------> RunResult
        |
        +-- tool calls
                |
                v
        schema + allowlist validation
                |
                v
           Tool.Execute
                |
                v
        append tool results and repeat

The root package reads no environment variables, selects no credentials, connects to no database, and registers no implicit global tools. Those policies belong to the consuming application.

See runtime internals for detailed execution semantics.

Examples

Example Demonstrates
examples/hello Minimal model adapter and one run
examples/tool-agent Complete model/tool loop with a facade
examples/openai-compat Official adapter with a real model, NewTool, and streaming output
demo/icoder Provider, tools, permissions, sessions, SQLite, Skills, MCP, and Sub-Agent composed together

Documentation

Documentation is currently written in Chinese; the code and API docs are in English.

  1. Introduction: positioning, capabilities, boundaries
  2. Quick start: a minimal runnable agent
  3. Overview: core concepts and package map
  4. Architecture: ports, adapters, composition
  5. Runtime internals: the run loop and durable boundaries
  6. Root package reference
  7. Subpackage responsibilities and integration guide
  8. Production composition patterns
  9. iCoder end-to-end tutorial
  10. Reference and glossary

Key semantics

  • AllowedTools == nil uses every tool in the registry; an empty slice explicitly disables tools.
  • ToolResult{IsError: true} is a model-visible, correctable tool error.
  • A non-nil Go error terminates the current attempt and preserves the original cause.
  • RunResult.Messages contains only the assistant/tool messages added during this run.
  • Observations are bounded, non-blocking, and lossy; they are not an authoritative event log.
  • Durable execution does not inherently guarantee exactly-once external side effects; downstream systems deduplicate with the stable ExecutionKey.
  • Prompts, Skills, and model output are not permission boundaries; real permissions must be enforced in tools and application adapters.

Verification

go test ./... -count=1
go test -race ./... -count=1
go vet ./...

Design boundary

The root package agent is the portable core and depends on no optional subpackage. Subpackages depend on the root as needed, and the application assembles concrete models, databases, permissions, and business policy in its composition root.

License

Apache License 2.0

Documentation

Overview

Package agent provides provider-neutral messages, models, tools, streaming, and a stateless multi-step model/tool runtime. Applications supply concrete model and tool adapters and may add optional child packages for stateful or durable hosting.

Index

Constants

View Source
const (
	// DefaultLoopDetectWindow is the sliding window size.
	DefaultLoopDetectWindow = 4
	// DefaultLoopDetectThreshold is the repeat threshold for one signature:
	// exceeding it (the third hit) marks the run as stuck.
	DefaultLoopDetectThreshold = 2
)

Default loop detection parameters. A server-side run is an order of magnitude shorter than a CLI session, so larger window/threshold pairs would never fill the window at small max_steps and detection would silently fail.

View Source
const LegacyExecutableVersion = "legacy"

LegacyExecutableVersion explicitly opts a tool into the ToolSet digest used before executable identities were introduced. It is only appropriate while restoring artifacts created by that implementation under the legacy format.

View Source
const (
	// RunSnapshotSchemaVersion is the only checkpoint representation understood
	// by this runtime. Readers reject every other version instead of guessing.
	RunSnapshotSchemaVersion = 1
)

Variables

View Source
var (
	// ErrAgentConfigInvalid reports an invalid agent configuration
	// (for example loop_detect_window > max_steps).
	ErrAgentConfigInvalid = errors.New("agent: invalid configuration")
	// ErrToolNotAllowed reports a tool that is not on the allowlist.
	ErrToolNotAllowed = errors.New("agent: tool not allowed")
	// ErrToolNotFound reports a tool that is not registered.
	ErrToolNotFound = errors.New("agent: tool not registered")
	// ErrLoopDetected reports a detected tool call loop.
	ErrLoopDetected = errors.New("agent: tool call loop detected")
	// ErrToolInputInvalid reports tool input that still violates the schema
	// after the bounded repair budget is exhausted.
	ErrToolInputInvalid = errors.New("agent: invalid tool input")
)

Core sentinel errors. The runtime exposes only sentinel errors; consuming applications map them to their own error codes with errors.Is.

View Source
var (
	// ErrUnsupportedRunSnapshotSchema means persisted state requires an explicit
	// migration or a runtime that understands its schema.
	ErrUnsupportedRunSnapshotSchema = errors.New("agent: unsupported run snapshot schema")
	// ErrInvalidRunTransition means a store mutation attempted an illegal
	// lifecycle transition.
	ErrInvalidRunTransition = errors.New("agent: invalid run transition")
	// ErrCheckpointConflict means revision, fence token, or lease ownership no
	// longer authorizes a mutation. Callers must reload rather than retry a stale write.
	ErrCheckpointConflict = errors.New("agent: checkpoint conflict")
	// ErrToolExecutionUnknown means an old worker may have executed a tool whose
	// result was never committed and the tool did not opt into safe replay.
	ErrToolExecutionUnknown = errors.New("agent: tool execution status unknown")
)
View Source
var ErrSessionNotFound = errors.New("agent: session not found")

ErrSessionNotFound indicates that a runtime session does not exist.

Functions

func CanonicalDigest

func CanonicalDigest(value any) (string, error)

CanonicalDigest returns the SHA-256 digest of the project's deterministic JSON representation. JSON object keys are ordered by the codec; array order remains significant because it can change message and tool semantics.

func ContextBudgetExceeded

func ContextBudgetExceeded(contextWindow, promptTokens int) bool

ContextBudgetExceeded reports whether the latest request's prompt occupancy is close to the window limit. promptTokens must be the input token count of the latest request, not billed usage accumulated across requests. Large-window models reserve a fixed buffer while small windows reserve proportionally: a fixed buffer would consume most of a small window. The runtime only detects and interrupts; it never compacts context itself.

func DigestRunConfig

func DigestRunConfig(config ImmutableRunConfig) (string, error)

DigestRunConfig fingerprints immutable execution configuration.

func DigestRunInput

func DigestRunInput(input ImmutableRunInput) (string, error)

DigestRunInput fingerprints immutable invocation data.

func DigestToolInput

func DigestToolInput(input string) (string, error)

DigestToolInput fingerprints tool input deterministically. Valid JSON uses its semantic representation; malformed JSON uses its exact raw bytes so it can be durably recorded before model-visible validation.

func MarshalRunSnapshot

func MarshalRunSnapshot(snapshot RunSnapshot) ([]byte, error)

MarshalRunSnapshot serializes only supported, internally coherent state.

func NewModelError

func NewModelError(kind ModelErrorKind, retryable bool, httpStatus int, retryAfter time.Duration, safeDetail string, cause error) error

NewModelError constructs a classified model error. Context termination is returned unchanged so callers retain the standard cancellation contract.

func ToolExecutionKey

func ToolExecutionKey(identity RunIdentity, stepNumber, ordinal int, call ToolCall) string

ToolExecutionKey derives a stable opaque key from immutable run and call coordinates. Valid JSON inputs are canonicalized; malformed inputs still get a deterministic key from their exact bytes so preparation can be audited.

func ToolExecutionKeyFromContext

func ToolExecutionKeyFromContext(ctx context.Context) (string, bool)

ToolExecutionKeyFromContext returns the stable key supplied by the durable runner. Tools must treat absence as meaning no idempotency guarantee.

func ValidateGenerateRequest

func ValidateGenerateRequest(req *GenerateRequest) error

ValidateGenerateRequest centralizes validation for adapter-facing requests. Model may be empty for adapters configured with their own default model.

func ValidateGenerateRequestCapabilities

func ValidateGenerateRequestCapabilities(req *GenerateRequest, caps Capabilities) error

ValidateGenerateRequestCapabilities rejects unsupported effects before a request reaches Model.

func ValidateMessage

func ValidateMessage(m Message) error

ValidateMessage validates the currently supported text/tool content model.

func ValidateResponse

func ValidateResponse(r *Response) error

ValidateResponse validates a provider's terminal response before the runtime can treat it as complete or execute any tool call.

func ValidateRunRequest

func ValidateRunRequest(req RunRequest) error

ValidateRunRequest centralizes request and supported content validation.

func ValidateRunRequestCapabilities

func ValidateRunRequestCapabilities(req RunRequest, caps Capabilities) error

ValidateRunRequestCapabilities rejects requests requiring unsupported model effects before execution starts.

func ValidateRunTransition

func ValidateRunTransition(from, to RunSnapshot) error

ValidateRunTransition validates adjacent lifecycle states independently of a persistence implementation. It also enforces immutable identity and digests.

func WithToolExecutionKey

func WithToolExecutionKey(ctx context.Context, key string) context.Context

WithToolExecutionKey exposes the stable key to Tool.Execute without using a collision-prone string context key. An empty key leaves ctx unchanged.

Types

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent is an assembled agent instance. It holds no session state and can be reused across turns and sessions.

func New

func New(cfg Config, model Model, registry *Registry) (*Agent, error)

New assembles an agent. Configuration problems surface at assembly time: a loop detection window larger than max_steps would silently disable detection, so it must fail immediately.

func (*Agent) ContextWindow

func (a *Agent) ContextWindow() int

ContextWindow returns the configured model context capacity.

func (*Agent) Key

func (a *Agent) Key() string

Key returns the agent identifier.

func (*Agent) PrepareDurableRun

func (a *Agent) PrepareDurableRun(request RunRequest) (string, string, Checkpoint, error)

PrepareDurableRun returns the immutable values used by durable Run Begin. Domain owners use it when run creation must share their claim transaction.

func (*Agent) Run

func (a *Agent) Run(ctx context.Context, request RunRequest) (result *RunResult, runErr error)

Run executes a runtime request. Observations are best-effort and never authoritative; callers use the returned result and error for terminal state.

type ArtifactVersions

type ArtifactVersions struct {
	Definition string `json:"definition"`
	Model      string `json:"model"`
	Tools      string `json:"tools"`
	Prompt     string `json:"prompt"`
	Policy     string `json:"policy"`
}

ArtifactVersions identifies executable or external artifacts captured by a definition.

type Capabilities

type Capabilities struct {
	Tools              bool `json:"tools"`
	ToolChoiceNone     bool `json:"tool_choice_none"`
	ToolChoiceRequired bool `json:"tool_choice_required"`
	ToolChoiceNamed    bool `json:"tool_choice_named"`
	StructuredOutput   bool `json:"structured_output"`
	Media              bool `json:"media"`
	ImageInput         bool `json:"image_input,omitempty"`
	Reasoning          bool `json:"reasoning"`
	UsageDetails       bool `json:"usage_details"`
}

Capabilities declares provider-neutral model features. Adapters must reject unsupported requests rather than silently degrading them.

func (Capabilities) Validate

func (c Capabilities) Validate() error

Validate rejects internally contradictory capability declarations.

type Checkpoint

type Checkpoint struct {
	History          []Message    `json:"history"`
	NewMessages      []Message    `json:"new_messages"`
	CompletedSteps   []StepResult `json:"completed_steps"`
	Usage            Usage        `json:"usage"`
	RepairCount      int          `json:"repair_count"`
	NextStep         int          `json:"next_step"`
	PendingToolCalls []ToolCall   `json:"pending_tool_calls"`
	Outcome          RunResult    `json:"outcome"`
}

Checkpoint is the complete resumable runtime state. History is the immutable input plus all committed messages; NewMessages is the run-local output subset. NextStep is the model step to execute after pending work has been resolved.

func (Checkpoint) Clone

func (checkpoint Checkpoint) Clone() Checkpoint

Clone returns a deep copy of all mutable checkpoint slices and pointers.

type CheckpointStore

type CheckpointStore interface {
	Begin(ctx context.Context, identity RunIdentity, inputDigest, configDigest string, checkpoint Checkpoint) (RunSnapshot, error)
	Acquire(ctx context.Context, runKey, leaseOwner string, leaseUntil time.Time) (RunSnapshot, error)
	ModelInflight(ctx context.Context, guard MutationGuard, checkpoint Checkpoint) (RunSnapshot, error)
	CommitModelResponse(ctx context.Context, guard MutationGuard, response Response, checkpoint Checkpoint) (RunSnapshot, error)
	PrepareTools(ctx context.Context, guard MutationGuard, tools []ToolExecution, checkpoint Checkpoint) (RunSnapshot, error)
	BeginTool(ctx context.Context, guard MutationGuard, idempotencyKey string, safeReplay bool) (RunSnapshot, ToolExecution, error)
	CommitTool(ctx context.Context, guard MutationGuard, execution ToolExecution, checkpoint Checkpoint) (RunSnapshot, error)
	Complete(ctx context.Context, guard MutationGuard, checkpoint Checkpoint) (RunSnapshot, error)
	Suspend(ctx context.Context, guard MutationGuard, checkpoint Checkpoint) (RunSnapshot, error)
	Fail(ctx context.Context, guard MutationGuard, checkpoint Checkpoint, failure RunFailure) (RunSnapshot, error)
	Load(ctx context.Context, runKey string) (RunSnapshot, error)
}

CheckpointStore is the durable recovery boundary. Implementations must make each method atomic in one local persistence transaction and return deep copies. They must not hold a transaction open while model or tool code executes.

Begin is create-if-absent by RunKey and by the caller's session/request pair. A duplicate with identical identity and digests returns the existing snapshot; conflicting immutable data returns ErrCheckpointConflict.

Acquire grants or takes over an expired/suspended lease, atomically increments FenceToken and Revision, and returns running state. Lease expiry permits a new acquisition but never authorizes writes by itself. Every remaining mutating operation atomically compares MutationGuard, applies one valid transition, and increments Revision; stale guards return ErrCheckpointConflict.

CommitModelResponse atomically records a complete provider response, usage, and history before tools can run. A crash during model_inflight cannot reveal whether the provider processed the request, so recovery repeats the model call: model generation is at-least-once.

PrepareTools atomically creates every ToolExecution in prepared state with its stable key before any Tool.Execute call. BeginTool changes exactly one entry to executing before the external call. CommitTool atomically stores its complete result and advances the checkpoint. A crash after an external effect but before CommitTool leaves executing ambiguity. Recovery must mark it unknown unless the tool can safely retry or query using the same key. Thus tool effects are also at-least-once by default and become effectively-once only when the tool's own database/provider deduplicates that key; this interface cannot promise exactly-once.

Complete, Suspend, and Fail atomically persist their final checkpoint and state. Complete must be invoked through a transaction-scoped implementation helper when an owning domain record must become final in the same database transaction. Load is read-only and does not acquire a lease or authorize a subsequent write.

type ChunkType

type ChunkType string

ChunkType is the streamed fragment type.

const (
	// ChunkText is a text delta.
	ChunkText ChunkType = "text"
	// ChunkToolCall is one fully assembled tool call.
	ChunkToolCall ChunkType = "tool_call"
	// ChunkFinish ends the step and carries the complete Response.
	ChunkFinish ChunkType = "finish"
	// ChunkError reports a failure and carries the original upstream error.
	ChunkError ChunkType = "error"
)

type Config

type Config struct {
	// Key identifies the agent, for example assistant.support.
	Key string
	// ModelName is the resolved upstream model name.
	ModelName string
	// MaxSteps caps tool-calling steps within a single run.
	MaxSteps int
	// AllowedTools is the tool allowlist; nil means no restriction.
	AllowedTools []string
	// LoopDetectWindow / LoopDetectThreshold configure loop detection;
	// values <= 0 use the defaults.
	LoopDetectWindow    int
	LoopDetectThreshold int
	// ContextWindow is the model context window size; 0 means unknown and
	// disables budget checks.
	ContextWindow int
	// Temperature / MaxTokens / TopP are optional sampling parameters.
	Temperature *float64
	MaxTokens   *int
	TopP        *float64
	// StopConditions are additional stop conditions, stacked on top of the
	// default StepCountIs(MaxSteps).
	StopConditions []StopCondition
	// ToolChoice is the default portable tool selection behavior.
	ToolChoice *ToolChoice
	// ToolRepairLimit is the number of invalid tool calls allowed before the next
	// invalid call fails the run. Zero uses the default of one; the hard maximum is two.
	ToolRepairLimit int
}

Config is the configuration needed to assemble one agent. Applications typically load it from their own configuration source.

type ContentPart

type ContentPart struct {
	Type PartType `json:"type"`
	// Text is valid only when Type=PartText.
	Text string `json:"text,omitempty"`
	// ToolCall is valid only when Type=PartToolCall.
	ToolCall *ToolCall `json:"tool_call,omitempty"`
	// ToolResult is valid only when Type=PartToolResult.
	ToolResult *ToolResult `json:"tool_result,omitempty"`
	// Image is valid only when Type=PartImage.
	Image *ImageContent `json:"image,omitempty"`
}

ContentPart is one content part of a message. An assistant message may contain text and several tool calls at once, hence a part list instead of a single string.

type DurableCompletion

type DurableCompletion struct {
	Guard      MutationGuard
	Checkpoint Checkpoint
}

DurableCompletion is returned after the accepted terminal response has been checkpointed. Domain code passes it to CompleteInTransaction.

type DurableFailure

type DurableFailure struct {
	Guard      MutationGuard
	Checkpoint Checkpoint
	Failure    RunFailure
}

type DurableRunConfig

type DurableRunConfig struct {
	Identity        RunIdentity
	CheckpointStore CheckpointStore
	LeaseOwner      string
	LeaseDuration   time.Duration
	InputDigest     string
	ConfigDigest    string
	PromptVersion   string
	PolicyVersion   string
	AutoComplete    bool
	// DeferFailureFinalization leaves retryable suspension to the domain
	// transaction instead of persisting it independently.
	DeferFailureFinalization bool
	// AttemptAcquired runs immediately after Acquire and before any observation,
	// model call, or tool call. Returning an error aborts the acquired attempt.
	AttemptAcquired func(RunIdentity, uint64) error
	// ObservationEmitterFactory binds attempt metadata only after Acquire returns
	// the authoritative fence token. It must return a non-blocking sink.
	ObservationEmitterFactory func(RunIdentity, uint64) *ObservationEmitter
}

DurableRunConfig enables checkpointed execution. Leaving it nil preserves the ordinary in-memory Run behavior.

type DurableSuspension

type DurableSuspension struct {
	Guard      MutationGuard
	Checkpoint Checkpoint
}

DurableSuspension authorizes the domain owner to atomically suspend a retryable attempt with its admission and product projection.

type ExecutableVersioner

type ExecutableVersioner interface {
	ExecutableVersion() string
}

ExecutableVersioner identifies behavior that is not represented by a tool's model-visible definition or replay policy. Durable artifact builders require this capability so exact restoration cannot substitute a different binary implementation under a historical tool reference.

type ExecutionSettings

type ExecutionSettings struct {
	MaxSteps            int             `json:"max_steps"`
	LoopDetectWindow    int             `json:"loop_detect_window,omitempty"`
	LoopDetectThreshold int             `json:"loop_detect_threshold,omitempty"`
	ToolRepairLimit     int             `json:"tool_repair_limit,omitempty"`
	Temperature         *float64        `json:"temperature,omitempty"`
	MaxTokens           *int            `json:"max_tokens,omitempty"`
	TopP                *float64        `json:"top_p,omitempty"`
	ToolChoice          *ToolChoice     `json:"tool_choice,omitempty"`
	StopConditions      []StopCondition `json:"-"`
}

ExecutionSettings contains definition-level runtime behavior.

type FinishReason

type FinishReason string

FinishReason is the reason the model stopped generating.

const (
	// FinishStop is a normal finish.
	FinishStop FinishReason = "stop"
	// FinishToolCalls means generation stopped to make tool calls.
	FinishToolCalls FinishReason = "tool_calls"
	// FinishLength means the length limit was reached.
	FinishLength FinishReason = "length"
	// FinishError means generation was interrupted by an error.
	FinishError FinishReason = "error"
)

type FuncTool

type FuncTool[T any] struct {
	// contains filtered or unexported fields
}

FuncTool is a Tool built from a typed Go function by NewTool. The input schema is generated from T and the raw JSON input is decoded into T before the function runs.

func MustNewTool

func MustNewTool[T any](name, description string, fn func(ctx context.Context, input T) (ToolResult, error), opts ...ToolOption) *FuncTool[T]

MustNewTool is NewTool that panics on error, for assembly-time registration where a schema problem is a programming error.

func NewTool

func NewTool[T any](name, description string, fn func(ctx context.Context, input T) (ToolResult, error), opts ...ToolOption) (*FuncTool[T], error)

NewTool builds a Tool from a typed Go function. T must be a struct (or pointer to struct); its exported fields become the JSON Schema sent to the model:

  • property names come from `json` tags (falling back to the field name)
  • fields are required unless they are pointers or tagged omitempty/omitzero
  • a `description` tag becomes the property description
  • nested structs, slices, and string-keyed maps are supported

The runtime validates raw input against the generated schema before Execute runs, so fn receives well-formed input. The schema is strict by default: undeclared properties are rejected and fed back to the model for repair.

type WeatherInput struct {
	City string `json:"city" description:"City name"`
	Days int    `json:"days,omitempty" description:"Forecast days"`
}

tool, err := agent.NewTool("get_weather", "Get the weather for a city.",
	func(ctx context.Context, input WeatherInput) (agent.ToolResult, error) {
		return agent.ToolResult{Content: lookup(input.City)}, nil
	})

func (*FuncTool[T]) Definition

func (t *FuncTool[T]) Definition() ToolDefinition

Definition returns the generated model-visible declaration.

func (*FuncTool[T]) ExecutableVersion

func (t *FuncTool[T]) ExecutableVersion() string

ExecutableVersion returns the declared implementation version. It is empty unless WithToolExecutableVersion was used.

func (*FuncTool[T]) Execute

func (t *FuncTool[T]) Execute(ctx context.Context, invocation ToolInvocation) (ToolResult, error)

Execute decodes the raw input into T and invokes the function. Decode failures are returned as model-correctable IsError results.

func (*FuncTool[T]) ReplayPolicy

func (t *FuncTool[T]) ReplayPolicy() ReplayPolicy

ReplayPolicy returns the configured replay policy.

type GenerateRequest

type GenerateRequest struct {
	// Model is the upstream model name resolved by the application.
	Model string `json:"model"`
	// Messages is the full conversation history, including system messages.
	Messages []Message `json:"messages"`
	// Tools lists the tool definitions available for this request (already allowlisted).
	Tools []ToolDefinition `json:"tools,omitempty"`
	// ToolChoice is omitted for portable auto behavior unless explicitly set.
	ToolChoice *ToolChoice `json:"tool_choice,omitempty"`
	// Temperature is the sampling temperature.
	Temperature *float64 `json:"temperature,omitempty"`
	// MaxTokens caps a single generation.
	MaxTokens *int `json:"max_tokens,omitempty"`
	// TopP is the nucleus sampling parameter.
	TopP *float64 `json:"top_p,omitempty"`
}

GenerateRequest is one request the runtime sends to a Model, decoupled from any upstream protocol. Optional scalar fields use pointer + omitempty: nil is omitted while *0 is sent upstream as-is.

type GenerationOptions

type GenerationOptions struct {
	Temperature *float64 `json:"temperature,omitempty"`
	MaxTokens   *int     `json:"max_tokens,omitempty"`
	TopP        *float64 `json:"top_p,omitempty"`
}

GenerationOptions are the bounded portable scalar generation controls.

type Generator

type Generator interface {
	Generate(ctx context.Context, req *GenerateRequest) (*Response, error)
}

Generator is the optional non-streaming model capability. The Runtime only depends on Model and never requires or probes this interface.

type ImageContent

type ImageContent struct {
	MediaType string `json:"media_type"`
	Data      []byte `json:"data,omitempty"`
	Ref       string `json:"ref,omitempty"`
	Digest    string `json:"digest,omitempty"`
	SizeBytes int64  `json:"size_bytes,omitempty"`
}

ImageContent contains either inline bytes or an opaque immutable reference.

type ImmutableRunConfig

type ImmutableRunConfig struct {
	AgentKey            string            `json:"agent_key"`
	ModelName           string            `json:"model_name"`
	MaxSteps            int               `json:"max_steps"`
	ContextWindow       int               `json:"context_window,omitempty"`
	LoopDetectWindow    int               `json:"loop_detect_window,omitempty"`
	LoopDetectThreshold int               `json:"loop_detect_threshold,omitempty"`
	ToolRepairLimit     int               `json:"tool_repair_limit,omitempty"`
	Generation          GenerationOptions `json:"generation"`
	ToolChoice          *ToolChoice       `json:"tool_choice,omitempty"`
	Tools               []ToolDefinition  `json:"tools,omitempty"`
	PromptVersion       string            `json:"prompt_version,omitempty"`
	PolicyVersion       string            `json:"policy_version,omitempty"`
}

ImmutableRunConfig contains execution choices that must not drift on resume. Version fields let callers represent prompt and policy implementations whose executable functions cannot themselves be serialized.

type ImmutableRunInput

type ImmutableRunInput struct {
	Messages   []Message   `json:"messages"`
	ToolChoice *ToolChoice `json:"tool_choice,omitempty"`
}

ImmutableRunInput is the input envelope whose digest is fixed by Begin. Event handlers and other process-local behavior are deliberately excluded.

type LoopDetector

type LoopDetector struct {
	// contains filtered or unexported fields
}

LoopDetector detects the model repeatedly calling the same tool with the same input, using tool interaction signatures counted over a sliding window. StepCountIs alone is not enough: the model can burn all steps without making progress.

func NewLoopDetector

func NewLoopDetector(window, threshold int) *LoopDetector

NewLoopDetector builds a detector. window/threshold <= 0 use the defaults.

func (*LoopDetector) Detect

func (d *LoopDetector) Detect(steps []StepResult) (sig string, count int, detected bool)

Detect reports whether recent steps form a loop, returning the signature and repeat count on a hit. There is deliberately no early return for len(steps) < window: with a small max_steps, returning false before the window fills would disable detection across the practical step range.

func (*LoopDetector) Threshold

func (d *LoopDetector) Threshold() int

Threshold returns the repeat threshold.

func (*LoopDetector) Validate

func (d *LoopDetector) Validate(maxSteps int) error

Validate ensures the window does not exceed max_steps. A window larger than max_steps means detection can never trigger; that silent failure must be exposed at assembly time rather than shipped to production.

func (*LoopDetector) Window

func (d *LoopDetector) Window() int

Window returns the window size.

type MemoryStore

type MemoryStore struct {
	// contains filtered or unexported fields
}

MemoryStore is a concurrency-safe Store implementation for tests and embedding.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

NewMemoryStore creates an empty in-memory store.

func (*MemoryStore) AddUsage

func (s *MemoryStore) AddUsage(_ context.Context, sessionID uint, usage Usage) error

func (*MemoryStore) AppendMessages

func (s *MemoryStore) AppendMessages(_ context.Context, sessionID uint, messages ...Message) error

func (*MemoryStore) CreateSession

func (s *MemoryStore) CreateSession(_ context.Context, session Session) error

func (*MemoryStore) GetSession

func (s *MemoryStore) GetSession(_ context.Context, sessionID uint) (Session, error)

func (*MemoryStore) ListMessages

func (s *MemoryStore) ListMessages(_ context.Context, sessionID uint) ([]Message, error)

func (*MemoryStore) UpdateSessionStatus

func (s *MemoryStore) UpdateSessionStatus(_ context.Context, sessionID uint, status SessionStatus) error

type Message

type Message struct {
	Role Role `json:"role"`
	// Parts is the list of content parts.
	Parts []ContentPart `json:"parts"`
	// FinishReason is meaningful only for assistant messages:
	// stop/tool_calls/length/error.
	FinishReason FinishReason `json:"finish_reason,omitempty"`
}

Message is one conversation message.

func NewAssistantMessage

func NewAssistantMessage(text string) Message

NewAssistantMessage builds a text-only assistant message.

func NewSystemMessage

func NewSystemMessage(text string) Message

NewSystemMessage builds a system message.

func NewToolMessage

func NewToolMessage(results ...ToolResult) Message

NewToolMessage wraps a batch of tool results into one tool message.

func NewUserMessage

func NewUserMessage(text string) Message

NewUserMessage builds a user message.

func (Message) Text

func (m Message) Text() string

Text concatenates all text parts of the message.

func (Message) ToolCalls

func (m Message) ToolCalls() []ToolCall

ToolCalls returns all tool calls in the message.

func (Message) ToolResults

func (m Message) ToolResults() []ToolResult

ToolResults returns all tool results in the message.

type MessageStore

type MessageStore interface {
	AppendMessages(ctx context.Context, sessionID uint, messages ...Message) error
	ListMessages(ctx context.Context, sessionID uint) ([]Message, error)
}

MessageStore persists ordered runtime messages.

type Model

type Model interface {
	// Name returns the provider identifier.
	Name() string
	// Capabilities returns a coherent provider capability declaration.
	Capabilities() Capabilities
	// Stream generates one step as a stream. Implementations must close the
	// channel before returning or at end of stream. On upstream failure, send
	// ChunkError first and then close; propagate the error message as-is.
	Stream(ctx context.Context, req *GenerateRequest) (<-chan StreamChunk, error)
}

Model is the provider integration port. agent-runtime-go defines only this interface; adapters implement it in the consuming application, keeping the core portable (dependency inversion).

type ModelError

type ModelError struct {
	Kind       ModelErrorKind
	Retryable  bool
	HTTPStatus int
	RetryAfter time.Duration
	SafeDetail string
	Cause      error
}

ModelError preserves safe provider metadata and the original cause. Error never includes Cause because provider errors may contain secrets.

func (*ModelError) Error

func (e *ModelError) Error() string

func (*ModelError) Unwrap

func (e *ModelError) Unwrap() error

type ModelErrorKind

type ModelErrorKind string

ModelErrorKind classifies a provider-neutral model operation failure.

const (
	ModelErrorKindTransport   ModelErrorKind = "transport"
	ModelErrorKindRateLimit   ModelErrorKind = "rate_limit"
	ModelErrorKindAuth        ModelErrorKind = "auth"
	ModelErrorKindRejected    ModelErrorKind = "rejected"
	ModelErrorKindProtocol    ModelErrorKind = "protocol"
	ModelErrorKindUnsupported ModelErrorKind = "unsupported"
)

type ModelMetadata

type ModelMetadata struct {
	Name          string       `json:"name"`
	Version       string       `json:"version"`
	ContextWindow int          `json:"context_window,omitempty"`
	Capabilities  Capabilities `json:"capabilities"`
}

ModelMetadata is the resolved, immutable model identity used by a definition.

type MutationGuard

type MutationGuard struct {
	RunKey     string `json:"run_key"`
	LeaseOwner string `json:"lease_owner"`
	Revision   uint64 `json:"revision"`
	FenceToken uint64 `json:"fence_token"`
}

MutationGuard is the complete write authority returned by Acquire or a prior mutation. A store must compare all fields in the same transaction as its write.

type Observation

type Observation struct {
	Type       ObservationType `json:"type"`
	Text       string          `json:"text,omitempty"`
	ToolCall   *ToolCall       `json:"tool_call,omitempty"`
	ToolResult *ToolResult     `json:"tool_result,omitempty"`
	Step       *StepResult     `json:"step,omitempty"`
}

Observation is a detached snapshot of non-authoritative runtime progress. The runtime deep-clones it before handing it to a sink.

type ObservationEmitter

type ObservationEmitter struct {
	// contains filtered or unexported fields
}

ObservationEmitter is the runtime's concrete bounded observation sink. The runtime only enqueues snapshots; delivery runs on one bounded worker and can never block model, tool, or checkpoint progress.

func NewObservationEmitter

func NewObservationEmitter(queueSize int, consume func(Observation)) *ObservationEmitter

NewObservationEmitter creates a bounded emitter. consume must not retain or mutate observations after it returns.

func (*ObservationEmitter) Close

func (e *ObservationEmitter) Close()

Close stops admission and waits for already queued observations to drain.

type ObservationType

type ObservationType string

ObservationType identifies a best-effort runtime observation. Terminal run state is deliberately absent; callers must use RunResult and durable state.

const (
	ObservationTextDelta    ObservationType = "text_delta"
	ObservationToolCall     ObservationType = "tool_call_start"
	ObservationToolResult   ObservationType = "tool_result"
	ObservationStepFinished ObservationType = "step_finish"
)

type Outcome

type Outcome string

Outcome is the typed lifecycle result of a run.

const (
	OutcomeCompleted Outcome = "completed"
	OutcomeSuspended Outcome = "suspended"
	OutcomeFailed    Outcome = "failed"
)

type PartType

type PartType string

PartType is the message content part type.

const (
	// PartText is a plain text part.
	PartText PartType = "text"
	// PartToolCall is a tool call initiated by the model.
	PartToolCall PartType = "tool_call"
	// PartToolResult is a tool execution result.
	PartToolResult PartType = "tool_result"
	// PartImage is a provider-neutral user image input.
	PartImage PartType = "image"
)

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is a concurrency-safe tool registry. One Registry may be shared across sessions.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty registry.

func (*Registry) Get

func (r *Registry) Get(name string) (Tool, bool)

Get returns a tool by name.

func (*Registry) Names

func (r *Registry) Names() []string

Names returns the registered tool names, sorted for stable tests and logs.

func (*Registry) Register

func (r *Registry) Register(t Tool) error

Register registers a new tool and rejects duplicate names.

func (*Registry) Replace

func (r *Registry) Replace(t Tool) error

Replace explicitly replaces an existing tool. Missing names are rejected.

type ReplayPolicy

type ReplayPolicy string
const (
	ReplayPolicyNever      ReplayPolicy = "never"
	ReplayPolicyIdempotent ReplayPolicy = "idempotent"
	ReplayPolicyResolve    ReplayPolicy = "resolve"
)

type Response

type Response struct {
	// Message is the assistant message produced by the model
	// (it may contain text and tool calls).
	Message Message `json:"message"`
	// Usage is the usage for this step.
	Usage Usage `json:"usage"`
	// FinishReason is the reason generation stopped.
	FinishReason FinishReason `json:"finish_reason"`
	// ModelName is the model actually used, for cost accounting.
	ModelName string `json:"model_name,omitempty"`
}

Response is the result of one model generation step.

func (*Response) ToolCalls

func (r *Response) ToolCalls() []ToolCall

ToolCalls returns the tool calls made in this step.

type Role

type Role string

Role is the message role.

const (
	// RoleSystem is the system prompt.
	RoleSystem Role = "system"
	// RoleUser is user input.
	RoleUser Role = "user"
	// RoleAssistant is model output, possibly with tool calls.
	RoleAssistant Role = "assistant"
	// RoleTool carries tool execution results fed back to the model.
	RoleTool Role = "tool"
)

type RunFailure

type RunFailure struct {
	Code    string `json:"code,omitempty"`
	Message string `json:"message"`
}

RunFailure is a serializable terminal failure. Error values are process-local and therefore do not belong in snapshots.

type RunIdentity

type RunIdentity struct {
	RunKey    string `json:"run_key"`
	AgentKey  string `json:"agent_key"`
	SessionID string `json:"session_id"`
	RequestID string `json:"request_id"`
}

RunIdentity contains caller-assigned immutable identifiers. RunKey must be globally unique; SessionID plus RequestID should also uniquely identify a run.

type RunPhase

type RunPhase string

RunPhase identifies the next durable boundary. Inflight phases do not prove that an external operation did or did not happen; they only record intent.

const (
	RunPhaseModelReady    RunPhase = "model_ready"
	RunPhaseModelInflight RunPhase = "model_inflight"
	RunPhaseToolsReady    RunPhase = "tools_ready"
	RunPhaseToolInflight  RunPhase = "tool_inflight"
	RunPhaseFinalizing    RunPhase = "finalizing"
	RunPhaseTerminal      RunPhase = "terminal"
)

type RunRequest

type RunRequest struct {
	Messages           []Message           `json:"messages"`
	ToolChoice         *ToolChoice         `json:"tool_choice,omitempty"`
	StepPolicy         StepPolicy          `json:"-"`
	ObservationEmitter *ObservationEmitter `json:"-"`
	DurableRun         *DurableRunConfig   `json:"-"`
}

RunRequest contains v2 runtime inputs. Messages are copied and never mutated.

type RunResult

type RunResult struct {
	// Messages contains the messages added during this run (assistant / tool),
	// for the application to persist.
	Messages []Message `json:"messages"`
	// Steps contains per-step details.
	Steps []StepResult `json:"steps"`
	// Usage is the accumulated usage for this run.
	Usage Usage `json:"usage"`
	// Text is the final answer text (the text of the last step).
	Text string `json:"text"`
	// StopReason explains why the run ended, for tuning and troubleshooting.
	StopReason StopReason `json:"stop_reason"`
	// ModelName is the model actually used.
	ModelName string `json:"model_name,omitempty"`
	// Outcome distinguishes complete answers, resumable interruption, and failure.
	Outcome Outcome `json:"outcome"`
	// DurableCompletion authorizes the domain owner to atomically finalize a
	// completed durable run with its own records. It is nil for ordinary runs.
	DurableCompletion *DurableCompletion `json:"-"`
	// DurableFailure authorizes the domain owner to atomically finalize a
	// permanent runtime failure with its own record.
	DurableFailure    *DurableFailure    `json:"-"`
	DurableSuspension *DurableSuspension `json:"-"`
	DurableFence      uint64             `json:"-"`
}

RunResult is the result of one Run.

type RunSnapshot

type RunSnapshot struct {
	SchemaVersion int         `json:"schema_version"`
	Identity      RunIdentity `json:"identity"`
	InputDigest   string      `json:"input_digest"`
	ConfigDigest  string      `json:"config_digest"`
	Status        RunStatus   `json:"status"`
	Phase         RunPhase    `json:"phase"`
	Revision      uint64      `json:"revision"`
	FenceToken    uint64      `json:"fence_token"`
	LeaseOwner    string      `json:"lease_owner,omitempty"`
	LeaseUntil    time.Time   `json:"lease_until,omitempty"`
	Checkpoint    Checkpoint  `json:"checkpoint"`
	Failure       *RunFailure `json:"failure,omitempty"`
}

RunSnapshot is the persistence-neutral serialized form of a durable run. Revision is incremented by every successful mutation. FenceToken is incremented by every successful Acquire and never decreases. LeaseUntil is advisory for acquisition; authorization of writes always requires the exact LeaseOwner, FenceToken, and Revision tuple.

func UnmarshalRunSnapshot

func UnmarshalRunSnapshot(data []byte) (RunSnapshot, error)

UnmarshalRunSnapshot rejects old and future schemas before state is resumed.

func (RunSnapshot) Clone

func (snapshot RunSnapshot) Clone() RunSnapshot

Clone returns a deep copy suitable for crossing a store or observer boundary.

func (RunSnapshot) Guard

func (snapshot RunSnapshot) Guard() MutationGuard

Guard returns the write authority represented by a leased snapshot.

type RunStatus

type RunStatus string

RunStatus is the durable ownership and terminal lifecycle of one run.

const (
	RunStatusClaimed   RunStatus = "claimed"
	RunStatusRunning   RunStatus = "running"
	RunStatusSuspended RunStatus = "suspended"
	RunStatusCompleted RunStatus = "completed"
	RunStatusFailed    RunStatus = "failed"
	RunStatusAbandoned RunStatus = "abandoned"
)

type RuntimeDefinition

type RuntimeDefinition struct {
	// contains filtered or unexported fields
}

RuntimeDefinition is a complete immutable runtime composition artifact.

func NewRuntimeDefinition

func NewRuntimeDefinition(spec RuntimeDefinitionSpec, model Model, tools *ToolSet) (*RuntimeDefinition, error)

NewRuntimeDefinition validates and snapshots a complete runtime composition.

func (*RuntimeDefinition) ArtifactVersions

func (d *RuntimeDefinition) ArtifactVersions() ArtifactVersions

func (*RuntimeDefinition) ExecutionSettings

func (d *RuntimeDefinition) ExecutionSettings() ExecutionSettings

func (*RuntimeDefinition) Key

func (d *RuntimeDefinition) Key() string

func (*RuntimeDefinition) ModelMetadata

func (d *RuntimeDefinition) ModelMetadata() ModelMetadata

func (*RuntimeDefinition) NewAgent

func (d *RuntimeDefinition) NewAgent() (*Agent, error)

NewAgent creates a stateless runner that retains this definition's snapshots.

func (*RuntimeDefinition) ToolDefinitions

func (d *RuntimeDefinition) ToolDefinitions() []ToolDefinition

type RuntimeDefinitionSpec

type RuntimeDefinitionSpec struct {
	Key           string            `json:"key"`
	Model         ModelMetadata     `json:"model"`
	Execution     ExecutionSettings `json:"execution"`
	PromptVersion string            `json:"prompt_version"`
	PolicyVersion string            `json:"policy_version"`
}

RuntimeDefinitionSpec is the validated value input to an immutable definition.

type Session

type Session struct {
	ID        uint          `json:"id"`
	UserID    uint          `json:"user_id"`
	AgentKey  string        `json:"agent_key"`
	Identity  string        `json:"identity,omitempty"`
	Status    SessionStatus `json:"status"`
	ModelName string        `json:"model_name,omitempty"`
	Metadata  string        `json:"metadata,omitempty"`
	Usage     Usage         `json:"usage"`
}

Session is the persistence-neutral runtime session representation.

type SessionStatus

type SessionStatus string

SessionStatus is the generic runtime session lifecycle.

const (
	SessionActive    SessionStatus = "active"
	SessionFinished  SessionStatus = "finished"
	SessionFailed    SessionStatus = "failed"
	SessionAbandoned SessionStatus = "abandoned"
)

type SessionStore

type SessionStore interface {
	CreateSession(ctx context.Context, session Session) error
	GetSession(ctx context.Context, sessionID uint) (Session, error)
	UpdateSessionStatus(ctx context.Context, sessionID uint, status SessionStatus) error
	AddUsage(ctx context.Context, sessionID uint, usage Usage) error
}

SessionStore persists generic runtime sessions and their token usage.

type StepPolicy

type StepPolicy func(StepPolicyInput) (StepPolicyDecision, error)

StepPolicy is a pure request-selection function. Implementations receive copies and cannot replace the Agent's Model or mutate conversation history.

type StepPolicyDecision

type StepPolicyDecision struct {
	ActiveTools []string          `json:"active_tools,omitempty"`
	ToolChoice  *ToolChoice       `json:"tool_choice,omitempty"`
	Model       string            `json:"model,omitempty"`
	Generation  GenerationOptions `json:"generation"`
}

StepPolicyDecision may shape only the next model request.

type StepPolicyInput

type StepPolicyInput struct {
	CompletedSteps []StepResult     `json:"completed_steps"`
	AvailableTools []ToolDefinition `json:"available_tools"`
}

StepPolicyInput is an immutable snapshot of completed execution state.

type StepResult

type StepResult struct {
	// StepNumber is the zero-based step index.
	StepNumber int `json:"step_number"`
	// Message is the assistant message produced in this step.
	Message Message `json:"message"`
	// ToolCalls are the tool calls made in this step.
	ToolCalls []ToolCall `json:"tool_calls,omitempty"`
	// ToolResults are this step's tool execution results, paired with
	// ToolCalls by ToolCallID.
	ToolResults []ToolResult `json:"tool_results,omitempty"`
	// Usage is the usage for this step.
	Usage Usage `json:"usage"`
	// FinishReason is the reason this step stopped.
	FinishReason FinishReason `json:"finish_reason,omitempty"`
}

StepResult is the result of one step (one model call plus its tool executions).

type StopCondition

type StopCondition = func(steps []StepResult) bool

StopCondition decides whether the loop should end. Conditions are composable and stack: any match stops the run.

func AnyStopCondition

func AnyStopCondition(conds ...StopCondition) StopCondition

AnyStopCondition merges several conditions into one: any match stops the run.

func HasToolCall

func HasToolCall(name string) StopCondition

HasToolCall stops once any step has called the named tool.

func MaxTokensUsed

func MaxTokensUsed(max int) StopCondition

MaxTokensUsed stops when accumulated token usage reaches max.

func StepCountIs

func StepCountIs(n int) StopCondition

StepCountIs stops when the step count reaches n.

type StopReason

type StopReason string

StopReason is the reason a run ended.

const (
	// StopReasonComplete means the model stopped calling tools and finished normally.
	StopReasonComplete StopReason = "complete"
	// StopReasonMaxSteps means the maximum step count forced the run to end.
	StopReasonMaxSteps StopReason = "max_steps"
	// StopReasonStopCondition means a stop condition matched.
	StopReasonStopCondition StopReason = "stop_condition"
	// StopReasonToolStopTurn means a tool requested an immediate end of turn.
	StopReasonToolStopTurn StopReason = "tool_stop_turn"
	// StopReasonLoopDetected means a tool call loop was detected.
	StopReasonLoopDetected StopReason = "loop_detected"
	// StopReasonContextBudget means the context budget was exhausted.
	StopReasonContextBudget StopReason = "context_budget"
	// StopReasonOutputLimit indicates the provider reached its generation limit.
	StopReasonOutputLimit StopReason = "output_limit"
)

type Store

type Store interface {
	SessionStore
	MessageStore
}

Store is the complete persistence boundary used by agent services.

type StreamChunk

type StreamChunk struct {
	Type ChunkType `json:"type"`
	// TextDelta is valid only when Type=ChunkText.
	TextDelta string `json:"text_delta,omitempty"`
	// ToolCall is valid only when Type=ChunkToolCall; its input is fully assembled.
	ToolCall *ToolCall `json:"tool_call,omitempty"`
	// Response is valid only when Type=ChunkFinish; it carries the complete
	// message and normalized usage.
	Response *Response `json:"response,omitempty"`
	// Err is valid only when Type=ChunkError. It carries the upstream error
	// as-is and must never be swallowed.
	Err error `json:"-"`
}

StreamChunk is one incremental fragment of a streamed response. Adapters are responsible for assembling upstream fragments (OpenAI groups by index, Anthropic buffers input_json_delta per content_block) into a complete ToolCall before emitting ChunkToolCall.

type TenantKey

type TenantKey string

TenantKey is an opaque tenant identity shared by Agent SDK packages. Portable SDK code may compare and persist it, but must not interpret its value.

func (TenantKey) Valid

func (k TenantKey) Valid() bool

Valid reports whether the key can scope a persisted SDK operation.

type Tool

type Tool interface {
	// Definition returns the model-visible declaration.
	Definition() ToolDefinition
	// ReplayPolicy declares recovery behavior after an ambiguous side effect.
	ReplayPolicy() ReplayPolicy
	// Execute returns IsError for model-correctable failures. A non-nil Go error
	// is fatal to the attempt and retains its cause.
	Execute(ctx context.Context, invocation ToolInvocation) (ToolResult, error)
}

Tool is a tool the model can call. Implementations belong to the consuming application; the runtime only uses this interface.

type ToolCall

type ToolCall struct {
	// ID is the upstream call identifier, used to pair with a ToolResult.
	ID string `json:"id"`
	// Name is the tool name.
	Name string `json:"name"`
	// Input is the raw input JSON. It is not parsed eagerly: it may be invalid,
	// and the error is fed back so the model can correct itself.
	Input string `json:"input"`
}

ToolCall is one tool call initiated by the model.

type ToolChoice

type ToolChoice struct {
	Mode ToolChoiceMode `json:"mode"`
	Name string         `json:"name,omitempty"`
}

ToolChoice selects whether, and which, tool a model may call.

func (ToolChoice) Validate

func (c ToolChoice) Validate(tools []ToolDefinition, caps Capabilities) error

Validate checks choice shape, active tools, and model support.

type ToolChoiceMode

type ToolChoiceMode string

ToolChoiceMode is the portable tool selection mode.

const (
	ToolChoiceAuto     ToolChoiceMode = "auto"
	ToolChoiceNone     ToolChoiceMode = "none"
	ToolChoiceRequired ToolChoiceMode = "required"
	ToolChoiceNamed    ToolChoiceMode = "named"
)

type ToolDefinition

type ToolDefinition struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	// Parameters is a JSON Schema in object form; adapters convert it to the
	// structure the upstream provider requires.
	Parameters map[string]any `json:"parameters"`
	// Strict rejects properties not declared by an object schema unless the
	// schema already specifies its own additionalProperties behavior.
	Strict bool `json:"strict,omitempty"`
}

ToolDefinition is the tool declaration sent to the model.

type ToolExecution

type ToolExecution struct {
	RunKey         string              `json:"run_key"`
	StepNumber     int                 `json:"step_number"`
	Ordinal        int                 `json:"ordinal"`
	ToolCall       ToolCall            `json:"tool_call"`
	IdempotencyKey string              `json:"idempotency_key"`
	InputHash      string              `json:"input_hash"`
	Status         ToolExecutionStatus `json:"status"`
	Result         *ToolResult         `json:"result,omitempty"`
}

ToolExecution is one durable tool-call ledger entry. IdempotencyKey and InputHash are fixed at preparation and must never be regenerated from mutable process state.

func NewToolExecution

func NewToolExecution(identity RunIdentity, stepNumber, ordinal int, call ToolCall) (ToolExecution, error)

NewToolExecution creates a prepared ledger record for raw tool input. Runtime schema validation remains in the shared execution path.

type ToolExecutionStatus

type ToolExecutionStatus string

ToolExecutionStatus records the durable side-effect ledger lifecycle.

const (
	ToolExecutionPrepared  ToolExecutionStatus = "prepared"
	ToolExecutionExecuting ToolExecutionStatus = "executing"
	ToolExecutionCompleted ToolExecutionStatus = "completed"
	// Unknown means execution may have produced an effect but no result was
	// durably committed. It must not be automatically replayed unless the tool's
	// system deduplicates or resolves the same idempotency key.
	ToolExecutionUnknown ToolExecutionStatus = "unknown"
)

type ToolInvocation

type ToolInvocation struct {
	CallID       string `json:"call_id"`
	Name         string `json:"name"`
	RawInput     string `json:"raw_input"`
	ExecutionKey string `json:"execution_key,omitempty"`
}

type ToolOption

type ToolOption func(*toolOptions)

ToolOption customizes a FuncTool created by NewTool.

func WithToolExecutableVersion

func WithToolExecutableVersion(version string) ToolOption

WithToolExecutableVersion declares the implementation version used by durable artifact digests. Tools that never participate in durable exact restoration can omit it.

func WithToolReplayPolicy

func WithToolReplayPolicy(policy ReplayPolicy) ToolOption

WithToolReplayPolicy sets the replay policy. The default is ReplayPolicyNever, the safest choice for tools with side effects.

func WithoutStrictSchema

func WithoutStrictSchema() ToolOption

WithoutStrictSchema disables the strict schema default, allowing the model to send properties that are not declared on T.

type ToolResult

type ToolResult struct {
	// ToolCallID references the matching ToolCall.ID.
	ToolCallID string `json:"tool_call_id"`
	// Name is the tool name, useful for logs and events.
	Name string `json:"name"`
	// Content is the result text fed back to the model. Serialize structured
	// results to a JSON string yourself.
	Content string `json:"content"`
	// IsError marks the result as an error (invalid input, unavailable tool,
	// or execution failure). Errors are also fed back to the model so it can
	// change course or correct itself.
	IsError bool `json:"is_error,omitempty"`
	// StopTurn, when true, ends the turn immediately without another step.
	StopTurn bool `json:"stop_turn,omitempty"`
}

ToolResult is the execution result of one tool call.

type ToolSet

type ToolSet struct {
	// contains filtered or unexported fields
}

ToolSet is an immutable snapshot of the tools available to an agent.

func NewToolSet

func NewToolSet(registry *Registry, allowed []string) (*ToolSet, error)

NewToolSet builds a tool set from an allowlist. A nil allowed slice means no restriction; an empty slice allows no tools. A name that is allowlisted but not registered returns ErrToolNotFound: exposing the configuration error at assembly time beats letting the model hit an unavailable tool at runtime.

func (*ToolSet) Allowed

func (s *ToolSet) Allowed(name string) bool

Allowed reports whether the tool is on the allowlist.

func (*ToolSet) Definitions

func (s *ToolSet) Definitions() []ToolDefinition

Definitions returns the tool declarations sent to the model, sorted by name so requests stay reproducible.

func (*ToolSet) Get

func (s *ToolSet) Get(name string) (Tool, error)

Get returns an allowlisted tool. If the tool exists but is not allowlisted, it returns ErrToolNotAllowed; callers feed a "tool unavailable" result back to the model instead of aborting the run.

func (*ToolSet) Subset

func (s *ToolSet) Subset(names []string) (*ToolSet, error)

Subset returns a tool set restricted to names already available in s.

func (*ToolSet) ValidateExecutableVersions

func (s *ToolSet) ValidateExecutableVersions() error

ValidateExecutableVersions rejects snapshots that cannot safely participate in durable exact restoration. Ordinary non-durable ToolSets may omit this optional capability.

func (*ToolSet) Version

func (s *ToolSet) Version() string

Version returns the deterministic digest of definitions, replay policies, and declared executable implementation versions.

type Usage

type Usage struct {
	PromptTokens        int `json:"prompt_tokens"`
	CompletionTokens    int `json:"completion_tokens"`
	TotalTokens         int `json:"total_tokens"`
	ReasoningTokens     int `json:"reasoning_tokens,omitempty"`
	CacheCreationTokens int `json:"cache_creation_tokens,omitempty"`
	CacheReadTokens     int `json:"cache_read_tokens,omitempty"`
}

Usage is normalized token usage.

func (*Usage) Add

func (u *Usage) Add(other Usage)

Add accumulates another usage sample, used to total usage across steps.

func (Usage) InputTokens

func (u Usage) InputTokens() int

InputTokens returns the complete current-request context occupancy.

func (Usage) Validate

func (u Usage) Validate() error

Validate checks the normalized usage contract. PromptTokens excludes cache categories; TotalTokens includes prompt, completion, cache creation and cache read.

Directories

Path Synopsis
Package agenttest provides reusable conformance tests for agent adapters.
Package agenttest provides reusable conformance tests for agent adapters.
Package app coordinates Agent runtime component readiness and shutdown ordering.
Package app coordinates Agent runtime component readiness and shutdown ordering.
cmd
docs command
Package context prepares immutable, revision-bound provider context plans.
Package context prepares immutable, revision-bound provider context plans.
Package coordinator resolves selectors into immutable executable agent definitions while persisting only canonical data manifests.
Package coordinator resolves selectors into immutable executable agent definitions while persisting only canonical data manifests.
Package durable provides persistence-neutral durable execution contracts and a thread-safe in-memory reference implementation.
Package durable provides persistence-neutral durable execution contracts and a thread-safe in-memory reference implementation.
Package event defines portable Agent event, outbox, delivery, and replay contracts.
Package event defines portable Agent event, outbox, delivery, and replay contracts.
examples
hello command
openai-compat command
Command openai-compat runs one real model/tool loop against any OpenAI-compatible endpoint using the official providers/openaicompat adapter and a tool generated with agent.NewTool.
Command openai-compat runs one real model/tool loop against any OpenAI-compatible endpoint using the official providers/openaicompat adapter and a tool generated with agent.NewTool.
tool-agent command
Package mcp provides a tenant-scoped MCP capability runtime.
Package mcp provides a tenant-scoped MCP capability runtime.
Package message owns the portable persisted message aggregate contract.
Package message owns the portable persisted message aggregate contract.
Package permission provides portable effect authorization and durable approval contracts.
Package permission provides portable effect authorization and durable approval contracts.
Package prompt provides side-effect-free prompt compilation and rendering.
Package prompt provides side-effect-free prompt compilation and rendering.
Package provider defines provider-neutral model catalogs and factories.
Package provider defines provider-neutral model catalogs and factories.
providers
openaicompat
Package openaicompat provides an agent.Model adapter for OpenAI-compatible chat completion APIs, including OpenAI, DeepSeek, Qwen, Kimi, vLLM, and Ollama's OpenAI endpoint.
Package openaicompat provides an agent.Model adapter for OpenAI-compatible chat completion APIs, including OpenAI, DeepSeek, Qwen, Kimi, vLLM, and Ollama's OpenAI endpoint.
Package session owns the portable session aggregate and branch contracts.
Package session owns the portable session aggregate and branch contracts.
Package skills provides a tenant-scoped, immutable catalog of untrusted instruction content.
Package skills provides a tenant-scoped, immutable catalog of untrusted instruction content.
Package subagent orchestrates independent durable child runs.
Package subagent orchestrates independent durable child runs.
Package tool provides the production lifecycle for local agent tools.
Package tool provides the production lifecycle for local agent tools.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL