title: Image generation roundtrip scenario: id: image-generation-roundtrip surface: image-generation coverage: primary: - media.image-generation - media.image-generation-delivery secondary: - channels.qa-channel objective: Verify a generated image is saved as media, reattached on the next turn, and described correctly through the vision path. successCriteria: - image_generate produces a saved MEDIA artifact. - The generated artifact is reattached on a follow-up turn. - The follow-up vision answer describes the generated scene rather than a generic attachment placeholder. docsRefs: - docs/tools/image-generation.md - docs/help/testing.md codeRefs: - src/agents/tools/image-generate-tool.ts - src/gateway/chat-attachments.ts - extensions/qa-lab/src/mock-openai-server.ts execution: kind: flow summary: Verify a generated image is saved as media, reattached on the next turn, and described correctly through the vision path. config: requiredChannelDriver: qa-channel generatePrompt: "Image generation check: generate a QA lighthouse image and summarize it in one short sentence." generatePromptSnippet: "Image generation check" inspectPrompt: "Roundtrip image inspection check: describe the generated lighthouse attachment in one short sentence." expectedNeedle: "lighthouse" flow: steps: - name: reattaches the generated media artifact on the follow-up turn actions: - call: ensureImageGenerationConfigured args: - ref: env - call: createSession args: - ref: env - Image roundtrip - agent:qa:image-roundtrip - call: reset - set: generatedStartedAtMs value: expr: Date.now() - call: runAgentPrompt args: - ref: env - sessionKey: agent:qa:image-roundtrip message: expr: config.generatePrompt timeoutMs: expr: liveTurnTimeoutMs(env, 45000) - call: resolveGeneratedImagePath saveAs: mediaPath args: - env: ref: env promptSnippet: expr: config.generatePromptSnippet startedAtMs: ref: generatedStartedAtMs timeoutMs: expr: liveTurnTimeoutMs(env, 45000) - call: fs.readFile saveAs: imageBuffer args: - ref: mediaPath - call: runAgentPrompt args: - ref: env - sessionKey: agent:qa:image-roundtrip message: expr: config.inspectPrompt attachments: - mimeType: image/png fileName: expr: path.basename(mediaPath) content: expr: imageBuffer.toString('base64') timeoutMs: expr: liveTurnTimeoutMs(env, 45000) - call: waitForCondition saveAs: outbound args: - lambda: expr: "state.getSnapshot().messages.filter((candidate) => candidate.direction === 'outbound' && candidate.conversation.id === 'qa-operator' && normalizeLowercaseStringOrEmpty(candidate.text).includes(normalizeLowercaseStringOrEmpty(config.expectedNeedle))).at(-1)" - expr: liveTurnTimeoutMs(env, 45000) - assert: expr: "!env.mock || Boolean((await fetchJson(`${env.mock.baseUrl}/debug/requests`)).find((request) => request.plannedToolName === 'image_generate' && String(request.prompt ?? '').includes(config.generatePromptSnippet)))" message: expected image_generate call before roundtrip inspection - assert: expr: "!env.mock || (await fetchJson(`${env.mock.baseUrl}/debug/requests`)).some((request) => String(request.prompt ?? '').includes(config.inspectPrompt) && (request.imageInputCount ?? 0) >= 1)" message: expr: "`expected generated artifact to be reattached on follow-up turn; recentRequests=${JSON.stringify((await fetchJson(`${env.mock.baseUrl}/debug/requests`)).slice(-12).map((request) => ({ prompt: String(request.prompt ?? '').slice(0, 240), imageInputCount: request.imageInputCount, allInputText: String(request.allInputText ?? '').slice(0, 240) })))}`" detailsExpr: "`MEDIA:${mediaPath}\\n${outbound.text}`"