fix(coding-agent): use strict JSONL framing fixes #1911
This commit is contained in:
@@ -24,6 +24,17 @@ Common options:
|
||||
|
||||
All commands support an optional `id` field for request/response correlation. If provided, the corresponding response will include the same `id`.
|
||||
|
||||
### Framing
|
||||
|
||||
RPC mode uses strict JSONL semantics with LF (`\n`) as the only record delimiter.
|
||||
|
||||
This matters for clients:
|
||||
- Split records on `\n` only
|
||||
- Accept optional `\r\n` input by stripping a trailing `\r`
|
||||
- Do not use generic line readers that treat Unicode separators as newlines
|
||||
|
||||
In particular, Node `readline` is not protocol-compliant for RPC mode because it also splits on `U+2028` and `U+2029`, which are valid inside JSON strings.
|
||||
|
||||
## Commands
|
||||
|
||||
### Prompting
|
||||
@@ -1292,13 +1303,39 @@ For a complete example of handling the extension UI protocol, see [`examples/rpc
|
||||
|
||||
```javascript
|
||||
const { spawn } = require("child_process");
|
||||
const readline = require("readline");
|
||||
const { StringDecoder } = require("string_decoder");
|
||||
|
||||
const agent = spawn("pi", ["--mode", "rpc", "--no-session"]);
|
||||
|
||||
readline.createInterface({ input: agent.stdout }).on("line", (line) => {
|
||||
function attachJsonlReader(stream, onLine) {
|
||||
const decoder = new StringDecoder("utf8");
|
||||
let buffer = "";
|
||||
|
||||
stream.on("data", (chunk) => {
|
||||
buffer += typeof chunk === "string" ? chunk : decoder.write(chunk);
|
||||
|
||||
while (true) {
|
||||
const newlineIndex = buffer.indexOf("\n");
|
||||
if (newlineIndex === -1) break;
|
||||
|
||||
let line = buffer.slice(0, newlineIndex);
|
||||
buffer = buffer.slice(newlineIndex + 1);
|
||||
if (line.endsWith("\r")) line = line.slice(0, -1);
|
||||
onLine(line);
|
||||
}
|
||||
});
|
||||
|
||||
stream.on("end", () => {
|
||||
buffer += decoder.end();
|
||||
if (buffer.length > 0) {
|
||||
onLine(buffer.endsWith("\r") ? buffer.slice(0, -1) : buffer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
attachJsonlReader(agent.stdout, (line) => {
|
||||
const event = JSON.parse(line);
|
||||
|
||||
|
||||
if (event.type === "message_update") {
|
||||
const { assistantMessageEvent } = event;
|
||||
if (assistantMessageEvent.type === "text_delta") {
|
||||
|
||||
Reference in New Issue
Block a user