Skip to content

feat: support Codex generated image attachments - #721

Merged
chuks-qua merged 3 commits into
mainfrom
feat/gpt-image
Jun 12, 2026
Merged

chuks-qua merged 3 commits into
mainfrom
feat/gpt-image

Conversation

@chuks-qua

@chuks-qua chuks-qua commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds Codex generated image handling to chat threads. When Codex app-server emits imageGeneration.savedPath, Mcode copies the image into attachment storage, persists it on the assistant message, and renders it with the existing thumbnail and lightbox UI.

Also moves the agent .env edit guard into a shared Node hook used by Codex, Claude, and Cursor.

Why

Codex image generation uses the local Codex session and returns a saved image path through the app-server protocol. Mcode preserves that artifact through turn finalization and thread reloads.

The old inline .env hook regex missed JSON tool input such as {"path":".env"}.

Key Changes

  • Added a generatedAttachment agent event and assistant message attachment support.
  • Copied Codex generated images into bounded, allowlisted attachment storage.
  • Buffered generated attachments through turn finalization and message persistence.
  • Rendered assistant image attachments in the transcript and lightbox.
  • Added unit coverage plus a targeted Playwright spec for generated assistant images.
  • Replaced inline .env hook regexes with scripts/agent/hooks/block-env-edits.mjs.

Verification

  • bun run test:scripts: 32 passed.
  • node scripts/agent/hooks/codex-stop.mjs: {"decision":"approve"}.
  • .env guard with Codex mode: {"decision":"block","reason":"Do not edit .env files directly. Update .env.example instead."}.
  • bun run e2e -- e2e/generated-image-message.spec.ts: 1 passed.
  • bun run verify: typecheck and lint passed. The full web unit suite failed in sidebar-settings-button.test.tsx, sidebar-usage-panel-tokens.test.tsx, MermaidBlock.test.tsx, and PlanDocument.test.tsx. Those files passed when rerun narrowly, except the first paired PlanDocument.test.tsx run timed out once before passing alone.

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • New Features

    • AI-generated images now appear inline in assistant messages with thumbnail preview and lightbox viewing.
    • Assistant messages can include image attachments that are delivered and displayed even when the assistant text is empty.
  • Tests

    • Added end-to-end and unit tests covering generated-image display and attachment persistence/handling.
  • Chores

    • Hardened environment-file edit protections and refactored attachment persistence/storage.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 86093079-026f-42ac-bc65-700d629a2a48

📥 Commits

Reviewing files that changed from the base of the PR and between fddbb0a and 8247b94.

📒 Files selected for processing (2)
  • apps/server/src/providers/codex/__tests__/codex-provider-subagent-turn.test.ts
  • apps/server/src/providers/codex/codex-provider.ts

📝 Walkthrough

Walkthrough

Adds end-to-end support for persisting Codex-generated images as assistant attachments (server contracts, provider mapping, attachment persistence, turn buffering, idempotent message writes, and web rendering) and replaces inline shell env-edit hook logic with a shared Node ESM script and tests.

Changes

Generated Image Attachment Support

Layer / File(s) Summary
Event contracts and types
packages/contracts/src/events/agent-event.ts, packages/contracts/src/events/__tests__/agent-event.test.ts, apps/server/src/providers/codex/codex-types.ts
Adds GeneratedAttachment event type, allows attachments on Message events, and extends CompletedItem with imageGeneration.savedPath and revisedPrompt.
Codex provider mapping and tests
apps/server/src/providers/codex/codex-provider.ts, apps/server/src/providers/codex/__tests__/*
Adds generatedImagePathFromCodexItem, injects AttachmentService, maps item/completed image results to GeneratedAttachment events by persisting savedPath, emits those events, and updates provider tests to supply persistGeneratedImageFromPath.
AttachmentService generated-image persistence
apps/server/src/services/attachment-service.ts, apps/server/src/__tests__/attachment-service-virtual.test.ts
Adds MIME/path helpers, MAX_GENERATED_IMAGE_SIZE, and persistGeneratedImageFromPath(threadId, sourcePath) that validates, copies, and returns a sanitized StoredAttachment; refactors safe-path resolution used by persist.
Server buffering, materialization, and persistence
apps/server/src/services/agent-service.ts, apps/server/src/services/turn-finalizer.ts, apps/server/src/repositories/message-repo.ts, apps/server/src/index.ts, apps/server/src/services/__tests__/turn-finalizer.test.ts
AgentService buffers GeneratedAttachment events; TurnFinalizer buffers/merges attachments and treats attachments-as-activity; MessageRepo.createAssistantIdempotent accepts and persists attachments and appends/merges on ignored inserts; server ignores GeneratedAttachment for normal broadcast flow.
Client store, UI, and tests
apps/web/src/stores/threadStore.ts, apps/web/src/components/chat/MessageBubble.tsx, apps/web/src/__tests__/*, apps/web/e2e/generated-image-message.spec.ts
ThreadStore validates/parses attachments and preserves them in session.message; MessageBubble renders assistant image attachments even when content is empty, adds preview lightbox and adjusted action text; unit and e2e tests added/updated.

Hook Infrastructure Refactoring

Layer / File(s) Summary
Env-edit blocking script & tests
scripts/agent/hooks/block-env-edits.mjs, scripts/agent/__tests__/block-env-edits.test.mjs, package.json
New Node ESM CLI hook extracts strings from TOOL_INPUT, finds protected .env* paths (excludes .env.example), and blocks by exit code or JSON decision (--codex); tests cover helpers and both modes; package test script narrowed to .test.mjs glob.
Hook configuration wiring
.claude/settings.json, .codex/hooks.json, .cursor/hooks.json
Hook commands updated to invoke the centralized block-env-edits.mjs script (Codex hook passes --codex).

Sequence Diagram(s)

sequenceDiagram
  participant CodexProvider
  participant AttachmentService
  participant AgentService
  participant TurnFinalizer
  participant MessageRepo
  participant WebClient
  CodexProvider->>AttachmentService: persistGeneratedImageFromPath(savedPath)
  AttachmentService-->>CodexProvider: StoredAttachment
  CodexProvider->>AgentService: emit GeneratedAttachment(attachment)
  AgentService->>TurnFinalizer: bufferAssistantAttachments(threadId, attachment)
  TurnFinalizer->>MessageRepo: createAssistantIdempotent(..., attachments)
  MessageRepo-->>TurnFinalizer: Message row with attachments
  WebClient->>AgentService: receives session.message with attachments
  WebClient-->>WebClient: render image thumbnail / open lightbox
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I chewed a script and stitched a flow,

Images travel where Codex seeds sow,
No bash to grep, Node gently guards,
Attachments nest in assistant cards,
Lightbox hops open — behold the show!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main feature: adding support for Codex-generated image attachments in the codebase.
Description check ✅ Passed The PR description follows the template with complete sections: What, Why, Key Changes, Config Changes, and Verification. All required information is present and detailed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@chuks-qua
chuks-qua merged commit d985185 into main Jun 12, 2026
6 of 7 checks passed
@chuks-qua
chuks-qua deleted the feat/gpt-image branch June 12, 2026 22:24
@mze-bot mze-bot Bot mentioned this pull request Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant