Skip to content

fix(checkpoint): externalize images in subagent transcripts before size cap - #2069

Open
suhaanthayyil wants to merge 4 commits into
mainfrom
fix/track-2063
Open

fix(checkpoint): externalize images in subagent transcripts before size cap#2069
suhaanthayyil wants to merge 4 commits into
mainfrom
fix/track-2063

Conversation

@suhaanthayyil

@suhaanthayyil suhaanthayyil commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Trail: https://entire.io/gh/entireio/cli/trails/1100

What: Run image externalization on subagent transcripts (when enabled) before the 50MB size check, and store returned assets under tasks/<id>/assets/.

Why / how it helps: Subagent path only sanitized then size-checked/redacted, so image-heavy transcripts were dropped whole and Codex input_image base64 reached redaction intact (corruption risk).

How: prepareSubagentTranscript: sanitize → optional imageextract → size-check externalized bytes; wire assets into persistent + ephemeral task writers.

Testing:

  • go test ./cmd/entire/cli/checkpoint/ -count=1 (375 passed)
  • go test ./cmd/entire/cli/transcript/imageextract/
  • go build ./... clean

Fixes #2063

Related: #2060 (redact skip for input_image), #2058 (durable subagent storage still open)

…ze cap

prepareSubagentTranscript only sanitized then size-checked, while the main
session path runs sanitize → externalize → redact. Inline images in subagent
transcripts therefore inflated past MaxChunkSize (dropped whole) or reached
redaction still as base64 (Codex input_image corrupted).

Externalize via the agent image codec when ENTIRE_EXTERNALIZE_IMAGES is on,
size-check the shrunk transcript, and write returned assets under
tasks/<id>/assets/ in both persistent and ephemeral stores.

Copilot AI 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.

Pull request overview

This PR updates the subagent-transcript storage pipeline in the checkpoint subsystem so that (when enabled) inline base64 images are externalized into checkpoint assets before enforcing the 50MB blob cap, aligning subagent handling with the main session transcript path and preventing image-heavy transcripts from being dropped or corrupted during redaction.

Changes:

  • Extend prepareSubagentTranscript to: sanitize → (opt-in) image externalize → size-check, returning extracted assets alongside the rewritten transcript.
  • Wire extracted task assets into both persistent (treeWriter) and ephemeral (shadow-branch) task checkpoint writers under tasks/<id>/assets/.
  • Add focused unit tests covering Claude + Codex image externalization, disabled gating, and size-cap behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
cmd/entire/cli/checkpoint/subagent_transcript.go Adds image externalization to the subagent transcript preparation pipeline and returns extracted assets.
cmd/entire/cli/checkpoint/subagent_transcript_test.go Adds unit tests validating extraction/gating and size-cap behavior for Claude and Codex formats.
cmd/entire/cli/checkpoint/persistent.go Persists extracted task assets into the committed checkpoint tree under the task subtree.
cmd/entire/cli/checkpoint/ephemeral.go Persists extracted task assets into the shadow-branch task subtree via tree-surgery changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cmd/entire/cli/checkpoint/ephemeral.go Outdated
Comment thread cmd/entire/cli/checkpoint/persistent.go Outdated
@suhaanthayyil
suhaanthayyil marked this pull request as ready for review August 19, 2026 18:07
@suhaanthayyil
suhaanthayyil requested a review from a team as a code owner August 19, 2026 18:07
Address Copilot review: prepareSubagentTranscript() ran even when
os.ReadFile failed, wasting work and risking misleading size/
externalization warnings from partial/empty reads before the readErr
check. Guard the call behind readErr == nil in both ephemeral and
persistent task writers.

Entire-Checkpoint: 01M0DMQ8A29WGK3S3VCAWA0THH
@suhaanthayyil

Copy link
Copy Markdown
Contributor Author

Fixed Copilot review comment: gated prepareSubagentTranscript() behind readErr == nil in both ephemeral.go and persistent.go. gofmt clean, go build ./... clean, checkpoint tests pass (637 passed).

SHA: 0f73c38

suhaanthayyil and others added 2 commits August 19, 2026 14:51
…re task bundles atomically

Image externalization lifted any sufficiently long base64 out of an
image-shaped field on the strength of the transcript's declared media type.
Assets are written to git as raw blobs and never pass through the redaction the
transcript body gets, so a non-image payload in that field — an agent packing a
file dump into a data-URI, a mislabeled upload — was moved out of the redacted
body and committed verbatim. Externalization now requires the decoded bytes to
carry a recognized image signature; anything else stays inline, where redaction
still sees it.

Extraction was also unbounded in aggregate: the per-image cap said nothing about
the set, whose decoded bytes are all retained until the caller has written them,
and the cap was applied only after DecodeString had already allocated the full
output. Add a hard total-bytes bound, a count bound, and an encoded-length check
that refuses an oversized value before decoding it.

A task's subagent transcript and its assets are one unit — once externalized the
image bytes exist nowhere else — but each was written independently, so a failed
asset write published a transcript whose placeholders could never resolve, and a
failed transcript write left orphan blobs. Both stores now stage the pair and
publish only once every blob exists. The asset set is also a replacement rather
than an addition: a rewrite clears the task's assets/ subtree first, including
when the new set is empty, which is what previously left the last attempt's
screenshots and manifest behind, referenced by nothing. A dropped write (source
unreadable, or oversize) still leaves the stored pair untouched, since those two
agree with each other.

Co-authored-by: Cursor <cursoragent@cursor.com>
Entire-Checkpoint: 01M0KSBJ7AS3MV7HB26WTRW82Z
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Subagent transcripts skip image externalization before size cap / redaction

2 participants