Documentation
¶
Overview ¶
Package exp provides experimental AI primitives for Genkit.
APIs in this package are under active development and may change in any minor version release.
Index ¶
- func ApplyPatch(document any, patch JSONPatch) (any, error)
- func NewSessionContext[State any](ctx context.Context, s *Session[State]) context.Context
- func ValidateResumeAgainstHistory(resume *ToolResume, history []*ai.Message) error
- type Agent
- func DefineAgent[State any](r api.Registry, name string, prompt InlinePrompt, opts ...AgentOption[State]) *Agent[State]
- func DefineCustomAgent[State any](r api.Registry, name string, fn AgentFunc[State], opts ...AgentOption[State]) *Agent[State]
- func DefinePromptAgent[State any](r api.Registry, name string, opts ...PromptAgentOption[State]) *Agent[State]
- func NewCustomAgent[State any](name string, fn AgentFunc[State], opts ...AgentOption[State]) *Agent[State]
- func (a *Agent[State]) Abort(ctx context.Context, snapshotID string) (SnapshotStatus, error)
- func (a *Agent[State]) AbortAction() api.Action
- func (a *Agent[State]) Connect(ctx context.Context, opts ...InvocationOption[State]) (*AgentConnection[State], error)
- func (a *Agent[State]) ConnectJSON(ctx context.Context, opts *api.BidiJSONOptions) (api.BidiJSONConnection, error)
- func (a *Agent[State]) Desc() api.ActionDesc
- func (a *Agent[State]) GetLatestSnapshot(ctx context.Context, sessionID string) (*SessionSnapshot[State], error)
- func (a *Agent[State]) GetSnapshot(ctx context.Context, snapshotID string) (*SessionSnapshot[State], error)
- func (a *Agent[State]) GetSnapshotAction() api.Action
- func (a *Agent[State]) Name() string
- func (a *Agent[State]) Ref() AgentRef
- func (a *Agent[State]) Register(r api.Registry)
- func (a *Agent[State]) Run(ctx context.Context, input *AgentInput, opts ...InvocationOption[State]) (*AgentOutput[State], error)
- func (a *Agent[State]) RunBidiJSON(ctx context.Context, input json.RawMessage, ...) (*api.ActionRunResult[json.RawMessage], error)
- func (a *Agent[State]) RunJSON(ctx context.Context, input json.RawMessage, ...) (json.RawMessage, error)
- func (a *Agent[State]) RunJSONWithTelemetry(ctx context.Context, input json.RawMessage, ...) (*api.ActionRunResult[json.RawMessage], error)
- func (a *Agent[State]) RunText(ctx context.Context, text string, opts ...InvocationOption[State]) (*AgentOutput[State], error)
- func (a *Agent[State]) Store() SessionStore[State]
- type AgentAbortRequest
- type AgentAbortResponse
- type AgentConnection
- func (c *AgentConnection[State]) Close() error
- func (c *AgentConnection[State]) Custom() (State, error)
- func (c *AgentConnection[State]) Detach() error
- func (c *AgentConnection[State]) Done() <-chan struct{}
- func (c *AgentConnection[State]) Output() (*AgentOutput[State], error)
- func (c *AgentConnection[State]) Receive() iter.Seq2[*AgentStreamChunk, error]
- func (c *AgentConnection[State]) Send(input *AgentInput) error
- func (c *AgentConnection[State]) SendMessage(message *ai.Message) error
- func (c *AgentConnection[State]) SendResume(resume *ToolResume) error
- func (c *AgentConnection[State]) SendText(text string) error
- type AgentFinishReason
- type AgentFunc
- type AgentInit
- type AgentInput
- type AgentMetadata
- type AgentOption
- func WithDescription[State any](description string) AgentOption[State]
- func WithSessionStore[State any](store SessionStore[State]) AgentOption[State]
- func WithStateTransform[State any](transform StateTransform[State]) AgentOption[State]
- func WithStreamTransform[State any](transform StreamTransform) AgentOption[State]
- type AgentOutput
- type AgentRef
- type AgentResult
- type AgentStateManagement
- type AgentStreamChunk
- type Artifact
- type ArtifactStore
- type GetSnapshotRequest
- type InlinePrompt
- type InterruptibleTool
- type InterruptibleToolFunc
- type InvocationOption
- type JSONPatch
- type JSONPatchOp
- type JSONPatchOperation
- type PromptAgentOption
- type Responder
- type Session
- func (s *Session[State]) AddArtifacts(artifacts ...*Artifact)
- func (s *Session[State]) AddMessages(messages ...*ai.Message)
- func (s *Session[State]) Artifacts() []*Artifact
- func (s *Session[State]) Custom() State
- func (s *Session[State]) Messages() []*ai.Message
- func (s *Session[State]) SessionID() string
- func (s *Session[State]) SetMessages(messages []*ai.Message)
- func (s *Session[State]) State() *SessionState[State]
- func (s *Session[State]) UpdateArtifacts(fn func([]*Artifact) []*Artifact)
- func (s *Session[State]) UpdateCustom(fn func(State) State)
- func (s *Session[State]) UpdateMessages(fn func([]*ai.Message) []*ai.Message)
- type SessionRunner
- type SessionSnapshot
- type SessionState
- type SessionStore
- type SnapshotReader
- type SnapshotStatus
- type SnapshotSubscriber
- type SnapshotWriter
- type StateTransform
- type StreamTransform
- type Tool
- func (t *Tool[In, Out]) Definition() *ai.ToolDefinition
- func (t *Tool[In, Out]) Name() string
- func (t *Tool[In, Out]) Register(r api.Registry)
- func (t *Tool[In, Out]) Respond(toolReq *ai.Part, outputData any, opts *ai.RespondOptions) *ai.Part
- func (t *Tool[In, Out]) Restart(toolReq *ai.Part, opts *ai.RestartOptions) *ai.Part
- func (t *Tool[In, Out]) RunRaw(ctx context.Context, input any) (any, error)
- func (t *Tool[In, Out]) RunRawMultipart(ctx context.Context, input any) (*ai.MultipartToolResponse, error)
- type ToolFunc
- type ToolResume
- type TurnContext
- type TurnEnd
- type TurnResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyPatch ¶
ApplyPatch applies an RFC 6902 JSON Patch to document and returns the new value. The input is not mutated; a normalized clone is patched and returned. Operating on the root pointer ("") replaces or removes the whole document.
It is lenient to keep streaming robust: an add or replace whose parent container is missing initializes it as an object, and a remove or replace of a missing member is a no-op. A test operation is honored and returns an error on mismatch. Other unknown operations also return an error.
func NewSessionContext ¶
NewSessionContext returns a new context with the session attached.
It also publishes a type-erased view of the session's custom state so prompt rendering can inject it into templates as {{@state}}. go/ai cannot import this package (this package imports go/ai), so the custom state is exposed through a getter in internal/base, evaluated at render time so templates see the latest values.
func ValidateResumeAgainstHistory ¶
func ValidateResumeAgainstHistory(resume *ToolResume, history []*ai.Message) error
ValidateResumeAgainstHistory ensures every restart and respond entry on a resume payload references a tool request the model actually issued, so a caller cannot drive a tool the model never asked for and interrupted on. For restart entries it additionally checks the input is unchanged from the original request, preventing a client from forging tool inputs on the interrupted call. The whole history is searched (every model message), not just the last turn. On a violation it returns an INVALID_ARGUMENT error.
The prompt-backed agent loop (DefineAgent) calls this automatically. A custom agent (DefineCustomAgent) that accepts an AgentInput.Resume from untrusted callers should call it before forwarding the payload to the model:
if input.Resume != nil {
if err := ValidateResumeAgainstHistory(input.Resume, sess.Messages()); err != nil {
return nil, err
}
}
Types ¶
type Agent ¶
type Agent[State any] struct { // contains filtered or unexported fields }
Agent is a bidirectional streaming agent with automatic snapshot management.
Agent implements api.BidiAction, so generic transports accept it directly (e.g. pass it to genkit.Handler to serve it over HTTP, one turn per request). Agent.Run, Agent.RunText, and Agent.Connect are typed conveniences over the same underlying action.
Server-managed agents (those with a SessionStore configured) also register companion actions for the snapshot lifecycle, available via Agent.GetSnapshotAction and Agent.AbortAction for serving alongside the agent, and expose the store itself via Agent.Store.
func DefineAgent ¶
func DefineAgent[State any]( r api.Registry, name string, prompt InlinePrompt, opts ...AgentOption[State], ) *Agent[State]
DefineAgent defines an agent backed by an inline prompt and registers it. The prompt is defined from prompt's ai.PromptOption values and registered under the agent's name; each turn renders it, appends conversation history, calls the model with streaming, and updates session state.
The prompt is an InlinePrompt, a list of ai.PromptOption values:
agent := DefineAgent(r, "pirate",
InlinePrompt{
ai.WithModelName("googleai/gemini-flash-latest"),
ai.WithSystem("You are a sarcastic pirate."),
},
WithSessionStore(store),
)
State is inferred from the typed agent options (e.g. WithSessionStore, WithStateTransform); pass an explicit [State] only when no typed option is provided. A typed option that disagrees with the inferred State fails at compile time.
To back an agent with a prompt already in the registry (e.g. one from a .prompt file), use DefinePromptAgent. For full control over the per-turn loop, use DefineCustomAgent.
func DefineCustomAgent ¶
func DefineCustomAgent[State any]( r api.Registry, name string, fn AgentFunc[State], opts ...AgentOption[State], ) *Agent[State]
DefineCustomAgent defines an agent with full control over the conversation loop and registers it (and any companion actions) with the registry. fn receives a Responder for streaming output and a SessionRunner for turn and state management; call SessionRunner.Run to enter the per-turn loop.
It is NewCustomAgent followed by Agent.Register. To build an agent without registering it, use NewCustomAgent directly. For agents backed by a prompt, use DefineAgent instead.
func DefinePromptAgent ¶
func DefinePromptAgent[State any]( r api.Registry, name string, opts ...PromptAgentOption[State], ) *Agent[State]
DefinePromptAgent defines a prompt-backed agent and registers it, sourcing its prompt from the registry by name. Each turn renders the prompt, appends conversation history, calls the model with streaming, and updates session state, exactly like DefineAgent.
By default the agent uses the prompt registered under its own name (e.g. one defined via ai.DefinePrompt or loaded from a .prompt file), so no source option is required. Pass WithNamedPrompt to reference a differently named prompt and supply its render input from code, so a single prompt can back many agents.
It is the registry-backed counterpart of DefineAgent: where DefineAgent defines the prompt inline, DefinePromptAgent points at a prompt already in the registry. The prompt source is a typed option (WithNamedPrompt) rather than a positional argument, so it composes with the other agent options (WithSessionStore, WithStateTransform, WithStreamTransform, WithDescription) in a single variadic. For full control over the per-turn loop, use DefineCustomAgent.
State is inferred from the typed agent options; pass an explicit [State] only when no typed option provides it (e.g. only WithNamedPrompt and WithDescription, whose State cannot be deduced from their arguments).
func NewCustomAgent ¶
func NewCustomAgent[State any]( name string, fn AgentFunc[State], opts ...AgentOption[State], ) *Agent[State]
NewCustomAgent creates an agent with full control over the conversation loop without registering it. Register it later with the registry (e.g. genkit.RegisterAction), which also registers its companion actions; see Agent.Register. fn receives a Responder for streaming output and a SessionRunner for turn and state management; call SessionRunner.Run to enter the per-turn loop.
This is the agent counterpart of core.NewStreamingAction: use it when the agent must outlive or precede a registry (e.g. built in a library, registered conditionally, or moved between registries). For the common case, DefineCustomAgent creates and registers in one step.
There is no NewAgent for prompt-backed agents: a prompt is bound to the registry it renders against, so it cannot be built before one exists. For prompt-like behavior without registration, render and generate with your own [genkit.Genkit] inside a custom fn.
func (*Agent[State]) Abort ¶
Abort aborts the detached invocation behind a pending snapshot by flipping it to SnapshotStatusAborted; the runtime observes the flip and cancels the background work. A caller that has only a store (no agent) aborts through the abort companion action instead. It is a no-op on a missing snapshot (returns "") or an already-terminal one (returns the existing status).
It returns FAILED_PRECONDITION on a client-managed agent and INVALID_ARGUMENT when snapshotID is empty.
func (*Agent[State]) AbortAction ¶
AbortAction returns the agent's abort companion action, which asks the background work behind a pending snapshot (e.g. a detached invocation) to stop (input AgentAbortRequest, output AgentAbortResponse). It returns nil when the agent has no SessionStore or the store does not implement SnapshotSubscriber.
Use it to expose aborting over a transport (e.g. mount it with genkit.Handler next to the agent itself); local Go code aborts with Agent.Abort; a store-only caller uses this companion action.
func (*Agent[State]) Connect ¶
func (a *Agent[State]) Connect( ctx context.Context, opts ...InvocationOption[State], ) (*AgentConnection[State], error)
Connect starts a new agent invocation with bidirectional streaming. Use this for multi-turn interactions where you need to send multiple inputs and receive streaming chunks. For single-turn usage, see Run and RunText.
func (*Agent[State]) ConnectJSON ¶
func (a *Agent[State]) ConnectJSON(ctx context.Context, opts *api.BidiJSONOptions) (api.BidiJSONConnection, error)
ConnectJSON starts a bidirectional streaming session using JSON-encoded messages. Local Go callers should prefer the typed Agent.Connect.
func (*Agent[State]) Desc ¶
func (a *Agent[State]) Desc() api.ActionDesc
Desc returns the descriptor of the agent's run action.
func (*Agent[State]) GetLatestSnapshot ¶
func (a *Agent[State]) GetLatestSnapshot(ctx context.Context, sessionID string) (*SessionSnapshot[State], error)
GetLatestSnapshot fetches a session's most recently created snapshot (whatever its status) through the agent, with the same transform and shaping as Agent.GetSnapshot. It is the transform-applying counterpart to SnapshotReader.GetLatestSnapshot and backs resume-by-session lookups.
It returns FAILED_PRECONDITION on a client-managed agent and INVALID_ARGUMENT when sessionID is empty; an unknown session is NOT_FOUND.
func (*Agent[State]) GetSnapshot ¶
func (a *Agent[State]) GetSnapshot(ctx context.Context, snapshotID string) (*SessionSnapshot[State], error)
GetSnapshot fetches a session snapshot by ID through the agent, applying the configured WithStateTransform and the same read-time shaping the getSnapshot companion action performs (a stale-heartbeat pending row is surfaced as SnapshotStatusExpired; an empty status or zero UpdatedAt is defaulted). Prefer it to reading Agent.Store directly, which returns raw, untransformed state.
It returns FAILED_PRECONDITION on a client-managed agent (no store) and INVALID_ARGUMENT when snapshotID is empty; a missing snapshot is NOT_FOUND.
func (*Agent[State]) GetSnapshotAction ¶
GetSnapshotAction returns the agent's getSnapshot companion action, which fetches a session snapshot by ID (input GetSnapshotRequest, output SessionSnapshot). It returns nil when the agent is client-managed (no SessionStore configured): there is no server-side snapshot to fetch.
Use it to expose snapshot polling over a transport (e.g. mount it with genkit.Handler next to the agent itself); local Go code should use Agent.GetSnapshot, which applies the configured state transform.
func (*Agent[State]) Name ¶
Name returns the agent's registered name. This is also the name under which any inline-defined prompt and companion actions (getSnapshot, abort) are registered.
func (*Agent[State]) Ref ¶
Ref returns an AgentRef for this agent, capturing its name and description so callers can reference it without restating either, and without a name string that can drift from the agent. Resolution remains by name, so the agent must be registered (as DefineAgent does) wherever the ref is used.
func (*Agent[State]) Register ¶
Register registers the agent's run action and any companion actions (getSnapshot, abort) with the registry. Agents defined via DefineAgent or DefineCustomAgent are already registered; this exists so an agent can travel to another registry as a unit. An inline-defined prompt does not travel: the agent holds it directly, so execution is unaffected, but the prompt action stays in the registry it was defined in.
func (*Agent[State]) Run ¶
func (a *Agent[State]) Run( ctx context.Context, input *AgentInput, opts ...InvocationOption[State], ) (*AgentOutput[State], error)
Run starts a single-turn agent invocation with the given input. It sends the input, waits for the agent to complete, and returns the output. For multi-turn interactions or streaming, use Connect instead.
In-band failures (e.g. a failed turn) resolve as a failed AgentOutput rather than an error; a rejected init payload fails with an error, since the invocation never starts. See AgentConnection.Output.
func (*Agent[State]) RunBidiJSON ¶
func (a *Agent[State]) RunBidiJSON(ctx context.Context, input json.RawMessage, cb func(context.Context, json.RawMessage) error, opts *api.BidiJSONOptions) (*api.ActionRunResult[json.RawMessage], error)
RunBidiJSON runs a one-shot invocation whose session init (the wire counterpart of the InvocationOption values) rides in opts: input is delivered as the only chunk on the input stream and outgoing chunks are forwarded to cb.
func (*Agent[State]) RunJSON ¶
func (a *Agent[State]) RunJSON(ctx context.Context, input json.RawMessage, cb func(context.Context, json.RawMessage) error) (json.RawMessage, error)
RunJSON runs a one-shot invocation with no init (a fresh session): input is the turn's AgentInput and the result is the final AgentOutput. To supply a session source, use Agent.RunBidiJSON.
func (*Agent[State]) RunJSONWithTelemetry ¶
func (a *Agent[State]) RunJSONWithTelemetry(ctx context.Context, input json.RawMessage, cb func(context.Context, json.RawMessage) error) (*api.ActionRunResult[json.RawMessage], error)
RunJSONWithTelemetry is Agent.RunJSON with trace information on the result.
func (*Agent[State]) RunText ¶
func (a *Agent[State]) RunText( ctx context.Context, text string, opts ...InvocationOption[State], ) (*AgentOutput[State], error)
RunText is a convenience method that starts a single-turn agent invocation with a user text message. It is equivalent to calling Run with an AgentInput whose Message is a user text message.
func (*Agent[State]) Store ¶
func (a *Agent[State]) Store() SessionStore[State]
Store returns the SessionStore the agent was configured with via WithSessionStore, or nil when the agent is client-managed (no store).
For reads and aborts prefer the typed facade Agent.GetSnapshot, Agent.GetLatestSnapshot, and Agent.Abort: they apply the configured WithStateTransform and read-time shaping. Store exposes the raw backend for advanced use; a direct SnapshotReader.GetSnapshot returns untransformed state.
The store is returned as the SessionStore interface, not its concrete type; a caller needing a store-specific capability (e.g. SnapshotSubscriber) type-asserts for it.
type AgentAbortRequest ¶
type AgentAbortRequest struct {
// SnapshotID identifies the snapshot whose invocation should be aborted.
SnapshotID string `json:"snapshotId"`
}
AgentAbortRequest is the input for the abort companion action.
type AgentAbortResponse ¶
type AgentAbortResponse struct {
// SnapshotID identifies the snapshot the abort attempt targeted.
SnapshotID string `json:"snapshotId"`
// Status is the snapshot's status after the abort attempt. For a
// pending snapshot this is [SnapshotStatusAborted]. For an
// already-terminal snapshot this is the existing terminal status (the
// abort is a no-op).
Status SnapshotStatus `json:"status,omitempty"`
}
AgentAbortResponse is the output of the abort companion action.
type AgentConnection ¶
type AgentConnection[State any] struct { // contains filtered or unexported fields }
AgentConnection is an active agent invocation with bidirectional streaming, adding agent-specific Send helpers (SendMessage, SendText, SendResume, Detach) over the core connection.
It also tracks custom state live: as AgentConnection.Receive yields chunks, it applies each chunk's AgentStreamChunk.CustomPatch to an internal copy, exposed by AgentConnection.Custom, so callers see custom state as it streams without applying patches themselves.
func (*AgentConnection[State]) Close ¶
func (c *AgentConnection[State]) Close() error
Close signals that no more inputs will be sent.
func (*AgentConnection[State]) Custom ¶
func (c *AgentConnection[State]) Custom() (State, error)
Custom returns the conversation's custom state as tracked from the streamed patches observed via AgentConnection.Receive. It reflects the deltas consumed so far, so reading it as a turn streams shows the live state; before any patch arrives it returns the zero value. The authoritative final state is on AgentOutput.State (client-managed) or the turn-end snapshot (server-managed).
func (*AgentConnection[State]) Detach ¶
func (c *AgentConnection[State]) Detach() error
Detach asks the server to write a pending snapshot, close the connection, and continue processing any already-buffered inputs in the background. Output() returns the pending snapshot ID; the client can later call Abort to stop the background work or GetSnapshot to observe its progression. The pending snapshot is finalized with the cumulative final state once the queued inputs are processed.
Chunks emitted after detach are not forwarded over the wire, but their session-level side effects still apply: an artifact sent via Responder.SendArtifact still lands in the final snapshot's state.
To send a final input in the same wire message, call Send(&AgentInput{Detach: true, Message: ...}) directly.
func (*AgentConnection[State]) Done ¶
func (c *AgentConnection[State]) Done() <-chan struct{}
Done returns a channel closed when the connection completes.
func (*AgentConnection[State]) Output ¶
func (c *AgentConnection[State]) Output() (*AgentOutput[State], error)
Output finalizes the connection and returns the agent's result. It closes the input side, drains any chunks not consumed via Receive, and blocks until the agent finalizes. It is idempotent: later calls return the same value, and the returned pointer is shared, so treat it as read-only.
In-band failures resolve rather than error. A failed turn returns an AgentOutput with AgentFinishReasonFailed, the error on AgentOutput.Error, and the last-good state on AgentOutput.State (client-managed) or behind AgentOutput.SnapshotID (server-managed), so a failure costs only the failed turn, not the session. A detached invocation resolves with the pending snapshot ID. A non-nil error means the invocation never started (a rejected init payload) or could not run to a result (e.g. its context was cancelled).
Do not call Output concurrently with a goroutine iterating Receive; both consume the stream and would split chunks between them. Finish Receive first.
func (*AgentConnection[State]) Receive ¶
func (c *AgentConnection[State]) Receive() iter.Seq2[*AgentStreamChunk, error]
Receive returns an iterator for receiving stream chunks. Breaking out of the iterator does not cancel the connection; multi-turn callers routinely break on TurnEnd, send the next input, then call Receive again to consume the next batch. Call AgentConnection.Output to finish the invocation, or cancel the ctx passed to Connect to abort it.
Each yielded chunk's AgentStreamChunk.CustomPatch is applied to the connection's tracked custom state before the chunk is yielded, so AgentConnection.Custom reflects every delta observed so far.
func (*AgentConnection[State]) Send ¶
func (c *AgentConnection[State]) Send(input *AgentInput) error
Send sends an AgentInput to the agent. The input must not be nil.
Once the invocation has resolved (e.g. a failed turn ended it), Send fails with an error matching core.ErrActionCompleted; the outcome is on AgentConnection.Output. The same applies to the SendMessage, SendText, SendResume, and Detach helpers.
func (*AgentConnection[State]) SendMessage ¶
func (c *AgentConnection[State]) SendMessage(message *ai.Message) error
SendMessage sends a message to the agent for one turn.
func (*AgentConnection[State]) SendResume ¶
func (c *AgentConnection[State]) SendResume(resume *ToolResume) error
SendResume sends a resume payload to continue an interrupted generation. Construct the payload with ai.ToolDef.RestartWith or ai.ToolDef.RespondWith parts.
func (*AgentConnection[State]) SendText ¶
func (c *AgentConnection[State]) SendText(text string) error
SendText sends a user text message to the agent.
type AgentFinishReason ¶
type AgentFinishReason string
AgentFinishReason is why an agent turn or invocation finished.
The first group mirrors the model-level ai.FinishReason so a turn backed by a single generate call can forward its reason verbatim: AgentFinishReasonStop, AgentFinishReasonLength, AgentFinishReasonBlocked, AgentFinishReasonInterrupted, AgentFinishReasonOther and AgentFinishReasonUnknown.
The remaining values are agent-specific outcomes with no generate-level equivalent (they never arise from forwarding a model finish reason): AgentFinishReasonAborted, AgentFinishReasonDetached and AgentFinishReasonFailed.
const ( // AgentFinishReasonStop indicates the model stopped naturally. AgentFinishReasonStop AgentFinishReason = "stop" // AgentFinishReasonLength indicates generation hit the token limit. AgentFinishReasonLength AgentFinishReason = "length" // AgentFinishReasonBlocked indicates generation was blocked (e.g. safety). AgentFinishReasonBlocked AgentFinishReason = "blocked" // AgentFinishReasonInterrupted indicates the model paused on a tool request // awaiting input (e.g. human approval). The turn can be resumed by sending an // [AgentInput] with a Resume payload. AgentFinishReasonInterrupted AgentFinishReason = "interrupted" // AgentFinishReasonOther indicates generation stopped for some other reason. AgentFinishReasonOther AgentFinishReason = "other" // AgentFinishReasonUnknown indicates the reason was unspecified. AgentFinishReasonUnknown AgentFinishReason = "unknown" // AgentFinishReasonAborted indicates the turn or invocation was aborted // (e.g. a detached invocation aborted via the abort companion action). AgentFinishReasonAborted AgentFinishReason = "aborted" // AgentFinishReasonDetached indicates the invocation was moved to the // background because the client detached. The returned [AgentOutput] reports // this reason; the persisted snapshot is later finalized with how the // background work actually ended. AgentFinishReasonDetached AgentFinishReason = "detached" // AgentFinishReasonFailed indicates the turn or invocation terminated with an // error. AgentFinishReasonFailed AgentFinishReason = "failed" )
type AgentFunc ¶
type AgentFunc[State any] = func(ctx context.Context, resp Responder, sess *SessionRunner[State]) (*AgentResult, error)
AgentFunc is the function signature for custom agents. The State type parameter is the shape of the conversation's custom state (see SessionState.Custom). The agent streams output through resp and reads or mutates state through sess; mutating custom state via Session.UpdateCustom automatically streams a AgentStreamChunk.CustomPatch delta to the client.
type AgentInit ¶
type AgentInit[State any] struct { // SessionID identifies the session (conversation) to resume or start. Only // valid when the agent is server-managed (a session store is configured); // mutually exclusive with State. Alone, it resumes the session's latest // snapshot, rejected if that snapshot is a failed, aborted, or pending dead // end. If the session has no snapshots yet, a fresh conversation starts under // this caller-chosen ID. Combined with SnapshotID, it asserts the snapshot // belongs to that session. SessionID string `json:"sessionId,omitempty"` // SnapshotID loads state from a persisted snapshot. Only valid when the // agent is server-managed (a session store is configured). May be // combined with SessionID to validate that the snapshot belongs to that // session. Mutually exclusive with State. SnapshotID string `json:"snapshotId,omitempty"` // State provides direct state for the invocation. Only valid when the agent // is client-managed (no session store). The conversation's identity rides // inside it ([SessionState.SessionID]). Mutually exclusive with SessionID and // SnapshotID. State *SessionState[State] `json:"state,omitempty"` }
AgentInit is the input for starting an agent invocation. SessionID, SnapshotID, and State are competing conversation sources, and which are valid depends on the agent's state management:
- Server-managed state (a session store is configured): callers may use SessionID (resume the session's latest snapshot), SnapshotID (resume a specific snapshot), or both (the session ID is asserted against the snapshot); sending State is rejected.
- Client-managed state (no session store): callers may use State, which carries the conversation's identity inside it (SessionState.SessionID); sending SessionID or SnapshotID is rejected.
Sending no fields starts a fresh invocation with empty state.
type AgentInput ¶
type AgentInput struct {
// Detach signals the client will disconnect after this input is accepted. The
// server writes a pending snapshot, returns [AgentOutput] with its ID, and
// keeps processing any already-buffered inputs in the background. The pending
// snapshot is finalized with the cumulative final state once the queued inputs
// are processed (or the invocation is aborted).
Detach bool `json:"detach,omitempty"`
// Message is the user's input for this turn.
Message *ai.Message `json:"message,omitempty"`
// Resume provides options for resuming an interrupted generation.
// Construct using [ai.ToolDef.RestartWith] / [ai.ToolDef.RespondWith]
// parts. When set, the generate call resumes with these parts instead
// of treating Message as a tool response.
Resume *ToolResume `json:"resume,omitempty"`
}
AgentInput is the input sent to an agent during a conversation turn.
type AgentMetadata ¶
type AgentMetadata struct {
// Abortable reports whether the agent's invocations can be aborted
// (true when the store implements [SnapshotSubscriber]).
Abortable bool `json:"abortable,omitempty"`
// StateManagement reports who owns session state.
StateManagement AgentStateManagement `json:"stateManagement,omitempty"`
// StateSchema is the JSON schema for the agent's custom session state
// (the Custom field of [SessionState]), inferred from the agent's state
// type. It lets the Dev UI and other reflective callers render or
// validate state without the agent describing it separately. Nil when the
// state type carries no schema to infer (e.g. an unstructured any state).
StateSchema map[string]any `json:"stateSchema,omitempty"`
}
AgentMetadata is the value placed under metadata["agent"] on an agent's action descriptor. It exposes capability information so the Dev UI and other reflective callers can render the right surface (e.g. hide the Abort button when the store doesn't support it).
type AgentOption ¶
type AgentOption[State any] interface { // contains filtered or unexported methods }
AgentOption configures an agent at definition time. It is accepted by DefineAgent, DefineCustomAgent, and DefinePromptAgent as a typed variadic, so a State mismatch fails at compile time.
Every AgentOption is also a PromptAgentOption: the shared options (WithSessionStore, WithStateTransform, WithStreamTransform, WithDescription) configure all three constructors. The converse does not hold. A prompt-source option such as WithNamedPrompt is a PromptAgentOption but not an AgentOption, so passing it to DefineAgent or DefineCustomAgent is a compile-time error.
func WithDescription ¶
func WithDescription[State any](description string) AgentOption[State]
WithDescription sets a human-readable description of the agent, stored on its action descriptor (read back via Agent.Desc and shown in the Dev UI).
func WithSessionStore ¶
func WithSessionStore[State any](store SessionStore[State]) AgentOption[State]
WithSessionStore sets the store for persisting snapshots. The store must implement SnapshotReader and SnapshotWriter at minimum. Detach support also requires SnapshotSubscriber; detach attempts on a store that lacks that interface are rejected at runtime.
func WithStateTransform ¶
func WithStateTransform[State any](transform StateTransform[State]) AgentOption[State]
WithStateTransform registers a StateTransform applied to session state on its way out to a client (via the getSnapshot companion action or AgentOutput.State). Typical uses are PII redaction and stripping secrets.
func WithStreamTransform ¶
func WithStreamTransform[State any](transform StreamTransform) AgentOption[State]
WithStreamTransform registers a StreamTransform applied to every AgentStreamChunk on its way out to a client. Typical uses are redacting streamed model tokens and stripping fields a client should not receive; it is the stream-side counterpart to WithStateTransform.
A chunk is not parameterized by the state type, so State cannot be inferred from the transform and must be supplied explicitly to match the agent's, e.g. WithStreamTransform[MyState](fn).
type AgentOutput ¶
type AgentOutput[State any] struct { // Artifacts contains artifacts produced during the session. Artifacts []*Artifact `json:"artifacts,omitempty"` // Error is the structured failure information when the invocation ended in // failure (FinishReason is [AgentFinishReasonFailed]). Its Status preserves // the original error category (e.g. INVALID_ARGUMENT, FAILED_PRECONDITION, // INTERNAL) so callers can still branch on it. Nil otherwise. Error *core.GenkitError `json:"error,omitempty"` // FinishReason is why the invocation finished. It is // [AgentFinishReasonDetached] when the client detached and the work continues // in the background, or [AgentFinishReasonFailed] when the invocation ended // in failure (see [AgentOutput.Error]); otherwise it is the last turn's // reason (or the value a custom agent set on its [AgentResult]). FinishReason AgentFinishReason `json:"finishReason,omitempty"` // Message is the last model response message from the conversation. Message *ai.Message `json:"message,omitempty"` // SessionID is the ID of the session this invocation belongs to, assigned by // the framework when the invocation starts and stable across resumes. Pass it // to [WithSessionID] to resume a server-managed session; with client-managed // state it also rides inside [AgentOutput.State] ([SessionState.SessionID]). SessionID string `json:"sessionId,omitempty"` // SnapshotID is the ID of the most recent turn-end snapshot for this // invocation. Empty when no store is configured or no turn committed. When // FinishReason is [AgentFinishReasonDetached] it is the pending detach // snapshot; when [AgentFinishReasonFailed], it is the last committed turn's // snapshot (the resume point, holding state through the last successful turn // and excluding the failed turn's partial mutations). SnapshotID string `json:"snapshotId,omitempty"` // State contains the final conversation state. // Only populated when state is client-managed (no store configured). // When FinishReason is [AgentFinishReasonFailed], it is the last-good state: // everything through the last successful turn, excluding the failed turn's // partial mutations. State *SessionState[State] `json:"state,omitempty"` }
AgentOutput is the output when an agent invocation completes. It wraps AgentResult with framework-managed fields.
type AgentRef ¶
type AgentRef struct {
// Name identifies the agent, resolved as /agent/<Name>. Required.
Name string `json:"name"`
// Description is a human-readable description used by consumers that list
// agents (e.g. the agents middleware's system prompt). [Agent.Ref] fills it
// from the agent's descriptor. Optional.
Description string `json:"description,omitempty"`
}
AgentRef refers to an agent by name, optionally carrying a description. It is the agent analog of ai.ModelRef / ai.ToolRef: a small, JSON-serializable value that names an agent for resolution against a registry. Like those, it resolves by name (the path the Dev UI, HTTP serving, and ListAgents all use), so the referenced agent must be registered wherever the ref is consumed.
Build one by name with a struct literal, or derive it from an agent value with Agent.Ref, which fills in the name and description so callers need not restate either:
aix.AgentRef{Name: "researcher"}
coderAgent.Ref()
type AgentResult ¶
type AgentResult struct {
// Artifacts contains artifacts produced during the session.
Artifacts []*Artifact `json:"artifacts,omitempty"`
// FinishReason is why the invocation finished. A custom agent may set it to
// override the default (the last turn's reason); leave it empty to accept the
// default.
FinishReason AgentFinishReason `json:"finishReason,omitempty"`
// Message is the last model response message from the conversation.
Message *ai.Message `json:"message,omitempty"`
}
AgentResult is the return value from an AgentFunc. It contains the user-specified outputs of the agent invocation.
type AgentStateManagement ¶
type AgentStateManagement string
AgentStateManagement enumerates who owns session state for an agent: "server" (a SessionStore is configured and snapshots are persisted server-side) or "client" (no store; state flows through invocation init / output).
const ( // AgentStateManagementServer indicates the agent is wired with // a [SessionStore] and persists snapshots server-side. AgentStateManagementServer AgentStateManagement = "server" // AgentStateManagementClient indicates the agent has no store; // session state is client-managed and round-trips through invocation // init and output. AgentStateManagementClient AgentStateManagement = "client" )
type AgentStreamChunk ¶
type AgentStreamChunk struct {
// Artifact contains a newly produced artifact.
Artifact *Artifact `json:"artifact,omitempty"`
// CustomPatch is an RFC 6902 JSON Patch describing a delta to the session's
// custom state, emitted automatically whenever the agent mutates it (e.g. via
// [Session.UpdateCustom]). Pointers are rooted at the custom document (e.g.
// "/agentStatus"), with no "/custom" prefix. The first patch of each turn is a
// whole-document replace at the root pointer ("") to re-base the client; later
// patches are incremental diffs. Apply it with [ApplyPatch] to keep a local
// copy of custom state live as the turn streams.
CustomPatch JSONPatch `json:"customPatch,omitempty"`
// ModelChunk contains generation tokens from the model.
ModelChunk *ai.ModelResponseChunk `json:"modelChunk,omitempty"`
// TurnEnd is non-nil when the agent has finished processing the current
// input. It groups all turn-end signals (snapshot ID, etc.) so callers can
// check a single field. When set, the client should stop iterating and may
// send the next input.
TurnEnd *TurnEnd `json:"turnEnd,omitempty"`
}
AgentStreamChunk represents a single item in the agent's output stream. Multiple fields can be populated in a single chunk.
type Artifact ¶
type Artifact struct {
// Metadata contains additional artifact-specific data.
Metadata map[string]any `json:"metadata,omitempty"`
// Name identifies the artifact (e.g., "generated_code.go", "diagram.png").
Name string `json:"name,omitempty"`
// Parts contains the artifact content (text, media, etc.).
Parts []*ai.Part `json:"parts"`
}
Artifact represents a named collection of parts produced during a session. Examples: generated files, images, code snippets, diagrams, etc.
type ArtifactStore ¶
type ArtifactStore interface {
// Artifacts returns a snapshot of the session's current artifacts.
Artifacts() []*Artifact
// AddArtifacts adds artifacts, replacing any existing artifact of the same
// name.
AddArtifacts(artifacts ...*Artifact)
}
ArtifactStore is the State-agnostic view of a session's artifact collection. Every Session satisfies it regardless of its State type, since artifact operations do not touch custom state. Middleware and tools that work with artifacts without knowing the agent's State type use it via ArtifactStoreFromContext, where SessionFromContext cannot help because it requires the concrete State.
func ArtifactStoreFromContext ¶
func ArtifactStoreFromContext(ctx context.Context) ArtifactStore
ArtifactStoreFromContext returns the active session's artifacts as a State-agnostic ArtifactStore, or nil if there is no active session in ctx. Unlike SessionFromContext it does not require knowing the session's State type, so it is the accessor for middleware and tools.
type GetSnapshotRequest ¶
type GetSnapshotRequest struct {
// SessionID identifies the session whose latest snapshot to fetch.
// Optional when SnapshotID is given. The latest snapshot is the session's
// most recently updated row regardless of status (pending, failed, or
// aborted included).
SessionID string `json:"sessionId,omitempty"`
// SnapshotID identifies the snapshot to fetch. Optional when SessionID is
// given; when both are present the fetched snapshot must belong to that
// session.
SnapshotID string `json:"snapshotId,omitempty"`
}
GetSnapshotRequest is the input for an agent's getSnapshot companion action, available when the agent has a session store configured. Intended for Dev UI and client reconnect flows, it returns the stored SessionSnapshot with WithStateTransform applied to its state if configured.
At least one of SnapshotID or SessionID must be set. SnapshotID fetches a specific snapshot; SessionID alone fetches the session's latest snapshot (whatever its status). When both are set, the fetched snapshot must belong to that session, or the request is rejected.
type InlinePrompt ¶
type InlinePrompt []ai.PromptOption
InlinePrompt is an inline prompt definition for an agent: the list of ai.PromptOption values that configure the agent's prompt. Pass one to DefineAgent, which registers the prompt under the agent's name:
agent := DefineAgent(r, "pirate",
InlinePrompt{
ai.WithModelName("googleai/gemini-flash-latest"),
ai.WithSystem("You are a sarcastic pirate."),
},
WithSessionStore(store),
)
To give the template a default render input, include ai.WithInputType among the options. For an agent backed by a prompt already in the registry (e.g. one defined via ai.DefinePrompt or loaded from a .prompt file), use DefinePromptAgent instead, which takes no InlinePrompt.
type InterruptibleTool ¶
InterruptibleTool is a Tool that supports typed interrupt/resume. The Res type parameter is the type of data the caller sends back when resuming the tool after an interrupt.
func DefineInterruptibleTool ¶
func DefineInterruptibleTool[In, Out, Res any]( r api.Registry, name, description string, fn InterruptibleToolFunc[In, Out, Res], opts ...ai.ToolOption, ) *InterruptibleTool[In, Out, Res]
DefineInterruptibleTool creates a new interruptible tool and registers it. The resumed parameter is non-nil when the tool is being resumed after an interrupt. Use tool.Interrupt inside the function to interrupt execution and send data to the caller.
func NewInterruptibleTool ¶
func NewInterruptibleTool[In, Out, Res any]( name, description string, fn InterruptibleToolFunc[In, Out, Res], opts ...ai.ToolOption, ) *InterruptibleTool[In, Out, Res]
NewInterruptibleTool creates a new unregistered interruptible tool.
func (*InterruptibleTool[In, Out, Resume]) Respond ¶
Respond creates a tool response ai.Part for an interrupted tool request. Instead of re-executing the tool (as [Resume] does), this provides a pre-computed result directly.
Unlike tool.Respond, this method validates that the interrupted part belongs to this tool and accepts a strongly-typed output.
func (*InterruptibleTool[In, Out, Resume]) Resume ¶
Resume creates a restart part for resuming this interrupted tool with typed data. The data will be deserialized into the *Res parameter of the tool function when it is re-executed.
Res must serialize to a JSON object (a struct or a map), since it is carried as structured metadata on the restart part; see tool.Interrupt.
Unlike tool.Resume, this method also validates that the interrupted part belongs to this tool.
type InterruptibleToolFunc ¶
type InterruptibleToolFunc[In, Out, Resume any] = func(ctx context.Context, input In, res *Resume) (Out, error)
InterruptibleToolFunc is the function signature for tools created with DefineInterruptibleTool and NewInterruptibleTool. The resumed parameter is non-nil when the tool is being re-executed after an interrupt.
type InvocationOption ¶
type InvocationOption[State any] interface { // contains filtered or unexported methods }
InvocationOption configures an agent invocation (Connect, Run, or RunText).
func WithSessionID ¶
func WithSessionID[State any](id string) InvocationOption[State]
WithSessionID resumes the conversation with the given ID from its latest snapshot (see SnapshotReader.GetLatestSnapshot). Use it when the caller tracks the conversation rather than individual snapshots; the ID is assigned on the conversation's first invocation (see AgentOutput.SessionID) and stays stable across resumes.
Valid only for server-managed agents, and so mutually exclusive with WithState (a client-managed conversation carries its identity inside the state). Combined with WithSnapshotID, the snapshot picks the resume point and the session ID is validated against it.
The resume is rejected if the latest snapshot is a failed, aborted, or pending dead end; a pending tip means a detached invocation is still running, so wait for it to finalize or abort it. If history was forked, the most recently updated branch wins; use WithSnapshotID for a specific branch. An empty ID is an error, not a no-op.
func WithSnapshotID ¶
func WithSnapshotID[State any](id string) InvocationOption[State]
WithSnapshotID loads state from a persisted snapshot by ID. Use this for server-managed state where snapshots are stored. Combine with WithSessionID to assert which session the snapshot belongs to; a mismatch is rejected. Mutually exclusive with WithState.
func WithState ¶
func WithState[State any](state *SessionState[State]) InvocationOption[State]
WithState sets the initial state for the invocation, for client-managed agents where the client sends state directly. The conversation's identity rides inside the state (SessionState.SessionID); the framework mints it on the first invocation and echoes it on the output, so resending the state keeps the identity. The state is deep-copied at the start, so the caller may reuse the object freely. Mutually exclusive with WithSessionID and WithSnapshotID.
type JSONPatch ¶
type JSONPatch []*JSONPatchOperation
JSONPatch is an RFC 6902 JSON Patch: an ordered list of operations applied in sequence. Use Diff to compute the patch between two values and ApplyPatch to apply one to a document.
func Diff ¶
Diff computes an RFC 6902 JSON Patch that transforms from into to.
The diff is rooted at the document, so pointers are bare (e.g. "/agentStatus", "/items/0"). Only add, remove, and replace operations are emitted. Object members recurse (add for new keys, remove for deleted keys); arrays diff by index, appending with the end-of-array token "/-" and removing from the tail backwards so indices stay valid. A root-level change that cannot be expressed member-by-member (object↔array↔primitive) collapses to a single whole-document replace at path "".
Object keys are visited in sorted order, so the patch is deterministic.
type JSONPatchOp ¶
type JSONPatchOp string
JSONPatchOp is the kind of a JSON Patch operation (RFC 6902): one of JSONPatchOpAdd, JSONPatchOpRemove, JSONPatchOpReplace, JSONPatchOpMove, JSONPatchOpCopy, or JSONPatchOpTest.
const ( JSONPatchOpAdd JSONPatchOp = "add" JSONPatchOpRemove JSONPatchOp = "remove" JSONPatchOpReplace JSONPatchOp = "replace" JSONPatchOpMove JSONPatchOp = "move" JSONPatchOpCopy JSONPatchOp = "copy" JSONPatchOpTest JSONPatchOp = "test" )
type JSONPatchOperation ¶
type JSONPatchOperation struct {
// From is a JSON Pointer to the source location; required for "move" and "copy".
From string `json:"from,omitempty"`
// Op is the operation to perform.
Op JSONPatchOp `json:"op"`
// Path is a JSON Pointer (RFC 6901) to the target location, e.g. "/agentStatus".
// The empty pointer "" refers to the whole document.
Path string `json:"path"`
// Value is the operand for "add", "replace", and "test"; an explicit null is a
// valid operand. Ignored for "remove", "move", and "copy".
Value any `json:"value"`
}
JSONPatchOperation is a single RFC 6902 (JSON Patch) operation. A JSONPatch applies an ordered list of these to transform one JSON document into another.
type PromptAgentOption ¶
type PromptAgentOption[State any] interface { // contains filtered or unexported methods }
PromptAgentOption configures a prompt-backed agent defined via DefinePromptAgent. It is the wider set that additionally admits the prompt-source option WithNamedPrompt; every AgentOption satisfies it, so the shared agent options compose with WithNamedPrompt in a single variadic.
func WithNamedPrompt ¶
func WithNamedPrompt[State any](name string, input any) PromptAgentOption[State]
WithNamedPrompt points a DefinePromptAgent at the prompt registered under name, rendered with input on every turn (pass nil for the prompt's own default input). name need not match the agent's name, so a single registered prompt can back many agents with different inputs; pass "" to keep the default same-named lookup while still supplying a custom input.
Without this option a prompt agent uses the prompt registered under its own name. This option lets a single registered prompt back many agents, each rendered with its own input, and composes with the other agent options in one variadic.
input is rendered through the prompt once at definition time as a smoke check, so an input that fails the prompt's schema panics there rather than on the first invocation.
This option applies only to DefinePromptAgent. Passing it to DefineAgent or DefineCustomAgent is a compile-time error.
type Responder ¶
type Responder struct {
// contains filtered or unexported fields
}
Responder is an agent's output channel to the client. Its Send methods are fire-and-forget: they return no error, and the agent function should stop producing once its own context is cancelled.
A Send applies its session-level side effects synchronously, so a state read (SessionRunner.Result, Session.Artifacts) or turn-end snapshot taken afterward observes them. Only the forward to the client is asynchronous, and it is dropped once the work context is cancelled (client disconnect, abort, or agent completion); the side effects still apply.
func (Responder) SendArtifact ¶
SendArtifact streams an artifact to the client and adds it to the session, replacing any existing artifact with the same name. The session keeps a deep copy, so later mutations of artifact do not affect session state.
func (Responder) SendModelChunk ¶
func (r Responder) SendModelChunk(chunk *ai.ModelResponseChunk)
SendModelChunk sends a generation chunk (token-level streaming).
type Session ¶
type Session[State any] struct { // contains filtered or unexported fields }
Session holds conversation state and provides thread-safe read/write access to messages, custom state, and artifacts.
func SessionFromContext ¶
SessionFromContext retrieves the current session from context. Returns nil if no session is in context or if the type doesn't match.
func (*Session[State]) AddArtifacts ¶
AddArtifacts adds artifacts to the session. If an artifact with the same name already exists, it is replaced.
func (*Session[State]) AddMessages ¶
AddMessages appends messages to the conversation history.
func (*Session[State]) Artifacts ¶
Artifacts returns the current artifacts. The returned slice is a fresh copy, but its elements point at the live artifacts held by the session: treat them as read-only, or deep-copy before mutating. Session.State returns a fully independent copy.
func (*Session[State]) Custom ¶
func (s *Session[State]) Custom() State
Custom returns the current user-defined custom state.
func (*Session[State]) Messages ¶
Messages returns the current conversation history. The returned slice is a fresh copy, but its elements point at the live messages held by the session: treat them as read-only, or deep-copy before mutating. Session.State returns a fully independent copy.
func (*Session[State]) SessionID ¶
SessionID returns the ID of the session this conversation belongs to. The agent runtime settles it before the agent function runs and keeps it stable for the invocation's lifetime, stamping it on every snapshot persisted. It is safe to use as a key for external resources tied to the conversation, including from code that retrieves the session via SessionFromContext.
func (*Session[State]) SetMessages ¶
SetMessages replaces the conversation history with the given messages.
func (*Session[State]) State ¶
func (s *Session[State]) State() *SessionState[State]
State returns a copy of the current state.
func (*Session[State]) UpdateArtifacts ¶
UpdateArtifacts atomically reads the current artifacts, applies the given function, and writes the result back. fn runs while the session's internal lock is held: it must not call other Session methods or send on a Responder, or it will deadlock.
func (*Session[State]) UpdateCustom ¶
func (s *Session[State]) UpdateCustom(fn func(State) State)
UpdateCustom atomically reads the current custom state, applies the given function, and writes the result back. fn runs while the session's internal lock is held: it must not call other Session methods or send on a Responder, or it will deadlock.
When the session is driven by an agent invocation, the mutation is streamed to the client as an AgentStreamChunk.CustomPatch describing the delta (the runtime computes and emits it after fn returns). Agents therefore just mutate state; they never hand-craft patches.
func (*Session[State]) UpdateMessages ¶
UpdateMessages atomically reads the current messages, applies the given function, and writes the result back. fn runs while the session's internal lock is held: it must not call other Session methods or send on a Responder, or it will deadlock.
type SessionRunner ¶
SessionRunner extends Session with agent-runtime functionality: turn management, snapshot persistence, and input channel handling.
func (*SessionRunner[State]) Result ¶
func (s *SessionRunner[State]) Result() *AgentResult
Result returns an AgentResult populated from the current session state: the last message in the conversation history and all artifacts. The returned value is independent of the session; callers may mutate it without affecting session state. An artifact sent through the Responder is visible here as soon as the Send call returns.
It is a convenience for custom agents that don't need to construct the result manually.
func (*SessionRunner[State]) Run ¶
func (s *SessionRunner[State]) Run(ctx context.Context, fn func(ctx context.Context, input *AgentInput) (*TurnResult, error)) error
Run loops over the input channel, calling fn for each turn. Each turn is wrapped in a trace span for observability. Input messages are automatically added to the session before fn is called. After fn returns successfully, a snapshot check is triggered and a TurnEnd chunk (carrying any new snapshot's ID) is sent.
fn may return a TurnResult to report how the turn ended (e.g. its finish reason); returning nil reports nothing. The reason rides the turn's TurnEnd chunk and is persisted on the turn-end snapshot.
When fn returns an error, Run records the failure (TurnEnd is emitted with AgentFinishReasonFailed and no snapshot is taken of the turn's partial state), stops looping, and returns the error. A custom agent may recover (e.g. call Run again to keep processing inputs) or propagate the error out of the agent function, which resolves the invocation with a failed AgentOutput carrying the error and the last-good state rather than failing the action.
type SessionSnapshot ¶
type SessionSnapshot[State any] struct { // CreatedAt is when the snapshot was created. CreatedAt time.Time `json:"createdAt"` // Error is the structured failure information for a snapshot in // [SnapshotStatusFailed]. Nil otherwise. Error *core.GenkitError `json:"error,omitempty"` // FinishReason is the semantic reason the turn or invocation captured here // ended (e.g. [AgentFinishReasonStop], [AgentFinishReasonInterrupted], // [AgentFinishReasonFailed], [AgentFinishReasonAborted]). It complements // [SessionSnapshot.Status] (the persistence lifecycle) so a resumed or // background task can report how it ended without re-deriving it from the // messages. FinishReason AgentFinishReason `json:"finishReason,omitempty"` // HeartbeatAt is refreshed periodically while a detached (background) turn is // in flight, so a reader can detect a dead background worker: if a pending // snapshot's heartbeat goes stale (older than the configured timeout), reads // surface its status as [SnapshotStatusExpired] (the dead worker can no longer // persist a terminal status itself). Refreshing it does not advance // [SessionSnapshot.UpdatedAt], so liveness stays distinct from state changes. Nil // on snapshots that never detached. HeartbeatAt *time.Time `json:"heartbeatAt,omitempty"` // ParentID is the ID of the previous snapshot in this timeline. It is // informational lineage (for debugging and UI history trees) and plays // no part in resolving a session's latest snapshot. ParentID string `json:"parentId,omitempty"` // SessionID is the ID of the session this snapshot belongs to. Assigned by the // framework on the conversation's first invocation and stamped on every later // snapshot in the chain, across resumed invocations; stores preserve it across // rewrites. SessionID string `json:"sessionId,omitempty"` // SnapshotID is the unique identifier for this snapshot (UUID). SnapshotID string `json:"snapshotId"` // State is the conversation state captured at this point. Nil on a // pending snapshot (the live state is not yet committed; the background // invocation is still processing queued inputs); populated on terminal // snapshots with the cumulative final state. State *SessionState[State] `json:"state,omitempty"` // Status is the lifecycle state of this snapshot. Empty is treated as // [SnapshotStatusCompleted] for backwards compatibility. Status SnapshotStatus `json:"status,omitempty"` // UpdatedAt is when the snapshot's state was last written. A heartbeat refresh on // a pending snapshot deliberately does not advance it, so a pending snapshot's // UpdatedAt equals CreatedAt until the snapshot is finalized, whose terminal write // advances it. UpdatedAt time.Time `json:"updatedAt,omitempty"` }
SessionSnapshot is a persisted point-in-time capture of session state. It is the canonical record written to and read from a SessionStore.
type SessionState ¶
type SessionState[State any] struct { // Artifacts are named collections of parts produced during the conversation. Artifacts []*Artifact `json:"artifacts,omitempty"` // Custom is the user-defined state associated with this conversation. Custom State `json:"custom,omitempty"` // Messages is the conversation history (user/model exchanges). // Does NOT include prompt-rendered messages — those are rendered fresh each turn. Messages []*ai.Message `json:"messages,omitempty"` // SessionID is the ID of the session (conversation) this state belongs to. // Framework-owned: assigned on the conversation's first invocation and // re-stamped on outbound state, so client-managed callers can round-trip the // state object opaquely. For server-managed agents the snapshot row's // [SessionSnapshot.SessionID] is canonical and this field mirrors it. SessionID string `json:"sessionId,omitempty"` }
SessionState is the portable conversation state that flows between client and server. It contains only the data needed for conversation continuity.
type SessionStore ¶
type SessionStore[State any] interface { SnapshotReader[State] SnapshotWriter[State] }
SessionStore is the minimum store interface required by WithSessionStore. Status-change observation is layered as the optional SnapshotSubscriber capability and checked at runtime: a store wired into an agent that intends to support detach must also implement SnapshotSubscriber, or the runtime will reject detach attempts.
type SnapshotReader ¶
type SnapshotReader[State any] interface { // GetSnapshot retrieves a snapshot by ID. Returns nil if not found. GetSnapshot(ctx context.Context, snapshotID string) (*SessionSnapshot[State], error) // GetLatestSnapshot returns the session's most recently created // snapshot, whatever its status: a pending, failed, or aborted row is // returned like any other, and the caller applies its own policy. // Returns nil if the session has no rows, and an error if sessionID is // empty. // // "Most recently created" means the greatest [SessionSnapshot.CreatedAt]; // break ties deterministically (e.g. by SnapshotID). This is a plain // max-timestamp lookup, implementable as a single indexed query (e.g. // WHERE sessionId = ? ORDER BY createdAt DESC LIMIT 1). A later rewrite of // an older row (e.g. a detach finalize) does not move it ahead of a // newer-created sibling, since CreatedAt is preserved across rewrites. // ParentID is informational lineage and plays no part in resolution: when // history forks, the most recently created branch wins. GetLatestSnapshot(ctx context.Context, sessionID string) (*SessionSnapshot[State], error) }
SnapshotReader retrieves snapshots. The minimum any session store must implement to be used with WithSessionStore.
type SnapshotStatus ¶
type SnapshotStatus string
SnapshotStatus describes the lifecycle state of a snapshot. Snapshots written for synchronous turns or invocations are always SnapshotStatusCompleted (an empty value is also treated as completed for backwards compatibility).
When a client sets AgentInput.Detach, the server writes a single snapshot with SnapshotStatusPending (and empty state) and returns its ID immediately. Background processing then either rewrites that snapshot with the cumulative final state and SnapshotStatusCompleted / SnapshotStatusFailed when the agent finishes, or with SnapshotStatusAborted if the client called abort in the meantime.
SnapshotStatusExpired is never persisted: it is computed on read for a pending snapshot whose background worker is presumed dead (its heartbeat went stale), surfacing the orphan rather than leaving it pending forever.
const ( // SnapshotStatusPending indicates a detached invocation is still // processing the queued inputs. The snapshot will be rewritten with a // terminal status once the background work finishes. SnapshotStatusPending SnapshotStatus = "pending" // SnapshotStatusCompleted indicates the snapshot captures a settled state. SnapshotStatusCompleted SnapshotStatus = "completed" // SnapshotStatusAborted indicates the snapshot's invocation was aborted // while detached (e.g. via the abort companion action). SnapshotStatusAborted SnapshotStatus = "aborted" // SnapshotStatusFailed indicates the invocation terminated with an error. // The snapshot's Error field describes the failure and resume is // rejected with that same error. SnapshotStatusFailed SnapshotStatus = "failed" // SnapshotStatusExpired indicates a pending snapshot whose detached background // worker is presumed dead: its [SessionSnapshot.HeartbeatAt] went stale. It is // computed on read (never persisted), so the raw store row stays // [SnapshotStatusPending] while a read surfaces it as expired. SnapshotStatusExpired SnapshotStatus = "expired" )
type SnapshotSubscriber ¶
type SnapshotSubscriber interface {
// OnSnapshotStatusChange returns a channel that yields the snapshot's
// status whenever it changes. The first value (if any) reflects the
// status at subscription time. The channel is closed when ctx is
// cancelled. If the snapshot does not exist when the subscription is
// established, the channel is closed without yielding a value.
//
// Implementations may push changes from a transaction log or CDC feed,
// or poll internally.
OnSnapshotStatusChange(ctx context.Context, snapshotID string) <-chan SnapshotStatus
}
SnapshotSubscriber is the optional capability layered on SessionStore that lets the agent runtime observe a snapshot's status changes without polling. It is what makes a detached invocation abortable: aborting is an ordinary SnapshotWriter.SaveSnapshot that flips a pending row to SnapshotStatusAborted, and the runtime reacts to that flip through this subscription, promptly cancelling the background work context.
A store that does not implement it cannot support detach (there is no way to signal the background work to stop); see the runtime's detach precondition check.
type SnapshotWriter ¶
type SnapshotWriter[State any] interface { // SaveSnapshot atomically reads the snapshot at id (if any), applies // fn, and persists the result largely verbatim. The store owns only // identity; the caller (fn) owns the lifecycle timestamps and status: // // - SnapshotID: if id is empty, the store generates a fresh ID; // otherwise the store uses id (any SnapshotID populated by fn is // overridden). // - SessionID: the ID of the session (chain of snapshots) the row // belongs to: preserved from the existing row on update (a row's // session never changes once set), otherwise taken from fn's row // as-is. Stores never mint or infer session IDs. // - CreatedAt / UpdatedAt: caller-managed. The store persists whatever fn // returns and never stamps them. fn sets CreatedAt and UpdatedAt to the // current time on a new row, preserves CreatedAt and advances UpdatedAt // on a state-changing rewrite, and preserves both on a non-state write // (e.g. a heartbeat refresh, which carries the existing snapshot through // unchanged but for HeartbeatAt). Keeping timestamps with the caller is // what lets a heartbeat advance liveness without registering as a state // change - the store has no special heartbeat path. // - Status: if the snapshot returned by fn has Status="", it is // defaulted to [SnapshotStatusCompleted] (the common case for // synchronous turn-end writes). Callers writing a pending row must // set Status explicitly. // // fn receives the existing snapshot (or nil if id is empty or the // row does not exist) and returns the snapshot to commit, or // (nil, nil) to skip the write without changing the row. // // Under contention, stores that use optimistic concurrency or // transaction retries may call fn multiple times. fn must therefore // be a pure function of its input: no side effects (channel sends, // logging, external I/O) inside fn. // // Returns the snapshot as persisted (with the store-owned fields // populated), or nil if fn declined to write. SaveSnapshot( ctx context.Context, snapshotID string, fn func(existing *SessionSnapshot[State]) (*SessionSnapshot[State], error), ) (*SessionSnapshot[State], error) }
SnapshotWriter persists snapshots. The minimum any session store must implement to be used with WithSessionStore.
type StateTransform ¶
type StateTransform[State any] = func(ctx context.Context, state *SessionState[State]) (*SessionState[State], error)
StateTransform rewrites session state on its way out to a client: it is applied to the state returned by the getSnapshot companion action and to AgentOutput.State for client-managed agents, but not to state persisted in the store or passed to the agent function. Typical uses are PII redaction and stripping secrets.
state is a fresh deep copy the transform owns. It returns the state to expose and a nil error, with two special outcomes:
- A nil state omits state from the response. This is an intentional, successful outcome: the stored snapshot and the agent's own view keep the data, only the outbound copy is dropped.
- A non-nil error fails closed: the operation being shaped aborts rather than exposing anything. A snapshot read returns the error; the final AgentOutput of an invocation resolves as a failed output carrying it. Use it when redaction cannot be performed safely (e.g. an RBAC policy lookup failed), where omitting (nil) would be a silent under-redaction and returning raw state would leak. The error's status code (such as PERMISSION_DENIED) propagates to the caller.
ctx is the request or invocation context, carrying deadlines and values such as the caller's identity for RBAC-aware redaction.
type StreamTransform ¶
type StreamTransform = func(ctx context.Context, chunk *AgentStreamChunk) (*AgentStreamChunk, error)
StreamTransform rewrites an AgentStreamChunk on its way out to a client: it runs at the wire boundary on every chunk the runtime forwards (model chunks, artifacts, custom-state patches, and turn-end signals), after the chunk's in-process side effects have already been applied. So, like StateTransform, it shapes only what the client sees, not session state, persisted snapshots, or anything passed to the agent function. It also leaves the final AgentOutput untouched; it is a stream-only hook. Typical uses are redacting streamed model tokens and stripping fields a client should not receive.
chunk is a fresh deep copy the transform owns. It returns the chunk to forward and a nil error, with two special outcomes:
- A nil chunk drops it from the stream. This is an intentional, successful outcome and is wire-only: the chunk's side effects (an artifact recorded on the session) and the final AgentOutput keep the underlying data. Dropping a chunk whose AgentStreamChunk.TurnEnd is set withholds the turn-end signal a client uses to pace the conversation, so reshape such a chunk rather than dropping it.
- A non-nil error fails closed: the whole invocation fails, so no unshaped chunk reaches the client and the offending chunk's side effects do not surface in the final output either. Use it when a chunk cannot be shaped safely; a panic in the transform is treated the same way.
ctx is the request context, carrying deadlines and values such as the caller's identity for RBAC-aware redaction.
To redact custom state, prefer WithStateTransform: the runtime applies it before diffing, so the custom-patch stream stays internally consistent. Rewriting an AgentStreamChunk.CustomPatch delta here can desync a client that reconstructs custom state from the patch sequence.
Unlike StateTransform it is not parameterized by State: a chunk carries no state type, so WithStreamTransform cannot infer State from the transform and takes it as an explicit type argument.
type Tool ¶
type Tool[In, Out any] struct { // contains filtered or unexported fields }
Tool wraps an ai.Tool with experimental x package features such as a plain context.Context function signature and tool.AttachParts.
DEPRECATED(breaking): With breaking changes, Tool would not wrap ai.ToolDef. It would be the primary tool type, backed directly by core.DefineAction, eliminating the inner field and all delegation methods below.
func DefineTool ¶
func DefineTool[In, Out any]( r api.Registry, name, description string, fn ToolFunc[In, Out], opts ...ai.ToolOption, ) *Tool[In, Out]
DefineTool creates a new tool with a simple function signature and registers it. The function receives a plain context.Context instead of ai.ToolContext. Use tool.AttachParts inside the function to return additional content parts.
func NewTool ¶
func NewTool[In, Out any]( name, description string, fn ToolFunc[In, Out], opts ...ai.ToolOption, ) *Tool[In, Out]
NewTool creates a new unregistered tool with a simple function signature. Use tool.AttachParts inside the function to return additional content parts.
func (*Tool[In, Out]) Definition ¶
func (t *Tool[In, Out]) Definition() *ai.ToolDefinition
Definition returns the ai.ToolDefinition for this tool.
The inner tool is built on ai.NewMultipartTool, whose function returns *ai.MultipartToolResponse, so the inner definition would advertise that envelope as the output schema. We override OutputSchema with the schema inferred from the Out type parameter, making the definition equivalent to what ai.NewTool exposes (the real output type) rather than leaking the multipart envelope to the model and Dev UI. Genkit infers schemas with DoNotReference, so the result is fully inlined and needs no registry resolution.
func (*Tool[In, Out]) Respond ¶
Respond creates a tool response part for an interrupted tool request.
func (*Tool[In, Out]) Restart ¶
Restart creates a restart part using the legacy ai.RestartOptions.
DEPRECATED(breaking): Remove entirely. Superseded by InterruptibleTool.Resume.
func (*Tool[In, Out]) RunRawMultipart ¶
func (t *Tool[In, Out]) RunRawMultipart(ctx context.Context, input any) (*ai.MultipartToolResponse, error)
RunRawMultipart runs the tool with raw input and returns the full multipart response.
type ToolFunc ¶
ToolFunc is the function signature for tools created with DefineTool and NewTool.
type ToolResume ¶
type ToolResume struct {
// Respond contains tool response parts to send to the model when resuming.
Respond []*ai.Part `json:"respond,omitempty"`
// Restart contains tool request parts to restart when resuming.
Restart []*ai.Part `json:"restart,omitempty"`
}
ToolResume holds the parts that resume an interrupted agent turn. Mirrors ai.GenerateActionResume but is named for the tool-call callsite where it is set on an AgentInput.
type TurnContext ¶
type TurnContext struct {
// SnapshotID is the ID the turn-end snapshot will be saved under, minted
// before the turn runs so the handler knows it in advance. A server-managed
// turn persists its snapshot under this ID on success. It is empty for a
// client-managed agent (no store, so no snapshot) and is the reserved-but-
// unused ID for a turn that writes none (a failed turn, or one whose
// snapshots a detach suspended).
SnapshotID string
// ParentSnapshotID is the ID of the snapshot this turn continues from: the
// previous turn's snapshot, or the snapshot the invocation resumed from. It
// is empty on the first turn of a fresh conversation and for a
// client-managed agent.
ParentSnapshotID string
// TurnIndex is the zero-based index of this turn within the invocation.
TurnIndex int
}
TurnContext carries per-turn metadata the runtime exposes to the per-turn function through its context. Retrieve it with TurnContextFromContext.
Its SnapshotID is reserved before the turn runs (for a server-managed agent), so a handler can name external, snapshot-correlated resources (e.g. a git worktree named after the snapshot) up front and have them line up with the snapshot the turn persists at its end.
func TurnContextFromContext ¶
func TurnContextFromContext(ctx context.Context) *TurnContext
TurnContextFromContext returns the TurnContext for the turn currently executing, or nil if ctx is not a per-turn context (e.g. it was called outside the SessionRunner.Run callback). The returned pointer is read-only; the runtime owns it.
type TurnEnd ¶
type TurnEnd struct {
// FinishReason is why this turn finished (e.g. [AgentFinishReasonStop],
// [AgentFinishReasonInterrupted]). It lets a caller react to a turn boundary
// (such as pausing on an interrupt) without scanning the message content.
// Empty when the turn reported no reason.
//
// [AgentFinishReasonFailed] reports a failed turn; unless the agent
// recovers and keeps processing, the invocation then resolves with a failed
// [AgentOutput] carrying the error and the last-good state, and further
// sends fail with [core.ErrActionCompleted].
FinishReason AgentFinishReason `json:"finishReason,omitempty"`
// SnapshotID is the ID of the snapshot persisted at the end of this turn.
// Empty if no snapshot was written (no store configured, the turn failed, or
// snapshots were suspended after detach).
SnapshotID string `json:"snapshotId,omitempty"`
}
TurnEnd groups the signals emitted when an agent turn finishes. A TurnEnd value is emitted exactly once per turn, regardless of whether a snapshot was persisted.
type TurnResult ¶
type TurnResult struct {
// FinishReason is why this turn ended (e.g. [AgentFinishReasonStop],
// [AgentFinishReasonInterrupted]). Empty to report no reason.
FinishReason AgentFinishReason
}
TurnResult is the optional return value of a SessionRunner.Run per-turn callback. It lets a custom agent report how the turn ended; the framework forwards the reason on the turn's TurnEnd chunk, persists it on the turn-end snapshot, and uses it to default the invocation's finish reason.
Returning nil (or a zero TurnResult) omits the reason: the framework performs no implicit inference. A prompt-backed agent populates it automatically from the underlying generate response.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package localstore provides single-process exp.SessionStore implementations suitable for local development, tests, and single-instance apps (CLI tools, desktop apps, local web services).
|
Package localstore provides single-process exp.SessionStore implementations suitable for local development, tests, and single-instance apps (CLI tools, desktop apps, local web services). |
|
Package tool provides runtime helpers for use inside tool functions.
|
Package tool provides runtime helpers for use inside tool functions. |