SuperPi.ACP.Server (super_pi v0.1.0)

Copy Markdown View Source

Agent Client Protocol agent over stdio: bin/super-pi acp.

Editors (Zed, JetBrains, GitHub Copilot CLI, the neovim plugins) start the agent as a subprocess and speak JSON-RPC 2.0, one message per line. ACP is bidirectional: the agent also sends requests (session/request_permission, fs/read_text_file) and waits for the answer. So this is not SuperPi.RPC.Server: that module only replies and notifies and has no table of outstanding requests. Here a pending table maps each outgoing request id to what waits for it.

Methods

ACPSuper-Pi
initializeAgent capabilities, authMethods from Auth.required?/0, harness capabilities in _meta.superPi.harnesses
authenticateThe token store of auth.login (token in _meta.token or SUPER_PI_GATEWAY_TOKEN)
session/newA conversation with workspacePaths: [cwd]. _meta.harness picks the harness. mcpServers are applied to the MCP manager
session/loadResume (not fork): replays history as session/update notifications, then answers
_superpi/session/forkFork at the latest entry into a new session (ACP's _ convention for custom methods)
session/promptSubmits in a supervised task, so session/cancel can arrive during the prompt
session/cancelUI.Broker.cancel_pending/1, then Machine.cancel/1, in that order
session/set_modeSets executionMode within the remote ceiling and the harness ceiling

stopReason: end_turn for a finished turn, cancelled for a cancel, refusal for an error (the error text goes to the client as a message chunk first).

Terminals and files

terminal/* is never delegated: SandboxRunner gives process-group kill, output spill and the sandbox, and an editor terminal gives none of that and bypasses permissions.deny. A running command is a tool_call of kind execute.

config :super_pi, :acp, fs_delegation: :unsaved_only | :never | :always (default :unsaved_only). fs/read_text_file returns the unsaved editor buffer, the only reason to delegate. SuperPi.Env.ClientFS asks the client only when the client advertised the method, the machine runs on this node (the editor's files do not exist on another node) and the path is inside the workspace. Writes always stay on the server.

Transport

run_stdio/1 starts the server and reads standard input. Output is one JSON object per line on standard output, so logs must go to standard error (SUPER_PI_LOG_STDERR=1, set by bin/super-pi). For tests, start_link(send: fun) and send(server, {:acp_line, line}).

Summary

Functions

Returns a specification to start this module under a supervisor.

Asks the client for the text of a file, including unsaved changes. Used by SuperPi.Env.ClientFS.

Starts the server on standard input and output and returns when the input ends.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

read_text_file(server, conversation_id, path, opts \\ [])

@spec read_text_file(pid(), integer(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}

Asks the client for the text of a file, including unsaved changes. Used by SuperPi.Env.ClientFS.

run_stdio(opts \\ [])

Starts the server on standard input and output and returns when the input ends.

start_link(opts \\ [])