Skip to content

Commit 0c4fc0a

Browse files
committed
refactor(agents): derive CLI commentary classification from consumer presence
1 parent 6396221 commit 0c4fc0a

10 files changed

Lines changed: 14 additions & 71 deletions

src/agents/cli-output.test.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,6 @@ describe("createCliJsonlStreamingParser", () => {
905905
sessionIdFields: ["session_id"],
906906
},
907907
providerId: "claude-cli",
908-
classifyCommentaryText: true,
909908
onAssistantDelta: (delta) => deltas.push({ text: delta.text, delta: delta.delta }),
910909
onCommentaryText: (text) => commentaryTexts.push(text),
911910
});
@@ -954,7 +953,6 @@ describe("createCliJsonlStreamingParser", () => {
954953
sessionIdFields: ["session_id"],
955954
},
956955
providerId: "claude-cli",
957-
classifyCommentaryText: true,
958956
onAssistantDelta: (delta) => deltas.push({ text: delta.text, delta: delta.delta }),
959957
onCommentaryText: (text) => commentaryTexts.push(text),
960958
});
@@ -990,7 +988,7 @@ describe("createCliJsonlStreamingParser", () => {
990988
expect(deltas).toEqual([{ text: "Final answer.", delta: "Final answer." }]);
991989
});
992990

993-
it("falls back to assistant deltas when classification is enabled without delivery", () => {
991+
it("keeps pre-tool text in assistant deltas when no commentary consumer is wired", () => {
994992
const deltas: Array<{ text: string; delta: string }> = [];
995993
const parser = createCliJsonlStreamingParser({
996994
backend: {
@@ -1000,7 +998,6 @@ describe("createCliJsonlStreamingParser", () => {
1000998
sessionIdFields: ["session_id"],
1001999
},
10021000
providerId: "claude-cli",
1003-
classifyCommentaryText: true,
10041001
onAssistantDelta: (delta) => deltas.push({ text: delta.text, delta: delta.delta }),
10051002
});
10061003

@@ -1041,7 +1038,6 @@ describe("createCliJsonlStreamingParser", () => {
10411038
sessionIdFields: ["session_id"],
10421039
},
10431040
providerId: "claude-cli",
1044-
classifyCommentaryText: true,
10451041
onAssistantDelta: () => undefined,
10461042
onCommentaryText: (text) => commentaryTexts.push(text),
10471043
});
@@ -1074,7 +1070,6 @@ describe("createCliJsonlStreamingParser", () => {
10741070
sessionIdFields: ["session_id"],
10751071
},
10761072
providerId: "claude-cli",
1077-
classifyCommentaryText: true,
10781073
onAssistantDelta: () => undefined,
10791074
onCommentaryText: (text) => commentaryTexts.push(text),
10801075
});
@@ -1122,7 +1117,6 @@ describe("createCliJsonlStreamingParser", () => {
11221117
sessionIdFields: ["session_id"],
11231118
},
11241119
providerId: "claude-cli",
1125-
classifyCommentaryText: true,
11261120
onAssistantDelta: () => undefined,
11271121
onCommentaryText: (text) => commentaryTexts.push(text),
11281122
});

src/agents/cli-output.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -624,15 +624,13 @@ function dispatchClaudeCliStreamingToolEvent(params: {
624624
}
625625
}
626626

627-
/** Creates an incremental JSONL parser for CLI streaming responses and tool events. */
628627
/** Creates a stateful parser for streaming JSONL CLI backend output. */
629628
export function createCliJsonlStreamingParser(params: {
630629
backend: CliBackendConfig;
631630
providerId: string;
632631
onAssistantDelta: (delta: CliStreamingDelta) => void;
633632
onToolUseStart?: (delta: CliToolUseStartDelta) => void;
634633
onToolResult?: (delta: CliToolResultDelta) => void;
635-
classifyCommentaryText?: boolean;
636634
onCommentaryText?: (text: string) => void;
637635
}) {
638636
let lineBuffer = "";
@@ -643,8 +641,10 @@ export function createCliJsonlStreamingParser(params: {
643641
let output: CliOutput | null = null;
644642
const texts: string[] = [];
645643
const toolTracker = createToolUseTracker();
644+
// Classification is keyed on consumer presence so reclassified pre-tool text
645+
// always has a destination; a separate enable flag let it be dropped (#92092).
646646
const classifyClaudeCommentary =
647-
params.classifyCommentaryText === true && usesClaudeStreamJsonDialect(params);
647+
Boolean(params.onCommentaryText) && usesClaudeStreamJsonDialect(params);
648648

649649
const flushPendingClaudeAssistantText = () => {
650650
if (!pendingClaudeText) {
@@ -665,16 +665,10 @@ export function createCliJsonlStreamingParser(params: {
665665
if (!pendingClaudeText) {
666666
return;
667667
}
668-
if (!params.onCommentaryText) {
669-
// No commentary consumer is wired: fall back to the assistant text lane
670-
// instead of silently discarding model output.
671-
flushPendingClaudeAssistantText();
672-
return;
673-
}
674668
const text = pendingClaudeText.trim();
675669
pendingClaudeText = "";
676670
if (text) {
677-
params.onCommentaryText(text);
671+
params.onCommentaryText?.(text);
678672
}
679673
};
680674

src/agents/cli-runner/claude-live-session.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,6 @@ function createTurn(params: {
11221122
onAssistantDelta: (delta: CliStreamingDelta) => void;
11231123
onToolUseStart?: (delta: CliToolUseStartDelta) => void;
11241124
onToolResult?: (delta: CliToolResultDelta) => void;
1125-
classifyCommentaryText?: boolean;
11261125
onCommentaryText?: (text: string) => void;
11271126
session: ClaudeLiveSession;
11281127
execPermission: ClaudeLiveExecPermission;
@@ -1150,7 +1149,6 @@ function createTurn(params: {
11501149
onAssistantDelta: params.onAssistantDelta,
11511150
onToolUseStart: params.onToolUseStart,
11521151
onToolResult: params.onToolResult,
1153-
classifyCommentaryText: params.classifyCommentaryText,
11541152
onCommentaryText: params.onCommentaryText,
11551153
}),
11561154
execPermission: params.execPermission,
@@ -1222,7 +1220,6 @@ export async function runClaudeLiveSessionTurn(params: {
12221220
onAssistantDelta: (delta: CliStreamingDelta) => void;
12231221
onToolUseStart?: (delta: CliToolUseStartDelta) => void;
12241222
onToolResult?: (delta: CliToolResultDelta) => void;
1225-
classifyCommentaryText?: boolean;
12261223
onCommentaryText?: (text: string) => void;
12271224
cleanup: () => Promise<void>;
12281225
}): Promise<ClaudeLiveRunResult> {
@@ -1341,7 +1338,6 @@ export async function runClaudeLiveSessionTurn(params: {
13411338
onAssistantDelta: params.onAssistantDelta,
13421339
onToolUseStart: params.onToolUseStart,
13431340
onToolResult: params.onToolResult,
1344-
classifyCommentaryText: params.classifyCommentaryText,
13451341
onCommentaryText: params.onCommentaryText,
13461342
session: liveSession,
13471343
execPermission,

src/agents/cli-runner/execute.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,6 @@ export async function executePreparedCliRun(
564564
},
565565
onToolUseStart: emitCliToolUseStart,
566566
onToolResult: emitCliToolResult,
567-
classifyCommentaryText: context.params.classifyCommentaryText,
568567
onCommentaryText: context.params.emitCommentaryText ? emitCliCommentaryText : undefined,
569568
cleanup: async () => {
570569
try {
@@ -610,7 +609,6 @@ export async function executePreparedCliRun(
610609
},
611610
onToolUseStart: emitCliToolUseStart,
612611
onToolResult: emitCliToolResult,
613-
classifyCommentaryText: context.params.classifyCommentaryText,
614612
onCommentaryText: context.params.emitCommentaryText
615613
? emitCliCommentaryText
616614
: undefined,

src/agents/cli-runner/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ export type RunCliAgentParams = {
107107
firstModelCallStarted?: boolean;
108108
}) => void;
109109
replyOperation?: ReplyOperation;
110-
classifyCommentaryText?: boolean;
111110
emitCommentaryText?: boolean;
112111
/**
113112
* Close any long-lived CLI live session created for this run after the run

src/auto-reply/reply/agent-runner-cli-dispatch.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,6 @@ export async function runCliAgentWithLifecycle(params: {
347347
try {
348348
const rawResult = await runCliAgent({
349349
...params.runParams,
350-
classifyCommentaryText:
351-
params.runParams.classifyCommentaryText ?? Boolean(params.onCommentaryText),
352350
emitCommentaryText: Boolean(params.onCommentaryText),
353351
});
354352
const result = params.transformResult?.(rawResult) ?? rawResult;

src/auto-reply/reply/agent-runner-execution.test.ts

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,12 +2243,7 @@ describe("runAgentTurnWithFallback", () => {
22432243
attempts: [],
22442244
}));
22452245
state.runCliAgentMock.mockImplementationOnce(
2246-
async (params: {
2247-
runId: string;
2248-
classifyCommentaryText?: boolean;
2249-
emitCommentaryText?: boolean;
2250-
}) => {
2251-
expect(params.classifyCommentaryText).toBe(false);
2246+
async (params: { runId: string; emitCommentaryText?: boolean }) => {
22522247
expect(params.emitCommentaryText).toBe(false);
22532248
const realAgentEvents = await vi.importActual<typeof import("../../infra/agent-events.js")>(
22542249
"../../infra/agent-events.js",
@@ -2311,12 +2306,7 @@ describe("runAgentTurnWithFallback", () => {
23112306
attempts: [],
23122307
}));
23132308
state.runCliAgentMock.mockImplementationOnce(
2314-
async (params: {
2315-
runId: string;
2316-
classifyCommentaryText?: boolean;
2317-
emitCommentaryText?: boolean;
2318-
}) => {
2319-
expect(params.classifyCommentaryText).toBe(false);
2309+
async (params: { runId: string; emitCommentaryText?: boolean }) => {
23202310
expect(params.emitCommentaryText).toBe(false);
23212311
const realAgentEvents = await vi.importActual<typeof import("../../infra/agent-events.js")>(
23222312
"../../infra/agent-events.js",
@@ -2402,12 +2392,7 @@ describe("runAgentTurnWithFallback", () => {
24022392
attempts: [],
24032393
}));
24042394
state.runCliAgentMock.mockImplementationOnce(
2405-
async (params: {
2406-
runId: string;
2407-
classifyCommentaryText?: boolean;
2408-
emitCommentaryText?: boolean;
2409-
}) => {
2410-
expect(params.classifyCommentaryText).toBe(false);
2395+
async (params: { runId: string; emitCommentaryText?: boolean }) => {
24112396
expect(params.emitCommentaryText).toBe(false);
24122397
const realAgentEvents = await vi.importActual<typeof import("../../infra/agent-events.js")>(
24132398
"../../infra/agent-events.js",
@@ -2481,12 +2466,7 @@ describe("runAgentTurnWithFallback", () => {
24812466
attempts: [],
24822467
}));
24832468
state.runCliAgentMock.mockImplementationOnce(
2484-
async (params: {
2485-
runId: string;
2486-
classifyCommentaryText?: boolean;
2487-
emitCommentaryText?: boolean;
2488-
}) => {
2489-
expect(params.classifyCommentaryText).toBe(true);
2469+
async (params: { runId: string; emitCommentaryText?: boolean }) => {
24902470
expect(params.emitCommentaryText).toBe(true);
24912471
const realAgentEvents = await vi.importActual<typeof import("../../infra/agent-events.js")>(
24922472
"../../infra/agent-events.js",
@@ -2541,7 +2521,7 @@ describe("runAgentTurnWithFallback", () => {
25412521
expect(call?.itemId).toBe("commentary-1");
25422522
});
25432523

2544-
it("does not classify CLI commentary when commentary progress is explicitly disabled", async () => {
2524+
it("does not emit CLI commentary when commentary progress is explicitly disabled", async () => {
25452525
state.isCliProviderMock.mockReturnValue(true);
25462526
state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => ({
25472527
result: await params.run("claude-cli", "claude-opus-4-6"),
@@ -2550,15 +2530,9 @@ describe("runAgentTurnWithFallback", () => {
25502530
attempts: [],
25512531
}));
25522532
state.runCliAgentMock.mockImplementationOnce(
2553-
async (params: {
2554-
runId: string;
2555-
classifyCommentaryText?: boolean;
2556-
emitCommentaryText?: boolean;
2557-
}) => {
2558-
// commentaryProgressEnabled: false (defined but off) must not engage
2559-
// classification: with no commentary consumer wired, classified text
2560-
// would be dropped instead of reaching the assistant stream (#91976).
2561-
expect(params.classifyCommentaryText).toBe(false);
2533+
async (params: { runId: string; emitCommentaryText?: boolean }) => {
2534+
// Defined-but-off commentary progress must leave commentary emission off
2535+
// so pre-tool text stays in the assistant stream (#92092).
25622536
expect(params.emitCommentaryText).toBe(false);
25632537
return { payloads: [{ text: "done" }], meta: {} };
25642538
},

src/auto-reply/reply/agent-runner-execution.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,9 +2199,6 @@ export async function runAgentTurnWithFallback(params: {
21992199
inputProvenance: params.followupRun.run.inputProvenance,
22002200
provider: cliExecutionProvider,
22012201
model,
2202-
classifyCommentaryText:
2203-
params.opts?.commentaryProgressEnabled === true &&
2204-
Boolean(params.opts.onItemEvent),
22052202
thinkLevel: params.followupRun.run.thinkLevel,
22062203
timeoutMs: params.followupRun.run.timeoutMs,
22072204
runTimeoutOverrideMs: params.followupRun.run.runTimeoutOverrideMs,

src/auto-reply/reply/followup-runner.test.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,12 +1401,7 @@ describe("createFollowupRunner runtime config", () => {
14011401
};
14021402
const onItemEvent = vi.fn(async () => {});
14031403
runCliAgentMock.mockImplementationOnce(
1404-
async (params: {
1405-
runId: string;
1406-
classifyCommentaryText?: boolean;
1407-
emitCommentaryText?: boolean;
1408-
}) => {
1409-
expect(params.classifyCommentaryText).toBe(true);
1404+
async (params: { runId: string; emitCommentaryText?: boolean }) => {
14101405
expect(params.emitCommentaryText).toBe(true);
14111406
realAgentEvents.emitAgentEvent({
14121407
runId: params.runId,

src/auto-reply/reply/followup-runner.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -940,8 +940,6 @@ export function createFollowupRunner(params: {
940940
...resolveRunAuthProfile(candidateRun, cliExecutionProvider, {
941941
config: runtimeConfig,
942942
}),
943-
classifyCommentaryText:
944-
opts?.commentaryProgressEnabled === true && Boolean(opts.onItemEvent),
945943
thinkLevel: run.thinkLevel,
946944
timeoutMs: run.timeoutMs,
947945
runTimeoutOverrideMs: run.runTimeoutOverrideMs,

0 commit comments

Comments
 (0)