Documentation
¶
Overview ¶
Package agui implements the AG-UI protocol (Agent-User Interaction Protocol, https://docs.ag-ui.com) as an isolated side-car adapter on top of Pando.
AG-UI is the wire contract CopilotKit and other Generative-UI frontends speak to any agent backend. Making Pando speak it is what lets a React application drive a Pando agent with `<CopilotKit agent="pando">` and zero Pando-specific frontend code.
Architectural invariants ¶
This package is deliberately a leaf adapter. It must never become a second implementation of the agent, and it must never disturb the surfaces that already exist (TUI, Web-UI, ACP). The following invariants are load-bearing:
- I1: no change to agent.NewAgent / agent.Run signatures. This package builds its OWN agent.Service instances through the already-exported constructors, exactly like internal/app/app.go does.
- I2: app.CoderAgent is never read or mutated here. TUI/Web-UI/ACP and the api BackgroundSessionManager keep using it untouched.
- I3: no AG-UI prompt ever reaches a desktop user. The runtime creates its own permission.Service and userinput.Service, so approvals and questions raised by a web run stay inside this adapter.
- I4: no new event types in agent.AgentEvent. Translation to AG-UI events is one-way and lives in translate.go.
- I5: off by default and removable. Deleting this package plus the ~90 lines of wiring in config/app/api restores the previous tree.
- I6: no *app.App import (that would also be an import cycle); dependencies arrive through the narrow Deps struct.
- I7: its own route namespace, its own auth/CORS policy, optionally its own listener.
Implementation status ¶
P0 (protocol layer), P1 (runtime, agent pool, thread map, translation, endpoint), P2 (shared state), P3 (frontend tools) and P4 (human in the loop) are implemented:
P2: STATE_SNAPSHOT after every RUN_STARTED and STATE_DELTA (RFC-6902) for todos, token usage and touched files. See state.go.
P3: RunAgentInput.Tools become blocking tools.BaseTool proxies; a call suspends the run with RUN_FINISHED{outcome:"interrupt"} and is resolved by the tool message of the next request on the thread. Runs are therefore detached from their HTTP request; see run.go and frontend_tool.go.
P4: permission prompts reach the client as a synthetic pando_permission_request tool call, and AskUserQuestion is substituted by a tool that waits on the client instead of on a local overlay. Both fail closed (deny / cancel) when nobody answers. Gated by Config.HumanInTheLoop; with it off the pre-P4 policy applies. See hitl.go.
P5: durable thread->session mapping in the adapter-owned agui_threads table (threads.go), hardened /info discovery, and the dedicated listener of invariant I7 (listener.go), reachable through `pando serve --agui-port` or the standalone `pando agui-serve` process.
P6: the client half, outside this package — the `@pando-ai/sdk/agui` subpath export and the Next.js application under examples/copilotkit. No Go code was involved, which is the point: the protocol is the contract.
P7: mesnada sub-agents are projected into the shared-state document as StateDoc.SubAgents (subagents.go), derived from the mesnada_* tool traffic the adapter already observes — the orchestrator is never consulted and no agent event type was added.
Tool calls that never reach the event stream ¶
agent.processEvent only publishes AgentEventTypeToolCall for providers that stream tool use incrementally (EventToolUseStart/Delta/Stop). A provider that reports its tool calls in one final EventComplete leaves the assistant message correct while the event stream stays silent about them. Every other surface renders from the database and never notices; this adapter has only the stream, so it must reconstruct what the stream omits: a suspending call carries its own name and arguments (suspension.call) so the handler can emit START/ARGS/END before the interrupt, and a tool result for a call that was never opened opens it first (translate.go), because a bare TOOL_CALL_END is rejected by AG-UI clients as a protocol error that aborts the whole run.
Tool results are not JSON ¶
tools.NewStructuredResponse renders TOON when it can, TOML next and indented JSON only as a last resort, and it chooses per value. Any code here that reads a tool result structurally must go through decodeToolResult (subagents.go); json.Unmarshal alone silently sees nothing, which is what kept the sub-agent board empty until 2026-07-29.
The state document belongs to the thread ¶
StateDoc is per thread and lives in the Runtime's stateStore, not in the run: a conversation's todos, touched files and sub-agents must survive its turns. A per-run document made them vanish on every new message. The store is memory only — the durable half is the thread->session binding in threads.go — and it evicts the least recently used threads past maxStateThreads.
Deliberately not implemented ¶
CopilotKit's own runtime protocol (GraphQL) is not served by Pando. The remaining half of P7 was "skip the Node hop" by embedding that runtime; it is declined on purpose. AG-UI is the protocol every agent backend implements and CopilotKit's runtime already translates it, so reimplementing that runtime in Go would buy one process hop at the cost of tracking a second, faster-moving protocol — and it would move the API token into the browser, which is the one place it must not be.
The AG-UI spec revision targeted here is the one documented at https://docs.ag-ui.com as of 2026-07-28.
Index ¶
- Constants
- Variables
- type ActivitySnapshotEvent
- type AgentDescriptor
- type BaseEvent
- type Capabilities
- type Config
- type Context
- type CustomEvent
- type Deps
- type Event
- type EventType
- type FileState
- type InfoResponse
- type InputContent
- type JSONPatchOperation
- type Listener
- type ListenerOptions
- type Message
- type MessageContent
- type MessagesSnapshotEvent
- type ModelDescriptor
- type ModelState
- type RawEvent
- type ReasoningEndEvent
- type ReasoningMessageContentEvent
- type ReasoningMessageEndEvent
- type ReasoningMessageStartEvent
- type ReasoningStartEvent
- type RunAgentInput
- type RunErrorEvent
- type RunFinishedEvent
- type RunStartedEvent
- type Runtime
- type SSEWriter
- type StateDeltaEvent
- type StateDoc
- type StateSnapshotEvent
- type StepFinishedEvent
- type StepStartedEvent
- type SubAgentState
- type TextMessageContentEvent
- type TextMessageEndEvent
- type TextMessageStartEvent
- type TokenUsageState
- type Tool
- type ToolCall
- type ToolCallArgsEvent
- type ToolCallEndEvent
- type ToolCallFunction
- type ToolCallResultEvent
- type ToolCallStartEvent
Constants ¶
const ( // OutcomeSuccess marks a run that completed on its own. OutcomeSuccess = "success" // OutcomeInterrupt marks a run that stopped waiting for the client (a // frontend tool result, a human decision). The agent-side run may still be // alive; the client resumes it with the next request on the same thread. OutcomeInterrupt = "interrupt" )
Run outcomes reported by RunFinishedEvent.
const ( RoleDeveloper = "developer" RoleSystem = "system" RoleAssistant = "assistant" RoleUser = "user" RoleTool = "tool" RoleActivity = "activity" RoleReasoning = "reasoning" )
Message roles defined by AG-UI.
const ( ContentText = "text" ContentImage = "image" ContentAudio = "audio" ContentVideo = "video" ContentDocument = "document" )
Multimodal input content kinds.
const ( FileActionRead = "read" FileActionWrite = "write" FileActionEdit = "edit" FileActionPatched = "patch" )
File actions reported in StateDoc.Files.
Variables ¶
var ErrInvalidInput = errors.New("agui: invalid RunAgentInput")
ErrInvalidInput is returned by DecodeRunAgentInput when the payload does not satisfy the protocol's minimum requirements.
var ErrStreamingUnsupported = errors.New("agui: streaming unsupported by the response writer")
ErrStreamingUnsupported is returned when the ResponseWriter cannot flush, in which case SSE cannot be served at all.
Functions ¶
This section is empty.
Types ¶
type ActivitySnapshotEvent ¶
type ActivitySnapshotEvent struct {
BaseEvent
MessageID string `json:"messageId"`
ActivityType string `json:"activityType"`
Content any `json:"content"`
Replace bool `json:"replace,omitempty"`
}
func NewActivitySnapshot ¶
func NewActivitySnapshot(messageID, activityType string, content any) ActivitySnapshotEvent
type AgentDescriptor ¶
type AgentDescriptor struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
URL string `json:"url"`
Model *ModelDescriptor `json:"model,omitempty"`
}
AgentDescriptor is one entry of the /info response.
type BaseEvent ¶
type BaseEvent struct {
Type EventType `json:"type"`
Timestamp int64 `json:"timestamp,omitempty"`
RawEvent any `json:"rawEvent,omitempty"`
}
BaseEvent carries the fields every AG-UI event shares.
type Capabilities ¶
type Capabilities struct {
// FrontendTools reports whether RunAgentInput.tools are proxied.
FrontendTools bool `json:"frontendTools"`
// HumanInTheLoop reports whether permission prompts and agent questions
// reach the client as tool calls.
HumanInTheLoop bool `json:"humanInTheLoop"`
SharedState bool `json:"sharedState"`
// Interrupts reports RUN_FINISHED{outcome:"interrupt"} and resumption.
Interrupts bool `json:"interrupts"`
}
Capabilities advertises the optional halves of the protocol this adapter implements, so a client can tell "not supported" from "nothing happened" without probing.
type Config ¶
type Config struct {
Path string
// Port serves the adapter on its own listener when > 0. Zero means the
// adapter is mounted on the API server's mux.
Port int
Agents []config.AgentName
AllowedOrigins []string
RequireToken bool
FrontendTools bool
AgentPoolSize int
AgentPoolTTL time.Duration
AutoApprove bool
// HumanInTheLoop surfaces permission prompts and questions to the AG-UI
// client. With it off (and AutoApprove off) a run that needs approval is
// denied instead of asking, which is the pre-P4 behaviour.
HumanInTheLoop bool
}
Config is the adapter's resolved configuration.
func ConfigFromApp ¶
func ConfigFromApp(c config.AGUIConfig) Config
ConfigFromApp resolves an AGUIConfig into the adapter's own Config, applying the defaults the adapter guarantees even when the config file predates this feature.
type CustomEvent ¶
func NewCustom ¶
func NewCustom(name string, value any) CustomEvent
NewCustom builds a CUSTOM event. Pando-specific signals that have no AG-UI counterpart are emitted this way, namespaced as "pando.<something>", so a generic AG-UI client can ignore them safely.
type Deps ¶
type Deps struct {
Sessions session.Service
Messages message.Service
History history.Service
Skills *skills.SkillManager
Gateway *mcpgateway.Gateway
Orchestrator *orchestrator.Orchestrator
Remembrances *rag.RemembrancesService
// LSP is the language-server provider used by the edit/view tools.
// *app.App satisfies it.
LSP tools.LSPProvider
// DB is the shared SQLite connection, used only for the adapter's own
// agui_threads table (thread -> session bindings). It is optional: with a nil
// DB the mapping is in-memory and does not survive a restart.
DB *sql.DB
// Token is the API bearer token clients must present when
// Config.RequireToken is set. It is supplied by the caller so the adapter
// shares the API server's token instead of minting a second one.
Token string
}
Deps are the collaborators the adapter needs to build its own agents. It mirrors the arguments internal/app/app.go already passes to agent.CoderAgentToolsWithMesnada, minus the two services the adapter creates itself (permissions and user input, see invariant I3 in doc.go) and minus the agent itself (invariant I2).
The struct exists so this package never imports *app.App: that would be an import cycle and would also make the adapter reachable from the rest of the application, which is exactly what the isolation invariants forbid.
type Event ¶
type Event interface {
EventType() EventType
}
Event is any AG-UI event. Implementations embed BaseEvent.
type EventType ¶
type EventType string
EventType is the AG-UI event discriminator. Values are serialized uppercase with underscores, matching the protocol's EventType enum.
const ( EventTextMessageStart EventType = "TEXT_MESSAGE_START" EventTextMessageContent EventType = "TEXT_MESSAGE_CONTENT" EventTextMessageEnd EventType = "TEXT_MESSAGE_END" EventTextMessageChunk EventType = "TEXT_MESSAGE_CHUNK" EventToolCallStart EventType = "TOOL_CALL_START" EventToolCallArgs EventType = "TOOL_CALL_ARGS" EventToolCallEnd EventType = "TOOL_CALL_END" EventToolCallResult EventType = "TOOL_CALL_RESULT" EventStateSnapshot EventType = "STATE_SNAPSHOT" EventStateDelta EventType = "STATE_DELTA" EventMessagesSnapshot EventType = "MESSAGES_SNAPSHOT" EventActivitySnapshot EventType = "ACTIVITY_SNAPSHOT" EventActivityDelta EventType = "ACTIVITY_DELTA" EventRaw EventType = "RAW" EventCustom EventType = "CUSTOM" EventRunStarted EventType = "RUN_STARTED" EventRunFinished EventType = "RUN_FINISHED" EventRunError EventType = "RUN_ERROR" EventStepStarted EventType = "STEP_STARTED" EventStepFinished EventType = "STEP_FINISHED" EventReasoningStart EventType = "REASONING_START" EventReasoningMessageStart EventType = "REASONING_MESSAGE_START" EventReasoningMessageContent EventType = "REASONING_MESSAGE_CONTENT" EventReasoningMessageEnd EventType = "REASONING_MESSAGE_END" EventReasoningEnd EventType = "REASONING_END" )
type FileState ¶
type FileState struct {
Path string `json:"path"`
Name string `json:"name"`
Action string `json:"action"`
}
FileState is one workspace file the run touched.
type InfoResponse ¶
type InfoResponse struct {
Protocol string `json:"protocol"`
Version string `json:"version,omitempty"`
Path string `json:"path"`
Agents []AgentDescriptor `json:"agents"`
Capabilities Capabilities `json:"capabilities"`
}
InfoResponse is the agent-discovery payload.
type InputContent ¶
type InputContent struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
// URL/Data carry non-text parts. Only text is consumed today; other kinds
// are preserved so P2+ can map them onto message.Attachment.
URL string `json:"url,omitempty"`
Data string `json:"data,omitempty"`
MimeType string `json:"mimeType,omitempty"`
}
InputContent is one part of a multimodal user message.
type JSONPatchOperation ¶
type JSONPatchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Value any `json:"value,omitempty"`
From string `json:"from,omitempty"`
}
JSONPatchOperation is a single RFC-6902 operation as carried by StateDelta.
type Listener ¶
type Listener struct {
// contains filtered or unexported fields
}
Listener is a running dedicated AG-UI listener.
func (*Listener) Shutdown ¶
Shutdown stops the listener. It does not close the Runtime: the caller owns that, because the same Runtime may also be mounted elsewhere.
type ListenerOptions ¶
type ListenerOptions struct {
// Host to bind to. Empty means localhost, never all interfaces: this
// surface drives an agent that executes code, so exposing it on 0.0.0.0 has
// to be a deliberate act.
Host string
// CertFile and KeyFile enable TLS. Both or neither.
CertFile string
KeyFile string
}
ListenerOptions describes the dedicated listener requested by Config.Port.
type Message ¶
type Message struct {
ID string `json:"id"`
Role string `json:"role"`
Content MessageContent `json:"content,omitempty"`
Name string `json:"name,omitempty"`
ToolCalls []ToolCall `json:"toolCalls,omitempty"`
ToolCallID string `json:"toolCallId,omitempty"`
Error string `json:"error,omitempty"`
ActivityType string `json:"activityType,omitempty"`
}
Message is one entry of the AG-UI conversation.
type MessageContent ¶
type MessageContent struct {
Text string
Parts []InputContent
}
MessageContent holds either a plain string or a list of multimodal parts. AG-UI allows both shapes on user messages.
func (MessageContent) HasNonTextParts ¶
func (m MessageContent) HasNonTextParts() bool
HasNonTextParts reports whether the message carries content this adapter cannot forward to the agent yet.
func (MessageContent) MarshalJSON ¶
func (m MessageContent) MarshalJSON() ([]byte, error)
MarshalJSON writes back the shape the content was received in.
func (MessageContent) String ¶
func (m MessageContent) String() string
String flattens the content to plain text, joining the text parts of a multimodal message. Non-text parts are skipped (see doc.go, P2).
func (*MessageContent) UnmarshalJSON ¶
func (m *MessageContent) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts either a JSON string or an array of InputContent.
type MessagesSnapshotEvent ¶
func NewMessagesSnapshot ¶
func NewMessagesSnapshot(msgs []Message) MessagesSnapshotEvent
type ModelDescriptor ¶
type ModelDescriptor struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
ContextWindow int64 `json:"contextWindow,omitempty"`
}
ModelDescriptor tells the client what it is talking to, so a dashboard can show the model and size its own context budget. It carries no credentials and no provider endpoint: the provider is named, never located.
type ModelState ¶
type ModelState struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Provider string `json:"provider,omitempty"`
ContextWindow int64 `json:"contextWindow,omitempty"`
}
ModelState describes the model backing the thread.
type ReasoningEndEvent ¶
func NewReasoningEnd ¶
func NewReasoningEnd(messageID string) ReasoningEndEvent
type ReasoningMessageContentEvent ¶
type ReasoningMessageContentEvent struct {
BaseEvent
MessageID string `json:"messageId"`
Delta string `json:"delta"`
}
func NewReasoningMessageContent ¶
func NewReasoningMessageContent(messageID, delta string) ReasoningMessageContentEvent
type ReasoningMessageEndEvent ¶
func NewReasoningMessageEnd ¶
func NewReasoningMessageEnd(messageID string) ReasoningMessageEndEvent
type ReasoningMessageStartEvent ¶
type ReasoningMessageStartEvent struct {
BaseEvent
MessageID string `json:"messageId"`
Role string `json:"role"`
}
func NewReasoningMessageStart ¶
func NewReasoningMessageStart(messageID string) ReasoningMessageStartEvent
type ReasoningStartEvent ¶
func NewReasoningStart ¶
func NewReasoningStart(messageID string) ReasoningStartEvent
type RunAgentInput ¶
type RunAgentInput struct {
ThreadID string `json:"threadId"`
RunID string `json:"runId"`
ParentRunID string `json:"parentRunId,omitempty"`
State any `json:"state,omitempty"`
Messages []Message `json:"messages,omitempty"`
Tools []Tool `json:"tools,omitempty"`
Context []Context `json:"context,omitempty"`
ForwardedProps any `json:"forwardedProps,omitempty"`
}
RunAgentInput is the request body of an AG-UI run. It is sent in full on every turn: the client owns the visible transcript, so `Messages` carries the whole conversation even though Pando keeps its own history server-side.
func DecodeRunAgentInput ¶
func DecodeRunAgentInput(r io.Reader, maxBytes int64) (*RunAgentInput, error)
DecodeRunAgentInput reads and validates a RunAgentInput from an HTTP body. maxBytes caps the payload; pass 0 for the default.
func (*RunAgentInput) ContextBlock ¶
func (in *RunAgentInput) ContextBlock() string
ContextBlock renders the client-supplied context entries as a text block that can be prefixed to the prompt. Returns "" when there is no context.
func (*RunAgentInput) LastUserMessage ¶
func (in *RunAgentInput) LastUserMessage() (Message, bool)
LastUserMessage returns the trailing user message, which is the only part of the transcript this adapter forwards to Pando: the agent keeps its own history, so replaying the whole array would duplicate context and defeat compaction and prompt caching.
func (*RunAgentInput) TrailingToolMessages ¶
func (in *RunAgentInput) TrailingToolMessages() []Message
TrailingToolMessages returns the tool messages that appear after the last user message. They are frontend tool results resolving a previously interrupted run rather than a new prompt (P3 consumes them).
func (*RunAgentInput) Validate ¶
func (in *RunAgentInput) Validate() error
Validate enforces the protocol's required fields.
type RunErrorEvent ¶
type RunErrorEvent struct {
BaseEvent
Message string `json:"message"`
Code string `json:"code,omitempty"`
}
func NewRunError ¶
func NewRunError(msg, code string) RunErrorEvent
type RunFinishedEvent ¶
type RunFinishedEvent struct {
BaseEvent
ThreadID string `json:"threadId"`
RunID string `json:"runId"`
Outcome string `json:"outcome,omitempty"`
Result any `json:"result,omitempty"`
}
func NewRunFinished ¶
func NewRunFinished(threadID, runID, outcome string, result any) RunFinishedEvent
type RunStartedEvent ¶
type RunStartedEvent struct {
BaseEvent
ThreadID string `json:"threadId"`
RunID string `json:"runId"`
ParentRunID string `json:"parentRunId,omitempty"`
}
func NewRunStarted ¶
func NewRunStarted(threadID, runID string) RunStartedEvent
type Runtime ¶
type Runtime struct {
// contains filtered or unexported fields
}
Runtime is the AG-UI adapter. It owns everything the protocol needs that Pando does not already provide: its own agent instances, its own permission and user-input services, and the thread bookkeeping AG-UI clients expect.
Nothing outside this package holds a reference to those objects, which is what keeps the adapter isolated from the TUI, Web-UI and ACP surfaces.
func New ¶
New builds the adapter. It does not start any listener; call Register to mount it on a mux.
func (*Runtime) Close ¶
func (r *Runtime) Close()
Close stops the adapter's background work and cancels every detached run. Pooled agents are left to the garbage collector.
func (*Runtime) Handler ¶
Handler returns a standalone mux carrying only the AG-UI routes, for serving the adapter on its own listener (Config.Port > 0).
func (*Runtime) Register ¶
Register mounts the adapter's routes on mux:
POST {path}/{agent} run an agent, streaming AG-UI events over SSE
GET {path}/info agent discovery, consumed by CopilotKit's runtime
It is the only place this package touches the outside world's routing, and it is called only when the feature is enabled.
func (*Runtime) StartListener ¶
func (r *Runtime) StartListener(opts ListenerOptions) (*Listener, error)
StartListener serves the adapter on its own port, carrying only the AG-UI routes.
This is deployment shape 2 of invariant I7: a browser origin that can reach the AG-UI endpoint then cannot reach the Web-UI API at all — no sessions list, no config, no file endpoints, no static UI. It is the recommended shape for anything beyond localhost.
The listener is bound synchronously so a port clash is reported to the caller instead of being lost in a goroutine.
type SSEWriter ¶
type SSEWriter struct {
// contains filtered or unexported fields
}
SSEWriter serializes AG-UI events to the Server-Sent Events wire format.
AG-UI puts the discriminator inside the JSON payload rather than in the SSE `event:` field, so every frame is a bare `data:` line. Clients (including AG-UI's HttpAgent) parse the JSON and switch on `type`.
func NewSSEWriter ¶
func NewSSEWriter(w http.ResponseWriter) (*SSEWriter, error)
NewSSEWriter writes the SSE response headers and returns a writer bound to w. Headers other than the streaming ones (CORS, auth) must already be set.
func (*SSEWriter) Close ¶
func (s *SSEWriter) Close()
Close marks the stream finished. Further writes are refused; the HTTP handler returning is what actually terminates the response.
func (*SSEWriter) Comment ¶
Comment emits an SSE comment. Used as a heartbeat to keep intermediaries from dropping an idle connection while the agent is busy in a long tool call.
type StateDeltaEvent ¶
type StateDeltaEvent struct {
BaseEvent
Delta []JSONPatchOperation `json:"delta"`
}
func NewStateDelta ¶
func NewStateDelta(ops []JSONPatchOperation) StateDeltaEvent
type StateDoc ¶
type StateDoc struct {
Thread string `json:"thread"`
Session string `json:"session"`
Agent string `json:"agent"`
Model ModelState `json:"model"`
Todos []tools.TodoItem `json:"todos"`
TokenUsage *TokenUsageState `json:"tokenUsage"`
Files []FileState `json:"files"`
// SubAgents lists the mesnada tasks this thread delegated (P7). See
// subagents.go: it is derived from the mesnada_* tool traffic, never read
// from the orchestrator.
SubAgents []SubAgentState `json:"subAgents"`
// Client echoes RunAgentInput.state. It is read-only context the page pushed
// into the run; the adapter never writes it back into Pando's config.
Client any `json:"client,omitempty"`
}
StateDoc is the document published to the client. Field order is irrelevant to the protocol; the JSON pointer paths used by the deltas are what matter, so the tags below are part of the contract.
type StateSnapshotEvent ¶
func NewStateSnapshot ¶
func NewStateSnapshot(snapshot any) StateSnapshotEvent
type StepFinishedEvent ¶
func NewStepFinished ¶
func NewStepFinished(name string) StepFinishedEvent
type StepStartedEvent ¶
func NewStepStarted ¶
func NewStepStarted(name string) StepStartedEvent
type SubAgentState ¶
type SubAgentState struct {
ID string `json:"id"`
Status string `json:"status"`
// Role is set for tasks created by mesnada_swarm, which assigns fixed roles.
Role string `json:"role,omitempty"`
Prompt string `json:"prompt,omitempty"`
Engine string `json:"engine,omitempty"`
Model string `json:"model,omitempty"`
Persona string `json:"persona,omitempty"`
Error string `json:"error,omitempty"`
ExitCode *int `json:"exitCode,omitempty"`
// Conclusion is the delegated task's self-reported outcome
// (success|partial|failed|blocked), present once the task concluded.
Conclusion string `json:"conclusion,omitempty"`
// Summary is the conclusion's one-paragraph summary, when captured.
Summary string `json:"summary,omitempty"`
}
SubAgentState is one delegated mesnada task as published to the client. Field names are camelCase because the JSON pointers built from them are part of the protocol contract, like the rest of StateDoc.
type TextMessageContentEvent ¶
type TextMessageContentEvent struct {
BaseEvent
MessageID string `json:"messageId"`
Delta string `json:"delta"`
}
func NewTextMessageContent ¶
func NewTextMessageContent(messageID, delta string) TextMessageContentEvent
type TextMessageEndEvent ¶
func NewTextMessageEnd ¶
func NewTextMessageEnd(messageID string) TextMessageEndEvent
type TextMessageStartEvent ¶
type TextMessageStartEvent struct {
BaseEvent
MessageID string `json:"messageId"`
Role string `json:"role"`
}
func NewTextMessageStart ¶
func NewTextMessageStart(messageID string) TextMessageStartEvent
type TokenUsageState ¶
type TokenUsageState struct {
PromptTokens int64 `json:"promptTokens"`
CompletionTokens int64 `json:"completionTokens"`
ContextWindow int64 `json:"contextWindow"`
Estimated bool `json:"estimated"`
CacheReadTokens int64 `json:"cacheReadTokens,omitempty"`
CacheWriteTokens int64 `json:"cacheWriteTokens,omitempty"`
ReasoningTokens int64 `json:"reasoningTokens,omitempty"`
Cost float64 `json:"cost,omitempty"`
}
TokenUsageState is the live context budget, mirroring agent.TokenUsageInfo in the protocol's camelCase convention.
type Tool ¶
type Tool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters any `json:"parameters,omitempty"`
}
Tool is a frontend-declared tool. The agent may call it; the browser executes it and returns the outcome as a tool message on the next run.
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
Type string `json:"type,omitempty"`
Function ToolCallFunction `json:"function"`
}
ToolCall is an assistant-issued call as echoed back by the client.
type ToolCallArgsEvent ¶
type ToolCallArgsEvent struct {
BaseEvent
ToolCallID string `json:"toolCallId"`
Delta string `json:"delta"`
}
func NewToolCallArgs ¶
func NewToolCallArgs(id, delta string) ToolCallArgsEvent
type ToolCallEndEvent ¶
func NewToolCallEnd ¶
func NewToolCallEnd(id string) ToolCallEndEvent
type ToolCallFunction ¶
ToolCallFunction is the OpenAI-shaped function payload of a tool call.
type ToolCallResultEvent ¶
type ToolCallResultEvent struct {
BaseEvent
MessageID string `json:"messageId"`
ToolCallID string `json:"toolCallId"`
Content string `json:"content"`
Role string `json:"role,omitempty"`
}
func NewToolCallResult ¶
func NewToolCallResult(messageID, toolCallID, content string) ToolCallResultEvent
type ToolCallStartEvent ¶
type ToolCallStartEvent struct {
BaseEvent
ToolCallID string `json:"toolCallId"`
ToolCallName string `json:"toolCallName"`
ParentMessageID string `json:"parentMessageId,omitempty"`
}
func NewToolCallStart ¶
func NewToolCallStart(id, name, parentMessageID string) ToolCallStartEvent