libacp

package
v0.36.0 Latest Latest
Warning

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

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

Documentation

Overview

Package libacp implements the Agent Client Protocol (ACP) v1 — the JSON-RPC-over-NDJSON protocol editors and agents use to talk to each other — for both roles:

Both connection types share the same wire machinery: NDJSON framing, request-id correlation, per-request cancelable contexts honoring "$/cancel_request", panic-safe handler dispatch, and extension-method passthrough (AgentSideConnection.SetExtRequestHandler, ClientSideConnection.CallExtMethod, and their mirrors).

A connection reads from any io.ReadWriteCloser. For the common case of an agent subprocess spoken to over stdio, the subpackage github.com/contenox/runtime/libacp/acpexec spawns the process and hands back the transport.

Driving an agent (client role)

The essential client flow — spawn, connect, initialize, open a session, prompt, cancel:

proc, err := acpexec.Spawn(ctx, exec.Command("contenox", "acp"))
if err != nil {
	return err
}
conn := libacp.NewClientSideConnection(proc, func(*libacp.ClientSideConnection) libacp.Client {
	return myClient{} // embeds libacp.UnimplementedClient; overrides SessionUpdate, RequestPermission, ...
})
go conn.Run(ctx) // serves the connection until ctx ends or the transport closes

if _, err := conn.Initialize(ctx, libacp.InitializeRequest{
	ProtocolVersion: libacp.ProtocolVersion,
	ClientInfo:      &libacp.Implementation{Name: "my-editor", Version: "1.0"},
}); err != nil {
	return err
}

sess, err := conn.NewSession(ctx, libacp.NewSessionRequest{
	Cwd:        "/abs/path/to/project",
	McpServers: []libacp.McpServer{}, // MCP servers to hand down to the agent
})
if err != nil {
	return err
}

// Prompt blocks until the turn ends; streamed output arrives on
// myClient.SessionUpdate concurrently, in wire order.
resp, err := conn.Prompt(ctx, libacp.PromptRequest{
	SessionID: sess.SessionID,
	Prompt:    []libacp.ContentBlock{libacp.NewTextContent("hello")},
})

// To cancel a turn from another goroutine while Prompt is in flight:
// sends session/cancel and auto-resolves the session's pending
// session/request_permission requests with the "cancelled" outcome, per
// the spec's cancellation contract. The Prompt call then resolves with
// StopReasonCancelled and a nil error.
_ = conn.CancelPrompt(sess.SessionID)
_ = resp

Serving an agent (agent role)

The mirror image: implement Agent, then

conn := libacp.NewAgentSideConnection(rw, func(c *libacp.AgentSideConnection) libacp.Agent {
	return newMyAgent(c) // keeps c to send SessionUpdate and reverse calls
})
err := conn.Run(ctx)

Handlers that must emit a session/update only after their own result is on the wire (e.g. available_commands_update after session/new) schedule it with AfterResponse. libacp/cmd/acp-stub-agent is a hermetic reference implementation of this role, used by the conformance harness.

Verification harnesses

Beyond the in-process unit tests, each role is validated against the independently implemented Rust reference SDK (github.com/agentclientprotocol/rust-sdk): `make acp-conformance` runs the acp-validator conformance client (source in tools/acp-validator) against the stub agent, and `make acp-client-e2e` runs this package's client side against the SDK's deterministic "testy" agent over a real subprocess. See docs/development/acp-client.md.

Index

Examples

Constants

View Source
const (
	ErrParseError     = -32700
	ErrInvalidRequest = -32600
	ErrMethodNotFound = -32601
	ErrInvalidParams  = -32602
	ErrInternalError  = -32603

	ErrAuthRequired     = -32000
	ErrResourceNotFound = -32002
)
View Source
const (
	AuthMethodTypeTerminal = "terminal"
	AuthMethodTypeEnvVar   = "env_var"
)
View Source
const (
	MethodInitialize   = "initialize"
	MethodAuthenticate = "authenticate"
	MethodLogout       = "logout"

	MethodSessionNew             = "session/new"
	MethodSessionLoad            = "session/load"
	MethodSessionResume          = "session/resume"
	MethodSessionClose           = "session/close"
	MethodSessionDelete          = "session/delete"
	MethodSessionList            = "session/list"
	MethodSessionPrompt          = "session/prompt"
	MethodSessionCancel          = "session/cancel"
	MethodSessionUpdate          = "session/update"
	MethodSessionSetMode         = "session/set_mode"
	MethodSessionSetConfigOption = "session/set_config_option"
	// MethodSessionSetModel is the UNSTABLE Zed model-picker method: switch a
	// session's active model (see SetSessionModelRequest / SessionModelState). The
	// client-side driver surfaces it as `unstable_setSessionModel`; it is dispatched
	// over this `session/set_model` method name. This is an experimental extension,
	// NOT part of the stable ACP spec, and MAY change or be removed.
	MethodSessionSetModel = "session/set_model"

	MethodSessionRequestPermission = "session/request_permission"

	// MethodCancelRequest is the protocol-level "$/cancel_request"
	// notification: either side may signal it no longer awaits the response to
	// an in-flight request. "$/"-prefixed methods are always safe to ignore.
	MethodCancelRequest = "$/cancel_request"

	MethodFSReadTextFile  = "fs/read_text_file"
	MethodFSWriteTextFile = "fs/write_text_file"

	MethodTerminalCreate      = "terminal/create"
	MethodTerminalOutput      = "terminal/output"
	MethodTerminalWaitForExit = "terminal/wait_for_exit"
	MethodTerminalKill        = "terminal/kill"
	MethodTerminalRelease     = "terminal/release"
)
View Source
const (
	SessionConfigOptionTypeSelect  = "select"
	SessionConfigOptionTypeBoolean = "boolean"
)

Session configuration option type discriminators (SessionConfigOption.Type).

View Source
const ExtensionMethodPrefix = "_"

ExtensionMethodPrefix is the reserved namespace for custom "extension" methods and notifications. Per extensibility.mdx: "The protocol reserves any method name starting with an underscore (_) for custom extensions." "$/"-prefixed methods (MethodCancelRequest) are a separate, protocol-owned namespace and are never extension-eligible.

View Source
const ProtocolVersion = 1

Variables

View Source
var (
	// ErrAgentStartFailed marks a failure to launch or initialize the agent
	// subprocess. It is a startup error (IsStartupError): a bad binary path or
	// broken agent build will not fix itself on retry, so a supervisor must
	// surface it rather than loop.
	ErrAgentStartFailed = errors.New("libacp: agent start failed")

	// ErrIdleTimeout marks a turn that went silent — no session/update and no
	// result — past a driver's idle deadline. Distinct from an overall
	// context deadline so a driver can reset an idle watchdog on every received
	// message (hash's pattern) rather than cap total turn time.
	ErrIdleTimeout = errors.New("libacp: agent idle timeout")

	// ErrNoDisplayableOutput marks a prompt turn that ended with a normal stop
	// reason but never produced a renderable agent message — the client-side
	// mirror of the agent-side empty-response bug this repo just fixed. A driver
	// gets an explicit, observable failure class instead of silently showing an
	// empty answer (hash's noOutputPromptError, acp.go:979). Use TurnTracker to
	// detect it over a turn's session/update stream.
	ErrNoDisplayableOutput = errors.New("libacp: prompt turn produced no displayable output")
)

Client-side failure sentinels for a consumer that drives an agent through a ClientSideConnection (and, typically, an acpexec subprocess). They exist so a driver can classify failures — see IsStartupError / IsTimeoutError / IsRetryableError — instead of string-matching, the lesson hash learned the hard way (tmp/hash/internal/agent/errors.go). libacp itself never returns these from its wire methods; they are the vocabulary a driver wraps its own transport/lifecycle failures in.

View Source
var (
	ErrConnectionClosed = errors.New("libacp: connection closed")
)

Functions

func AfterResponse

func AfterResponse(ctx context.Context, fn func())

AfterResponse schedules fn to run after the result of the request currently being handled has been written to the wire. Use it from a request handler (NewSession, LoadSession, ...) to emit session/update notifications that must reach the client only once it can resolve the session — most importantly the available_commands_update after session/new, which a client (e.g. Zed) drops as an "unknown session" if it arrives before the session/new result.

Called outside a request handler (no sink in ctx), fn runs immediately, so it is always safe to use regardless of caller context.

func IsExtensionMethod added in v0.36.0

func IsExtensionMethod(method string) bool

IsExtensionMethod reports whether method is eligible for dispatch through an ExtRequestHandler/ExtNotificationHandler: non-empty and starting with ExtensionMethodPrefix.

