Skip to content

fix(assistants): fix silent zero-attachment bug in Claude session upload detection - #462

Open
Sergei-Nikitin-epam wants to merge 4 commits into
codemie-ai:mainfrom
Sergei-Nikitin-epam:EPMCDME-13907
Open

fix(assistants): fix silent zero-attachment bug in Claude session upload detection#462
Sergei-Nikitin-epam wants to merge 4 commits into
codemie-ai:mainfrom
Sergei-Nikitin-epam:EPMCDME-13907

Conversation

@Sergei-Nikitin-epam

Copy link
Copy Markdown
Contributor

Summary

codemie assistants chat was silently returning no attachments when a file was uploaded in a Claude session, because claudeUploadsDetector made wrong assumptions about the Claude Code JSONL message structure. Two bugs were identified via manual testing against a live Claude session (EPMCDME-13907).

Bug A — wrong turn anchor: The previous backward scan stopped at the first type === 'assistant' message. In real Claude Code JSONL the assistant tool_use entry appears after the user's isMeta messages for the same prompt, so the scan broke before reaching the image data.

Bug B — split isMeta structure: Base64 image data and the [Image: source: /path] filename text live in separate isMeta messages (not the same one), so the old single-message two-pass produced the image with a fallback filename instead of the real name.

Changes

  • ClaudeMessage interface — added promptId?: string (groups all JSONL entries belonging to one user prompt turn)
  • extractFileContentFromMessages — replaced the backward turn-boundary scan with a promptId-based algorithm: find the most recent non-meta user message, collect all isMeta entries sharing its promptId, gather filenames across all of them first, then match positionally to base64 attachment items
  • Tests — 2 new tests encoding the real split-message structure (Bug B) and the assistant-tool-use-in-between ordering (Bug A); 8 single-isMeta fixtures gained a non-meta anchor message; cross-turn isolation test given promptId annotations; 40 tests, all green

Testing

  • Tests added for Bug A (assistant tool_use after isMeta) and Bug B (split isMeta messages)
  • All 40 unit tests pass (npx vitest run)
  • TypeScript clean (npm run typecheck)
  • Manual test with node bin/codemie-claude.js confirmed fix resolves the live session failure

Checklist

  • Code follows project standards
  • CI is green (npm run ci)
  • No merge conflicts with main

Closes EPMCDME-13907

SergeyVNikitin and others added 4 commits August 4, 2026 17:52
…oad detection

Replace broken two-pass buildAttachmentMap (wrong JSONL structure assumption)
and RECENT_MESSAGES_LIMIT=2 (too narrow for real sessions with tool-result
messages) with a turn-boundary backward scan that stops at the most recent
assistant message.

Real Claude Code JSONL has isMeta=true messages carrying both base64 attachment
data and [Image: source: /path] filename text in the same message object.
The old code expected base64 in a non-meta parent and filename text in a meta
child, so the attachment map was never populated and zero files were returned.

The scan window of 2 also broke in real sessions where tool-result messages
at positions 1-2 pushed the image meta message to position 3, outside the window.

EPMCDME-13907
Technical analysis, implementation plan, code review diff and verdict,
complexity assessment, decision log, and events ledger for the
claudeUploadsDetector fix.
…ude sessions

The previous turn-boundary scan (stopping at type==='assistant') failed in
real Claude Code JSONL because:
- Bug A: the assistant tool_use entry appears *after* the user's isMeta
  messages for the same prompt, so the scan broke before reaching the images.
- Bug B: base64 data and the [Image: source: /path] filename live in two
  *separate* isMeta entries (not the same one), so the old single-message
  pass produced the image with a fallback filename.

Fix: use the promptId field that Claude Code stamps on every message in a
single prompt turn. Find the most recent non-meta user message, capture its
promptId, collect all isMeta messages sharing that id, gather filenames
across them first, then match positionally to base64 attachment items.

Also adds promptId to the ClaudeMessage interface and updates test fixtures
to reflect the real split-message JSONL structure.

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
…t --conversation-id

--conversation-id identifies the assistant chat thread (e.g. a workflow_id
generated by a skill). CODEMIE_SESSION_ID identifies the Claude session whose
JSONL contains uploaded file blobs. Using --conversation-id for session lookup
caused detectFileUploadsFromSession to look for a non-existent session file,
returning no attachments even when files were uploaded in the current Claude turn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162w98kuqJ7EWaA6h2FjDCK
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.

2 participants