feat(ai-client): accept a per-call body via SendMessageOptions - #1027
feat(ai-client): accept a per-call body via SendMessageOptions#1027boring91 wants to merge 2 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
🚧 Files skipped from review as they are similar to previous changes (15)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughAdds per-call ChangesPer-call message bodies
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to This change adds per-call request body support across chat clients and wrappers without changing existing call behavior; no actionable merge-blocking risk remains after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant Caller
participant ChatClient
participant ConnectionAdapter
participant ChatAPI
Caller->>ChatClient: sendMessage(content, { body })
ChatClient->>ChatClient: merge per-call body with chat-level body
ChatClient->>ConnectionAdapter: send request with forwardedProps
ConnectionAdapter->>ChatAPI: POST chat request
ChatAPI-->>Caller: assistant response
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.changeset/spotty-donuts-repeat.md:
- Line 9: Correct the direct ChatClient usage in the changeset: reserve
sendMessage(content, { body: { ... } }) for framework hooks, and document
ChatClient calls as sendMessage(content, { ... }) with the marker fields
directly, or as options passed in the third argument.
In `@packages/ai-client/tests/chat-client.test.ts`:
- Around line 3400-3448: Move the added ChatClient body-precedence tests from
packages/ai-client/tests/chat-client.test.ts#L3400-L3448 into a source-adjacent
*.test.ts file covering ChatClient, move the queue-body test from
packages/ai-client/tests/chat-client-queue.test.ts#L688-L722 into its
source-adjacent test file, move the injectChat test from
packages/ai-angular/tests/inject-chat.test.ts#L126-L147 into its source-adjacent
test file, and move the useChat test from
packages/ai-react/tests/use-chat.test.ts#L292-L319 into its source-adjacent test
file; preserve the existing test behavior and assertions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 81377b9c-09ab-4682-a091-3342b2d01c25
📒 Files selected for processing (15)
.changeset/spotty-donuts-repeat.mddocs/chat/connection-adapters.mdpackages/ai-angular/tests/inject-chat.test.tspackages/ai-client/src/chat-client.tspackages/ai-client/src/types.tspackages/ai-client/tests/chat-client-queue.test.tspackages/ai-client/tests/chat-client.test.tspackages/ai-preact/src/use-mcp-app-bridge.tspackages/ai-react/src/types.tspackages/ai-react/src/use-mcp-app-bridge.tspackages/ai-react/tests/use-chat.test.tspackages/ai-solid/src/types.tstesting/e2e/fixtures/chat/basic.jsontesting/e2e/src/routes/$provider/$feature.tsxtesting/e2e/tests/per-call-body.spec.ts
|
thanks for this, I have the same issue! |
a3f47d9 to
9ee3d19
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
|
Maintainer sweep: rebased onto |
|
View your CI Pipeline Execution ↗ for commit a420768
☁️ Nx Cloud last updated this comment at |
9ee3d19 to
a34529b
Compare
|
Maintainer sweep: rebased onto |
a34529b to
115ec26
Compare
|
Maintainer sweep: rebased onto |
@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-code-mode
@tanstack/ai-code-mode-snippets
@tanstack/ai-codex
@tanstack/ai-cohere
@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-isolate-cloudflare
@tanstack/ai-isolate-daytona
@tanstack/ai-isolate-node
@tanstack/ai-isolate-quickjs
@tanstack/ai-isolate-quickjs-bun
@tanstack/ai-mcp
@tanstack/ai-memory
@tanstack/ai-mistral
@tanstack/ai-ollama
@tanstack/ai-openai
@tanstack/ai-opencode
@tanstack/ai-openrouter
@tanstack/ai-perplexity
@tanstack/ai-persistence
@tanstack/ai-preact
@tanstack/ai-react
@tanstack/ai-react-ui
@tanstack/ai-sandbox
@tanstack/ai-sandbox-cloudflare
@tanstack/ai-sandbox-daytona
@tanstack/ai-sandbox-docker
@tanstack/ai-sandbox-local-process
@tanstack/ai-sandbox-sprites
@tanstack/ai-sandbox-vercel
@tanstack/ai-solid
@tanstack/ai-solid-ui
@tanstack/ai-svelte
@tanstack/ai-utils
@tanstack/ai-vercel-gateway
@tanstack/ai-vue
@tanstack/ai-vue-ui
@tanstack/openai-base
@tanstack/preact-ai-devtools
@tanstack/react-ai-devtools
@tanstack/solid-ai-devtools
commit: |
ChatClient.sendMessage already took a per-call body as its positional second argument, but every framework hook (useChat, injectChat, createChat, ...) exposes sendMessage(content, options) and forwards undefined for it — leaving no race-free way to send per-message data (e.g. attachment ids) through a hook: updating a reactive chat-level body/forwardedProps option right before sending can flush after the send. SendMessageOptions gains an optional body that ChatClient resolves as a fallback to the positional argument (positional wins), so every wrapper inherits the capability with no wrapper code changes. Queued sends preserve it exactly like the positional form. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On ChatClient the second positional argument is the raw body, so the
{ body } options form belongs to the hooks; direct ChatClient callers
pass it as the third argument.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
115ec26 to
a420768
Compare
|
Maintainer sweep: rebased onto |
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
🎯 Changes
ChatClient.sendMessage(content, body?, sendOptions?)accepts a per-callbodymerged into the request'sforwardedPropsat the highest priority — but every framework hook (useChat,injectChat,createChat, …) exposessendMessage(content, options)and hardcodesundefinedfor the positional argument (e.g.ai-angular/src/inject-chat.ts,ai-react/src/use-chat.ts), and none of them expose the underlyingChatClient.That leaves no race-free way to send per-message data through a hook. The workaround — updating a reactive chat-level
body/forwardedPropsoption right before sending — is racy: reactive option changes sync to the client asynchronously (e.g. via an Angulareffect), so "set option, then send" can flush after the request is built. Real-world case: attaching upload ids to the specific message that references them.The fix:
SendMessageOptionsgains an optionalbody.ChatClient.sendMessageresolvesbody ?? sendOptions.body(the positional argument wins — it predates the option and existing callers may pass both), so every framework wrapper inherits the capability with zero wrapper code changes — they already forwardsendOptions. Queued sends preserve the per-call body exactly like the positional form (sameenqueueMessage/deliverMessagepath).Also included:
docs/chat/connection-adapters.md; updatedsendMessageJSDoc (the "(body must still be the 2nd arg on ChatClient)" note is no longer true) and theuseMcpAppBridgeexample, which can now forward the bridge'sbodyinstead of dropping it.Test plan
ai-client(chat-client.test.ts,chat-client-queue.test.ts):sendOptions.bodymerges over chat-levelbody; positionalbodywins over (replaces, not merges with)sendOptions.body; queued sends drain with their own per-callsendOptions.body.ai-react/tests/use-chat.test.ts,ai-angular/tests/inject-chat.test.ts): hook-levelsendMessage(content, { body })reaches the connection adapter'sdata, merged with the chat-levelbodyoption.testing/e2e/tests/per-call-body.spec.ts+ fixture + a[per-call-body]branch in the chat page): drives the browser UI and asserts the/api/chatPOST body carries the per-call marker underforwardedProps, merged with — not replacing — the chat-level keys. A regression that dropsoptions.bodyfails the marker assertion; one that replaces the merge fails the provider/feature assertions.pnpm run test:pr(sherif, knip, docs links, kiira doc-snippet typecheck, oxlint, unit, types, build — all green) and the e2e subsetper-call-body+chat.spec.ts+queue.spec.ts(27 passed).✅ Checklist
pnpm run test:pr.🚀 Release Impact
@tanstack/ai-clientminor).🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests