Skip to content

fix: avoid replaying file attachment content#1865

Merged
zerob13 merged 1 commit into
devfrom
codex/issue-1864-file-handling
Jul 2, 2026
Merged

fix: avoid replaying file attachment content#1865
zerob13 merged 1 commit into
devfrom
codex/issue-1864-file-handling

Conversation

@zerob13

@zerob13 zerob13 commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Tests

  • pnpm run format
  • pnpm run i18n
  • pnpm run lint
  • pnpm run typecheck
  • pnpm vitest run test/main/presenter/agentRuntimePresenter/contextBuilder.test.ts test/main/presenter/agentRuntimePresenter/compactionService.test.ts test/renderer/components/ChatInputBox.test.ts

Summary by CodeRabbit

  • New Features

    • Improved attachment handling in chats and summaries so files are represented with metadata instead of repeatedly re-sending full contents.
    • Better support for different attachment types, including images and audio, with behavior that adapts to the app’s capabilities.
  • Bug Fixes

    • Prevented file content bloat in later messages and compaction summaries.
    • Preserved attachment paths and markers while keeping inline content omitted unless needed.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an options parameter to buildUserMessageContent controlling inclusion of image, audio, and non-image file content, refactors buildNonImageFileContext accordingly, updates call sites (createUserChatMessage, recordToChatMessages), adjusts related tests, adds a spec document, an SDD workflow step, and an unrelated test mock update.

Changes

Attachment token bloat reduction

Layer / File(s) Summary
Spec and workflow docs
docs/issues/file-attachment-token-bloat/spec.md, .agents/skills/deepchat-sdd/SKILL.md
Adds a new spec document defining the file attachment token bloat problem and acceptance criteria, and adds an SDD workflow cleanup step for deleting plan/tasks files.
Content build options & non-image file context
src/main/presenter/agentRuntimePresenter/contextBuilder.ts
Introduces UserMessageContentBuildOptions and refactors buildNonImageFileContext to accept an options object, emitting placeholder text when file content inclusion is disabled.
buildUserMessageContent inclusion logic
src/main/presenter/agentRuntimePresenter/contextBuilder.ts
Derives include flags from options, conditionally builds audio/image structured parts, and reworks fallback text assembly to append image metadata when appropriate.
Call site wiring
src/main/presenter/agentRuntimePresenter/contextBuilder.ts
Updates createUserChatMessage and recordToChatMessages to pass explicit inclusion options (images/audio embedded vs. omitted per context).
Tests for attachment metadata behavior
test/main/presenter/agentRuntimePresenter/compactionService.test.ts, test/main/presenter/agentRuntimePresenter/contextBuilder.test.ts
Updates assertions to expect omitted file bodies with metadata placeholders, and adds tests for image/audio structured part handling under vision/audio modes.
Unrelated composer mock update
test/renderer/components/ChatInputBox.test.ts
Adds new mocked composer-related fields (composerActiveSkills, composerActiveCount, composerActiveSkillItems) to the useSkillsData test mock.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
    participant Caller as createUserChatMessage/recordToChatMessages
    participant Builder as buildUserMessageContent
    participant FileCtx as buildNonImageFileContext
    participant Prompt as ChatMessage content

    Caller->>Builder: call with options includeImageData includeAudioData includeFileContent
    Builder->>Builder: derive includeImageData and includeAudioData flags
    Builder->>Prompt: add input_audio structured part when audio enabled
    Builder->>FileCtx: build non-image file context with includeFileContent option
    FileCtx-->>Builder: return metadata with placeholder or full file content
    Builder->>Prompt: add image_url structured parts when vision and includeImageData enabled
    Builder->>Prompt: append image metadata text fallback when no image parts produced
    Builder-->>Caller: assembled ChatMessage content
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: preventing file attachment content from being replayed in prompts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/issue-1864-file-handling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
test/renderer/components/ChatInputBox.test.ts (1)

134-136: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Static mocks diverge from derived real-hook behavior.

