用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ofrades/bursa --skill tanstack-ai命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Query OpenRouter for available AI models, pricing, capabilities, throughput, and provider performance. Use when the user asks about available OpenRouter models, model pricing, model context lengths, model capabilities, provider latency or uptime, throughput limits, supported parameters, wants to search/filter/compare models, or find the fastest provider for a model.
React renderer for json-render that turns JSON specs into React components. Use when working with @json-render/react, building React UIs from JSON, creating component catalogs, or rendering AI-generated specs.
Pre-built shadcn/ui components for json-render. Use when working with @json-render/shadcn, adding standard UI components to a catalog, or building web UIs with Radix UI + Tailwind CSS components.
基于 SOC 职业分类
正在显示 SKILL.md
| name | tanstack-ai |
| description | Provider-agnostic, type-safe AI SDK for streaming, tool calling, structured output, and multimodal content. |
TanStack AI is a modular, provider-agnostic AI SDK with tree-shakeable adapters for OpenAI, Anthropic, Gemini, Ollama, and more. It provides streaming-first text generation, tool calling with approval workflows, structured output with Zod schemas, multimodal content support, and React hooks for chat/completion UIs.
Core: @tanstack/ai
Vanilla Client: @tanstack/ai-client (framework-agnostic)
React: @tanstack/ai-react
Solid: @tanstack/ai-solid
Adapters: @tanstack/ai-openai, @tanstack/ai-anthropic, @tanstack/ai-gemini, @tanstack/ai-ollama
Languages: TypeScript/JavaScript, PHP, Python
Status: Alpha
npm install @tanstack/ai @tanstack/ai-react
# Or for framework-agnostic vanilla client:
npm install @tanstack/ai @tanstack/ai-client
# Provider adapters (install only what you need):
npm install @tanstack/ai-openai
npm install @tanstack/ai-anthropic
npm install @tanstack/ai-gemini
npm install @tanstack/ai-ollama
composer require tanstack/ai tanstack/ai-openai
pip install tanstack-ai tanstack-ai-openai
import { generate } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai/adapters";
const result = await generate({
adapter: openaiText({ model: "gpt-4o" }),
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Explain React hooks in 3 sentences." },
],
});
// Streaming with async iteration
for await (const chunk of result) {
process.stdout.write(chunk.text);
}
import { openaiText } from "@tanstack/ai-openai/adapters";
import { anthropicText } from "@tanstack/ai-anthropic/adapters";
import { geminiText } from "@tanstack/ai-gemini/adapters";
import { ollamaText } from "@tanstack/ai-ollama/adapters";
// OpenAI
const openai = openaiText({ model: "gpt-4o" });
// Anthropic
const anthropic = anthropicText({ model: "claude-sonnet-4-20250514" });
// Google Gemini
const gemini = geminiText({ model: "gemini-pro" });
// Ollama (local)
const ollama = ollamaText({ model: "llama3" });
// Runtime adapter switching
const adapter = process.env.AI_PROVIDER === "anthropic" ? anthropic : openai;
import { useChat } from "@tanstack/ai-react";
function ChatUI() {
const { messages, input, setInput, handleSubmit, isLoading } = useChat({
adapter: openaiText({ model: "gpt-4o" }),
});
return (
<div>
{messages.map((msg) => (
<div key={msg.id}>
<strong>{msg.role}:</strong> {msg.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type a message..."
/>
<button type="submit" disabled={isLoading}>
Send
</button>
</form>
</div>
);
}
import { useCompletion } from "@tanstack/ai-react";
function CompletionUI() {
const { completion, input, setInput, handleSubmit, isLoading } = useCompletion({
adapter: openaiText({ model: "gpt-4o" }),
});
return (
<div>
<form onSubmit={handleSubmit}>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Enter prompt..."
/>
<button type="submit" disabled={isLoading}>
Generate
</button>
</form>
{completion && <div>{completion}</div>}
</div>
);
}
import { createChat } from "@tanstack/ai-solid";
function ChatUI() {
const chat = createChat({
adapter: openaiText({ model: "gpt-4o" }),
});
return (
<div>
<For each={chat.messages()}>
{(msg) => (
<div>
<strong>{msg.role}:</strong> {msg.content}
</div>
)}
</For>
<form onSubmit={chat.handleSubmit}>
<input
value={chat.input()}
onInput={(e) => chat.setInput(e.target.value)}
placeholder="Type a message..."
/>
<button type="submit" disabled={chat.isLoading()}>
Send
</button>
</form>
</div>
);
}
For framework-agnostic usage without React or Solid:
import { createAIClient } from "@tanstack/ai-client";
import { openaiText } from "@tanstack/ai-openai/adapters";
const client = createAIClient({
adapter: openaiText({ model: "gpt-4o" }),
});
// Subscribe to state changes
client.subscribe((state) => {
console.log("Messages:", state.messages);
console.log("Loading:", state.isLoading);
});
// Send a message
await client.send("Hello, world!");
// Clear conversation
client.clear();
import { generate } from '@tanstack/ai'
// Default: stream chunks as they arrive
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [...],
stream: true,
})
for await (const chunk of result) {
// Process each chunk
console.log(chunk.text)
}
Available streaming strategies:
// Server-side SSE endpoint
import { createReplayStream } from "@tanstack/ai";
export async function handler(req: Request) {
const stream = createReplayStream({
adapter: openaiText({ model: "gpt-4o" }),
messages: await req.json(),
});
return new Response(stream, {
headers: { "Content-Type": "text/event-stream" },
});
}
import { generate } from "@tanstack/ai";
import { convertZodToJsonSchema } from "@tanstack/ai";
import { z } from "zod";
const RecipeSchema = z.object({
name: z.string(),
ingredients: z.array(
z.object({
item: z.string(),
amount: z.string(),
}),
),
steps: z.array(z.string()),
cookTime: z.number(),
});
const result = await generate({
adapter: openaiText({ model: "gpt-4o" }),
messages: [{ role: "user", content: "Give me a pasta recipe" }],
schema: convertZodToJsonSchema(RecipeSchema),
});
// result is typed as z.infer<typeof RecipeSchema>
console.log(result.name, result.ingredients);
import { generate } from "@tanstack/ai";
const result = await generate({
adapter: openaiText({ model: "gpt-4o" }),
messages: [{ role: "user", content: "What is the weather in NYC?" }],
tools: {
getWeather: {
description: "Get weather for a location",
parameters: z.object({
location: z.string(),
unit: z.enum(["celsius", "fahrenheit"]).optional(),
}),
execute: async ({ location, unit }) => {
const data = await fetchWeather(location, unit);
return data;
},
},
},
});
import { ToolCallManager } from "@tanstack/ai";
const manager = new ToolCallManager({
tools: {
deleteUser: {
description: "Delete a user account",
parameters: z.object({ userId: z.string() }),
requiresApproval: true, // Requires human approval
execute: async ({ userId }) => {
await deleteUser(userId);
return { success: true };
},
},
},
onApprovalRequired: async (toolCall) => {
// Present to user for approval
return await showApprovalDialog(toolCall);
},
});
const result = await generate({
adapter: openaiText({ model: "gpt-4o" }),
messages: [{ role: "user", content: "Research and summarize the topic" }],
tools: { search, summarize, writeReport },
maxIterations: 10, // Limit agent loop iterations
});
// Images
const result = await generate({
adapter: openaiText({ model: "gpt-4o" }),
messages: [
{
role: "user",
content: [
{ type: "text", text: "What is in this image?" },
{ type: "image_url", image_url: { url: "https://example.com/photo.jpg" } },
],
},
],
});
// Image generation with DALL-E
import { openaiImage } from "@tanstack/ai-openai/adapters";
const image = await generate({
adapter: openaiImage({ model: "dall-e-3" }),
messages: [{ role: "user", content: "A sunset over mountains" }],
});
// Image generation with Gemini Imagen
import { geminiImage } from "@tanstack/ai-gemini/adapters";
const image = await generate({
adapter: geminiImage({ model: "imagen-3" }),
messages: [{ role: "user", : }],
});
Support for models with extended reasoning/thinking capabilities:
import { generate } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic/adapters";
const result = await generate({
adapter: anthropicText({ model: "claude-sonnet-4-20250514" }),
messages: [{ role: "user", content: "Solve this complex math problem step by step..." }],
thinking: {
enabled: true,
budget: 10000, // Max thinking tokens
},
});
// Access thinking/reasoning output
console.log("Thinking:", result.thinking);
console.log("Response:", result.text);
// Streaming with thinking tokens
for await (const chunk of result) {
if (chunk.type === "thinking") {
console.log("[Thinking]", chunk.text);
} else {
process.stdout.write(chunk.text);
}
}
import { generateMessageId, normalizeToUIMessage } from "@tanstack/ai";
// Generate unique message IDs
const id = generateMessageId();
// Normalize provider-specific messages to UI format
const uiMessage = normalizeToUIMessage(providerMessage);
const result = await generate({
adapter: openaiText({ model: 'gpt-4o' }),
messages: [...],
onEvent: (event) => {
// Structured, typed events
switch (event.type) {
case 'text':
console.log('Text chunk:', event.data)
break
case 'tool_call':
console.log('Tool called:', event.name)
break
case 'error':
console.error('Error:', event.error)
break
}
},
})
TanStack AI includes a dedicated devtools panel for debugging AI workflows:
import { TanStackDevtools } from "@tanstack/react-devtools";
import { AIDevtoolsPanel } from "@tanstack/ai-react/devtools";
function App() {
return (
<TanStackDevtools
plugins={[
{
id: "ai",
name: "AI",
render: () => <AIDevtoolsPanel />,
},
]}
/>
);
}
AI Devtools features:
// Shared implementation between AI tools and server functions
import { createServerFn } from "@tanstack/react-start";
import { generate } from "@tanstack/ai";
const aiChat = createServerFn({ method: "POST" })
.validator(z.object({ messages: z.array(messageSchema) }))
.handler(async ({ data }) => {
const result = await generate({
adapter: openaiText({ model: "gpt-4o" }),
messages: data.messages,
});
return result;
});
For streaming structured output that arrives incrementally:
import { parsePartialJson } from "@tanstack/ai";
// Parse incomplete JSON during streaming
const partial = parsePartialJson('{"name": "Pasta", "ingredients": [{"item": "flour"');
// Returns: { name: "Pasta", ingredients: [{ item: "flour" }] }
maxIterations on agentic loops to prevent runaway executionrequiresApproval for destructive tool callsonEvent for observability and debugging in developmentmaxIterations in agentic loops (can run indefinitely)