fix(baoyu-image-gen): require real image_gen evidence in codex-imagegen

Stop Codex from satisfying a request by copying an unrelated pre-existing
image from generated_images instead of generating a new one. Verification
now requires a PNG in this thread's generated_images dir (or an image_gen
stream item, kept as a forward-compatible signal), and the spawned-agent
instruction forbids reading or reusing history images before image_gen is
called. Removes the findCpToTarget fallback that allowed the shortcut.

Validated against a real codex exec run: image_gen leaves no stream item,
so the filesystem check is the load-bearing signal; locked in via a
condensed real-stream regression fixture.

Closes #185
This commit is contained in:
Jim Liu 宝玉
2026-06-18 14:13:43 -05:00
parent 441ca307a6
commit 51b31aa050
6 changed files with 105 additions and 64 deletions
@@ -33,17 +33,26 @@ test("parseEventStream tolerates malformed lines", () => {
expect(r.usage?.input).toBe(1);
});
test("hasImageGenInvocation finds shell calls touching generated_images", () => {
test("hasImageGenInvocation does not infer image_gen from shell copies", () => {
const r = parseEventStream(REAL_PoC_STREAM);
// image_gen itself is not an event; inferred via generated_images cp path
// this test only verifies parser behavior; driver logic lives in validator
const hasCp = r.toolCalls.some((tc) => tc.command?.includes("generated_images"));
expect(hasCp).toBe(true);
expect(hasImageGenInvocation(r.toolCalls)).toBe(false);
});
test("hasImageGenInvocation (proper) returns false when no image_gen tool", () => {
test("hasImageGenInvocation detects real image_gen tool calls only", () => {
expect(hasImageGenInvocation([{ id: "1", tool: "shell", status: "completed" }])).toBe(false);
expect(
hasImageGenInvocation([{ id: "1", tool: "image_gen", status: "completed" }]),
).toBe(true);
});
test("parseEventStream normalizes an image_generation item to image_gen", () => {
const stream = `{"type":"thread.started","thread_id":"t1"}
{"type":"item.started","item":{"id":"g0","type":"image_generation","status":"in_progress"}}
{"type":"item.completed","item":{"id":"g0","type":"image_generation","status":"completed"}}
{"type":"item.completed","item":{"id":"m0","type":"agent_message","text":"done"}}`;
const r = parseEventStream(stream);
expect(r.toolCalls.some((tc) => tc.tool === "image_gen")).toBe(true);
expect(hasImageGenInvocation(r.toolCalls)).toBe(true);
});