| Safe Haskell | None |
|---|---|
| Language | GHC2024 |
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_modehangs — mode is switched withsession/set_config_option {configId: "mode", value: "auto"}.session/request_permissionresponses are broken in kimi 0.33.0; inautomode file I/O arrives asfs/*reverse-RPCs instead.fs/*params carryuri(with afile:////prefix), not the spec'spath— 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
- data AcpConfig = AcpConfig {
- acpCommand :: FilePath
- acpArgs :: [String]
- acpWorkDir :: FilePath
- acpTranscript :: Maybe FilePath
- defaultAcpConfig :: AcpConfig
- data AcpClient = AcpClient {}
- openAcp :: AcpConfig -> IO AcpClient
- closeAcp :: AcpClient -> IO ()
- data Frame
- classifyFrame :: Json -> Maybe Frame
- data Update
- parseUpdate :: Json -> Maybe Update
- acpSendValue :: AcpClient -> Json -> IO ()
- acpReadFrame :: AcpClient -> Int -> IO (Maybe Json)
- acpRequest :: AcpClient -> Int -> Text -> Json -> IO (Maybe Json, [Json])
- acpInitialize :: AcpClient -> Int -> IO (Maybe Json, [Json])
- acpNewSession :: AcpClient -> Int -> FilePath -> IO (Maybe Text, [Json])
- acpSetConfigOption :: AcpClient -> Int -> Text -> Text -> Text -> IO (Maybe Json, [Json])
- acpSetModeAuto :: AcpClient -> Int -> Text -> IO (Maybe Json, [Json])
- acpPrompt :: AcpClient -> Int -> Text -> Text -> IO PromptResult
- data PromptResult = PromptResult {
- prReply :: Text
- prThoughts :: Text
- prStopReason :: Maybe Text
- prUpdates :: [Update]
- prMessages :: [Json]
- acpCancel :: AcpClient -> Text -> IO ()
- acpReadStderr :: AcpClient -> IO Text
Configuration
What to spawn and where the plumbing lives.
Constructors
| AcpConfig | |
Fields
| |
Instances
defaultAcpConfig :: AcpConfig Source #
kimi acp with the child working directory at /tmp/free-agent-acp.
Client
A live ACP child process plus client-side protocol state.
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.
Wire frames
A classified incoming frame.
Constructors
| Response Int Json | Response to one of our requests: id and the whole message
( |
| AgentRequest Int Text Json | Reverse-RPC: kimi requests something from the client. |
| Notification Text Json | Notification (no id): method and params. |
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
Parsed session/update notification payload (params.update).
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
| Show PromptResult Source # | |
Defined in Free.Agent.Acp Methods showsPrec :: Int -> PromptResult -> ShowS # show :: PromptResult -> String # showList :: [PromptResult] -> ShowS # | |