Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/adapters/agenticLoop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,28 @@ describe('runAgenticLoop final-answer recovery (INT-2879)', () => {
expect(logs).toContain('↻ Final answer was empty — retrying once (no tools)');
});

it('requires an explicit review verdict from a tool-exhausted reviewer (AGT-4484)', async () => {
let salvagePrompt = '';
const result = await runAgenticLoop({
prompt: 'Review this change and return a verdict.',
cwd: process.cwd(),
model: 'test',
webTools: false,
maxTurns: 1,
callApi: async (messages, tools) => {
if (tools.length > 0) return toolCallResp('read', 'read_file', { path: 'package.json' });
salvagePrompt = String(messages.at(-1)?.content ?? '');
// This is the conclusion the historical reviewer omitted after using
// its full tool budget: a verdict, not a worker-style status report.
return finalResp('Decision: approve\nNo actionable issues found.');
},
});

expect(salvagePrompt).toContain('Decision: approve');
expect(salvagePrompt).toContain('worker-status summary');
expect(result.text).toContain('Decision: approve');
});

it('fails explicitly when the retry is also reasoning-only/empty', async () => {
let calls = 0;
let finalAnswerCalls = 0;
Expand Down
5 changes: 4 additions & 1 deletion src/adapters/agenticLoop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,10 @@ async function runAgenticLoopInner(
const stepLimitPrompt =
"You've reached this turn's step limit, so stop calling tools now. Using everything " +
'above, write a non-empty final answer now. Follow the output format requested in the ' +
'original task exactly. Do not mention step/tool limits or "budget" to the user.';
'original task exactly. If the original task requests a review or verdict, begin with ' +
'`Decision: approve`, `Decision: revise`, or `Decision: reject` and give concrete ' +
'reasoning; do not return a worker-status summary. Do not mention step/tool limits or ' +
'"budget" to the user.';
messages.push({ role: 'user', content: stepLimitPrompt });
// Salvage is where a cut-short run gets the answer that becomes its verdict,
// and it used to leave no trace at all: the transcript ended on a tool
Expand Down
Loading