Files
Mark Fogle ad67eb068c fix(showcase/mastra): sanitize OpenAI Responses input[].id so multi-turn chat stops 400-ing
Multi-turn chat on every mastra demo fails on the 2nd turn:

  AI_APICallError: Invalid 'input[3].id': 'msg-92Y7BhMpWBhXt7dm'.
  Expected an ID that contains letters, numbers, underscores, or dashes,
  but this value contained additional characters. (code: INCOMPLETE_STREAM)

Root cause: OpenAI's Responses API actually REJECTS dashes in `input[].id`
(its 400 message misleadingly lists dashes as allowed — empirically only
`[A-Za-z0-9_]` is accepted; `msg-92Y7…` 400s, `msg_92Y7…` succeeds).
CopilotKit mints message ids like `msg-…`, and @ag-ui/mastra + the AI SDK
forward them straight into `input[].id` when replaying prior-turn history, so
the whole request fails. Turn 1 works (no prior ids); every turn after dies.

Fix at the HTTP boundary: the mastra provider already routes every outbound
LLM call through `forwardingFetch` (header-forwarding shim). Rewrite dashes
(and any other non-`[A-Za-z0-9_]` char) in each outbound `input[].id` to `_`
there.

Why here and not in the @ag-ui/mastra message conversion: this touches ONLY
the bytes sent to OpenAI. Mastra's in-memory `CoreMessage.id` — which drives
its upsert-by-id history dedup — is left untouched, so dedup is unaffected.
OpenAI-issued ids (`msg_…`, `rs_…`) contain no dashes and pass through
unchanged, preserving server-side conversation-state references. Chat
Completions bodies (no `input[]` array) are untouched.

Supersedes the ineffective ag-ui-protocol/ag-ui#2227 (a bridge-layer charset
munge that kept dashes — a no-op on the real failing ids; being reverted).

Tests: tests/vitest/header-forwarding-id-sanitize.test.ts (8 cases — the real
failing id, valid-id no-op, full-charset mapping, body rewrite, no-op/passthrough,
chat-completions untouched). All green.

--no-verify: sparse showcase checkout has no monorepo lefthook/commitlint binaries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 00:40:52 +00:00
..