free-agent
Safe HaskellNone
LanguageGHC2024

Free.Agent.Acp

Description

ACP (Agent Client Protocol) JSON-RPC 2.0 NDJSON client over Process ends.

The wire: one JSON object per line on the child's stdout (no Content-Length headers); stdin takes the same framing; stderr is diagnostics, not protocol. Requests are id-correlated; notifications carry no id; kimi also issues reverse-RPC requests (with an id) that the client must answer.

Ground truth is the leg-1 probe (~/lab/acp-probe/report.md, kimi acp v0.33.0):

  • session/set_mode hangs — mode is switched with session/set_config_option {configId: "mode", value: "auto"}.
  • session/request_permission responses are broken in kimi 0.33.0; in auto mode file I/O arrives as fs/* reverse-RPCs instead.
  • fs/* params carry uri (with a file://// prefix), not the spec's path — both are accepted here.

Requests travel through the shared stdin commit port of StdPorts; replies are line-framed blocking reads from the stdout queue.

Synopsis

Configuration

data AcpConfig Source #

What to spawn and where the plumbing lives.

Constructors

AcpConfig 

Fields

Instances

Instances details
Eq AcpConfig Source # 
Instance details

Defined in Free.Agent.Acp

Show AcpConfig Source # 
Instance details

Defined in Free.Agent.Acp

defaultAcpConfig :: AcpConfig Source #

kimi acp with the child working directory at /tmp/free-agent-acp.

Client

data AcpClient Source #

A live ACP child process plus client-side protocol state.

Constructors

AcpClient 

Fields

openAcp :: AcpConfig -> IO AcpClient Source #

Spawn the ACP child and open the protocol state. Pipes all the way down: no FIFO, no log files — stdout frames arrive line by line on the blocking emit end.

closeAcp :: AcpClient -> IO () Source #

Terminate the child (kills the pumps, closes the pipes).

Wire frames

data Frame Source #

A classified incoming frame.

Constructors

Response Int Json

Response to one of our requests: id and the whole message (result or error lives inside).

AgentRequest Int Text Json

Reverse-RPC: kimi requests something from the client.

Notification Text Json

Notification (no id): method and params.

Instances

Instances details
Show Frame Source # 
Instance details

Defined in Free.Agent.Acp

Methods

showsPrec :: Int -> Frame -> ShowS #

show :: Frame -> String #

showList :: [Frame] -> ShowS #

classifyFrame :: Json -> Maybe Frame Source #

Classify a decoded message. Note ids are Ints and may be 0 (kimi sends id: 0 on session/request_permission).

Session updates

data Update Source #

Parsed session/update notification payload (params.update).

Instances

Instances details
Eq Update Source # 
Instance details

Defined in Free.Agent.Acp

Methods

(==) :: Update -> Update -> Bool #

(/=) :: Update -> Update -> Bool #

Show Update Source # 
Instance details

Defined in Free.Agent.Acp

parseUpdate :: Json -> Maybe Update Source #

Parse the params of a session/update notification. Nothing if the update object or its sessionUpdate tag is missing.

Requests

acpSendValue :: AcpClient -> Json -> IO () Source #

Encode and commit one JSON-RPC message line, logging the raw frame.

acpReadFrame :: AcpClient -> Int -> IO (Maybe Json) Source #

Read the next decodable JSON message, blocking on the stdout queue until one arrives or the timeout (microseconds) expires. Lines that fail to parse are skipped (they stay in the transcript).

acpRequest :: AcpClient -> Int -> Text -> Json -> IO (Maybe Json, [Json]) Source #

Send a request and block until its response arrives or the timeout (microseconds) expires. Interleaved reverse-RPCs are answered (see acpAnswer); every frame seen (including the response) is returned in arrival order alongside the response.

acpInitialize :: AcpClient -> Int -> IO (Maybe Json, [Json]) Source #

initialize handshake: protocolVersion 1, fs client capabilities on, terminal off.

acpNewSession :: AcpClient -> Int -> FilePath -> IO (Maybe Text, [Json]) Source #

session/new with the session cwd pinned. Returns the sessionId on success.

acpSetConfigOption :: AcpClient -> Int -> Text -> Text -> Text -> IO (Maybe Json, [Json]) Source #

session/set_config_option — returns the full configOptions array.

acpSetModeAuto :: AcpClient -> Int -> Text -> IO (Maybe Json, [Json]) Source #

Switch a session to auto mode. Do NOT use session/set_mode — it hangs in kimi 0.33.0.

acpPrompt :: AcpClient -> Int -> Text -> Text -> IO PromptResult Source #

session/prompt with a single text block. Streams are collected until the prompt response, then drained briefly for trailing notifications (usage_update arrives after the response).

data PromptResult Source #

The result of one prompt turn.

Constructors

PromptResult 

Fields

Instances

Instances details
Show PromptResult Source # 
Instance details

Defined in Free.Agent.Acp

acpCancel :: AcpClient -> Text -> IO () Source #

session/cancel notification — cancels the current turn.

acpReadStderr :: AcpClient -> IO Text Source #

Drain pending stderr diagnostics (bounded: returns after ~100ms of quiet). Stderr is diagnostics, not dialogue — a bounded drain, not a blocking read, so a silent stderr cannot stall the caller.