func IsRetryableError added in v0.36.0

func IsRetryableError(err error) bool

IsRetryableError reports whether retrying the turn (typically after respawning the agent) might succeed. Mirrors hash's taxonomy (errors.go:44): an explicit cancellation and startup failures are never retryable; timeouts, a dropped transport (ErrConnectionClosed / EOF / closed pipe / EPIPE / ECONNRESET) and an empty turn are. The trailing string match is a cross-platform safety net for transport errors that do not wrap into a recognizable sentinel.

func IsStartupError added in v0.36.0

func IsStartupError(err error) bool

IsStartupError reports whether err indicates the agent could not be started or is unusable as configured — conditions a retry cannot cure. Adopts hash's classification (errors.go:26): a missing binary or a marked start failure is terminal, not transient.

func IsTimeoutError added in v0.36.0

func IsTimeoutError(err error) bool

IsTimeoutError reports whether err indicates a turn ran out of time — either a context deadline or an idle-watchdog trip. Split from IsRetryableError so a driver can, like hash (errors.go:36), treat "slow/stuck" differently from a hard protocol error.

func NegotiateProtocolVersion added in v0.36.0

func NegotiateProtocolVersion(theirs, ours int) int

NegotiateProtocolVersion returns the protocol version two peers will speak, given the version the other peer requested or offered (theirs) and the highest version this peer implements (ours — normally ProtocolVersion). It accepts theirs when this peer can speak it (1 <= theirs <= ours) and otherwise falls back to ours, matching acpsvc's spec-correct agent-side negotiation (runtime/acpsvc/initialize.go).

This deliberately does NOT require exact equality between the requested and returned version. hash's client hard-fails unless the agent echoes back the literal version it sent (tmp/hash acp.go:562), which is stricter than the spec and will break interop with any future peer that legitimately answers a different version it can still speak. Pinning min-of-both here gives any future libacp client consumer the resilient semantics as a reusable primitive so a refactor cannot drift toward that fragility.

Types

type Agent

type Agent interface {
	Initialize(ctx context.Context, req InitializeRequest) (InitializeResponse, error)
	Authenticate(ctx context.Context, req AuthenticateRequest) (AuthenticateResponse, error)
	Logout(ctx context.Context, req LogoutRequest) (LogoutResponse, error)
	NewSession(ctx context.Context, req NewSessionRequest) (NewSessionResponse, error)
	LoadSession(ctx context.Context, req LoadSessionRequest) (LoadSessionResponse, error)
	ResumeSession(ctx context.Context, req ResumeSessionRequest) (ResumeSessionResponse, error)
	CloseSession(ctx context.Context, req CloseSessionRequest) (CloseSessionResponse, error)
	DeleteSession(ctx context.Context, req DeleteSessionRequest) (DeleteSessionResponse, error)
	ListSessions(ctx context.Context, req ListSessionsRequest) (ListSessionsResponse, error)
	SetSessionMode(ctx context.Context, req SetSessionModeRequest) (SetSessionModeResponse, error)
	// SetSessionModel switches a session's active model. This is the UNSTABLE Zed
	// model-picker surface (session/set_model, see MethodSessionSetModel); an agent
	// that advertises no `models` state returns MethodNotFound, matching the
	// experimental method's optional-capability contract.
	SetSessionModel(ctx context.Context, req SetSessionModelRequest) (SetSessionModelResponse, error)
	SetSessionConfigOption(ctx context.Context, req SetSessionConfigOptionRequest) (SetSessionConfigOptionResponse, error)
	Prompt(ctx context.Context, req PromptRequest) (PromptResponse, error)
	Cancel(ctx context.Context, req CancelNotification) error
}

type AgentAuthCapabilities added in v0.36.0

type AgentAuthCapabilities struct {
	Logout *LogoutCapabilities `json:"logout,omitempty"`
	Meta   json.RawMessage     `json:"_meta,omitempty"`
}

AgentAuthCapabilities describes authentication-related capabilities supported by the agent — currently just whether it supports the `logout` method.

type AgentCapabilities

type AgentCapabilities struct {
	LoadSession         bool                  `json:"loadSession,omitempty"`
	PromptCapabilities  PromptCapabilities    `json:"promptCapabilities,omitempty"`
	McpCapabilities     McpCapabilities       `json:"mcpCapabilities,omitempty"`
	SessionCapabilities SessionCapabilities   `json:"sessionCapabilities,omitempty"`
	Auth                AgentAuthCapabilities `json:"auth,omitempty"`
	Meta                json.RawMessage       `json:"_meta,omitempty"`
}

type AgentFactory

type AgentFactory func(conn *AgentSideConnection) Agent

type AgentSideConnection

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

func NewAgentSideConnection

func NewAgentSideConnection(rw io.ReadWriteCloser, factory AgentFactory) *AgentSideConnection

func (*AgentSideConnection) CallExtMethod added in v0.36.0

func (c *AgentSideConnection) CallExtMethod(ctx context.Context, method string, params json.RawMessage) (json.RawMessage, error)

CallExtMethod sends a custom extension request (method must satisfy IsExtensionMethod) to the client and returns its raw result. This is the outbound half of the extension-method seam; SetExtRequestHandler installs the inbound half. A canceled ctx aborts the wait and best-effort notifies the client with "$/cancel_request", exactly like any other outbound call (see call).

func (*AgentSideConnection) CloseErr

func (c *AgentSideConnection) CloseErr() error

func (*AgentSideConnection) Closed

func (c *AgentSideConnection) Closed() <-chan struct{}

func (*AgentSideConnection) CreateTerminal

func (*AgentSideConnection) KillTerminal

func (*AgentSideConnection) ReadTextFile

func (*AgentSideConnection) ReleaseTerminal

func (*AgentSideConnection) RequestPermission

func (*AgentSideConnection) Run

func (*AgentSideConnection) SendExtNotification added in v0.36.0

func (c *AgentSideConnection) SendExtNotification(method string, params json.RawMessage) error

SendExtNotification sends a custom, fire-and-forget extension notification (method must satisfy IsExtensionMethod) to the client.

func (*AgentSideConnection) SessionUpdate

func (c *AgentSideConnection) SessionUpdate(n SessionNotification) error

func (*AgentSideConnection) SetExtNotificationHandler added in v0.36.0

func (c *AgentSideConnection) SetExtNotificationHandler(h ExtNotificationHandler)

SetExtNotificationHandler installs h to handle inbound extension notifications. Call it from the AgentFactory, before Run starts reading. A nil h (the default) leaves extension notifications silently ignored, exactly as before this seam existed.

func (*AgentSideConnection) SetExtRequestHandler added in v0.36.0

func (c *AgentSideConnection) SetExtRequestHandler(h ExtRequestHandler)

SetExtRequestHandler installs h to handle inbound extension requests (method names starting with ExtensionMethodPrefix that fall outside the core ACP method set). Call it from the AgentFactory, before Run starts reading. A nil h (the default) leaves extension requests answered with MethodNotFound, exactly as before this seam existed.

func (*AgentSideConnection) TerminalOutput

func (*AgentSideConnection) WaitForTerminalExit

func (*AgentSideConnection) WriteTextFile

type Annotations

type Annotations struct {
	Audience []string `json:"audience,omitempty"`
	// LastModified is an ISO 8601 timestamp indicating when the underlying
	// resource was last modified.
	LastModified string          `json:"lastModified,omitempty"`
	Priority     *float64        `json:"priority,omitempty"`
	Meta         json.RawMessage `json:"_meta,omitempty"`
}

type AuthCapabilities

type AuthCapabilities struct {
	Terminal bool `json:"terminal,omitempty"`
}

AuthCapabilities is the client-side auth capability object (unstable spec surface): it gates which auth method types the client can handle.

type AuthEnvVar added in v0.36.0

type AuthEnvVar struct {
	Name     string          `json:"name"`
	Label    string          `json:"label,omitempty"`
	Secret   *bool           `json:"secret,omitempty"`
	Optional bool            `json:"optional,omitempty"`
	Meta     json.RawMessage `json:"_meta,omitempty"`
}

AuthEnvVar describes one variable of an env_var auth method. Secret is a pointer because the spec default is true: nil emits nothing (client assumes secret), an explicit false must reach the wire.

type AuthMethod

type AuthMethod struct {
	ID          string            `json:"id"`
	Name        string            `json:"name"`
	Description string            `json:"description,omitempty"`
	Type        string            `json:"type,omitempty"`
	Args        []string          `json:"args,omitempty"`
	Env         map[string]string `json:"env,omitempty"`
	Vars        []AuthEnvVar      `json:"vars,omitempty"`
	Link        string            `json:"link,omitempty"`
	Meta        json.RawMessage   `json:"_meta,omitempty"`
}

AuthMethod covers the spec's auth method union in one struct. Type discriminates on the wire: "" (agent, the stable default), "terminal" (unstable; Args/Env describe how to launch the agent binary for a TUI), or "env_var" (unstable; Vars lists the environment variables the client should collect and set when launching the agent).

type AuthenticateRequest

type AuthenticateRequest struct {
	MethodID string          `json:"methodId"`
	Meta     json.RawMessage `json:"_meta,omitempty"`
}

type AuthenticateResponse

type AuthenticateResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type AvailableCommand

type AvailableCommand struct {
	Name string `json:"name"`
	// Description is spec-required (strict clients reject commands without
	// it), so no omitempty: an empty string still reaches the wire.
	Description string                 `json:"description"`
	Input       *AvailableCommandInput `json:"input,omitempty"`
	Meta        json.RawMessage        `json:"_meta,omitempty"`
}

type AvailableCommandInput

type AvailableCommandInput struct {
	Hint string `json:"hint,omitempty"`
}

type CancelNotification

type CancelNotification struct {
	SessionID SessionID       `json:"sessionId"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

type CancelRequestNotification added in v0.36.0

type CancelRequestNotification struct {
	RequestID RequestID       `json:"requestId"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

CancelRequestNotification is the payload of "$/cancel_request": the JSON-RPC id of the request whose response is no longer awaited.

type Client added in v0.36.0

type Client interface {
	RequestPermission(ctx context.Context, req RequestPermissionRequest) (RequestPermissionResponse, error)
	ReadTextFile(ctx context.Context, req ReadTextFileRequest) (ReadTextFileResponse, error)
	WriteTextFile(ctx context.Context, req WriteTextFileRequest) (WriteTextFileResponse, error)
	CreateTerminal(ctx context.Context, req CreateTerminalRequest) (CreateTerminalResponse, error)
	TerminalOutput(ctx context.Context, req TerminalOutputRequest) (TerminalOutputResponse, error)
	WaitForTerminalExit(ctx context.Context, req WaitForTerminalExitRequest) (WaitForTerminalExitResponse, error)
	KillTerminal(ctx context.Context, req KillTerminalRequest) (KillTerminalResponse, error)
	ReleaseTerminal(ctx context.Context, req ReleaseTerminalRequest) (ReleaseTerminalResponse, error)
	// SessionUpdate handles an inbound "session/update" notification. It has no
	// response on the wire (JSON-RPC notifications never do); the returned
	// error is reported to the implementation only, e.g. for logging.
	SessionUpdate(ctx context.Context, n SessionNotification) error
}

Client is the editor-side counterpart to Agent (agent.go): the set of requests an agent may send to the client, plus the inbound session/update notification. ClientSideConnection (clientconn.go) is the mirror image of AgentSideConnection: it dispatches these methods for incoming JSON-RPC requests/notifications, and exposes the agent-bound methods (Initialize, session/new, session/prompt, ...) as outbound calls.

func FilterSessionUpdates added in v0.36.0

func FilterSessionUpdates(live SessionID, inner Client) Client

FilterSessionUpdates wraps a Client so that session/update notifications for any session other than live are dropped before reaching inner.SessionUpdate; every other Client method passes straight through. It is opt-in middleware: a ClientSideConnection forwards every session/update regardless of session id (correct at the library layer — the app owns session bookkeeping), so a driver that reconnects or swaps sessions must filter stale updates itself, or a just-abandoned session's chunks leak into the new turn's UI. hash learned this the hard way and filters inline (acp.go:1504); this wrapper lets future consumers inherit the guard instead of re-learning it.

Wrap the Client the ClientFactory returns; update live (by constructing a new wrapper) whenever the driver's active session changes.

type ClientCapabilities

type ClientCapabilities struct {
	FS       FileSystemCapabilities     `json:"fs,omitempty"`
	Terminal bool                       `json:"terminal,omitempty"`
	Session  *ClientSessionCapabilities `json:"session,omitempty"`
	Auth     AuthCapabilities           `json:"auth,omitempty"`
	Meta     json.RawMessage            `json:"_meta,omitempty"`
}

func (ClientCapabilities) SupportsBooleanConfigOptions added in v0.36.0

func (c ClientCapabilities) SupportsBooleanConfigOptions() bool

SupportsBooleanConfigOptions reports whether the client advertised clientCapabilities.session.configOptions.boolean.

type ClientFactory added in v0.36.0

type ClientFactory func(conn *ClientSideConnection) Client

type ClientSessionCapabilities added in v0.36.0

type ClientSessionCapabilities struct {
	ConfigOptions *SessionConfigOptionsCapabilities `json:"configOptions,omitempty"`
	Meta          json.RawMessage                   `json:"_meta,omitempty"`
}

ClientSessionCapabilities mirrors the spec's clientCapabilities.session.

type ClientSideConnection added in v0.36.0

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

ClientSideConnection is the editor-side mirror of AgentSideConnection (conn.go): it dispatches incoming agent->client requests (session/request_ permission, fs/*, terminal/*) and the session/update notification to a Client, and exposes the client->agent methods (initialize, session/new, session/prompt, ...) as outbound calls. The wire framing, id correlation, and shutdown behavior are the same design as AgentSideConnection; see that file's comments for the rationale behind each piece.

func NewClientSideConnection added in v0.36.0

func NewClientSideConnection(rw io.ReadWriteCloser, factory ClientFactory) *ClientSideConnection

func (*ClientSideConnection) Authenticate added in v0.36.0

func (*ClientSideConnection) CallExtMethod added in v0.36.0

func (c *ClientSideConnection) CallExtMethod(ctx context.Context, method string, params json.RawMessage) (json.RawMessage, error)

CallExtMethod sends a custom extension request (method must satisfy IsExtensionMethod) to the agent and returns its raw result. This is the outbound half of the extension-method seam; SetExtRequestHandler installs the inbound half. Mirrors AgentSideConnection.CallExtMethod (conn.go).

func (*ClientSideConnection) CancelPrompt added in v0.36.0

func (c *ClientSideConnection) CancelPrompt(sessionID SessionID) error

CancelPrompt cancels sessionID's in-flight prompt turn: it sends "session/cancel" and, for as long as this session's Prompt call remains outstanding, makes this connection auto-resolve every session/request_permission request for sessionID — new or already in-flight — with the "cancelled" outcome, instead of invoking (new requests) or waiting on (in-flight requests) the application's Client.RequestPermission.

This implements the client-side half of prompt-turn.mdx's cancellation contract: "The Client MUST respond to all pending session/request_permission requests with the cancelled outcome." The auto-resolve mark is cleared the moment the Prompt call for sessionID returns, so it never leaks into a later, unrelated turn on the same session.

If no Prompt call for sessionID is currently outstanding on this connection, CancelPrompt behaves exactly like CancelSession: there is nothing to mark or force-resolve.

func (*ClientSideConnection) CancelSession added in v0.36.0

func (c *ClientSideConnection) CancelSession(req CancelNotification) error

CancelSession sends "session/cancel" — a notification, not a request, per spec: the agent MUST resolve the in-flight session/prompt call with stop reason "cancelled" rather than answering this call itself.

CancelSession does not by itself apply the pending-permission auto-cancel rule (see CancelPrompt); use CancelPrompt when cancelling an active prompt turn started through this connection's Prompt method.

func (*ClientSideConnection) CloseErr added in v0.36.0

func (c *ClientSideConnection) CloseErr() error

func (*ClientSideConnection) CloseSession added in v0.36.0

func (*ClientSideConnection) Closed added in v0.36.0

func (c *ClientSideConnection) Closed() <-chan struct{}

func (*ClientSideConnection) DeleteSession added in v0.36.0

func (*ClientSideConnection) Initialize added in v0.36.0

func (*ClientSideConnection) ListSessions added in v0.36.0

func (*ClientSideConnection) LoadSession added in v0.36.0

func (*ClientSideConnection) Logout added in v0.36.0

Logout is only meaningful when the agent advertised AgentCapabilities.Auth.Logout during initialize.

func (*ClientSideConnection) NewSession added in v0.36.0

func (*ClientSideConnection) Prompt added in v0.36.0

Prompt registers req.SessionID's turn in promptTurns for the duration of the call, so CancelPrompt can find it (to mark it for the pending-permission auto-cancel rule) and so a subsequent session/request_permission request can be checked against it via promptCancelling. The entry is removed when this call returns — by which point the turn, cancelled or not, is over — deleting it only if it is still this call's own entry (pointer identity), so it can never remove a later, overlapping Prompt call's registration for the same session.

func (*ClientSideConnection) ResumeSession added in v0.36.0

func (*ClientSideConnection) Run added in v0.36.0

func (*ClientSideConnection) SendExtNotification added in v0.36.0

func (c *ClientSideConnection) SendExtNotification(method string, params json.RawMessage) error

SendExtNotification sends a custom, fire-and-forget extension notification (method must satisfy IsExtensionMethod) to the agent. Mirrors AgentSideConnection.SendExtNotification (conn.go).

func (*ClientSideConnection) SetExtNotificationHandler added in v0.36.0

func (c *ClientSideConnection) SetExtNotificationHandler(h ExtNotificationHandler)

SetExtNotificationHandler installs h to handle inbound extension notifications. Call it from the ClientFactory, before Run starts reading. A nil h (the default) leaves extension notifications silently ignored, exactly as before this seam existed. Mirrors AgentSideConnection.SetExtNotificationHandler (conn.go).

func (*ClientSideConnection) SetExtRequestHandler added in v0.36.0

func (c *ClientSideConnection) SetExtRequestHandler(h ExtRequestHandler)

SetExtRequestHandler installs h to handle inbound extension requests (method names starting with ExtensionMethodPrefix that fall outside the core ACP method set). Call it from the ClientFactory, before Run starts reading. A nil h (the default) leaves extension requests answered with MethodNotFound, exactly as before this seam existed. Mirrors AgentSideConnection.SetExtRequestHandler (conn.go).

func (*ClientSideConnection) SetSessionConfigOption added in v0.36.0

func (*ClientSideConnection) SetSessionMode added in v0.36.0

SetSessionMode switches a session to a different SessionMode.ID, one of the ids the session's SessionModeState.AvailableModes advertised.

func (*ClientSideConnection) SetSessionModel added in v0.36.0

SetSessionModel switches a session to a different ModelInfo.ID, one of the ids the session's SessionModelState.AvailableModels advertised. This is the UNSTABLE Zed model-picker surface (session/set_model, see MethodSessionSetModel) — Zed's claude-code-acp adapter exposes it as `unstable_setSessionModel`; it is not part of the stable ACP spec and MAY change. On success the requested model is authoritative (the response carries no state, and no session/update kind exists to reconfirm it).

type CloseSessionRequest added in v0.36.0

type CloseSessionRequest struct {
	SessionID SessionID       `json:"sessionId"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

type CloseSessionResponse added in v0.36.0

type CloseSessionResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type ContentBlock

type ContentBlock struct {
	Type        string            `json:"type"`
	Text        string            `json:"text,omitempty"`
	Data        string            `json:"data,omitempty"`
	MimeType    string            `json:"mimeType,omitempty"`
	URI         string            `json:"uri,omitempty"`
	Name        string            `json:"name,omitempty"`
	Title       string            `json:"title,omitempty"`
	Description string            `json:"description,omitempty"`
	Size        *int64            `json:"size,omitempty"`
	Resource    *EmbeddedResource `json:"resource,omitempty"`
	Annotations *Annotations      `json:"annotations,omitempty"`
	Meta        json.RawMessage   `json:"_meta,omitempty"`
}

func NewImageContent

func NewImageContent(data, mimeType string) ContentBlock

func NewResourceContent

func NewResourceContent(resource EmbeddedResource) ContentBlock
func NewResourceLink(uri, name string) ContentBlock

func NewTextContent

func NewTextContent(text string) ContentBlock

type ContentKind

type ContentKind string
const (
	ContentKindText         ContentKind = "text"
	ContentKindImage        ContentKind = "image"
	ContentKindAudio        ContentKind = "audio"
	ContentKindResource     ContentKind = "resource"
	ContentKindResourceLink ContentKind = "resource_link"
)

type CreateTerminalRequest

type CreateTerminalRequest struct {
	SessionID       SessionID       `json:"sessionId"`
	Command         string          `json:"command"`
	Args            []string        `json:"args,omitempty"`
	Env             []EnvVariable   `json:"env,omitempty"`
	Cwd             string          `json:"cwd,omitempty"`
	OutputByteLimit *int64          `json:"outputByteLimit,omitempty"`
	Meta            json.RawMessage `json:"_meta,omitempty"`
}

type CreateTerminalResponse

type CreateTerminalResponse struct {
	TerminalID string          `json:"terminalId"`
	Meta       json.RawMessage `json:"_meta,omitempty"`
}

type DeleteSessionRequest added in v0.36.0

type DeleteSessionRequest struct {
	SessionID SessionID       `json:"sessionId"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

type DeleteSessionResponse added in v0.36.0

type DeleteSessionResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type EmbeddedResource

type EmbeddedResource struct {
	URI      string          `json:"uri"`
	MimeType string          `json:"mimeType,omitempty"`
	Text     string          `json:"text,omitempty"`
	Blob     string          `json:"blob,omitempty"`
	Meta     json.RawMessage `json:"_meta,omitempty"`
}

type EnvVariable

type EnvVariable struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type Error

type Error struct {
	Code    int             `json:"code"`
	Message string          `json:"message"`
	Data    json.RawMessage `json:"data,omitempty"`
}

func AsError

func AsError(err error) *Error

func InternalError

func InternalError(msg string) *Error

func InvalidParams

func InvalidParams(msg string) *Error

func InvalidRequest

func InvalidRequest(msg string) *Error

func MethodNotFound

func MethodNotFound(method string) *Error

func NewError

func NewError(code int, message string) *Error

func NewErrorf

func NewErrorf(code int, format string, args ...any) *Error

func ParseError

func ParseError(msg string) *Error

func (*Error) Error

func (e *Error) Error() string

type ExtNotificationHandler added in v0.36.0

type ExtNotificationHandler func(ctx context.Context, method string, params json.RawMessage)

ExtNotificationHandler handles an inbound extension notification — fire-and-forget, matching the spec's "implementations SHOULD ignore unrecognized notifications" for anything it doesn't recognize itself.

See ExtNotification in the ACP schema (v1) and protocol docs: https://agentclientprotocol.com/protocol/extensibility

type ExtRequestHandler added in v0.36.0

type ExtRequestHandler func(ctx context.Context, method string, params json.RawMessage) (json.RawMessage, *Error)

ExtRequestHandler handles an inbound extension request: a JSON-RPC request whose method is not part of the core ACP method set but is extension- eligible (IsExtensionMethod). params is the request's raw, unparsed params exactly as received (nil if the request omitted them) — extension methods define their own wire schema, so libacp does not attempt to interpret them. A handler returns either a raw JSON result or an *Error, mirroring how a core method handler returns (response, error): both are written back through the same JSON-RPC result/error machinery, and the request participates in "$/cancel_request" cancellation via ctx like any other inbound request.

See ExtRequest/ExtResponse in the ACP schema (v1) and protocol docs: https://agentclientprotocol.com/protocol/extensibility

type FileSystemCapabilities

type FileSystemCapabilities struct {
	ReadTextFile  bool            `json:"readTextFile,omitempty"`
	WriteTextFile bool            `json:"writeTextFile,omitempty"`
	Meta          json.RawMessage `json:"_meta,omitempty"`
}

type HttpHeader

type HttpHeader struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type Implementation

type Implementation struct {
	Name    string `json:"name"`
	Title   string `json:"title,omitempty"`
	Version string `json:"version,omitempty"`
}

type Incoming

type Incoming struct {
	Kind         IncomingKind
	Request      Request
	Notification Notification
	Response     Response
}

func ParseIncoming

func ParseIncoming(data []byte) (Incoming, error)

type IncomingKind

type IncomingKind uint8
const (
	IncomingKindUnknown IncomingKind = iota
	IncomingKindRequest
	IncomingKindNotification
	IncomingKindResponse
)

type InitializeRequest

type InitializeRequest struct {
	ProtocolVersion    int                `json:"protocolVersion"`
	ClientCapabilities ClientCapabilities `json:"clientCapabilities,omitempty"`
	ClientInfo         *Implementation    `json:"clientInfo,omitempty"`
	Meta               json.RawMessage    `json:"_meta,omitempty"`
}

type InitializeResponse

type InitializeResponse struct {
	ProtocolVersion   int               `json:"protocolVersion"`
	AgentCapabilities AgentCapabilities `json:"agentCapabilities,omitempty"`
	AgentInfo         *Implementation   `json:"agentInfo,omitempty"`
	AuthMethods       []AuthMethod      `json:"authMethods,omitempty"`
	Meta              json.RawMessage   `json:"_meta,omitempty"`
}

type KillTerminalRequest

type KillTerminalRequest struct {
	SessionID  SessionID       `json:"sessionId"`
	TerminalID string          `json:"terminalId"`
	Meta       json.RawMessage `json:"_meta,omitempty"`
}

type KillTerminalResponse

type KillTerminalResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type ListSessionsRequest

type ListSessionsRequest struct {
	Cwd    string          `json:"cwd,omitempty"`
	Cursor string          `json:"cursor,omitempty"`
	Meta   json.RawMessage `json:"_meta,omitempty"`
}

type ListSessionsResponse

type ListSessionsResponse struct {
	Sessions   []SessionInfo   `json:"sessions"`
	NextCursor string          `json:"nextCursor,omitempty"`
	Meta       json.RawMessage `json:"_meta,omitempty"`
}

type LoadSessionRequest

type LoadSessionRequest struct {
	SessionID SessionID `json:"sessionId"`
	Cwd       string    `json:"cwd"`
	// AdditionalDirectories are extra workspace roots to activate for this
	// session, on top of Cwd. Each path must be absolute. Omitted or empty
	// means none.
	AdditionalDirectories []string        `json:"additionalDirectories,omitempty"`
	McpServers            []McpServer     `json:"mcpServers"`
	Meta                  json.RawMessage `json:"_meta,omitempty"`
}

type LoadSessionResponse

type LoadSessionResponse struct {
	Modes         *SessionModeState     `json:"modes,omitempty"`
	Models        *SessionModelState    `json:"models,omitempty"`
	ConfigOptions []SessionConfigOption `json:"configOptions,omitempty"`
	Meta          json.RawMessage       `json:"_meta,omitempty"`
}

type LogoutCapabilities added in v0.36.0

type LogoutCapabilities struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

LogoutCapabilities is present ({}) when the agent supports the `logout` method.

type LogoutRequest added in v0.36.0

type LogoutRequest struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

LogoutRequest terminates the current authenticated session. Only meaningful when the agent advertises AgentCapabilities.Auth.Logout.

type LogoutResponse added in v0.36.0

type LogoutResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type McpCapabilities

type McpCapabilities struct {
	HTTP bool            `json:"http,omitempty"`
	SSE  bool            `json:"sse,omitempty"`
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type McpServer

type McpServer struct {
	Type    string          `json:"type,omitempty"`
	Name    string          `json:"name"`
	Command string          `json:"command,omitempty"`
	Args    []string        `json:"args,omitempty"`
	Env     []EnvVariable   `json:"env,omitempty"`
	URL     string          `json:"url,omitempty"`
	Headers []HttpHeader    `json:"headers,omitempty"`
	Meta    json.RawMessage `json:"_meta,omitempty"`
}

func (McpServer) Kind

func (m McpServer) Kind() McpServerKind

func (McpServer) MarshalJSON added in v0.36.0

func (m McpServer) MarshalJSON() ([]byte, error)

MarshalJSON forces args/env (McpServerStdio) and headers (McpServerHttp/ McpServerSse) onto the wire as `[]` rather than omitting them when empty: the spec (and the reference Rust implementation) declares these fields as plain, always-serialized arrays with no default, so a strict receiver rejects a payload missing them. omitempty alone cannot express this on the flattened McpServer struct — it treats a zero-length slice as absent regardless of nil-ness — hence the two per-transport wire shapes below.

func (McpServer) Validate

func (m McpServer) Validate() error

type McpServerKind

type McpServerKind string
const (
	McpServerKindStdio McpServerKind = ""
	McpServerKindHTTP  McpServerKind = "http"
	McpServerKindSSE   McpServerKind = "sse"
)

type ModelInfo added in v0.36.0

type ModelInfo struct {
	ID          string          `json:"modelId"`
	Name        string          `json:"name"`
	Description string          `json:"description,omitempty"`
	Meta        json.RawMessage `json:"_meta,omitempty"`
}

ModelInfo describes a single selectable model in a SessionModelState. ID is the stable identifier passed back in SetSessionModelRequest; Name is the human-readable label. Part of the UNSTABLE Zed model-picker surface. Note that this surface carries no effort/fast-mode facet — a model entry is id + name + optional description only; reasoning-effort controls (if any) live elsewhere, not in this state.

type NewSessionRequest

type NewSessionRequest struct {
	Cwd string `json:"cwd"`
	// AdditionalDirectories are extra workspace roots for this session, on top
	// of Cwd. Each path must be absolute. Omitted or empty means none.
	AdditionalDirectories []string        `json:"additionalDirectories,omitempty"`
	McpServers            []McpServer     `json:"mcpServers"`
	Meta                  json.RawMessage `json:"_meta,omitempty"`
}

type NewSessionResponse

type NewSessionResponse struct {
	SessionID SessionID         `json:"sessionId"`
	Modes     *SessionModeState `json:"modes,omitempty"`
	// Models is the UNSTABLE Zed model-picker surface (session/set_model + the
	// `models` state, see SessionModelState) an agent MAY advertise in its
	// session/new response. Omitted (nil) means the agent exposes no selectable
	// model, the byte-identical spec-conformant default.
	Models        *SessionModelState    `json:"models,omitempty"`
	ConfigOptions []SessionConfigOption `json:"configOptions,omitempty"`
	Meta          json.RawMessage       `json:"_meta,omitempty"`
}

type Notification

type Notification struct {
	JSONRPC string          `json:"jsonrpc"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params,omitempty"`
}

func NewNotification

func NewNotification(method string, params json.RawMessage) Notification

type PermissionOption

type PermissionOption struct {
	OptionID string               `json:"optionId"`
	Name     string               `json:"name"`
	Kind     PermissionOptionKind `json:"kind"`
	Meta     json.RawMessage      `json:"_meta,omitempty"`
}

type PermissionOptionKind

type PermissionOptionKind string
const (
	PermissionAllowOnce    PermissionOptionKind = "allow_once"
	PermissionAllowAlways  PermissionOptionKind = "allow_always"
	PermissionRejectOnce   PermissionOptionKind = "reject_once"
	PermissionRejectAlways PermissionOptionKind = "reject_always"
)

type PermissionOutcomeKind

type PermissionOutcomeKind string
const (
	PermissionOutcomeCancelled PermissionOutcomeKind = "cancelled"
	PermissionOutcomeSelected  PermissionOutcomeKind = "selected"
)

type PermissionToolCall

type PermissionToolCall struct {
	ToolCallID string             `json:"toolCallId"`
	Title      string             `json:"title,omitempty"`
	Kind       ToolKind           `json:"kind,omitempty"`
	Status     ToolCallStatus     `json:"status,omitempty"`
	Content    []ToolCallContent  `json:"content,omitempty"`
	Locations  []ToolCallLocation `json:"locations,omitempty"`
	RawInput   json.RawMessage    `json:"rawInput,omitempty"`
	RawOutput  json.RawMessage    `json:"rawOutput,omitempty"`
	Meta       json.RawMessage    `json:"_meta,omitempty"`
}

type PlanEntry

type PlanEntry struct {
	Content  string            `json:"content"`
	Priority PlanEntryPriority `json:"priority"`
	Status   PlanEntryStatus   `json:"status"`
	Meta     json.RawMessage   `json:"_meta,omitempty"`
}

type PlanEntryPriority

type PlanEntryPriority string
const (
	PlanPriorityHigh   PlanEntryPriority = "high"
	PlanPriorityMedium PlanEntryPriority = "medium"
	PlanPriorityLow    PlanEntryPriority = "low"
)

type PlanEntryStatus

type PlanEntryStatus string
const (
	PlanStatusPending    PlanEntryStatus = "pending"
	PlanStatusInProgress PlanEntryStatus = "in_progress"
	PlanStatusCompleted  PlanEntryStatus = "completed"
)

type PromptCapabilities

type PromptCapabilities struct {
	Image           bool            `json:"image,omitempty"`
	Audio           bool            `json:"audio,omitempty"`
	EmbeddedContext bool            `json:"embeddedContext,omitempty"`
	Meta            json.RawMessage `json:"_meta,omitempty"`
}

type PromptRequest

type PromptRequest struct {
	SessionID SessionID       `json:"sessionId"`
	Prompt    []ContentBlock  `json:"prompt"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

type PromptResponse

type PromptResponse struct {
	StopReason StopReason      `json:"stopReason"`
	Meta       json.RawMessage `json:"_meta,omitempty"`
}

PromptResponse is the result of a "session/prompt" request. Per the ACP v1 schema it carries only stopReason and _meta — a prior revision added a non-spec "usage" field (per-turn token counts) directly at the type's root, which extensibility.mdx forbids: "Implementations MUST NOT add any custom fields at the root of a type that's part of the specification." It was removed rather than migrated into _meta because nothing in this repo produced or consumed it: acpsvc never populated it, and the beam client only ever destructured stopReason from the call result. Session context/cost reporting already has a sanctioned, fully wired channel — the "usage_update" SessionUpdate (see SessionUpdateUsageUpdate) — which is where that data belongs and is already emitted (see acpsvc's sendInitialUsageUpdate and its translateEvents usage_update path).

type ReadTextFileRequest

type ReadTextFileRequest struct {
	SessionID SessionID       `json:"sessionId"`
	Path      string          `json:"path"`
	Line      *int            `json:"line,omitempty"`
	Limit     *int            `json:"limit,omitempty"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

type ReadTextFileResponse

type ReadTextFileResponse struct {
	Content string          `json:"content"`
	Meta    json.RawMessage `json:"_meta,omitempty"`
}

type ReleaseTerminalRequest

type ReleaseTerminalRequest struct {
	SessionID  SessionID       `json:"sessionId"`
	TerminalID string          `json:"terminalId"`
	Meta       json.RawMessage `json:"_meta,omitempty"`
}

type ReleaseTerminalResponse

type ReleaseTerminalResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type Request

type Request struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      RequestID       `json:"id"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params,omitempty"`
}

func NewRequest

func NewRequest(id RequestID, method string, params json.RawMessage) Request

type RequestID

type RequestID struct {
	Kind   RequestIDKind
	Number int64
	String string
}

func NewRequestIDNull

func NewRequestIDNull() RequestID

func NewRequestIDNumber

func NewRequestIDNumber(n int64) RequestID

func NewRequestIDString

func NewRequestIDString(s string) RequestID

func (RequestID) Equal

func (r RequestID) Equal(other RequestID) bool

func (RequestID) MarshalJSON

func (r RequestID) MarshalJSON() ([]byte, error)

func (RequestID) String_

func (r RequestID) String_() string

func (*RequestID) UnmarshalJSON

func (r *RequestID) UnmarshalJSON(data []byte) error

type RequestIDKind

type RequestIDKind uint8
const (
	RequestIDKindNull RequestIDKind = iota
	RequestIDKindNumber
	RequestIDKindString
)

type RequestPermissionOutcome

type RequestPermissionOutcome struct {
	Outcome  PermissionOutcomeKind `json:"outcome"`
	OptionID string                `json:"optionId,omitempty"`
}

func (*RequestPermissionOutcome) UnmarshalJSON

func (o *RequestPermissionOutcome) UnmarshalJSON(data []byte) error

type RequestPermissionRequest

type RequestPermissionRequest struct {
	SessionID SessionID          `json:"sessionId"`
	ToolCall  PermissionToolCall `json:"toolCall"`
	Options   []PermissionOption `json:"options"`
	Meta      json.RawMessage    `json:"_meta,omitempty"`
}

type RequestPermissionResponse

type RequestPermissionResponse struct {
	Outcome RequestPermissionOutcome `json:"outcome"`
	Meta    json.RawMessage          `json:"_meta,omitempty"`
}

type Response

type Response struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      RequestID       `json:"id"`
	Result  json.RawMessage `json:"result,omitempty"`
	Error   *Error          `json:"error,omitempty"`
}

func NewErrorResponse

func NewErrorResponse(id RequestID, err *Error) Response

func NewResultResponse

func NewResultResponse(id RequestID, result json.RawMessage) Response

type ResumeSessionRequest added in v0.36.0

type ResumeSessionRequest struct {
	SessionID SessionID `json:"sessionId"`
	Cwd       string    `json:"cwd"`
	// AdditionalDirectories are extra workspace roots to activate for this
	// session, on top of Cwd. Each path must be absolute. Omitted or empty
	// means none.
	AdditionalDirectories []string        `json:"additionalDirectories,omitempty"`
	McpServers            []McpServer     `json:"mcpServers,omitempty"`
	Meta                  json.RawMessage `json:"_meta,omitempty"`
}

ResumeSessionRequest reconnects to an existing session WITHOUT history replay (the client kept its transcript). McpServers is optional here, unlike session/new and session/load.

type ResumeSessionResponse added in v0.36.0

type ResumeSessionResponse struct {
	Modes         *SessionModeState     `json:"modes,omitempty"`
	Models        *SessionModelState    `json:"models,omitempty"`
	ConfigOptions []SessionConfigOption `json:"configOptions,omitempty"`
	Meta          json.RawMessage       `json:"_meta,omitempty"`
}

type SessionCapabilities

type SessionCapabilities struct {
	List   *struct{} `json:"list,omitempty"`
	Resume *struct{} `json:"resume,omitempty"`
	Close  *struct{} `json:"close,omitempty"`
	Delete *struct{} `json:"delete,omitempty"`
	// AdditionalDirectories present ({}) means the agent honors
	// additionalDirectories on session/new, session/load, and session/resume,
	// and may report SessionInfo.AdditionalDirectories from session/list.
	AdditionalDirectories *struct{}       `json:"additionalDirectories,omitempty"`
	Meta                  json.RawMessage `json:"_meta,omitempty"`
}

type SessionConfigGroup added in v0.29.0

type SessionConfigGroup struct {
	Group   string               `json:"group"`
	Name    string               `json:"name"`
	Options []SessionConfigValue `json:"options"`
	Meta    json.RawMessage      `json:"_meta,omitempty"`
}

type SessionConfigOption added in v0.29.0

type SessionConfigOption struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Category    string `json:"category,omitempty"`
	Type        string `json:"type"`
	// CurrentValue is always the Go-side string form: for
	// SessionConfigOptionTypeSelect it is the selected SessionConfigValue.Value
	// id; for SessionConfigOptionTypeBoolean it is "true"/"false" (mirroring
	// SessionConfigOptionValue.AsString). MarshalJSON renders it as a JSON
	// boolean on the wire for the boolean type, as SessionConfigBoolean
	// requires; UnmarshalJSON accepts either wire shape back into this string.
	CurrentValue string              `json:"currentValue"`
	Options      SessionConfigValues `json:"options"`
	Meta         json.RawMessage     `json:"_meta,omitempty"`
}

func (SessionConfigOption) MarshalJSON added in v0.36.0

func (o SessionConfigOption) MarshalJSON() ([]byte, error)

func (*SessionConfigOption) UnmarshalJSON added in v0.36.0

func (o *SessionConfigOption) UnmarshalJSON(data []byte) error

type SessionConfigOptionValue added in v0.36.0

type SessionConfigOptionValue struct {
	IsBool bool
	Str    string
	Bool   bool
}

SessionConfigOptionValue is the value union of session/set_config_option: a plain string value id (default) or a boolean (request Type "boolean").

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/contenox/runtime/libacp"
)

func main() {
	var req libacp.SetSessionConfigOptionRequest
	_ = json.Unmarshal([]byte(`{"sessionId":"s","configId":"c","value":"model-x"}`), &req)
	fmt.Println(req.Value.AsString(), req.Value.IsBool)

	_ = json.Unmarshal([]byte(`{"sessionId":"s","configId":"c","type":"boolean","value":true}`), &req)
	fmt.Println(req.Value.AsString(), req.Value.IsBool)
}
Output:
model-x false
true true

func BoolConfigValue added in v0.36.0

func BoolConfigValue(b bool) SessionConfigOptionValue

func StringConfigValue added in v0.36.0

func StringConfigValue(s string) SessionConfigOptionValue

func (SessionConfigOptionValue) AsString added in v0.36.0

func (v SessionConfigOptionValue) AsString() string

AsString renders the value for consumers that key handling off strings; booleans become "true"/"false".

func (SessionConfigOptionValue) MarshalJSON added in v0.36.0

func (v SessionConfigOptionValue) MarshalJSON() ([]byte, error)

func (*SessionConfigOptionValue) UnmarshalJSON added in v0.36.0

func (v *SessionConfigOptionValue) UnmarshalJSON(data []byte) error

type SessionConfigOptionsCapabilities added in v0.36.0

type SessionConfigOptionsCapabilities struct {
	// Boolean present ({}) means the client accepts type:"boolean" config
	// options and may send boolean set_config_option values.
	Boolean *struct{}       `json:"boolean,omitempty"`
	Meta    json.RawMessage `json:"_meta,omitempty"`
}

type SessionConfigValue added in v0.29.0

type SessionConfigValue struct {
	Value       string          `json:"value"`
	Name        string          `json:"name"`
	Description string          `json:"description,omitempty"`
	Meta        json.RawMessage `json:"_meta,omitempty"`
}

type SessionConfigValues added in v0.29.0

type SessionConfigValues struct {
	Values []SessionConfigValue
	Groups []SessionConfigGroup
}

func NewGroupedSessionConfigValues added in v0.29.0

func NewGroupedSessionConfigValues(groups []SessionConfigGroup) SessionConfigValues

func NewSessionConfigValues added in v0.29.0

func NewSessionConfigValues(values []SessionConfigValue) SessionConfigValues

func (SessionConfigValues) AllValues added in v0.29.0

func (v SessionConfigValues) AllValues() []SessionConfigValue

func (SessionConfigValues) MarshalJSON added in v0.29.0

func (v SessionConfigValues) MarshalJSON() ([]byte, error)

func (*SessionConfigValues) UnmarshalJSON added in v0.29.0

func (v *SessionConfigValues) UnmarshalJSON(data []byte) error

type SessionID

type SessionID string

type SessionInfo

type SessionInfo struct {
	SessionID SessionID `json:"sessionId"`
	Cwd       string    `json:"cwd,omitempty"`
	// AdditionalDirectories is the complete ordered additional-root list
	// associated with this session, when the agent tracks and reports it.
	AdditionalDirectories []string        `json:"additionalDirectories,omitempty"`
	Title                 string          `json:"title,omitempty"`
	UpdatedAt             string          `json:"updatedAt,omitempty"`
	Meta                  json.RawMessage `json:"_meta,omitempty"`
}

type SessionMode

type SessionMode struct {
	ID          string          `json:"id"`
	Name        string          `json:"name"`
	Description string          `json:"description,omitempty"`
	Meta        json.RawMessage `json:"_meta,omitempty"`
}

type SessionModeState added in v0.36.0

type SessionModeState struct {
	CurrentModeID  string          `json:"currentModeId"`
	AvailableModes []SessionMode   `json:"availableModes"`
	Meta           json.RawMessage `json:"_meta,omitempty"`
}

SessionModeState is the spec's wire shape for `modes` in session/new and session/load responses: an object carrying the current mode id plus the available modes, not a bare array.

type SessionModelState added in v0.36.0

type SessionModelState struct {
	CurrentModelID  string          `json:"currentModelId"`
	AvailableModels []ModelInfo     `json:"availableModels"`
	Meta            json.RawMessage `json:"_meta,omitempty"`
}

SessionModelState is the UNSTABLE Zed model-picker surface: the wire shape of the optional `models` field in session/new, session/load, and session/resume responses. It carries the current model id plus the set of selectable models, mirroring SessionModeState for modes. This is an experimental extension (the client-side driver invokes it as `unstable_setSessionModel` and it is dispatched over the `session/set_model` method — see MethodSessionSetModel); it is not part of the stable ACP spec and MAY change.

type SessionNotification

type SessionNotification struct {
	SessionID SessionID       `json:"sessionId"`
	Update    SessionUpdate   `json:"update"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

type SessionUpdate

type SessionUpdate struct {
	SessionUpdate SessionUpdateKind `json:"sessionUpdate"`

	Content *ContentBlock `json:"-"`

	ToolCallID  string             `json:"toolCallId,omitempty"`
	Title       string             `json:"title,omitempty"`
	Kind        ToolKind           `json:"kind,omitempty"`
	Status      ToolCallStatus     `json:"status,omitempty"`
	ToolContent []ToolCallContent  `json:"-"`
	Locations   []ToolCallLocation `json:"locations,omitempty"`
	RawInput    json.RawMessage    `json:"rawInput,omitempty"`
	RawOutput   json.RawMessage    `json:"rawOutput,omitempty"`

	Entries []PlanEntry `json:"entries,omitempty"`

	AvailableCommands []AvailableCommand `json:"availableCommands,omitempty"`

	CurrentModeID string `json:"currentModeId,omitempty"`

	ConfigOptions []SessionConfigOption `json:"configOptions,omitempty"`

	// For usage_update (ACP session context indicator)
	Used int        `json:"used,omitempty"`
	Size int        `json:"size,omitempty"`
	Cost *UsageCost `json:"cost,omitempty"`

	// MessageID groups streamed chunks into messages: all chunks of one message
	// share an id; a change marks a new message. Optional in the spec.
	MessageID string `json:"messageId,omitempty"`

	// UpdatedAt is the session_info_update timestamp (ISO 8601); Title above is
	// shared with tool_call updates (same wire key).
	UpdatedAt string `json:"updatedAt,omitempty"`

	Meta json.RawMessage `json:"_meta,omitempty"`
}

func NewAgentMessageChunk

func NewAgentMessageChunk(text string) SessionUpdate

func NewAgentThoughtChunk

func NewAgentThoughtChunk(text string) SessionUpdate

func NewUserMessageChunk

func NewUserMessageChunk(text string) SessionUpdate

func (SessionUpdate) MarshalJSON

func (u SessionUpdate) MarshalJSON() ([]byte, error)

func (*SessionUpdate) UnmarshalJSON

func (u *SessionUpdate) UnmarshalJSON(data []byte) error

type SessionUpdateKind

type SessionUpdateKind string
const (
	SessionUpdateUserMessageChunk  SessionUpdateKind = "user_message_chunk"
	SessionUpdateAgentMessageChunk SessionUpdateKind = "agent_message_chunk"
	SessionUpdateAgentThoughtChunk SessionUpdateKind = "agent_thought_chunk"
	SessionUpdateToolCall          SessionUpdateKind = "tool_call"
	SessionUpdateToolCallUpdate    SessionUpdateKind = "tool_call_update"
	SessionUpdatePlan              SessionUpdateKind = "plan"
	SessionUpdateAvailableCommands SessionUpdateKind = "available_commands_update"
	SessionUpdateCurrentMode       SessionUpdateKind = "current_mode_update"
	SessionUpdateConfigOption      SessionUpdateKind = "config_option_update"
	SessionUpdateUsageUpdate       SessionUpdateKind = "usage_update"
	SessionUpdateSessionInfo       SessionUpdateKind = "session_info_update"
)

type SetSessionConfigOptionRequest added in v0.29.0

type SetSessionConfigOptionRequest struct {
	SessionID SessionID `json:"sessionId"`
	ConfigID  string    `json:"configId"`
	// Type discriminates the value variant: absent/unknown means Value is a
	// string value id (the default), "boolean" means Value is a bool.
	Type  string                   `json:"type,omitempty"`
	Value SessionConfigOptionValue `json:"value"`
	Meta  json.RawMessage          `json:"_meta,omitempty"`
}

type SetSessionConfigOptionResponse added in v0.29.0

type SetSessionConfigOptionResponse struct {
	ConfigOptions []SessionConfigOption `json:"configOptions"`
	Meta          json.RawMessage       `json:"_meta,omitempty"`
}

type SetSessionModeRequest added in v0.36.0

type SetSessionModeRequest struct {
	SessionID SessionID       `json:"sessionId"`
	ModeID    string          `json:"modeId"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

SetSessionModeRequest is session/set_mode's params: switch a session to a different SessionMode.ID, one of the ids SessionModeState.AvailableModes advertised.

type SetSessionModeResponse added in v0.36.0

type SetSessionModeResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

type SetSessionModelRequest added in v0.36.0

type SetSessionModelRequest struct {
	SessionID SessionID       `json:"sessionId"`
	ModelID   string          `json:"modelId"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

SetSessionModelRequest is session/set_model's params: switch a session to a different ModelInfo.ID, one of the ids SessionModelState.AvailableModels advertised. Part of the UNSTABLE Zed model-picker surface (see MethodSessionSetModel); the client-side driver names it `unstable_setSessionModel`.

type SetSessionModelResponse added in v0.36.0

type SetSessionModelResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

SetSessionModelResponse is session/set_model's result: an empty object (the UNSTABLE surface carries no state back — the requested modelId is authoritative on success, and no session/update notification kind exists to reconfirm it).

type StopReason

type StopReason string
const (
	StopReasonEndTurn         StopReason = "end_turn"
	StopReasonMaxTokens       StopReason = "max_tokens"
	StopReasonMaxTurnRequests StopReason = "max_turn_requests"
	StopReasonRefusal         StopReason = "refusal"
	StopReasonCancelled       StopReason = "cancelled"
)

type TerminalExitStatus

type TerminalExitStatus struct {
	ExitCode *int    `json:"exitCode,omitempty"`
	Signal   *string `json:"signal,omitempty"`
}

type TerminalOutputRequest

type TerminalOutputRequest struct {
	SessionID  SessionID       `json:"sessionId"`
	TerminalID string          `json:"terminalId"`
	Meta       json.RawMessage `json:"_meta,omitempty"`
}

type TerminalOutputResponse

type TerminalOutputResponse struct {
	Output     string              `json:"output"`
	Truncated  bool                `json:"truncated"`
	ExitStatus *TerminalExitStatus `json:"exitStatus,omitempty"`
	Meta       json.RawMessage     `json:"_meta,omitempty"`
}

type ToolCallContent

type ToolCallContent struct {
	Type       ToolCallContentKind `json:"type"`
	Content    *ContentBlock       `json:"content,omitempty"`
	Path       string              `json:"path,omitempty"`
	OldText    string              `json:"oldText,omitempty"`
	NewText    string              `json:"newText,omitempty"`
	TerminalID string              `json:"terminalId,omitempty"`
	Meta       json.RawMessage     `json:"_meta,omitempty"`
}

func (ToolCallContent) MarshalJSON added in v0.36.0

func (c ToolCallContent) MarshalJSON() ([]byte, error)

MarshalJSON forces path/newText onto the wire for the "diff" variant even when empty — e.g. newText:"" is the correct (and spec-required) shape for a diff that clears a file's content, but plain omitempty can't distinguish that from "absent" for a string. Every other field, and every other ToolCallContent kind, keeps its normal omitempty behavior.

type ToolCallContentKind

type ToolCallContentKind string
const (
	ToolCallContentRegular  ToolCallContentKind = "content"
	ToolCallContentDiff     ToolCallContentKind = "diff"
	ToolCallContentTerminal ToolCallContentKind = "terminal"
)

type ToolCallLocation

type ToolCallLocation struct {
	Path string `json:"path"`
	Line *int   `json:"line,omitempty"`
}

type ToolCallStatus

type ToolCallStatus string
const (
	ToolCallStatusPending    ToolCallStatus = "pending"
	ToolCallStatusInProgress ToolCallStatus = "in_progress"
	ToolCallStatusCompleted  ToolCallStatus = "completed"
	ToolCallStatusFailed     ToolCallStatus = "failed"
)

type ToolKind

type ToolKind string
const (
	ToolKindRead       ToolKind = "read"
	ToolKindEdit       ToolKind = "edit"
	ToolKindDelete     ToolKind = "delete"
	ToolKindMove       ToolKind = "move"
	ToolKindSearch     ToolKind = "search"
	ToolKindExecute    ToolKind = "execute"
	ToolKindThink      ToolKind = "think"
	ToolKindFetch      ToolKind = "fetch"
	ToolKindSwitchMode ToolKind = "switch_mode"
	ToolKindOther      ToolKind = "other"
)

type TurnTracker added in v0.36.0

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

TurnTracker watches one prompt turn's session/update stream and tells a client-side driver whether the agent ever produced a renderable answer. It exists because an agent can return a perfectly normal session/prompt result while never emitting a single agent_message_chunk — the empty-response failure this repo fixed on the agent side, and the interop failure hash guards on the client side (noOutputPromptError, tmp/hash acp.go:979). A driver feeds each notification to Observe and, when the turn ends, calls Err to convert "nothing displayable" into an explicit ErrNoDisplayableOutput instead of surfacing an empty message. Opt-in and single-turn: construct a fresh one (or call Reset) per turn. Not safe for concurrent use; drive it from the same goroutine that consumes the turn's updates (the read loop).

func (*TurnTracker) Err added in v0.36.0

func (t *TurnTracker) Err(stop StopReason) error

Err returns nil when the turn produced displayable output, otherwise an ErrNoDisplayableOutput enriched with the turn's stop reason and tool-update count. Call it once the session/prompt result is in hand, passing that result's StopReason.

func (*TurnTracker) Observe added in v0.36.0

func (t *TurnTracker) Observe(n SessionNotification)

Observe records one inbound session/update. It only inspects the update payload; session-id matching (stale-update filtering) is a separate concern — see FilterSessionUpdates.

func (*TurnTracker) Reset added in v0.36.0

func (t *TurnTracker) Reset()

Reset returns the tracker to its zero state so it can be reused for the next turn on the same session.

func (*TurnTracker) SawDisplayableOutput added in v0.36.0

func (t *TurnTracker) SawDisplayableOutput() bool

SawDisplayableOutput reports whether any agent_message_chunk carrying renderable content has been observed this turn.

func (*TurnTracker) ToolUpdateCount added in v0.36.0

func (t *TurnTracker) ToolUpdateCount() int

ToolUpdateCount reports how many tool_call / tool_call_update notifications were observed. Reported inside Err so an operator can tell "tool activity but no final text" from "literally nothing" (hash captures the same count).

type UnimplementedAgent

type UnimplementedAgent struct{}

func (UnimplementedAgent) Authenticate

func (UnimplementedAgent) Cancel

func (UnimplementedAgent) CloseSession added in v0.36.0

func (UnimplementedAgent) DeleteSession added in v0.36.0

func (UnimplementedAgent) Initialize

func (UnimplementedAgent) ListSessions

func (UnimplementedAgent) LoadSession

func (UnimplementedAgent) Logout added in v0.36.0

func (UnimplementedAgent) NewSession

func (UnimplementedAgent) Prompt

func (UnimplementedAgent) ResumeSession added in v0.36.0

func (UnimplementedAgent) SetSessionConfigOption added in v0.29.0

func (UnimplementedAgent) SetSessionMode added in v0.36.0

func (UnimplementedAgent) SetSessionModel added in v0.36.0

type UnimplementedClient added in v0.36.0

type UnimplementedClient struct{}

UnimplementedClient rejects every request-shaped Client method with MethodNotFound and treats SessionUpdate as a no-op, mirroring UnimplementedAgent (agent.go). Embed it to implement only the methods a particular client cares about.

func (UnimplementedClient) CreateTerminal added in v0.36.0

func (UnimplementedClient) KillTerminal added in v0.36.0

func (UnimplementedClient) ReadTextFile added in v0.36.0

func (UnimplementedClient) ReleaseTerminal added in v0.36.0

func (UnimplementedClient) RequestPermission added in v0.36.0

func (UnimplementedClient) SessionUpdate added in v0.36.0

func (UnimplementedClient) TerminalOutput added in v0.36.0

func (UnimplementedClient) WaitForTerminalExit added in v0.36.0

func (UnimplementedClient) WriteTextFile added in v0.36.0

type UsageCost added in v0.34.0

type UsageCost struct {
	Amount   float64 `json:"amount"`
	Currency string  `json:"currency"`
}

type WaitForTerminalExitRequest

type WaitForTerminalExitRequest struct {
	SessionID  SessionID       `json:"sessionId"`
	TerminalID string          `json:"terminalId"`
	Meta       json.RawMessage `json:"_meta,omitempty"`
}

type WaitForTerminalExitResponse

type WaitForTerminalExitResponse struct {
	ExitCode *int            `json:"exitCode,omitempty"`
	Signal   *string         `json:"signal,omitempty"`
	Meta     json.RawMessage `json:"_meta,omitempty"`
}

type WriteTextFileRequest

type WriteTextFileRequest struct {
	SessionID SessionID       `json:"sessionId"`
	Path      string          `json:"path"`
	Content   string          `json:"content"`
	Meta      json.RawMessage `json:"_meta,omitempty"`
}

type WriteTextFileResponse

type WriteTextFileResponse struct {
	Meta json.RawMessage `json:"_meta,omitempty"`
}

Directories

Path Synopsis
Package acpexec spawns a subprocess and wires its stdin/stdout together as a single io.ReadWriteCloser, the transport shape libacp.NewAgentSideConnection and libacp.NewClientSideConnection both expect.
Package acpexec spawns a subprocess and wires its stdin/stdout together as a single io.ReadWriteCloser, the transport shape libacp.NewAgentSideConnection and libacp.NewClientSideConnection both expect.
cmd
acp-stub-agent command
Command acp-stub-agent is a hermetic ACP Agent used to validate libacp's agent-side wire dispatch (conn.go, agent.go) against the Rust conformance-checking clients (acp-validator, yopo) without needing any LLM backend.
Command acp-stub-agent is a hermetic ACP Agent used to validate libacp's agent-side wire dispatch (conn.go, agent.go) against the Rust conformance-checking clients (acp-validator, yopo) without needing any LLM backend.

Jump to

Keyboard shortcuts

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