wire

package
v0.27.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package common is the memcode PROTOCOL contract: the wire types shared by the CLI (the client) and the api gateway (the server), the sdk/agent ↔ CLI stream-json envelope, the abstract Intent, shared error sentinels, and the model/pricing metadata both ledgers price against.

It is the single source of truth for everything that crosses a memcode wire. Both the cli and api modules redeclared these types independently once, and the drift caused real outages (tool input_schema, lane bypass) — this package exists so that can never happen again.

Invariant: common holds the PROTOCOL only and is stdlib-only (zero third-party dependencies). It contains no prompt doctrine, no provider keys, no routing logic, and no capability interfaces — those live at their consuming boundary (the cli and api each declare the structural interface they need; a client implementation merely satisfies them). A guard test enforces the stdlib-only rule.

Index

Constants

View Source
const (
	// client → CLI (control)
	MsgInitialize         = "initialize"          // first message; configure the session
	MsgUserTurn           = "user_turn"           // submit a user prompt (starts a turn)
	MsgPermissionResponse = "permission_response" // answer a permission_request
	MsgAskResponse        = "ask_response"        // answer an ask_request
	MsgCancel             = "cancel"              // interrupt the running turn

	// CLI → client (events)
	MsgInitialized       = "initialized"        // session ready; carries session id
	MsgAssistantDelta    = "assistant_delta"    // a chunk of assistant text
	MsgToolCall          = "tool_call"          // a tool is running
	MsgToolResult        = "tool_result"        // a tool finished (summary)
	MsgPermissionRequest = "permission_request" // the turn is blocked awaiting approval
	MsgAskRequest        = "ask_request"        // the turn is blocked awaiting a user choice
	MsgSessionState      = "session_state"      // busy/idle + room/mode telemetry
	MsgUsage             = "usage"              // running token counts
	MsgResult            = "result"             // a turn finished
	MsgError             = "error"              // a turn errored
)

Message families. The direction comments are from the wrapper's point of view.

View Source
const CodeAccountLocked = "account_locked"

CodeAccountLocked is the gateway's machine-readable error code for an org locked by a negative balance (HTTP 402), mapped to ErrAccountLocked.

View Source
const CodeByokKeyFailed = "byok_key_failed"

CodeByokKeyFailed is the gateway's machine-readable error code for a turn killed by the user's own provider key (HTTP 422 body and the SSE error event), mapped to ErrByokKeyFailed.

View Source
const CodeContextOverflow = "context_overflow"

CodeContextOverflow is the gateway's machine-readable error code for a context-window overflow — carried on the HTTP 413 body and the SSE error event, mapped to ErrContextOverflow by the client.

View Source
const CodeInsufficientCredit = "insufficient_credits"

CodeInsufficientCredit is the gateway's machine-readable error code for an exhausted credit wallet — carried on the HTTP 402 body and the SSE error event, mapped to ErrInsufficientCredit by the client.

View Source
const CodeSubscriptionRequired = "subscription_required"

CodeSubscriptionRequired is the gateway's machine-readable error code for an org with no active subscription (HTTP 402), mapped to ErrSubscriptionRequired.

View Source
const StreamJSONVersion = "1"

StreamJSONVersion is the protocol version stamped on every Envelope. Bump on a breaking change to the message families or payloads.

Variables

View Source
var ErrAccountLocked = errors.New("your balance is negative — hosted models are paused; settle it at memcode.ai/account/billing (your own API keys keep working via /apikeys)")

ErrAccountLocked is returned when the org's balance went negative from a post-hoc debit overrun — the gateway returns 402 with code "account_locked". Everything is refused, BYOK included, until credits are added. Never retried.

View Source
var ErrByokKeyFailed = errors.New("your API key was rejected — fix or remove it with /apikeys")

ErrByokKeyFailed is returned when the turn died on the USER's own provider key (fail-the-turn doctrine: a failing BYOK key is never absorbed onto memcode's keys) — the gateway returns 422 with code "byok_key_failed". Never retried: the fix is /apikeys, not another attempt.

View Source
var ErrContextOverflow = errors.New("context window overflow")

ErrContextOverflow is returned when a turn's prompt exceeds the served context window on EVERY available backend (the gateway already absorbs vLLM overflow up to Anthropic; this fires only when even Anthropic's window is exceeded). The CLI runtime watches for it with errors.Is and compacts-then-retries the turn rather than surfacing a raw error — the reactive end of the routing ladder. On the wire it is signalled by HTTP 413 with code "context_overflow" and by an SSE error event carrying the same code.

View Source
var ErrInsufficientCredit = errors.New("credits exhausted — add your own API keys with /apikeys, or manage your plan and credits at memcode.ai/account/billing")

ErrInsufficientCredit is returned when the org's prepaid credit balance is exhausted — the gateway returns 402 with code "insufficient_credits". The CLI surfaces a friendly message and stops the turn (no retry: it's a user action, not a transient failure). Keys lead the message: they're the fix on every plan, while "add credits" doesn't exist on the BYOK-only Free plan.

View Source
var ErrStreamIncomplete = errors.New("gateway stream ended without a response")

ErrStreamIncomplete is returned when an SSE stream ends WITHOUT a terminal response event (a mid-stream read error, or the connection closing early — e.g. a Cloud Run request-timeout cutting off a long model call). It is a transient TRANSPORT failure, not a model/logic error: the failed call appended nothing, so the runtime can retry it from the same history. Watched with errors.Is and retried (bounded) rather than dying mid-turn with work half-done.

View Source
var ErrSubscriptionRequired = errors.New("subscription required — choose a plan at memcode.ai/account/billing")

ErrSubscriptionRequired is returned when the org has no active subscription — the gateway returns 402 with code "subscription_required". Subscription is mandatory for every LLM call, BYOK included (2026-07-26). Never retried: choosing a plan is a user action.

View Source
var ErrUnauthorized = errors.New("not signed in — your session expired or the token was revoked; run /login to reconnect")

ErrUnauthorized is returned when the gateway rejects the bearer token (HTTP 401): expired, revoked, or the retired legacy static token. It means the SESSION is signed out, not that the turn transiently failed — hosts watch with errors.Is, flip to their signed-out state, and prompt for /login instead of surfacing a raw HTTP error. Never retried.

Functions

This section is empty.

Types

type AskRequestData

type AskRequestData struct {
	Question string   `json:"question"`
	Options  []string `json:"options,omitempty"`
}

AskRequestData / AskResponseData are the ask_user human-in-the-loop round-trip.

type AskResponseData

type AskResponseData struct {
	Answer string `json:"answer"`
}

type AssistantDeltaData

type AssistantDeltaData struct {
	Text string `json:"text"`
}

AssistantDeltaData is a chunk of streamed assistant text (CLI → client).

type Block

type Block struct {
	Type string `json:"type"` // "text" | "image" | "document" | "tool_use" | "tool_result"
	Text string `json:"text,omitempty"`

	// image / document
	Source *MediaSource `json:"source,omitempty"`

	// tool_use
	ID    string          `json:"id,omitempty"`
	Name  string          `json:"name,omitempty"`
	Input json.RawMessage `json:"input,omitempty"`

	// tool_result
	ToolUseID string `json:"tool_use_id,omitempty"`
	Content   string `json:"content,omitempty"`
	IsError   bool   `json:"is_error,omitempty"`

	// ContentBlocks carries STRUCTURED content for a tool_result — one or more
	// content blocks (text and/or image) instead of the flat Content string. This
	// is the path for tool results that include vision (e.g. a browser screenshot
	// returned to the model as an image block). When non-empty, providers emit the
	// structured content union (Anthropic: text+image parts in the tool_result;
	// OpenAI: multi-part tool message). When empty, Content (flat string) is used
	// — backwards compatible with every text-only tool result.
	ContentBlocks []Block `json:"content_blocks,omitempty"`

	// thinking (extended/adaptive reasoning). These MUST round-trip UNMODIFIED: the
	// API requires the assistant's thinking blocks to be passed back verbatim on the
	// next tool-use turn (it verifies them via Signature) or it rejects the request.
	// So we parse them off responses and re-send them; we just don't display them.
	// Data carries a redacted_thinking block's opaque payload, if one ever appears.
	Thinking  string `json:"thinking,omitempty"`
	Signature string `json:"signature,omitempty"`
	Data      string `json:"data,omitempty"`

	// prompt caching (set on the wire only, never on shared history — see the gateway)
	CacheControl *CacheControl `json:"cache_control,omitempty"`
}

Block is one content block in a message (text, image/document, a tool call, or a tool result, or a thinking block).

func DocumentBlock

func DocumentBlock(mediaType string, data []byte) Block

DocumentBlock builds a document block from raw file bytes (application/pdf is the interoperable case: Anthropic document source, OpenAI Responses input_file, Gemini inline blob). Models without native document input absorb the turn to a capable tier — the catalog's pdf flag gates that in the router.

func ImageBlock

func ImageBlock(mediaType string, data []byte) Block

ImageBlock builds a vision block from raw image bytes.

func TextBlock

func TextBlock(text string) Block

TextBlock builds a text block.

func ToolResultBlocks

func ToolResultBlocks(toolUseID string, blocks []Block, isError bool) Block

ToolResultBlocks builds a tool_result block carrying structured content blocks (text and/or image) instead of a flat string. This is the path for tool results that include vision — e.g. a browser screenshot returned as an image block. When blocks is empty, falls back to an empty text result.

func (Block) MarshalJSON

func (b Block) MarshalJSON() ([]byte, error)

MarshalJSON serializes a Block for the wire. Thinking blocks MUST carry the "thinking" field even when its text is EMPTY: adaptive thinking frequently returns a block that is just a signature (the reasoning text omitted), and on the next tool-use turn Anthropic rejects a thinking block without the field — "thinking.thinking: Field required". The struct tag is `omitempty` (correct for every OTHER block type, which must NOT carry a stray empty "thinking"), so we special-case thinking / redacted_ thinking here and let the alias handle the rest with default tags.

type CacheControl

type CacheControl struct {
	Type string `json:"type"` // "ephemeral"
	// TTL is the cache lifetime: "" (default 5m) or "1h". The long TTL is used for the
	// STABLE doctrine+tools prefix, which is byte-identical across turns even as the
	// volatile facts (room/personality) change — so it survives interactive gaps >5min.
	TTL string `json:"ttl,omitempty"`
}

CacheControl marks a prompt-cache breakpoint. Everything from the start of the prompt up to and including the marked block is cached (5-min ephemeral TTL); later requests sharing that prefix read it instead of re-paying input tokens, and cache reads are excluded from the input-tokens/min rate limit.

type Effort

type Effort string

Effort is an abstract reasoning-depth setting. It exists so call sites express INTENT ("this is a judgment call, think harder") without hardcoding a provider shape that differs by model — e.g. Opus 5 rejects manual budget_tokens and requires adaptive thinking + an effort hint, while Opus 4.5 wants budget_tokens.

const (
	EffortOff    Effort = ""       // no extended thinking (default; cheap paths)
	EffortLow    Effort = "low"    // light reasoning
	EffortMedium Effort = "medium" // judgment calls (edits, reflection)
	EffortHigh   Effort = "high"   // hardest reasoning (planning, review)
)

type Envelope

type Envelope struct {
	Version string          `json:"version"`
	Type    string          `json:"type"`
	ID      string          `json:"id,omitempty"`      // correlation id (e.g. a permission/ask request↔response)
	TurnID  string          `json:"turn_id,omitempty"` // the turn this message belongs to
	Data    json.RawMessage `json:"data,omitempty"`
}

Envelope is the single wire frame. Data is a type-specific payload (below).

type ErrorData

type ErrorData struct {
	Message string `json:"message"`
}

ErrorData reports a turn-level error (CLI → client).

type InitializeData

