agentproxy

package
v1.167.0-beta.4 Latest Latest
Warning

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

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

Documentation

Overview

Package agentproxy implements the local WebSocket facade that lets an unmodified coding-agent CLI (codex today, others later) drive a hosted MARS session as if the session were its own local backend.

Index

Constants

This section is empty.

Variables

View Source
var ErrMethodNotFound = &RPCError{Code: -32601, Message: "method not found"}

ErrMethodNotFound is returned by a Facade for any method it doesn't (yet) implement. The bridge logs it as "unhandled: <method>" and, for requests (a message with an id), turns it into a JSON-RPC error response — so the client never hangs waiting on a reply that was logged-and-dropped instead of sent.

Functions

func Serve

func Serve(ctx context.Context, port int, newFacade func() Facade) error

Serve binds a WebSocket listener on 127.0.0.1:port — never "localhost" (IPv6 ::1 resolution can fail to connect) or 0.0.0.0 (codex requires auth for non-loopback listeners, and there's no reason to expose this beyond the machine anyway) — and speaks newFacade's JSON-RPC protocol to exactly one connected client at a time, until ctx is canceled.

func ServeListener

func ServeListener(ctx context.Context, ln net.Listener, newFacade func() Facade) error

ServeListener is Serve, except it speaks newFacade's protocol over an already-bound listener instead of binding one from a port number itself.

This exists for tests: picking a free ephemeral port ahead of time (e.g. via net.Listen("tcp", "127.0.0.1:0")) and having a *separate* call to Serve re-bind that same port number is inherently racy — anything else on the machine could grab it in between. Handing the already-bound *net.Listener straight to ServeListener closes that race window entirely: the listener is accepting connections (into the kernel backlog, at least) from the moment net.Listen returns, before this function is even called.

newFacade is called once per accepted connection, not once for the whole listener: a facade like codex's carries per-connection state (in-flight turns, whether its event loop is running, the connection's Notifier), and only one client connects at a time anyway (see the slot below), so reusing one Facade instance across a disconnect/reconnect would leak that state into the new connection — notifications from a still-unwinding previous connection's background goroutine could even land on the new socket via a shared notifier. A fresh Facade per connection starts clean and makes the previous one's goroutines (if still winding down) entirely self-contained.

Types

type AfterReply

type AfterReply interface {
	AfterReply(ctx context.Context, method string)
}

AfterReply is optionally implemented by a Facade that wants a hook after handleConn has written a successful request result (Dispatch returned nil and the JSON-RPC reply was written). Not invoked for JSON-RPC error replies. codex uses this to start --replay only once thread/start|resume has been acknowledged, so a replayed turn/started cannot race onto the wire before the thread it refers to.

type Facade

type Facade interface {
	Dispatch(ctx context.Context, method string, params json.RawMessage) (result any, err error)
}

Facade is the per-agent seam start-proxy dispatches JSON-RPC messages to. One implementation per --type (v1: codex; future: claude-code, opencode).

Dispatch handles a single JSON-RPC message, request or notification alike; it doesn't need to know which one it's looking at. The bridge is the one that knows: a message with a non-nil id is a request and its (result, err) becomes a reply; a message with a nil id is a notification and (result, err) only affects logging, never the wire.

type Notifier

type Notifier interface {
	Notify(method string, params any) error

	// Request sends a server-initiated JSON-RPC request and blocks until the
	// client replies or ctx is done. This is the reverse of Notify: some
	// codex methods (the item/*/requestApproval family) need an answer from
	// the client, not just to inform it of something. The bridge correlates
	// the reply by a synthesized request id — a Facade never sees or manages
	// that id itself.
	Request(ctx context.Context, method string, params any) (result json.RawMessage, err error)
}

Notifier lets a Facade push a server-initiated JSON-RPC notification to the connected client at any time — not just synchronously in reply to a request. Needed for events that arrive asynchronously from the harness (streamed tokens, turn completion) on their own timeline, well after the request that kicked off the turn has already been answered.

type NotifierAware

type NotifierAware interface {
	SetNotifier(Notifier)
}

NotifierAware is implemented by facades that need to push asynchronous notifications rather than only answer synchronous requests. The bridge calls SetNotifier once per connection, before handing it any messages, so Dispatch can stash it and use it later from a background goroutine.

type RPCError

type RPCError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

RPCError is a JSON-RPC 2.0 error object.

func (*RPCError) Error

func (e *RPCError) Error() string

Directories

Path Synopsis
Package agentproxytest fakes the DigitalOcean Hosted Agents session HTTP API (see github.com/digitalocean/godo's hosted_agents.go) behind an httptest.Server, so agentproxy tests can drive a real do.HostedAgentsService end to end without a live harness backend.
Package agentproxytest fakes the DigitalOcean Hosted Agents session HTTP API (see github.com/digitalocean/godo's hosted_agents.go) behind an httptest.Server, so agentproxy tests can drive a real do.HostedAgentsService end to end without a live harness backend.
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 implements agentproxy.Facade for the codex CLI's app-server JSON-RPC protocol (github.com/openai/codex, codex-rs/app-server).

Jump to

Keyboard shortcuts

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