Skip to content

feat(ui): drop the /ui createChatHook factory - #1269

Closed
tombeckenham wants to merge 9 commits into
feat/typed-headless-chat-uifrom
cut/drop-create-chat-hook-factory
Closed

feat(ui): drop the /ui createChatHook factory#1269
tombeckenham wants to merge 9 commits into
feat/typed-headless-chat-uifrom
cut/drop-create-chat-hook-factory

Conversation

@tombeckenham

@tombeckenham tombeckenham commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Note for @AlemTuzlak — this is a question, not a merge request.

This is a cut-down of the /ui factory you added in #1263. It targets your
branch, so it stacks on your work instead of competing with it. Tell me if
this feels lighter than what you proposed, or if it drops something you need.
If you prefer your version, I will close this.

The /ui subpath no longer owns the chat options. A screen calls useChat(options) from the framework package, then passes that instance and a typed components map to <Chat chat={chat} components={components} />.

The factory createChatHook({ options, chatComponents }) and <chat.AppChat /> are gone from /ui. Options-only createChatHook(options) on the main package stays as it is.

The question for you

The factory bound three things together: the chat options, the component catalog, and the React or Solid contexts. My argument is that the instance and the catalog are separate concerns, and that binding them costs more than it returns.

What this removes, per framework:

  1. create-chat-hook in all four packages (React, Solid, Svelte, Vue).
  2. create-ui-contexts in React and Solid.
  3. The chatContext, partContext, and interruptContext objects a user had to build and pass in. The chatbot example deleted its whole src/chat/ui-context.ts for this.
  4. The second way to get a chat instance. There is now one: useChat.

Net across the branch: 58 files, +1058 / -3741. Packages alone drop 1,940 lines.

Two things I want your read on:

  • Contexts. I think useChatContext() from /ui covers what the three context objects did. Tell me if you had a case it does not cover.
  • Type inference. components is checked with satisfies ChatUIComponents<typeof chatOptions>. Tool and interrupt names still infer. Tell me if you were protecting an inference case I broke.

🎯 Changes

  • /ui exports Chat and useChatContext. Screens call useChat or createChat themselves.
  • Drop the /ui factory that mixed AppChat onto the chat instance.
  • Keep compound ChatMessages / ChatInput on /ui. The old connection-based root is DeprecatedChat.
  • Update React, Solid, Vue, Svelte examples and the trip-desk chatbot to <Chat chat={chat} components={components} />.
  • Update the existing create-chat-hook changeset to match this API.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested code changes locally with pnpm run test:pr, or these tests do not apply to this pull request.
  • I fully understand the code in this pull request, including any code generated with AI assistance.
  • Docs: I updated docs/ for this change, or this change is not user-facing.
  • Changeset: I added a changeset (pnpm changeset), or this PR does not change a published package.

🚀 Release Impact

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

Testing

Commands run

  1. pnpm test:pr passed for all 86 projects after the rebase.
  2. pnpm install --frozen-lockfile passed. The lockfile is consistent with the base branch.
  3. Playwright E2E was not run on my machine. CI runs it on this PR.

Manual test

  1. Run pnpm --filter ts-react-ui-chatbot dev.
  2. Send "Look up Kyoto".
  3. Confirm the budget interrupt renders and the tool cards still render.
  4. Repeat on examples/ts-solid-chat /solid-ui, the Vue UI in examples/ts-vue-chat, and examples/ts-svelte-chat /svelte-ui.

How this PR makes testing easy

  • Chat UI tests live under packages/ai-*/tests/chat-ui.
  • The chatbot example and testing/e2e/src/routes/headless-ui.tsx use the public Chat + components API.

Public API change

Before

import { createChatHook } from '@tanstack/ai-react/ui'

const { useAppChat } = createChatHook({
  options: chatOptions,
  chatComponents: catalog,
})

function Support() {
  const chat = useAppChat({ threadId: 'support-1' })
  return <chat.AppChat />
}

After

import { useChat } from '@tanstack/ai-react'
import { Chat } from '@tanstack/ai-react/ui'

function Support() {
  const chat = useChat({ ...chatOptions, threadId: 'support-1' })
  return <Chat chat={chat} components={catalog} />
}

createChatHook(options) on @tanstack/ai-react still returns a bound useChat. It does not take chatComponents.

