Documentation
¶
Overview ¶
Code generated by testdata/generate-format-patterns.ts; DO NOT EDIT. Expressions from TypeBox 1.3.27; see LICENSE.typebox.
Code generated by testdata/generate-unicode-properties.ts; DO NOT EDIT. Pi eeac84ca92498ac18b6832754d01aef1d3c5f654; Bun 1.3.14; Unicode 15.1. Property aliases: Unicode 15.1 UCD; see testdata/unicode-15.1/LICENSE.txt.
Package engine is the native Go port of Pi's agent state machine. It works with the lossless ai transcript rather than the legacy agentcore messages.
Index ¶
- Constants
- func MessagePointers(messages []ai.Message) []*ai.Message
- func MessageValues(messages []*ai.Message) []ai.Message
- func SetDefaultStreamFn(stream StreamFn)
- func StreamProxy(ctx context.Context, model json.RawMessage, transcript ai.TranscriptContext, ...) *ai.AssistantMessageEventStream
- type AdmitRequestFn
- type AfterToolCall
- type AfterToolResult
- type Agent
- func (a *Agent) Abort()
- func (a *Agent) ClearAllQueues()
- func (a *Agent) ClearFollowUpQueue()
- func (a *Agent) ClearSteeringQueue()
- func (a *Agent) Configure(options AgentConfig) error
- func (a *Agent) Continue(ctx context.Context) error
- func (a *Agent) FollowUp(message *ai.Message)
- func (a *Agent) FollowUpMode() string
- func (a *Agent) HasQueuedMessages() bool
- func (a *Agent) PeekQueuedMessages() []*ai.Message
- func (a *Agent) Prompt(ctx context.Context, input any, images ...*ai.ContentBlock) error
- func (a *Agent) Reset() error
- func (a *Agent) SetFollowUpMode(mode string)
- func (a *Agent) SetMessageList(messages *MessageList)
- func (a *Agent) SetMessages(messages []*ai.Message)
- func (a *Agent) SetModel(model json.RawMessage)
- func (a *Agent) SetSteeringMode(mode string)
- func (a *Agent) SetThinkingLevel(level string)
- func (a *Agent) SetToolList(tools *ToolList)
- func (a *Agent) SetTools(tools []*Tool)
- func (a *Agent) Signal() context.Context
- func (a *Agent) State() State
- func (a *Agent) Steer(message *ai.Message)
- func (a *Agent) SteeringMode() string
- func (a *Agent) Subscribe(listener *Listener) func()
- func (a *Agent) WaitForIdle(ctx context.Context) error
- type AgentConfig
- type AgentEventStream
- type AgentOptions
- type Array
- type BeforeToolCall
- type BeforeToolResult
- type Config
- type Context
- type Event
- type EventSink
- type InitialState
- type JSONMethod
- type List
- func (l *List[T]) Append(values ...T) int
- func (l *List[T]) Clone() *List[T]
- func (l *List[T]) Delete(index int)
- func (l *List[T]) DeleteProperty(name string)
- func (l *List[T]) Get(index int) T
- func (l *List[T]) GetProperty(name string) (T, bool)
- func (l *List[T]) Has(index int) bool
- func (l *List[T]) Keys() []int
- func (l *List[T]) Len() int
- func (l *List[T]) MarshalJSON() ([]byte, error)
- func (l *List[T]) PropertyKeys() []string
- func (l *List[T]) Set(index int, value T)
- func (l *List[T]) SetLength(length int)
- func (l *List[T]) SetProperty(name string, value T)
- func (l *List[T]) UnmarshalJSON(raw []byte) error
- func (l *List[T]) Values() []T
- type Listener
- type MessageList
- type Object
- type Property
- type ProxyStreamOptions
- type Request
- type RequestAdmission
- type State
- type StreamFn
- type Tool
- type ToolCallSet
- type ToolHooks
- type ToolList
- type ToolOutcome
- type ToolResult
- type Turn
- type TurnUpdate
Constants ¶
const Null = jsonjs.Null
const Undefined = jsonjs.Undefined
Variables ¶
This section is empty.
Functions ¶
func MessagePointers ¶
MessagePointers exposes the entries of a value slice to the native loop. The loop and its callbacks retain these objects; callers must synchronize any concurrent writes. Replacing a list entry does not replace that object.
func MessageValues ¶
MessageValues projects shared message objects at a snapshot or provider boundary. Nested payloads remain shared and must be treated as immutable.
func SetDefaultStreamFn ¶
func SetDefaultStreamFn(stream StreamFn)
SetDefaultStreamFn supplies Pi's process-wide fallback. Passing nil clears it. Per-run stream arguments take precedence and avoid global configuration.
func StreamProxy ¶
func StreamProxy(ctx context.Context, model json.RawMessage, transcript ai.TranscriptContext, options ProxyStreamOptions) *ai.AssistantMessageEventStream
StreamProxy reconstructs assistant messages in Go, without a JS worker. It returns immediately; request/protocol failures settle an error event. Partial pointers stay live. Use the stream's snapshot methods or Synchronize when inspecting payloads while the producer is still running.
Types ¶
type AdmitRequestFn ¶
type AfterToolCall ¶
type AfterToolCall struct {
BeforeToolCall
// Result refers to the executed result object. Mutations survive even when
// After returns nil; a returned override is applied to that mutated value.
// Replacing this pointer only changes the hook's context, as in Pi.
Result *ToolResult
IsError bool
}
type AfterToolResult ¶
type AfterToolResult = ToolResult
type Agent ¶
type Agent struct {
// contains filtered or unexported fields
}
Agent owns transcript state, queues and awaited subscriptions. It invokes the native Go loop directly; no worker process or legacy Agent is involved.
func NewAgent ¶
func NewAgent(options AgentOptions) (*Agent, error)
func (*Agent) ClearAllQueues ¶
func (a *Agent) ClearAllQueues()
func (*Agent) ClearFollowUpQueue ¶
func (a *Agent) ClearFollowUpQueue()
func (*Agent) ClearSteeringQueue ¶
func (a *Agent) ClearSteeringQueue()
func (*Agent) Configure ¶
func (a *Agent) Configure(options AgentConfig) error
func (*Agent) FollowUpMode ¶
func (*Agent) HasQueuedMessages ¶
func (*Agent) PeekQueuedMessages ¶
func (*Agent) Prompt ¶
Prompt accepts text, message values/references, native slices or a MessageList. A MessageList preserves live prompt membership during initial event delivery; native slice inputs copy membership. Both retain their message objects. Images accompany text input. Their list membership is copied, while the supplied block objects remain shared with events, history and requests. A nil image argument is an explicitly present null entry. It blocks until the run and its listeners settle. Admission errors are returned directly; run failures become Pi's assistant failure lifecycle.
func (*Agent) SetFollowUpMode ¶
func (*Agent) SetMessageList ¶
func (a *Agent) SetMessageList(messages *MessageList)
SetMessageList mirrors assigning a state array, including its sparse slots. Assignment detaches the outer collection and retains message objects.
func (*Agent) SetMessages ¶
func (*Agent) SetModel ¶
func (a *Agent) SetModel(model json.RawMessage)
func (*Agent) SetSteeringMode ¶
func (*Agent) SetThinkingLevel ¶
func (*Agent) SetToolList ¶
func (*Agent) SteeringMode ¶
type AgentConfig ¶
type AgentConfig struct {
Config
StreamFn StreamFn
PrepareNextTurn func(context.Context) (*TurnUpdate, error)
PrepareNextTurnWithContext func(context.Context, *Turn) (*TurnUpdate, error)
SteeringMode string
FollowUpMode string
SessionID *string
ThinkingBudgets json.RawMessage
Transport string
MaxRetryDelayMS *int
}
AgentConfig configures the stateful wrapper. Config supplies the shared loop hooks and stream options; state and owned queues override its model/queue fields. Configure replaces these options atomically for future runs. An already-installed preparation hook reads the latest wrapper callbacks.
type AgentEventStream ¶
type AgentEventStream struct {
*ai.EventStream[Event, *MessageList]
// contains filtered or unexported fields
}
AgentEventStream is Pi's unbounded event queue with an independent final message result. Reading events is optional; Result does not consume them. A terminal agent_end settles Result before the producer itself returns. Result and the terminal event retain the same live *MessageList.
Wait observes producer completion, including Go errors and panics. Like Pi's wrapper, a rejected low-level loop does not invent agent_end, close the event queue, or settle Result. Use Wait to observe such contract failures and a cancellable context when waiting for events/results that may never arrive. Provider error/aborted messages are normal terminal results, not failures.
func AgentLoop ¶
func AgentLoop(ctx context.Context, prompts *MessageList, initial Context, config Config, provider StreamFn) *AgentEventStream
AgentLoop starts the low-level loop asynchronously. It queues agent_start before returning, as the original wrapper does before its first await. Cancelling a reader does not abort the run; ctx controls the provider/tools.
func AgentLoopContinue ¶
func AgentLoopContinue(ctx context.Context, initial Context, config Config, provider StreamFn) (*AgentEventStream, error)
AgentLoopContinue validates the existing tail synchronously, then continues without re-emitting old messages. Custom roles are validated by ConvertToLLM at the request boundary, exactly as in Continue.
type AgentOptions ¶
type AgentOptions struct {
InitialState InitialState
AgentConfig
}
type BeforeToolCall ¶
type BeforeToolCall struct {
AssistantMessage *ai.Message
// ToolCall is the original block. Field edits survive into execution and
// lifecycle events; replacing this hook's pointer does not replace it.
ToolCall *ai.ContentBlock
// Args contains the validated *Object, *Array or primitive value. Nested
// edits are shared with execution and After without revalidation. Assigning
// a different value only replaces this hook context's field, as in Pi.
// ToolCall.Arguments remains the separate raw input.
Args any
Context *Context
}
type BeforeToolResult ¶
type Config ¶
type Config struct {
Model json.RawMessage
Reasoning string
Options map[string]any
ToolExecution string
ToolHooks
ConvertToLLM func(*MessageList) (*MessageList, error)
TransformContext func(context.Context, *MessageList) (*MessageList, error)
GetAPIKey func(string) (string, error)
FinishTurn func(context.Context, *Turn) (string, error)
PrepareRequest func(context.Context, Request) (*TurnUpdate, error)
// AdmitRequest, when supplied by a Go host, owns prepare/transform/convert,
// credential acquisition and streaming. The nil path follows Pi unchanged.
// It must return the selected request before any of its events are consumed.
AdmitRequest AdmitRequestFn
PrepareNextTurn func(*Turn) (*TurnUpdate, error)
GetSteeringMessages func() (*MessageList, error)
GetFollowUpMessages func() (*MessageList, error)
// Now supplies Date.now for deterministic replay and differential testing.
Now func() int64
// contains filtered or unexported fields
}
type Context ¶
type Context struct {
Messages *MessageList `json:"messages"`
Tools *ToolList `json:"-"`
// contains filtered or unexported fields
}
Context retains live message/tool collections shared with hooks. Replacing a field detaches that collection; edits through a retained list remain visible.
type Event ¶
type Event struct {
Type string
Message *ai.Message
Messages *MessageList
ToolResults *MessageList
AssistantMessageEvent *ai.AssistantMessageEvent
ToolCallID string
ToolName string
Args json.RawMessage
Result *ToolResult
PartialResult *ToolResult
IsError bool
// contains filtered or unexported fields
}
func (Event) Await ¶
Await yields a provider payload lock while a synchronous event sink waits, then reacquires it before returning. Do not inspect live message fields in work. Non-provider events call work directly. A provider event's Await is scoped to its sink invocation and must not be retained for later use.
func (Event) MarshalJSON ¶
MarshalJSON emits exactly the fields belonging to each Pi event variant.
func (Event) Synchronize ¶
func (e Event) Synchronize(read func())
Synchronize protects access to a retained provider event's live payload. Sinks already hold this lock; use this method only outside the sink callback. Like Pi, retaining an event does not detach its nested messages or blocks.
type EventSink ¶
EventSink is awaited. Parallel tools may enter it concurrently; a sink that keeps mutable state must synchronize its own writes.
type InitialState ¶
type JSONMethod ¶
type JSONMethod = jsonjs.JSONMethod
type List ¶
type List[T any] struct { // contains filtered or unexported fields }
List preserves collection identity when entries or length change. Container operations are synchronized; callers still synchronize edits to shared items. Values returns a detached, dense slice; Has distinguishes holes from zero T.
func (*List[T]) Clone ¶
Clone copies indexed entries, retaining item references and sparse slots. Like Array.slice, it drops ordinary named properties.
func (*List[T]) DeleteProperty ¶
func (*List[T]) GetProperty ¶
GetProperty reads indexed or ordinary enumerable data properties, excluding inherited properties and the reserved length property.
func (*List[T]) MarshalJSON ¶
func (*List[T]) PropertyKeys ¶
PropertyKeys includes enumerable own data properties in JavaScript key order. Keys returns only array indices. Neither method includes the length property.
func (*List[T]) SetProperty ¶
SetProperty defines an enumerable own data property, including names such as __proto__; it does not invoke JavaScript prototype setters or accessors.
func (*List[T]) UnmarshalJSON ¶
type Listener ¶
Listener has identity independently of its Go callback. Subscribing the same pointer twice is idempotent, as with Pi's Set of listener functions.
type MessageList ¶
func Continue ¶
func Continue(ctx context.Context, initial Context, config Config, emit EventSink, stream StreamFn) (*MessageList, error)
Continue reuses the transcript without emitting the existing prompt again.
func Run ¶
func Run(ctx context.Context, prompts *MessageList, initial Context, config Config, emit EventSink, stream StreamFn) (*MessageList, error)
Run starts a prompt invocation. Its returned list is shared with Turn.NewMessages and the agent_end event, and excludes pre-existing history. The prompt remains live during initial event iteration unless declaring tools creates a replacement list. Context/result membership is copied before events. Hooks and sink failures propagate without inventing agent_end.
type Object ¶
Object and Array retain nested identity across argument hooks and execution. Callers must synchronize concurrent access to shared values.
type ProxyStreamOptions ¶
type ProxyStreamOptions struct {
ProxyURL string
AuthToken string
Options map[string]any
Client *http.Client
Now func() int64
}
ProxyStreamOptions configures Pi's compact HTTP streaming protocol. Options holds provider controls; only the protocol's explicit allowlist is sent. Client and Now are optional Go transport/clock dependencies.
type RequestAdmission ¶
type RequestAdmission struct {
Request Request
Stream *ai.AssistantMessageEventStream
}
RequestAdmission is a Go host extension for orchestration which can select a different prepared request before releasing provider events. Context contains native messages/tools, not the transformed provider-only transcript.
type State ¶
type State struct {
Model json.RawMessage `json:"model,omitempty"`
ThinkingLevel string `json:"thinkingLevel"`
Tools *ToolList `json:"tools"`
Messages *MessageList `json:"messages"`
IsStreaming bool `json:"isStreaming"`
StreamingMessage *ai.Message `json:"streamingMessage,omitempty"`
PendingToolCalls *ToolCallSet `json:"pendingToolCalls"`
ErrorMessage *string `json:"errorMessage,omitempty"`
}
State snapshots scalar fields while retaining live message/tool collections and message objects. List operations are synchronized; callers synchronize concurrent item edits. Use SetMessages/SetTools to replace a collection.
func (State) MarshalJSON ¶
func (State) SystemPrompt ¶
SystemPrompt replays the current collection lazily, like Pi's state getter. Holding State retains that collection even when the agent later replaces it.
type StreamFn ¶
StreamFn must encode provider failures as error/aborted stream messages. A returned Go error is a contract failure and interrupts the low-level loop. Models and option fields remain raw to retain provider-specific metadata.
func GetDefaultStreamFn ¶
type Tool ¶
type Tool struct {
ai.Tool
Label string
OutputSchema json.RawMessage
Replay string
ExecutionMode string
PrepareArguments func(json.RawMessage) (json.RawMessage, error)
// Execute shares validated *Object/*Array values with hooks; primitives
// are passed by value. Nested edits are shared, local reassignment is not.
// Updates share result objects with hooks and events.
// Tools must synchronize access when retaining or sharing these pointers.
Execute func(context.Context, string, any, func(*ToolResult)) (*ToolResult, error)
}
Tool is shared by pointer. Preparation selects the object before invoking argument and lifecycle hooks; later field edits affect that selected tool, while replacing its entry in Context.Tools only affects future selection. Callers must synchronize concurrent mutation of tool definitions/callbacks.
func (Tool) MarshalJSON ¶
type ToolCallSet ¶
type ToolCallSet struct {
// contains filtered or unexported fields
}
ToolCallSet is an immutable, insertion-ordered set of executing tool call IDs. Agent retains the same set between tool events and replaces it at every start, end, reset and run settlement. Retained sets can be read concurrently.
func (*ToolCallSet) Has ¶
func (s *ToolCallSet) Has(id string) bool
func (*ToolCallSet) Len ¶
func (s *ToolCallSet) Len() int
func (*ToolCallSet) MarshalJSON ¶
func (s *ToolCallSet) MarshalJSON() ([]byte, error)
MarshalJSON matches JSON.stringify on Pi's Set. Transport adapters that need an array of IDs must explicitly serialize Values instead.
func (*ToolCallSet) Values ¶
func (s *ToolCallSet) Values() []string
Values returns a detached slice in insertion order.
type ToolHooks ¶
type ToolHooks struct {
Before func(context.Context, *BeforeToolCall) (*BeforeToolResult, error)
After func(context.Context, AfterToolCall) (*AfterToolResult, error)
}
type ToolOutcome ¶
type ToolOutcome struct {
ToolCall *ai.ContentBlock `json:"toolCall"`
Result *ToolResult `json:"result"`
IsError bool `json:"isError"`
}
func RunToolCall ¶
func RunToolCall(ctx context.Context, call *ai.ContentBlock, tools *ToolList, assistant *ai.Message, current *Context, hooks ToolHooks, update func(*ToolResult) error) (ToolOutcome, error)
RunToolCall applies the same preparation, validation and hooks as a model call, without emitting lifecycle events or appending transcript messages. The input call, hook call and outcome call retain the same pointer. The selected tool object survives replacement of its entry in tools. A nil tools argument uses current.Tools; an explicit empty list overrides it. Results and updates retain the tool's pointers unless a hook overrides or fails. An update callback's panic propagates synchronously to the executing tool; a returned error represents a rejected update promise and rejects the call after execution settles. Tools that launch goroutines own their panic boundary.
type ToolResult ¶
type ToolResult struct {
Content *ai.BlockList `json:"content"`
Details any `json:"-"`
StructuredContent any `json:"-"`
Usage *ai.Usage `json:"usage,omitempty"`
IsError *bool `json:"isError,omitempty"`
Terminate *bool `json:"terminate,omitempty"`
// contains filtered or unexported fields
}
ToolResult shares its content list, Details and StructuredContent with hooks/events. Values use *Object, *Array or primitives. nil/Undefined omit an optional field; Null retains explicit JSON null. Concurrent access needs synchronization.
func (ToolResult) MarshalJSON ¶
func (r ToolResult) MarshalJSON() ([]byte, error)
func (*ToolResult) UnmarshalJSON ¶
func (r *ToolResult) UnmarshalJSON(raw []byte) error
JS tools can return additional result metadata and explicit nulls. Keep only fields the typed projection would omit. Dynamic value fields decode into the shared live graph and do not need another retained raw copy. Native field updates take precedence, and copies of a result share only immutable source metadata.
type Turn ¶
type Turn struct {
Message *ai.Message
ToolResults *MessageList
Context *Context
NewMessages *MessageList
}
Turn is shared by pointer between FinishTurn and PrepareNextTurn. Its initial fields reference the completed message, per-turn tool results, active context and accumulating run result. Replacing fields changes this retained view, not the loop's own references; context replacement takes effect through TurnUpdate. Edits belong to awaited callbacks; concurrent access requires synchronization.
type TurnUpdate ¶
type TurnUpdate struct {
Context *Context
// Messages stays live until the loop spreads prepared and pending messages.
Messages *MessageList
Model json.RawMessage
ThinkingLevel *string
}
Source Files
¶
- agent.go
- argument_arrays.go
- argument_composition.go
- argument_error_order.go
- argument_errors.go
- argument_format_patterns.go
- argument_formats.go
- argument_hostname.go
- argument_numbers.go
- argument_objects.go
- argument_punycode.go
- argument_regexp.go
- argument_regexp_captures.go
- argument_regexp_characters.go
- argument_regexp_progress.go
- argument_regexp_properties.go
- argument_regexp_repetition.go
- argument_regexp_syntax.go
- argument_scalars.go
- argument_schema.go
- argument_unicode_properties.go
- argument_url.go
- arguments.go
- event_stream.go
- json.go
- list.go
- loop.go
- messages.go
- proxy.go
- proxy_json.go
- stream.go
- tool_call_set.go
- tools.go
- types.go
- values.go