fix(webapp): precise S2 record cap + CORS 413 on session append#3720
Conversation
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (6)**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
{packages/core,apps/webapp}/**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
**/*.ts📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)
Files:
apps/webapp/**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Files:
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (5)📚 Learning: 2026-03-22T13:26:12.060ZApplied to files:
📚 Learning: 2026-03-22T19:24:14.403ZApplied to files:
📚 Learning: 2026-05-18T08:21:27.694ZApplied to files:
📚 Learning: 2026-05-18T08:21:27.694ZApplied to files:
📚 Learning: 2026-05-12T21:04:05.815ZApplied to files:
🔇 Additional comments (2)
WalkthroughThis PR adds per-record metered-size enforcement to realtime session append operations. The S2 service layer now exports size constants and a Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
…act (triggerdotdev#3721) ## Summary Updates the AI chat docs to match the slim-wire + field-level merge behavior shipped in triggerdotdev#3719 and the precise `.in/append` cap + CORS-readable 413 shipped in triggerdotdev#3720. No behavior changes here — code is correct in `main`; the docs were lagging on three patterns customers copy out of the page. ## What changed - **`hydrateMessages` examples upsert by id** (in `lifecycle-hooks.mdx`, `patterns/database-persistence.mdx`, and `patterns/persistence-and-replay.mdx`). The previous `stored.push(newMsg)` pattern duplicated the assistant id on HITL continuations and caused the LLM to receive a tool call with no `arguments`. The new examples include the rationale inline. - **`onValidateMessages` example filters to user messages** (`lifecycle-hooks.mdx`). The previous example called `validateUIMessages({ messages, tools })` directly, which now throws on HITL slim wires (the AI SDK schema requires `input` on resolved tool parts). New example shows the filter pattern, with a Warning callout explaining why. - **Merge contract description updated** (`lifecycle-hooks.mdx`). The old wording said incoming messages are "auto-merged" / "replaced"; the new description explains the actual field-level overlay (state advances only). - **Approval-responded wire example slimmed** (`client-protocol.mdx`). Shows the minimum shape the agent reads — `state` + `approval` (or `output` / `errorText` for HITL). Notes that the built-in transports ship this slim shape by default and that fuller shapes are still accepted. - **`/in/append` 413 row and FAQ updated** (`client-protocol.mdx`, `patterns/trusted-edge-signals.mdx`). Reflects the new precise S2 cap and the CORS-readable 413. - **New changelog entry** at the top of `changelog.mdx` covering all of the above. The historical `## 512 KiB ceiling removed` entry further down the changelog is left as-is (it's a snapshot of the prior transition), and the v4.5 upgrade-guide section is skipped — the merge contract is backwards compatible. ## Test plan - Mintlify dev preview renders cleanly with no broken anchors - Linked references resolve (`/ai-chat/lifecycle-hooks#hydratemessages`, `/ai-chat/lifecycle-hooks#onvalidatemessages`, `/ai-chat/patterns/database-persistence#alternative-hydratemessages`, `/ai-chat/client-protocol#step-3-send-messages-stops-and-actions`, `/ai-chat/patterns/large-payloads`)
Summary
Two improvements to session
.in/append:TypeError: Failed to fetch. App-side retry-on-disconnect loops no longer spin forever on a permanently-rejected payload.Design
S2 enforces a per-record metered size of
8 + 2*H + Σ(header name + value) + body ≤ 1048576bytes. With no record headers (our case), the budget reduces tobody ≤ 1048568. Verified empirically against cloud S2 — append succeeds at metered=1048576 and 422s at 1048577 withrecord must have metered size less than 1 MiB.The old
MAX_APPEND_BODY_BYTES = 512 KiBwas derived by assuming worst-case JSON escape doubling (every byte becomes\"or\\), giving(1 MiB - overhead) / 2. Safe, but rejects ~half the legitimate input space.The new flow:
S2RealtimeStreams.#appendPartByNamecomputesBuffer.byteLength(JSON.stringify({data: part, id: partId}), "utf8") + 8and throwsS2RecordTooLargeError(aServiceValidationErrorwith status 413) if it would exceed S2's ceiling. The route's existing error branch maps the throw to a 413 with a descriptive message.The 413 CORS fix is a single-line change in
apiBuilder.server.ts—wrapResponsewas being skipped on the body-too-large branch; every other error branch wraps; the 413 was the exception.Test plan
[1048568, 1048569, ..., 1048576]and across H ∈ {0, 1×5 hdr bytes, 1×14 hdr bytes} — the formula matches exactlystatus: 413(noTypeError: Failed to fetch)