Documentation
¶
Index ¶
- Constants
- Variables
- type AgentDescriptor
- type Backend
- type Config
- type Context
- type DescriptorAuth
- type EventType
- type ExposedWorkload
- type Interrupt
- type Message
- type ResumeEntry
- type ResumeStatus
- type RunAgentInput
- type RunError
- type RunErrorCode
- type RunFinished
- type RunInput
- type RunMetric
- type RunOutcome
- type RunOutcomeType
- type RunResult
- type RunStarted
- type Server
- type StateDelta
- type StateSnapshot
- type StepFinished
- type StepStarted
- type TextMessageContent
- type TextMessageEnd
- type TextMessageStart
- type Tool
- type ToolCallArgs
- type ToolCallEnd
- type ToolCallResult
- type ToolCallStart
Constants ¶
const DiscoveryPath = "/agui/agents.json"
DiscoveryPath is the unauthenticated discovery endpoint listing the AG-UI workloads this daemon exposes (docs/ag-ui-design.md open question 8).
const ProtocolVersion = "0.1"
ProtocolVersion is the AG-UI protocol line this server implements. It is advertised in the discovery descriptor and pinned per release (docs/ag-ui-design.md).
Variables ¶
var ErrNotResumable = errors.New("agui: session is not awaiting input (nothing to resume)")
ErrNotResumable marks a resume request (RunAgentInput.Resume present) whose target session is not awaiting input — no such session, or it is not paused on any interrupt the client named. When a Backend returns it before emitting any frame, the server reports HTTP 409 (Conflict): the client's answer does not correspond to an open interrupt, so driving a fresh turn would silently discard it. Refusing before the SSE upgrade keeps this a clean HTTP status rather than a fabricated stream.
ErrUnavailable marks a transiently-unavailable backend — e.g. a daemon draining for shutdown that refuses new work. When a Backend returns it before emitting any frame, the server reports HTTP 503 (retryable) rather than opening a stream it cannot fill.
Functions ¶
This section is empty.
Types ¶
type AgentDescriptor ¶
type AgentDescriptor struct {
Name string `json:"name"`
Endpoint string `json:"endpoint"`
Description string `json:"description,omitempty"`
InputSchema map[string]any `json:"input_schema,omitempty"`
ProtocolVersion string `json:"protocol_version"`
Auth DescriptorAuth `json:"auth"`
}
AgentDescriptor is one workload's entry in the discovery document. Field names follow the AG-UI discovery convention (snake_case for the compound keys, matching the bundle's agui: config surface).
type Backend ¶
type Backend interface {
RunAgent(ctx context.Context, in RunInput, emit func(any)) (RunResult, error)
}
Backend drives an AG-UI run against the mast runtime. The daemon implements it over runTurnPre (cmd/mast/agui.go); this package never imports the runtime. emit is called synchronously and in order on the calling goroutine — the SSE handler writes each frame to the wire — so implementations need no locking around it. The backend emits the opening frames (RunStarted, then StateSnapshot) and all interior frames; the server emits the terminal frame from the returned RunResult. A backend that cannot start the turn (draining) must return ErrUnavailable BEFORE any emit, so the server can report a clean HTTP error instead of a truncated stream. A backend must not emit after returning.
type Config ¶
type Config struct {
// Listen is the bind address, e.g. ":7781". Used by ListenAndServe.
Listen string
// Exposed are the workloads served, each on its own EndpointPath. An
// empty slice serves only the discovery endpoint; the daemon starts the
// server only when at least one workload opts in.
Exposed []ExposedWorkload
// Validator authenticates every run request. Nil disables auth (dev
// only). When set, a request without a valid bearer is refused 401 before
// any dispatch.
Validator serverauth.TokenValidator
// Limiter, when non-nil, admits or refuses each run request before
// dispatch — see serverauth.RateLimiter. Nil disables rate limiting.
Limiter serverauth.RateLimiter
// Backend is required.
Backend Backend
// Metric, when non-nil, records run outcomes.
Metric RunMetric
// Logger defaults to slog.Default().
Logger *slog.Logger
// BaseContext, when non-nil, is the context every request derives from
// (the daemon passes its turn lifetime).
BaseContext context.Context
}
Config configures the AG-UI server.
type Context ¶
type Context struct {
Description string `json:"description,omitempty"`
Value string `json:"value,omitempty"`
}
Context is one supplementary context entry a client attaches to a run (docs/ag-ui-design.md RunAgentInput). Carried through opaquely.
type DescriptorAuth ¶
type DescriptorAuth struct {
Required bool `json:"required"`
Scopes []string `json:"scopes,omitempty"`
}
DescriptorAuth describes the auth a workload's endpoint requires. Required is true whenever the server has a validator configured; Scopes lists the per-workload scopes a caller additionally needs.
type EventType ¶
type EventType string
EventType is the discriminator on every AG-UI SSE event's "type" field.
const ( // Lifecycle. EventRunStarted EventType = "RUN_STARTED" EventRunFinished EventType = "RUN_FINISHED" EventRunError EventType = "RUN_ERROR" EventStepStarted EventType = "STEP_STARTED" EventStepFinished EventType = "STEP_FINISHED" // Assistant text (streamed as start → one-or-more content deltas → end). EventTextMessageStart EventType = "TEXT_MESSAGE_START" EventTextMessageContent EventType = "TEXT_MESSAGE_CONTENT" EventTextMessageEnd EventType = "TEXT_MESSAGE_END" // Tool calls (start → args deltas → end, then a result once available). EventToolCallStart EventType = "TOOL_CALL_START" EventToolCallArgs EventType = "TOOL_CALL_ARGS" EventToolCallEnd EventType = "TOOL_CALL_END" EventToolCallResult EventType = "TOOL_CALL_RESULT" // Shared state. EventStateSnapshot EventType = "STATE_SNAPSHOT" EventStateDelta EventType = "STATE_DELTA" )
The AG-UI event vocabulary this server emits (docs/ag-ui-design.md emission map). Stage 1 ships the lifecycle, text-message triad, tool-call quartet, and state families; activity/reasoning/raw/custom families are deferred.
type ExposedWorkload ¶
type ExposedWorkload struct {
// WorkloadName is the mast workload backing this endpoint; the backend
// resolves it to a session and drives the turn.
WorkloadName string
// EndpointPath is the HTTP path the workload is served at, e.g.
// "/agui/triage". Must start with "/". Each exposed workload owns a
// distinct path.
EndpointPath string
// Description is surfaced in the discovery descriptor.
Description string
// InputSchema is an optional JSON-Schema-shaped hint surfaced in the
// discovery descriptor so a client can render an input form.
InputSchema map[string]any
// Scopes are required to invoke this workload. Empty means the endpoint
// needs authentication only (a valid token, no specific scope) when a
// validator is configured, or open access when it is not.
Scopes []string
}
ExposedWorkload is one workload's AG-UI exposure, projected by the daemon from the bundle's agui: section (this package does not import pkg/workload).
type Interrupt ¶
type Interrupt struct {
ID string `json:"id"`
Message string `json:"message,omitempty"`
ResponseSchema json.RawMessage `json:"responseSchema,omitempty"`
ExpiresAt *int64 `json:"expiresAt,omitempty"`
}
Interrupt describes one open interrupt a run paused on. ID is the resume correlation key (the client echoes it in a ResumeEntry.InterruptID); Message is the human-readable prompt; ResponseSchema, when present, is the JSON schema the answer payload should conform to (a client can render a form from it). ExpiresAt (epoch ms) is modeled for spec completeness but unset — mast HITL interrupts carry no wall-clock expiry today.
type Message ¶
type Message struct {
ID string `json:"id,omitempty"`
Role string `json:"role"`
Content string `json:"content,omitempty"`
Name string `json:"name,omitempty"`
}
Message is one conversational message in a RunAgentInput. Role is the AG-UI role vocabulary ("user", "assistant", "system", "tool"); Content is the text body. Unmodeled per-role fields (tool calls on assistant messages, toolCallId on tool messages) are not consumed by the Stage 1 server.
type ResumeEntry ¶
type ResumeEntry struct {
InterruptID string `json:"interruptId"`
Status ResumeStatus `json:"status"`
Payload json.RawMessage `json:"payload,omitempty"`
}
ResumeEntry answers one prior interrupt when a client resumes a run. The InterruptID must match an interrupt the server reported in a prior RunFinished{outcome: interrupt}; Payload is the client's answer.
type ResumeStatus ¶
type ResumeStatus string
ResumeStatus is the disposition a client reports when answering an interrupt (docs/ag-ui-design.md Resume): "resolved" (the human answered) or "cancelled" (the human declined). The vocabulary follows the design doc; the shipped Stage 1 placeholder used "accepted"/"rejected", reconciled here now that the lifecycle is live. mast forwards the entry's Payload verbatim as the interrupt answer regardless of status (the runtime resume channel carries the answer value, not a separate disposition — see cmd/mast buildResumeMessage); when a cancelled entry carries no payload, mast synthesizes a minimal {"status":"cancelled"} answer so a workload can branch on a decline.
const ( ResumeStatusResolved ResumeStatus = "resolved" ResumeStatusCancelled ResumeStatus = "cancelled" )
type RunAgentInput ¶
type RunAgentInput struct {
ThreadID string `json:"threadId"`
RunID string `json:"runId"`
ParentRunID *string `json:"parentRunId,omitempty"`
State json.RawMessage `json:"state,omitempty"`
Messages []Message `json:"messages,omitempty"`
Tools []Tool `json:"tools,omitempty"`
Context []Context `json:"context,omitempty"`
ForwardedProps json.RawMessage `json:"forwardedProps,omitempty"`
Resume []ResumeEntry `json:"resume,omitempty"`
}
RunAgentInput is the request body a client POSTs to a workload's AG-UI endpoint to drive one turn. Field names follow the AG-UI spec JSON (camelCase). State/ForwardedProps ride along as raw JSON — the server echoes State back as the opening StateSnapshot and does not otherwise interpret it. Resume carries the client's answers when continuing an interrupted run (the HITL lifecycle): a non-empty Resume turns this request into a resume rather than a fresh user turn. Tools are parsed but unused (client-tool acceptance is a follow-on stage); modeled so the input contract stays complete and forward-compatible.
type RunError ¶
type RunError struct {
Message string `json:"message"`
Code RunErrorCode `json:"code,omitempty"`
// contains filtered or unexported fields
}
RunError is the terminal event for a run that did not complete normally: aborted or an internal fault. (A HITL pause is NOT a RunError — it is a terminal RunFinished carrying outcome.type == "interrupt"; see RunOutcome.) Message is a short human-readable summary; Code is the machine-readable disposition.
func NewRunError ¶
func NewRunError(msg string, code RunErrorCode) RunError
type RunErrorCode ¶
type RunErrorCode string
RunErrorCode is the machine-readable code on a RUN_ERROR event. The vocabulary is deliberately small: aborted (operator/client cancellation) and internal (any server-side fault, with no detail leaked to the client). A HITL pause is NOT an error — it is a terminal RunFinished{outcome: interrupt} (see RunOutcome), so it carries no error code.
const ( RunErrorAborted RunErrorCode = "aborted" RunErrorInternal RunErrorCode = "internal" )
type RunFinished ¶
type RunFinished struct {
ThreadID string `json:"threadId"`
RunID string `json:"runId"`
Outcome *RunOutcome `json:"outcome,omitempty"`
Result json.RawMessage `json:"result,omitempty"`
// contains filtered or unexported fields
}
RunFinished is the terminal event for a run that reached a stopping point, carrying a RunOutcome that says which. A success outcome carries Result (the workload's final answer, also present as the closing TextMessage triad; the duplication is inherent under message-granular streaming). An interrupt outcome carries the open Interrupts the client must answer to resume — a HITL pause is a clean run stop, not a RunError (docs/ag-ui-design.md).
func NewRunFinished ¶
func NewRunFinished(threadID, runID string, result json.RawMessage) RunFinished
NewRunFinished builds the terminal event for a run that completed successfully, carrying a success outcome and the final answer.
func NewRunFinishedInterrupt ¶
func NewRunFinishedInterrupt(threadID, runID string, interrupts []Interrupt) RunFinished
NewRunFinishedInterrupt builds the terminal event for a run that paused for human input, carrying an interrupt outcome and the open interrupts the client must answer to resume. It carries no Result — the run has not produced a final answer yet.
type RunInput ¶
type RunInput struct {
// WorkloadName is the target workload (the endpoint the request hit).
WorkloadName string
// ThreadID / RunID are the client-supplied correlation ids; the daemon
// derives the (namespaced) mast session id from them and never trusts a
// client-supplied raw session id.
ThreadID string
RunID string
// ParentRunID is the run this one continues, when the client sets it. A
// resume arrives as a NEW run (new RunID) but must reach the session the
// parent run parked; under a run-keyed session model the daemon keys the
// resume's session on ParentRunID. Empty when absent.
ParentRunID string
// Text is the turn's user input (the last user message's content).
Text string
// State is the client-supplied shared-state document, echoed back as the
// opening StateSnapshot; nil when absent.
State json.RawMessage
// Resume, when non-empty, makes this a resume of an interrupted run: each
// entry answers one open interrupt (by id) rather than driving a fresh user
// turn. The daemon translates the answers into the runtime's resume input.
Resume []ResumeEntry
}
RunInput is a RunAgentInput projected onto the runtime seam. The server extracts it from the decoded request; the daemon converts Text into a user turn and runs it through the turn chokepoint. State rides along as raw JSON for the backend to echo as the opening StateSnapshot.
type RunMetric ¶
type RunMetric interface {
AGUIRun(workload, outcome string)
}
RunMetric records AG-UI run outcomes. The daemon backs it with observability.Registry.AGUIRun; nil disables. The outcome is one of a fixed vocabulary (see observability.Prime): success, interrupted, error, aborted, rejected.
type RunOutcome ¶
type RunOutcome struct {
Type RunOutcomeType `json:"type"`
Interrupts []Interrupt `json:"interrupts,omitempty"`
}
RunOutcome is the structured disposition on a RunFinished. Type is "success" (the run completed; the answer is in RunFinished.Result) or "interrupt" (the run paused for human input; Interrupts lists what to answer). The interrupt lifecycle maps directly onto mast's durable pause/resume: each Interrupt.ID is a mast pending-interrupt id, and a client resumes by POSTing a new run whose RunAgentInput.Resume answers it.
type RunOutcomeType ¶
type RunOutcomeType string
RunOutcomeType discriminates a RunFinished's disposition.
const ( RunOutcomeSuccess RunOutcomeType = "success" RunOutcomeInterrupt RunOutcomeType = "interrupt" )
type RunResult ¶
RunResult is the terminal outcome of a run, returned by the Backend after the turn completes. Exactly one disposition holds: Aborted (operator/client cancellation), Interrupted (the turn paused for human input), or neither (success, with Text the final answer surfaced in RunFinished.result). When Interrupted, Interrupts lists the open interrupts the client must answer to resume; the server emits them in the terminal RunFinished{outcome: interrupt}.
type RunStarted ¶
type RunStarted struct {
ThreadID string `json:"threadId"`
RunID string `json:"runId"`
// contains filtered or unexported fields
}
RunStarted opens a run's event stream (docs/ag-ui-design.md: session start).
func NewRunStarted ¶
func NewRunStarted(threadID, runID string) RunStarted
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the AG-UI HTTP server. Construct with New; serve with ListenAndServe or Serve.
func (*Server) Handler ¶
Handler exposes the server's routes for mounting on an external mux or for tests (httptest.NewServer).
func (*Server) ListenAndServe ¶
ListenAndServe blocks serving requests; returns http.ErrServerClosed on graceful shutdown.
type StateDelta ¶
type StateDelta struct {
Delta json.RawMessage `json:"delta"`
// contains filtered or unexported fields
}
type StateSnapshot ¶
type StateSnapshot struct {
Snapshot json.RawMessage `json:"snapshot"`
// contains filtered or unexported fields
}
StateSnapshot carries the full shared-state document; StateDelta carries an RFC-6902 JSON Patch against the last snapshot. Stage 1 emits one opening StateSnapshot (echoing the input State); per-key StateDelta emission is deferred (it needs a state-projection allowlist), but the type ships so the state vocabulary is complete.
func NewStateSnapshot ¶
func NewStateSnapshot(snapshot json.RawMessage) StateSnapshot
type StepFinished ¶
type StepFinished struct {
StepName string `json:"stepName"`
// contains filtered or unexported fields
}
type StepStarted ¶
type StepStarted struct {
StepName string `json:"stepName"`
// contains filtered or unexported fields
}
StepStarted / StepFinished bracket a named step within a run (reserved for multi-step workloads; modeled so consumers can rely on the vocabulary).
type TextMessageContent ¶
type TextMessageContent struct {
MessageID string `json:"messageId"`
Delta string `json:"delta"`
// contains filtered or unexported fields
}
func NewTextMessageContent ¶
func NewTextMessageContent(messageID, delta string) TextMessageContent
type TextMessageEnd ¶
type TextMessageEnd struct {
MessageID string `json:"messageId"`
// contains filtered or unexported fields
}
func NewTextMessageEnd ¶
func NewTextMessageEnd(messageID string) TextMessageEnd
type TextMessageStart ¶
type TextMessageStart struct {
MessageID string `json:"messageId"`
Role string `json:"role"`
// contains filtered or unexported fields
}
TextMessageStart / TextMessageContent / TextMessageEnd stream one assistant message. mast runs StreamingModeNone (message-granular), so a message is emitted as start + a single content frame carrying the whole text + end; the triad shape keeps token-level streaming a forward-compatible upgrade. Role is present only on the start frame ("assistant").
func NewTextMessageStart ¶
func NewTextMessageStart(messageID string) TextMessageStart
type Tool ¶
type Tool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters json.RawMessage `json:"parameters,omitempty"`
}
Tool is a client-declared tool offered to the agent for this run. Parsed but ignored (accepting client tools is a follow-on); modeled so the input contract is complete.
type ToolCallArgs ¶
type ToolCallArgs struct {
ToolCallID string `json:"toolCallId"`
Delta string `json:"delta"`
// contains filtered or unexported fields
}
func NewToolCallArgs ¶
func NewToolCallArgs(toolCallID, delta string) ToolCallArgs
type ToolCallEnd ¶
type ToolCallEnd struct {
ToolCallID string `json:"toolCallId"`
// contains filtered or unexported fields
}
func NewToolCallEnd ¶
func NewToolCallEnd(toolCallID string) ToolCallEnd
type ToolCallResult ¶
type ToolCallResult struct {
ToolCallID string `json:"toolCallId"`
MessageID string `json:"messageId,omitempty"`
Content string `json:"content"`
// contains filtered or unexported fields
}
func NewToolCallResult ¶
func NewToolCallResult(toolCallID, content string) ToolCallResult
type ToolCallStart ¶
type ToolCallStart struct {
ToolCallID string `json:"toolCallId"`
ToolCallName string `json:"toolCallName"`
ParentMessageID string `json:"parentMessageId,omitempty"`
// contains filtered or unexported fields
}
ToolCallStart / ToolCallArgs / ToolCallEnd stream one tool invocation, and ToolCallResult reports its outcome once the runtime has run it. Args carries the JSON-encoded call arguments; Content carries the JSON-encoded response. ParentMessageID links the call to the assistant message that issued it.
func NewToolCallStart ¶
func NewToolCallStart(toolCallID, name, parentMessageID string) ToolCallStart