type InitializeData struct {
	Cwd  string `json:"cwd,omitempty"`  // working directory / repo root
	Mode string `json:"mode,omitempty"` // permission mode: ask | auto | allow-all
	Pin  string `json:"pin,omitempty"`  // pinned model label ("" = Automatic)
}

InitializeData configures the session (client → CLI).

type InitializedData

type InitializedData struct {
	SessionID string `json:"session_id"`
	Protocol  string `json:"protocol"` // echoes the version for handshake validation
}

InitializedData announces a ready session (CLI → client).

type Intent

type Intent struct {
	// Purpose is what this turn is FOR (ledger attribution + lane selection):
	// "main_loop" | "explore" | "classify" | "compact" | …
	Purpose string `json:"purpose,omitempty"`

	// Mode names the doctrine the turn runs under ("chat" | "exec" | "plan" |
	// …) — plan mode has its own lane branch.
	Mode string `json:"mode,omitempty"`

	// Reasoning is the abstract reasoning depth the turn warrants (maps to Effort).
	Reasoning Effort `json:"reasoning,omitempty"`

	// Difficulty is the TIER demand the turn was judged to have — a separate axis
	// from Reasoning (thinking depth): a tricky single-file bug can be
	// {standard, high-thinking}. Judged by the turn_intent classifier on the
	// classify lane: "lookup" (short read-only retrieval → cheap tier) |
	// "standard" (ordinary work) | "deep" (repo-scale/architectural/root-cause →
	// heavy tier). Empty = unjudged (judge unavailable) — the ladder falls back
	// to Reasoning-based escalation.
	Difficulty string `json:"difficulty,omitempty"`

	// Risk is the session layer's escalation signal — what only it observes:
	// "self_heal" | "user_friction_high" | … (folded from RoutingHint.Reason).
	Risk string `json:"risk,omitempty"`

	// Interactive is true when a live user is present (vs a batch/background
	// job) — available to the policy for latency-vs-cost trade-offs.
	Interactive bool `json:"interactive,omitempty"`

	// Vendor is the per-session strong-tier override: "" = the configured
	// default, or one of "openai" | "anthropic" | "gemini" | "grok". It names a
	// VENDOR, not a model — the ladder still resolves the tier (frontier/
	// balanced/cheap) within that vendor from the catalog's tier triples. Set by
	// the CLI's /model selector; BYOK steering may prefer a keyed vendor when
	// none is configured.
	Vendor string `json:"vendor,omitempty"`

	// Pin is the user's explicit model choice from /model: a catalog LABEL
	// ("sol", "sonnet", "glm-5p2", …), never a raw provider id — raw ids stay at
	// the serving edge. "" = Automatic (the routing doctrine decides). When set
	// and valid, every real request serves this model; invisible plumbing
	// (classify/compact/shrinkwrap) stays on the utility lanes, and an
	// unknown/un-pinnable label falls through to Automatic so a stale pin never
	// breaks a session. Pins are never coerced — capability gaps fail typed, not
	// silently rerouted.
	Pin string `json:"pin,omitempty"`
}

Intent is the abstract selection contract: the session layer expresses WHAT a turn is, and the CLI's selection policy (cli/internal/llm: laneFor + the resolver) maps intent → concrete catalog label. It is a client-internal type now — it never rides a wire. The abstraction survives the policy's move from the gateway because it is what keeps call sites from naming models: purposes and modes are stable vocabulary; labels and tiers are catalog data.

type MediaSource

type MediaSource struct {
	Type      string `json:"type"`       // "base64"
	MediaType string `json:"media_type"` // e.g. image/png, application/pdf
	Data      string `json:"data"`
}

MediaSource carries base64 image/document data for vision blocks.

type Message

type Message struct {
	Role   string  `json:"role"` // "user" | "assistant"
	Blocks []Block `json:"content"`
}

Message is one turn (a role plus its content blocks).

type PermissionRequestData

type PermissionRequestData struct {
	Title    string `json:"title"`
	Label    string `json:"label,omitempty"`
	Detail   string `json:"detail,omitempty"`
	Command  string `json:"command,omitempty"`
	Cwd      string `json:"cwd,omitempty"`
	Risk     string `json:"risk,omitempty"`
	Editable bool   `json:"editable,omitempty"`
}

PermissionRequestData asks the client to approve an action (CLI → client). The client answers with a PermissionResponseData carrying the same Envelope.ID.

type PermissionResponseData

type PermissionResponseData struct {
	Allow     bool   `json:"allow"`
	Command   string `json:"command,omitempty"`   // run this edited command instead
	Reason    string `json:"reason,omitempty"`    // when !allow: fed back to the model
	Interrupt bool   `json:"interrupt,omitempty"` // stop the whole turn
}

type Request

type Request struct {
	Model    string    `json:"model,omitempty"` // resolved id at the serving edge; clients carry their choice in Pin
	System   string    `json:"system,omitempty"`
	Messages []Message `json:"messages"`

	// SystemVolatile is the per-turn-variable doctrine suffix (room/personality/
	// extra-mile/nudge + the turn-scoped extra) split OUT of System so it sits
	// OUTSIDE the cached prefix. The CLI's doctrine composer fills it (directly,
	// or via the transport's compose hook from Mode+Facts); adapters place it
	// cache-safely — Anthropic as a second, uncached system block, chat/
	// completions as a trailing system message, so the stable prefix still
	// auto-caches.
	SystemVolatile string    `json:"system_volatile,omitempty"`
	Tools          []ToolDef `json:"tools,omitempty"`
	MaxTokens      int       `json:"max_tokens,omitempty"`

	// ToolChoice, when set to a tool name, FORCES the model to call that tool — the
	// reliable cross-provider path to structured output (Anthropic tool_choice / OpenAI
	// tool_choice). Used by the plan reviewer's verdict so the JSON comes back in a tool_use
	// block instead of best-effort prose-JSON. "" = the model chooses (the common case).
	ToolChoice string `json:"tool_choice,omitempty"`

	// Mode + Facts select a doctrine prompt: the transport's compose hook
	// (cli/internal/doctrine) renders the mode's doctrine with these gathered
	// facts (root, platform, shell, overview/pack, room, nudge) into System/
	// SystemVolatile just before encoding. Mode "" = raw transport (no
	// composition; System passes through as-is).
	Mode  string            `json:"mode,omitempty"`
	Facts map[string]string `json:"facts,omitempty"`

	// Effort is the ABSTRACT reasoning-depth knob. The provider maps it to whatever
	// thinking control the target model actually supports (adaptive+effort, manual
	// budget_tokens, or nothing). Zero value (EffortOff) means no extended thinking.
	Effort Effort `json:"effort,omitempty"`

	// RoutingHint is the session layer's escalation signal (ROUTING.md): user
	// friction/mood, a self-healing retry after the agent's own edit broke, a
	// high-risk surface. The Runner folds its Reason into Intent.Risk for the
	// selection ladder. nil = no opinion (the common case).
	RoutingHint *RoutingHint `json:"routing_hint,omitempty"`

	// Purpose + Session are transport-local labels (json:"-": never marshaled on
	// this type). Purpose labels the call for the client ledger and the lane
	// leak-log. Session rides the compat wire as the standard `user` field for
	// serving affinity (prefix-cache locality) and gateway telemetry. Stamped by
	// the CLI's llm.Runner; never set by hand.
	Purpose string `json:"-"`
	Session string `json:"-"`

	// Difficulty is the turn_intent judge's tier verdict ("lookup" | "standard"
	// | "deep"), a CLI-side selection input (json:"-", read by the CLI's own
	// resolution policy — it never rides the wire).
	Difficulty string `json:"-"`

	// Pin is the CLI-side carrier for the session's model choice: the resolved
	// catalog LABEL the transport puts in the wire `model` field. Under
	// all-policy-client-side the CLI's selection policy stamps it on EVERY
	// call (Automatic is client behavior); "" is only ever seen by test fakes.
	Pin string `json:"-"`

	// BillingLane is the requested billing lane: "" / "byok_preferred" |
	// "byok_only" | "credits". Client-side it is set by policy (the consented
	// credits retry after a BYOK key failure) and rides the wire as the
	// memcode_billing extension; server-side the compat handler re-stamps it
	// from that extension and the gateway ENFORCES it — it never silently
	// reroutes between the user's keys and credits. NOT marshaled on this type.
	BillingLane string `json:"-"`
	// LaneBypass forces a turn OFF its family lane after an explicit,
	// consented exhaustion choice: "gateway" serves it on the hosted base.
	// Client-side routing state only — never serialized to any wire.
	LaneBypass string `json:"-"`
}

