appserver

package
v1.1.2 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package appserver is a typed client for the codex app-server JSON-RPC protocol over stdio. It is the backing transport used by codex adapter runs whose resolved driver.Request selects provider-native streaming.

The package is organised into five files:

  • generate.go / generated.go — schema-derived flat notification types. Generated from schema/{v1,v2}/*.json via go:generate; do not edit by hand.
  • union.go — hand-written discriminated unions that go-jsonschema cannot express (ThreadItem, UserInput, SandboxPolicy, CommandAction, WebSearchAction, and the envelope Params/Response types we call directly).
  • codec.go — stdioStream, a minimal jsonrpc2.ObjectStream adapter that bridges a subprocess's stdin (io.WriteCloser) and stdout (io.Reader) into the format sourcegraph/jsonrpc2 expects. It does not mutate frames; sourcegraph/jsonrpc2 already tolerates missing "jsonrpc":"2.0" markers.
  • client.go — sourcegraph/jsonrpc2.Conn wrapper with typed method helpers for Initialize, ThreadStart, ThreadResume, TurnStart, TurnInterrupt, and notification subscription. Chosen over creachadair/jrpc2 because its Handler is dispatched synchronously and preserves wire order of notifications.
  • run.go — driver-facing entry point that owns the codex app-server subprocess lifecycle for a single Run.
  • translate.go — notification → StreamPayload mapping.

Protocol upgrades follow the generation procedure in generate.go.

Index

Constants

View Source
const (
	// MethodInitialize performs the JSON-RPC initialize handshake.
	MethodInitialize = "initialize"
	// MethodInitialized notifies the server that the client is ready.
	MethodInitialized = "initialized"
	// MethodThreadStart starts a new codex thread.
	MethodThreadStart = "thread/start"
	// MethodThreadResume resumes an existing codex thread.
	MethodThreadResume = "thread/resume"
	// MethodThreadFork creates a child thread without mutating its parent.
	MethodThreadFork = "thread/fork"
	// MethodTurnStart starts one turn inside a thread.
	MethodTurnStart = "turn/start"
	// MethodTurnInterrupt interrupts an in-flight turn.
	MethodTurnInterrupt = "turn/interrupt"

	// NotifyThreadStarted reports that a thread was created/resumed.
	NotifyThreadStarted = "thread/started"
	// NotifyThreadStatusChanged reports thread status transitions.
	NotifyThreadStatusChanged = "thread/status/changed"
	// NotifyThreadTokenUsageUpdated reports cumulative token usage.
	NotifyThreadTokenUsageUpdated = "thread/tokenUsage/updated"
	// NotifyTurnStarted reports that a turn began.
	NotifyTurnStarted = "turn/started"
	// NotifyTurnCompleted reports normal turn completion.
	NotifyTurnCompleted = "turn/completed"
	// NotifyItemStarted reports the start of a thread item lifecycle.
	NotifyItemStarted = "item/started"
	// NotifyItemCompleted reports the end of a thread item lifecycle.
	NotifyItemCompleted = "item/completed"
	// NotifyItemAgentMessageDelta carries assistant text deltas.
	NotifyItemAgentMessageDelta = "item/agentMessage/delta"
	// NotifyItemReasoningTextDelta carries reasoning text deltas.
	NotifyItemReasoningTextDelta = "item/reasoning/textDelta"
	// NotifyItemReasoningSummaryTextDelta carries reasoning-summary deltas.
	NotifyItemReasoningSummaryTextDelta = "item/reasoning/summaryTextDelta"
	// NotifyItemReasoningSummaryPartAdded reports a new reasoning-summary part.
	NotifyItemReasoningSummaryPartAdded = "item/reasoning/summaryPartAdded"
	// NotifyItemCommandExecutionOutputDelta carries command output deltas.
	NotifyItemCommandExecutionOutputDelta = "item/commandExecution/outputDelta"
	// NotifyCommandExecOutputDelta carries command output deltas emitted under
	// the alternate app-server notification name.
	NotifyCommandExecOutputDelta = "command/exec/outputDelta"
	// NotifyItemFileChangeOutputDelta carries file-change output deltas.
	NotifyItemFileChangeOutputDelta = "item/fileChange/outputDelta"
	// NotifyItemPlanDelta carries plan text deltas.
	NotifyItemPlanDelta = "item/plan/delta"
	// NotifyError carries a server-side error notification.
	NotifyError = "error"
)

Method names for ClientRequest and notifications. Only the subset the codex adapter actually uses is listed; unknown notifications still reach the subscriber map as raw payloads so translate.go can forward them through StreamPayload.Raw.

Variables

This section is empty.

Functions

func IsDisconnected

func IsDisconnected(err error) bool

IsDisconnected reports whether err indicates the underlying connection has been closed. Exposed for callers that want to distinguish a clean shutdown from an RPC-level failure.

func Run

func Run(ctx context.Context, opts Options, sink driver.EventSink) (driver.Response, error)

Run spawns a codex app-server subprocess, completes the initialize / thread / turn handshake, forwards every relevant notification into the supplied sink as a StreamPayload, and returns the accumulated driver.Response once the turn completes.

The returned driver.Response satisfies the Driver SPI output contract: codex/driver.go (Output, Transcript, ExitCode, Usage, Checkpoint, and RawStreams when available). Errors from the subprocess or JSON-RPC transport are propagated; if the turn itself fails, the error is surfaced inside driver.Response.Failure rather than as a returned error.

Types

type AgentMessageDeltaNotification

type AgentMessageDeltaNotification struct {
	// Delta corresponds to the JSON schema field "delta".
	Delta string `json:"delta"`

	// ItemID corresponds to the JSON schema field "itemId".
	ItemID string `json:"itemId"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

type Client

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

Client is a thin, strongly-typed wrapper around sourcegraph/jsonrpc2.Conn. It hides the minimal JSON-RPC plumbing adapters should never need to re-implement.

Why sourcegraph/jsonrpc2 rather than creachadair/jrpc2:

  • Handler.Handle is called synchronously per inbound frame, giving us a hard FIFO ordering contract without any extra wrapping. jrpc2 spawned a goroutine per notification and serialized them behind a sync.Mutex, whose non-FIFO wake order reordered codex token deltas in practice.
  • No "jsonrpc":"2.0" strictness — codex app-server omits the marker on many frames, so no tolerant codec is needed.

func NewClient

func NewClient(ctx context.Context, stream jsonrpc2.ObjectStream) *Client

NewClient takes ownership of the ObjectStream and spins up the JSON-RPC dispatcher goroutine. The caller is responsible for producing the stream (usually by spawning `codex app-server --listen stdio://` and handing over its stdio).

func (*Client) Close

func (c *Client) Close() error

Close tears down the client. It is safe to call multiple times.

func (*Client) DisconnectNotify

func (c *Client) DisconnectNotify() <-chan struct{}

DisconnectNotify is closed after the JSON-RPC reader reaches EOF or a protocol/transport error. Waiting for it before snapshotting captured stdout guarantees the reader has consumed every available inbound byte.

func (*Client) Initialize

func (c *Client) Initialize(ctx context.Context, params InitializeParams) (*InitializeResponse, error)

Initialize performs the "initialize" handshake.

func (*Client) NotifyInitialized

func (c *Client) NotifyInitialized(ctx context.Context) error

NotifyInitialized sends the "initialized" notification that completes the handshake.

func (*Client) SetNotificationHandler

func (c *Client) SetNotificationHandler(h NotificationHandler)

SetNotificationHandler registers the single handler that receives all server-initiated notifications. Calling it more than once replaces the previous handler. A nil handler disables delivery without failing.

func (*Client) ThreadFork

func (c *Client) ThreadFork(ctx context.Context, params ThreadForkParams) (*ThreadForkResponse, error)

ThreadFork creates a new child thread from an existing parent thread id.

func (*Client) ThreadResume

func (c *Client) ThreadResume(ctx context.Context, params ThreadResumeParams) (*ThreadResumeResponse, error)

ThreadResume resumes an existing thread by id.

func (*Client) ThreadStart

func (c *Client) ThreadStart(ctx context.Context, params ThreadStartParams) (*ThreadStartResponse, error)

ThreadStart creates a new thread.

func (*Client) TurnInterrupt

func (c *Client) TurnInterrupt(ctx context.Context, params TurnInterruptParams) error

TurnInterrupt cancels an in-flight turn.

func (*Client) TurnStart

func (c *Client) TurnStart(ctx context.Context, params TurnStartParams) (*TurnStartResponse, error)

TurnStart kicks off a new turn on the given thread and returns once the server has acknowledged the request (not once the turn completes).

type ClientInfo

type ClientInfo struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

ClientInfo identifies the calling application during initialize.

type CodexErrorInfo

type CodexErrorInfo interface{}

This translation layer make sure that we expose codex error code in camel case.

When an upstream HTTP status is available (for example, from the Responses API or a provider), it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.

type CommandExecOutputDeltaNotification

type CommandExecOutputDeltaNotification struct {
	// `true` on the final streamed chunk for a stream when `outputBytesCap` truncated
	// later output on that stream.
	CapReached bool `json:"capReached"`

	// Base64-encoded output bytes.
	DeltaBase64 string `json:"deltaBase64"`

	// Client-supplied, connection-scoped `processId` from the original `command/exec`
	// request.
	ProcessID string `json:"processId"`

	// Output stream for this chunk.
	Stream interface{} `json:"stream"`
}

Base64-encoded output chunk emitted for a streaming `command/exec` request.

These notifications are connection-scoped. If the originating connection closes, the server terminates the process.

type CommandExecOutputStream

type CommandExecOutputStream interface{}

Stream label for `command/exec/outputDelta` notifications.

type CommandExecutionOutputDeltaNotification

type CommandExecutionOutputDeltaNotification struct {
	// Delta corresponds to the JSON schema field "delta".
	Delta string `json:"delta"`

	// ItemID corresponds to the JSON schema field "itemId".
	ItemID string `json:"itemId"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

type ErrorNotification

type ErrorNotification struct {
	// Error corresponds to the JSON schema field "error".
	Error TurnError `json:"error"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`

	// WillRetry corresponds to the JSON schema field "willRetry".
	WillRetry bool `json:"willRetry"`
}

type FileChange

type FileChange struct {
	Path string          `json:"path"`
	Diff string          `json:"diff"`
	Kind json.RawMessage `json:"kind,omitempty"`
}

FileChange is a single entry in a fileChange item.

type FileChangeOutputDeltaNotification

type FileChangeOutputDeltaNotification struct {
	// Delta corresponds to the JSON schema field "delta".
	Delta string `json:"delta"`

	// ItemID corresponds to the JSON schema field "itemId".
	ItemID string `json:"itemId"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

type InitializeParams

type InitializeParams struct {
	ClientInfo   ClientInfo      `json:"clientInfo"`
	Capabilities json.RawMessage `json:"capabilities,omitempty"`
}

InitializeParams is the payload for the "initialize" request.

type InitializeResponse

type InitializeResponse struct {
	UserAgent      string          `json:"userAgent,omitempty"`
	CodexHome      string          `json:"codexHome,omitempty"`
	PlatformFamily string          `json:"platformFamily,omitempty"`
	PlatformOs     string          `json:"platformOs,omitempty"`
	Extras         json.RawMessage `json:"-"`
}

InitializeResponse is the server's initialize reply. codex-cli 0.120.0 returns opaque diagnostic metadata; we keep it as RawMessage because no current codex adapter code path inspects individual fields.

type ItemCompletedNotificationBody

type ItemCompletedNotificationBody struct {
	ThreadID string          `json:"threadId"`
	TurnID   string          `json:"turnId"`
	Item     json.RawMessage `json:"item"`
}

ItemCompletedNotificationBody is the adapter's view of "item/completed".

type ItemStartedNotificationBody

type ItemStartedNotificationBody struct {
	ThreadID string          `json:"threadId"`
	TurnID   string          `json:"turnId"`
	Item     json.RawMessage `json:"item"`
}

ItemStartedNotificationBody is the adapter's view of "item/started". The item field is a discriminated union decoded via DecodeThreadItem.

type NonSteerableTurnKind

type NonSteerableTurnKind string
const NonSteerableTurnKindCompact NonSteerableTurnKind = "compact"
const NonSteerableTurnKindReview NonSteerableTurnKind = "review"

type NotificationHandler

type NotificationHandler func(method string, params json.RawMessage)

NotificationHandler receives one decoded server notification. The raw JSON params are provided so handlers can decode into whatever typed shape they need (see translate.go).

Ordering contract: the underlying sourcegraph/jsonrpc2 dispatcher invokes Handler.Handle synchronously — each call must return before the next wire frame is dispatched — so this handler sees every notification in strict wire order. Keep the function inexpensive; any heavy work should be queued elsewhere. Blocking here is what preserves the order guarantee downstream.

type Options

type Options struct {
	// Command is the codex binary; defaults to "codex".
	Command string
	// Args appended after "app-server --listen stdio://"; typically empty.
	ExtraArgs []string
	// CWD where the subprocess is launched. Empty means inherit.
	CWD string
	// Env is the environment set for the subprocess, using EnvBinding
	// semantics identical to codex exec runs.
	Env []driver.EnvBinding

	// ClientName and ClientVersion identify the caller in the initialize
	// handshake. Codex surfaces these in its diagnostic logs.
	ClientName    string
	ClientVersion string

	// Prompt is the user input for the single turn.
	Prompt string

	// Thread controls whether this run starts, resumes, or forks a thread.
	// ResumeThreadID and ForkThreadID are mutually exclusive. A fork returns a
	// checkpoint for the newly created child and never runs a turn on the parent.
	ResumeThreadID string
	ForkThreadID   string
	Ephemeral      bool

	// Sandbox / Approval / Model overrides.
	Sandbox  string // "read-only" | "workspace-write" | "danger-full-access"
	Approval string // passed to TurnStartParams.ApprovalPolicy
	Model    string
	Effort   string
	// ServiceTier is the official app-server service tier override (for
	// example, "fast").
	ServiceTier string
	// OutputSchema is forwarded to turn/start and validated before the final
	// public lifecycle event when native structured output is selected.
	OutputSchema *driver.OutputSchema

	// RunID identifies the run for StreamPayload attribution.
	RunID string
}

Options bundles the driver-provided inputs for a single run of the codex app-server. The caller (codex/driver.go) populates it from driver.Request and its package-owned codex.Config.

type PlanDeltaNotification

type PlanDeltaNotification struct {
	// Delta corresponds to the JSON schema field "delta".
	Delta string `json:"delta"`

	// ItemID corresponds to the JSON schema field "itemId".
	ItemID string `json:"itemId"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

EXPERIMENTAL - proposed plan streaming deltas for plan items. Clients should not assume concatenated deltas match the completed plan item content.

type Process

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

Process owns one initialized app-server connection and one loaded Codex thread. Callers must serialize RunTurn calls; Process also enforces that rule so an accidental second writer cannot interleave JSON-RPC turns.

func Open

func Open(ctx context.Context, opts Options, sink driver.EventSink) (*Process, error)

Open spawns and initializes an app-server and starts or resumes one thread, but deliberately sends no user prompt. The returned Process can therefore be pre-warmed without risking duplicate model/tool side effects.

func (*Process) CloseGracefully

func (p *Process) CloseGracefully(ctx context.Context, grace time.Duration) error

CloseGracefully closes stdin, then force-terminates after grace or ctx.

func (*Process) Done

func (p *Process) Done() <-chan struct{}

Done closes after the subprocess has exited and stderr has been drained.

func (*Process) IsClosed

func (p *Process) IsClosed() bool

IsClosed reports whether shutdown has started or the peer disconnected.

func (*Process) RunTurn

func (p *Process) RunTurn(ctx context.Context, opts Options, sink driver.EventSink) (result driver.Response, promptSent bool, err error)

RunTurn sends exactly one prompt on the loaded thread. promptSent becomes true immediately before turn/start because an RPC error cannot prove the peer did not receive the request; callers must not replay in that case.

func (*Process) TerminateAndWait

func (p *Process) TerminateAndWait(ctx context.Context) error

TerminateAndWait kills the independently grouped process and reaps it.

func (*Process) ThreadID

func (p *Process) ThreadID() string

ThreadID is the provider thread loaded by this process.

type ReasoningSummaryPartAddedNotification

type ReasoningSummaryPartAddedNotification struct {
	// ItemID corresponds to the JSON schema field "itemId".
	ItemID string `json:"itemId"`

	// SummaryIndex corresponds to the JSON schema field "summaryIndex".
	SummaryIndex int `json:"summaryIndex"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

type ReasoningSummaryTextDeltaNotification

type ReasoningSummaryTextDeltaNotification struct {
	// Delta corresponds to the JSON schema field "delta".
	Delta string `json:"delta"`

	// ItemID corresponds to the JSON schema field "itemId".
	ItemID string `json:"itemId"`

	// SummaryIndex corresponds to the JSON schema field "summaryIndex".
	SummaryIndex int `json:"summaryIndex"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

type ReasoningTextDeltaNotification

type ReasoningTextDeltaNotification struct {
	// ContentIndex corresponds to the JSON schema field "contentIndex".
	ContentIndex int `json:"contentIndex"`

	// Delta corresponds to the JSON schema field "delta".
	Delta string `json:"delta"`

	// ItemID corresponds to the JSON schema field "itemId".
	ItemID string `json:"itemId"`

	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

type SandboxPolicy

type SandboxPolicy struct {
	Type          SandboxPolicyKind `json:"type"`
	NetworkAccess *bool             `json:"networkAccess,omitempty"`
	Extras        json.RawMessage   `json:"-"`
}

SandboxPolicy is the sandbox policy override passed on TurnStart. Only the variants the codex adapter needs at call sites are modelled; extra fields per variant round-trip through Extras.

type SandboxPolicyKind

type SandboxPolicyKind string

SandboxPolicyKind lists the sandbox policy variants.

const (
	// SandboxPolicyKindDangerFull requests unrestricted local execution.
	SandboxPolicyKindDangerFull SandboxPolicyKind = "dangerFullAccess"
	// SandboxPolicyKindReadOnly requests read-only sandboxing.
	SandboxPolicyKindReadOnly SandboxPolicyKind = "readOnly"
	// SandboxPolicyKindExternal delegates sandboxing outside codex.
	SandboxPolicyKindExternal SandboxPolicyKind = "externalSandbox"
	// SandboxPolicyKindWorkspaceWrite allows writes inside the workspace.
	SandboxPolicyKindWorkspaceWrite SandboxPolicyKind = "workspaceWrite"
)

type ThreadForkParams

type ThreadForkParams struct {
	ThreadID       string `json:"threadId"`
	CWD            string `json:"cwd,omitempty"`
	Ephemeral      bool   `json:"ephemeral,omitempty"`
	Sandbox        string `json:"sandbox,omitempty"`
	Model          string `json:"model,omitempty"`
	ServiceTier    string `json:"serviceTier,omitempty"`
	ApprovalPolicy string `json:"approvalPolicy,omitempty"`
}

ThreadForkParams is the official v2 thread/fork request. Forking creates a new provider thread from ThreadID; the parent thread remains unchanged.

type ThreadForkResponse

type ThreadForkResponse struct {
	Thread ThreadRef `json:"thread"`
}

ThreadForkResponse is the reply to thread/fork. Thread.ID is the new child identifier and is the only checkpoint that may be returned by the fork run.

type ThreadItem

type ThreadItem struct {
	ID   string         `json:"id"`
	Kind ThreadItemKind `json:"-"`

	// Exactly one of the following pointers is set when Kind matches.
	AgentMessage     *ThreadItemAgentMessageBody     `json:"-"`
	Reasoning        *ThreadItemReasoningBody        `json:"-"`
	CommandExecution *ThreadItemCommandExecutionBody `json:"-"`
	FileChange       *ThreadItemFileChangeBody       `json:"-"`
	McpToolCall      *ThreadItemMcpToolCallBody      `json:"-"`
	WebSearch        *ThreadItemWebSearchBody        `json:"-"`
	DynamicToolCall  *ThreadItemDynamicToolCallBody  `json:"-"`

	// Raw preserves the original JSON representation. It is always non-nil;
	// use it when Kind is unknown or when a caller needs an unmodeled field.
	Raw json.RawMessage `json:"-"`
}

ThreadItem is the discriminated union payload observed on item/started and item/completed notifications. The concrete variant is accessible through the exported ThreadItem* structs; unrecognised variants retain their original JSON in Raw for forward compatibility.

func DecodeThreadItem

func DecodeThreadItem(raw json.RawMessage) (*ThreadItem, error)

DecodeThreadItem parses a ThreadItem from its raw JSON, dispatching on the "type" discriminator. Unknown types are returned with Kind == ThreadItemUnknown and Raw populated; this lets translate.go emit them as StreamPayload.Raw without failing the whole run.

type ThreadItemAgentMessageBody

type ThreadItemAgentMessageBody struct {
	Text  string `json:"text"`
	Phase string `json:"phase,omitempty"`
}

ThreadItemAgentMessageBody is the "agentMessage" variant.

type ThreadItemCommandExecutionBody

type ThreadItemCommandExecutionBody struct {
	Command          string `json:"command"`
	CWD              string `json:"cwd,omitempty"`
	Status           string `json:"status"`
	ExitCode         *int   `json:"exitCode,omitempty"`
	AggregatedOutput string `json:"aggregatedOutput,omitempty"`
	DurationMs       *int64 `json:"durationMs,omitempty"`
	ProcessID        string `json:"processId,omitempty"`
	Source           string `json:"source,omitempty"`
}

ThreadItemCommandExecutionBody is the "commandExecution" variant.

type ThreadItemDynamicToolCallBody

type ThreadItemDynamicToolCallBody struct {
	Tool       string          `json:"tool"`
	Arguments  json.RawMessage `json:"arguments,omitempty"`
	Status     string          `json:"status"`
	Success    *bool           `json:"success,omitempty"`
	DurationMs *int64          `json:"durationMs,omitempty"`
}

ThreadItemDynamicToolCallBody is the "dynamicToolCall" variant.

type ThreadItemFileChangeBody

type ThreadItemFileChangeBody struct {
	Changes []FileChange `json:"changes"`
	Status  string       `json:"status"`
}

ThreadItemFileChangeBody is the "fileChange" variant.

type ThreadItemKind

type ThreadItemKind string

ThreadItemKind enumerates the ThreadItem variants we model. We cover the ones the codex adapter maps into StreamPayload; other variants are preserved through the Unknown/Raw path so downstream code can still emit them as StreamPayload.Raw.

const (
	// ThreadItemAgentMessage is assistant text.
	ThreadItemAgentMessage ThreadItemKind = "agentMessage"
	// ThreadItemReasoning is model reasoning/thinking content.
	ThreadItemReasoning ThreadItemKind = "reasoning"
	// ThreadItemCommandExecution is a shell command execution item.
	ThreadItemCommandExecution ThreadItemKind = "commandExecution"
	// ThreadItemFileChange is a file-change item.
	ThreadItemFileChange ThreadItemKind = "fileChange"
	// ThreadItemMcpToolCall is an MCP tool-call item.
	ThreadItemMcpToolCall ThreadItemKind = "mcpToolCall"
	// ThreadItemWebSearch is a web-search item.
	ThreadItemWebSearch ThreadItemKind = "webSearch"
	// ThreadItemDynamicToolCall is a dynamic tool-call item.
	ThreadItemDynamicToolCall ThreadItemKind = "dynamicToolCall"
	// ThreadItemPlan is a plan update item.
	ThreadItemPlan ThreadItemKind = "plan"
	// ThreadItemUserMessage is a user message item.
	ThreadItemUserMessage ThreadItemKind = "userMessage"
	// ThreadItemImageView is an image-view item.
	ThreadItemImageView ThreadItemKind = "imageView"
	// ThreadItemImageGeneration is an image-generation item.
	ThreadItemImageGeneration ThreadItemKind = "imageGeneration"
	// ThreadItemContextCompaction is a context-compaction item.
	ThreadItemContextCompaction ThreadItemKind = "contextCompaction"
	// ThreadItemUnknown preserves unknown variants through the Raw path.
	ThreadItemUnknown ThreadItemKind = ""
)

type ThreadItemMcpToolCallBody

type ThreadItemMcpToolCallBody struct {
	Server     string          `json:"server"`
	Tool       string          `json:"tool"`
	Arguments  json.RawMessage `json:"arguments,omitempty"`
	Result     json.RawMessage `json:"result,omitempty"`
	Error      json.RawMessage `json:"error,omitempty"`
	Status     string          `json:"status"`
	DurationMs *int64          `json:"durationMs,omitempty"`
}

ThreadItemMcpToolCallBody is the "mcpToolCall" variant.

type ThreadItemReasoningBody

type ThreadItemReasoningBody struct {
	Content []string `json:"content,omitempty"`
	Summary []string `json:"summary,omitempty"`
}

ThreadItemReasoningBody is the "reasoning" variant.

type ThreadItemWebSearchBody

type ThreadItemWebSearchBody struct {
	Query  string          `json:"query"`
	Action json.RawMessage `json:"action,omitempty"`
}

ThreadItemWebSearchBody is the "webSearch" variant.

type ThreadRef

type ThreadRef struct {
	ID        string          `json:"id"`
	Ephemeral bool            `json:"ephemeral,omitempty"`
	CreatedAt int64           `json:"createdAt,omitempty"`
	UpdatedAt int64           `json:"updatedAt,omitempty"`
	Extras    json.RawMessage `json:"-"`
}

ThreadRef is the minimal surface of the server's Thread object exposed through thread/start and thread/started.

type ThreadResumeParams

type ThreadResumeParams struct {
	ThreadID string `json:"threadId"`
}

ThreadResumeParams is the payload for the "thread/resume" request.

type ThreadResumeResponse

type ThreadResumeResponse struct {
	Thread ThreadRef `json:"thread"`
}

ThreadResumeResponse is the reply to thread/resume.

type ThreadStartParams

type ThreadStartParams struct {
	CWD         string          `json:"cwd,omitempty"`
	Ephemeral   bool            `json:"ephemeral,omitempty"`
	Sandbox     string          `json:"sandbox,omitempty"`
	Model       string          `json:"model,omitempty"`
	ServiceTier string          `json:"serviceTier,omitempty"`
	Extras      json.RawMessage `json:"-"`
}

ThreadStartParams matches the v2 ThreadStartParams schema. All fields are optional per the codex protocol; we only set the ones the adapter needs.

type ThreadStartResponse

type ThreadStartResponse struct {
	Thread ThreadRef `json:"thread"`
}

ThreadStartResponse is the reply to thread/start.

type ThreadStartedNotificationBody

type ThreadStartedNotificationBody struct {
	Thread ThreadRef `json:"thread"`
}

ThreadStartedNotificationBody is the minimal view the adapter takes of the "thread/started" notification.

type ThreadTokenUsage

type ThreadTokenUsage struct {
	// Last corresponds to the JSON schema field "last".
	Last TokenUsageBreakdown `json:"last"`

	// ModelContextWindow corresponds to the JSON schema field "modelContextWindow".
	ModelContextWindow ThreadTokenUsageModelContextWindow `json:"modelContextWindow,omitempty,omitzero"`

	// Total corresponds to the JSON schema field "total".
	Total TokenUsageBreakdown `json:"total"`
}

type ThreadTokenUsageModelContextWindow

type ThreadTokenUsageModelContextWindow *int

type ThreadTokenUsageUpdatedNotification

type ThreadTokenUsageUpdatedNotification struct {
	// ThreadID corresponds to the JSON schema field "threadId".
	ThreadID string `json:"threadId"`

	// TokenUsage corresponds to the JSON schema field "tokenUsage".
	TokenUsage ThreadTokenUsage `json:"tokenUsage"`

	// TurnID corresponds to the JSON schema field "turnId".
	TurnID string `json:"turnId"`
}

type TokenUsageBreakdown

type TokenUsageBreakdown struct {
	// CachedInputTokens corresponds to the JSON schema field "cachedInputTokens".
	CachedInputTokens int `json:"cachedInputTokens"`

	// InputTokens corresponds to the JSON schema field "inputTokens".
	InputTokens int `json:"inputTokens"`

	// OutputTokens corresponds to the JSON schema field "outputTokens".
	OutputTokens int `json:"outputTokens"`

	// ReasoningOutputTokens corresponds to the JSON schema field
	// "reasoningOutputTokens".
	ReasoningOutputTokens int `json:"reasoningOutputTokens"`

	// TotalTokens corresponds to the JSON schema field "totalTokens".
	TotalTokens int `json:"totalTokens"`
}

type Translator

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

Translator converts codex app-server notifications into StreamPayload events understood by the SDK and downstream bridges. A translator is per-run and single-goroutine: jrpc2 delivers notifications sequentially so there is no internal locking beyond what tracks per-turn state.

func NewTranslator

func NewTranslator(sink driver.EventSink, runID string) *Translator

NewTranslator creates a translator that attributes every emitted payload to runID.

func (*Translator) Dispatch

func (t *Translator) Dispatch(method string, params json.RawMessage)

Dispatch routes one notification to the appropriate handler. Unknown methods are forwarded as a StreamPayload with Kind "" and their raw body in Raw so downstream bridges can still surface them as custom events.

func (*Translator) FinishError

func (t *Translator) FinishError(err error)

FinishError closes a run whose transport or protocol ended without a usable official turn/completed notification. It never fabricates a Raw provider terminal; it only satisfies the normalized stream lifecycle.

func (*Translator) FinishFailure

func (t *Translator) FinishFailure(failure *driver.RunFailure, raw *driver.RawStreams, usage *driver.Usage)

FinishFailure publishes the unique normalized run.error after the caller has combined the official provider terminal with process and validation outcomes. Raw provider terminal bytes remain attached for protocol-aware bridges without allowing an earlier optimistic run.finished.

func (*Translator) SetThread

func (t *Translator) SetThread(id string)

SetThread records the thread id associated with the active run. Bridges use it to fill StreamPayload.ThreadID on every emitted payload.

func (*Translator) SetTurn

func (t *Translator) SetTurn(id string)

SetTurn records the turn id acknowledged by turn/start before queued wire notifications are flushed. This ensures even an unknown first notification carries the authoritative RPC identity.

func (*Translator) ThreadID

func (t *Translator) ThreadID() string

ThreadID returns the thread id currently associated with the run. It is exposed for adapter code that needs to report the id back to the caller.

type TurnCompletedNotificationBody

type TurnCompletedNotificationBody struct {
	ThreadID string            `json:"threadId"`
	Turn     TurnCompletedTurn `json:"turn"`
}

TurnCompletedNotificationBody is the adapter's view of "turn/completed".

type TurnCompletedTurn

type TurnCompletedTurn struct {
	ID          string            `json:"id"`
	Status      TurnStatus        `json:"status"`
	Error       *TurnError        `json:"error,omitempty"`
	Usage       *TurnUsage        `json:"usage,omitempty"`
	CompletedAt int64             `json:"completedAt,omitempty"`
	Items       []json.RawMessage `json:"items,omitempty"`
}

TurnCompletedTurn is the trimmed turn object embedded in "turn/completed". Usage is the important field; Error surfaces on failure.

type TurnError

type TurnError struct {
	// AdditionalDetails corresponds to the JSON schema field "additionalDetails".
	AdditionalDetails TurnErrorAdditionalDetails `json:"additionalDetails,omitempty,omitzero"`

	// CodexErrorInfo corresponds to the JSON schema field "codexErrorInfo".
	CodexErrorInfo interface{} `json:"codexErrorInfo,omitempty,omitzero"`

	// Message corresponds to the JSON schema field "message".
	Message string `json:"message"`
}

type TurnErrorAdditionalDetails

type TurnErrorAdditionalDetails *string

type TurnInterruptParams

type TurnInterruptParams struct {
	ThreadID string `json:"threadId"`
	TurnID   string `json:"turnId,omitempty"`
}

TurnInterruptParams is the payload for the "turn/interrupt" request.

type TurnInterruptResponse

type TurnInterruptResponse struct{}

TurnInterruptResponse is the reply to turn/interrupt.

type TurnRef

type TurnRef struct {
	ID     string     `json:"id"`
	Status TurnStatus `json:"status"`
}

TurnRef carries the minimum turn metadata the adapter tracks.

type TurnStartParams

type TurnStartParams struct {
	ThreadID       string          `json:"threadId"`
	Input          []UserInput     `json:"input"`
	ApprovalPolicy string          `json:"approvalPolicy,omitempty"`
	SandboxPolicy  *SandboxPolicy  `json:"sandboxPolicy,omitempty"`
	Model          string          `json:"model,omitempty"`
	Effort         string          `json:"effort,omitempty"`
	ServiceTier    string          `json:"serviceTier,omitempty"`
	CWD            string          `json:"cwd,omitempty"`
	OutputSchema   json.RawMessage `json:"outputSchema,omitempty"`
}

TurnStartParams matches the v2 TurnStartParams schema. The adapter always attaches a text-only input; richer UserInput variants are future work.

type TurnStartResponse

type TurnStartResponse struct {
	Turn TurnRef `json:"turn"`
}

TurnStartResponse is the reply to turn/start.

type TurnStartedNotificationBody

type TurnStartedNotificationBody struct {
	ThreadID string  `json:"threadId"`
	Turn     TurnRef `json:"turn"`
}

TurnStartedNotificationBody is the adapter's view of "turn/started".

type TurnStatus

type TurnStatus string

TurnStatus is the official status carried by turn objects. A turn/completed notification is the sole terminal notification; its status distinguishes success, provider failure, and interruption.

const (
	TurnStatusCompleted   TurnStatus = "completed"
	TurnStatusFailed      TurnStatus = "failed"
	TurnStatusInterrupted TurnStatus = "interrupted"
	TurnStatusInProgress  TurnStatus = "inProgress"
)

type TurnUsage

type TurnUsage struct {
	InputTokens       int `json:"inputTokens"`
	OutputTokens      int `json:"outputTokens"`
	CachedInputTokens int `json:"cachedInputTokens,omitempty"`
}

TurnUsage carries the per-turn token counts reported on completion.

type UserInput

type UserInput struct {
	Type UserInputKind `json:"type"`

	// Fields by type; absent fields are omitted on the wire.
	Text string `json:"text,omitempty"`
	URL  string `json:"url,omitempty"`
	Path string `json:"path,omitempty"`
	Name string `json:"name,omitempty"`
}

UserInput is the tagged union carried by TurnStartParams.Input.

func TextInput

func TextInput(text string) UserInput

TextInput is a shorthand constructor for the default input case.

type UserInputKind

type UserInputKind string

UserInputKind enumerates the variants of UserInput the adapter emits. Only the "text" variant is wired today; image variants round-trip via Extras.

const (
	// UserInputKindText carries plain text input.
	UserInputKindText UserInputKind = "text"
	// UserInputKindImage carries remote image input.
	UserInputKindImage UserInputKind = "image"
	// UserInputKindLocalImage carries local image input.
	UserInputKindLocalImage UserInputKind = "localImage"
	// UserInputKindSkill carries a skill reference input.
	UserInputKindSkill UserInputKind = "skill"
	// UserInputKindMention carries a structured mention input.
	UserInputKindMention UserInputKind = "mention"
)

Jump to

Keyboard shortcuts

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