Skip to content

refactor(chat): define chat/ai tools once as framework-agnostic specs - #935

Merged
bensabic merged 1 commit into
mainfrom
tanstack-tool-specs
Sep 16, 2026
Merged

bensabic merged 1 commit into
mainfrom
tanstack-tool-specs

Conversation

@bensabic

Copy link
Copy Markdown
Collaborator

Every tool in chat/ai was built directly with the AI SDK's tool() helper, which meant the tool definitions could only ever produce AI SDK tools. This PR separates the definition from the framework so the next PR can offer the same tools to TanStack AI.

Each tool is now a plain spec:

export const postMessageSpec = (chat, { needsApproval = true, guard } = {}): ChatToolSpec<Input, Output> => ({
  name: "postMessage",
  description: "Post a message inside an existing thread. ...",
  needsApproval,
  inputSchema: POST_MESSAGE_INPUT,
  execute: async ({ threadId, message }) => { ... },
});

and the AI SDK wrapping happens once, in toAiTool. The presets, approval flags, scope guard, and override filtering that createChatTools wires up move to a shared module, and the link and attachment plumbing behind toAiMessages moves out the same way.

Nothing changes for callers. createChatTools, toAiMessages, and the 17 standalone tool factories keep their signatures, return types, and behavior, and the existing tests are untouched. The examples in examples/nextjs-chat and examples/nuxt-chat compile as before.

One relocation worth explaining: ToolOverrides is an AI SDK Pick<Tool, ...>, and it used to live beside ChatBinding in ai/types.ts. It moves next to the AI SDK wrapper so the shared modules never reference ai, not even as a type. Without that, tsup's declaration chunking pulls an import 'ai' into any entry that shares those modules.

Changed files:

Middle of a three-PR stack; no changeset of its own since nothing observable changes.

@bensabic
bensabic requested a review from a team as a code owner September 15, 2026 07:05
@vercel

vercel Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
chat Ready Ready Preview, v0 Sep 16, 2026 12:13am UTC
chat-sdk-nextjs-chat Ready Ready Preview, v0 Sep 16, 2026 12:13am UTC

Base automatically changed from tanstack-streams to main September 16, 2026 00:12
Every tool in chat/ai used to be built directly with the AI SDK's tool()
helper. Each one is now a plain ChatToolSpec (name, description, zod input
schema, execute), and the AI SDK wrapping happens in one place,
tools/ai-sdk.ts. The presets, approval flags and scope guard that
createChatTools wires up move to toolset.ts so another framework can reuse
them, and the link and attachment handling behind toAiMessages moves to
message-content.ts for the same reason.

ToolOverrides moves next to the AI SDK wrapper so none of the shared
modules reference the ai package.

createChatTools, toAiMessages and the standalone tool factories keep their
signatures and behavior.

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
@bensabic
bensabic merged commit 21dc60c into main Sep 16, 2026
19 checks passed
@bensabic
bensabic deleted the tanstack-tool-specs branch September 16, 2026 00:19
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