Skip to content

fix(history): return only the fields the UI renders - #39

Merged
IBJunior merged 1 commit into
mainfrom
fix/history-payload-projection
Sep 16, 2026
Merged

IBJunior merged 1 commit into
mainfrom
fix/history-payload-projection

Conversation

@IBJunior

Copy link
Copy Markdown
Member

GET /api/agent/history/:threadId returned msg.toDict() cast to MessageResponse — LangChain's own serialization, not our wire contract. The cast asserted a shape rather than producing one, so every field LangChain carries rode along unnoticed: content_blocks (a byte-identical duplicate of content, verified on all 65 AI messages in the sample), usage_metadata, response_metadata, invalid_tool_calls, ai.name (always "model") and tool.metadata (the same @langchain/core version on every row). None have a reader anywhere in src/.

A 24-message thread went out at 34.7 KB.

projectHistory now builds the response explicitly. Also drops an AI content array when it only restates tool_calls — the same call was serialized three times.

34.7 KB → 21.8 KB (−37%), measured live on the same thread.

Verification

Diffed the live before/after payload field by field: every UI-read field byte-identical, order preserved, all 10 tool results and the chart artifact intact. The only differences were three tool_calls: [] empty arrays now absent — both consumers are guarded (Array.isArray(...) && length > 0, || []), so behavior is unchanged.

Kept deliberately: the human content array passes through untouched, since HumanMessage extracts file attachments from inside it for checkpoint-loaded messages; and tool.status, which costs ~0.3% and is where an approval outcome would surface.

historyProjection.test.ts pins the contract (DB-free). 274 tests pass, tsc --noEmit clean.

🤖 Generated with Claude Code

`toDict()` is LangChain's serialization, not our wire contract, and casting it
to `MessageResponse` shipped every field it carries: `content_blocks` (a
byte-identical copy of `content`), token counts and provider metadata no
component reads. A 24-message thread went out at 34.7 KB.

Project explicitly instead — 37% smaller on that thread, with the OpenAPI
response narrowed from an open object to the real shape.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@IBJunior
IBJunior merged commit b0fd2fa into main Sep 16, 2026
1 check passed
@IBJunior
IBJunior deleted the fix/history-payload-projection branch September 16, 2026 20:09
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