Documentation
¶
Overview ¶
Package agent provides the core agent loop and message types. Mirrors packages/agent of the pinned Pi release.
Ports packages/agent/src/types.ts.
Ports packages/ai/src/utils/validation.ts.
Index ¶
- Constants
- Variables
- func BranchSummaryContextText(summary string) string
- func CalculateContextTokens(usage ai.Usage) int
- func CompactionSummaryContextText(summary string) string
- func ConvertToLLM(msgs []AgentMessage, model *ai.Model) []ai.Message
- func EstimateTokens(msg AgentMessage) int
- func EventObservation(event AgentEvent) *ai.StreamObservation
- func SetDefaultStreamFn(fn StreamFn)
- func StreamProxy(ctx context.Context, model *ai.Model, transcript ai.TranscriptContext, ...) *ai.AssistantMessageEventStream
- func ValidateToolArguments(tool ai.ToolSchema, call ai.ToolCall) (map[string]any, error)
- func WithMutationTicket(ctx context.Context, ticket *MutationTicket) context.Context
- func WithToolEnvironment(ctx context.Context, env ToolEnvironment) context.Context
- type AfterToolCallHook
- type AfterToolCallResult
- type Agent
- func (a *Agent) Abort()
- func (a *Agent) AddAfterToolCallHook(h AfterToolCallHook)
- func (a *Agent) AddBeforeToolCallHook(h BeforeToolCallHook)
- func (a *Agent) BeginSendContent(ctx context.Context, content []ai.UserContentBlock) (*PromptRun, error)
- func (a *Agent) BeginSendMessages(ctx context.Context, messages []AgentMessage) (*PromptRun, error)
- func (a *Agent) ClearAllQueues() (steering, followUp []AgentMessage)
- func (a *Agent) ClearFollowUpQueue() []AgentMessage
- func (a *Agent) ClearSteeringQueue() []AgentMessage
- func (a *Agent) ClearSystemPrompt()
- func (a *Agent) Continue(ctx context.Context) ([]AgentMessage, error)
- func (a *Agent) ErrorMessage() string
- func (a *Agent) FinishTurnHook() FinishTurn
- func (a *Agent) FollowUp(msg AgentMessage)
- func (a *Agent) FollowUpMode() QueueMode
- func (a *Agent) HasPendingMessages() bool
- func (a *Agent) HasQueuedMessages() bool
- func (a *Agent) IsStreaming() bool
- func (a *Agent) Messages() []AgentMessage
- func (a *Agent) MessagesSnapshot() []AgentMessage
- func (a *Agent) Model() *ai.Model
- func (a *Agent) ObserveRunSignal(observe func()) func()
- func (a *Agent) PeekQueuedMessages() []AgentMessage
- func (a *Agent) PendingMessages() (steering, followUp []AgentMessage)
- func (a *Agent) PendingToolCalls() []string
- func (a *Agent) PrepareNextTurnHook() PrepareNextTurn
- func (a *Agent) PrepareRequestHook() PrepareRequest
- func (a *Agent) QueueNextTurn(msg AgentMessage)
- func (a *Agent) Reset() error
- func (a *Agent) Send(ctx context.Context, content string) ([]AgentMessage, error)
- func (a *Agent) SendContent(ctx context.Context, content []ai.UserContentBlock) ([]AgentMessage, error)
- func (a *Agent) SendMessages(ctx context.Context, msgs []AgentMessage) ([]AgentMessage, error)
- func (a *Agent) SetBeforeProviderHook(fn func(payload any, model *ai.Model) (any, error))
- func (a *Agent) SetFinishTurn(fn FinishTurn)
- func (a *Agent) SetFollowUpMode(mode QueueMode)
- func (a *Agent) SetMessages(msgs []AgentMessage)
- func (a *Agent) SetModel(m *ai.Model)
- func (a *Agent) SetPrepareNextTurn(fn PrepareNextTurn)
- func (a *Agent) SetPrepareRequest(fn PrepareRequest)
- func (a *Agent) SetSessionID(id string)
- func (a *Agent) SetSteeringMode(mode QueueMode)
- func (a *Agent) SetStreamFunction(streamFn StreamFn)
- func (a *Agent) SetSystemPrompt(prompt string)
- func (a *Agent) SetThinkingLevel(level ai.ThinkingLevel)
- func (a *Agent) SetTools(tools []AgentTool)
- func (a *Agent) SetTransformContext(fn func(msgs []AgentMessage) []AgentMessage)
- func (a *Agent) SetTransformContextWithContext(fn func(context.Context, []AgentMessage) ([]AgentMessage, error))
- func (a *Agent) SetTransformHeaders(fn func(context.Context, ai.ProviderHeaders) (ai.ProviderHeaders, error))
- func (a *Agent) SetTransport(transport ai.Transport)
- func (a *Agent) Signal() context.Context
- func (a *Agent) Steer(msg AgentMessage)
- func (a *Agent) SteeringMode() QueueMode
- func (a *Agent) StreamFunction() StreamFn
- func (a *Agent) StreamingMessage() *AgentMessage
- func (a *Agent) Subscribe(listener func(context.Context, AgentEvent) error) func()
- func (a *Agent) SystemPrompt() string
- func (a *Agent) SystemPromptOverride() (string, bool)
- func (a *Agent) SystemPromptSnapshot() (string, bool)
- func (a *Agent) ThinkingLevel() ai.ThinkingLevel
- func (a *Agent) Timings() *Recorder
- func (a *Agent) ToolExecutionMode() ToolExecutionMode
- func (a *Agent) Tools() []AgentTool
- func (a *Agent) WaitForIdle()
- type AgentEndEvent
- type AgentEvent
- type AgentLoopTurnUpdate
- type AgentMessage
- type AgentOptions
- type AgentRequestUpdate
- type AgentSettledEvent
- type AgentStartEvent
- type AgentTool
- type AgentToolCall
- type AgentToolCallOutcome
- type AgentToolResult
- type AgentTurnAction
- type AgentTurnContext
- type AgentTurnDecision
- type ArgumentPreparer
- type AssistantMessage
- type AutoRetryEndEvent
- type AutoRetryStartEvent
- type BashExecutionUpdateEvent
- type BeforeToolCallHook
- type CompactionEndEvent
- type CompactionStartEvent
- type ContextUsageEstimate
- type EntryAppendedEvent
- type FinishTurn
- type MessageEndEvent
- type MessageStartEvent
- type MessageUpdateEvent
- type MutationTicket
- type OutputSchemaProvider
- type PendingMessageQueue
- func (q *PendingMessageQueue) Clear() []AgentMessage
- func (q *PendingMessageQueue) Drain() []AgentMessage
- func (q *PendingMessageQueue) Enqueue(msg AgentMessage)
- func (q *PendingMessageQueue) HasItems() bool
- func (q *PendingMessageQueue) Len() int
- func (q *PendingMessageQueue) Messages() []AgentMessage
- func (q *PendingMessageQueue) Mode() QueueMode
- func (q *PendingMessageQueue) Peek() []AgentMessage
- func (q *PendingMessageQueue) SetMode(mode QueueMode)
- type PrepareNextTurn
- type PrepareNextTurnContext
- type PrepareRequest
- type PrepareRequestContext
- type PromptRun
- type ProxyAssistantMessageEvent
- type ProxyStreamOptions
- type ProxyThinkingBudgets
- type QueueMode
- type QueueOrderable
- type QueueUpdateEvent
- type Recorder
- func (r *Recorder) CurrentTurnElapsed() time.Duration
- func (r *Recorder) Elapsed() time.Duration
- func (r *Recorder) EndTurn() time.Duration
- func (r *Recorder) LastTurnDuration() time.Duration
- func (r *Recorder) RecordTool(name string, d time.Duration)
- func (r *Recorder) Snapshot() TimingSnapshot
- func (r *Recorder) StartTurn()
- type RunToolCallOptions
- type SessionInfoChangedEvent
- type StreamFn
- type SummarizationRetryAttemptStartEvent
- type SummarizationRetryFinishedEvent
- type SummarizationRetryScheduledEvent
- type ThinkingLevelChangedEvent
- type TimingEventdeprecated
- type TimingSnapshot
- type ToolCallHookResult
- type ToolCallHooks
- type ToolEnvironment
- type ToolExecutionEndEvent
- type ToolExecutionMode
- type ToolExecutionStartEvent
- type ToolExecutionUpdateEvent
- type ToolResultMessage
- type ToolUpdateCallback
- type ToolUpdateSink
- type TurnEndEvent
- type TurnStartEvent
- type UserMessage
Constants ¶
const ( RoleUser = "user" RoleAssistant = "assistant" RoleToolResult = "toolResult" // Custom roles used by the coding agent layer. RoleBashExecution = "bashExecution" RoleCustom = "custom" RoleBranchSummary = "branchSummary" RoleCompactionSummary = "compactionSummary" )
Role constants mirror upstream.
Variables ¶
var ErrAlreadyProcessing = errors.New("Agent is already processing.")
ErrAlreadyProcessing is returned when Continue or Reset is called while a run is active. Mirrors upstream Agent.continue and Agent.reset.
var ErrAlreadyProcessingPrompt = errors.New("Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.")
ErrAlreadyProcessingPrompt is returned when a prompt is sent while a run is active. Mirrors upstream Agent.prompt's "Agent is already processing a prompt" error: queue the message with Steer or FollowUp instead.
var ErrMaxTurnsReached = errors.New("agent stopped at its turn limit with tool results still unanswered")
ErrMaxTurnsReached reports that a run stopped at AgentOptions.MaxTurns with tool results still waiting for a model response.
var ErrNoMessagesToContinue = errors.New("No messages to continue from")
ErrNoMessagesToContinue is returned by Continue on an empty transcript. Mirrors upstream Agent.continue's "No messages to continue from".
var ErrNoModelSelected = errors.New("no model selected")
ErrNoModelSelected is returned when a turn is requested with no usable model. Upstream agent-session.prompt() throws formatNoModelSelectedMessage() before streaming; pig surfaces the same condition as an error rather than panicking on a nil model in runLoop.
var ErrToolResultsUnanswered = errors.New("agent run ended after tool results without a model response")
ErrToolResultsUnanswered reports that a run ended with tool results the model never answered although no tool asked to terminate the run. It guards the invariant that a run never ends silently mid-task.
Functions ¶
func BranchSummaryContextText ¶
BranchSummaryContextText wraps a branch summary for LLM context. Mirrors upstream BRANCH_SUMMARY_PREFIX + summary + BRANCH_SUMMARY_SUFFIX from packages/coding-agent/src/core/messages.ts.
func CalculateContextTokens ¶
CalculateContextTokens computes context tokens from usage stats. Mirrors upstream calculateContextTokens (compaction.ts:135): prefer the provider-reported total, else sum the components.
func CompactionSummaryContextText ¶
CompactionSummaryContextText wraps a compaction summary for LLM context. Mirrors upstream COMPACTION_SUMMARY_PREFIX + summary + COMPACTION_SUMMARY_SUFFIX from packages/coding-agent/src/core/messages.ts.
func ConvertToLLM ¶
func ConvertToLLM(msgs []AgentMessage, model *ai.Model) []ai.Message
ConvertToLLM converts AgentMessages to the wire format expected by the AI provider. It calls NormalizeMessages first to filter errored/aborted assistant messages and insert synthetic tool results for orphaned tool calls.
func EstimateTokens ¶
func EstimateTokens(msg AgentMessage) int
EstimateTokens estimates the token count for a single message using a chars/4 heuristic covering all roles. Mirrors upstream estimateTokens (compaction.ts:232).
func EventObservation ¶
func EventObservation(event AgentEvent) *ai.StreamObservation
EventObservation returns the attached stream scope for synchronous host dispatch. Session transfers that scope before notifying its synchronous subscribers; it is not message data or wire metadata.
func SetDefaultStreamFn ¶
func SetDefaultStreamFn(fn StreamFn)
SetDefaultStreamFn configures the stream used by newly constructed agents when their caller omits StreamFn. Nil removes the configured fallback.
func StreamProxy ¶
func StreamProxy(ctx context.Context, model *ai.Model, transcript ai.TranscriptContext, options ProxyStreamOptions) *ai.AssistantMessageEventStream
StreamProxy streams through a server that manages provider authentication. Each toolcall_start replaces the indexed tool and its accumulated JSON. It returns immediately; request, protocol, and cancellation failures are delivered as terminal error events.
func ValidateToolArguments ¶
ValidateToolArguments clones, prepares optional nulls, coerces and validates the call's arguments without changing the provider call.
func WithMutationTicket ¶
func WithMutationTicket(ctx context.Context, ticket *MutationTicket) context.Context
WithMutationTicket returns ctx carrying a reservation for the tool call it is passed into. Execute implementations that also implement QueueOrderable must check MutationTicketFromContext and honor an existing reservation instead of registering a second time.
func WithToolEnvironment ¶
func WithToolEnvironment(ctx context.Context, env ToolEnvironment) context.Context
WithToolEnvironment returns ctx carrying env for the tools it executes.
Types ¶
type AfterToolCallHook ¶
type AfterToolCallHook func(ctx context.Context, toolCallID, toolName string, args json.RawMessage, result AgentToolResult) AfterToolCallResult
AfterToolCallHook is called after a tool executes and may override its result. Full upstream contract, including terminate signals and result overrides. Replaces the old void-return signature which had no override capability. upstream: agent-loop.ts afterToolCall({ toolCall, args, result, isError })
type AfterToolCallResult ¶
type AfterToolCallResult struct {
Content []ai.ToolResultMessageContent
Details any
IsError *bool // nil = keep original
Usage *ai.Usage
Terminate *bool
// StructuredContent replaces the result's structured content. When Content is replaced without it, the structured content is dropped, because it may no longer match the content.
StructuredContent json.RawMessage
}
AfterToolCallResult carries per-tool overrides returned by AfterToolCallHook. Mirrors upstream types.ts AfterToolCallResult (agent-loop.ts:617-640). Merge semantics: field-by-field replace; no deep merge. Nil fields keep the original; a non-nil empty Content replaces it with an empty array.
- Content: if non-nil, replaces the ordered content, including an empty array.
- IsError: if non-nil, replaces the tool result error flag.
- Usage: if non-nil, replaces the tool result usage.
- Terminate: if non-nil, replaces the early-termination hint. The agent stops after the batch only when every finalized result terminates (upstream shouldTerminateToolBatch).
type Agent ¶
type Agent struct {
// contains filtered or unexported fields
}
Agent is the agent loop.
Mirrors upstream packages/agent/src/agent.ts (class Agent).
func (*Agent) Abort ¶
func (a *Agent) Abort()
Abort cancels the active run. Calling Abort on an idle agent does nothing.
func (*Agent) AddAfterToolCallHook ¶
func (a *Agent) AddAfterToolCallHook(h AfterToolCallHook)
AddAfterToolCallHook appends a hook that fires after each tool execution. Mirrors upstream agent.afterToolCall assignment (agent-session.ts:396).
func (*Agent) AddBeforeToolCallHook ¶
func (a *Agent) AddBeforeToolCallHook(h BeforeToolCallHook)
AddBeforeToolCallHook appends a hook that fires before each tool execution. Mirrors upstream agent.beforeToolCall assignment (agent-session.ts:373).
func (*Agent) BeginSendContent ¶
func (a *Agent) BeginSendContent(ctx context.Context, content []ai.UserContentBlock) (*PromptRun, error)
BeginSendContent claims the agent and binds its cancellation context synchronously without starting events. Pending preflight is not an active run; a claimed prompt is active before its first awaited listener finishes.
func (*Agent) BeginSendMessages ¶
BeginSendMessages claims a turn for already-built messages without starting events. The owner calls Run exactly once, even if Start fails, just as for BeginSendContent.
func (*Agent) ClearAllQueues ¶
func (a *Agent) ClearAllQueues() (steering, followUp []AgentMessage)
ClearAllQueues removes and returns all pending messages from both queues.
func (*Agent) ClearFollowUpQueue ¶
func (a *Agent) ClearFollowUpQueue() []AgentMessage
ClearFollowUpQueue removes and returns all pending follow-up messages.
func (*Agent) ClearSteeringQueue ¶
func (a *Agent) ClearSteeringQueue() []AgentMessage
ClearSteeringQueue removes and returns all pending steering messages.
func (*Agent) ClearSystemPrompt ¶
func (a *Agent) ClearSystemPrompt()
ClearSystemPrompt removes a SetSystemPrompt projection, so later requests use the transcript's own system prompt again.
func (*Agent) Continue ¶
func (a *Agent) Continue(ctx context.Context) ([]AgentMessage, error)
Continue runs the agent loop from the current message state without prepending a new user message. Used to retry a turn after auto-compaction when an overflow error is recovered by compacting and replaying.
If the last message is an assistant message, Continue first checks the steering queue, then the follow-up queue. Without queued input it rejects the assistant tail. Mirrors upstream Agent.continue (packages/agent/src/agent.ts).
func (*Agent) ErrorMessage ¶
ErrorMessage returns the last failed turn's error, cleared at the next run or reset.
func (*Agent) FinishTurnHook ¶
func (a *Agent) FinishTurnHook() FinishTurn
FinishTurnHook returns the current FinishTurn hook, or nil.
func (*Agent) FollowUp ¶
func (a *Agent) FollowUp(msg AgentMessage)
FollowUp enqueues a follow-up message. Follow-up messages are delivered only after the agent has no more tool calls AND no steering messages, starting a fresh outer-loop iteration.
func (*Agent) FollowUpMode ¶
FollowUpMode returns the current follow-up drain policy.
func (*Agent) HasPendingMessages ¶
HasPendingMessages reports whether either queue has messages.
func (*Agent) HasQueuedMessages ¶
HasQueuedMessages reports whether either queue still contains pending messages. Mirrors upstream agent.ts:290.
func (*Agent) IsStreaming ¶
IsStreaming returns true when the agent is actively in a Send/Continue loop. Mirrors upstream AgentState.isStreaming for extension queries.
func (*Agent) Messages ¶
func (a *Agent) Messages() []AgentMessage
Messages returns the current message history.
func (*Agent) MessagesSnapshot ¶
func (a *Agent) MessagesSnapshot() []AgentMessage
MessagesSnapshot copies the message history. Unlike Messages it is safe to call from any goroutine while a run appends.
func (*Agent) Model ¶
Model returns the active model. New agents use the upstream unknown descriptor until one is selected; SetModel(nil) clears it.
func (*Agent) ObserveRunSignal ¶
func (a *Agent) ObserveRunSignal(observe func()) func()
ObserveRunSignal registers observe to run after a run claims the agent, when Signal already returns the run's context, and after the run releases it, when Signal already returns nil. Pi's `agent.signal` is a getter (agent.ts:336-338), so an owner that replicates the signal elsewhere learns of both instants here. observe runs on the goroutine that changes the run, after the agent's lock is released, so it may call Signal; the run waits for observe to return. The returned function removes the observer and can be called repeatedly.
func (*Agent) PeekQueuedMessages ¶
func (a *Agent) PeekQueuedMessages() []AgentMessage
PeekQueuedMessages previews the messages selected for the next turn without consuming them: the steering queue's selection, or the follow-up queue's when no steering is queued. Mirrors upstream Agent.peekQueuedMessages.
func (*Agent) PendingMessages ¶
func (a *Agent) PendingMessages() (steering, followUp []AgentMessage)
PendingMessages returns a snapshot of both queues without draining. Used for UI display (e.g. "2 steering, 1 follow-up pending").
func (*Agent) PendingToolCalls ¶
PendingToolCalls returns the active tool call IDs in start order.
func (*Agent) PrepareNextTurnHook ¶
func (a *Agent) PrepareNextTurnHook() PrepareNextTurn
PrepareNextTurnHook returns the current PrepareNextTurn hook, or nil.
func (*Agent) PrepareRequestHook ¶
func (a *Agent) PrepareRequestHook() PrepareRequest
PrepareRequestHook returns the current PrepareRequest hook, or nil.
func (*Agent) QueueNextTurn ¶
func (a *Agent) QueueNextTurn(msg AgentMessage)
QueueNextTurn defers a message to the start of the next user turn, where it is injected beside the user message as context for the first model call.
This is not FollowUp. A follow-up continues the turn that is running, so it reaches the model only after the current response completes; a message meant to inform the next prompt would arrive a model call too late, and on an idle agent it would sit in a queue with no goroutine to drain it.
func (*Agent) Reset ¶
Reset retains the replayed system baseline and clears conversation state and queues. It refuses while a run is active, as upstream Agent.reset throws. Mirrors upstream Agent.reset.
func (*Agent) Send ¶
Send sends a plain-text user message and runs the agent loop until the LLM stops calling tools. Steering and follow-up messages queued via Steer/FollowUp are polled at the appropriate points in the loop.
func (*Agent) SendContent ¶
func (a *Agent) SendContent(ctx context.Context, content []ai.UserContentBlock) ([]AgentMessage, error)
SendContent is the structured-content variant of Send.
func (*Agent) SendMessages ¶
func (a *Agent) SendMessages(ctx context.Context, msgs []AgentMessage) ([]AgentMessage, error)
SendMessages seeds a turn with already-built messages instead of a user prompt, mirroring upstream agent.prompt(messages) (agent-session.ts:1063). An extension delivering a custom message while the agent is idle needs a turn to start from that message; without this the message can only be enqueued for a turn that may never run.
func (*Agent) SetBeforeProviderHook ¶
SetBeforeProviderHook transforms each provider's final wire payload. Mirrors upstream before_provider_request through StreamOptions.OnPayload.
func (*Agent) SetFinishTurn ¶
func (a *Agent) SetFinishTurn(fn FinishTurn)
SetFinishTurn replaces the FinishTurn hook for later runs. Mirrors assigning upstream's public Agent.finishTurn; FinishTurnHook returns the current one so a caller can chain it.
func (*Agent) SetFollowUpMode ¶
SetFollowUpMode changes the follow-up queue's drain policy.
func (*Agent) SetMessages ¶
func (a *Agent) SetMessages(msgs []AgentMessage)
SetMessages replaces the message history (used for session restore). The agent keeps a copy of the top-level slice, as upstream's state.messages setter copies the assigned array.
func (*Agent) SetModel ¶
SetModel swaps the active LLM model. The next streaming turn uses the new provider/model. The agent's tools, system prompt, and message history are unchanged. Mid-session model switch.
func (*Agent) SetPrepareNextTurn ¶
func (a *Agent) SetPrepareNextTurn(fn PrepareNextTurn)
SetPrepareNextTurn replaces the PrepareNextTurn hook for later runs. Mirrors assigning upstream's public Agent.prepareNextTurnWithContext.
func (*Agent) SetPrepareRequest ¶
func (a *Agent) SetPrepareRequest(fn PrepareRequest)
SetPrepareRequest replaces the PrepareRequest hook for later runs. Mirrors assigning upstream's public Agent.prepareRequest.
func (*Agent) SetSessionID ¶
SetSessionID updates the session ID used for prompt caching. Called after session creation/resume when the stable session ID is known.
func (*Agent) SetSteeringMode ¶
SetSteeringMode changes the steering queue's drain policy.
func (*Agent) SetStreamFunction ¶
SetStreamFunction replaces the provider request function for subsequent requests, matching Agent.streamFunction assignment in Pi. Nil restores the stock stream.
func (*Agent) SetSystemPrompt ¶
SetSystemPrompt projects a replacement system prompt onto subsequent provider requests without rewriting transcript history.
func (*Agent) SetThinkingLevel ¶
func (a *Agent) SetThinkingLevel(level ai.ThinkingLevel)
SetThinkingLevel updates the reasoning depth used for future Send calls. Wired by InteractiveMode.cycleThinkingLevel() on Shift+Tab. The current in-flight call (if any) is unaffected; the new level applies starting with the next agent.Send invocation.
func (*Agent) SetTransformContext ¶
func (a *Agent) SetTransformContext(fn func(msgs []AgentMessage) []AgentMessage)
SetTransformContext sets a hook that fires before each LLM call to allow extensions to modify the message context. Mirrors upstream context event.
func (*Agent) SetTransformContextWithContext ¶
func (a *Agent) SetTransformContextWithContext(fn func(context.Context, []AgentMessage) ([]AgentMessage, error))
SetTransformContextWithContext installs a request transform with cancellation and error propagation owned by the active agent run.
func (*Agent) SetTransformHeaders ¶
func (a *Agent) SetTransformHeaders(fn func(context.Context, ai.ProviderHeaders) (ai.ProviderHeaders, error))
SetTransformHeaders sets the hook that rewrites each provider request's merged HTTP headers. Mirrors upstream StreamOptions.transformHeaders.
func (*Agent) SetTransport ¶
SetTransport updates the preferred provider transport for future Send calls.
func (*Agent) Steer ¶
func (a *Agent) Steer(msg AgentMessage)
Steer enqueues a steering message. Steering messages are delivered after the current tool batch finishes but before the next LLM call, allowing the user to redirect the agent mid-turn.
func (*Agent) SteeringMode ¶
SteeringMode returns the current steering drain policy.
func (*Agent) StreamFunction ¶
Ports packages/agent/src/agent.ts StreamFunction returns the caller's stream override. Nil denotes the stock stream, allowing summarization to distinguish optional custom-stream auth from required stock auth without comparing Go function values.
func (*Agent) StreamingMessage ¶
func (a *Agent) StreamingMessage() *AgentMessage
StreamingMessage returns a snapshot of the message currently streaming.
func (*Agent) Subscribe ¶
func (a *Agent) Subscribe(listener func(context.Context, AgentEvent) error) func()
Subscribe registers a lifecycle listener. Listeners run in subscription order with the active run context; the run waits for each callback to return. The returned function removes this subscription and can be called repeatedly.
func (*Agent) SystemPrompt ¶
SystemPrompt returns the current replayed instructions or an explicit provider prompt override. It is safe to call while the agent appends messages.
func (*Agent) SystemPromptOverride ¶
SystemPromptOverride returns only the explicit provider projection and its presence, not replayed transcript instructions.
func (*Agent) SystemPromptSnapshot ¶
SystemPromptSnapshot reads the prompt and whether it is present under one lock. Presence distinguishes an empty projected prompt from an uninitialized transcript.
func (*Agent) ThinkingLevel ¶
func (a *Agent) ThinkingLevel() ai.ThinkingLevel
ThinkingLevel returns the reasoning depth used for future Send calls.
func (*Agent) Timings ¶
Timings returns the agent's timing recorder. Read-only consumers (status line, /cost, --diagnose) hold this reference for the session's lifetime and call Snapshot()/Elapsed() on demand.
func (*Agent) ToolExecutionMode ¶
func (a *Agent) ToolExecutionMode() ToolExecutionMode
ToolExecutionMode returns the batch strategy for assistant messages with several tool calls. Mirrors upstream Agent.toolExecution.
func (*Agent) WaitForIdle ¶
func (a *Agent) WaitForIdle()
WaitForIdle waits for the current run and its synchronous listeners to settle. It returns immediately when no run is active.
type AgentEndEvent ¶
type AgentEndEvent struct {
Messages []AgentMessage
WillRetry bool
}
type AgentEvent ¶
type AgentEvent interface {
// contains filtered or unexported methods
}
AgentEvent is emitted by the agent loop to notify observers.
func RefreshEvent ¶
func RefreshEvent(event AgentEvent) AgentEvent
RefreshEvent returns the message event with the assistant message's and the provider event's partial fields set to the stream state at this call. A host dispatcher calls it when it delivers a retained event to a listener after an awaited step. Other events are returned unchanged.
func WithEventObservation ¶
func WithEventObservation(event AgentEvent, observation *ai.StreamObservation) AgentEvent
WithEventObservation carries a stream scope across synchronous host dispatch without changing message identity or serialized fields. Events outside the message lifecycle are unchanged.
type AgentLoopTurnUpdate ¶
type AgentLoopTurnUpdate struct {
// Context replaces the loop context for the next provider request.
Context []AgentMessage
// Messages are appended before the next provider request, with normal
// lifecycle events.
Messages []AgentMessage
// Model is the model for the next provider request.
Model *ai.Model
// ThinkingLevel is the thinking level for the next provider request.
ThinkingLevel *ai.ThinkingLevel
}
AgentLoopTurnUpdate carries optional next-turn overrides returned by PrepareNextTurn. Mirrors upstream AgentLoopTurnUpdate.
type AgentMessage ¶
type AgentMessage struct {
System *ai.SystemMessage
User *UserMessage
Assistant *AssistantMessage
ToolResult *ToolResultMessage
// Custom message types (bash execution, branch summary, etc.)
Custom map[string]any // raw JSON for custom types
}
AgentMessage is the union of all message types. Only one field is non-nil.
func NormalizeMessages ¶
func NormalizeMessages(msgs []AgentMessage, model *ai.Model) []AgentMessage
NormalizeMessages filters and normalizes msgs before they are converted to the provider wire format by convertToLLM. Two guarantees are provided:
Assistant messages with StopReason "error" or "aborted" are dropped. Replaying them causes API errors (partial reasoning, orphaned tool calls, OpenAI "reasoning without following item").
Orphaned tool calls: tool_use blocks in an assistant message with no matching tool_result: get a synthetic ToolResultMessage injected immediately after the assistant message. This keeps the message sequence valid for all providers.
Cross-model thinking blocks are normalized against the target model (upstream transform-messages.ts isSameModel branch): redacted thinking is dropped for a different model, same-model signed thinking is kept for replay, empty thinking is dropped, and other cross-model thinking is converted to plain text so a foreign reasoning signature never reaches a provider converter. model may be nil on contextless/test paths, which is treated as same-model (thinking passes through).
The returned slice may be shorter than msgs (dropped aborted/errored entries) or longer (inserted synthetic tool results). Assistant entries whose thinking is normalized are copied; other non-modified entries share their underlying struct pointers with msgs.
func (AgentMessage) Clone ¶
func (m AgentMessage) Clone() AgentMessage
Clone copies the message envelope and mutable top-level slices/maps. A streaming assistant becomes an independently owned current observation.
func (AgentMessage) ContentBlocks ¶
func (m AgentMessage) ContentBlocks() []ai.ContentBlock
func (AgentMessage) MarshalJSON ¶
func (m AgentMessage) MarshalJSON() ([]byte, error)
MarshalJSON emits the upstream flat role-discriminated AgentMessage union. User strings and text blocks retain their JavaScript UTF-16 units.
func (*AgentMessage) UnmarshalJSON ¶
func (m *AgentMessage) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes the upstream flat role-discriminated AgentMessage union and retains lone UTF-16 units in user content as WTF-8.
type AgentOptions ¶
type AgentOptions struct {
Model *ai.Model
Tools []AgentTool
SystemPrompt string
MaxTurns int // 0 = unlimited, as upstream, which has no turn cap
ThinkingLevel ai.ThinkingLevel
ThinkingBudgets *ai.ThinkingBudgets
Transport ai.Transport
// SessionID is forwarded to the provider for prompt caching
// (OpenAI prompt_cache_key). Set by the session wrapper when
// the session has a stable identifier.
SessionID string
// SessionFile, when set, reports the session file tools may expose as
// PI_SESSION_FILE. Nil or an empty result exports nothing.
SessionFile func() string
// SteeringMode controls how steering messages are drained (default: one-at-a-time).
// Mirrors upstream packages/agent/src/agent.ts:104.
SteeringMode QueueMode
// FollowUpMode controls how follow-up messages are drained (default: one-at-a-time).
// Mirrors upstream packages/agent/src/agent.ts:105.
FollowUpMode QueueMode
BeforeToolCall []BeforeToolCallHook
AfterToolCall []AfterToolCallHook
// PrepareToolResult processes the final extension-modified result before
// events and persistence. Processing failures preserve the original result.
PrepareToolResult func(context.Context, AgentToolResult) AgentToolResult
// FinishTurn runs after a turn's assistant message and tool results and
// before TurnEndEvent; it may end the run or request one more request.
FinishTurn FinishTurn
// PrepareRequest runs immediately before every provider request and may
// replace the context, model, and thinking level for the run.
PrepareRequest PrepareRequest
// ConvertToLlm converts the transformed agent context to provider messages.
// The run waits for it and reports conversion failures through its lifecycle.
// Nil uses the standard message conversion.
ConvertToLlm func([]AgentMessage) ([]ai.Message, error)
// TransformLLMMessages post-processes the provider messages that the
// built-in conversion produced for each request. The coding session uses
// it as upstream createAgentSession wraps convertToLlm
// (convertToLlmWithBlockImages in sdk.ts).
TransformLLMMessages func([]ai.Message) []ai.Message
// PrepareNextTurn runs before the next turn starts when the loop
// continues, and may replace or extend the next request's state.
PrepareNextTurn PrepareNextTurn
// PreparePrompt lets the owning Session prepare new prompt messages before
// their lifecycle events and persistence. It does not run for continuation
// or queued steering/follow-up messages.
PreparePrompt func(context.Context, []AgentMessage) ([]AgentMessage, error)
// ToolExecution is the batch strategy for assistant messages with several
// tool calls (default parallel). A tool whose ExecutionMode is sequential
// forces its batch to run sequentially. Mirrors upstream Agent.toolExecution.
ToolExecution ToolExecutionMode
// EventCh receives agent events. If nil, events are discarded. Every
// event is delivered, including after the run's context is cancelled, as
// upstream awaits every listener; emit blocks until the event is received
// or EventDone is closed.
EventCh chan<- AgentEvent
// EventDone, when closed, reports that EventCh has no receiver anymore.
// Events emitted after that are dropped instead of blocking the agent.
EventDone <-chan struct{}
// OnEvent, if set, runs synchronously for every event before the event is
// persisted or delivered, as upstream Agent awaits its listeners before it
// continues. It may replace a message_end message in place (mutating the
// pointed-to message or custom map), and the replacement is what agent
// state, persistence and EventCh observe.
OnEvent func(AgentEvent)
// AfterEvent runs after persistence and channel publication, before the loop polls queued work. An error fails the same run.
AfterEvent func(AgentEvent) error
// StreamFn sends each provider request. Nil uses DefaultStreamFn or the model's native provider.
// Mirrors upstream AgentOptions.streamFn.
StreamFn StreamFn
// DefaultStreamFn supplies the host's stock request path without making it a caller override. Nil uses the configured host default.
DefaultStreamFn StreamFn
// OnMessagePersist, if set, is invoked exactly once for each NEW message
// the agent produces during a turn: the user prompt, steering / follow-up
// user messages, assistant messages (including aborted/error ones), and
// tool-result messages: in production order. It is driven by message_end in
// emit() and is NOT called for replayed/resumed context (the runLoop replay
// emits message_end only for this run's new messages, never loaded history).
// Mirrors upstream's single incremental persistence site (agent-session.ts
// message_end handler) so a turn interrupted mid-flight is durably recorded
// instead of lost on the next resume. An error fails the run the way a
// throwing message_end listener does upstream: the loop stops and the run
// ends with an error assistant message.
OnMessagePersist func(AgentMessage) error
// OnProviderStreamEvent is forwarded to every provider request. Mirrors upstream AgentOptions.onProviderStreamEvent (packages/agent/src/agent.ts:122).
OnProviderStreamEvent func(ctx context.Context, data any, model *ai.Model) error
}
AgentOptions configures the agent loop.
type AgentRequestUpdate ¶
type AgentRequestUpdate struct {
Context []AgentMessage
Model *ai.Model
ThinkingLevel *ai.ThinkingLevel
}
AgentRequestUpdate replaces runtime state for the provider request being prepared and later requests in the run. Mirrors upstream AgentRequestUpdate (AgentLoopTurnUpdate without messages).
type AgentSettledEvent ¶
type AgentSettledEvent struct{}
AgentSettledEvent fires once an agent run has fully settled: no automatic retry, compaction, or queued continuation will follow. Upstream emits it from the _runAgentPrompt finally (agent-session.ts:1073) to both the extension runner and the session event stream.
type AgentStartEvent ¶
type AgentStartEvent struct{}
type AgentTool ¶
type AgentTool interface {
// Name is the tool's name as known to the LLM.
Name() string
// Label returns a human-readable display name for the tool header.
// If empty, Name() is used for display. Mirrors upstream AgentTool.label.
Label() string
// Schema returns the JSON Schema for the tool's parameters.
Schema() ai.ToolSchema
// Execute runs the tool.
Execute(ctx context.Context, toolCallID string, params json.RawMessage,
onUpdate ToolUpdateCallback) (AgentToolResult, error)
// ExecutionMode returns the tool's parallelism preference.
ExecutionMode() ToolExecutionMode
}
AgentTool is the interface that all tools must implement.
type AgentToolCall ¶
AgentToolCall is a tool call block of an assistant message. Mirrors upstream AgentToolCall.
type AgentToolCallOutcome ¶
type AgentToolCallOutcome struct {
ToolCall AgentToolCall
Result AgentToolResult
IsError bool
}
AgentToolCallOutcome is the final outcome of a tool call after the hooks ran. Mirrors upstream AgentToolCallOutcome (packages/agent/src/types.ts).
func RunToolCall ¶
func RunToolCall(ctx context.Context, call AgentToolCall, options RunToolCallOptions) (AgentToolCallOutcome, error)
RunToolCall runs one tool call through the same steps as a model-issued call: argument preparation, schema validation, the before hooks, execution, and the after hooks. It emits no events and adds no messages. Tools that call other tools use it so the hooks (for example permission checks) apply to those calls too. Mirrors upstream runToolCall (agent-loop.ts:800-820).
It never fails for tool failures: unknown tools, validation errors, blocked calls, and panics come back as an outcome with IsError set. It returns the first error of options.OnUpdate after the tool returned, without running the after hooks, as upstream's promise rejects.
type AgentToolResult ¶
type AgentToolResult struct {
// MemberOrder names the members of the result object in the order its tool wrote them (content, details,
// isError, structuredContent, usage, terminate). Upstream hands the tool's own object on, so JSON.stringify
// writes its members in that order; a result without it (a built-in tool, a Go tool) has the declared order.
// upstream: agent-loop.ts:778-786, 912-919
MemberOrder []string
Content []ai.ToolResultMessageContent
Details any
// StructuredContent is the machine-readable result of a tool that declares
// an output schema. upstream: structuredContent?: JsonValue
StructuredContent json.RawMessage
// IsError is upstream's `result.isError`: the tool returned a failure instead of throwing it, so
// details and structuredContent are kept. A thrown error, an unknown tool, invalid arguments and a
// blocked call produce a result without it; the failure is reported by ToolExecutionEndEvent.IsError
// and AgentToolCallOutcome.IsError. upstream: types.ts:436-441, agent-loop.ts:906-910
IsError bool
// Thrown marks a result that stands for an error upstream's tool throws. The agent reports the call as failed, drops
// the result's IsError and Thrown, and keeps the rest, which is createErrorToolResult's content and empty details
// (agent-loop.ts:906-910). A tool that returns a Go error has the same effect.
Thrown bool
// StructuredContentAppended records that afterToolCall gave a result that had no structuredContent one. Upstream's
// `{...result}` spread keeps the tool's key order and assigning an existing key keeps its position, so only a key the
// hook adds follows every key the tool set (agent-loop.ts:877-889). It only orders the serialized result.
StructuredContentAppended bool
// Usage is the usage of the tool execution itself, if available. It is
// not used for main LLM context accounting. upstream: usage?: Usage
Usage *ai.Usage
// Terminate hints that the agent should stop after the current tool
// batch. Early termination happens only when every finalized result in
// the batch sets it. upstream: terminate?: boolean
Terminate bool
// Preview is an optional short summary shown when the tool result is
// collapsed in the TUI. When non-empty, overrides the default
// tail-preview behavior. Extensions can set this to provide a
// custom collapsed view (e.g. a table header, a line count, or a
// brief summary) without implementing a full BodyRenderer.
// pig extension: no upstream equivalent (Pi extensions use in-process
// renderResult callbacks; subprocess extensions need a serializable
// alternative).
Preview string
}
AgentToolResult carries the ordered text/image blocks returned by a tool. Ports packages/agent/src/types.ts.
func (AgentToolResult) DetailsNull ¶
func (r AgentToolResult) DetailsNull() bool
DetailsNull reports a result that holds details: null: the tool wrote the details member with no value. A Go tool that leaves Details nil and records no MemberOrder holds no details.
func (AgentToolResult) Images ¶
func (r AgentToolResult) Images() []ai.ImageContent
Images selects image blocks for displays with a separate image area.
func (AgentToolResult) MemberNames ¶
func (r AgentToolResult) MemberNames() []string
MemberNames lists the members of the result object this result holds (content, details, structuredContent, isError, usage, terminate), in the order upstream's object keeps them. Without a recorded MemberOrder that is the order the built-in tools build theirs in, with a structuredContent a hook added last. With one it is the tool's own order, and a member the tool did not set, which a hook added, follows the tool's in the order of the hook's spread, `{...result, content, details, usage, terminate}`, then the structuredContent assigned after it (agent-loop.ts:877-889). Content is always listed. A member MemberOrder names is held even when its value is a zero value (details or usage null, isError or terminate false): the tool wrote it, so upstream's object has it and JSON.stringify writes it. upstream: agent-loop.ts:778-786, 877-889, 912-919; coding-agent/src/core/tools/bash.ts:403-409
func (AgentToolResult) Text ¶
func (r AgentToolResult) Text() string
Text joins text blocks for text-only displays; Content retains their boundaries and image positions.
type AgentTurnAction ¶
type AgentTurnAction string
AgentTurnAction is the action of an AgentTurnDecision.
const ( // AgentTurnContinue ensures one more provider request after the turn. AgentTurnContinue AgentTurnAction = "continue" // AgentTurnEnd ends the run without polling queues or preparing another request. AgentTurnEnd AgentTurnAction = "end" )
type AgentTurnContext ¶
type AgentTurnContext struct {
// Message is the assistant message that completed the turn.
Message *AssistantMessage
// ToolResults are the tool result messages emitted for the completed turn.
ToolResults []ToolResultMessage
// Context is the loop context after the turn's assistant message and tool
// results have been appended.
Context []AgentMessage
// NewMessages are the messages this run returns if it exits now. Prompt
// runs include the initial prompt messages; continuation runs do not
// include pre-existing context messages.
NewMessages []AgentMessage
}
AgentTurnContext is passed to completed-turn callbacks (FinishTurn and PrepareNextTurn). Mirrors upstream packages/agent/src/types.ts AgentTurnContext.
type AgentTurnDecision ¶
type AgentTurnDecision struct {
Action AgentTurnAction
}
AgentTurnDecision is returned by FinishTurn. A nil decision preserves normal scheduling. Mirrors upstream AgentTurnDecision.
type ArgumentPreparer ¶
type ArgumentPreparer interface {
PrepareArguments(raw json.RawMessage) (json.RawMessage, error)
}
ArgumentPreparer is an optional interface tools may implement to normalize / coerce their raw input BEFORE schema validation runs. Mirrors upstream's per-tool `prepareArguments` hook (.upstream/current/packages/coding-agent/src/core/tools/edit.ts:308, `parameters: editSchema, ... prepareArguments: prepareEditArguments`).
Use cases:
- edit tool: rewrites the legacy `{path, oldText, newText}` flat input shape into `{path, edits:[{oldText, newText}]}` so the strict editSchema accepts it (LLMs like Opus 4.6 / GLM-5.1 still emit the flat shape).
- any future tool that accepts multiple wire shapes for the same semantic input.
Without this hook, schema validation in dispatch() rejects valid legacy inputs before tool.Execute() ever runs, breaking parity with upstream which normalizes first and validates after.
type AssistantMessage ¶
type AssistantMessage struct {
Role string `json:"role"` // "assistant"
Content []ai.AssistantContentBlock `json:"content"`
Thinking string `json:"-"`
Timestamp int64 `json:"timestamp"`
Usage *ai.Usage `json:"usage,omitempty"`
API ai.API `json:"api,omitempty"`
Provider string `json:"provider,omitempty"`
ModelID string `json:"model,omitempty"`
ResponseModel string `json:"responseModel,omitempty"`
ResponseID string `json:"responseId,omitempty"`
ProviderThinkingLevel string `json:"providerThinkingLevel,omitempty"`
// ThinkingLevel is the level the agent loop requested for this response; see ai.AssistantMessage.ThinkingLevel.
ThinkingLevel ai.ModelThinkingLevel `json:"thinkingLevel,omitempty"`
Diagnostics []ai.AssistantMessageDiagnostic `json:"diagnostics,omitempty"`
Deferred *ai.DeferredHandle `json:"deferred,omitempty"`
// StopReason records why the assistant turn ended. Mirrors upstream
// AssistantMessage.stopReason in packages/ai/src/types.ts.
// Values: "stop" (normal), "toolUse" (tool calls present),
// "aborted" (context cancelled), "error" (EventError received).
StopReason ai.StopReason `json:"stopReason,omitempty"`
// ErrorMessage holds the error string when StopReason == "error".
ErrorMessage string `json:"errorMessage,omitempty"`
RawStopReason string `json:"rawStopReason,omitempty"`
EndTurn *bool `json:"endTurn,omitempty"`
// ThinkingSignature is a legacy runtime convenience; durable signatures
// live on ThinkingContent blocks in the upstream wire shape.
ThinkingSignature string `json:"-"`
// contains filtered or unexported fields
}
AssistantMessage is a streamed response from the LLM. Streaming events retain a shallow provider view; Observe and JSON serialization read its current nested state without mutating these exported fields.
func (*AssistantMessage) LLMMessage ¶
func (m *AssistantMessage) LLMMessage() ai.AssistantMessage
LLMMessage returns the provider-facing form of an assistant message. Plain messages share content and diagnostics slices with m; retained streaming views produce an owned observation.
func (AssistantMessage) MarshalJSON ¶
func (m AssistantMessage) MarshalJSON() ([]byte, error)
MarshalJSON observes retained streaming messages at the serialization boundary.
func (*AssistantMessage) Observe ¶
func (m *AssistantMessage) Observe() *AssistantMessage
Observe returns an independently owned observation of the message. A streaming shallow view keeps its copied top-level values while observing its retained nested objects.
func (*AssistantMessage) ObserveUsage ¶
func (m *AssistantMessage) ObserveUsage() *ai.Usage
ObserveUsage returns an owned usage snapshot without traversing message content or metadata. Streaming views observe their retained usage reference; ordinary absent usage stays absent.
type AutoRetryEndEvent ¶
type AutoRetryEndEvent struct {
Success bool
Attempt int
FinalError string // set when Success==false
}
AutoRetryEndEvent fires when an auto-retry cycle completes (success or exhausted). Mirrors upstream auto_retry_end (agent-session.ts:131).
type AutoRetryStartEvent ¶
AutoRetryStartEvent fires when pig is about to retry a failed request due to a transient error (overload, rate limit, server error). Mirrors upstream auto_retry_start (agent-session.ts:130).
type BashExecutionUpdateEvent ¶
BashExecutionUpdateEvent reports one command-output delta. A nil ID omits the correlation identifier; a non-nil empty ID remains explicit.
type BeforeToolCallHook ¶
type BeforeToolCallHook func(ctx context.Context, toolCallID, toolName string, args json.RawMessage) ToolCallHookResult
BeforeToolCallHook is called before a tool executes. Return ToolCallHookResult{Block: true} to prevent execution.
type CompactionEndEvent ¶
type CompactionEndEvent struct {
Reason string
Aborted bool
WillRetry bool
Summary string
FirstKeptEntryID string
TokensBefore int
EstimatedTokensAfter int
Usage *ai.Usage
Details any
ErrorMessage string
}
CompactionEndEvent fires when compaction completes, aborts, or errors. Mirrors upstream compaction_end event (agent-session.ts).
type CompactionStartEvent ¶
type CompactionStartEvent struct {
Reason string // "manual" | "threshold" | "overflow"
}
CompactionStartEvent fires when auto-compaction or /compact begins. Mirrors upstream compaction_start event (agent-session.ts).
type ContextUsageEstimate ¶
type ContextUsageEstimate struct {
Tokens int
UsageTokens int
TrailingTokens int
LastUsageIndex int // -1 if not found
}
ContextUsageEstimate is the result of EstimateContextTokens. Mirrors upstream ContextUsageEstimate (compaction.ts:177).
func EstimateContextTokens ¶
func EstimateContextTokens(messages []AgentMessage) ContextUsageEstimate
EstimateContextTokens estimates context token usage from a message slice. Uses the last assistant usage that is not aborted, errored, or all-zero (upstream getAssistantUsage), plus a chars/4 estimate of the messages trailing it; falls back to a full estimate when no usage is present. Mirrors upstream estimateContextTokens (compaction.ts:186).
type EntryAppendedEvent ¶
type EntryAppendedEvent struct {
Entry json.RawMessage
}
EntryAppendedEvent reports a Session entry appended outside the agent loop, such as cache-warming usage. Entry is the persisted entry's JSON. Mirrors upstream AgentSessionEvent entry_appended (agent-session.ts:178).
type FinishTurn ¶
type FinishTurn func(ctx context.Context, turn AgentTurnContext) (*AgentTurnDecision, error)
FinishTurn is called after a completed assistant turn and all of its tool-result messages, but before TurnEndEvent. On a normal turn, AgentTurnContinue ensures one next provider request: tool-result, steering, or follow-up scheduling satisfies that request without adding another; otherwise the loop continues once with the current context. Error and aborted responses remain hard exits. ctx is the run's context (upstream's abort signal). A rejected callback enters the owning failed-turn lifecycle. Mirrors upstream FinishTurn.
type MessageEndEvent ¶
type MessageEndEvent struct {
Message AgentMessage
// contains filtered or unexported fields
}
type MessageStartEvent ¶
type MessageStartEvent struct {
Message AgentMessage
// contains filtered or unexported fields
}
type MessageUpdateEvent ¶
type MessageUpdateEvent struct {
Message AgentMessage
AssistantMessageEvent ai.AssistantMessageEvent
// contains filtered or unexported fields
}
type MutationTicket ¶
type MutationTicket struct {
Wait func()
Release func()
}
MutationTicket is a reserved position in a shared per-path mutation queue (internal/codingagent/tools.FileMutationQueue), obtained synchronously, in tool-call source order, before the parallel dispatcher spawns this call's goroutine. Wait blocks until it is this ticket's turn; Release must run exactly once, after the tool's mutation completes, regardless of outcome.
func MutationTicketFromContext ¶
func MutationTicketFromContext(ctx context.Context) (*MutationTicket, bool)
MutationTicketFromContext returns the ticket the dispatcher reserved for this call, if any.
type OutputSchemaProvider ¶
type OutputSchemaProvider interface {
OutputSchema() json.RawMessage
}
OutputSchemaProvider is implemented by a tool that declares the JSON Schema of the structured content in its successful results. Mirrors upstream AgentTool.outputSchema.
type PendingMessageQueue ¶
type PendingMessageQueue struct {
// contains filtered or unexported fields
}
PendingMessageQueue is a thread-safe FIFO of agent messages with a configurable drain policy. Used for steering and follow-up queues.
Mirrors upstream packages/agent/src/agent.ts:113 (class PendingMessageQueue).
func NewPendingMessageQueue ¶
func NewPendingMessageQueue(mode QueueMode) *PendingMessageQueue
NewPendingMessageQueue creates a queue with the given drain mode.
func (*PendingMessageQueue) Clear ¶
func (q *PendingMessageQueue) Clear() []AgentMessage
Clear removes and returns all queued messages regardless of mode.
func (*PendingMessageQueue) Drain ¶
func (q *PendingMessageQueue) Drain() []AgentMessage
Drain removes and returns pending messages according to the queue's mode. "all" drains every message; "one-at-a-time" drains the oldest single message. Returns nil when the queue is empty. Mirrors upstream PendingMessageQueue.drain.
func (*PendingMessageQueue) Enqueue ¶
func (q *PendingMessageQueue) Enqueue(msg AgentMessage)
Enqueue appends a message to the queue.
func (*PendingMessageQueue) HasItems ¶
func (q *PendingMessageQueue) HasItems() bool
HasItems reports whether the queue has any pending messages.
func (*PendingMessageQueue) Len ¶
func (q *PendingMessageQueue) Len() int
Len returns the number of queued messages.
func (*PendingMessageQueue) Messages ¶
func (q *PendingMessageQueue) Messages() []AgentMessage
Messages returns copies of all queued messages without draining, whatever the mode. Used for UI display of pending steering/follow-up messages.
func (*PendingMessageQueue) Mode ¶
func (q *PendingMessageQueue) Mode() QueueMode
Mode returns the current drain mode.
func (*PendingMessageQueue) Peek ¶
func (q *PendingMessageQueue) Peek() []AgentMessage
Peek returns the messages the next Drain would remove, without removing them: every message in "all" mode, the oldest one in "one-at-a-time" mode. Mirrors upstream PendingMessageQueue.peek.
func (*PendingMessageQueue) SetMode ¶
func (q *PendingMessageQueue) SetMode(mode QueueMode)
SetMode changes the drain mode.
type PrepareNextTurn ¶
type PrepareNextTurn func(ctx context.Context, turn PrepareNextTurnContext) (*AgentLoopTurnUpdate, error)
PrepareNextTurn is called after TurnEndEvent when the loop continues, immediately before the next turn starts. ctx is the run's context. Mirrors upstream prepareNextTurnWithContext. An error preserves Promise rejection and prevents the next provider request.
type PrepareNextTurnContext ¶
type PrepareNextTurnContext = AgentTurnContext
PrepareNextTurnContext mirrors upstream's PrepareNextTurnContext, which extends AgentTurnContext without adding fields.
type PrepareRequest ¶
type PrepareRequest func(ctx context.Context, request PrepareRequestContext) (*AgentRequestUpdate, error)
PrepareRequest is called immediately before every provider request, including the first. Pending messages have already been appended and emitted when it runs, and it does not poll queues. A rejected callback enters the owning failed-turn lifecycle. Mirrors upstream PrepareRequest.
type PrepareRequestContext ¶
type PrepareRequestContext struct {
Context []AgentMessage
Model *ai.Model
ThinkingLevel ai.ThinkingLevel
}
PrepareRequestContext is the runtime state available immediately before a provider request. Mirrors upstream PrepareRequestContext.
type PromptRun ¶
type PromptRun struct {
// contains filtered or unexported fields
}
PromptRun owns a claimed prompt and its cancellation context. Start dispatches agent_start; Run drains the remaining events and releases the claim. The owner must call Run exactly once, even if Start fails or the context is cancelled.
func (*PromptRun) Run ¶
func (r *PromptRun) Run() ([]AgentMessage, error)
Run drains the claimed prompt and releases its active-run state, including when Start failed. The owner calls Run once; it calls Start when needed.
type ProxyAssistantMessageEvent ¶
type ProxyAssistantMessageEvent struct {
Type string `json:"type"`
ContentIndex int `json:"contentIndex"`
Delta string `json:"delta"`
ContentSignature *string `json:"contentSignature,omitempty"`
ID string `json:"id"`
ToolName string `json:"toolName"`
ToolCall *ai.ToolCall `json:"toolCall,omitempty"`
Reason ai.StopReason `json:"reason"`
Usage ai.Usage `json:"usage"`
ErrorMessage *string `json:"errorMessage,omitempty"`
ProviderThinkingLevel *string `json:"providerThinkingLevel,omitempty"`
}
ProxyAssistantMessageEvent is one compact event returned by a proxy server. Partial assistant messages are omitted and reconstructed by StreamProxy.
func (ProxyAssistantMessageEvent) MarshalJSON ¶
func (event ProxyAssistantMessageEvent) MarshalJSON() ([]byte, error)
MarshalJSON emits only the fields carried by the selected proxy event variant.
type ProxyStreamOptions ¶
type ProxyStreamOptions struct {
Temperature *float64
SamplingParams map[string]any
MaxTokens *int
Reasoning ai.ThinkingLevel
CacheRetention ai.CacheRetention
SessionID string
Headers ai.ProviderHeaders
Metadata map[string]any
Transport ai.Transport
ThinkingBudgets *ProxyThinkingBudgets
MaxRetryDelayMs *int
AuthToken string
ProxyURL string
}
ProxyStreamOptions configures StreamProxy. Context cancellation is the Go equivalent of upstream's optional AbortSignal. Non-nil maps retain empty objects. ThinkingBudgets preserves each budget's presence, including explicit zeros.
type ProxyThinkingBudgets ¶
type ProxyThinkingBudgets struct {
Minimal *int `json:"minimal,omitempty"`
Low *int `json:"low,omitempty"`
Medium *int `json:"medium,omitempty"`
High *int `json:"high,omitempty"`
}
ProxyThinkingBudgets carries optional per-level token budgets to the proxy server. Nil fields stay omitted; non-nil fields send their value, including zero. A non-nil empty struct sends an empty object without overriding server defaults.
type QueueMode ¶
type QueueMode string
QueueMode controls how PendingMessageQueue.Drain behaves. Mirrors upstream packages/agent/src/agent.ts:55 (type QueueMode).
type QueueOrderable ¶
type QueueOrderable interface {
ReserveMutationOrder(params json.RawMessage) (*MutationTicket, bool)
}
QueueOrderable is an optional interface a tool may implement so the parallel dispatcher reserves its place in a shared mutation queue in tool-call order, before any goroutine starts, rather than leaving admission order to goroutine-arrival order.
Upstream dispatches parallel tool calls via Promise.all(calls.map(tool => executeToolCall(tool))): Array.prototype.map runs its callback synchronously per element, in array order, so every call's synchronous prefix — including withFileMutationQueue's registration step (file-mutation-queue.ts:32-45), which chains the new call onto whatever is currently in the per-path map — completes for call N before call N+1's synchronous prefix begins, even though the calls then run concurrently (agent-loop.ts executeToolCallsParallel). Go's per-call goroutines (tool_execution.go executeToolCallsParallel) give no equivalent guarantee: nothing stops goroutine N+1 from reaching the queue before goroutine N. ReserveMutationOrder lets the dispatcher perform that registration step itself, synchronously, in its own call-ordered loop, closing that gap.
ReserveMutationOrder returns ok=false when the call will not reach the queue at all (a tool implementing this must return exactly the same ok/no-ok decision its Execute would reach, or a reservation could be left registered but never released). The returned params are the same (possibly ArgumentPreparer-normalized) arguments Execute receives.
type QueueUpdateEvent ¶
QueueUpdateEvent reports the current pending steering and follow-up text. It mirrors the coding-agent session queue_update event.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder captures per-turn and per-tool timing data for one agent session. Mirrors the data side of upstream pi's `core/timings.ts` startup profiler, but extended to cover the agent loop's lifecycle (turn start/end + tool execution latencies) so the status line, /cost, and --diagnose can all read from a single source.
All methods are safe for concurrent use. Tool execution may run in parallel goroutines, so RecordTool can be called from multiple goroutines at once.
func NewRecorder ¶
func NewRecorder() *Recorder
NewRecorder creates a Recorder. SessionStart is set to time.Now().
func (*Recorder) CurrentTurnElapsed ¶
CurrentTurnElapsed returns the elapsed time of the in-flight turn, or 0 if no turn is in flight.
func (*Recorder) EndTurn ¶
EndTurn appends the elapsed turn duration and clears turn state. Returns the recorded duration. If StartTurn was not called, returns 0.
func (*Recorder) LastTurnDuration ¶
LastTurnDuration returns the duration of the most recently completed turn, or 0 if no turn has completed yet. This is a static snapshot (not a live counter), suitable for display in the status line when the agent is idle.
func (*Recorder) RecordTool ¶
RecordTool aggregates a tool execution latency.
func (*Recorder) Snapshot ¶
func (r *Recorder) Snapshot() TimingSnapshot
Snapshot returns an immutable copy of recorder state.
type RunToolCallOptions ¶
type RunToolCallOptions struct {
ToolCallHooks
// Tools the call resolves against.
Tools []AgentTool
// OnUpdate receives the tool's progress updates.
OnUpdate ToolUpdateSink
}
RunToolCallOptions configures RunToolCall. Mirrors upstream RunToolCallOptions (.upstream/v0.99.1/packages/agent/src/agent-loop.ts:789-798). Upstream's assistantMessage and context options only feed the hooks' context argument, which Go hook signatures do not carry, so they are not modeled; the context argument of RunToolCall is upstream's signal.
type SessionInfoChangedEvent ¶
type SessionInfoChangedEvent struct {
Name string
}
SessionInfoChangedEvent reports the effective Session name; an empty name clears it.
type StreamFn ¶
type StreamFn func(ctx context.Context, model *ai.Model, transcript ai.TranscriptContext, options ai.StreamOptions) (*ai.AssistantMessageEventStream, error)
StreamFn starts one provider request for an already normalized transcript. Mirrors upstream StreamFn.
func GetDefaultStreamFn ¶
GetDefaultStreamFn returns the configured host stream function, or an error when no host has installed one. Models with native provider runtimes can still stream directly when an agent has no explicit or configured stream.
type SummarizationRetryAttemptStartEvent ¶
SummarizationRetryAttemptStartEvent fires after the backoff sleep, right before the retried summarization call. Source is "compaction" or "branchSummary"; Reason ("manual"|"threshold"|"overflow") applies to compaction and lets the TUI recreate the right status indicator. Mirrors upstream summarization_retry_attempt_start (agent-session.ts:173).
type SummarizationRetryFinishedEvent ¶
type SummarizationRetryFinishedEvent struct{}
SummarizationRetryFinishedEvent fires once when a retried summarization loop ends. Mirrors upstream summarization_retry_finished (agent-session.ts:179).
type SummarizationRetryScheduledEvent ¶
type SummarizationRetryScheduledEvent struct {
Attempt int
MaxAttempts int
DelayMs int
ErrorMessage string
}
SummarizationRetryScheduledEvent fires before the backoff sleep of each retry of a compaction or branch-summary summarization call. Mirrors upstream summarization_retry_scheduled (agent-session.ts:167).
type ThinkingLevelChangedEvent ¶
type ThinkingLevelChangedEvent struct {
Level ai.ThinkingLevel
}
ThinkingLevelChangedEvent reports an effective reasoning-level change.
type TimingEvent
deprecated
type TimingEvent = timingEvent
TimingEvent retains the former diagnostic event shape for source compatibility. The agent no longer emits timing events, matching Pi's event stream.
Deprecated: Read Agent.Timings or observe TurnEndEvent and ToolExecutionEndEvent.
type TimingSnapshot ¶
type TimingSnapshot struct {
Total time.Duration
Turns []time.Duration
ToolTotals map[string]time.Duration
ToolCounts map[string]int
CurrentTurn time.Duration // 0 if idle
// Token usage. Populated externally (not by Recorder itself) -
// the caller fills these before passing to formatCostSummary.
TotalIn int
TotalOut int
CacheRead int
CacheWrite int
// Cost is the accumulated per-turn cost (USD), tier/cache-aware.
Cost float64
}
TimingSnapshot is an immutable copy of recorder state.
type ToolCallHookResult ¶
type ToolCallHookResult struct {
Block bool
Reason string
Terminate bool
// Mutated args (if the hook wants to rewrite them). They execute without
// revalidation, as upstream executes a hook's mutated args.
Args json.RawMessage
}
ToolCallHookResult controls whether tool execution proceeds.
Mirrors upstream BeforeToolCallResult. Terminate on a blocked call joins the batch early-termination rule: the agent stops after the batch only when every finalized result in it terminates.
type ToolCallHooks ¶
type ToolCallHooks struct {
BeforeToolCall []BeforeToolCallHook
AfterToolCall []AfterToolCallHook
PrepareToolResult func(context.Context, AgentToolResult) AgentToolResult
}
ToolCallHooks are the hooks a tool call runs through. Mirrors upstream ToolCallHooks.
type ToolEnvironment ¶
type ToolEnvironment struct {
SessionID string
SessionFile string
Provider string
Model string
ThinkingLevel string
InputLimits *ai.ModelInputLimits
SupportsImages *bool
}
ToolEnvironment is the session state a tool may expose to the processes it starts. Upstream's bash tool exports it as PI_SESSION_ID, PI_SESSION_FILE, PI_PROVIDER, PI_MODEL, and PI_REASONING_LEVEL. Empty fields are not exported. Image metadata supplies the selected model profile to read tools.
func ToolEnvironmentFrom ¶
func ToolEnvironmentFrom(ctx context.Context) (ToolEnvironment, bool)
ToolEnvironmentFrom returns the environment the agent attached to a tool call.
type ToolExecutionEndEvent ¶
type ToolExecutionEndEvent struct {
ToolCallID string
ToolName string
Result AgentToolResult
// IsError is upstream's `event.isError`: the call failed, whether the tool threw, returned `isError`, or an
// afterToolCall hook said so. It is not Result.IsError. upstream: agent-loop.ts:912-919
IsError bool
Duration time.Duration
// ParentToolCallID is set on the events of a call another tool made through `ctx.executeTool()`. upstream: agent-session.ts:182-189 (WithParentToolCallId)
ParentToolCallID string
}
type ToolExecutionMode ¶
type ToolExecutionMode string
ToolExecutionMode controls parallelism.
const ( ToolModeSequential ToolExecutionMode = "sequential" ToolModeParallel ToolExecutionMode = "parallel" )
type ToolExecutionStartEvent ¶
type ToolExecutionStartEvent struct {
ToolCallID string
ToolName string
ToolLabel string // human-readable display name (empty = use ToolName)
Args json.RawMessage
// ParentToolCallID is set on the events of a call another tool made through `ctx.executeTool()`. upstream: agent-session.ts:182-189 (WithParentToolCallId)
ParentToolCallID string
}
type ToolExecutionUpdateEvent ¶
type ToolExecutionUpdateEvent struct {
ToolCallID string
ToolName string
// PartialResult is the tool's streaming progress. Subsequent updates carry the full accumulated result so far (upstream's onUpdate contract: every update is a complete-so-far snapshot, not a delta). Tool components in the TUI replace their visible body with each update, giving a live tail. upstream: agent-loop.ts:778-786
PartialResult AgentToolResult
// Args is the original tool call arguments (same as ToolExecutionStartEvent.Args).
// Passed through for extensions that need to correlate updates with inputs.
Args json.RawMessage
// ParentToolCallID is set on the events of a call another tool made through `ctx.executeTool()`. upstream: agent-session.ts:182-189 (WithParentToolCallId)
ParentToolCallID string
}
type ToolResultMessage ¶
type ToolResultMessage struct {
Role string `json:"role"` // "toolResult"
ToolCallID string `json:"toolCallId"`
ToolName string `json:"toolName"`
Content []ai.ToolResultMessageContent `json:"content"`
// Details is the tool's details value. Nil is no details unless DetailsNull is set.
Details any `json:"details,omitempty"`
// DetailsNull marks a nil Details as an explicit JSON null: the tool wrote details: null, and JSON writes
// `"details":null`. Without it a nil Details is absent and JSON omits the key. It has no effect when Details is set.
DetailsNull bool `json:"-"`
Usage *ai.Usage `json:"usage,omitempty"`
// NestedCalls are the calls this tool made to other tools. Kept for the session record; not sent to the model.
// upstream: .upstream/v0.99.1/packages/ai/src/types.ts:604
NestedCalls *ai.NestedToolCalls `json:"nestedCalls,omitempty"`
IsError bool `json:"isError"`
Timestamp int64 `json:"timestamp"`
}
ToolResultMessage carries one tool execution result back to the LLM. Mirrors upstream pi-ai ToolResultMessage.
func (ToolResultMessage) Images ¶
func (m ToolResultMessage) Images() []ai.ImageContent
func (ToolResultMessage) Result ¶
func (m ToolResultMessage) Result() AgentToolResult
Result is the result a display renders for this message: its content, details and error flag. A message with details: null gives a result that holds details: null.
func (ToolResultMessage) Text ¶
func (m ToolResultMessage) Text() string
type ToolUpdateCallback ¶
type ToolUpdateCallback func(partial AgentToolResult)
ToolUpdateCallback is called when a tool emits a streaming progress update. The partial result is the complete-so-far AgentToolResult, which the tool_execution_update event carries verbatim as `partialResult`. upstream: packages/agent/src/types.ts AgentToolUpdateCallback, agent-loop.ts:778-786
type ToolUpdateSink ¶
type ToolUpdateSink = func(partial AgentToolResult) error
ToolUpdateSink receives the progress updates of a tool call that RunToolCall runs. A non-nil error is upstream's rejected promise: the update is not delivered further, later updates still reach the sink, and the call fails with the first error once the tool returns.
upstream: agent-loop.ts:685 (ToolUpdateSink), 820-849 (executePreparedToolCall)
type TurnEndEvent ¶
type TurnEndEvent struct {
TurnIndex int
Message AgentMessage
ToolResults []ToolResultMessage
MessageEntryID string
ToolResultEntryIDs []string
}
type TurnStartEvent ¶
type UserMessage ¶
type UserMessage struct {
Role string `json:"role"` // "user"
Content ai.UserContent `json:"content"`
Timestamp int64 `json:"timestamp"`
}
UserMessage is a user turn whose content retains the upstream string-or-block-array shape.
func (*UserMessage) LLMMessage ¶
func (m *UserMessage) LLMMessage() ai.UserMessage
LLMMessage retains the user content variant and normalizes an omitted Go content value to an empty array.
Source Files
¶
- agent.go
- agent_loop.go
- context_tokens.go
- lifecycle.go
- message_json.go
- messages.go
- mutation_reservation.go
- proxy.go
- queue.go
- run_tool_call.go
- stream_fn.go
- system_state.go
- timings.go
- tool_environment.go
- tool_execution.go
- transform.go
- types.go
- validate.go
- validate_arguments.go
- validate_convert.go
- validate_errors.go
- validate_json.go
- validate_schema.go