Skip to content

Commit da6ec3e

Browse files
ziggyclaude
andcommitted
fix: strip heartbeat markers from stdout before accumulation/parsing
Heartbeat lines were leaking into the stdout buffer and parse stream. Container-runner now filters them out immediately after resetting the idle timer — they serve their purpose (keepalive signal) and disappear cleanly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d27347d commit da6ec3e

1 file changed

Lines changed: 13 additions & 4 deletions

File tree

src/container-runner.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { RegisteredGroup } from './types.js';
2222
// Sentinel markers for robust output parsing (must match agent-runner)
2323
const OUTPUT_START_MARKER = '---GHOSTCLAW_OUTPUT_START---';
2424
const OUTPUT_END_MARKER = '---GHOSTCLAW_OUTPUT_END---';
25+
const HEARTBEAT_MARKER = '---GHOSTCLAW_HEARTBEAT---';
2526

2627
export interface ContainerInput {
2728
prompt: string;
@@ -320,22 +321,30 @@ export async function runContainerAgent(
320321
const chunk = data.toString();
321322
resetIdleTimer();
322323

324+
// Strip heartbeat lines — they exist only to reset the idle timer and
325+
// should not appear in logs, output buffers, or the parse stream.
326+
const filtered = chunk
327+
.split('\n')
328+
.filter((line: string) => line !== HEARTBEAT_MARKER)
329+
.join('\n');
330+
if (!filtered.trim() && !chunk.includes(OUTPUT_START_MARKER)) return;
331+
323332
if (!stdoutTruncated) {
324333
const remaining = CONTAINER_MAX_OUTPUT_SIZE - stdout.length;
325-
if (chunk.length > remaining) {
326-
stdout += chunk.slice(0, remaining);
334+
if (filtered.length > remaining) {
335+
stdout += filtered.slice(0, remaining);
327336
stdoutTruncated = true;
328337
logger.warn(
329338
{ group: group.name, size: stdout.length },
330339
'Agent stdout truncated due to size limit',
331340
);
332341
} else {
333-
stdout += chunk;
342+
stdout += filtered;
334343
}
335344
}
336345

337346
if (onOutput) {
338-
parseBuffer += chunk;
347+
parseBuffer += filtered;
339348
let startIdx: number;
340349
while ((startIdx = parseBuffer.indexOf(OUTPUT_START_MARKER)) !== -1) {
341350
const endIdx = parseBuffer.indexOf(OUTPUT_END_MARKER, startIdx);

0 commit comments

Comments
 (0)