fix(coding-agent): use strict JSONL framing fixes #1911

This commit is contained in:
Mario Zechner
2026-03-07 14:20:44 +01:00
parent 841c95ac9c
commit e3adaf1bd9
7 changed files with 188 additions and 27 deletions

View File

@@ -5,12 +5,12 @@
*/
import { type ChildProcess, spawn } from "node:child_process";
import * as readline from "node:readline";
import type { AgentEvent, AgentMessage, ThinkingLevel } from "@mariozechner/pi-agent-core";
import type { ImageContent } from "@mariozechner/pi-ai";
import type { SessionStats } from "../../core/agent-session.js";
import type { BashResult } from "../../core/bash-executor.js";
import type { CompactionResult } from "../../core/compaction/index.js";
import { attachJsonlLineReader, serializeJsonLine } from "./jsonl.js";
import type { RpcCommand, RpcResponse, RpcSessionState, RpcSlashCommand } from "./rpc-types.js";
// ============================================================================
@@ -53,7 +53,7 @@ export type RpcEventListener = (event: AgentEvent) => void;
export class RpcClient {
private process: ChildProcess | null = null;
private rl: readline.Interface | null = null;
private stopReadingStdout: (() => void) | null = null;
private eventListeners: RpcEventListener[] = [];
private pendingRequests: Map<string, { resolve: (response: RpcResponse) => void; reject: (error: Error) => void }> =
new Map();
@@ -94,13 +94,8 @@ export class RpcClient {
this.stderr += data.toString();
});
// Set up line reader for stdout
this.rl = readline.createInterface({
input: this.process.stdout!,
terminal: false,
});
this.rl.on("line", (line) => {
// Set up strict JSONL reader for stdout.
this.stopReadingStdout = attachJsonlLineReader(this.process.stdout!, (line) => {
this.handleLine(line);
});
@@ -118,7 +113,8 @@ export class RpcClient {
async stop(): Promise<void> {
if (!this.process) return;
this.rl?.close();
this.stopReadingStdout?.();
this.stopReadingStdout = null;
this.process.kill("SIGTERM");
// Wait for process to exit
@@ -135,7 +131,6 @@ export class RpcClient {
});
this.process = null;
this.rl = null;
this.pendingRequests.clear();
}
@@ -493,7 +488,7 @@ export class RpcClient {
},
});
this.process!.stdin!.write(`${JSON.stringify(fullCommand)}\n`);
this.process!.stdin!.write(serializeJsonLine(fullCommand));
});
}