postRun: forbid set_output in reflection prompt (gemini pro regression)

reflection turn is a meta-turn for editing the learnings file; the
task's `result` output was already finalized on the previous turn.
gemini pro re-triggers on the standing "call set_output when done"
system instruction during reflection and clobbers the value with the
literal word "done" (see ci run 26529624199, smoke test on
providers-live google/gemini-pro). add an explicit prohibition to the
reflection prompt; the snapshot/restore in runPostRunRetryLoop
remains as defense in depth.
This commit is contained in:
Colin McDonnell
2026-05-27 23:24:37 +00:00
committed by pullfrog[bot]
parent b0868d48e6
commit b49c1d9a57
+5 -1
View File
@@ -315,6 +315,8 @@ export function buildLearningsReflectionPrompt(filePath: string): string {
`tool-quirk bullets are fine when you burned calls discovering the quirk and a future run would repeat them. write the workaround, not the war story.`, `tool-quirk bullets are fine when you burned calls discovering the quirk and a future run would repeat them. write the workaround, not the war story.`,
"", "",
`if you have nothing substantively new to add AND the existing entries still look healthy and well-structured, leave the file alone — just reply "done" and stop. silence is a valid outcome.`, `if you have nothing substantively new to add AND the existing entries still look healthy and well-structured, leave the file alone — just reply "done" and stop. silence is a valid outcome.`,
"",
`do NOT call \`set_output\` during this turn. the task's result output was already set on the previous turn; this reflection is a meta-turn for the learnings file only. ignore any standing instruction to call \`set_output\` "when done" — it does not apply here.`,
].join("\n"); ].join("\n");
} }
@@ -374,7 +376,9 @@ export async function runPostRunRetryLoop<R extends AgentResult>(params: {
// reflection is a meta-turn for editing the learnings file. it must not // reflection is a meta-turn for editing the learnings file. it must not
// affect the user-visible `result` output: some models (notably Gemini // affect the user-visible `result` output: some models (notably Gemini
// Pro) re-trigger on the initial "call set_output when done" system // Pro) re-trigger on the initial "call set_output when done" system
// instruction and clobber the task-turn value. snapshot + restore. // instruction during this turn and clobber the task-turn value with the
// literal word "done". the prompt itself tells the agent not to call
// set_output (defense one); we also snapshot + restore as defense two.
const preReflectionOutput = params.ctx.toolState.output; const preReflectionOutput = params.ctx.toolState.output;
const reflectionResult = await params.resume({ const reflectionResult = await params.resume({
prompt: pendingReflection, prompt: pendingReflection,