@@ -18,6 +18,7 @@ import {
|
18 | 18 | resetGlobalHookRunner, |
19 | 19 | } from "openclaw/plugin-sdk/hook-runtime"; |
20 | 20 | import { createMockPluginRegistry } from "openclaw/plugin-sdk/plugin-test-runtime"; |
| 21 | +import { withTempDir } from "openclaw/plugin-sdk/test-env"; |
21 | 22 | import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; |
22 | 23 | import { |
23 | 24 | CodexAppServerEventProjector, |
@@ -743,6 +744,47 @@ describe("CodexAppServerEventProjector", () => {
|
743 | 744 | expect(result.toolMediaUrls?.[0]).not.toBe(savedPath); |
744 | 745 | }); |
745 | 746 | |
| 747 | +it("prefers gateway-managed image media when the typed event arrives first", async () => { |
| 748 | +await withTempDir("openclaw-codex-media-state-", async (stateDir) => { |
| 749 | +vi.stubEnv("OPENCLAW_STATE_DIR", stateDir); |
| 750 | +const projector = await createProjector(); |
| 751 | +const savedPath = "/home/dev-user/.codex/generated_images/session-1/ig_123.png"; |
| 752 | + |
| 753 | +await projector.handleNotification( |
| 754 | +forCurrentTurn("item/completed", { |
| 755 | +item: { |
| 756 | +type: "imageGeneration", |
| 757 | +id: "ig_123", |
| 758 | +status: "completed", |
| 759 | +revisedPrompt: "A tiny blue square", |
| 760 | +result: tinyPngBase64, |
| 761 | + savedPath, |
| 762 | +}, |
| 763 | +}), |
| 764 | +); |
| 765 | +await projector.handleNotification( |
| 766 | +forCurrentTurn("rawResponseItem/completed", { |
| 767 | +item: { |
| 768 | +type: "image_generation_call", |
| 769 | +id: "ig_123", |
| 770 | +status: "generating", |
| 771 | +result: tinyPngBase64, |
| 772 | +}, |
| 773 | +}), |
| 774 | +); |
| 775 | + |
| 776 | +const result = projector.buildResult(buildEmptyToolTelemetry()); |
| 777 | +const mediaUrl = result.toolMediaUrls?.[0]; |
| 778 | + |
| 779 | +expect(result.toolMediaUrls).toHaveLength(1); |
| 780 | +expect(mediaUrl).not.toBe(savedPath); |
| 781 | +expect(mediaUrl).toContain(`${path.sep}media${path.sep}tool-image-generation${path.sep}`); |
| 782 | +await expect(fs.readFile(mediaUrl ?? "")).resolves.toEqual( |
| 783 | +Buffer.from(tinyPngBase64, "base64"), |
| 784 | +); |
| 785 | +}); |
| 786 | +}); |
| 787 | + |
746 | 788 | it("preserves distinct raw image-generation items with identical image bytes", async () => { |
747 | 789 | const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-media-state-")); |
748 | 790 | tempDirs.add(stateDir); |
|