与框架无关的无头客户端,用于管理聊天状态和流式传输。
npm install @tanstack/ai-client
用于管理聊天状态的主要客户端类。
import { ChatClient, fetchServerSentEvents } from "@tanstack/ai-client";
const client = new ChatClient({
connection: fetchServerSentEvents("/api/chat"),
initialMessages: [],
onMessagesChange: (messages) => {
console.log("Messages updated:", messages);
},
onToolCall: async ({ toolName, input }) => {
// Handle client tool execution
return { result: "..." };
},
});
发送用户消息并获取响应。
await client.sendMessage("Hello!");
将消息附加到对话中。
await client.append({
role: "user",
content: "Additional context",
});
重新加载上一条助手消息。
await client.reload();
停止当前的响应生成。
client.stop();
清除所有消息。
client.clear();
手动设置消息数组。
client.setMessagesManually([...newMessages]);
添加客户端工具执行的结果。
await client.addToolResult({
toolCallId: "call_123",
tool: "toolName",
output: { result: "..." },
state: "output-available",
});
响应工具审批请求。
await client.addToolApprovalResponse({
id: "approval_123",
approved: true,
});
创建 SSE 连接适配器。
import { fetchServerSentEvents } from "@tanstack/ai-client";
const adapter = fetchServerSentEvents("/api/chat", {
headers: {
Authorization: "Bearer token",
},
});
创建 HTTP 流连接适配器。
import { fetchHttpStream } from "@tanstack/ai-client";
const adapter = fetchHttpStream("/api/chat");
创建自定义连接适配器。
import { stream } from "@tanstack/ai-client";
const adapter = stream(async (messages, data, signal) => {
// Custom implementation
const response = await fetch("/api/chat", {
method: "POST",
body: JSON.stringify({ messages, ...data }),
signal,
});
return processStream(response);
});
创建带有适当类型推断的客户端工具的类型化数组。这消除了在定义工具数组时使用 as const 的需要,并能够进行适当的区分联合类型缩小。
import { clientTools } from "@tanstack/ai-client";
import { myTool1, myTool2 } from "./tools";
// Create client implementations
const tool1Client = myTool1.client((input) => {
// Implementation
return { result: "..." };
});
const tool2Client = myTool2.client((input) => {
// Implementation
return { result: "..." };
});
// Create typed tools array (no 'as const' needed!)
const tools = clientTools(tool1Client, tool2Client);
// Now when you use these tools in chat options:
const chatOptions = createChatClientOptions({
connection: fetchServerSentEvents("/api/chat"),
tools, // Fully typed with literal tool names
});
// In your component:
messages.forEach((message) => {
message.parts.forEach((part) => {
if (part.type === "tool-call" && part.name === "myTool1") {
// ✅ TypeScript knows part.name is literally "myTool1"
// ✅ part.input is typed from myTool1's input schema
// ✅ part.output is typed from myTool1's output schema
}
});
});
辅助函数,用于使用适当的类型推断创建类型化的聊天客户端选项。
import { createChatClientOptions, clientTools } from "@tanstack/ai-client";
const tools = clientTools(tool1, tool2);
const chatOptions = createChatClientOptions({
connection: fetchServerSentEvents("/api/chat"),
tools,
});
// Use InferChatMessages to extract message types
type ChatMessages = InferChatMessages<typeof chatOptions>;
interface UIMessage {
id: string;
role: "user" | "assistant";
parts: MessagePart[];
createdAt?: Date;
}
type MessagePart = TextPart | ThinkingPart | ToolCallPart | ToolResultPart;
interface TextPart {
type: "text";
content: string;
}
interface ThinkingPart {
type: "thinking";
content: string;
}
思考部分代表模型的内部推理过程。它们通常以可折叠格式显示,并在出现响应文本时自动折叠。思考部分仅供 UI 使用,不会在后续请求中发送回模型。
注意:思考部分仅在使用支持推理/思考的模型时可用(例如,启用思考的 Anthropic Claude,启用推理的 OpenAI GPT-5)。
interface ToolCallPart {
type: "tool-call";
id: string;
name: string;
arguments: string; // JSON string (may be incomplete during streaming)
input?: any; // Parsed tool input (typed from tool's inputSchema)
state: ToolCallState;
approval?: ApprovalRequest;
output?: any; // Tool execution output (typed from tool's outputSchema)
}
在使用带有 clientTools() 和 createChatClientOptions() 的类型化工具时,input 和 output 字段将根据您的工具的 Zod 模式自动类型化,并且 name 成为一个区分联合,从而实现类型缩小。
interface ToolResultPart {
type: "tool-result";
id: string;
toolCallId: string;
tool: string;
output: any;
state: ToolResultState;
errorText?: string;
}
type ToolCallState =
| "pending"
| "approval-requested"
| "executing"
| "output-available"
| "output-error"
| "cancelled";
type ToolResultState =
| "pending"
| "executing"
| "output-available"
| "output-error";
使用块策略配置流处理
import { ImmediateStrategy, fetchServerSentEvents } from "@tanstack/ai-client";
const client = new ChatClient({
connection: fetchServerSentEvents("/api/chat"),
streamProcessor: {
chunkStrategy: new ImmediateStrategy(), // Emit every chunk
},
});