Skip to content

[Bug] A chat past the provider's image cap can never be recovered: no pruning, and "Try again" re-sends the same history #1289

Open

Description

@myhdesarrolo

Environment: ThinkRail 0.3.2 (stable, ~/.local/bin/thinkrail.exe), Windows 11, provider enforces a per-conversation image cap (the 400 below is Anthropic-shaped: invalid_request_error, "we currently limit the number of images per conversation to 120").

Symptom: once a chat has accumulated more image blocks than the provider allows, every subsequent turn fails, including plain text turns and including the UI's own "Try again", which re-sends the same history:

400: {"message":"Too many images were provided, we currently limit the number of images per conversation to 120 (ref: …)","type":"invalid_request_error","param":null,"code":null}

There is no way back from inside the app: the composer stays enabled, the retry button is offered, and each attempt reposts the oversized history. The only recovery is editing the transcript on disk by hand.

How the chat got there: image blocks are stored inline in the transcript, {type:'image', data:'<base64>', mimeType:'image/png'}, inside message/toolResult content arrays. Screenshots that a tool returns (Playwright/MCP page.screenshot, or a pasted clipboard image) are kept forever. The affected transcript here:

entries 3 010
image blocks 182 across 165 entries
base64 payload 27.3 MB (file 33.4 MB)
compactions already in the file 3
provider limit 120

Compaction does not remove image blocks, so it doesn't bring the chat back under the cap.

Expected: a conversation should stay usable no matter how many images have passed through it — the same principle that already applies to context compaction. At minimum the failure should be actionable (say the chat is over the provider's image cap and what to do) instead of offering a retry that cannot succeed.

Suggested approach: prune at send time rather than in the UI. Build the request with at most N recent image blocks (N configurable, comfortably under the smallest provider limit) and replace older ones with a short text placeholder, the way long tool output is already elided. Doing it while compacting would also keep transcripts small (this one is 33 MB, 27 MB of it images). Both paths are cheap compared with the current dead end.

Workaround used to recover the chat: copy the .jsonl aside, walk the entries and replace every {type:'image',…} block outside the most recent 20 entries with a text placeholder, keep everything else identical. 3 010 entries and all text preserved, images 182 → 20, file 33.4 MB → 9.3 MB, and the chat sends again.

Related: #671 (WebSocket frames over 16 MB close the socket while the composer allows 24 MB of images) is a different failure on the same unbounded-image path — one is the transport, this is the provider cap. Fixing the send-time pruning would make #671 much harder to reach.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions