Repository navigation
feat(ai-ui-message-stream): bridge TanStack AI and the AI SDK UI message stream - #1893
tombeckenham wants to merge 7 commits into
Conversation
…age stream Add @tanstack/ai-ui-message-stream. Serve AI SDK useChat from chat() with chatParamsFromAISDKRequest and toUIMessageStream, or point TanStack useChat at an AI SDK route with fromChatTransport. Text, reasoning, tools, client tools, tool approvals, activity, subagents and stream resume cross the bridge. Shared state goes from a TanStack server to an AI SDK client. Adds unit tests against the real ai and @tanstack/ai-client code, E2E scenarios, two migration docs pages, and the migration skill update.
…idge as a stop gap Add a reference page that lists, per feature, event and message part, what crosses the bridge as is, what is mapped or grouped, and what is dropped. Say on every page that the bridge is a stop gap while porting.
…r-executed tools An audit of both wires found data the bridge dropped that providers need: - Tool-call provider metadata (Gemini thoughtSignature, OpenAI item ids) now round-trips through callProviderMetadata in both directions. - Provider-executed tools (web search) keep their flag, so neither client runs them, and their sources become source-url chunks. - Steps map to start-step / STEP_* events, and the history sent to an AI SDK route gets step-start parts, so a tool loop keeps its order. - Model, response ids and usage go into message metadata, and come back for OpenAI Responses replay. - The approval signature, descriptor and automatic approvals are kept. - System messages are no longer sent to an AI SDK route, and a finished structured output goes back as text. TOOL_CALL_END now waits for an approval or output of the same call, so late metadata never follows TOOL_CALL_END. The compatibility table is rewritten from the new mappings and aligned.
…nect for AI SDK routes TanStack useChat gets more from an AI SDK route: - fromChatTransport sends the client's tool declarations in the request body. clientToolsFromAISDKBody(body, serverTools) turns them into AI SDK tools without execute on the route, so client and WebMCP tools need no copy there. Server tools win a name clash. - With outputSchema, an Output.object answer becomes a typed structured-output part with partial objects and a checked final value. - A dropped stream reconnects with createReconnectTracker, the backoff of the TanStack HTTP connections, set with the reconnect option. @tanstack/ai-client now exports createReconnectTracker. Tests prove client persistence, the message queue, devtools and loading saved AI SDK chats over the bridge.
🦋 Changeset detectedLatest commit: a576436 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
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 |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
View your CI Pipeline Execution ↗ for commit a576436
☁️ Nx Cloud last updated this comment at |
Coverage✅ Coverage held across 75 compared package(s). Each package is measured twice in this job — on this PR and on its merge-base with
|
@tanstack/ai
@tanstack/ai-acp
@tanstack/ai-angular
@tanstack/ai-anthropic
@tanstack/ai-bedrock
@tanstack/ai-byteplus
@tanstack/ai-claude-code
@tanstack/ai-client
@tanstack/ai-cloudflare
@tanstack/ai-code-mode
@tanstack/ai-code-mode-snippets
@tanstack/ai-codex
@tanstack/ai-cohere
@tanstack/ai-compaction
@tanstack/ai-computer-local
@tanstack/ai-computer-playwright
@tanstack/ai-computer-sandbox
@tanstack/ai-computer-use
@tanstack/ai-devtools-core
@tanstack/ai-durable-stream
@tanstack/ai-elevenlabs
@tanstack/ai-event-client
@tanstack/ai-fal
@tanstack/ai-gemini
@tanstack/ai-grok
@tanstack/ai-grok-build
@tanstack/ai-groq
@tanstack/ai-harness
@tanstack/ai-harness-cli
@tanstack/ai-isolate-cloudflare
@tanstack/ai-isolate-daytona
@tanstack/ai-isolate-e2b
@tanstack/ai-isolate-node
@tanstack/ai-isolate-quickjs
@tanstack/ai-isolate-quickjs-bun
@tanstack/ai-llmgateway
@tanstack/ai-lovable
@tanstack/ai-mcp
@tanstack/ai-memory
@tanstack/ai-mistral
@tanstack/ai-neon
@tanstack/ai-octane
@tanstack/ai-ollama
@tanstack/ai-ollaya
@tanstack/ai-openai
@tanstack/ai-opencode
@tanstack/ai-openrouter
@tanstack/ai-perplexity
@tanstack/ai-persistence
@tanstack/ai-preact
@tanstack/ai-react
@tanstack/ai-reactor
@tanstack/ai-remix
@tanstack/ai-sandbox
@tanstack/ai-sandbox-blaxel
@tanstack/ai-sandbox-boxd
@tanstack/ai-sandbox-cloudflare
@tanstack/ai-sandbox-daytona
@tanstack/ai-sandbox-docker
@tanstack/ai-sandbox-e2b
@tanstack/ai-sandbox-local-process
@tanstack/ai-sandbox-railway
@tanstack/ai-sandbox-sprites
@tanstack/ai-sandbox-upstash-box
@tanstack/ai-sandbox-vercel
@tanstack/ai-skills
@tanstack/ai-solid
@tanstack/ai-svelte
@tanstack/ai-typesafe
@tanstack/ai-ui-message-stream
@tanstack/ai-utils
@tanstack/ai-vercel-gateway
@tanstack/ai-vertex
@tanstack/ai-vue
@tanstack/ai-worldlabs
@tanstack/openai-base
@tanstack/preact-ai-devtools
@tanstack/react-ai-devtools
@tanstack/solid-ai-devtools
@tanstack/svelte-ai-devtools
commit: |
Port an app from the Vercel AI SDK to TanStack AI one side at a time. This is a stop gap while porting, not a long-term integration. The new
@tanstack/ai-ui-message-streampackage serves AI SDKuseChat(and AI Elements) fromchat(), and lets TanStackuseChatcall an AI SDKstreamTextroute. Text, reasoning, tools, tool approvals, activity, subagents and stream resume cross in both directions.🎯 Changes
@tanstack/ai-ui-message-stream. It converts between AG-UI events and the AI SDK v7 UI message stream, and between the two message history shapes.chatParamsFromAISDKRequest,toUIMessageStream,toResumableUIMessageStreamResponse,resumeUIMessageStreamResponse.fromChatTransport(transport, { threadId, tools })wraps any AI SDKChatTransport, so fetch, SSE and request options stay in AI SDK code.tool-approval-requeston one side and a boundtool-approvalinterrupt on the other.thoughtSignatureand OpenAI item ids on tool calls, provider-executed tools (web search) and their sources, step boundaries, and model, response ids and usage in message metadata.TOOL_CALL_ENDwaits for an approval or output of the same call, so no metadata event follows it.useChaton an AI SDK route (merged in from the stacked feat(ai-ui-message-stream): client tools, structured output and reconnect for AI SDK routes #1891):clientToolsFromAISDKBody(body, serverTools)reads them there, so the route needs no copy. WebMCP page tools work too.outputSchema, anOutput.objectanswer is a typedstructured-outputpart with partial objects.reconnectoption.@tanstack/ai-clientexportscreateReconnectTrackerfor this and is now a required peer.ai-sdk-client-tanstack-server,tanstack-client-ai-sdk-server) and a compatibility reference (ai-sdk-compatibility) that lists, per feature, event and message part, what crosses as is, what is mapped or grouped, and what is dropped. Each page says the bridge is a stop gap. All are linked from "From Vercel AI SDK". Thetanstack-ai-migrationskill is updated.minorfor the new package.The converters started from the Cloudflare Agents fork (
tombeckenham/agents-tom, branchag-ui-canonical) and were rewritten on@ag-ui/core1.0 andai7 types.✅ Checklist
pnpm run test:pr, or these tests do not apply to this pull request.docs/for this change, or this change is not user-facing.pnpm changeset), or this PR does not change a published package.🚀 Release Impact
Testing
Commands run
packages/ai-ui-message-stream:vitest run(48 passed),test:types,test:oxlint,test:build(publint).packages/ai-client:test:types,test:oxlint.knipon the package,pnpm test:sherif,pnpm test:docs, andkiira checkon the new and changed docs (all snippets pass).pnpm nx run @tanstack/ai-e2e:test:types.pnpm test:prand the E2E suite. CI runs them.Manual test
pnpm --filter @tanstack/ai-e2e test:e2e -- --grep "AI SDK UI message stream"./ai-sdk-clientin the e2e app. The AI SDKuseChatpage streams achat()reply with a server tool./ai-sdk-client?prompt=Delete%20notes.txtand click approve. The tool runs and the reply continues./ai-sdk-server. TanStackuseChatstreams the reply of an AI SDKstreamTextroute.How this PR makes testing easy
packages/ai-ui-message-stream/tests/run each direction through the realaireader, realchat()withfakeText, and a realChatClient.testing/e2e/tests/ui-message-stream.spec.tshas 6 scenarios: text and tools both ways, approvals both ways, activity, and resume after a reload.Risk / rollback
The package is new, and no existing package imports it. Revert the PR to remove it. The resume-after-reload E2E test depends on timing and is the most likely to be flaky.
Public API change
Before: AI SDK
useChatcannot read achat()route.After
@tanstack/ai-clientalso exportscreateReconnectTracker.