Skip to content

Conversation

@nikas-belogolov
Copy link

@nikas-belogolov nikas-belogolov commented Jan 25, 2026

🎯 Changes

Added a status property to useChat to track the generation lifecycle (ready, submitted, streaming, error).

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features

    • Adds unified generation status (ready, submitted, streaming, error) exposed by the client and chat hooks, plus a status observer callback and getter.
  • Tests

    • Adds cross-framework tests verifying status transitions, error handling, stop/reset behavior, and initial readiness.
  • Chores

    • Bumps minor versions of related ai-* packages.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 25, 2026

📝 Walkthrough

Walkthrough

Adds a ChatClientState lifecycle type ('ready' | 'submitted' | 'streaming' | 'error'), surfaces a new status field across framework integrations' useChat APIs, and implements status tracking plus an onStatusChange callback and getStatus() on ChatClient.

Changes

Cohort / File(s) Summary
Changeset / Release note
\.changeset/shy-ravens-sink.md
Bumps minor package versions and documents the new status property on useChat.
AI Client core
packages/typescript/ai-client/src/chat-client.ts, packages/typescript/ai-client/src/types.ts, packages/typescript/ai-client/src/index.ts
Add exported ChatClientState type; add onStatusChange?: (status) => void to ChatClientOptions; internal status field with setStatus() helper; emit status transitions at stream lifecycle points; add public getStatus() getter and re-export ChatClientState.
Preact integration
packages/typescript/ai-preact/src/types.ts, packages/typescript/ai-preact/src/use-chat.ts, packages/typescript/ai-preact/tests/use-chat.test.ts
Import ChatClientState; UseChatReturn includes status: ChatClientState; hook wires client onStatusChange to local state; tests updated/added for status transitions.
React integration
packages/typescript/ai-react/src/types.ts, packages/typescript/ai-react/src/use-chat.ts, packages/typescript/ai-react/tests/use-chat.test.ts
Import ChatClientState; expose status state from useChat; wrap client callbacks and wire onStatusChange; tests updated/added for status.
Svelte integration
packages/typescript/ai-svelte/src/types.ts, packages/typescript/ai-svelte/src/create-chat.svelte.ts, packages/typescript/ai-svelte/tests/use-chat.test.ts
Add reactive status (initialized 'ready'); expose get status() on chat object; wire onStatusChange to reactive status; update types and tests.
Solid integration
packages/typescript/ai-solid/src/types.ts, packages/typescript/ai-solid/src/use-chat.ts, packages/typescript/ai-solid/tests/*, packages/typescript/ai-solid/tests/test-utils.ts
Introduce signal-based status: Accessor<ChatClientState>; update hook to update signal via onStatusChange; return status and include in test utils; tests added/updated.
Vue integration
packages/typescript/ai-vue/src/types.ts, packages/typescript/ai-vue/src/use-chat.ts, packages/typescript/ai-vue/tests/*, packages/typescript/ai-vue/tests/test-utils.ts
Add reactive status (ShallowRef/DeepReadonly) exposed as readonly; wire onStatusChange to update status; update types, test utils, and tests.
Tests across packages
packages/typescript/*/tests/*use-chat.test.ts, packages/typescript/ai-client/tests/chat-client.test.ts
Add status-focused tests validating initial state, transitions (submitted/streaming → ready), error transition, and stop/reset behavior. Note: some test blocks appear duplicated in diffs.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant ChatClient as ChatClient
  participant UseChat as UseChat Hook
  participant UI as UI

  Client->>ChatClient: sendMessage(...)
  ChatClient->>ChatClient: setStatus("submitted")
  ChatClient->>UseChat: onStatusChange("submitted")
  ChatClient->>ChatClient: onStreamStart -> setStatus("streaming")
  ChatClient->>UseChat: onStatusChange("streaming")
  ChatClient->>ChatClient: onStreamEnd -> setStatus("ready")
  ChatClient->>UseChat: onStatusChange("ready")
  ChatClient->>UseChat: onError -> setStatus("error")
  UseChat->>UI: expose status ('ready'|'submitted'|'streaming'|'error')
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • AlemTuzlak
  • jherr

Poem

🐰
I hop from ready to submitted with cheer,
I twitch when streaming as chunks appear,
I flinch when errors give me a start,
Then back to ready — a thumping heart,
A rabbit's clap for lifecycle art 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a status property to useChat that tracks generation lifecycle states.
Description check ✅ Passed The description follows the template structure, includes the changes summary, has completed all required checklist items, and properly indicates a changeset was generated.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
packages/typescript/ai-preact/src/types.ts (1)

27-31: Inconsistency with React: onStreamStart should be omitted from UseChatOptions.

The React adapter omits 'onStreamStart' from UseChatOptions (since the hook manages it internally to track status transitions), but the Preact adapter does not. This inconsistency allows Preact users to pass onStreamStart while React users cannot.

Suggested fix
 export type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any> =
   Omit<
     ChatClientOptions<TTools>,
-    'onMessagesChange' | 'onLoadingChange' | 'onErrorChange'
+    'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStreamStart'
   >
packages/typescript/ai-svelte/src/types.ts (1)

27-32: Inconsistency with React: onStreamStart should be omitted from CreateChatOptions.

Same issue as in Preact — the React adapter omits 'onStreamStart' from options, but Svelte does not. For consistency, all framework adapters should handle internal callbacks the same way.

Suggested fix
 export type CreateChatOptions<
   TTools extends ReadonlyArray<AnyClientTool> = any,
 > = Omit<
   ChatClientOptions<TTools>,
-  'onMessagesChange' | 'onLoadingChange' | 'onErrorChange'
+  'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStreamStart'
 >
packages/typescript/ai-client/src/chat-client.ts (1)

31-81: Keep onStreamStart in sync in updateOptions.

updateOptions updates onResponse/onChunk/onFinish/onError but omits onStreamStart, so refreshed callbacks won’t be picked up. Please add it for parity with the other callbacks.

🛠️ Suggested fix
   updateOptions(options: {
     connection?: ConnectionAdapter
     body?: Record<string, any>
     tools?: ReadonlyArray<AnyClientTool>
     onResponse?: (response?: Response) => void | Promise<void>
     onChunk?: (chunk: StreamChunk) => void
     onFinish?: (message: UIMessage) => void
+    onStreamStart?: () => void
     onError?: (error: Error) => void
   }): void {
@@
     if (options.onFinish !== undefined) {
       this.callbacksRef.current.onFinish = options.onFinish
     }
+    if (options.onStreamStart !== undefined) {
+      this.callbacksRef.current.onStreamStart = options.onStreamStart
+    }
     if (options.onError !== undefined) {
       this.callbacksRef.current.onError = options.onError
     }
   }
packages/typescript/ai-preact/src/use-chat.ts (1)

1-10: Fix ESLint import order and type-only import usage.

The linter reports two errors: @tanstack/ai type import must occur after preact/hooks, and ChatClientState is only used as a type and should be imported with type.

🔧 Proposed import fix
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, ChatClientState } from '@tanstack/ai-client'
-import {
-  useCallback,
-  useEffect,
-  useId,
-  useMemo,
-  useRef,
-  useState,
-} from 'preact/hooks'
+import {
+  useCallback,
+  useEffect,
+  useId,
+  useMemo,
+  useRef,
+  useState,
+} from 'preact/hooks'
+import { ChatClient, type ChatClientState } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
🤖 Fix all issues with AI agents
In `@packages/typescript/ai-client/src/types.ts`:
- Around line 203-206: The JSDoc for the onStreamStart callback is missing a
space before the closing "*/"; update the comment above the onStreamStart?: ()
=> void declaration to match the project's JSDoc style (ensure a space before
the closing */, e.g. " * Callback when stream starts */" formatting) so it is
consistent with other comments in the file.

