feat(ai): add type-safe tool call events to chat() stream#452
feat(ai): add type-safe tool call events to chat() stream#452AlemTuzlak wants to merge 6 commits intomainfrom
Conversation
When tools with Zod schemas are passed to chat(), the stream chunks now carry type information on TOOL_CALL_START and TOOL_CALL_END events: - toolName narrows to the union of tool name literals - input on TOOL_CALL_END is typed as the union of tool input types Made ToolCallStartEvent and ToolCallEndEvent generic with backward- compatible defaults. Added TypedStreamChunk<TTools> type that threads through TextActivityOptions, TextActivityResult, chat(), and createChatOptions(). Includes IsAny guard in ToolInputsOf to prevent `any` leaking through InferSchemaType for tools without inputSchema. Fully backward compatible — StreamChunk and AGUIEvent are unchanged, unparameterized event types use string/unknown defaults.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (3)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds generic tool-aware stream typing: Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 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 |
🚀 Changeset Version Preview4 package(s) bumped directly, 23 bumped as dependents. 🟩 Patch bumps
|
|
View your CI Pipeline Execution ↗ for commit d46cd6d
☁️ Nx Cloud last updated this comment at |
@tanstack/ai
@tanstack/ai-anthropic
@tanstack/ai-client
@tanstack/ai-code-mode
@tanstack/ai-code-mode-skills
@tanstack/ai-devtools-core
@tanstack/ai-elevenlabs
@tanstack/ai-event-client
@tanstack/ai-fal
@tanstack/ai-gemini
@tanstack/ai-grok
@tanstack/ai-groq
@tanstack/ai-isolate-cloudflare
@tanstack/ai-isolate-node
@tanstack/ai-isolate-quickjs
@tanstack/ai-ollama
@tanstack/ai-openai
@tanstack/ai-openrouter
@tanstack/ai-preact
@tanstack/ai-react
@tanstack/ai-react-ui
@tanstack/ai-solid
@tanstack/ai-solid-ui
@tanstack/ai-svelte
@tanstack/ai-vue
@tanstack/ai-vue-ui
@tanstack/preact-ai-devtools
@tanstack/react-ai-devtools
@tanstack/solid-ai-devtools
commit: |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/chat/streaming.md`:
- Around line 115-117: Remove the blank line between the two blockquotes so the
"**Note:**" and "**Tip:**" paragraphs are adjacent (or merge them into one
blockquote); specifically edit the section containing the "**Note:** When
multiple tools..." and the "**Tip:** The typed stream chunk type..." strings so
there is no empty line between those blockquote lines to satisfy markdownlint
MD028.
In `@docs/reference/type-aliases/StreamChunk.md`:
- Line 23: The "Defined in" source anchor for the TypedStreamChunk entry is
stale; update the anchor in docs/reference/type-aliases/StreamChunk.md to point
to the current declaration location packages/typescript/ai/src/types.ts at line
1048 (or to the exact URL/permalink generated by TypeDoc for TypedStreamChunk),
ensuring the link text and URL reflect the new file and line; update the
markdown so it uses the correct Markdown link format and matches the repo's
TypeDoc-generated anchor for TypedStreamChunk.
In `@packages/typescript/ai/tests/type-check.test.ts`:
- Around line 6-17: The named imports in this test file are not alphabetized
causing ESLint sort-imports errors; reorder the members inside each import's
braces alphabetically (e.g., change "describe, it, expectTypeOf" to "describe,
expectTypeOf, it" for the vitest import, and similarly alphabetize "chat,
createChatOptions, toolDefinition" and the type import list "JSONSchema,
StreamChunk, Tool, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent,
TypedStreamChunk") so each import's named members are in ascending alphabetical
order.
🪄 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
Run ID: 28ddc119-4e8d-45ba-8567-1aae00525797
📒 Files selected for processing (7)
docs/chat/streaming.mddocs/reference/type-aliases/StreamChunk.mddocs/tools/tools.mdexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai/src/activities/chat/index.tspackages/typescript/ai/src/types.tspackages/typescript/ai/tests/type-check.test.ts
| type TypedStreamChunk<TTools extends ReadonlyArray<Tool<any, any, any>> = ReadonlyArray<Tool<any, any, any>>> | ||
| ``` | ||
|
|
||
| Defined in: [types.ts:1033](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/types.ts#L1033) |
There was a problem hiding this comment.
Update the TypedStreamChunk source anchor.
This Defined in link still points to types.ts:1033, but the alias is declared at packages/typescript/ai/src/types.ts Line 1048 in this PR, so the reference page is already stale. As per coding guidelines, docs/**/*.md: Use Markdown for documentation in the docs/ directory with auto-generated docs via TypeDoc.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/reference/type-aliases/StreamChunk.md` at line 23, The "Defined in"
source anchor for the TypedStreamChunk entry is stale; update the anchor in
docs/reference/type-aliases/StreamChunk.md to point to the current declaration
location packages/typescript/ai/src/types.ts at line 1048 (or to the exact
URL/permalink generated by TypeDoc for TypedStreamChunk), ensuring the link text
and URL reflect the new file and line; update the markdown so it uses the
correct Markdown link format and matches the repo's TypeDoc-generated anchor for
TypedStreamChunk.
| import { describe, it, expectTypeOf } from 'vitest' | ||
| import { createChatOptions } from '../src' | ||
| import { z } from 'zod' | ||
| import { chat, createChatOptions, toolDefinition } from '../src' | ||
| import type { | ||
| JSONSchema, | ||
| StreamChunk, | ||
| Tool, | ||
| ToolCallArgsEvent, | ||
| ToolCallStartEvent, | ||
| ToolCallEndEvent, | ||
| TypedStreamChunk, | ||
| } from '../src' |
There was a problem hiding this comment.
Fix the import member ordering before merge.
ESLint is already flagging this block (sort-imports on Line 6 and Line 15), so this file will stay red until the named imports are alphabetized.
🧰 Tools
🪛 ESLint
[error] 6-6: Member 'expectTypeOf' of the import declaration should be sorted alphabetically.
(sort-imports)
[error] 15-15: Member 'ToolCallEndEvent' of the import declaration should be sorted alphabetically.
(sort-imports)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/typescript/ai/tests/type-check.test.ts` around lines 6 - 17, The
named imports in this test file are not alphabetized causing ESLint sort-imports
errors; reorder the members inside each import's braces alphabetically (e.g.,
change "describe, it, expectTypeOf" to "describe, expectTypeOf, it" for the
vitest import, and similarly alphabetize "chat, createChatOptions,
toolDefinition" and the type import list "JSONSchema, StreamChunk, Tool,
ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent, TypedStreamChunk") so
each import's named members are in ascending alphabetical order.
…put narrowing Replace flat toolName/input unions with distributive conditional types so checking toolName === 'x' narrows input to that specific tool's type.
There was a problem hiding this comment.
♻️ Duplicate comments (2)
docs/reference/type-aliases/StreamChunk.md (1)
23-23:⚠️ Potential issue | 🟡 MinorStale
Defined inlink forTypedStreamChunk.The link points to
types.ts:1033, butTypedStreamChunkis defined at line 1065 in the current code. This will create a broken anchor.📝 Suggested fix
-Defined in: [types.ts:1033](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/types.ts#L1033) +Defined in: [types.ts:1065](https://github.com/TanStack/ai/blob/main/packages/typescript/ai/src/types.ts#L1065)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/reference/type-aliases/StreamChunk.md` at line 23, The documentation entry for TypedStreamChunk has a stale "Defined in" anchor; update the link target in docs/reference/type-aliases/StreamChunk.md so it points to the actual definition of TypedStreamChunk in types.ts (current location around line 1065) or replace the fragile line-number anchor with a file-level link to types.ts and a search-friendly fragment for TypedStreamChunk; ensure the reference text "Defined in" continues to reference types.ts and that the anchor resolves to the TypedStreamChunk definition.packages/typescript/ai/tests/type-check.test.ts (1)
6-17:⚠️ Potential issue | 🟡 MinorImport members need alphabetical sorting.
ESLint's
sort-importsrule requires alphabetically ordered named imports within each statement.🔧 Suggested fix
-import { describe, it, expectTypeOf } from 'vitest' +import { describe, expectTypeOf, it } from 'vitest' import { z } from 'zod' import { chat, createChatOptions, toolDefinition } from '../src' import type { JSONSchema, StreamChunk, Tool, ToolCallArgsEvent, - ToolCallStartEvent, ToolCallEndEvent, + ToolCallStartEvent, TypedStreamChunk, } from '../src'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/typescript/ai/tests/type-check.test.ts` around lines 6 - 17, The named imports in this file are not alphabetized; reorder the identifiers alphabetically within each import statement—for example change "describe, it, expectTypeOf" to "describe, expectTypeOf, it", "chat, createChatOptions, toolDefinition" to "chat, createChatOptions, toolDefinition" (ensure correct alphabetical order), and the type import list "JSONSchema, StreamChunk, Tool, ToolCallArgsEvent, ToolCallStartEvent, ToolCallEndEvent, TypedStreamChunk" should be reordered alphabetically (e.g., "JSONSchema, StreamChunk, Tool, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent, TypedStreamChunk") so each import's named members follow ESLint's sort-imports rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@docs/reference/type-aliases/StreamChunk.md`:
- Line 23: The documentation entry for TypedStreamChunk has a stale "Defined in"
anchor; update the link target in docs/reference/type-aliases/StreamChunk.md so
it points to the actual definition of TypedStreamChunk in types.ts (current
location around line 1065) or replace the fragile line-number anchor with a
file-level link to types.ts and a search-friendly fragment for TypedStreamChunk;
ensure the reference text "Defined in" continues to reference types.ts and that
the anchor resolves to the TypedStreamChunk definition.
In `@packages/typescript/ai/tests/type-check.test.ts`:
- Around line 6-17: The named imports in this file are not alphabetized; reorder
the identifiers alphabetically within each import statement—for example change
"describe, it, expectTypeOf" to "describe, expectTypeOf, it", "chat,
createChatOptions, toolDefinition" to "chat, createChatOptions, toolDefinition"
(ensure correct alphabetical order), and the type import list "JSONSchema,
StreamChunk, Tool, ToolCallArgsEvent, ToolCallStartEvent, ToolCallEndEvent,
TypedStreamChunk" should be reordered alphabetically (e.g., "JSONSchema,
StreamChunk, Tool, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent,
TypedStreamChunk") so each import's named members follow ESLint's sort-imports
rule.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 230ab7f9-f926-49b5-a973-0080ff8b4502
📒 Files selected for processing (5)
docs/chat/streaming.mddocs/reference/type-aliases/StreamChunk.mdexamples/ts-react-chat/src/routes/api.tanchat.tspackages/typescript/ai/src/types.tspackages/typescript/ai/tests/type-check.test.ts
✅ Files skipped from review due to trivial changes (1)
- docs/chat/streaming.md
- Show practical property access after discriminated narrowing - Add description field to searchTool example for consistency - Add cross-link from server-tools to streaming type safety - Fix stale line number references in StreamChunk.md
- Remove T & Tool<any,any,any> intersection in DistributedToolCallEnd that caused tsc to resolve input as unknown for all tools - Relax SafeToolInput constraint to structural match (no generic bound) - Fix "Zod schema inference" → "Standard Schema inference" in JSDoc/docs - Fix off-by-one line number in StreamChunk.md reference - Fix misleading test comment about searchClientTool - Add | undefined to input type annotation in streaming docs - Broaden server-tools.md tip to cover all typed tool variants - Add tests for mixed Zod+JSON Schema and chat() with server/client tools
Summary
ToolCallStartEventandToolCallEndEventgeneric with backward-compatible defaults (string/unknown)TypedStreamChunk<TTools>exported type that replaces untyped tool call events with typed versions based on the tools arrayTToolsgeneric throughTextActivityOptions,TextActivityResult,chat(), andcreateChatOptions()so the stream return type carries tool type informationIsAnyguard inToolInputsOfto preventanyleaking throughInferSchemaTypefor tools withoutinputSchemachat()inference without explicit type argsStreamChunk.mdreference, and cross-links from tools docsts-react-chatexampleTest plan
pnpm --filter @tanstack/ai test:lib)pnpm --filter @tanstack/ai build)pnpm --filter ts-react-chat build)string/unknown, empty arrays,as const, server/client tool variants,chat()inference, backward compat (assignability,StreamChunkunchanged)toBeUnknown()assertions used instead oftoEqualTypeOf<unknown>()to catchanyleaks🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation