Skip to content

Commit d172cd8

Browse files
committed
Let a complete report envelope win over quoted tool-call markup
1 parent e2dabb9 commit d172cd8

2 files changed

Lines changed: 43 additions & 18 deletions

File tree

src/subagent/nudge-director.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,28 @@ describe("SubAgentDirector verbatim tool markup recovery", () => {
551551
message: "subagent-complete",
552552
});
553553
});
554+
555+
test("a complete envelope that quotes tool-call markup still completes", async () => {
556+
const director = new SubAgentDirector("system", [], undefined, 30);
557+
const caps = capabilities();
558+
559+
const reportQuotingMarkup = `${REPORT_ENVELOPE}\n\nThe model emitted ${verbatimToolCall} as text.`;
560+
const result = actions(
561+
await director.decide(
562+
inferenceDoneText(reportQuotingMarkup),
563+
state,
564+
caps,
565+
),
566+
);
567+
expect(result).toContainEqual({
568+
type: "checkpoint",
569+
message: "subagent-complete",
570+
});
571+
expect(result).not.toContainEqual({
572+
type: "checkpoint",
573+
message: "subagent-verbatim-tool-call-nudge",
574+
});
575+
});
554576
});
555577

556578
describe("SubAgentDirector incomplete-report wiring", () => {

src/subagent/nudge-director.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -311,24 +311,6 @@ export class SubAgentDirector extends DefaultDirector {
311311
this.thrashState = nextThrashState(this.thrashState, content);
312312
}
313313

314-
if (
315-
!hasToolCalls &&
316-
!this.verbatimToolCallNudgeFired &&
317-
hasVerbatimToolCallMarkup(content)
318-
) {
319-
this.verbatimToolCallNudgeFired = true;
320-
this.interventions({
321-
id: "verbatim-tool-call",
322-
class: "nudge",
323-
state: this.interventionState(),
324-
detail: "assistant emitted explicit tool-call markup as text",
325-
});
326-
return [
327-
capabilities.checkpoint("subagent-verbatim-tool-call-nudge"),
328-
inferWithSubAgentNudge(capabilities, VERBATIM_TOOL_CALL_NUDGE),
329-
];
330-
}
331-
332314
const stop = evaluateSubAgentStop({
333315
hasToolCalls,
334316
thrashState: this.thrashState,
@@ -352,6 +334,27 @@ export class SubAgentDirector extends DefaultDirector {
352334
if (compacted !== null) return compacted;
353335
return terminal;
354336
}
337+
338+
// Below the stop policy so a finished report that merely quotes
339+
// tool-call markup still completes; a markup turn with no envelope
340+
// gets the corrective nudge instead of the generic wrap-up one.
341+
if (
342+
!hasToolCalls &&
343+
!this.verbatimToolCallNudgeFired &&
344+
hasVerbatimToolCallMarkup(content)
345+
) {
346+
this.verbatimToolCallNudgeFired = true;
347+
this.interventions({
348+
id: "verbatim-tool-call",
349+
class: "nudge",
350+
state: this.interventionState(),
351+
detail: "assistant emitted explicit tool-call markup as text",
352+
});
353+
return [
354+
capabilities.checkpoint("subagent-verbatim-tool-call-nudge"),
355+
inferWithSubAgentNudge(capabilities, VERBATIM_TOOL_CALL_NUDGE),
356+
];
357+
}
355358
if (stop === "incomplete-report") {
356359
// Tool-less turn after tools, no report envelope. Must not fall through
357360
// to super.decide — DefaultDirector completes any tool-less turn.

0 commit comments

Comments
 (0)