composerActiveCount/composerActiveSkillItems are hardcoded rather than derived from activeSkillsRef, unlike the real useSkillsData where they're computed from composerActiveSkills (see useSkillsData.ts lines 39-56). Not currently exercised since ChatInputBox.vue only reads composerActiveSkills, but any future assertion on these fields would silently diverge from real behavior.

♻️ Optional alignment
-    composerActiveCount: ref(0),
-    composerActiveSkillItems: ref([]),
+    composerActiveCount: computed(() => activeSkillsRef.value.length),
+    composerActiveSkillItems: ref([]),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/renderer/components/ChatInputBox.test.ts` around lines 134 - 136, The
test mock in ChatInputBox.test.ts has composerActiveCount and
composerActiveSkillItems hardcoded instead of matching the derived behavior in
useSkillsData; update the mock setup so these fields are computed from
composerActiveSkills/activeSkillsRef the same way useSkillsData does, using the
existing activeSkillsRef and the related reactive symbols. Keep the mock aligned
with the real hook’s derived outputs so any future assertions against
composerActiveCount or composerActiveSkillItems reflect actual behavior.
src/main/presenter/agentRuntimePresenter/contextBuilder.ts (1)

426-463: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider simplifying the early-return guard using shouldBuildImageParts.

Line 462's condition (!supportsVision || imageFiles.length === 0) && audioParts.length === 0 doesn't account for includeImageData being explicitly false while vision is supported and images exist (the historical-image path). Functionally the code still converges to the same result via the later !hasStructuredParts branch, but it does redundant work building empty parts/imageParts arrays for a case that could return baseText immediately.

♻️ Optional simplification
-  if ((!supportsVision || imageFiles.length === 0) && audioParts.length === 0) {
+  if (!shouldBuildImageParts && audioParts.length === 0) {
     return baseText
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/presenter/agentRuntimePresenter/contextBuilder.ts` around lines 426
- 463, Simplify the early-return guard in contextBuilder so it uses
shouldBuildImageParts and returns baseText when image parts are not being built,
including the case where includeImageData is false but vision is supported and
imageFiles exist. Update the conditional near the baseText return in
buildContext to avoid the redundant parts/imageParts work and keep the logic
aligned with shouldBuildImageParts and audioParts handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/main/presenter/agentRuntimePresenter/contextBuilder.ts`:
- Around line 426-463: Simplify the early-return guard in contextBuilder so it
uses shouldBuildImageParts and returns baseText when image parts are not being
built, including the case where includeImageData is false but vision is
supported and imageFiles exist. Update the conditional near the baseText return
in buildContext to avoid the redundant parts/imageParts work and keep the logic
aligned with shouldBuildImageParts and audioParts handling.

In `@test/renderer/components/ChatInputBox.test.ts`:
- Around line 134-136: The test mock in ChatInputBox.test.ts has
composerActiveCount and composerActiveSkillItems hardcoded instead of matching
the derived behavior in useSkillsData; update the mock setup so these fields are
computed from composerActiveSkills/activeSkillsRef the same way useSkillsData
does, using the existing activeSkillsRef and the related reactive symbols. Keep
the mock aligned with the real hook’s derived outputs so any future assertions
against composerActiveCount or composerActiveSkillItems reflect actual behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3354a114-e83c-4593-84cc-d8effd5e8471

📥 Commits

Reviewing files that changed from the base of the PR and between ec18d24 and b6a0c96.

📒 Files selected for processing (6)
  • .agents/skills/deepchat-sdd/SKILL.md
  • docs/issues/file-attachment-token-bloat/spec.md
  • src/main/presenter/agentRuntimePresenter/contextBuilder.ts
  • test/main/presenter/agentRuntimePresenter/compactionService.test.ts
  • test/main/presenter/agentRuntimePresenter/contextBuilder.test.ts
  • test/renderer/components/ChatInputBox.test.ts

@zerob13 zerob13 merged commit f12b17c into dev Jul 2, 2026
3 checks passed
@zhangmo8 zhangmo8 deleted the codex/issue-1864-file-handling branch July 7, 2026 05:47
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.

[BUG] File attachments cause massive token bloat — file data resent with every API call

1 participant