Request is a model completion request — the provider-neutral shape every adapter encodes from. Model selection is the CLI's job (llm/lane.go + llm/resolve.go): the Runner's policy resolves a catalog label into Pin, and the transport writes it into the wire `model` field. Server-side, Model carries the gateway's raw provider id after the label gate resolves it.

type Response

type Response struct {
	StopReason   string  `json:"stop_reason"` // "end_turn" | "tool_use" | "max_tokens"
	Blocks       []Block `json:"blocks"`      // assistant content (text and/or tool_use)
	InputTokens  int     `json:"input_tokens"`
	OutputTokens int     `json:"output_tokens"`

	// prompt-cache telemetry (tokens written to / read from the cache this call)
	CacheWriteTokens int `json:"cache_write_tokens,omitempty"`
	CacheReadTokens  int `json:"cache_read_tokens,omitempty"`

	// SearchCount is the number of native server-side web searches the serving
	// vendor billed on this call (Anthropic usage.server_tool_use.web_search_requests;
	// OpenAI/Grok Responses web_search_call output items). Searches carry a
	// PER-REQUEST fee on top of tokens — the gateway prices it via
	// common.SearchFeeUSD(Backend, SearchCount) when it emits cost_usd.
	SearchCount int `json:"search_count,omitempty"`

	// ToolOrigin records how a tool call was obtained: "structured" (the model's native
	// tool_calls — the intended path) or "salvaged_*" (the gateway recovered it from
	// text a brittle parser missed). Surfaced so salvage stays OBSERVABLE, never silently
	// the main contract.
	ToolOrigin string `json:"tool_origin,omitempty"`

	// Serving telemetry — the ledger's ground truth for WHO served this call.
	// Model is the model that actually ran (a fallback-chain hop can differ from
	// the requested label). Backend is the serving vendor: "cheap" (the hosted
	// cheap lane, vendor-neutral — the inference vendor never rides the wire) |
	// "anthropic" | "openai" | "gemini" | "grok" | "unknown" (label missing from
	// the client catalog); "vllm" is the legacy cheap-lane tag an un-redeployed
	// gateway sends (clients accept both). FallbackReason names why the served
	// model differs from the primary choice: a client-side absorb ("vision" |
	// "pdf" | "window") or a recovery hop ("model_error: …").
	Model          string `json:"model,omitempty"`
	Backend        string `json:"backend,omitempty"`
	FallbackReason string `json:"fallback_reason,omitempty"`

	// RequestedModel is the label the selection policy chose BEFORE any absorb/
	// fallback — the basis for the ledger's counterfactual "what the primary
	// would have cost". The CLI's finalize stamps it (the gateway echoes the
	// requested id on hosted turns); it equals Model when nothing intervened.
	RequestedModel string `json:"requested_model,omitempty"`

	// ContextWindow is the serving backend's real input window in tokens, when
	// the backend reports one (0 when the client's catalog already knows it).
	ContextWindow int `json:"context_window,omitempty"`

	// InputBudget is the serving lane's usable INPUT budget (window − output reserve −
	// safety margin) — the size a prompt must fit under to land on THIS lane. The CLI
	// learns the cheap lane's budget from this and aims compaction at it. 0 when not
	// lane-served.
	InputBudget int `json:"input_budget,omitempty"`

	// Pool is the cheap lane's served-model short label ("glm-5p2" | "kimi-k3"),
	// the CLI's ⇄ ServedBy tag for lane serves. EstimatedPromptTokens is the
	// server's pre-call size estimate (stamped per serve so the usage log's
	// EstimateRatio can calibrate the estimator against real InputTokens).
	Pool                  string `json:"pool,omitempty"`
	EstimatedPromptTokens int    `json:"estimated_prompt_tokens,omitempty"`

	// BYOK telemetry. BYOK (whether this call ran on the user's OWN provider
	// key) rides the wire — it is the key owner's own information, shown by the
	// CLI footer strictly per-turn. BYOKVendor stays SERVER-INTERNAL (json:"-"):
	// the cheap lane's inference vendor never leaves the server (SanitizeResponse
	// zeroes it defensively). The gateway reads both for metering (usage line +
	// zero-debit policy) before sanitizing.
	BYOK       bool   `json:"byok,omitempty"`
	BYOKVendor string `json:"-"`
}

Response is a model completion result, plus the serving telemetry the footer/ ledger read. On the hosted backend the gateway stamps the serving facts (via the memcode response extension); in direct-endpoint mode the CLI's recovery policy stamps them itself (finalize) — same fields, one reader.

func (Response) Text

func (r Response) Text() string

Text returns the concatenated text blocks of a response.

func (Response) ToolUses

func (r Response) ToolUses() []Block

ToolUses returns the tool_use blocks of a response.

type ResultData

type ResultData struct {
	Text      string `json:"text,omitempty"` // final assistant text, if captured
	Completed bool   `json:"completed"`
}

ResultData ends a turn (CLI → client).

type RoutingHint

type RoutingHint struct {
	Reason string `json:"reason,omitempty"`
}

RoutingHint carries the escalation signal only the CLI can observe — the Risk input to the CLI's OWN semantic ladder (cli/internal/llm/lane.go): "self_heal" | "agent_frontier" | "agent_strong" | "user_friction_high" | "high_risk_surface" | the plan escalation reasons. It never rides any wire; it is a request-local field the Runner's selection policy reads. (The old PreferredPath/Force fields were read by nothing — deleted.)

type SessionStateData

type SessionStateData struct {
	Busy bool   `json:"busy"`
	Mode string `json:"mode,omitempty"` // room mode (normal/repair/replan), when known
}

SessionStateData reports busy/idle + light room telemetry (CLI → client).

type StreamHandler

type StreamHandler struct {
	Text  func(delta string)
	Usage func(input, output int)
}

StreamHandler receives incremental events during a streamed completion. Both callbacks are optional. Text fires for each chunk of assistant text as it arrives; Usage fires when the API reports token counts (input at the start, authoritative output near the end — NOT per delta, so a live "tokens so far" display must estimate from streamed text between Usage calls and reconcile when Usage fires).

This is a data type (a struct of callbacks), part of the wire contract's shape. The capability INTERFACES (ModelProvider, Streamer, WebSearcher, WebFetcher, Advisor) are intentionally NOT declared here — each consumer declares the structural interface it needs, referencing these common types; an implementation merely satisfies it.

type ToolCallData

type ToolCallData struct {
	Name   string `json:"name"`
	Target string `json:"target,omitempty"`
	Detail string `json:"detail,omitempty"`
}

ToolCallData / ToolResultData report tool activity (CLI → client).

type ToolDef

type ToolDef struct {
	Name        string         `json:"name"`
	Description string         `json:"description"`
	InputSchema map[string]any `json:"input_schema"`

	// prompt caching — set on the LAST tool only, on the wire (see the gateway)
	CacheControl *CacheControl `json:"cache_control,omitempty"`
}

ToolDef describes a tool the model may call.

type ToolResultData

type ToolResultData struct {
	Name   string `json:"name"`
	Status string `json:"status,omitempty"` // "ok" | "failed" | …
}

type UsageData

type UsageData struct {
	OutputTokens int `json:"output_tokens"`
}

UsageData reports running token counts (CLI → client).

type UserTurnData

type UserTurnData struct {
	Text string `json:"text"`
}

UserTurnData submits a prompt (client → CLI).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL