Solid useChat drops earlier turns after a reactive request option changes
I maintainer di solito rispondono entro 1 giorno
@AlemTuzlak ci sta già lavorando.
Dal 28/9/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
TanStack AI version
@tanstack/[email protected] and @tanstack/[email protected], reproduced on TanStack/ai main at 62bec34bb.
Framework/Library version
SolidJS 1.9.10.
Describe the bug and the steps to reproduce it
useChat starts a new ChatClient when a reactive body getter changes, even when the caller has not changed the conversation's threadId. The next send uses the new client's empty transcript. A two-turn conversation then reaches the connection adapter as two separate one-turn requests.
The cause is in packages/ai-solid/src/use-chat.ts. On main, the client is constructed inside createMemo (around line 105). That memo reads options.body while building the ChatClient (around line 140). Solid tracks the signal read by the getter. Updating that signal reruns the memo and constructs a new client. The [clientId] passed as the second argument to createMemo (line 219) is its initial value, not a dependency array. It does not restrict reruns to clientId changes. The effect below the memo then updates options on the newly constructed client; it cannot restore the old transcript.
The following minimal Vitest case uses the repository's existing fake connection adapter. Save it as packages/ai-solid/tests/repro-reactive-body.test.ts on clean main:
import { renderHook } from '@solidjs/testing-library'
import { createSignal } from 'solid-js'
import { expect, it } from 'vitest'
import { useChat } from '../src/use-chat'
import { createMockConnectionAdapter, createTextChunks } from './test-utils'
it('keeps the first turn after a reactive body change', async () => {
const requests: Array<{ users: number; provider: unknown }> = []
const connection = createMockConnectionAdapter({
chunks: createTextChunks('Response'),
onConnect(messages, data) {
requests.push({
users: messages.filter((message) => message.role === 'user').length,
provider: data?.['provider'],
})
},
})
const { result } = renderHook(() => {
const [provider, setProvider] = createSignal('openai')
const chat = useChat({
connection,
get body() { return { provider: provider() } },
})
return { chat, setProvider }
})
await result.chat.sendMessage('First')
result.setProvider('anthropic')
await result.chat.sendMessage('Second')
expect(requests).toEqual([
{ users: 1, provider: 'openai' },
{ users: 2, provider: 'anthropic' },
])
})
Run pnpm --dir packages/ai-solid exec vitest run tests/repro-reactive-body.test.ts. The same case was run in detached checkouts of clean main and the fix branch:
main 62bec34bb: 1 failed
AssertionError: expected [ 1, 1 ] to deeply equal [ 1, 2 ]
fix 589539c82: 1 passed
requests: [{ users: 1, provider: 'openai' },
{ users: 2, provider: 'anthropic' }]
The maintained regression is in the proposed branch. It uses this same public hook and fake adapter. The browser E2E case checks the same two-send path.
Expected behavior
Changing request metadata such as body or forwardedProps should change the next request without changing the ChatClient that owns the transcript. A new threadId should select a new conversation and release the old connection. The current Solid API guide calls threadId the chat's identity, and ChatClient.updateOptions already supports changing wire-payload options without replacing the client.
Impact and scope
This is observable without a provider key: the second call to the connection adapter contains one user message rather than two. A provider therefore lacks the first user turn and its reply when generating the second response. The affected path is Solid useChat with a reactive option getter; this report does not concern per-call sendMessage body forwarding. PR #1227 addressed that separate path, and PR #1232 changes client snapshots rather than the Solid memo.
Your Minimal, Reproducible Example - (Sandbox Highly Recommended)
Runnable repository test on the proposed branch. The complete main-branch reproduction is inline above and needs no external service.
Screenshots or Videos (Optional)
Not applicable; the request history is asserted directly.
Do you intend to try to help solve this bug with your own PR?
Yes, I am also opening a PR that solves the problem alongside this issue.
Terms & Code of Conduct
- I agree to follow this project's Code of Conduct.
- I understand that a bug without a reliable reproduction can be closed.
Environment
- Node.js
24.11.1, pnpm11.19.0, Windows 11. - The reproduction uses Solid's test harness and a local connection adapter; no provider, browser service, or API key is required.
- Lingua principale
- TypeScript
- Stelle
- 3.1k
- Fork
- 340
- Merge medio
- 2g 10h
- PR unite (30g)
- 175
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di TanStack/ai
-
update elevenlabsForse già presa @tombeckenham l’ha presa oggi. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
I maintainer di solito rispondono entro 1 giorno
-
onAfterToolCall failure records a second, contradictory result for a successful server toolForse già presa @AlemTuzlak l’ha presa oggi. Apertahas-pr waiting-on: maintainer
TanStack/ai#1558 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
SSE and NDJSON response streams drain unread sources without backpressureForse già presa @tombeckenham l’ha presa oggi. Apertahas-pr waiting-on: maintainer
TanStack/ai#1556 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
Tool calls from one model step run one at a time, but the docs say they run in parallelForse già presa @tombeckenham l’ha presa 1 giorno fa. Apertawaiting-on: maintainer
TanStack/ai#1547 · 1 reazione · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
OpenRouter adapters: optional tool fields cannot be omitted (Chat Completions) or fail validation (Responses)Forse già presa @tombeckenham l’ha presa 1 giorno fa. Apertahas-pr waiting-on: maintainer
TanStack/ai#1542 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Issue simili
-
documentation
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
inu-appcenter/memorIN-frontend#106 ·
I maintainer di solito rispondono entro 1 giorno
-
kind/bug
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
I maintainer di solito rispondono entro 7 giorni
-
[Bug] @deck.gl/arcgis dist import resolves to unpublished @deck.gl/core source path (9.3.11, 9.4.0)Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
fix: CopyFilters ignores tabApertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
CSCfi/sd-search-ui#145 ·
I maintainer di solito rispondono entro 1 giorno
-
Add: Cbeebies pl SDApertacheck:passed streams:add
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
I maintainer di solito rispondono entro 1 giorno