Risk / rollback

This is a breaking change to the unreleased /ui factory on feat/typed-headless-chat-ui. Nothing published changes, because that branch has not shipped. A revert restores createChatHook({ options, chatComponents }) and <chat.AppChat />. Headless useChat(options) call sites do not change.

Housekeeping

This branch carried nine commits that had already landed on feat/typed-headless-chat-ui. That is why it read as 100 files and showed a conflict. I rebased onto the current base, so the diff is now the real 58 files and it merges clean. The content of the four commits did not change.

@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e4c259c6-fe0f-47aa-a131-40db6195d142

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@nx-cloud

nx-cloud Bot commented Aug 30, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 31be36d

Command Status Duration Result
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 3s View ↗

☁️ Nx Cloud last updated this comment at 2026-08-31 03:36:39 UTC

@pkg-pr-new

pkg-pr-new Bot commented Aug 30, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

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

@tanstack/ai-acp

npm i https://pkg.pr.new/@tanstack/ai-acp@1269

@tanstack/ai-angular

npm i https://pkg.pr.new/@tanstack/ai-angular@1269

@tanstack/ai-anthropic

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

@tanstack/ai-bedrock

npm i https://pkg.pr.new/@tanstack/ai-bedrock@1269

@tanstack/ai-byteplus

npm i https://pkg.pr.new/@tanstack/ai-byteplus@1269

@tanstack/ai-claude-code

npm i https://pkg.pr.new/@tanstack/ai-claude-code@1269

@tanstack/ai-client

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

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@1269

@tanstack/ai-code-mode-snippets

npm i https://pkg.pr.new/@tanstack/ai-code-mode-snippets@1269

@tanstack/ai-codex

npm i https://pkg.pr.new/@tanstack/ai-codex@1269

@tanstack/ai-cohere

npm i https://pkg.pr.new/@tanstack/ai-cohere@1269

@tanstack/ai-compaction

npm i https://pkg.pr.new/@tanstack/ai-compaction@1269

@tanstack/ai-devtools-core

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

@tanstack/ai-durable-stream

npm i https://pkg.pr.new/@tanstack/ai-durable-stream@1269

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@1269

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@1269

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@1269

@tanstack/ai-gemini

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

@tanstack/ai-grok

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

@tanstack/ai-grok-build

npm i https://pkg.pr.new/@tanstack/ai-grok-build@1269

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@1269

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@1269

@tanstack/ai-isolate-daytona

npm i https://pkg.pr.new/@tanstack/ai-isolate-daytona@1269

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@1269

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@1269

@tanstack/ai-isolate-quickjs-bun

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs-bun@1269

@tanstack/ai-llmgateway

npm i https://pkg.pr.new/@tanstack/ai-llmgateway@1269

@tanstack/ai-lovable

npm i https://pkg.pr.new/@tanstack/ai-lovable@1269

@tanstack/ai-mcp

npm i https://pkg.pr.new/@tanstack/ai-mcp@1269

@tanstack/ai-memory

npm i https://pkg.pr.new/@tanstack/ai-memory@1269

@tanstack/ai-mistral

npm i https://pkg.pr.new/@tanstack/ai-mistral@1269

@tanstack/ai-octane

npm i https://pkg.pr.new/@tanstack/ai-octane@1269

@tanstack/ai-ollama

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

@tanstack/ai-openai

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

@tanstack/ai-opencode

npm i https://pkg.pr.new/@tanstack/ai-opencode@1269

@tanstack/ai-openrouter

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

@tanstack/ai-perplexity

npm i https://pkg.pr.new/@tanstack/ai-perplexity@1269

@tanstack/ai-persistence

npm i https://pkg.pr.new/@tanstack/ai-persistence@1269

@tanstack/ai-preact

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

@tanstack/ai-react

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

@tanstack/ai-react-ui

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

@tanstack/ai-sandbox

npm i https://pkg.pr.new/@tanstack/ai-sandbox@1269

@tanstack/ai-sandbox-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-sandbox-cloudflare@1269

@tanstack/ai-sandbox-daytona

npm i https://pkg.pr.new/@tanstack/ai-sandbox-daytona@1269

@tanstack/ai-sandbox-docker

npm i https://pkg.pr.new/@tanstack/ai-sandbox-docker@1269

@tanstack/ai-sandbox-local-process

npm i https://pkg.pr.new/@tanstack/ai-sandbox-local-process@1269

@tanstack/ai-sandbox-sprites

npm i https://pkg.pr.new/@tanstack/ai-sandbox-sprites@1269

@tanstack/ai-sandbox-upstash-box

npm i https://pkg.pr.new/@tanstack/ai-sandbox-upstash-box@1269

@tanstack/ai-sandbox-vercel

npm i https://pkg.pr.new/@tanstack/ai-sandbox-vercel@1269

@tanstack/ai-skills

npm i https://pkg.pr.new/@tanstack/ai-skills@1269

@tanstack/ai-solid

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

@tanstack/ai-solid-ui

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

@tanstack/ai-svelte

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

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@1269

@tanstack/ai-vercel-gateway

npm i https://pkg.pr.new/@tanstack/ai-vercel-gateway@1269

@tanstack/ai-vertex

npm i https://pkg.pr.new/@tanstack/ai-vertex@1269

@tanstack/ai-vue

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

@tanstack/ai-vue-ui

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

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@1269

@tanstack/preact-ai-devtools

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

@tanstack/react-ai-devtools

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

@tanstack/solid-ai-devtools

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

@tanstack/svelte-ai-devtools

npm i https://pkg.pr.new/@tanstack/svelte-ai-devtools@1269

commit: 31be36d

AlemTuzlak and others added 5 commits August 31, 2026 07:10
* feat(client): add createChatHook bound useChat factory

* feat(ui): align createChatUI with Form and Table factories

* feat(ui): move chat UI onto framework /ui subpaths

Fold the *-ui packages into @tanstack/ai-react/ui, @tanstack/ai-solid/ui, @tanstack/ai-vue/ui, and @tanstack/ai-svelte/ui.

createChatHook({ options, chatComponents }) returns useAppChat (Svelte: createAppChat). useAppChat mixes AppChat onto the instance so screens render <chat.AppChat />.

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Restore @tanstack/ai-react-ui, ai-solid-ui, ai-vue-ui, and ai-svelte-ui as
thin re-exports of the framework /ui subpath until 1.0.0.

Document createChatHook, chat.AppChat, and the import path change.
That package never shipped on npm. Svelte chat UI lives on
@tanstack/ai-svelte/ui. Keep deprecated shims only for the
published react, solid, and vue UI packages.
@tombeckenham
tombeckenham force-pushed the feat/typed-headless-chat-ui branch from 0ed4bdd to 88e47e7 Compare August 30, 2026 21:11
tombeckenham and others added 4 commits August 31, 2026 12:27
Render `<Chat chat={chat} components={components} />` with `useChat` /
`createChat` from the framework package. Keep options-only
`createChatHook` on the main package.
Keep ChatMessages, ChatInput, and the old Chat root as DeprecatedChat
so the *-ui re-export shim still exposes those names. Drop unused shim
devDependencies.
@tombeckenham
tombeckenham force-pushed the cut/drop-create-chat-hook-factory branch from 11244a8 to 31be36d Compare August 31, 2026 03:34
@tombeckenham
tombeckenham marked this pull request as ready for review August 31, 2026 03:36
@github-actions github-actions Bot added the waiting-on: author Waiting for the author to respond or update label Aug 31, 2026
@AlemTuzlak
AlemTuzlak force-pushed the feat/typed-headless-chat-ui branch from 88e47e7 to f71ed93 Compare August 31, 2026 09:25
@AlemTuzlak
AlemTuzlak requested a review from a team as a code owner August 31, 2026 09:25
@AlemTuzlak

Copy link
Copy Markdown
Contributor

Heads up: #1252 was rewound to the pre-merge createChatUI commit (the #1263 squash is no longer on that branch). The Form/Table factory work is stacked again as #1275 (feat/create-chat-hook -> feat/typed-headless-chat-ui). This branch will now diff against the restored #1252 base, so it will look much larger. Happy to talk through retargeting if you still want this cut on top of #1275 instead.

@github-actions github-actions Bot added the merge-conflicts Conflicts with the base branch — needs a rebase label Aug 31, 2026
@AlemTuzlak AlemTuzlak closed this Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-conflicts Conflicts with the base branch — needs a rebase waiting-on: author Waiting for the author to respond or update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants