codex

package
v1.171.2 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package codex implements agentproxy.Facade for the codex CLI's app-server JSON-RPC protocol (github.com/openai/codex, codex-rs/app-server).

Package codex: raw event passthrough (v1.5) — the prefer-source_raw half of the translator strategy translate.go's doc comment reserved a seam for.

When the hosted session's agent runtime is codex itself (Facade.AgentKind), every canonical event the OHR adapter emitted carries the exact native app-server frame it was mapped from (HostedAgentEvent.SourceRaw — one JSON-RPC message as read off the codex app-server transport in the sandbox, requested via StreamSession's IncludeRaw). Forwarding that frame to the TUI beats reconstructing an approximation from canonical's ~15-event common denominator: canonical carries no file diffs, no command output, no reasoning deltas, no item metadata — the native frame carries all of it.

"Verbatim" has exactly one deliberate exception: identifier rewriting. The in-sandbox adapter drove its own thread/start and turn/start against the VM's app-server, so the raw params reference the VM's thread and turn ids — but this proxy's client was told the thread id is Facade.SessionID (thread/start's synthesized reply) and each turn's id is the harness run id (turn/start's synthesized reply). A frame forwarded with the VM's ids would describe a thread and turn the client has never heard of, so threadId/turnId (and turn.id) are rewritten to the proxy's ids. Native item ids are kept: the proxy never promises item ids in any reply, so the raw frames' own item lifecycle (started → deltas → completed, all sharing the native id) is self-consistent as-is.

The fallback is per event, as the v1.5 plan specifies: an event with no usable raw frame (adapter-synthesized events like a TurnError-mapped run.failed; a server that doesn't retain bytes; a non-codex session) takes translate.go's canonical reconstruction instead. The two paths keep their item-id families from colliding naturally: a turn whose run.started was forwarded raw never sets turnState.itemStarted, so finishTurn's synthesized agentMessage item/completed — the only canonical notification that could duplicate a raw item — stays suppressed for that turn.

This file also holds the inbound halves, which come in two shapes because the client sends two kinds of message.

Notifications and turns (v2): rawTurnStartFrame packages the TUI's turn/start params as SendInput's source_raw, so the in-sandbox adapter drives the turn from the client's actual params (input items, model, effort, approval policy) instead of a synthesized single-text turn.

Client *requests* — the ones that block waiting for an answer — have no inbound path at all. A method this facade cannot answer itself is refused, which is why turn/interrupt only acknowledges and why a slash command codex gained after this proxy shipped does not work.

The direction is inverted but the id discipline is symmetric. Outbound rewrites VM ids to proxy ids. Inbound ships the proxy-side ids as-is and the adapter rewrites them to the VM's own — it is the only component that knows those.

Package codex: --replay support, feeding a session's durable event history into the first thread this facade bootstraps.

Package codex: canonical-event-to-codex-notification translation.

This file is the "translator-strategy seam" the original implementation plan called for: the logic that decides what a canonical event means in codex terms lives here, not scattered inline in runEventLoop/drainStream's own dispatch loop (facade.go). As of v1.5 the seam carries two strategies: translateEvent first offers each event to tryRawPassthrough (raw.go), which forwards the event's native codex frame when one is available, and only reconstructs from canonical — everything below — when it isn't.

This is deliberately not a Go interface with multiple implementations: the raw strategy is one conditional at the top of translateEvent plus its own self-contained file, exactly the shape the v1 comment here reserved. The canonical reconstruction is not legacy — it is the permanent fallback (adapter-synthesized events carry no raw bytes; non-codex sessions never forward raw at all) and the only path that can ever serve cross-agent use.

Index

Constants

View Source
const TestedVersion = "0.142.5"

TestedVersion is the codex-cli version this facade's protocol handling was captured against (hosted-agents' docs/design/codex-app-server-protocol-capture.md: stdio send-message-v2 capture plus a live codex --remote / app-server pairing over WebSocket). Re-run that capture and update this pin on every codex upgrade — the WS/app-server transport is officially experimental and can change without notice.

Variables

This section is empty.

Functions

This section is empty.

Types

type Facade

type Facade struct {
	// SessionID is the hosted session this facade bridges to. thread/start's
	// synthesized thread id is exactly this value — simplest possible way to
	// satisfy "a synthesized thread whose id embeds the session id" while
	// matching what the real capture showed too (thread.id == thread.sessionId
	// there as well).
	SessionID string

	// Sessions is the harness bridge: turn/start calls SendInput on it, and
	// the background streaming goroutine reads StreamSession's SSE events to
	// translate into codex notifications. The bootstrap methods (initialize,
	// thread/start, etc.) don't touch it.
	Sessions do.HostedAgentsService

	// AgentKind is the hosted session's agent runtime, from GetSession at
	// proxy startup. Raw passthrough (v1.5) is gated on it: an event's
	// native SourceRaw bytes are only forwarded when the session's agent
	// speaks this facade's protocol (AGENT_KIND_CODEX_CLI) — cross-agent
	// sessions (e.g. codex TUI driving an OpenCode session) always take the
	// canonical-reconstruction path, where raw bytes would be the wrong
	// protocol entirely. Empty (older CLI paths, tests that don't care)
	// disables raw passthrough.
	AgentKind godo.HostedAgentKind

	// Replay, when true, feeds this session's full durable event history
	// into the first thread this facade bootstraps before that thread would
	// otherwise appear to start with no prior conversation — see
	// replaySessionHistory. Set once at construction from the --replay CLI
	// flag; never toggled per-connection.
	Replay bool
	// contains filtered or unexported fields
}

Facade implements agentproxy.Facade for codex --remote.

func (*Facade) AfterReply

func (f *Facade) AfterReply(ctx context.Context, method string)

AfterReply implements agentproxy.AfterReply: once handleConn has written a successful thread/start or thread/resume result, start the deferred replaySessionHistory goroutine if maybeReplay armed one.

func (*Facade) Dispatch

func (f *Facade) Dispatch(ctx context.Context, method string, params json.RawMessage) (any, error)

Dispatch implements agentproxy.Facade.

func (*Facade) SetNotifier

func (f *Facade) SetNotifier(n agentproxy.Notifier)

SetNotifier implements agentproxy.NotifierAware.

Jump to

Keyboard shortcuts

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