agent

package
v0.11.6 Latest Latest
Warning

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

Go to latest
Published: Aug 21, 2026 License: AGPL-3.0 Imports: 28 Imported by: 0

Documentation

Overview

Package agent defines shared types and infrastructure for coding agent backends. Backend implementations live in sub-packages (e.g. agent/claudecode).

Message dispatch

Conn.ReadMessages reads agent stdout and forwards parsed messages to Options.MsgCh. The task checkout drains this channel in a separate goroutine (startMessageDispatch) that performs blocking side-effects: git fetch, diff stat, branch locking. The channel decouples the fast reader from these slow operations — without it, a blocked git fetch would backpressure the agent's stdout pipe and risk deadlock.

Conn is an interface. Backends that need to intercept messages (e.g. injecting control commands after initialization) wrap the default Conn returned by NewConn to override ReadMessages.

Relay shutdown protocol

Each agent runs inside a container behind a relay daemon (relay.py) that survives SSH disconnects. Graceful shutdown uses a null-byte (\x00) sentinel written to stdin:

Flow 1 — One task is purged (user action or container death):

Server calls Checkout.Cleanup → Session.Stop writes \x00\n then closes
stdin → attach_client forwards sentinel through Unix socket, sees stdin
EOF, exits → _client_reader sets shutdown_event → _shutdown_watchdog
closes proc.stdin, sends SIGINT, escalates to SIGTERM/SIGKILL →
reader_thread sees stdout EOF → server kills container.

Flow 2 — Backend restarts (upgrade, crash):

SSH connections are severed → attach_client sees stdin EOF and disconnects
(no \x00 sent) → relay daemon + agent keep running → on restart, server
discovers the container during task import, reads output.jsonl to restore
conversation state, and calls relay.py attach --offset N to reconnect.

Index

Constants

View Source
const (
	RelayDir        = "/tmp/caic-relay"
	RelayScriptPath = RelayDir + "/relay.py"
	RelaySockPath   = RelayDir + "/relay.sock"
	RelayOutputPath = RelayDir + "/output.jsonl"
	RelayLogPath    = RelayDir + "/relay.log"
)

Relay paths inside the container.

View Source
const MaxWidgetHTMLBytes = 256 * 1024 // 256 KB

MaxWidgetHTMLBytes is the maximum size of widget HTML the backend will forward to clients. Widgets exceeding this limit are replaced with an error message.

View Source
const PendingUserActionMessageType = messageTypePendingUserAction

PendingUserActionMessageType identifies a persisted pending user action.

View Source
const WidgetPluginDir = RelayDir + "/widget-plugin"

WidgetPluginDir is the container path where the widget plugin is deployed.

Variables

View Source
var WidgetMCPServerScript []byte

WidgetMCPServerScript is the Python MCP server script that exposes the show_widget tool. It is deployed to containers by backends that support widget rendering (claude, codex).

View Source
var WidgetToolNames = map[string]struct{}{
	"show_widget":              {},
	"mcp__widget__show_widget": {},
	"mcp__plugin_caic-widget_widget__show_widget": {},
}

WidgetToolNames is the set of tool names that produce HTML widgets. Each harness parser checks this set to decide whether a tool_use block should emit WidgetMessage instead of ToolUseMessage.

Functions

func APIKeyHash added in v0.9.0

func APIKeyHash(envVars []string) string

APIKeyHash computes a deterministic SHA-256 hex digest of the *_API_KEY environment variable entries from the harness env list (KEY=VALUE pairs). Variables whose name does not end with _API_KEY are ignored. An empty input produces an empty hash.

func AppendNativeRecord added in v0.11.5

func AppendNativeRecord(log LogSink, version LogVersion, data []byte) error

AppendNativeRecord appends a native record in the exact physical format.

func CleanRelayState added in v0.6.0

func CleanRelayState(ctx context.Context, container string) error

CleanRelayState removes the relay state directory in the container so that a subsequent StartRelay begins with a clean output.jsonl. Used by fork to prevent the source task's message history from leaking into the forked task.

func DefaultReadMessages added in v0.7.0

func DefaultReadMessages(ctx context.Context, log *slog.Logger, r io.Reader, dispatch func(ParsedMessage), sink LogSink, version LogVersion, parseNative func([]byte) ([]Message, error)) error

DefaultReadMessages reads physical relay records, persists each exactly once, and forwards the parser's original ParsedMessage wrappers.

func DeployEmbeddedDir added in v0.5.1

func DeployEmbeddedDir(ctx context.Context, container string, fsys fs.FS, targetDir string) error

DeployEmbeddedDir writes all files from an embed.FS to a target directory in the container via a single SSH + tar invocation. Idempotent.

func DeployRelay

func DeployRelay(ctx context.Context, target runtime.ConnectionTarget, version LogVersion) error

DeployRelay uploads the selected relay script into the runtime target. Idempotent.

func HasRelayDir

func HasRelayDir(ctx context.Context, container string) (bool, error)

HasRelayDir checks whether the caic relay directory exists in the container. Its presence proves caic deployed the relay at some point.

func IsRelayRunning

func IsRelayRunning(ctx context.Context, container string) (bool, error)

IsRelayRunning checks whether the relay socket exists in the container.

func MarshalLogMessage added in v0.11.5

func MarshalLogMessage(version LogVersion, m Message) ([]byte, error)

MarshalLogMessage encodes one semantic backend control record for version.

func MarshalMessage

func MarshalMessage(m Message) ([]byte, error)

MarshalMessage serializes a Message to JSON. For RawMessage, returns the original bytes to preserve unknown fields. For typed messages, uses json.Marshal.

func PlainTextWritePrompt added in v0.3.0

func PlainTextWritePrompt(w io.Writer, p Prompt, log LogSink) error

PlainTextWritePrompt writes a user prompt as a plain text line on stdin and logs it as NDJSON.

func ReadPlan

func ReadPlan(ctx context.Context, container, planFile string) (string, error)

ReadPlan reads a plan file from the container by invoking relay.py read-plan over SSH. If planFile is non-empty, that specific file is read; otherwise the most recently modified .md file in ~/.claude/plans/ is used.

func ReadRelayLog

func ReadRelayLog(ctx context.Context, container string, maxBytes int) string

ReadRelayLog reads the last maxBytes of the relay daemon's log file from the container. Returns empty string on any error (missing file, SSH failure).

func RelayOutputSize added in v0.9.0

func RelayOutputSize(ctx context.Context, container string) (int64, error)

RelayOutputSize returns the byte size of the relay output.jsonl in the container. This is fast (single stat call) and avoids transferring the file.

func RelayScript added in v0.11.5

func RelayScript(version LogVersion) ([]byte, error)

RelayScript selects the embedded script for a validated log version.

func RelayStatus added in v0.5.0

func RelayStatus(ctx context.Context, container string) (alive bool, detail string, err error)

RelayStatus checks relay socket + PID liveness and returns diagnostic detail.

func RenderDiscussion added in v0.11.5

func RenderDiscussion(meta *MetaMessage, result *MetaResultMessage, pr *MetaPRMessage, msgs []Message) string

RenderDiscussion assembles a self-contained markdown document from task-owned parsed log data. It performs no physical log loading or harness parsing.

func SortModels added in v0.8.0

func SortModels(models []string) []string

SortModels returns models with version deduplication: only the latest version per family key is kept. Models matching a modelBlacklist prefix are dropped. Models without parseable versions are preserved as-is. Output is sorted alphabetically.

The input slice is copied first so the caller's backing array is not modified by slices.DeleteFunc's clear() call.

func StopRelay added in v0.11.5

func StopRelay(ctx context.Context, target runtime.ConnectionTarget) error

StopRelay sends the relay shutdown sentinel through a fresh attachment and waits for the attach client to exit. It terminates the persistent relay and its agent subprocess without treating an SSH disconnect as a shutdown.

func StreamRelay added in v0.9.0

func StreamRelay(ctx context.Context, container string, parser *LogRecordParser, tailBytes, size int64) iter.Seq2[ParsedMessage, error]

StreamRelay streams NDJSON messages from the relay output.jsonl in the container over SSH, yielding each in order. When tailBytes > 0 and the file is larger, only the last tailBytes are transferred (via tail -c) and the partial first line is skipped; otherwise the whole file is streamed (cat).

The SSH stdout is read incrementally, so memory usage is O(1) regardless of file size. If the consumer stops early the ssh process is killed and reaped, so no process leaks per abandoned reader.

func WriteMetaSession added in v0.9.2

func WriteMetaSession(log LogSink, init *InitMessage) error

WriteMetaSession appends a caic_session control record for init metadata.

Types

type AskMessage added in v0.3.0

type AskMessage struct {
	ToolUseID string        `json:"id"`
	Questions []AskQuestion `json:"questions"`
}

AskMessage is emitted when the agent asks the user a question via the AskUserQuestion tool.

func (*AskMessage) Type added in v0.3.0

func (m *AskMessage) Type() string

Type implements Message.

type AskOption added in v0.3.0

type AskOption struct {
	Label       string `json:"label"`
	Description string `json:"description,omitempty"`
}

AskOption is a single option in an AskUserQuestion.

type AskQuestion added in v0.3.0

type AskQuestion struct {
	Question    string      `json:"question"`
	Header      string      `json:"header,omitempty"`
	Options     []AskOption `json:"options"`
	MultiSelect bool        `json:"multiSelect,omitempty"`
}

AskQuestion is a single question from AskUserQuestion.

type Backend

type Backend interface {
	// Start launches the agent at the configured target. Parsed messages are
	// forwarded to opts.MsgCh; opts.Log owns persisted task-log records.
	Start(ctx context.Context, opts *Options) (*Session, error)

	// AttachRelay connects to an already-running relay daemon in the
	// configured target. opts.RelayOffset specifies the byte offset into
	// output.jsonl to replay from (use 0 for full replay).
	// opts.ResumeSessionID is the known agent session ID, used by stateful
	// wire formats (e.g. codex) that need it before the first replay message.
	// opts.PendingUserActions contains user-facing actions restored before
	// reconnect, such as unanswered AskUserQuestion requests. It excludes
	// backend-only control protocol state.
	AttachRelay(ctx context.Context, opts *Options) (*Session, error)

	// Harness returns the harness identifier ("claude", "codex", etc.)
	Harness() harness.Name

	// ModelInventory returns the models and per-model configuration supported
	// by this backend.
	ModelInventory() ModelInventory

	// SetModelInventory replaces the models and per-model configuration.
	// The server uses it to push dynamically discovered inventories into all
	// checkout backends.
	SetModelInventory(inventory ModelInventory)

	// SupportsImages reports whether this backend accepts image content blocks.
	SupportsImages() bool

	// SupportsCompact reports whether this backend supports context compaction.
	SupportsCompact() bool

	// AgentArgs returns the CLI arguments for launching this backend's agent
	// subprocess, including the executable name and all session-specific flags
	// derived from a. Empty fields in a are treated as "use default".
	AgentArgs(a HarnessArgs) []string

	// NewWire creates a fresh WireFormat for this backend. Each call returns
	// independent state; suitable for use outside the normal relay transport.
	NewWire() WireFormat

	// ContextWindowLimit returns the API prompt token limit for the given model.
	// The model parameter is the model name reported by the agent at runtime.
	ContextWindowLimit(model string) int
}

Backend launches and communicates with a coding agent process. Each implementation translates its native wire format into the shared Message types so the rest of the system (task, eventconv, SSE, frontend) remains agent-agnostic.

type Base added in v0.3.0

type Base struct {
	HarnessID     harness.Name
	Images        bool
	ContextWindow int
	Compact       bool
	// contains filtered or unexported fields
}

Base provides default implementations for metadata-only Backend methods. Embed it in backend-specific types to inherit the boilerplate. Each backend must implement Start and AttachRelay itself using the package-level helpers (StartRelay, AttachRelaySession). Base is registered once per process and shared across every concurrent task for its harness (see backends.Default), so ModelInventory/SetModelInventory guard the inventory with a mutex: a background refresh (SetModelInventory) and concurrent request handlers (ModelInventory) can run at the same time. ModelInventory itself is treated as immutable once set, so the mutex only needs to guard a pointer swap, not the read.

func (*Base) ContextWindowLimit added in v0.3.0

func (b *Base) ContextWindowLimit(string) int

ContextWindowLimit implements Backend.

func (*Base) Harness added in v0.3.0

func (b *Base) Harness() harness.Name

Harness implements Backend.

func (*Base) ModelInventory added in v0.11.3

func (b *Base) ModelInventory() ModelInventory

ModelInventory implements Backend.

func (*Base) SetModelInventory added in v0.11.3

func (b *Base) SetModelInventory(inventory ModelInventory)

SetModelInventory implements Backend.

func (*Base) SupportsCompact added in v0.6.0

func (b *Base) SupportsCompact() bool

SupportsCompact implements Backend.

func (*Base) SupportsImages added in v0.3.0

func (b *Base) SupportsImages() bool

SupportsImages implements Backend.

type CompactCommand added in v0.6.0

type CompactCommand interface {
	WriteCompact(w io.Writer, instructions string, log LogSink) error
}

CompactCommand is an optional interface for WireFormat implementations that support context compaction. The server checks for this capability to conditionally enable the compact button in the UI.

type Conn added in v0.7.0

type Conn interface {
	// SendPrompt writes a user message to the agent's stdin.
	SendPrompt(p Prompt) error
	// SendRaw writes pre-encoded NDJSON bytes to the agent's stdin.
	SendRaw(data []byte) error
	// SendCompact sends a compact/context-reduction command.
	SendCompact(instructions string) error
	// ReadMessages runs the message read loop: reads NDJSON lines from r,
	// parses them, writes raw lines to the log, and forwards parsed messages
	// to msgCh.
	ReadMessages(r io.Reader, msgCh chan<- ParsedMessage) error
	// SendStop sends the null-byte sentinel to trigger graceful agent shutdown.
	// Best-effort: returns when ctx is done if the write blocks.
	SendStop(ctx context.Context)
	// Close closes the stdin pipe.
	Close() error
}

Conn handles wire-format I/O for a single agent session. It is safe for concurrent use. Backends can wrap a Conn to intercept messages (e.g. injecting control commands after initialization).

func NewConn added in v0.7.0

func NewConn(ctx context.Context, log *slog.Logger, stdin io.WriteCloser, sink LogSink, wire WireFormat) Conn

NewConn creates a connection using the task log's physical record version. log and sink must be non-nil; use DiscardLogSink{Version: version} when persistence is unnecessary.

type DiffFileStat

type DiffFileStat struct {
	Path    string `json:"path"`
	Added   int    `json:"added"`
	Deleted int    `json:"deleted"`
	Binary  bool   `json:"binary,omitempty"`
}

DiffFileStat describes changes to a single file.

type DiffStat

type DiffStat []DiffFileStat

DiffStat summarises the changes in a branch relative to its base.

type DiffStatMessage

type DiffStatMessage struct {
	MessageType string   `json:"type"`
	DiffStat    DiffStat `json:"diff_stat"`
	Ts          float64  `json:"ts,omitempty"` // Unix epoch seconds (ms precision) when the relay emitted this record.
}

DiffStatMessage is emitted periodically by the relay's diff watcher thread with the current in-container git diff stats.

func (*DiffStatMessage) Type

func (m *DiffStatMessage) Type() string

Type implements Message.

type DiscardLogSink added in v0.11.5

type DiscardLogSink struct {
	Version LogVersion
}

DiscardLogSink ignores task-log records for non-persistent agent operations. Version must be set to the physical record version represented by the caller.

func (DiscardLogSink) AppendMessage added in v0.11.5

func (DiscardLogSink) AppendMessage(Message) error

AppendMessage discards one caic control record.

func (DiscardLogSink) AppendNative added in v0.11.5

func (DiscardLogSink) AppendNative([]byte) error

AppendNative discards one native physical record.

func (DiscardLogSink) Close added in v0.11.5

func (DiscardLogSink) Close() error

Close releases no resources.

func (DiscardLogSink) LogVersion added in v0.11.5

func (s DiscardLogSink) LogVersion() LogVersion

LogVersion returns the physical record version represented by the discarded records.

type ExitMessage added in v0.8.0

type ExitMessage struct {
	MessageType     string   `json:"type"`
	ExitCode        int      `json:"exit_code"`
	Command         []string `json:"cmd,omitempty"`
	Signal          int      `json:"signal,omitempty"`
	Error           string   `json:"error,omitempty"`
	StderrTruncated bool     `json:"stderr_truncated,omitempty"`
	Ts              float64  `json:"ts,omitempty"`
}

ExitMessage is written by the relay to output.jsonl when the agent subprocess exits, regardless of shutdown reason (crash, sentinel, EOF). It carries the exit code, command, signal, stderr, and timestamp so the backend can diagnose why a relay session ended without parsing relay.log.

func (*ExitMessage) ExitError added in v0.10.1

func (m *ExitMessage) ExitError() string

ExitError returns the user-facing diagnostic for a non-zero process exit.

func (*ExitMessage) Type added in v0.8.0

func (m *ExitMessage) Type() string

Type implements Message.

type FileChange added in v0.10.2

type FileChange struct {
	Path  string `json:"path"`
	Patch string `json:"patch"`
}

FileChange is one changed file rendered from a unified patch.

type HarnessArgs added in v0.9.1

type HarnessArgs struct {
	Model           string // Model name or alias; empty means use backend default.
	Effort          string // Thinking effort level (e.g. "low", "high"); empty means default.
	ResumeSessionID string // Agent session ID to resume; empty starts a new session.
}

HarnessArgs holds the session-specific parameters that influence the CLI arguments passed to an agent subprocess.

type HarnessCache added in v0.7.6

type HarnessCache struct {
	// contains filtered or unexported fields
}

HarnessCache is a thread-safe disk-backed cache for per-harness model inventories. The file is shared across harnesses; each harness owns its own key.

func OpenHarnessCache added in v0.7.6

func OpenHarnessCache(path string) *HarnessCache

OpenHarnessCache loads the cache from path. A missing or corrupt file starts with an empty cache — no error is returned.

func (*HarnessCache) ModelInventory added in v0.11.3

func (c *HarnessCache) ModelInventory(h harness.Name, envHash string) (inventory ModelInventory, fresh bool)

ModelInventory returns the cached inventory for h and whether it is fresh (updated within the last 24 h) and its API-key hash matches envHash. Invalid inventory entries are treated as unavailable.

func (*HarnessCache) SetModelInventory added in v0.11.3

func (c *HarnessCache) SetModelInventory(h harness.Name, inventory ModelInventory, envHash string)

SetModelInventory updates the cache for h and writes to disk atomically.

type HarnessCacheEntry added in v0.7.6

type HarnessCacheEntry struct {
	Inventory ModelInventory `json:"inventory"`
	Updated   time.Time      `json:"updated"`
	EnvHash   string         `json:"env_hash,omitempty"` // SHA-256 of *_API_KEY env vars from config.toml
}

HarnessCacheEntry holds cached data for a single harness.

type ImageData

type ImageData struct {
	MediaType string `json:"media_type"` // e.g. "image/png", "image/jpeg"
	Data      string `json:"data"`       // base64-encoded
}

ImageData carries a single base64-encoded image for multi-modal input.

type InitMessage added in v0.3.0

type InitMessage struct {
	SessionID string   `json:"session_id"`
	Cwd       string   `json:"cwd"`
	Tools     []string `json:"tools"`
	Model     string   `json:"model"`
	Version   string   `json:"claude_code_version"`
	Effort    string   `json:"effort,omitempty"` // Thinking effort (e.g. "low", "medium", "high", "max"). Empty when not supported.
}

InitMessage is emitted when a session starts.

func (*InitMessage) Type added in v0.3.0

func (m *InitMessage) Type() string

Type implements Message.

type LogMessage added in v0.3.0

type LogMessage struct {
	MessageType string `json:"type"`
	Line        string `json:"line"`
}

LogMessage is a provisioning/startup log line from the container backend.

func (*LogMessage) Type added in v0.3.0

func (m *LogMessage) Type() string

Type implements Message.

type LogRecordParser added in v0.11.3

type LogRecordParser struct {
	// contains filtered or unexported fields
}

LogRecordParser decodes versioned physical task-log records around one harness-native parser. A parser holds ordered log state and is not safe for concurrent use.

func NewLogRecordParser added in v0.11.3

func NewLogRecordParser(version LogVersion, parseNative func([]byte) ([]Message, error)) (*LogRecordParser, error)

NewLogRecordParser constructs a parser for an already-validated physical log version. parseNative is called synchronously and must parse and validate the supplied harness-native JSON before returning.

The callback input may alias scanner-owned record memory. parseNative must not retain or use the input after it returns.

func (*LogRecordParser) ParseRecord added in v0.11.3

func (p *LogRecordParser) ParseRecord(line []byte) (ParsedRecord, error)

ParseRecord decodes one physical task-log record according to the parser's exact version. Classification belongs to this parser so task-log consumers never duplicate or guess control vocabulary.

type LogSink added in v0.11.5

type LogSink interface {
	LogVersion() LogVersion
	AppendNative(data []byte) error
	AppendMessage(message Message) error
	Close() error
}

LogSink appends complete task-log records through the task-owned physical log authority. Native records are already encoded physical records; semantic messages are backend controls encoded according to the owned log version.

type LogVersion added in v0.11.3

type LogVersion int

LogVersion identifies a physical task-log format.

const (
	// LogVersionV1 is the legacy bare-harness task-log format.
	LogVersionV1 LogVersion = 1
	// LogVersionV2 is the caic-enveloped task-log format.
	LogVersionV2 LogVersion = 2
)

func (LogVersion) Validate added in v0.11.3

func (v LogVersion) Validate() error

Validate rejects unsupported task-log versions.

type Message

type Message interface {
	// Type returns the message type string.
	Type() string
}

Message is the interface for all agent streaming messages.

type MetaCacheMount added in v0.10.2

type MetaCacheMount struct {
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	HostPath    string `json:"hostPath,omitempty"`
	// ContainerPath is the resolved target path in the runtime container.
	ContainerPath string `json:"containerPath,omitempty"`
	ReadOnly      bool   `json:"readOnly,omitempty"`
	Shallow       bool   `json:"shallow,omitempty"`
}

MetaCacheMount describes one cache mount in a MetaMessage.

type MetaMessage

type MetaMessage struct {
	MessageType       string           `json:"type"`
	Version           int              `json:"version"`
	Prompt            string           `json:"prompt"`
	Title             string           `json:"title,omitempty"`
	Repos             []MetaRepo       `json:"repos"`
	Harness           harness.Name     `json:"harness"`
	Model             string           `json:"model,omitempty"`
	Effort            string           `json:"effort,omitempty"`
	StartedAt         time.Time        `json:"started_at"`
	ForgeIssue        int              `json:"forge_issue,omitempty"` // Originating issue/PR number for bot comment callbacks.
	ForkedFromTaskID  string           `json:"forked_from_task_id,omitempty"`
	Tailscale         bool             `json:"tailscale,omitempty"`
	USB               bool             `json:"usb,omitempty"`
	Display           bool             `json:"display,omitempty"`
	Sudo              bool             `json:"sudo,omitempty"`
	GitHubToken       bool             `json:"gitHubToken,omitempty"`
	RuntimeName       string           `json:"runtimeName,omitempty"`
	BaseImage         string           `json:"baseImage,omitempty"`
	ContainerPlatform string           `json:"containerPlatform,omitempty"`
	MaxCPUs           int              `json:"maxCPUs,omitempty"`
	CacheMounts       []MetaCacheMount `json:"cacheMounts,omitempty"`
	Mounts            []MetaMount      `json:"mounts,omitempty"`
}

MetaMessage is written as the first line of a JSONL log file. It captures task-level metadata so logs can be reloaded on restart.

func (*MetaMessage) Type

func (m *MetaMessage) Type() string

Type implements Message.

func (*MetaMessage) Validate

func (m *MetaMessage) Validate() error

Validate checks that all required fields are present and the version is supported.

type MetaMount added in v0.10.2

type MetaMount struct {
	HostPath string `json:"hostPath,omitempty"`
	// ContainerPath is the resolved target path in the runtime container.
	ContainerPath string `json:"containerPath,omitempty"`
	ReadOnly      bool   `json:"readOnly,omitempty"`
}

MetaMount describes one custom bind mount in a MetaMessage.

type MetaPRMessage added in v0.5.0

type MetaPRMessage struct {
	MessageType string `json:"type"`
	ForgeOwner  string `json:"forge_owner"`
	ForgeRepo   string `json:"forge_repo"`
	ForgePR     int    `json:"forge_pr"`
}

MetaPRMessage is written to the JSONL log when a PR is created so that the PR number can be restored on server restart.

func (*MetaPRMessage) Type added in v0.5.0

func (m *MetaPRMessage) Type() string

Type implements Message.

type MetaRepo added in v0.5.0

type MetaRepo struct {
	Name          string `json:"name"`
	BaseBranch    string `json:"base_branch,omitempty"`
	Branch        string `json:"branch"`
	ContainerPath string `json:"containerPath,omitempty"`
}

MetaRepo describes one repository entry in a MetaMessage.

type MetaResultMessage

type MetaResultMessage struct {
	MessageType              string   `json:"type"`
	State                    string   `json:"state"`
	Title                    string   `json:"title,omitempty"`
	CostUSD                  float64  `json:"cost_usd,omitempty"`
	Duration                 float64  `json:"duration,omitempty"` // Seconds.
	NumTurns                 int      `json:"num_turns,omitempty"`
	InputTokens              int      `json:"input_tokens,omitempty"`
	OutputTokens             int      `json:"output_tokens,omitempty"`
	CacheCreationInputTokens int      `json:"cache_creation_input_tokens,omitempty"`
	CacheReadInputTokens     int      `json:"cache_read_input_tokens,omitempty"`
	ReasoningOutputTokens    int      `json:"reasoning_output_tokens,omitempty"`
	DiffStat                 DiffStat `json:"diff_stat,omitzero"`
	Error                    string   `json:"error,omitempty"`
	AgentResult              string   `json:"agent_result,omitempty"`
}

MetaResultMessage is appended as the last line of a JSONL log file when a task reaches a terminal state.

func (*MetaResultMessage) Type

func (m *MetaResultMessage) Type() string

Type implements Message.

type MetaSessionMessage added in v0.9.2

type MetaSessionMessage struct {
	MessageType  string `json:"type"`
	SessionID    string `json:"session_id"`
	Model        string `json:"model,omitempty"`
	AgentVersion string `json:"agent_version,omitempty"`
}

MetaSessionMessage records the backend-native session identifier needed to resume a stateful harness after server restart.

func (*MetaSessionMessage) Type added in v0.9.2

func (m *MetaSessionMessage) Type() string

Type implements Message.

type Model added in v0.11.3

type Model struct {
	ID            string   `json:"id"`
	EffortOptions []string `json:"effortOptions"`
}

Model describes the configuration choices supported by one model. Values are protocol-agnostic strings because they are persisted in task preferences and sent back to each harness as user selections.

type ModelFetcher added in v0.9.2

type ModelFetcher interface {
	FetchModelInventory(ctx context.Context, target runtime.ConnectionTarget, env []string) (ModelInventory, error)
}

ModelFetcher is an optional backend capability for discovering a model inventory.

type ModelInfoMessage added in v0.11.5

type ModelInfoMessage struct {
	MessageType   string `json:"type"`
	ContextWindow int64  `json:"context_window"`
}

ModelInfoMessage records a harness-reported context window for replay.

func (*ModelInfoMessage) Type added in v0.11.5

func (m *ModelInfoMessage) Type() string

Type implements Message.

type ModelInventory added in v0.11.3

type ModelInventory struct {
	Models []Model `json:"models"`
}

ModelInventory is the immutable model and configuration data discovered for a harness.

func CachedModelInventory added in v0.11.3

func CachedModelInventory(cacheDir string, h harness.Name, envVars []string) ModelInventory

CachedModelInventory loads a harness inventory from cacheDir. An empty cacheDir returns an empty inventory.

func (ModelInventory) IDs added in v0.11.3

func (i ModelInventory) IDs() []string

IDs returns the model IDs in inventory order.

type Options

type Options struct {
	Logger          *slog.Logger // Non-nil session logger.
	Target          runtime.ConnectionTarget
	Dir             string // Working directory inside the runtime.
	Model           string // Model alias ("opus", "sonnet", "haiku", "fable") or full ID. Empty = default.
	Effort          string // Thinking effort (e.g. "low", "medium", "high", "max"). Empty = default.
	InitialPrompt   Prompt // Initial prompt; never mutated after creation.
	ResumeSessionID string
	RelayOffset     int64 // Byte offset into relay output.jsonl for AttachRelay.
	// PendingUserActions is the restored user-facing work that still needs
	// input after AttachRelay reconnects. It must not contain backend-only
	// protocol state such as keepalive, auto-allow, or environment control
	// messages.
	PendingUserActions []PendingUserAction
	MsgCh              chan<- ParsedMessage // Receives parsed physical records from the agent.
	Log                LogSink              // Non-nil task-owned physical task-log authority; use DiscardLogSink{Version: version} when persistence is unnecessary.
	StripEnv           []string             // Env var names for relay to strip from subprocess and emit as caic_stripped_env.
}

Options configures an agent session launch.

type ParseErrorMessage

type ParseErrorMessage struct {
	Err  string
	Line string
}

ParseErrorMessage is emitted when a backend output line cannot be decoded. It carries the error and the raw line for diagnostic display.

func (*ParseErrorMessage) Type

func (m *ParseErrorMessage) Type() string

Type implements Message.

type ParsedMessage added in v0.11.3

type ParsedMessage struct {
	Message      Message
	ProducerTime time.Time
}

ParsedMessage pairs a semantic message with its producer timestamp. A zero ProducerTime means the physical record did not provide producer time.

func ReadRelayTail added in v0.9.0

func ReadRelayTail(ctx context.Context, container string, parser *LogRecordParser, maxBytes int64) (msgs []ParsedMessage, size int64, err error)

ReadRelayTail reads only the tail of the relay output.jsonl from the container and returns the parsed messages plus the total file size (for RelayOffset). It streams the SSH output directly, so memory usage is O(1) and no multi-GB transfer occurs during runtime import.

type ParsedRecord added in v0.11.5

type ParsedRecord struct {
	Messages []ParsedMessage
	Control  bool
}

ParsedRecord is a parser-owned semantic task-log record. Control reports whether the version-specific discriminator identifies a caic-owned control.

type PendingAskAction added in v0.10.2

type PendingAskAction struct {
	Questions []AskQuestion `json:"questions,omitzero"`
}

PendingAskAction is the payload for PendingUserActionAskUserQuestion. It stores the rendered questions so reconnect can answer the original backend control request without replaying provider-specific raw JSON.

type PendingUserAction added in v0.10.2

type PendingUserAction struct {
	Kind PendingUserActionKind `json:"kind"`

	// RequestID is the backend request ID needed to complete the action.
	RequestID string `json:"request_id,omitempty"`

	// ToolUseID is the user-visible tool call that created the action.
	ToolUseID string `json:"tool_use_id,omitempty"`

	Ask PendingAskAction `json:"ask,omitzero"`
}

PendingUserAction records one user-facing action that must be completed before the agent can continue after a reconnect.

This is intentionally user-facing state, not a generic backend control protocol bucket. Permission auto-allow, keepalive, environment updates, and other backend-only control messages should not be represented here.

func ClonePendingUserAction added in v0.10.2

func ClonePendingUserAction(a PendingUserAction) PendingUserAction

ClonePendingUserAction returns a deep copy of a.

func ClonePendingUserActions added in v0.10.2

func ClonePendingUserActions(actions []PendingUserAction) []PendingUserAction

ClonePendingUserActions returns a deep copy of actions.

type PendingUserActionKind added in v0.10.2

type PendingUserActionKind string

PendingUserActionKind identifies the user action caic is waiting for.

const (
	// PendingUserActionAskUserQuestion means the agent invoked AskUserQuestion
	// and caic still needs the user's answer.
	PendingUserActionAskUserQuestion PendingUserActionKind = "ask_user_question"
)

type PendingUserActionMessage added in v0.10.2

type PendingUserActionMessage struct {
	MessageType string            `json:"type"`
	Action      PendingUserAction `json:"action"`
}

PendingUserActionMessage persists a PendingUserAction in task history. It is metadata for reconnect and should not be rendered as a chat message.

func (*PendingUserActionMessage) Type added in v0.10.2

func (m *PendingUserActionMessage) Type() string

Type implements Message.

type PrePromptWriter added in v0.9.1

type PrePromptWriter interface {
	WritePrePrompt(w io.Writer, model string, log LogSink) error
}

PrePromptWriter is implemented by backends that send initialization commands to stdin before the first user prompt (e.g. Pi's set_model).

type Prompt

type Prompt struct {
	Text   string      `json:"text"`
	Images []ImageData `json:"images,omitempty,omitzero"`
}

Prompt bundles user text with optional images for a single interaction.

type QuotaProvider added in v0.11.2

type QuotaProvider string

QuotaProvider identifies a monitored quota source. Add a value here when adding a provider fetcher or harness quota adapter so their identifiers stay coupled at compile time.

const (
	// QuotaProviderAnthropic identifies direct Anthropic API usage.
	QuotaProviderAnthropic QuotaProvider = "anthropic"
	// QuotaProviderClaudeCode identifies a Claude Code OAuth subscription.
	QuotaProviderClaudeCode QuotaProvider = "claudecode"
	// QuotaProviderCodex identifies Codex usage.
	QuotaProviderCodex QuotaProvider = "codex"
	// QuotaProviderDeepSeek identifies DeepSeek API usage.
	QuotaProviderDeepSeek QuotaProvider = "deepseek"
	// QuotaProviderOpenRouter identifies OpenRouter API usage.
	QuotaProviderOpenRouter QuotaProvider = "openrouter"
	// QuotaProviderXiaomi identifies Xiaomi MiMo API usage.
	QuotaProviderXiaomi QuotaProvider = "xiaomi"
)

func (QuotaProvider) Valid added in v0.11.2

func (p QuotaProvider) Valid() bool

Valid reports whether p is a supported quota provider.

type RateLimitMessage added in v0.5.5

type RateLimitMessage struct {
	Status          RateLimitStatus `json:"status"`            // "allowed", "allowed_warning", "rejected".
	ResetsAt        time.Time       `json:"resets_at"`         // When the quota window resets; zero if unknown.
	RateLimitType   string          `json:"rate_limit_type"`   // Harness-native window ID (for example, "five_hour"); use QuotaWindow for the canonical ID.
	Utilization     float64         `json:"utilization"`       // Fraction of the window used in [0, 1], not a percentage; 0 if unknown.
	IsUsingOverage  bool            `json:"is_using_overage"`  // True when extra/overage usage is active.
	OverageResetsAt time.Time       `json:"overage_resets_at"` // When overage resets; zero if unknown.
	QuotaProvider   QuotaProvider   `json:"quota_provider"`    // Canonical usage-provider ID that matches ProviderQuota.Provider; empty when the harness cannot identify it.
	QuotaLabel      string          `json:"quota_label"`       // Human-readable canonical provider label.
	QuotaWindow     string          `json:"quota_window"`      // Canonical provider window ID; empty when unknown.
}

RateLimitMessage is emitted when the CLI reports a rate limit status change.

func (*RateLimitMessage) Type added in v0.5.5

func (m *RateLimitMessage) Type() string

Type implements Message.

type RateLimitStatus added in v0.11.2

type RateLimitStatus string

RateLimitStatus describes whether a provider accepted or rejected a request for a quota window.

const (
	// RateLimitStatusAllowed means the provider accepted the request.
	RateLimitStatusAllowed RateLimitStatus = "allowed"
	// RateLimitStatusAllowedWarning means the provider accepted the request and warned of high usage.
	RateLimitStatusAllowedWarning RateLimitStatus = "allowed_warning"
	// RateLimitStatusRejected means the provider rejected the request for quota exhaustion.
	RateLimitStatusRejected RateLimitStatus = "rejected"
)

func (RateLimitStatus) Valid added in v0.11.2

func (s RateLimitStatus) Valid() bool

Valid reports whether s is a supported rate-limit status.

type RawMessage

type RawMessage struct {
	MessageType string
	Raw         []byte
}

RawMessage is a pass-through for message types we don't need to inspect (tool_progress, etc.).

func (*RawMessage) Type

func (m *RawMessage) Type() string

Type implements Message.

type RecordHandshaker added in v0.9.1

type RecordHandshaker interface {
	RecordHandshake(ctx context.Context, stdin io.Writer, stdout io.Reader, model string) (WireFormat, io.Reader, error)
}

RecordHandshaker is implemented by backends that perform a bidirectional handshake over stdin/stdout before writing prompts (e.g. ACP-based agents like OpenCode). The returned io.Reader replaces the original stdout for subsequent reads (it may be a buffered reader that consumed bytes beyond the handshake response).

type RelayProcess added in v0.7.0

type RelayProcess struct {
	Cmd    *exec.Cmd
	Stdin  io.WriteCloser
	Stdout io.Reader
}

RelayProcess holds the started relay SSH command and its I/O pipes.

func PrepareRelay added in v0.7.0

func PrepareRelay(ctx context.Context, opts *Options, agentArgs []string) (*RelayProcess, error)

PrepareRelay deploys the relay script and starts the SSH serve-attach process. The caller creates a Conn and Session from the returned process.

type RelayRecordReader added in v0.11.5

type RelayRecordReader struct {
	// contains filtered or unexported fields
}

RelayRecordReader reads one physical relay record at a time. Agent payloads are returned as their unchanged native JSON; caic controls are returned only as parsed controls and never presented as native handshake data. logW is the caller's explicit persistence policy: use io.Discard for unpersisted reads.

func NewRelayRecordReader added in v0.11.5

func NewRelayRecordReader(r io.Reader, version LogVersion, log LogSink) (*RelayRecordReader, error)

NewRelayRecordReader creates a version-aware physical relay reader. version must be the caller-validated task-log version. log must be non-nil; use DiscardLogSink{Version: version} when persistence is unnecessary.

func (*RelayRecordReader) ReadRecord added in v0.11.5

func (r *RelayRecordReader) ReadRecord() (native []byte, controls []ParsedMessage, err error)

ReadRecord reads the next non-empty physical relay record. It persists the original encoded bytes once according to the reader's policy before strict parsing. Native is non-nil only for an agent payload; controls are separate.

func (*RelayRecordReader) Reader added in v0.11.5

func (r *RelayRecordReader) Reader() *bufio.Reader

Reader returns the buffered source positioned after records consumed by ReadRecord.

type ResultMessage

type ResultMessage struct {
	MessageType   string   `json:"type"`
	Subtype       string   `json:"subtype"`
	IsError       bool     `json:"is_error"`
	DurationMs    int64    `json:"duration_ms"`
	DurationAPIMs int64    `json:"duration_api_ms"`
	NumTurns      int      `json:"num_turns"`
	Result        string   `json:"result"`
	SessionID     string   `json:"session_id"`
	TotalCostUSD  float64  `json:"total_cost_usd"`
	Usage         Usage    `json:"usage"`
	UUID          string   `json:"uuid"`
	DiffStat      DiffStat `json:"diff_stat,omitzero"` // Set by caic after running container diff.
}

ResultMessage is the terminal message for a query.

func (*ResultMessage) Type

func (m *ResultMessage) Type() string

Type implements Message.

type Session

type Session struct {
	Conn
	// contains filtered or unexported fields
}

Session manages a running agent process. It embeds Conn for wire I/O.

func AttachRelaySession added in v0.3.0

func AttachRelaySession(ctx context.Context, opts *Options, wire WireFormat, wrap func(Conn) (Conn, error)) (*Session, error)

AttachRelaySession connects to an already-running relay in the container and returns a new Session. It waits briefly for the attach process to confirm connectivity; if the process exits immediately (e.g. relay socket is stale), an error is returned so the caller can fall back to --resume. Backends may pass wrap to intercept the default Conn before message reading starts.

func NewSession

func NewSession(ctx context.Context, cmd *exec.Cmd, c Conn, stdout io.Reader, msgCh chan<- ParsedMessage, log *slog.Logger) *Session

NewSession creates a Session from an already-started command. Messages read from stdout are parsed and forwarded to msgCh through the Conn's ReadMessages method.

A background goroutine reads stdout until EOF, then waits for the process to exit. The done channel is closed when both are complete. Callers should use Done() to detect session end and Wait() to retrieve the error.

Error priority: parse errors take precedence over wait errors, since a parse error indicates corrupted output while the process may still exit 0.

func StartRelay added in v0.3.0

func StartRelay(ctx context.Context, opts *Options, agentArgs []string, wire WireFormat) (*Session, error)

StartRelay is a convenience that calls PrepareRelay, creates a default Conn, and sends the initial prompt.

func StartSession added in v0.7.0

func StartSession(ctx context.Context, rp *RelayProcess, c Conn, opts *Options) (*Session, error)

StartSession creates a Session from a RelayProcess and Conn, sends the initial prompt if present, and returns the session.

func (*Session) Done

func (s *Session) Done() <-chan struct{}

Done returns a channel that is closed when the agent process exits.

func (*Session) Stop added in v0.7.0

func (s *Session) Stop(ctx context.Context) error

Stop sends the null-byte sentinel, closes stdin, and waits for the agent process to exit or the context to expire. Returns nil on clean exit, the process exit error on abnormal exit, or the context error on timeout.

Closing stdin after the sentinel is critical: the attach_client's main thread is blocked on stdin.read1(). Without the close, attach_client never exits, SSH never exits, and cmd.Wait() never returns — deadlocking Stop.

The sentinel must be written explicitly rather than inferred from stdin EOF in the attach client, because EOF also occurs on SSH drops and backend restarts where the container should keep running.

func (*Session) Wait

func (s *Session) Wait() error

Wait blocks until the agent process exits.

type SlogWriter added in v0.3.0

type SlogWriter struct {
	Context   context.Context
	Logger    *slog.Logger
	Prefix    string
	Container string
	// contains filtered or unexported fields
}

SlogWriter is an io.Writer that logs each line via slog.Warn. It is used as cmd.Stderr for SSH relay subprocesses across all backends.

func (*SlogWriter) Write added in v0.3.0

func (w *SlogWriter) Write(p []byte) (int, error)

type StrippedEnvMessage added in v0.7.0

type StrippedEnvMessage struct {
	MessageType string            `json:"type"`
	Variables   map[string]string `json:"variables"`
}

StrippedEnvMessage is emitted by the relay when it strips environment variables (e.g. ANTHROPIC_API_KEY) before spawning the agent subprocess. The backend uses these values to re-inject them after auth completes.

func (*StrippedEnvMessage) Type added in v0.7.0

func (m *StrippedEnvMessage) Type() string

Type implements Message.

type SubagentEndMessage added in v0.3.0

type SubagentEndMessage struct {
	TaskID string `json:"task_id"`
	Status string `json:"status"` // "completed", "failed", "stopped"
}

SubagentEndMessage is emitted when a subagent task completes, fails, or stops.

func (*SubagentEndMessage) Type added in v0.3.0

func (m *SubagentEndMessage) Type() string

Type implements Message.

type SubagentSpawn added in v0.10.2

type SubagentSpawn struct {
	Agent string `json:"agent"`
	Task  string `json:"task"`
	Label string `json:"label,omitempty"`
	Phase string `json:"phase,omitempty"`
}

SubagentSpawn is one backend-normalized subagent invocation.

type SubagentStartMessage added in v0.3.0

type SubagentStartMessage struct {
	TaskID      string `json:"task_id"`
	Description string `json:"description"`
}

SubagentStartMessage is emitted when a subagent task begins.

func (*SubagentStartMessage) Type added in v0.3.0

func (m *SubagentStartMessage) Type() string

Type implements Message.

type SystemMessage

type SystemMessage struct {
	MessageType string `json:"type"`
	Subtype     string `json:"subtype"`
	SessionID   string `json:"session_id"`
	UUID        string `json:"uuid"`
	Detail      string `json:"detail,omitempty"` // Optional human-readable detail (e.g. model names for model_rerouted).
	Model       string `json:"model,omitempty"`  // Active model after model_rerouted; used to update task.reportedModel.
}

SystemMessage is a generic system message (status, compact_boundary, etc.).

func ContextCleared added in v0.11.6

func ContextCleared() *SystemMessage

ContextCleared creates the persisted context-clear system marker.

func (*SystemMessage) Type

func (m *SystemMessage) Type() string

Type implements Message.

type TextDeltaMessage added in v0.3.0

type TextDeltaMessage struct {
	Text string
}

TextDeltaMessage is a streaming text fragment, emitted when --include-partial-messages is enabled. Extracted from the nested wire format (stream_event → content_block_delta → text_delta) during parsing.

func (*TextDeltaMessage) Type added in v0.3.0

func (m *TextDeltaMessage) Type() string

Type implements Message.

type TextMessage added in v0.3.0

type TextMessage struct {
	Text  string `json:"text"`
	Phase string `json:"phase,omitempty"` // Codex only: "commentary" | "final_answer" | "".
}

TextMessage is emitted when the agent produces text output.

func (*TextMessage) Type added in v0.3.0

func (m *TextMessage) Type() string

Type implements Message.

type TextReplacement added in v0.10.2

type TextReplacement struct {
	OldText string
	NewText string
}

TextReplacement is one exact text replacement reported by an edit tool.

type ThinkingDeltaMessage added in v0.3.0

type ThinkingDeltaMessage struct {
	Text string
}

ThinkingDeltaMessage is a streaming thinking fragment.

func (*ThinkingDeltaMessage) Type added in v0.3.0

func (m *ThinkingDeltaMessage) Type() string

Type implements Message.

type ThinkingMessage added in v0.3.0

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

ThinkingMessage is emitted when the agent produces a thinking block.

func (*ThinkingMessage) Type added in v0.3.0

func (m *ThinkingMessage) Type() string

Type implements Message.

type TodoItem added in v0.3.0

type TodoItem struct {
	Content    string `json:"content"`
	Status     string `json:"status"` // "pending", "in_progress", "completed".
	ActiveForm string `json:"activeForm,omitempty"`
}

TodoItem is a single todo entry from a TodoWrite tool call.

type TodoMessage added in v0.3.0

type TodoMessage struct {
	ToolUseID string     `json:"id"`
	Todos     []TodoItem `json:"todos"`
}

TodoMessage is emitted when the agent updates its todo list via the TodoWrite tool.

func (*TodoMessage) Type added in v0.3.0

func (m *TodoMessage) Type() string

Type implements Message.

type ToolInputView added in v0.10.2

type ToolInputView struct {
	Kind      ToolInputViewKind `json:"kind"`
	Files     []FileChange      `json:"files,omitzero"`
	Subagents []SubagentSpawn   `json:"subagents,omitzero"`
}

ToolInputView is a backend-normalized rendering model for known tool inputs.

func FileChangesInputView added in v0.10.2

func FileChangesInputView(files []FileChange) ToolInputView

FileChangesInputView returns a normalized file-change rendering model.

func FileChangesInputViewFromReplacements added in v0.10.2

func FileChangesInputViewFromReplacements(path string, replacements []TextReplacement) ToolInputView

FileChangesInputViewFromReplacements converts exact replacements to a synthetic unified patch so every edit-like tool uses the same display model.

type ToolInputViewKind added in v0.10.2

type ToolInputViewKind string

ToolInputViewKind identifies a normalized tool input view.

const (
	// ToolInputFileChanges renders changed files as unified patches.
	ToolInputFileChanges ToolInputViewKind = "fileChanges"
	// ToolInputSubagents renders one or more spawned subagents.
	ToolInputSubagents ToolInputViewKind = "subagents"
)

type ToolOutputDeltaMessage added in v0.5.0

type ToolOutputDeltaMessage struct {
	ToolUseID string
	Delta     string
}

ToolOutputDeltaMessage is a streaming output fragment from a tool execution. Codex only: emitted via item/commandExecution/outputDelta (Bash stdout) and item/mcpToolCall/progress (MCP tool progress messages).

func (*ToolOutputDeltaMessage) Type added in v0.5.0

func (m *ToolOutputDeltaMessage) Type() string

Type implements Message.

type ToolResultMessage added in v0.3.0

type ToolResultMessage struct {
	ToolUseID string `json:"tool_use_id"`
	Error     string `json:"error,omitempty"` // Non-empty when the tool reported an error.
}

ToolResultMessage is emitted when a tool returns its result.

func (*ToolResultMessage) Type added in v0.3.0

func (m *ToolResultMessage) Type() string

Type implements Message.

type ToolUseMessage added in v0.3.0

type ToolUseMessage struct {
	ToolUseID   string          `json:"id"`
	Name        string          `json:"name"`
	Input       json.RawMessage `json:"input,omitempty"`
	Detail      string          `json:"detail,omitempty"` // Backend-normalized short display detail for tool headers.
	InputView   ToolInputView   `json:"input_view,omitzero"`
	PlanContent string          `json:"-"` // Snapshot of plan content; set by task on ExitPlanMode.
}

ToolUseMessage is emitted when the agent invokes a tool (except AskUserQuestion and TodoWrite which have their own types).

func (*ToolUseMessage) Type added in v0.3.0

func (m *ToolUseMessage) Type() string

Type implements Message.

type Usage

type Usage struct {
	InputTokens              int `json:"input_tokens"`
	OutputTokens             int `json:"output_tokens"`
	CacheCreationInputTokens int `json:"cache_creation_input_tokens"`
	CacheReadInputTokens     int `json:"cache_read_input_tokens"`
	ReasoningOutputTokens    int `json:"reasoning_output_tokens,omitempty"`
	CacheTTLSeconds          int `json:"cache_ttl_seconds,omitempty"` // Effective cache TTL from last API call; 0 = unknown.
}

Usage tracks per-API-call token consumption as reported by the Anthropic API.

The three input token fields are disjoint; total input context for one call equals InputTokens + CacheCreationInputTokens + CacheReadInputTokens. InputTokens is only the small non-cached, non-cache-creation portion (typically single-digit). The bulk of the input context lands in cache fields.

In ResultMessage these values are per-query (sum of all API calls in the turn). Task.liveUsage sums them across all queries for cumulative totals.

ReasoningOutputTokens is a subset of OutputTokens used for extended thinking (Claude) or reasoning summaries (Codex). Zero when the harness does not report it.

type UsageMessage added in v0.3.0

type UsageMessage struct {
	Usage         Usage  `json:"usage"`
	Model         string `json:"model,omitempty"`
	ContextWindow int    `json:"context_window,omitempty"` // Non-zero when the backend reports the active context window size.
}

UsageMessage reports token consumption for a single API call.

func (*UsageMessage) Type added in v0.3.0

func (m *UsageMessage) Type() string

Type implements Message.

type UserInputMessage added in v0.3.0

type UserInputMessage struct {
	Text   string      `json:"text,omitempty"`
	Images []ImageData `json:"images,omitempty"`
}

UserInputMessage represents direct user text/image input (not a tool result).

func (*UserInputMessage) Type added in v0.3.0

func (m *UserInputMessage) Type() string

Type implements Message.

type WidgetDeltaMessage added in v0.5.1

type WidgetDeltaMessage struct {
	ToolUseID string
	Delta     string // Partial HTML fragment.
}

WidgetDeltaMessage is a streaming fragment of widget HTML, emitted as the agent generates the widget code. Clients accumulate deltas for progressive rendering; the final WidgetMessage replaces them.

func (*WidgetDeltaMessage) Type added in v0.5.1

func (m *WidgetDeltaMessage) Type() string

Type implements Message.

type WidgetMessage added in v0.5.1

type WidgetMessage struct {
	ToolUseID string `json:"id"`
	Title     string `json:"title"`
	HTML      string `json:"html"`
}

WidgetMessage is emitted when the agent produces an interactive HTML widget via a tool call (e.g. Claude's show_widget). The HTML is the complete, renderable widget code.

func NewWidgetMessage added in v0.5.2

func NewWidgetMessage(toolUseID string, input json.RawMessage) *WidgetMessage

NewWidgetMessage creates a WidgetMessage from raw tool input JSON. It extracts the title and widget_code fields and enforces MaxWidgetHTMLBytes. Shared by all backend parsers.

func (*WidgetMessage) Type added in v0.5.1

func (m *WidgetMessage) Type() string

Type implements Message.

type WireFormat

type WireFormat interface {
	// WritePrompt writes a user prompt to the agent's stdin in the
	// backend's wire format. logW receives a copy.
	WritePrompt(w io.Writer, p Prompt, log LogSink) error

	// ParseMessage decodes a single NDJSON line into one or more typed
	// Messages. A single wire line may produce multiple semantic messages.
	ParseMessage(line []byte) ([]Message, error)
}

WireFormat defines the wire protocol for a backend's stdin/stdout communication. Implementations must pair WritePrompt and ParseMessage for the same protocol.

Directories

Path Synopsis
Package agenttest provides shared test helpers for agent harness golden-file tests.
Package agenttest provides shared test helpers for agent harness golden-file tests.
Package backends constructs configured agent backend sets.
Package backends constructs configured agent backend sets.
Package claudecode implements agent.Backend for Claude Code.
Package claudecode implements agent.Backend for Claude Code.
Package codex implements agent.Backend for Codex CLI.
Package codex implements agent.Backend for Codex CLI.
Package harness defines coding agent harness identifiers shared across backend domains.
Package harness defines coding agent harness identifiers shared across backend domains.
Package opencode implements agent.Backend for OpenCode via ACP (Agent Client Protocol): JSON-RPC 2.0 over stdin/stdout.
Package opencode implements agent.Backend for OpenCode via ACP (Agent Client Protocol): JSON-RPC 2.0 over stdin/stdout.
Package pi implements agent.Backend for Pi coding agent CLI in RPC mode.
Package pi implements agent.Backend for Pi coding agent CLI in RPC mode.
Package relay embeds the version-specific Python relay scripts used inside containers.
Package relay embeds the version-specific Python relay scripts used inside containers.

Jump to

Keyboard shortcuts

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