In `@packages/typescript/ai-svelte/src/create-chat.svelte.ts`:
- Around line 78-80: The onStreamStart handler currently only sets status =
'streaming' but doesn't call the user-provided callback; update the handler to
mirror the onFinish/onError pattern by invoking the passed-in callback (e.g.
call opts.onStreamStart?.() or onStreamStart?.() depending on how callbacks are
named) after setting status so user code is notified; reference the
onStreamStart handler and the existing onFinish/onError invocation pattern to
implement the call.
- Around line 1-2: Reorder the imports so that symbols from
'@tanstack/ai-client' come before '@tanstack/ai' and import ChatClientState as a
type-only import; specifically, update the top-level import statement to import
ChatClient and (type) ChatClientState from '@tanstack/ai-client' and then import
AnyClientTool and ModelMessage from '@tanstack/ai', keeping the rest of the file
(e.g. the $state<ChatClientState> usage) unchanged.

In `@packages/typescript/ai-vue/src/use-chat.ts`:
- Around line 48-50: The onStreamStart handler currently only sets status.value
= 'streaming' and ignores any user callback; update the onStreamStart
implementation to set status.value = 'streaming' then invoke the user-provided
callback (e.g., props.onStreamStart or options.onStreamStart /
callbacks.onStreamStart if available) in a safe way (check for existence before
calling) so consumer callbacks are forwarded while preserving the existing
status update.
🧹 Nitpick comments (5)
packages/typescript/ai-svelte/tests/use-chat.test.ts (1)

149-160: Consider adding status transition coverage for Svelte.

This test only verifies the initial 'ready' state. To catch regressions and align with other framework tests, consider driving a mock stream/error to assert 'submitted' → 'streaming' → 'ready'/'error' transitions.

packages/typescript/ai-vue/tests/use-chat.test.ts (1)

1-10: Fix import order to satisfy ESLint rules.

Type imports should occur after regular imports per the project's import order configuration.

♻️ Suggested fix
-import type { ModelMessage } from '@tanstack/ai'
 import { flushPromises } from '@vue/test-utils'
 import { describe, expect, it, vi } from 'vitest'
-import type { UIMessage } from '../src/types'
 import {
   createMockConnectionAdapter,
   createTextChunks,
   createToolCallChunks,
   renderUseChat,
 } from './test-utils'
+import type { ModelMessage } from '@tanstack/ai'
+import type { UIMessage } from '../src/types'
packages/typescript/ai-vue/tests/test-utils.ts (1)

1-5: Fix import order to satisfy ESLint rules.

Type imports should occur after regular imports per the project's import order configuration.

♻️ Suggested fix
-import type { UIMessage } from '@tanstack/ai-client'
 import { mount } from '@vue/test-utils'
 import { defineComponent } from 'vue'
-import type { UseChatOptions } from '../src/types'
 import { useChat } from '../src/use-chat'
+import type { UIMessage } from '@tanstack/ai-client'
+import type { UseChatOptions } from '../src/types'
packages/typescript/ai-react/src/use-chat.ts (1)

2-2: Use type-only import for ChatClientState.

ChatClientState is only used as a type, so it should be imported using the type keyword to enable better tree-shaking and satisfy the ESLint rule.

♻️ Suggested fix
-import { ChatClient, ChatClientState } from '@tanstack/ai-client'
+import { ChatClient } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
packages/typescript/ai-solid/src/use-chat.ts (1)

7-9: Fix import order and use type-only import for ChatClientState.

Two issues flagged by ESLint:

  1. @tanstack/ai-client import should occur before the type import of @tanstack/ai
  2. ChatClientState is only used as a type
♻️ Suggested fix
 import {
   createEffect,
   createMemo,
   createSignal,
   createUniqueId,
 } from 'solid-js'
-
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, ChatClientState } from '@tanstack/ai-client'
+import { ChatClient } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
+import type { ChatClientState } from '@tanstack/ai-client'
 import type { UIMessage, UseChatOptions, UseChatReturn } from './types'

Comment on lines 1 to 2
import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
import { ChatClient, ChatClientState } from '@tanstack/ai-client'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the file and read its contents
cat -n packages/typescript/ai-svelte/src/create-chat.svelte.ts | head -50

Repository: TanStack/ai

Length of output: 2040


🏁 Script executed:

# Check if ChatClientState is exported from the tanstack packages
rg "export.*ChatClientState" --type ts --type tsx

Repository: TanStack/ai

Length of output: 82


🏁 Script executed:

# Search for how ChatClientState is used in the file
rg "ChatClientState" packages/typescript/ai-svelte/src/create-chat.svelte.ts -B 2 -A 2

Repository: TanStack/ai

Length of output: 430


🏁 Script executed:

# Find where ChatClientState is exported from
rg "export.*ChatClientState" --type ts

Repository: TanStack/ai

Length of output: 127


🏁 Script executed:

# Check import order patterns in similar files
rg -B2 -A2 "import.*@tanstack/ai-client" packages/typescript/ai-svelte/src/ --type ts | head -30

Repository: TanStack/ai

Length of output: 487


🏁 Script executed:

# Check if there's an eslint config specifying import order
find . -name ".eslintrc*" -o -name "eslint.config.*" | head -5

Repository: TanStack/ai

Length of output: 284


🏁 Script executed:

# Check the eslint config for ai-svelte
cat packages/typescript/ai-svelte/eslint.config.js

Repository: TanStack/ai

Length of output: 214


🏁 Script executed:

# Also check the root eslint config
cat ./eslint.config.js

Repository: TanStack/ai

Length of output: 603


Use a type-only import for ChatClientState and reorder imports.

ChatClientState is used only as a type annotation (line 47: $state<ChatClientState>), so it should be imported as type-only. Additionally, imports from @tanstack/ai-client should come before @tanstack/ai per ESLint conventions.

Suggested fix
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, ChatClientState } from '@tanstack/ai-client'
+import { ChatClient } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
import { ChatClient, ChatClientState } from '@tanstack/ai-client'
import { ChatClient } from '@tanstack/ai-client'
import type { ChatClientState } from '@tanstack/ai-client'
import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
🧰 Tools
🪛 ESLint

[error] 2-2: Imports "ChatClientState" are only used as type.

(@typescript-eslint/consistent-type-imports)


[error] 2-2: @tanstack/ai-client import should occur before type import of @tanstack/ai

(import/order)

🤖 Prompt for AI Agents
In `@packages/typescript/ai-svelte/src/create-chat.svelte.ts` around lines 1 - 2,
Reorder the imports so that symbols from '@tanstack/ai-client' come before
'@tanstack/ai' and import ChatClientState as a type-only import; specifically,
update the top-level import statement to import ChatClient and (type)
ChatClientState from '@tanstack/ai-client' and then import AnyClientTool and
ModelMessage from '@tanstack/ai', keeping the rest of the file (e.g. the
$state<ChatClientState> usage) unchanged.

Comment on lines 78 to 80
onStreamStart: () => {
status = 'streaming'
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Forward onStreamStart to user callbacks.

Right now the status updates but user-provided onStreamStart is never invoked. Mirror the onFinish/onError pattern.

🛠️ Suggested fix
     onStreamStart: () => {
       status = 'streaming'
+      options.onStreamStart?.()
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onStreamStart: () => {
status = 'streaming'
},
onStreamStart: () => {
status = 'streaming'
options.onStreamStart?.()
},
🤖 Prompt for AI Agents
In `@packages/typescript/ai-svelte/src/create-chat.svelte.ts` around lines 78 -
80, The onStreamStart handler currently only sets status = 'streaming' but
doesn't call the user-provided callback; update the handler to mirror the
onFinish/onError pattern by invoking the passed-in callback (e.g. call
opts.onStreamStart?.() or onStreamStart?.() depending on how callbacks are
named) after setting status so user code is notified; reference the
onStreamStart handler and the existing onFinish/onError invocation pattern to
implement the call.

Comment on lines 48 to 50
onStreamStart: () => {
status.value = 'streaming'
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Forward onStreamStart to user callbacks.

onStreamStart currently sets status but ignores any user-provided callback. Please forward it to preserve expected behavior.

🛠️ Suggested fix
     onStreamStart: () => {
       status.value = 'streaming'
+      options.onStreamStart?.()
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onStreamStart: () => {
status.value = 'streaming'
},
onStreamStart: () => {
status.value = 'streaming'
options.onStreamStart?.()
},
🤖 Prompt for AI Agents
In `@packages/typescript/ai-vue/src/use-chat.ts` around lines 48 - 50, The
onStreamStart handler currently only sets status.value = 'streaming' and ignores
any user callback; update the onStreamStart implementation to set status.value =
'streaming' then invoke the user-provided callback (e.g., props.onStreamStart or
options.onStreamStart / callbacks.onStreamStart if available) in a safe way
(check for existence before calling) so consumer callbacks are forwarded while
preserving the existing status update.

nikas-belogolov and others added 3 commits January 25, 2026 16:23
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@nikas-belogolov nikas-belogolov marked this pull request as draft January 25, 2026 14:44
@nikas-belogolov nikas-belogolov marked this pull request as ready for review January 25, 2026 14:44
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/typescript/ai-preact/src/use-chat.ts (1)

1-10: Resolve import order + type-only split (lint).

This triggers import/order and import/consistent-type-specifier-style.

🛠️ Suggested fix
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, type ChatClientState } from '@tanstack/ai-client'
-import {
-  useCallback,
-  useEffect,
-  useId,
-  useMemo,
-  useRef,
-  useState,
-} from 'preact/hooks'
+import {
+  useCallback,
+  useEffect,
+  useId,
+  useMemo,
+  useRef,
+  useState,
+} from 'preact/hooks'
+import { ChatClient } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
packages/typescript/ai-solid/src/use-chat.ts (1)

1-10: Fix import order + type-only split (lint).

This violates import/order and import/consistent-type-specifier-style.

🛠️ Suggested fix
 import {
   createEffect,
   createMemo,
   createSignal,
   createUniqueId,
 } from 'solid-js'
 
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, type ChatClientState } from '@tanstack/ai-client'
+import { ChatClient } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
 import type { UIMessage, UseChatOptions, UseChatReturn } from './types'
🤖 Fix all issues with AI agents
In `@packages/typescript/ai-preact/src/use-chat.ts`:
- Around line 76-78: The onStreamStart handler currently only calls
setStatus('streaming') but never invokes the user-provided callback; update the
handler inside useChat (the onStreamStart block) to call the passed-in user
callback after updating status (e.g., options.onStreamStart or onStreamStart
prop) using safe optional invocation (options?.onStreamStart?.(...)) and forward
any relevant args/events to it so the user's callback runs when streaming
starts.

In `@packages/typescript/ai-react/src/use-chat.ts`:
- Around line 1-3: The import currently mixes a type with a value import for
ChatClientState; change it to a top-level type-only import by moving
ChatClientState into its own import line using the `import type {
ChatClientState } from '@tanstack/ai-client'` form and leave `import {
ChatClient } from '@tanstack/ai-client'` (or vice versa) so ChatClientState is
imported purely as a type (refer to the ChatClient and ChatClientState symbols
in use-chat.ts).
- Around line 54-56: The onStreamStart handler currently only calls
setStatus("streaming") and never invokes the consumer's callback; update the
onStreamStart block in use-chat.ts (the onStreamStart handler) to call the
user-provided callback after updating status — e.g., keep setStatus("streaming")
then check for and invoke the external onStreamStart callback (the
prop/option/callback passed into the useChat/useChat hook) so consumers receive
the event.

In `@packages/typescript/ai-solid/src/use-chat.ts`:
- Around line 58-60: The onStreamStart handler currently only calls
setStatus('streaming') but doesn't invoke the consumer's callback; update the
onStreamStart implementation to call the user-provided onStreamStart callback
after setting status (e.g., if (props.onStreamStart)
props.onStreamStart(...args) or options.onStreamStart?.(args)), preserving any
arguments the stream start provides and guarding for its existence so both
setStatus('streaming') and the user's callback run.

In `@packages/typescript/ai-vue/src/use-chat.ts`:
- Around line 1-4: The file imports ChatClientState with a mixed value/type
import which violates the consistent-type-specifier-style rule; change the
imports to use a top-level type-only import for ChatClientState and keep
ChatClient as a value import — i.e., split the current "import { ChatClient,
type ChatClientState } from '@tanstack/ai-client'" into a value import for
ChatClient and a separate "import type { ChatClientState }" so ChatClientState
is only imported as a type; update references to ChatClientState and ChatClient
in use-chat.ts accordingly.
♻️ Duplicate comments (2)
packages/typescript/ai-svelte/src/create-chat.svelte.ts (1)

1-3: Fix import ordering + type-only split to satisfy lint.

ESLint still flags import/order and import/consistent-type-specifier-style here.

🛠️ Suggested fix
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, type ChatClientState } from '@tanstack/ai-client'
+import { ChatClient } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
packages/typescript/ai-vue/src/use-chat.ts (1)

48-50: Forward onStreamStart to consumer callback.

Status changes but the user callback is skipped.

🛠️ Suggested fix
     onStreamStart: () => {
       status.value = 'streaming'
+      options.onStreamStart?.()
     },

nikas-belogolov and others added 2 commits January 25, 2026 19:31
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/typescript/ai-react/src/use-chat.ts`:
- Around line 1-4: Reorder the import statements to satisfy ESLint import-order
rules by placing React imports (useCallback, useEffect, useId, useMemo, useRef,
useState from 'react') before external package imports; move the line importing
ChatClient and ChatClientState from '@tanstack/ai-client' and the types
AnyClientTool and ModelMessage from '@tanstack/ai' after the React import so
that React comes first, then third‑party packages, keeping each import's
original named symbols (ChatClient, ChatClientState, AnyClientTool,
ModelMessage) unchanged.

In `@packages/typescript/ai-vue/src/use-chat.ts`:
- Around line 1-4: Reorder the imports so the concrete module imports from
'@tanstack/ai-client' (ChatClient, ChatClientState) appear before the type-only
import from '@tanstack/ai' (AnyClientTool, ModelMessage) to satisfy ESLint
ordering; keep the 'type' modifiers on type-only imports (e.g., type {
AnyClientTool, ModelMessage } and type { ChatClientState }) and preserve the
existing Vue imports (onScopeDispose, readonly, shallowRef, useId) after the
tanstack imports.
♻️ Duplicate comments (2)
packages/typescript/ai-react/src/use-chat.ts (1)

55-57: Forward onStreamStart to the consumer callback.

The internal handler updates status but doesn’t invoke the user’s onStreamStart, so external listeners never fire.

🛠️ Proposed fix
       onStreamStart: () => {
-        setStatus("streaming")
+        setStatus('streaming')
+        optionsRef.current.onStreamStart?.()
       },
packages/typescript/ai-vue/src/use-chat.ts (1)

49-50: Forward onStreamStart to user callbacks.

The hook updates status but doesn’t invoke options.onStreamStart, so consumers miss the event.

🛠️ Proposed fix
     onStreamStart: () => {
       status.value = 'streaming'
+      options.onStreamStart?.()
     },

Comment on lines 1 to +4
import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
import { ChatClient } from '@tanstack/ai-client'
import type { ChatClientState } from '@tanstack/ai-client'
import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix import ordering to satisfy lint rules.

ESLint flags the current ordering of the React and @tanstack/ai-client imports.

🛠️ Proposed fix
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient } from '@tanstack/ai-client'
-import type { ChatClientState } from '@tanstack/ai-client'
-import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
+import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
+import { ChatClient } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
import { ChatClient } from '@tanstack/ai-client'
import type { ChatClientState } from '@tanstack/ai-client'
import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
import { ChatClient } from '@tanstack/ai-client'
import type { ChatClientState } from '@tanstack/ai-client'
import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
🧰 Tools
🪛 ESLint

[error] 2-2: @tanstack/ai-client import should occur before type import of @tanstack/ai

(import/order)


[error] 4-4: react import should occur before type import of @tanstack/ai

(import/order)

🤖 Prompt for AI Agents
In `@packages/typescript/ai-react/src/use-chat.ts` around lines 1 - 4, Reorder the
import statements to satisfy ESLint import-order rules by placing React imports
(useCallback, useEffect, useId, useMemo, useRef, useState from 'react') before
external package imports; move the line importing ChatClient and ChatClientState
from '@tanstack/ai-client' and the types AnyClientTool and ModelMessage from
'@tanstack/ai' after the React import so that React comes first, then
third‑party packages, keeping each import's original named symbols (ChatClient,
ChatClientState, AnyClientTool, ModelMessage) unchanged.

Comment on lines 73 to 77
if (newIsLoading) {
setStatus('submitted')
} else {
setStatus((prev) => (prev === 'error' ? 'error' : 'ready'))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mind collapsing this into setStatus(newIsLoading ? "submitted" : ...)

@nx-cloud
Copy link

nx-cloud bot commented Jan 26, 2026

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit a4c1371

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ❌ Failed 1m 50s View ↗
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 50s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-27 12:38:11 UTC

Copy link
Contributor

@AlemTuzlak AlemTuzlak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jherr Do you think we should collapse the status into the ChatClient internally instead of requiring state management per lib? I think that would be a sane way of approaching this and then the consumer libs just read it instead of having to deal with re-implementing the logic 5x times?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/typescript/ai-vue/tests/test-utils.ts`:
- Around line 1-5: Reorder the imports so type-only imports come after the value
import from '../src/use-chat' to satisfy ESLint import/order: keep value imports
like import { useChat } from '../src/use-chat' and runtime imports (mount,
defineComponent) earlier, then move type imports (import type { UIMessage } and
import type { UseChatOptions }) immediately after those, ensuring you use
"import type" for the type-only symbols (UIMessage, UseChatOptions) and leave
useChat, mount, and defineComponent as value imports.
♻️ Duplicate comments (2)
packages/typescript/ai-react/src/use-chat.ts (2)

1-4: Resolve ESLint import/order violation.

Line 1-4 should place React imports first and keep @tanstack/ai-client before the @tanstack/ai type import.

🧹 Proposed import reorder
-import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient } from '@tanstack/ai-client'
-import type { ChatClientState } from '@tanstack/ai-client'
-import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
+import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
+import { ChatClient } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
+import type { AnyClientTool, ModelMessage } from '@tanstack/ai'

55-65: Forward onStreamStart to the user callback.

Line 55-57 updates status but drops the consumer callback, so external listeners never fire.

🛠️ Suggested fix
       onStreamStart: () => {
         setStatus('streaming')
+        optionsRef.current.onStreamStart?.()
       },

Comment on lines +1 to +5
import type { UIMessage } from '@tanstack/ai-client'
import { mount } from '@vue/test-utils'
import { useChat } from '../src/use-chat'
import { defineComponent } from 'vue'
import type { UseChatOptions } from '../src/types'
import type { UIMessage } from '@tanstack/ai-client'
import { useChat } from '../src/use-chat'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix import order to satisfy ESLint.

Line 1-5 violate import/order (type imports should follow the value import from ../src/use-chat).

🧹 Proposed import reorder
-import type { UIMessage } from '@tanstack/ai-client'
-import { mount } from '@vue/test-utils'
-import { defineComponent } from 'vue'
-import type { UseChatOptions } from '../src/types'
-import { useChat } from '../src/use-chat'
+import { mount } from '@vue/test-utils'
+import { defineComponent } from 'vue'
+import { useChat } from '../src/use-chat'
+import type { UIMessage } from '@tanstack/ai-client'
+import type { UseChatOptions } from '../src/types'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { UIMessage } from '@tanstack/ai-client'
import { mount } from '@vue/test-utils'
import { useChat } from '../src/use-chat'
import { defineComponent } from 'vue'
import type { UseChatOptions } from '../src/types'
import type { UIMessage } from '@tanstack/ai-client'
import { useChat } from '../src/use-chat'
import { mount } from '@vue/test-utils'
import { defineComponent } from 'vue'
import { useChat } from '../src/use-chat'
import type { UIMessage } from '@tanstack/ai-client'
import type { UseChatOptions } from '../src/types'
🧰 Tools
🪛 ESLint

[error] 1-1: @tanstack/ai-client type import should occur after import of ../src/use-chat

(import/order)


[error] 4-4: ../src/types type import should occur after import of ../src/use-chat

(import/order)

🤖 Prompt for AI Agents
In `@packages/typescript/ai-vue/tests/test-utils.ts` around lines 1 - 5, Reorder
the imports so type-only imports come after the value import from
'../src/use-chat' to satisfy ESLint import/order: keep value imports like import
{ useChat } from '../src/use-chat' and runtime imports (mount, defineComponent)
earlier, then move type imports (import type { UIMessage } and import type {
UseChatOptions }) immediately after those, ensuring you use "import type" for
the type-only symbols (UIMessage, UseChatOptions) and leave useChat, mount, and
defineComponent as value imports.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/typescript/ai-preact/tests/use-chat.test.ts`:
- Around line 1-10: Reorder the imports so type-only imports come after the
regular imports: move "import type { ModelMessage } from '@tanstack/ai'" and
"import type { UIMessage } from '../src/types'" to after the block that imports
createMockConnectionAdapter, createTextChunks, createToolCallChunks, and
renderUseChat from './test-utils' to satisfy the import/order ESLint rule; keep
the existing testing-library and vitest imports where they are and ensure only
type imports are relocated.

In `@packages/typescript/ai-vue/tests/use-chat.test.ts`:
- Around line 1-10: Move the type-only imports (ModelMessage, UIMessage) below
the regular imports from the test-utils module so they follow the
createMockConnectionAdapter, createTextChunks, createToolCallChunks,
renderUseChat imports; specifically, reorder the top of the file so the non-type
import block (createMockConnectionAdapter, createTextChunks,
createToolCallChunks, renderUseChat) appears before the type imports
(ModelMessage, UIMessage) to satisfy the import/order ESLint rule.
🧹 Nitpick comments (4)
packages/typescript/ai-client/src/chat-client.ts (2)

1-16: Import order flagged by linter.

ESLint reports that regular imports should occur before type imports from the same module. This is a style issue.

♻️ Suggested fix
-import type { AnyClientTool, ModelMessage, StreamChunk } from '@tanstack/ai'
 import {
   StreamProcessor,
   generateMessageId,
   normalizeToUIMessage,
 } from '@tanstack/ai'
+import type { AnyClientTool, ModelMessage, StreamChunk } from '@tanstack/ai'
 import type { ConnectionAdapter } from './connection-adapters'
 import type { ChatClientEventEmitter } from './events'
 import { DefaultChatClientEventEmitter } from './events'

81-91: Duplicate setStatus('error') call when errors occur in stream processing.

When an error occurs during stream processing, setError(error) is called at line 89, which internally calls setStatus('error') (lines 205-207). Then line 90 explicitly calls setStatus('error') again. While this is harmless (idempotent), it triggers onStatusChange twice with the same value.

♻️ Suggested fix - remove redundant call
       onError: (error: Error) => {
         this.setError(error)
-        this.setStatus('error')
         this.callbacksRef.current.onError(error)
       },
packages/typescript/ai-preact/src/use-chat.ts (1)

1-2: Import order and type specifier style flagged by linter.

ESLint reports import order issues and suggests using top-level type-only imports. This is a style consistency matter.

♻️ Suggested fix
+import {
+  useCallback,
+  useEffect,
+  useId,
+  useMemo,
+  useRef,
+  useState,
+} from 'preact/hooks'
+
 import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, type ChatClientState } from '@tanstack/ai-client'
-import {
-  useCallback,
-  useEffect,
-  useId,
-  useMemo,
-  useRef,
-  useState,
-} from 'preact/hooks'
+import type { ChatClientState } from '@tanstack/ai-client'
+import { ChatClient } from '@tanstack/ai-client'
packages/typescript/ai-solid/src/use-chat.ts (1)

7-9: Import order and type specifier style flagged by linter.

ESLint reports import order issues and suggests using top-level type-only imports.

♻️ Suggested fix
 import {
   createEffect,
   createMemo,
   createSignal,
   createUniqueId,
 } from 'solid-js'
-
 import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
-import { ChatClient, type ChatClientState } from '@tanstack/ai-client'
+import type { ChatClientState } from '@tanstack/ai-client'
+import { ChatClient } from '@tanstack/ai-client'
 import type { UIMessage, UseChatOptions, UseChatReturn } from './types'

Comment on lines +1 to 10
import type { ModelMessage } from '@tanstack/ai'
import { act, waitFor } from '@testing-library/preact'
import { describe, expect, it, vi } from 'vitest'
import type { UIMessage } from '../src/types'
import {
createMockConnectionAdapter,
createTextChunks,
createToolCallChunks,
renderUseChat,
} from './test-utils'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix import order to satisfy ESLint rules.

Type imports should occur after the regular imports from ./test-utils per the configured import/order rule.

🔧 Proposed fix
-import type { ModelMessage } from '@tanstack/ai'
 import { act, waitFor } from '@testing-library/preact'
 import { describe, expect, it, vi } from 'vitest'
-import type { UIMessage } from '../src/types'
 import {
   createMockConnectionAdapter,
   createTextChunks,
   createToolCallChunks,
   renderUseChat,
 } from './test-utils'
+import type { ModelMessage } from '@tanstack/ai'
+import type { UIMessage } from '../src/types'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { ModelMessage } from '@tanstack/ai'
import { act, waitFor } from '@testing-library/preact'
import { describe, expect, it, vi } from 'vitest'
import type { UIMessage } from '../src/types'
import {
createMockConnectionAdapter,
createTextChunks,
createToolCallChunks,
renderUseChat,
} from './test-utils'
import { act, waitFor } from '@testing-library/preact'
import { describe, expect, it, vi } from 'vitest'
import {
createMockConnectionAdapter,
createTextChunks,
createToolCallChunks,
renderUseChat,
} from './test-utils'
import type { ModelMessage } from '@tanstack/ai'
import type { UIMessage } from '../src/types'
🧰 Tools
🪛 ESLint

[error] 1-1: @tanstack/ai type import should occur after import of ./test-utils

(import/order)


[error] 4-4: ../src/types type import should occur after import of ./test-utils

(import/order)

🤖 Prompt for AI Agents
In `@packages/typescript/ai-preact/tests/use-chat.test.ts` around lines 1 - 10,
Reorder the imports so type-only imports come after the regular imports: move
"import type { ModelMessage } from '@tanstack/ai'" and "import type { UIMessage
} from '../src/types'" to after the block that imports
createMockConnectionAdapter, createTextChunks, createToolCallChunks, and
renderUseChat from './test-utils' to satisfy the import/order ESLint rule; keep
the existing testing-library and vitest imports where they are and ensure only
type imports are relocated.

Comment on lines +1 to 10
import type { ModelMessage } from '@tanstack/ai'
import { flushPromises } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import type { UIMessage } from '../src/types'
import {
createMockConnectionAdapter,
createTextChunks,
createToolCallChunks,
renderUseChat,
} from './test-utils'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix import order to satisfy ESLint rules.

Type imports should occur after the regular imports from ./test-utils per the configured import/order rule.

🔧 Proposed fix
-import type { ModelMessage } from '@tanstack/ai'
 import { flushPromises } from '@vue/test-utils'
 import { describe, expect, it, vi } from 'vitest'
-import type { UIMessage } from '../src/types'
 import {
   createMockConnectionAdapter,
   createTextChunks,
   createToolCallChunks,
   renderUseChat,
 } from './test-utils'
+import type { ModelMessage } from '@tanstack/ai'
+import type { UIMessage } from '../src/types'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { ModelMessage } from '@tanstack/ai'
import { flushPromises } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import type { UIMessage } from '../src/types'
import {
createMockConnectionAdapter,
createTextChunks,
createToolCallChunks,
renderUseChat,
} from './test-utils'
import { flushPromises } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import {
createMockConnectionAdapter,
createTextChunks,
createToolCallChunks,
renderUseChat,
} from './test-utils'
import type { ModelMessage } from '@tanstack/ai'
import type { UIMessage } from '../src/types'
🧰 Tools
🪛 ESLint

[error] 1-1: @tanstack/ai type import should occur after import of ./test-utils

(import/order)


[error] 4-4: ../src/types type import should occur after import of ./test-utils

(import/order)

🤖 Prompt for AI Agents
In `@packages/typescript/ai-vue/tests/use-chat.test.ts` around lines 1 - 10, Move
the type-only imports (ModelMessage, UIMessage) below the regular imports from
the test-utils module so they follow the createMockConnectionAdapter,
createTextChunks, createToolCallChunks, renderUseChat imports; specifically,
reorder the top of the file so the non-type import block
(createMockConnectionAdapter, createTextChunks, createToolCallChunks,
renderUseChat) appears before the type imports (ModelMessage, UIMessage) to
satisfy the import/order ESLint rule.

Comment on lines 205 to 207
if (error) {
this.setStatus('error')
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is called both here and on line 90, remove this check

Copy link
Contributor

@AlemTuzlak AlemTuzlak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really neat now! Thank you @nikas-belogolov , I'll let @jherr review it as well

Just please address my comment on the error status

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 27, 2026

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai@247

@tanstack/ai-anthropic

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-anthropic@247

@tanstack/ai-client

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-client@247

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-devtools-core@247

@tanstack/ai-gemini

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-gemini@247

@tanstack/ai-grok

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-grok@247

@tanstack/ai-ollama

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-ollama@247

@tanstack/ai-openai

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-openai@247

@tanstack/ai-openrouter

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-openrouter@247

@tanstack/ai-preact

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-preact@247

@tanstack/ai-react

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-react@247

@tanstack/ai-react-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-react-ui@247

@tanstack/ai-solid

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-solid@247

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-solid-ui@247

@tanstack/ai-svelte

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-svelte@247

@tanstack/ai-vue

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-vue@247

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-vue-ui@247

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/preact-ai-devtools@247

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/react-ai-devtools@247

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/solid-ai-devtools@247

commit: a4c1371

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/typescript/ai-client/src/chat-client.ts`:
- Around line 88-91: The onError handler is redundantly calling
setStatus('error') after setError(error) (which already sets status), causing
duplicate onStatusChange notifications; remove the extra setStatus('error')
calls in the onError blocks so only setError(error) is invoked before calling
callbacksRef.current.onError(error); apply the same removal for the second
occurrence around the code that mirrors this logic (the one referenced at lines
205-207).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/typescript/ai-preact/tests/use-chat.test.ts`:
- Around line 566-650: Three status tests are commented out (initial status,
error transition, stop transition) in the use-chat test suite; locate the tests
using identifiers renderUseChat, createMockConnectionAdapter,
result.current.sendMessage, result.current.stop and either (A) re-enable and fix
them so they pass (restore the original it(...) blocks and address any
framework-specific failure causing assertions on result.current.status), or (B)
explicitly mark them as skipped with a reason using it.skip('reason', ...) or
add a TODO/FIXME comment above each block explaining why they are disabled and
linking to an issue; pick one approach and apply it consistently for the three
blocks so test intent and visibility are preserved.
🧹 Nitpick comments (3)
packages/typescript/ai-client/src/chat-client.ts (1)

1-16: Fix import order per ESLint rules.

The static analysis indicates import order violations. Type imports from @tanstack/ai should occur after regular imports, and other type imports should be grouped appropriately.

🔧 Suggested fix
-import type { AnyClientTool, ModelMessage, StreamChunk } from '@tanstack/ai'
 import {
   StreamProcessor,
   generateMessageId,
   normalizeToUIMessage,
 } from '@tanstack/ai'
-import type { ConnectionAdapter } from './connection-adapters'
-import type { ChatClientEventEmitter } from './events'
 import { DefaultChatClientEventEmitter } from './events'
+import type { AnyClientTool, ModelMessage, StreamChunk } from '@tanstack/ai'
+import type { ConnectionAdapter } from './connection-adapters'
+import type { ChatClientEventEmitter } from './events'
 import type {
   ChatClientOptions,
   ChatClientState,
   MessagePart,
   ToolCallPart,
   UIMessage,
 } from './types'
packages/typescript/ai-client/tests/chat-client.test.ts (1)

395-423: Consider adding explicit tests for initial status and error transitions.

The status test suite covers the happy path well but could be more comprehensive:

  1. Missing explicit test for initial status being 'ready' (constructor default)
  2. Missing dedicated test for status transitioning to 'error' (currently only tested implicitly in the error handling section)

This would align with the test coverage in other framework test files (e.g., Svelte tests have explicit error transition tests in the status section).

💡 Suggested additional tests
it('should have initial status of ready', () => {
  const adapter = createMockConnectionAdapter()
  const client = new ChatClient({ connection: adapter })
  expect(client.getStatus()).toBe('ready')
})

it('should transition to error on connection failure', async () => {
  const adapter = createMockConnectionAdapter({
    shouldError: true,
    error: new Error('Test error'),
  })
  const client = new ChatClient({ connection: adapter })

  await client.sendMessage('Test')
  expect(client.getStatus()).toBe('error')
})
packages/typescript/ai-vue/tests/use-chat.test.ts (1)

466-489: Consider adding a test for the 'error' status transition.

The test covers the happy path ('ready''submitted'/'streaming''ready'), but the 'error' status is not explicitly tested. Since the status property includes 'error' as a valid state, consider adding a test to verify the status transitions to 'error' when an error occurs.

♻️ Suggested test addition
     it('should transition through states during generation', async () => {
       // ... existing test
     })
+
+    it('should transition to error status on failure', async () => {
+      const error = new Error('Test error')
+      const adapter = createMockConnectionAdapter({
+        shouldError: true,
+        error,
+      })
+      const { result } = renderUseChat({ connection: adapter })
+
+      expect(result.current.status).toBe('ready')
+
+      await result.current.sendMessage('Test')
+      await flushPromises()
+
+      expect(result.current.status).toBe('error')
+      expect(result.current.error).toBeDefined()
+    })
   })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants