@tanstack/ai-react 0.27.2 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/chat-ui/create-ui.d.ts +37 -4
- package/dist/esm/chat-ui/create-ui.js +94 -4
- package/dist/esm/chat-ui/create-ui.js.map +1 -1
- package/dist/esm/create-chat-hook.d.ts +8 -4
- package/dist/esm/create-chat-hook.js.map +1 -1
- package/dist/esm/types.d.ts +19 -5
- package/dist/esm/ui.d.ts +1 -1
- package/dist/esm/use-chat.d.ts +3 -1
- package/dist/esm/use-chat.js +1 -0
- package/dist/esm/use-chat.js.map +1 -1
- package/package.json +4 -4
- package/src/chat-ui/create-ui.tsx +250 -8
- package/src/create-chat-hook.ts +13 -3
- package/src/types.ts +24 -2
- package/src/ui.ts +2 -0
- package/src/use-chat.ts +11 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentType, ReactNode } from 'react';
|
|
2
|
-
import { ChatUIData, ChatUIHasNamedInterrupts, ChatUIHasNamedTools, ChatUIInterrupt, ChatUIInterruptName, ChatUIInterruptOf, ChatUIInterruptsOf, ChatUIMessages, ChatUINamedInterruptId, ChatUIPartKey, ChatUIPartOf, ChatUISchemaOf, ChatUISelectedPart, ChatUIToolApproval, ChatUIToolName, ChatUIToolsOf } from '@tanstack/ai-client/ui';
|
|
3
|
-
import { MessagePart, QueuedMessage, ToolCallPart, ToolResultPart, UIMessage } from '@tanstack/ai-client';
|
|
2
|
+
import { ChatUIApprovalToolName, ChatUIData, ChatUIHasNamedInterrupts, ChatUIHasNamedSubagents, ChatUIHasNamedTools, ChatUIInterrupt, ChatUIInterruptName, ChatUIInterruptOf, ChatUIInterruptsOf, ChatUIMessages, ChatUINamedInterruptId, ChatUIPartKey, ChatUIPartOf, ChatUISchemaOf, ChatUISelectedPart, ChatUISubagentName, ChatUISubagentOf, ChatUISubagentOptions, ChatUIToolApproval, ChatUIToolName, ChatUIToolsOf } from '@tanstack/ai-client/ui';
|
|
3
|
+
import { MessagePart, QueuedMessage, SubagentHandle, SubagentHandles, ToolCallPart, ToolResultPart, UIMessage } from '@tanstack/ai-client';
|
|
4
4
|
import { UseChatReturn } from '../types.js';
|
|
5
5
|
import { ChatUIContexts } from './create-ui-contexts.js';
|
|
6
6
|
export type ChatUIHost<TOptions = unknown> = UseChatReturn<ChatUIToolsOf<TOptions>, ChatUISchemaOf<TOptions>, ChatUIInterruptsOf<TOptions>>;
|
|
@@ -11,6 +11,7 @@ export type LayoutProps<TOptions, TInput extends ComponentType<any> | undefined
|
|
|
11
11
|
Messages: ComponentType;
|
|
12
12
|
Interrupts: ComponentType;
|
|
13
13
|
Queue: ComponentType;
|
|
14
|
+
Subagents: ComponentType;
|
|
14
15
|
readonly __ui?: TOptions;
|
|
15
16
|
} & (TInput extends ComponentType<any> ? {
|
|
16
17
|
Input: ComponentType;
|
|
@@ -29,6 +30,26 @@ export type QueueProps<TOptions> = {
|
|
|
29
30
|
export type PartProps<TOptions, TKey extends ChatUIPartKey = ChatUIPartKey> = {
|
|
30
31
|
part: ChatUIPartOf<TOptions, TKey>;
|
|
31
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Widgets for one subagent card. Each entry replaces the enclosing entry of
|
|
35
|
+
* the same key: the root map at top level, the outer card's map when nested.
|
|
36
|
+
* It applies to this card and the children nested in it. An unset key keeps
|
|
37
|
+
* the enclosing entry. Tool names and tool props come from that agent's
|
|
38
|
+
* `tools`.
|
|
39
|
+
*/
|
|
40
|
+
export type SubagentPartsProps<TOptions, TName extends ChatUISubagentName<TOptions> = ChatUISubagentName<TOptions>> = {
|
|
41
|
+
partsComponents?: ChatUIPartsComponents<ChatUISubagentOptions<TOptions, TName>>;
|
|
42
|
+
toolsComponents?: {
|
|
43
|
+
[K in ChatUIToolName<ChatUISubagentOptions<TOptions, TName>>]?: ComponentType<ToolProps<ChatUISubagentOptions<TOptions, TName>, K>>;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
export type SubagentProps<TOptions, TName extends ChatUISubagentName<TOptions> = ChatUISubagentName<TOptions>> = {
|
|
47
|
+
subagent: [ChatUISubagentOf<TOptions, TName>] extends [never] ? SubagentHandle & {
|
|
48
|
+
name: TName;
|
|
49
|
+
} : SubagentHandles<ReadonlyArray<ChatUISubagentOf<TOptions, TName>>>;
|
|
50
|
+
Parts: ComponentType<SubagentPartsProps<TOptions, TName>>;
|
|
51
|
+
readonly __ui?: TOptions;
|
|
52
|
+
};
|
|
32
53
|
export type ToolProps<TOptions, TName extends ChatUIToolName<TOptions> = ChatUIToolName<TOptions>> = {
|
|
33
54
|
part: Extract<ToolCallPart<ChatUIToolsOf<TOptions>>, {
|
|
34
55
|
name: TName;
|
|
@@ -48,7 +69,7 @@ type GenericInterruptComponents<TOptions> = ChatUIHasNamedInterrupts<TOptions> e
|
|
|
48
69
|
fallback?: ComponentType<InterruptProps<TOptions>>;
|
|
49
70
|
};
|
|
50
71
|
type ToolApprovalMap<TOptions> = {
|
|
51
|
-
[K in
|
|
72
|
+
[K in ChatUIApprovalToolName<TOptions>]?: ComponentType<InterruptProps<TOptions, K & ChatUIInterruptName<TOptions>>>;
|
|
52
73
|
};
|
|
53
74
|
/** The chrome around the message list: `layout`, `message`, and `input`. */
|
|
54
75
|
export type ChatUIChromeComponents<TOptions, TInput extends ComponentType<InputProps<TOptions>> | undefined = ComponentType<InputProps<TOptions>>> = {
|
|
@@ -84,6 +105,14 @@ export type ChatUIComponents<TOptions, TInput extends ComponentType<InputProps<T
|
|
|
84
105
|
tools?: ToolApprovalMap<TOptions>;
|
|
85
106
|
generic?: GenericInterruptComponents<TOptions>;
|
|
86
107
|
};
|
|
108
|
+
}) & (ChatUIHasNamedSubagents<TOptions> extends true ? {
|
|
109
|
+
subagentsComponents: {
|
|
110
|
+
[K in ChatUISubagentName<TOptions>]: ComponentType<SubagentProps<TOptions, K>>;
|
|
111
|
+
};
|
|
112
|
+
} : {
|
|
113
|
+
subagentsComponents?: {
|
|
114
|
+
[K in ChatUISubagentName<TOptions>]?: ComponentType<SubagentProps<TOptions, K>>;
|
|
115
|
+
};
|
|
87
116
|
});
|
|
88
117
|
/** Scoped contexts, for widgets in other files or nested chat trees. */
|
|
89
118
|
export type ChatUIContextConfig = {
|
|
@@ -105,7 +134,7 @@ type PartMixins<TOptions> = {
|
|
|
105
134
|
type InterruptMixins<TOptions> = {
|
|
106
135
|
[K in ChatUINamedInterruptId<TOptions>]: BoundWidget;
|
|
107
136
|
} & {
|
|
108
|
-
[K in
|
|
137
|
+
[K in ChatUIApprovalToolName<TOptions>]?: BoundWidget;
|
|
109
138
|
} & {
|
|
110
139
|
fallback?: BoundWidget;
|
|
111
140
|
Render: BoundWidget;
|
|
@@ -147,6 +176,10 @@ export declare function createChatUI<const TOptions, TInput extends ComponentTyp
|
|
|
147
176
|
children?: (mixed: ChatUIInterrupt & InterruptMixins<TOptions>) => ReactNode;
|
|
148
177
|
}) => import("react/jsx-runtime").JSX.Element>;
|
|
149
178
|
Queue: () => import("react/jsx-runtime").JSX.Element | null;
|
|
179
|
+
Subagents: ({ children, }?: {
|
|
180
|
+
children?: (subagents: Array<SubagentHandle>) => ReactNode;
|
|
181
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
182
|
+
SubagentMessages: ({ partsComponents, toolsComponents, }: SubagentPartsProps<TOptions>) => import("react/jsx-runtime").JSX.Element;
|
|
150
183
|
useChatContext: () => ChatUIHost<TOptions>;
|
|
151
184
|
Input: TInput | undefined;
|
|
152
185
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defaultChatUIContexts } from "./create-ui-contexts.js";
|
|
2
|
-
import { createContext, memo, useContext } from "react";
|
|
2
|
+
import { createContext, memo, useContext, useMemo } from "react";
|
|
3
3
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
4
4
|
import { automaticPartsForMessage, collectInlineToolNames, resolveInterruptComponent, selectChatUI, selectMessageUI } from "@tanstack/ai-client/ui";
|
|
5
5
|
//#region src/chat-ui/create-ui.tsx
|
|
@@ -21,6 +21,12 @@ function readInterrupts(chat) {
|
|
|
21
21
|
function queueItemEqual(prev, next) {
|
|
22
22
|
return prev.item.id === next.item.id && prev.item.createdAt === next.item.createdAt && prev.item.content === next.item.content && prev.cancelQueued === next.cancelQueued;
|
|
23
23
|
}
|
|
24
|
+
function subagentListItemEqual(prev, next) {
|
|
25
|
+
return prev.handle.id === next.handle.id && prev.handle.stop === next.handle.stop && prev.status === next.status && prev.error === next.error;
|
|
26
|
+
}
|
|
27
|
+
function subagentMessagesEqual(prev, next) {
|
|
28
|
+
return prev.messages === next.messages;
|
|
29
|
+
}
|
|
24
30
|
function selectedPartPropsEqual(prev, next) {
|
|
25
31
|
if (prev.selected.key !== next.selected.key) return false;
|
|
26
32
|
if (prev.selected.part !== next.selected.part) return false;
|
|
@@ -31,6 +37,12 @@ function selectedPartPropsEqual(prev, next) {
|
|
|
31
37
|
function isSelectedPart(value) {
|
|
32
38
|
return "key" in value && "part" in value;
|
|
33
39
|
}
|
|
40
|
+
/** `base` with each set entry of `overrides`. An unset entry keeps `base`. */
|
|
41
|
+
function withWidgets(base, overrides) {
|
|
42
|
+
const out = { ...base };
|
|
43
|
+
for (const [key, component] of Object.entries(overrides ?? {})) if (component) out[key] = component;
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
34
46
|
function bindMap(map, bind) {
|
|
35
47
|
const out = {};
|
|
36
48
|
for (const [key, component] of Object.entries(map ?? {})) if (component) out[key] = bind(component);
|
|
@@ -47,7 +59,7 @@ function bindMap(map, bind) {
|
|
|
47
59
|
* when widgets live in other files or when nested chats need isolation.
|
|
48
60
|
*/
|
|
49
61
|
function createChatUI(options, config) {
|
|
50
|
-
const { context: contextOption, components, partsComponents: parts, toolsComponents: tools, interruptsComponents: interrupts } = config;
|
|
62
|
+
const { context: contextOption, components, partsComponents: parts, toolsComponents: tools, interruptsComponents: interrupts, subagentsComponents: subagentComponents } = config;
|
|
51
63
|
const { layout: Layout, message: MessageComponent, input: InputComponent, queue: QueueItemComponent } = components;
|
|
52
64
|
const { chatContext: chatContextOption, partContext: partContextOption, interruptContext: interruptContextOption } = contextOption ?? {};
|
|
53
65
|
const warn = createWarnOnce();
|
|
@@ -119,6 +131,7 @@ function createChatUI(options, config) {
|
|
|
119
131
|
Messages,
|
|
120
132
|
Interrupts,
|
|
121
133
|
Queue,
|
|
134
|
+
Subagents,
|
|
122
135
|
Input: InputComponent ?? MissingInput
|
|
123
136
|
};
|
|
124
137
|
function Chat({ chat }) {
|
|
@@ -157,6 +170,11 @@ function createChatUI(options, config) {
|
|
|
157
170
|
}, message.id)) });
|
|
158
171
|
}
|
|
159
172
|
const MessageRenderContext = createContext(null);
|
|
173
|
+
const SubagentRenderContext = createContext(null);
|
|
174
|
+
const WidgetsContext = createContext({
|
|
175
|
+
parts,
|
|
176
|
+
tools: tools ?? {}
|
|
177
|
+
});
|
|
160
178
|
function Parts() {
|
|
161
179
|
const scope = useContext(MessageRenderContext);
|
|
162
180
|
if (!scope) throw new Error("`Parts` must be rendered by a `message` component.");
|
|
@@ -201,9 +219,10 @@ function createChatUI(options, config) {
|
|
|
201
219
|
return /* @__PURE__ */ jsx(Fragment, { children: automaticPartsForMessage(selected).map((part, index) => /* @__PURE__ */ jsx(SelectedPartView, { selected: part }, `${message.id}-${index}`)) });
|
|
202
220
|
});
|
|
203
221
|
const SelectedPartInner = memo(function SelectedPartInner({ selected }) {
|
|
222
|
+
const widgets = useContext(WidgetsContext);
|
|
204
223
|
if (selected.key === "toolCall") {
|
|
205
224
|
const name = selected.part.name;
|
|
206
|
-
const Tool = tools
|
|
225
|
+
const Tool = widgets.tools[name];
|
|
207
226
|
if (!Tool) {
|
|
208
227
|
warn(`tool:${name}`, `[tanstack-ai-ui] Missing tools.${name} component`);
|
|
209
228
|
return null;
|
|
@@ -214,7 +233,19 @@ function createChatUI(options, config) {
|
|
|
214
233
|
interrupt: selected.interrupt
|
|
215
234
|
});
|
|
216
235
|
}
|
|
217
|
-
|
|
236
|
+
if (selected.key === "subagent" && selected.part.type === "subagent") {
|
|
237
|
+
const name = selected.part.subagent.name;
|
|
238
|
+
const Subagent = subagentComponents?.[name];
|
|
239
|
+
if (!Subagent) throw new Error(`[tanstack-ai-ui] Missing subagentsComponents.${name}`);
|
|
240
|
+
return /* @__PURE__ */ jsx(SubagentRenderContext.Provider, {
|
|
241
|
+
value: { handle: selected.part.subagent },
|
|
242
|
+
children: /* @__PURE__ */ jsx(Subagent, {
|
|
243
|
+
Parts: SubagentMessages,
|
|
244
|
+
subagent: selected.part.subagent
|
|
245
|
+
})
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
const PartComponent = widgets.parts[selected.key] ?? widgets.parts.fallback;
|
|
218
249
|
if (!PartComponent) {
|
|
219
250
|
warn(`part:${selected.key}`, `[tanstack-ai-ui] Missing parts.${selected.key} component`);
|
|
220
251
|
return null;
|
|
@@ -275,6 +306,63 @@ function createChatUI(options, config) {
|
|
|
275
306
|
children: children ? children(mixInterrupt(interrupt)) : /* @__PURE__ */ jsx(InterruptInner, { interrupt })
|
|
276
307
|
});
|
|
277
308
|
});
|
|
309
|
+
function readSubagentMessages() {
|
|
310
|
+
const scoped = useContext(SubagentRenderContext);
|
|
311
|
+
const chat = useChatContext();
|
|
312
|
+
if (scoped?.listed) return (chat.subagents.find((item) => item.id === scoped.handle.id) ?? scoped.handle).messages;
|
|
313
|
+
if (scoped) return scoped.handle.messages;
|
|
314
|
+
const selected = useContext(PartContext);
|
|
315
|
+
if (selected?.key === "subagent" && selected.part.type === "subagent") return selected.part.subagent.messages;
|
|
316
|
+
throw new Error("`Parts` must be rendered by a subagent component or `Subagents` item.");
|
|
317
|
+
}
|
|
318
|
+
const SubagentMessagesBody = memo(function SubagentMessagesBody({ messages }) {
|
|
319
|
+
const interrupts = readInterrupts(useChatContext());
|
|
320
|
+
return /* @__PURE__ */ jsx(Fragment, { children: messages.map((message) => /* @__PURE__ */ jsx(AutomaticParts, {
|
|
321
|
+
inlineToolNames,
|
|
322
|
+
interrupts,
|
|
323
|
+
message
|
|
324
|
+
}, message.id)) });
|
|
325
|
+
}, subagentMessagesEqual);
|
|
326
|
+
function SubagentMessages({ partsComponents, toolsComponents }) {
|
|
327
|
+
const messages = readSubagentMessages();
|
|
328
|
+
const outer = useContext(WidgetsContext);
|
|
329
|
+
const widgets = useMemo(() => partsComponents || toolsComponents ? {
|
|
330
|
+
parts: withWidgets(outer.parts, partsComponents),
|
|
331
|
+
tools: withWidgets(outer.tools, toolsComponents)
|
|
332
|
+
} : outer, [
|
|
333
|
+
outer,
|
|
334
|
+
partsComponents,
|
|
335
|
+
toolsComponents
|
|
336
|
+
]);
|
|
337
|
+
return /* @__PURE__ */ jsx(WidgetsContext.Provider, {
|
|
338
|
+
value: widgets,
|
|
339
|
+
children: /* @__PURE__ */ jsx(SubagentMessagesBody, { messages })
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
const SubagentListItem = memo(function SubagentListItem({ handle }) {
|
|
343
|
+
const Subagent = subagentComponents?.[handle.name];
|
|
344
|
+
if (!Subagent) throw new Error(`[tanstack-ai-ui] Missing subagentsComponents.${handle.name}`);
|
|
345
|
+
return /* @__PURE__ */ jsx(SubagentRenderContext.Provider, {
|
|
346
|
+
value: {
|
|
347
|
+
handle,
|
|
348
|
+
listed: true
|
|
349
|
+
},
|
|
350
|
+
children: /* @__PURE__ */ jsx(Subagent, {
|
|
351
|
+
Parts: SubagentMessages,
|
|
352
|
+
subagent: handle
|
|
353
|
+
})
|
|
354
|
+
});
|
|
355
|
+
}, subagentListItemEqual);
|
|
356
|
+
function Subagents({ children } = {}) {
|
|
357
|
+
const live = useChatContext().subagents;
|
|
358
|
+
if (children) return /* @__PURE__ */ jsx(Fragment, { children: children(live) });
|
|
359
|
+
if (live.length === 0) return null;
|
|
360
|
+
return /* @__PURE__ */ jsx(Fragment, { children: live.map((handle) => /* @__PURE__ */ jsx(SubagentListItem, {
|
|
361
|
+
handle,
|
|
362
|
+
status: handle.status,
|
|
363
|
+
error: handle.error
|
|
364
|
+
}, handle.id)) });
|
|
365
|
+
}
|
|
278
366
|
return {
|
|
279
367
|
Chat,
|
|
280
368
|
Provider,
|
|
@@ -284,6 +372,8 @@ function createChatUI(options, config) {
|
|
|
284
372
|
Interrupts,
|
|
285
373
|
Interrupt,
|
|
286
374
|
Queue,
|
|
375
|
+
Subagents,
|
|
376
|
+
SubagentMessages,
|
|
287
377
|
useChatContext,
|
|
288
378
|
Input: InputComponent
|
|
289
379
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-ui.js","names":[],"sources":["../../../src/chat-ui/create-ui.tsx"],"sourcesContent":["import { createContext, memo, useContext } from 'react'\nimport type { ComponentProps, ComponentType, Context, ReactNode } from 'react'\nimport {\n automaticPartsForMessage,\n collectInlineToolNames,\n resolveInterruptComponent,\n selectChatUI,\n selectMessageUI,\n} from '@tanstack/ai-client/ui'\nimport type {\n ChatUIData,\n ChatUIHasNamedInterrupts,\n ChatUIHasNamedTools,\n ChatUIInterrupt,\n ChatUIInterruptName,\n ChatUIInterruptOf,\n ChatUIInterruptsOf,\n ChatUIMessages,\n ChatUINamedInterruptId,\n ChatUIPartKey,\n ChatUIPartOf,\n ChatUISchemaOf,\n ChatUISelectedPart,\n ChatUISelectedPartOf,\n ChatUIToolApproval,\n ChatUIToolName,\n ChatUIToolsOf,\n} from '@tanstack/ai-client/ui'\nimport type {\n MessagePart,\n QueuedMessage,\n ToolCallPart,\n ToolResultPart,\n UIMessage,\n} from '@tanstack/ai-client'\nimport type { UseChatReturn } from '../types'\nimport { defaultChatUIContexts } from './create-ui-contexts'\nimport type { ChatUIContexts } from './create-ui-contexts'\n\nexport type ChatUIHost<TOptions = unknown> = UseChatReturn<\n ChatUIToolsOf<TOptions>,\n ChatUISchemaOf<TOptions>,\n ChatUIInterruptsOf<TOptions>\n>\n\nexport type ChatUIQueueItem = QueuedMessage & {\n cancelQueued: () => void\n}\n\nexport type LayoutProps<\n TOptions,\n TInput extends ComponentType<any> | undefined = ComponentType<\n InputProps<TOptions>\n >,\n> = {\n Messages: ComponentType\n Interrupts: ComponentType\n Queue: ComponentType\n readonly __ui?: TOptions\n} & (TInput extends ComponentType<any> ? { Input: ComponentType } : {})\n\nexport type MessageProps<TOptions> = {\n message: UIMessage<ChatUIToolsOf<TOptions>, ChatUIData<TOptions>>\n Parts: ComponentType\n}\n\nexport type InputProps<TOptions> = {\n readonly __ui?: TOptions\n}\n\nexport type QueueProps<TOptions> = {\n item: ChatUIQueueItem\n readonly __ui?: TOptions\n}\n\nexport type PartProps<TOptions, TKey extends ChatUIPartKey = ChatUIPartKey> = {\n part: ChatUIPartOf<TOptions, TKey>\n}\n\nexport type ToolProps<\n TOptions,\n TName extends ChatUIToolName<TOptions> = ChatUIToolName<TOptions>,\n> = {\n part: Extract<ToolCallPart<ChatUIToolsOf<TOptions>>, { name: TName }>\n result?: ToolResultPart\n interrupt?: ChatUIToolApproval<TOptions, TName>\n}\n\nexport type InterruptProps<\n TOptions,\n TName extends ChatUIInterruptName<TOptions> = never,\n> = {\n interrupt: ChatUIInterruptOf<TOptions, TName>\n readonly __ui?: TOptions\n}\n\ntype GenericInterruptComponents<TOptions> =\n ChatUIHasNamedInterrupts<TOptions> extends true\n ? {\n [K in ChatUINamedInterruptId<TOptions>]: ComponentType<\n InterruptProps<TOptions, K & ChatUIInterruptName<TOptions>>\n >\n } & {\n fallback?: ComponentType<InterruptProps<TOptions>>\n }\n : {\n fallback?: ComponentType<InterruptProps<TOptions>>\n }\n\ntype ToolApprovalMap<TOptions> = {\n [K in ChatUIToolName<TOptions>]?: ComponentType<\n InterruptProps<TOptions, K & ChatUIInterruptName<TOptions>>\n >\n}\n\n/** The chrome around the message list: `layout`, `message`, and `input`. */\nexport type ChatUIChromeComponents<\n TOptions,\n TInput extends ComponentType<InputProps<TOptions>> | undefined =\n ComponentType<InputProps<TOptions>>,\n> = {\n layout: ComponentType<LayoutProps<TOptions, TInput>>\n message: ComponentType<MessageProps<TOptions>>\n input?: TInput\n queue?: ComponentType<QueueProps<TOptions>>\n}\n\nexport type ChatUIPartsComponents<TOptions> = {\n [K in ChatUIPartKey]?: ComponentType<PartProps<TOptions, K>>\n} & {\n fallback?: ComponentType<PartProps<TOptions>>\n}\n\nexport type ChatUIInterruptsComponents<TOptions> = {\n tools?: ToolApprovalMap<TOptions>\n generic: GenericInterruptComponents<TOptions>\n}\n\nexport type ChatUIComponents<\n TOptions,\n TInput extends ComponentType<InputProps<TOptions>> | undefined =\n ComponentType<InputProps<TOptions>>,\n> = {\n components: ChatUIChromeComponents<TOptions, TInput>\n partsComponents: ChatUIPartsComponents<TOptions>\n} & (ChatUIHasNamedTools<TOptions> extends true\n ? {\n toolsComponents: {\n [K in ChatUIToolName<TOptions>]: ComponentType<ToolProps<TOptions, K>>\n }\n }\n : {\n toolsComponents?: {\n [K in ChatUIToolName<TOptions>]?: ComponentType<ToolProps<TOptions, K>>\n }\n }) &\n (ChatUIHasNamedInterrupts<TOptions> extends true\n ? { interruptsComponents: ChatUIInterruptsComponents<TOptions> }\n : {\n interruptsComponents?: {\n tools?: ToolApprovalMap<TOptions>\n generic?: GenericInterruptComponents<TOptions>\n }\n })\n\n/** Scoped contexts, for widgets in other files or nested chat trees. */\nexport type ChatUIContextConfig = {\n chatContext?: ChatUIContexts['chatContext']\n partContext?: ChatUIContexts['partContext']\n interruptContext?: ChatUIContexts['interruptContext']\n}\n\nexport type ChatUIFactoryConfig<\n TOptions,\n TInput extends ComponentType<InputProps<TOptions>> | undefined =\n ComponentType<InputProps<TOptions>>,\n> = ChatUIComponents<TOptions, TInput> & {\n context?: ChatUIContextConfig\n}\n\ntype BoundWidget = ComponentType<Record<string, never>>\n\ntype PartMixins<TOptions> = {\n [K in ChatUIPartKey]?: BoundWidget\n} & {\n [K in ChatUIToolName<TOptions>]: BoundWidget\n} & {\n Render: BoundWidget\n}\n\ntype InterruptMixins<TOptions> = {\n [K in ChatUINamedInterruptId<TOptions>]: BoundWidget\n} & {\n [K in ChatUIToolName<TOptions>]?: BoundWidget\n} & {\n fallback?: BoundWidget\n Render: BoundWidget\n}\n\nfunction createWarnOnce() {\n const seen = new Set<string>()\n return (key: string, message: string) => {\n if (process.env.NODE_ENV === 'production') return\n if (seen.has(key)) return\n seen.add(key)\n console.warn(message)\n }\n}\n\nfunction readMessages<TOptions>(chat: ChatUIHost<TOptions>) {\n return chat.messages as ChatUIMessages<TOptions>\n}\n\nfunction readInterrupts<TOptions>(chat: ChatUIHost<TOptions>) {\n return chat.interrupts ?? []\n}\n\nfunction queueItemEqual(\n prev: { item: QueuedMessage; cancelQueued: (id: string) => void },\n next: { item: QueuedMessage; cancelQueued: (id: string) => void },\n) {\n return (\n prev.item.id === next.item.id &&\n prev.item.createdAt === next.item.createdAt &&\n prev.item.content === next.item.content &&\n prev.cancelQueued === next.cancelQueued\n )\n}\n\nfunction selectedPartPropsEqual(\n prev: { selected: ChatUISelectedPart },\n next: { selected: ChatUISelectedPart },\n) {\n if (prev.selected.key !== next.selected.key) return false\n if (prev.selected.part !== next.selected.part) return false\n if (prev.selected.key === 'toolCall' && next.selected.key === 'toolCall') {\n return (\n prev.selected.result === next.selected.result &&\n prev.selected.interrupt === next.selected.interrupt\n )\n }\n if (\n prev.selected.key === 'toolResult' &&\n next.selected.key === 'toolResult'\n ) {\n return prev.selected.matched === next.selected.matched\n }\n return true\n}\n\nfunction isSelectedPart(\n value: MessagePart | ChatUISelectedPart,\n): value is ChatUISelectedPart {\n return 'key' in value && 'part' in value\n}\n\nfunction bindMap(\n map: Record<string, ComponentType<any> | undefined> | undefined,\n bind: (component: ComponentType<any>) => BoundWidget,\n) {\n const out: Record<string, BoundWidget> = {}\n for (const [key, component] of Object.entries(map ?? {})) {\n if (component) out[key] = bind(component)\n }\n return out\n}\n\n/**\n * Bind chat options and UI widgets once at module scope. This matches Form\n * `createFormHook` and Table `createTableHook`: widgets register here, mix\n * onto Part / Interrupt / the UI kit, and automatic dispatch still walks the\n * message list.\n *\n * `chatOptions` is type-only at runtime. Pass optional `chatContext`,\n * `partContext`, and `interruptContext` from {@link createChatHookContexts}\n * when widgets live in other files or when nested chats need isolation.\n */\nexport function createChatUI<\n const TOptions,\n TInput extends ComponentType<any> | undefined =\n | ComponentType<InputProps<NoInfer<TOptions>>>\n | undefined,\n>(options: TOptions, config: ChatUIFactoryConfig<NoInfer<TOptions>, TInput>) {\n void options\n const {\n context: contextOption,\n components,\n partsComponents: parts,\n toolsComponents: tools,\n interruptsComponents: interrupts,\n } = config as ChatUIFactoryConfig<TOptions, TInput> & {\n toolsComponents?: Record<string, ComponentType<any> | undefined>\n interruptsComponents?: {\n tools?: Record<string, ComponentType<any> | undefined>\n generic?: Record<string, ComponentType<any> | undefined>\n }\n }\n const {\n layout: Layout,\n message: MessageComponent,\n input: InputComponent,\n queue: QueueItemComponent,\n } = components\n const {\n chatContext: chatContextOption,\n partContext: partContextOption,\n interruptContext: interruptContextOption,\n } = contextOption ?? {}\n const warn = createWarnOnce()\n const ChatContext = (chatContextOption ??\n defaultChatUIContexts.chatContext) as Context<ChatUIHost<TOptions> | null>\n const PartContext = (partContextOption ??\n defaultChatUIContexts.partContext) as Context<ChatUISelectedPart | null>\n const InterruptContext = (interruptContextOption ??\n defaultChatUIContexts.interruptContext) as Context<ChatUIInterrupt | null>\n const inlineToolNames = collectInlineToolNames(\n interrupts?.tools as Record<string, unknown> | undefined,\n Object.keys(tools ?? {}),\n )\n\n function useChatContext() {\n const chat = useContext(ChatContext)\n if (!chat) {\n throw new Error(\n '`useChatContext` must be used within `UI.Provider` or `UI.Chat`.',\n )\n }\n return chat\n }\n\n function usePartContext<TKey extends ChatUIPartKey = ChatUIPartKey>() {\n const selected = useContext(PartContext)\n if (!selected) {\n throw new Error(\n '`usePartContext` must be used within `UI.Part` or an automatic part.',\n )\n }\n return selected as ChatUISelectedPartOf<TOptions, TKey>\n }\n\n function useInterruptContext<\n TName extends ChatUIInterruptName<TOptions> = ChatUIInterruptName<TOptions>,\n >() {\n const interrupt = useContext(InterruptContext)\n if (!interrupt) {\n throw new Error(\n '`useInterruptContext` must be used within `UI.Interrupt`.',\n )\n }\n return interrupt as ChatUIInterruptOf<TOptions, TName>\n }\n\n function bindPart(Component: ComponentType<PartProps<TOptions>>) {\n return function BoundPart() {\n const selected = usePartContext()\n return <Component part={selected.part as PartProps<TOptions>['part']} />\n }\n }\n\n function bindTool(Component: ComponentType<ToolProps<TOptions>>) {\n return function BoundTool() {\n const selected = usePartContext()\n if (selected.key !== 'toolCall') return null\n return (\n <Component\n part={selected.part as ToolProps<TOptions>['part']}\n result={selected.result}\n interrupt={selected.interrupt as ToolProps<TOptions>['interrupt']}\n />\n )\n }\n }\n\n function bindInterrupt(Component: ComponentType<InterruptProps<TOptions>>) {\n return function BoundInterrupt() {\n const interrupt = useInterruptContext()\n return (\n <Component\n interrupt={interrupt as InterruptProps<TOptions>['interrupt']}\n />\n )\n }\n }\n\n const partMixins = bindMap(\n parts as Record<string, ComponentType<any> | undefined>,\n bindPart,\n )\n const toolMixins = bindMap(\n tools as Record<string, ComponentType<any> | undefined>,\n bindTool,\n )\n const interruptMixins = {\n ...bindMap(\n interrupts?.generic as\n | Record<string, ComponentType<any> | undefined>\n | undefined,\n bindInterrupt,\n ),\n ...bindMap(\n interrupts?.tools as\n | Record<string, ComponentType<any> | undefined>\n | undefined,\n bindInterrupt,\n ),\n }\n\n function mixPart(selected: ChatUISelectedPart) {\n return Object.assign({}, selected, partMixins, toolMixins, {\n Render: BoundRender,\n }) as ChatUISelectedPart & PartMixins<TOptions>\n }\n\n function mixInterrupt(interrupt: ChatUIInterrupt) {\n return Object.assign({}, interrupt, interruptMixins, {\n Render: BoundInterruptRender,\n }) as ChatUIInterrupt & InterruptMixins<TOptions>\n }\n\n function Provider({\n chat,\n children,\n }: {\n chat: ChatUIHost<TOptions>\n children?: ReactNode\n }) {\n return <ChatContext.Provider value={chat}>{children}</ChatContext.Provider>\n }\n\n // Backstop for when the conditional `Input` type cannot be inferred (see the\n // `input` note in docs/ui/react.md). The type hides `Input` when no `input`\n // is registered, but inference degrades on some config shapes, so always\n // supply a component: warn once rather than crash on an undefined element.\n function MissingInput() {\n warn(\n 'input',\n '[tanstack-ai-ui] Rendered <Input /> but no `input` component is registered.',\n )\n return null\n }\n\n // `Messages`, `Interrupts`, `Queue` and `InputComponent` are declared once\n // per factory, so these props are stable for the lifetime of the kit.\n const LayoutSlots = {\n Messages: Messages as ComponentType,\n Interrupts: Interrupts as ComponentType,\n Queue: Queue as ComponentType,\n Input: (InputComponent ?? MissingInput) as ComponentType,\n }\n\n function Chat({ chat }: { chat: ChatUIHost<TOptions> }) {\n return (\n <Provider chat={chat}>\n <Layout {...(LayoutSlots as ComponentProps<ComponentType<any>>)} />\n </Provider>\n )\n }\n\n function Queue() {\n const chat = useChatContext()\n if (!QueueItemComponent) return null\n const items = chat.queue\n return (\n <>\n {items.map((item) => (\n <QueueItemView\n key={item.id}\n cancelQueued={chat.cancelQueued}\n item={item}\n />\n ))}\n </>\n )\n }\n\n const QueueItemView = memo(function QueueItemView({\n item,\n cancelQueued,\n }: {\n item: QueuedMessage\n cancelQueued: (id: string) => void\n }) {\n if (!QueueItemComponent) return null\n return (\n <QueueItemComponent\n item={{\n ...item,\n cancelQueued: () => {\n cancelQueued(item.id)\n },\n }}\n />\n )\n }, queueItemEqual)\n\n function Messages({\n children,\n }: {\n children?: (messages: ChatUIMessages<TOptions>) => ReactNode\n } = {}) {\n const chat = useChatContext()\n const messages = readMessages(chat)\n const interrupts = readInterrupts(chat)\n if (children) return <>{children(messages)}</>\n return (\n <>\n {messages.map((message) => (\n <MessageView\n key={message.id}\n inlineToolNames={inlineToolNames}\n interrupts={interrupts}\n message={message}\n />\n ))}\n </>\n )\n }\n\n // Scoped to one message render. `Parts` reads it instead of closing over the\n // message, which is what keeps its identity constant across re-renders — a\n // fresh component per render would remount every part on each stream chunk.\n type MessageRenderValue = {\n message: ChatUIMessages<TOptions>[number]\n interrupts: ReadonlyArray<ChatUIInterrupt>\n inlineToolNames: ReadonlyArray<string>\n }\n const MessageRenderContext = createContext<MessageRenderValue | null>(null)\n\n function Parts() {\n const scope = useContext(MessageRenderContext)\n if (!scope) {\n throw new Error('`Parts` must be rendered by a `message` component.')\n }\n return (\n <AutomaticParts\n inlineToolNames={scope.inlineToolNames}\n interrupts={scope.interrupts}\n message={scope.message}\n />\n )\n }\n\n const MessageView = memo(function MessageView({\n message,\n interrupts,\n inlineToolNames: names,\n children,\n }: {\n message: ChatUIMessages<TOptions>[number]\n interrupts: ReadonlyArray<ChatUIInterrupt>\n inlineToolNames: ReadonlyArray<string>\n children?: (parts: Array<ChatUISelectedPart>) => ReactNode\n }) {\n const selected = selectMessageUI(message, {\n interrupts,\n inlineToolNames: names,\n })\n if (children) return <>{children(selected.parts)}</>\n return (\n <MessageRenderContext.Provider\n value={{ message, interrupts, inlineToolNames: names }}\n >\n <MessageComponent message={message} Parts={Parts} />\n </MessageRenderContext.Provider>\n )\n })\n\n function Message({\n message,\n children,\n }: {\n message: ChatUIMessages<TOptions>[number]\n children?: (parts: Array<ChatUISelectedPart>) => ReactNode\n }) {\n const chat = useChatContext()\n return (\n <MessageView\n children={children}\n inlineToolNames={inlineToolNames}\n interrupts={readInterrupts(chat)}\n message={message}\n />\n )\n }\n\n const AutomaticParts = memo(function AutomaticParts({\n message,\n interrupts,\n inlineToolNames: names,\n }: {\n message: ChatUIMessages<TOptions>[number]\n interrupts: ReadonlyArray<ChatUIInterrupt>\n inlineToolNames: ReadonlyArray<string>\n }) {\n const selected = selectMessageUI(message, {\n interrupts,\n inlineToolNames: names,\n })\n return (\n <>\n {automaticPartsForMessage(selected).map((part, index) => (\n <SelectedPartView key={`${message.id}-${index}`} selected={part} />\n ))}\n </>\n )\n })\n\n const SelectedPartInner = memo(function SelectedPartInner({\n selected,\n }: {\n selected: ChatUISelectedPart\n }) {\n if (selected.key === 'toolCall') {\n const name = selected.part.name\n const Tool = tools?.[name as ChatUIToolName<TOptions>] as\n | ComponentType<ToolProps<TOptions>>\n | undefined\n if (!Tool) {\n warn(`tool:${name}`, `[tanstack-ai-ui] Missing tools.${name} component`)\n return null\n }\n return (\n <Tool\n part={selected.part as ToolProps<TOptions>['part']}\n result={selected.result}\n interrupt={selected.interrupt as ToolProps<TOptions>['interrupt']}\n />\n )\n }\n\n const PartComponent = (parts[selected.key] ?? parts.fallback) as\n | ComponentType<PartProps<TOptions>>\n | undefined\n if (!PartComponent) {\n warn(\n `part:${selected.key}`,\n `[tanstack-ai-ui] Missing parts.${selected.key} component`,\n )\n return null\n }\n return <PartComponent part={selected.part as PartProps<TOptions>['part']} />\n }, selectedPartPropsEqual)\n\n const SelectedPartView = memo(function SelectedPartView({\n selected,\n }: {\n selected: ChatUISelectedPart\n }) {\n return (\n <PartContext.Provider value={selected}>\n <SelectedPartInner selected={selected} />\n </PartContext.Provider>\n )\n })\n\n function BoundRender() {\n const selected = usePartContext()\n return <SelectedPartInner selected={selected} />\n }\n\n function Part({\n part,\n children,\n }: {\n part: MessagePart | ChatUISelectedPart\n children?: (mixed: ChatUISelectedPart & PartMixins<TOptions>) => ReactNode\n }) {\n const chat = useChatContext()\n const selected = isSelectedPart(part)\n ? part\n : selectMessageUI(\n { id: 'part', role: 'assistant', parts: [part] },\n { interrupts: readInterrupts(chat), inlineToolNames: [] },\n ).parts[0]\n if (!selected) return null\n return (\n <PartContext.Provider value={selected}>\n {children ? (\n children(mixPart(selected))\n ) : (\n <SelectedPartInner selected={selected} />\n )}\n </PartContext.Provider>\n )\n }\n\n function Interrupts({\n children,\n }: {\n children?: (interrupts: ReadonlyArray<ChatUIInterrupt>) => ReactNode\n } = {}) {\n const chat = useChatContext()\n const selected = selectChatUI({\n messages: readMessages(chat),\n interrupts: readInterrupts(chat),\n inlineToolNames,\n })\n if (children) return <>{children(selected.interrupts)}</>\n return (\n <>\n {selected.interrupts.map((interrupt) => (\n <Interrupt key={interrupt.id} interrupt={interrupt} />\n ))}\n </>\n )\n }\n\n const InterruptInner = memo(function InterruptInner({\n interrupt,\n }: {\n interrupt: ChatUIInterrupt\n }) {\n const Component = resolveInterruptComponent(interrupt, interrupts) as\n | ComponentType<InterruptProps<TOptions>>\n | undefined\n if (!Component) {\n warn(\n `interrupt:${interrupt.id}`,\n `[tanstack-ai-ui] Missing interrupt component for ${interrupt.kind}`,\n )\n return null\n }\n return <Component interrupt={interrupt} />\n })\n\n function BoundInterruptRender() {\n const interrupt = useInterruptContext()\n return <InterruptInner interrupt={interrupt} />\n }\n\n const Interrupt = memo(function Interrupt({\n interrupt,\n children,\n }: {\n interrupt: ChatUIInterrupt\n children?: (mixed: ChatUIInterrupt & InterruptMixins<TOptions>) => ReactNode\n }) {\n return (\n <InterruptContext.Provider value={interrupt}>\n {children ? (\n children(mixInterrupt(interrupt))\n ) : (\n <InterruptInner interrupt={interrupt} />\n )}\n </InterruptContext.Provider>\n )\n })\n\n return {\n Chat,\n Provider,\n Messages,\n Message,\n Part,\n Interrupts,\n Interrupt,\n Queue,\n useChatContext,\n Input: InputComponent,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create-ui.js","names":[],"sources":["../../../src/chat-ui/create-ui.tsx"],"sourcesContent":["import { createContext, memo, useContext, useMemo } from 'react'\nimport type { ComponentProps, ComponentType, Context, ReactNode } from 'react'\nimport {\n automaticPartsForMessage,\n collectInlineToolNames,\n resolveInterruptComponent,\n selectChatUI,\n selectMessageUI,\n} from '@tanstack/ai-client/ui'\nimport type {\n ChatUIApprovalToolName,\n ChatUIData,\n ChatUIHasNamedInterrupts,\n ChatUIHasNamedSubagents,\n ChatUIHasNamedTools,\n ChatUIInterrupt,\n ChatUIInterruptName,\n ChatUIInterruptOf,\n ChatUIInterruptsOf,\n ChatUIMessages,\n ChatUINamedInterruptId,\n ChatUIPartKey,\n ChatUIPartOf,\n ChatUISchemaOf,\n ChatUISelectedPart,\n ChatUISelectedPartOf,\n ChatUISubagentName,\n ChatUISubagentOf,\n ChatUISubagentOptions,\n ChatUIToolApproval,\n ChatUIToolName,\n ChatUIToolsOf,\n} from '@tanstack/ai-client/ui'\nimport type {\n MessagePart,\n QueuedMessage,\n SubagentHandle,\n SubagentHandles,\n ToolCallPart,\n ToolResultPart,\n UIMessage,\n} from '@tanstack/ai-client'\nimport type { UseChatReturn } from '../types'\nimport { defaultChatUIContexts } from './create-ui-contexts'\nimport type { ChatUIContexts } from './create-ui-contexts'\n\nexport type ChatUIHost<TOptions = unknown> = UseChatReturn<\n ChatUIToolsOf<TOptions>,\n ChatUISchemaOf<TOptions>,\n ChatUIInterruptsOf<TOptions>\n>\n\nexport type ChatUIQueueItem = QueuedMessage & {\n cancelQueued: () => void\n}\n\nexport type LayoutProps<\n TOptions,\n TInput extends ComponentType<any> | undefined = ComponentType<\n InputProps<TOptions>\n >,\n> = {\n Messages: ComponentType\n Interrupts: ComponentType\n Queue: ComponentType\n Subagents: ComponentType\n readonly __ui?: TOptions\n} & (TInput extends ComponentType<any> ? { Input: ComponentType } : {})\n\nexport type MessageProps<TOptions> = {\n message: UIMessage<ChatUIToolsOf<TOptions>, ChatUIData<TOptions>>\n Parts: ComponentType\n}\n\nexport type InputProps<TOptions> = {\n readonly __ui?: TOptions\n}\n\nexport type QueueProps<TOptions> = {\n item: ChatUIQueueItem\n readonly __ui?: TOptions\n}\n\nexport type PartProps<TOptions, TKey extends ChatUIPartKey = ChatUIPartKey> = {\n part: ChatUIPartOf<TOptions, TKey>\n}\n\n/**\n * Widgets for one subagent card. Each entry replaces the enclosing entry of\n * the same key: the root map at top level, the outer card's map when nested.\n * It applies to this card and the children nested in it. An unset key keeps\n * the enclosing entry. Tool names and tool props come from that agent's\n * `tools`.\n */\nexport type SubagentPartsProps<\n TOptions,\n TName extends ChatUISubagentName<TOptions> = ChatUISubagentName<TOptions>,\n> = {\n partsComponents?: ChatUIPartsComponents<\n ChatUISubagentOptions<TOptions, TName>\n >\n toolsComponents?: {\n [K in ChatUIToolName<\n ChatUISubagentOptions<TOptions, TName>\n >]?: ComponentType<ToolProps<ChatUISubagentOptions<TOptions, TName>, K>>\n }\n}\n\nexport type SubagentProps<\n TOptions,\n TName extends ChatUISubagentName<TOptions> = ChatUISubagentName<TOptions>,\n> = {\n subagent: [ChatUISubagentOf<TOptions, TName>] extends [never]\n ? SubagentHandle & { name: TName }\n : SubagentHandles<ReadonlyArray<ChatUISubagentOf<TOptions, TName>>>\n Parts: ComponentType<SubagentPartsProps<TOptions, TName>>\n readonly __ui?: TOptions\n}\n\nexport type ToolProps<\n TOptions,\n TName extends ChatUIToolName<TOptions> = ChatUIToolName<TOptions>,\n> = {\n part: Extract<ToolCallPart<ChatUIToolsOf<TOptions>>, { name: TName }>\n result?: ToolResultPart\n interrupt?: ChatUIToolApproval<TOptions, TName>\n}\n\nexport type InterruptProps<\n TOptions,\n TName extends ChatUIInterruptName<TOptions> = never,\n> = {\n interrupt: ChatUIInterruptOf<TOptions, TName>\n readonly __ui?: TOptions\n}\n\ntype GenericInterruptComponents<TOptions> =\n ChatUIHasNamedInterrupts<TOptions> extends true\n ? {\n [K in ChatUINamedInterruptId<TOptions>]: ComponentType<\n InterruptProps<TOptions, K & ChatUIInterruptName<TOptions>>\n >\n } & {\n fallback?: ComponentType<InterruptProps<TOptions>>\n }\n : {\n fallback?: ComponentType<InterruptProps<TOptions>>\n }\n\ntype ToolApprovalMap<TOptions> = {\n [K in ChatUIApprovalToolName<TOptions>]?: ComponentType<\n InterruptProps<TOptions, K & ChatUIInterruptName<TOptions>>\n >\n}\n\n/** The chrome around the message list: `layout`, `message`, and `input`. */\nexport type ChatUIChromeComponents<\n TOptions,\n TInput extends ComponentType<InputProps<TOptions>> | undefined =\n ComponentType<InputProps<TOptions>>,\n> = {\n layout: ComponentType<LayoutProps<TOptions, TInput>>\n message: ComponentType<MessageProps<TOptions>>\n input?: TInput\n queue?: ComponentType<QueueProps<TOptions>>\n}\n\nexport type ChatUIPartsComponents<TOptions> = {\n [K in ChatUIPartKey]?: ComponentType<PartProps<TOptions, K>>\n} & {\n fallback?: ComponentType<PartProps<TOptions>>\n}\n\nexport type ChatUIInterruptsComponents<TOptions> = {\n tools?: ToolApprovalMap<TOptions>\n generic: GenericInterruptComponents<TOptions>\n}\n\nexport type ChatUIComponents<\n TOptions,\n TInput extends ComponentType<InputProps<TOptions>> | undefined =\n ComponentType<InputProps<TOptions>>,\n> = {\n components: ChatUIChromeComponents<TOptions, TInput>\n partsComponents: ChatUIPartsComponents<TOptions>\n} & (ChatUIHasNamedTools<TOptions> extends true\n ? {\n toolsComponents: {\n [K in ChatUIToolName<TOptions>]: ComponentType<ToolProps<TOptions, K>>\n }\n }\n : {\n toolsComponents?: {\n [K in ChatUIToolName<TOptions>]?: ComponentType<ToolProps<TOptions, K>>\n }\n }) &\n (ChatUIHasNamedInterrupts<TOptions> extends true\n ? { interruptsComponents: ChatUIInterruptsComponents<TOptions> }\n : {\n interruptsComponents?: {\n tools?: ToolApprovalMap<TOptions>\n generic?: GenericInterruptComponents<TOptions>\n }\n }) &\n (ChatUIHasNamedSubagents<TOptions> extends true\n ? {\n subagentsComponents: {\n [K in ChatUISubagentName<TOptions>]: ComponentType<\n SubagentProps<TOptions, K>\n >\n }\n }\n : {\n subagentsComponents?: {\n [K in ChatUISubagentName<TOptions>]?: ComponentType<\n SubagentProps<TOptions, K>\n >\n }\n })\n\n/** Scoped contexts, for widgets in other files or nested chat trees. */\nexport type ChatUIContextConfig = {\n chatContext?: ChatUIContexts['chatContext']\n partContext?: ChatUIContexts['partContext']\n interruptContext?: ChatUIContexts['interruptContext']\n}\n\nexport type ChatUIFactoryConfig<\n TOptions,\n TInput extends ComponentType<InputProps<TOptions>> | undefined =\n ComponentType<InputProps<TOptions>>,\n> = ChatUIComponents<TOptions, TInput> & {\n context?: ChatUIContextConfig\n}\n\ntype BoundWidget = ComponentType<Record<string, never>>\n\ntype PartMixins<TOptions> = {\n [K in ChatUIPartKey]?: BoundWidget\n} & {\n [K in ChatUIToolName<TOptions>]: BoundWidget\n} & {\n Render: BoundWidget\n}\n\ntype InterruptMixins<TOptions> = {\n [K in ChatUINamedInterruptId<TOptions>]: BoundWidget\n} & {\n [K in ChatUIApprovalToolName<TOptions>]?: BoundWidget\n} & {\n fallback?: BoundWidget\n Render: BoundWidget\n}\n\nfunction createWarnOnce() {\n const seen = new Set<string>()\n return (key: string, message: string) => {\n if (process.env.NODE_ENV === 'production') return\n if (seen.has(key)) return\n seen.add(key)\n console.warn(message)\n }\n}\n\nfunction readMessages<TOptions>(chat: ChatUIHost<TOptions>) {\n return chat.messages as ChatUIMessages<TOptions>\n}\n\nfunction readInterrupts<TOptions>(chat: ChatUIHost<TOptions>) {\n return chat.interrupts ?? []\n}\n\nfunction queueItemEqual(\n prev: { item: QueuedMessage; cancelQueued: (id: string) => void },\n next: { item: QueuedMessage; cancelQueued: (id: string) => void },\n) {\n return (\n prev.item.id === next.item.id &&\n prev.item.createdAt === next.item.createdAt &&\n prev.item.content === next.item.content &&\n prev.cancelQueued === next.cancelQueued\n )\n}\n\n// The handle is one live object that the client updates in place, so a row\n// gets its changing card fields as separate props. Messages are not one of\n// them: `SubagentMessages` reads them from the chat context, so new child\n// text shows without a row render.\ntype SubagentRowProps = {\n handle: SubagentHandle\n status: SubagentHandle['status']\n error: SubagentHandle['error']\n}\n\nfunction subagentListItemEqual(prev: SubagentRowProps, next: SubagentRowProps) {\n return (\n prev.handle.id === next.handle.id &&\n prev.handle.stop === next.handle.stop &&\n prev.status === next.status &&\n prev.error === next.error\n )\n}\n\nfunction subagentMessagesEqual(\n prev: { messages: SubagentHandle['messages'] },\n next: { messages: SubagentHandle['messages'] },\n) {\n return prev.messages === next.messages\n}\n\nfunction selectedPartPropsEqual(\n prev: { selected: ChatUISelectedPart },\n next: { selected: ChatUISelectedPart },\n) {\n if (prev.selected.key !== next.selected.key) return false\n if (prev.selected.part !== next.selected.part) return false\n if (prev.selected.key === 'toolCall' && next.selected.key === 'toolCall') {\n return (\n prev.selected.result === next.selected.result &&\n prev.selected.interrupt === next.selected.interrupt\n )\n }\n if (\n prev.selected.key === 'toolResult' &&\n next.selected.key === 'toolResult'\n ) {\n return prev.selected.matched === next.selected.matched\n }\n return true\n}\n\nfunction isSelectedPart(\n value: MessagePart | ChatUISelectedPart,\n): value is ChatUISelectedPart {\n return 'key' in value && 'part' in value\n}\n\n/** `base` with each set entry of `overrides`. An unset entry keeps `base`. */\nfunction withWidgets(\n base: Record<string, ComponentType<any> | undefined>,\n overrides: Record<string, ComponentType<any> | undefined> | undefined,\n) {\n const out = { ...base }\n for (const [key, component] of Object.entries(overrides ?? {})) {\n if (component) out[key] = component\n }\n return out\n}\n\nfunction bindMap(\n map: Record<string, ComponentType<any> | undefined> | undefined,\n bind: (component: ComponentType<any>) => BoundWidget,\n) {\n const out: Record<string, BoundWidget> = {}\n for (const [key, component] of Object.entries(map ?? {})) {\n if (component) out[key] = bind(component)\n }\n return out\n}\n\n/**\n * Bind chat options and UI widgets once at module scope. This matches Form\n * `createFormHook` and Table `createTableHook`: widgets register here, mix\n * onto Part / Interrupt / the UI kit, and automatic dispatch still walks the\n * message list.\n *\n * `chatOptions` is type-only at runtime. Pass optional `chatContext`,\n * `partContext`, and `interruptContext` from {@link createChatHookContexts}\n * when widgets live in other files or when nested chats need isolation.\n */\nexport function createChatUI<\n const TOptions,\n TInput extends ComponentType<any> | undefined =\n | ComponentType<InputProps<NoInfer<TOptions>>>\n | undefined,\n>(options: TOptions, config: ChatUIFactoryConfig<NoInfer<TOptions>, TInput>) {\n void options\n const {\n context: contextOption,\n components,\n partsComponents: parts,\n toolsComponents: tools,\n interruptsComponents: interrupts,\n subagentsComponents: subagentComponents,\n } = config as ChatUIFactoryConfig<TOptions, TInput> & {\n toolsComponents?: Record<string, ComponentType<any> | undefined>\n interruptsComponents?: {\n tools?: Record<string, ComponentType<any> | undefined>\n generic?: Record<string, ComponentType<any> | undefined>\n }\n subagentsComponents?: Record<string, ComponentType<any> | undefined>\n }\n const {\n layout: Layout,\n message: MessageComponent,\n input: InputComponent,\n queue: QueueItemComponent,\n } = components\n const {\n chatContext: chatContextOption,\n partContext: partContextOption,\n interruptContext: interruptContextOption,\n } = contextOption ?? {}\n const warn = createWarnOnce()\n const ChatContext = (chatContextOption ??\n defaultChatUIContexts.chatContext) as Context<ChatUIHost<TOptions> | null>\n const PartContext = (partContextOption ??\n defaultChatUIContexts.partContext) as Context<ChatUISelectedPart | null>\n const InterruptContext = (interruptContextOption ??\n defaultChatUIContexts.interruptContext) as Context<ChatUIInterrupt | null>\n const inlineToolNames = collectInlineToolNames(\n interrupts?.tools as Record<string, unknown> | undefined,\n Object.keys(tools ?? {}),\n )\n\n function useChatContext() {\n const chat = useContext(ChatContext)\n if (!chat) {\n throw new Error(\n '`useChatContext` must be used within `UI.Provider` or `UI.Chat`.',\n )\n }\n return chat\n }\n\n function usePartContext<TKey extends ChatUIPartKey = ChatUIPartKey>() {\n const selected = useContext(PartContext)\n if (!selected) {\n throw new Error(\n '`usePartContext` must be used within `UI.Part` or an automatic part.',\n )\n }\n return selected as ChatUISelectedPartOf<TOptions, TKey>\n }\n\n function useInterruptContext<\n TName extends ChatUIInterruptName<TOptions> = ChatUIInterruptName<TOptions>,\n >() {\n const interrupt = useContext(InterruptContext)\n if (!interrupt) {\n throw new Error(\n '`useInterruptContext` must be used within `UI.Interrupt`.',\n )\n }\n return interrupt as ChatUIInterruptOf<TOptions, TName>\n }\n\n function bindPart(Component: ComponentType<PartProps<TOptions>>) {\n return function BoundPart() {\n const selected = usePartContext()\n return <Component part={selected.part as PartProps<TOptions>['part']} />\n }\n }\n\n function bindTool(Component: ComponentType<ToolProps<TOptions>>) {\n return function BoundTool() {\n const selected = usePartContext()\n if (selected.key !== 'toolCall') return null\n return (\n <Component\n part={selected.part as ToolProps<TOptions>['part']}\n result={selected.result}\n interrupt={selected.interrupt as ToolProps<TOptions>['interrupt']}\n />\n )\n }\n }\n\n function bindInterrupt(Component: ComponentType<InterruptProps<TOptions>>) {\n return function BoundInterrupt() {\n const interrupt = useInterruptContext()\n return (\n <Component\n interrupt={interrupt as InterruptProps<TOptions>['interrupt']}\n />\n )\n }\n }\n\n const partMixins = bindMap(\n parts as Record<string, ComponentType<any> | undefined>,\n bindPart,\n )\n const toolMixins = bindMap(\n tools as Record<string, ComponentType<any> | undefined>,\n bindTool,\n )\n const interruptMixins = {\n ...bindMap(\n interrupts?.generic as\n | Record<string, ComponentType<any> | undefined>\n | undefined,\n bindInterrupt,\n ),\n ...bindMap(\n interrupts?.tools as\n | Record<string, ComponentType<any> | undefined>\n | undefined,\n bindInterrupt,\n ),\n }\n\n function mixPart(selected: ChatUISelectedPart) {\n return Object.assign({}, selected, partMixins, toolMixins, {\n Render: BoundRender,\n }) as ChatUISelectedPart & PartMixins<TOptions>\n }\n\n function mixInterrupt(interrupt: ChatUIInterrupt) {\n return Object.assign({}, interrupt, interruptMixins, {\n Render: BoundInterruptRender,\n }) as ChatUIInterrupt & InterruptMixins<TOptions>\n }\n\n function Provider({\n chat,\n children,\n }: {\n chat: ChatUIHost<TOptions>\n children?: ReactNode\n }) {\n return <ChatContext.Provider value={chat}>{children}</ChatContext.Provider>\n }\n\n // Backstop for when the conditional `Input` type cannot be inferred (see the\n // `input` note in docs/ui/react.md). The type hides `Input` when no `input`\n // is registered, but inference degrades on some config shapes, so always\n // supply a component: warn once rather than crash on an undefined element.\n function MissingInput() {\n warn(\n 'input',\n '[tanstack-ai-ui] Rendered <Input /> but no `input` component is registered.',\n )\n return null\n }\n\n // `Messages`, `Interrupts`, `Queue` and `InputComponent` are declared once\n // per factory, so these props are stable for the lifetime of the kit.\n const LayoutSlots = {\n Messages: Messages as ComponentType,\n Interrupts: Interrupts as ComponentType,\n Queue: Queue as ComponentType,\n Subagents: Subagents as ComponentType,\n Input: (InputComponent ?? MissingInput) as ComponentType,\n }\n\n function Chat({ chat }: { chat: ChatUIHost<TOptions> }) {\n return (\n <Provider chat={chat}>\n <Layout {...(LayoutSlots as ComponentProps<ComponentType<any>>)} />\n </Provider>\n )\n }\n\n function Queue() {\n const chat = useChatContext()\n if (!QueueItemComponent) return null\n const items = chat.queue\n return (\n <>\n {items.map((item) => (\n <QueueItemView\n key={item.id}\n cancelQueued={chat.cancelQueued}\n item={item}\n />\n ))}\n </>\n )\n }\n\n const QueueItemView = memo(function QueueItemView({\n item,\n cancelQueued,\n }: {\n item: QueuedMessage\n cancelQueued: (id: string) => void\n }) {\n if (!QueueItemComponent) return null\n return (\n <QueueItemComponent\n item={{\n ...item,\n cancelQueued: () => {\n cancelQueued(item.id)\n },\n }}\n />\n )\n }, queueItemEqual)\n\n function Messages({\n children,\n }: {\n children?: (messages: ChatUIMessages<TOptions>) => ReactNode\n } = {}) {\n const chat = useChatContext()\n const messages = readMessages(chat)\n const interrupts = readInterrupts(chat)\n if (children) return <>{children(messages)}</>\n return (\n <>\n {messages.map((message) => (\n <MessageView\n key={message.id}\n inlineToolNames={inlineToolNames}\n interrupts={interrupts}\n message={message}\n />\n ))}\n </>\n )\n }\n\n // Scoped to one message render. `Parts` reads it instead of closing over the\n // message, which is what keeps its identity constant across re-renders — a\n // fresh component per render would remount every part on each stream chunk.\n type MessageRenderValue = {\n message: ChatUIMessages<TOptions>[number]\n interrupts: ReadonlyArray<ChatUIInterrupt>\n inlineToolNames: ReadonlyArray<string>\n }\n const MessageRenderContext = createContext<MessageRenderValue | null>(null)\n const SubagentRenderContext = createContext<{\n handle: SubagentHandle\n /** A `Subagents` row. Its messages come from the live chat state. */\n listed?: true\n } | null>(null)\n // The widgets that dispatch uses. A subagent card's `Parts` can replace\n // entries for its subtree. Outside a card these are the factory maps.\n type WidgetMap = Record<string, ComponentType<any> | undefined>\n const rootWidgets: { parts: WidgetMap; tools: WidgetMap } = {\n parts: parts as WidgetMap,\n tools: tools ?? {},\n }\n const WidgetsContext = createContext(rootWidgets)\n\n function Parts() {\n const scope = useContext(MessageRenderContext)\n if (!scope) {\n throw new Error('`Parts` must be rendered by a `message` component.')\n }\n return (\n <AutomaticParts\n inlineToolNames={scope.inlineToolNames}\n interrupts={scope.interrupts}\n message={scope.message}\n />\n )\n }\n\n const MessageView = memo(function MessageView({\n message,\n interrupts,\n inlineToolNames: names,\n children,\n }: {\n message: ChatUIMessages<TOptions>[number]\n interrupts: ReadonlyArray<ChatUIInterrupt>\n inlineToolNames: ReadonlyArray<string>\n children?: (parts: Array<ChatUISelectedPart>) => ReactNode\n }) {\n const selected = selectMessageUI(message, {\n interrupts,\n inlineToolNames: names,\n })\n if (children) return <>{children(selected.parts)}</>\n return (\n <MessageRenderContext.Provider\n value={{ message, interrupts, inlineToolNames: names }}\n >\n <MessageComponent message={message} Parts={Parts} />\n </MessageRenderContext.Provider>\n )\n })\n\n function Message({\n message,\n children,\n }: {\n message: ChatUIMessages<TOptions>[number]\n children?: (parts: Array<ChatUISelectedPart>) => ReactNode\n }) {\n const chat = useChatContext()\n return (\n <MessageView\n children={children}\n inlineToolNames={inlineToolNames}\n interrupts={readInterrupts(chat)}\n message={message}\n />\n )\n }\n\n const AutomaticParts = memo(function AutomaticParts({\n message,\n interrupts,\n inlineToolNames: names,\n }: {\n message: UIMessage\n interrupts: ReadonlyArray<ChatUIInterrupt>\n inlineToolNames: ReadonlyArray<string>\n }) {\n const selected = selectMessageUI(message, {\n interrupts,\n inlineToolNames: names,\n })\n return (\n <>\n {automaticPartsForMessage(selected).map((part, index) => (\n <SelectedPartView key={`${message.id}-${index}`} selected={part} />\n ))}\n </>\n )\n })\n\n const SelectedPartInner = memo(function SelectedPartInner({\n selected,\n }: {\n selected: ChatUISelectedPart\n }) {\n const widgets = useContext(WidgetsContext)\n if (selected.key === 'toolCall') {\n const name = selected.part.name\n const Tool = widgets.tools[name] as\n | ComponentType<ToolProps<TOptions>>\n | undefined\n if (!Tool) {\n warn(`tool:${name}`, `[tanstack-ai-ui] Missing tools.${name} component`)\n return null\n }\n return (\n <Tool\n part={selected.part as ToolProps<TOptions>['part']}\n result={selected.result}\n interrupt={selected.interrupt as ToolProps<TOptions>['interrupt']}\n />\n )\n }\n\n if (selected.key === 'subagent' && selected.part.type === 'subagent') {\n const name = selected.part.subagent.name\n const Subagent = subagentComponents?.[name] as\n | ComponentType<SubagentProps<TOptions>>\n | undefined\n if (!Subagent) {\n throw new Error(`[tanstack-ai-ui] Missing subagentsComponents.${name}`)\n }\n return (\n <SubagentRenderContext.Provider\n value={{ handle: selected.part.subagent }}\n >\n <Subagent\n Parts={SubagentMessages}\n subagent={\n selected.part.subagent as SubagentProps<TOptions>['subagent']\n }\n />\n </SubagentRenderContext.Provider>\n )\n }\n\n const PartComponent = (widgets.parts[selected.key] ??\n widgets.parts.fallback) as ComponentType<PartProps<TOptions>> | undefined\n if (!PartComponent) {\n warn(\n `part:${selected.key}`,\n `[tanstack-ai-ui] Missing parts.${selected.key} component`,\n )\n return null\n }\n return <PartComponent part={selected.part as PartProps<TOptions>['part']} />\n }, selectedPartPropsEqual)\n\n const SelectedPartView = memo(function SelectedPartView({\n selected,\n }: {\n selected: ChatUISelectedPart\n }) {\n return (\n <PartContext.Provider value={selected}>\n <SelectedPartInner selected={selected} />\n </PartContext.Provider>\n )\n })\n\n function BoundRender() {\n const selected = usePartContext()\n return <SelectedPartInner selected={selected} />\n }\n\n function Part({\n part,\n children,\n }: {\n part: MessagePart | ChatUISelectedPart\n children?: (mixed: ChatUISelectedPart & PartMixins<TOptions>) => ReactNode\n }) {\n const chat = useChatContext()\n const selected = isSelectedPart(part)\n ? part\n : selectMessageUI(\n { id: 'part', role: 'assistant', parts: [part] },\n { interrupts: readInterrupts(chat), inlineToolNames: [] },\n ).parts[0]\n if (!selected) return null\n return (\n <PartContext.Provider value={selected}>\n {children ? (\n children(mixPart(selected))\n ) : (\n <SelectedPartInner selected={selected} />\n )}\n </PartContext.Provider>\n )\n }\n\n function Interrupts({\n children,\n }: {\n children?: (interrupts: ReadonlyArray<ChatUIInterrupt>) => ReactNode\n } = {}) {\n const chat = useChatContext()\n const selected = selectChatUI({\n messages: readMessages(chat),\n interrupts: readInterrupts(chat),\n inlineToolNames,\n })\n if (children) return <>{children(selected.interrupts)}</>\n return (\n <>\n {selected.interrupts.map((interrupt) => (\n <Interrupt key={interrupt.id} interrupt={interrupt} />\n ))}\n </>\n )\n }\n\n const InterruptInner = memo(function InterruptInner({\n interrupt,\n }: {\n interrupt: ChatUIInterrupt\n }) {\n const Component = resolveInterruptComponent(interrupt, interrupts) as\n | ComponentType<InterruptProps<TOptions>>\n | undefined\n if (!Component) {\n warn(\n `interrupt:${interrupt.id}`,\n `[tanstack-ai-ui] Missing interrupt component for ${interrupt.kind}`,\n )\n return null\n }\n return <Component interrupt={interrupt} />\n })\n\n function BoundInterruptRender() {\n const interrupt = useInterruptContext()\n return <InterruptInner interrupt={interrupt} />\n }\n\n const Interrupt = memo(function Interrupt({\n interrupt,\n children,\n }: {\n interrupt: ChatUIInterrupt\n children?: (mixed: ChatUIInterrupt & InterruptMixins<TOptions>) => ReactNode\n }) {\n return (\n <InterruptContext.Provider value={interrupt}>\n {children ? (\n children(mixInterrupt(interrupt))\n ) : (\n <InterruptInner interrupt={interrupt} />\n )}\n </InterruptContext.Provider>\n )\n })\n\n function readSubagentMessages() {\n const scoped = useContext(SubagentRenderContext)\n const chat = useChatContext()\n if (scoped?.listed) {\n const live = chat.subagents.find((item) => item.id === scoped.handle.id)\n return (live ?? scoped.handle).messages\n }\n if (scoped) return scoped.handle.messages\n const selected = useContext(PartContext)\n if (selected?.key === 'subagent' && selected.part.type === 'subagent') {\n return selected.part.subagent.messages\n }\n throw new Error(\n '`Parts` must be rendered by a subagent component or `Subagents` item.',\n )\n }\n\n const SubagentMessagesBody = memo(function SubagentMessagesBody({\n messages,\n }: {\n messages: SubagentHandle['messages']\n }) {\n const chat = useChatContext()\n const interrupts = readInterrupts(chat)\n return (\n <>\n {messages.map((message) => (\n <AutomaticParts\n key={message.id}\n inlineToolNames={inlineToolNames}\n interrupts={interrupts}\n message={message}\n />\n ))}\n </>\n )\n }, subagentMessagesEqual)\n\n function SubagentMessages({\n partsComponents,\n toolsComponents,\n }: SubagentPartsProps<TOptions>) {\n const messages = readSubagentMessages()\n const outer = useContext(WidgetsContext)\n const widgets = useMemo(\n () =>\n partsComponents || toolsComponents\n ? {\n parts: withWidgets(outer.parts, partsComponents),\n tools: withWidgets(outer.tools, toolsComponents),\n }\n : outer,\n [outer, partsComponents, toolsComponents],\n )\n // ponytail: root `<Interrupts />` still lists an approval for a tool call\n // inside a card, so it shows in both places. Hiding it needs `selectChatUI`\n // to collect tool-call ids from nested subagent messages (its `callIds` is\n // top-level only) plus the card tool names in `inlineToolNames`.\n return (\n <WidgetsContext.Provider value={widgets}>\n <SubagentMessagesBody messages={messages} />\n </WidgetsContext.Provider>\n )\n }\n\n const SubagentListItem = memo(function SubagentListItem({\n handle,\n }: SubagentRowProps) {\n const Subagent = subagentComponents?.[handle.name] as\n | ComponentType<SubagentProps<TOptions>>\n | undefined\n if (!Subagent) {\n throw new Error(\n `[tanstack-ai-ui] Missing subagentsComponents.${handle.name}`,\n )\n }\n return (\n <SubagentRenderContext.Provider value={{ handle, listed: true }}>\n <Subagent\n Parts={SubagentMessages}\n subagent={handle as SubagentProps<TOptions>['subagent']}\n />\n </SubagentRenderContext.Provider>\n )\n }, subagentListItemEqual)\n\n function Subagents({\n children,\n }: {\n children?: (subagents: Array<SubagentHandle>) => ReactNode\n } = {}) {\n const chat = useChatContext()\n const live = chat.subagents\n if (children) return <>{children(live)}</>\n if (live.length === 0) return null\n return (\n <>\n {live.map((handle) => (\n <SubagentListItem\n key={handle.id}\n handle={handle}\n status={handle.status}\n error={handle.error}\n />\n ))}\n </>\n )\n }\n\n return {\n Chat,\n Provider,\n Messages,\n Message,\n Part,\n Interrupts,\n Interrupt,\n Queue,\n Subagents,\n SubagentMessages,\n useChatContext,\n Input: InputComponent,\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { AnyClientTool, InterruptDefinition, SchemaInput } from '@tanstack/ai/client';
|
|
2
2
|
import { InferredClientContext } from '@tanstack/ai-client';
|
|
3
3
|
import { UseChatOptions } from './types.js';
|
|
4
|
-
type ChatHookOverrides<TTools extends ReadonlyArray<AnyClientTool>, TSchema extends SchemaInput | undefined, TContext, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any
|
|
4
|
+
type ChatHookOverrides<TTools extends ReadonlyArray<AnyClientTool>, TSchema extends SchemaInput | undefined, TContext, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>>, TSubagents extends ReadonlyArray<{
|
|
5
|
+
name: string;
|
|
6
|
+
}> | undefined> = {
|
|
5
7
|
threadId?: string;
|
|
6
8
|
live?: boolean;
|
|
7
9
|
forwardedProps?: Record<string, any>;
|
|
8
10
|
body?: Record<string, any>;
|
|
9
|
-
initialMessages?: UseChatOptions<TTools, TSchema, TContext, TInterrupts>['initialMessages'];
|
|
11
|
+
initialMessages?: UseChatOptions<TTools, TSchema, TContext, TInterrupts, TSubagents>['initialMessages'];
|
|
10
12
|
};
|
|
11
13
|
/**
|
|
12
14
|
* Bind chat options once at module scope. The returned `useChat` hook
|
|
@@ -29,7 +31,9 @@ type ChatHookOverrides<TTools extends ReadonlyArray<AnyClientTool>, TSchema exte
|
|
|
29
31
|
* }
|
|
30
32
|
* ```
|
|
31
33
|
*/
|
|
32
|
-
export declare function createChatHook<const TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []
|
|
33
|
-
|
|
34
|
+
export declare function createChatHook<const TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly [], const TSubagents extends ReadonlyArray<{
|
|
35
|
+
name: string;
|
|
36
|
+
}> | undefined = undefined>(options: UseChatOptions<TTools, TSchema, TContext, TInterrupts, TSubagents>): {
|
|
37
|
+
useChat: (overrides?: ChatHookOverrides<TTools, TSchema, TContext, TInterrupts, TSubagents>) => import('./types.js').UseChatReturn<TTools, TSchema, TInterrupts, TSubagents>;
|
|
34
38
|
};
|
|
35
39
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-chat-hook.js","names":[],"sources":["../../src/create-chat-hook.ts"],"sourcesContent":["import { useChat as useUnboundChat } from './use-chat'\nimport type {\n AnyClientTool,\n InterruptDefinition,\n SchemaInput,\n} from '@tanstack/ai/client'\nimport type { InferredClientContext } from '@tanstack/ai-client'\nimport type { UseChatOptions } from './types'\n\ntype ChatHookOverrides<\n TTools extends ReadonlyArray<AnyClientTool>,\n TSchema extends SchemaInput | undefined,\n TContext,\n TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>>,\n> = {\n threadId?: string\n live?: boolean\n forwardedProps?: Record<string, any>\n body?: Record<string, any>\n initialMessages?: UseChatOptions<\n TTools,\n TSchema,\n TContext,\n TInterrupts\n >['initialMessages']\n}\n\n/**\n * Bind chat options once at module scope. The returned `useChat` hook\n * creates a chat instance from those options.\n *\n * Pass per-call overrides for instance keys such as `threadId`,\n * `initialMessages`, `live`, and `forwardedProps`. Do not change `tools`,\n * `interrupts`, or `outputSchema` here. Those stay on the factory options.\n *\n * Rename the hook at the call site if you already import `useChat` from\n * `@tanstack/ai-react`: `const { useChat: useAppChat } = createChatHook(chatOptions)`.\n *\n * @example\n * ```tsx\n * const { useChat } = createChatHook(chatOptions)\n *\n * function Support() {\n * const chat = useChat({ threadId: 'support-1' })\n * return <UI.Chat chat={chat} />\n * }\n * ```\n */\nexport function createChatHook<\n const TTools extends ReadonlyArray<AnyClientTool> = any,\n TSchema extends SchemaInput | undefined = undefined,\n TContext = InferredClientContext<TTools>,\n const TInterrupts extends ReadonlyArray<\n InterruptDefinition<any, any, any, any>\n > = readonly [],\n>(options: UseChatOptions<TTools, TSchema, TContext, TInterrupts>) {\n function useChat(\n overrides?: ChatHookOverrides
|
|
1
|
+
{"version":3,"file":"create-chat-hook.js","names":[],"sources":["../../src/create-chat-hook.ts"],"sourcesContent":["import { useChat as useUnboundChat } from './use-chat'\nimport type {\n AnyClientTool,\n InterruptDefinition,\n SchemaInput,\n} from '@tanstack/ai/client'\nimport type { InferredClientContext } from '@tanstack/ai-client'\nimport type { UseChatOptions } from './types'\n\ntype ChatHookOverrides<\n TTools extends ReadonlyArray<AnyClientTool>,\n TSchema extends SchemaInput | undefined,\n TContext,\n TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>>,\n TSubagents extends ReadonlyArray<{ name: string }> | undefined,\n> = {\n threadId?: string\n live?: boolean\n forwardedProps?: Record<string, any>\n body?: Record<string, any>\n initialMessages?: UseChatOptions<\n TTools,\n TSchema,\n TContext,\n TInterrupts,\n TSubagents\n >['initialMessages']\n}\n\n/**\n * Bind chat options once at module scope. The returned `useChat` hook\n * creates a chat instance from those options.\n *\n * Pass per-call overrides for instance keys such as `threadId`,\n * `initialMessages`, `live`, and `forwardedProps`. Do not change `tools`,\n * `interrupts`, or `outputSchema` here. Those stay on the factory options.\n *\n * Rename the hook at the call site if you already import `useChat` from\n * `@tanstack/ai-react`: `const { useChat: useAppChat } = createChatHook(chatOptions)`.\n *\n * @example\n * ```tsx\n * const { useChat } = createChatHook(chatOptions)\n *\n * function Support() {\n * const chat = useChat({ threadId: 'support-1' })\n * return <UI.Chat chat={chat} />\n * }\n * ```\n */\nexport function createChatHook<\n const TTools extends ReadonlyArray<AnyClientTool> = any,\n TSchema extends SchemaInput | undefined = undefined,\n TContext = InferredClientContext<TTools>,\n const TInterrupts extends ReadonlyArray<\n InterruptDefinition<any, any, any, any>\n > = readonly [],\n const TSubagents extends ReadonlyArray<{ name: string }> | undefined =\n undefined,\n>(options: UseChatOptions<TTools, TSchema, TContext, TInterrupts, TSubagents>) {\n function useChat(\n overrides?: ChatHookOverrides<\n TTools,\n TSchema,\n TContext,\n TInterrupts,\n TSubagents\n >,\n ) {\n if (!overrides) {\n return useUnboundChat(options)\n }\n return useUnboundChat({ ...options, ...overrides })\n }\n\n return { useChat }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,eASd,SAA6E;CAC7E,SAAS,UACP,WAOA;EACA,IAAI,CAAC,WACH,OAAO,QAAe,OAAO;EAE/B,OAAO,QAAe;GAAE,GAAG;GAAS,GAAG;EAAU,CAAC;CACpD;CAEA,OAAO,EAAE,SAAA,UAAQ;AACnB"}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyClientTool, InterruptDefinition, InferSchemaType, ModelMessage, RunAgentResumeItem, SchemaInput } from '@tanstack/ai/client';
|
|
2
|
-
import { AIDevtoolsDisplayOptions, BoundInterrupts, ChatClientOptions, ChatClientState, ResolvableChatInterrupt, ChatInterruptState, ChatRequestBody, ChatResumeState, ClientContextOptionFromTools, ConnectionStatus, DistributedOmit, InferredClientContext, MultimodalContent, QueueConfig, QueueOption, QueueStrategy, QueuedMessage, SendMessageOptions, UIMessage, WhenBusy } from '@tanstack/ai-client';
|
|
2
|
+
import { AIDevtoolsDisplayOptions, BoundInterrupts, ChatClientOptions, ChatClientState, ResolvableChatInterrupt, ChatInterruptState, ChatRequestBody, ChatResumeState, ClientContextOptionFromTools, ConnectionStatus, DistributedOmit, InferredClientContext, MultimodalContent, QueueConfig, QueueOption, QueueStrategy, QueuedMessage, SendMessageOptions, UIMessage, WhenBusy, SubagentClientAgent, SubagentHandles } from '@tanstack/ai-client';
|
|
3
3
|
export type { ChatRequestBody, MultimodalContent, QueueConfig, QueuedMessage, QueueOption, QueueStrategy, SendMessageOptions, UIMessage, WhenBusy, };
|
|
4
4
|
/**
|
|
5
5
|
* Recursive partial — every property and every nested array element is optional.
|
|
@@ -35,7 +35,7 @@ export type DeepPartial<T> = T extends ReadonlyArray<infer U> ? Array<DeepPartia
|
|
|
35
35
|
* Note: Connection and body changes will recreate the ChatClient instance.
|
|
36
36
|
* To update these options, remount the component or use a key prop.
|
|
37
37
|
*/
|
|
38
|
-
export type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = DistributedOmit<ChatClientOptions<TTools, TContext, TInterrupts>, 'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStatusChange' | 'onSubscriptionChange' | 'onConnectionStatusChange' | 'onSessionGeneratingChange' | 'onQueueChange' | 'onResumeStateChange' | 'onRunIdChange' | 'context' | 'devtools'> & {
|
|
38
|
+
export type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly [], TSubagents extends ReadonlyArray<SubagentClientAgent> | undefined = undefined> = DistributedOmit<ChatClientOptions<TTools, TContext, TInterrupts>, 'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStatusChange' | 'onSubscriptionChange' | 'onConnectionStatusChange' | 'onSessionGeneratingChange' | 'onQueueChange' | 'onResumeStateChange' | 'onRunIdChange' | 'context' | 'devtools' | 'subagents'> & {
|
|
39
39
|
/** Display options for TanStack AI Devtools. */
|
|
40
40
|
devtools?: AIDevtoolsDisplayOptions;
|
|
41
41
|
/**
|
|
@@ -50,13 +50,19 @@ export type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TS
|
|
|
50
50
|
* against the schema passed to `chat({ outputSchema })` on the server route.
|
|
51
51
|
*/
|
|
52
52
|
outputSchema?: TSchema;
|
|
53
|
+
/**
|
|
54
|
+
* Agents from `defineAgent`. This types `messages` parts and `subagents`.
|
|
55
|
+
* The hook does not call `run` and does not send the agents to the server.
|
|
56
|
+
* Pass the same array you give to `chat({ subagents: { agents } })`.
|
|
57
|
+
*/
|
|
58
|
+
subagents?: TSubagents;
|
|
53
59
|
} & ClientContextOptionFromTools<TTools, TContext>;
|
|
54
60
|
/**
|
|
55
61
|
* Discriminated return shape: when `outputSchema` is supplied, the hook adds
|
|
56
62
|
* typed `partial` / `final` fields; when it is omitted (default), the return
|
|
57
63
|
* is unchanged.
|
|
58
64
|
*/
|
|
59
|
-
export type UseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = BaseUseChatReturn<TTools, TSchema extends SchemaInput ? InferSchemaType<TSchema> : unknown, TInterrupts> & (TSchema extends SchemaInput ? {
|
|
65
|
+
export type UseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly [], TSubagents extends ReadonlyArray<SubagentClientAgent> | undefined = undefined> = BaseUseChatReturn<TTools, TSchema extends SchemaInput ? InferSchemaType<TSchema> : unknown, TInterrupts, TSubagents> & (TSchema extends SchemaInput ? {
|
|
60
66
|
/**
|
|
61
67
|
* Live, progressively-parsed structured output. Updated from
|
|
62
68
|
* `TEXT_MESSAGE_CONTENT` deltas via `parsePartialJSON` while the stream
|
|
@@ -71,13 +77,21 @@ export type UseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TSc
|
|
|
71
77
|
*/
|
|
72
78
|
final: InferSchemaType<TSchema> | null;
|
|
73
79
|
} : Record<never, never>);
|
|
74
|
-
interface BaseUseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TData = unknown, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> {
|
|
80
|
+
interface BaseUseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TData = unknown, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly [], TSubagents extends ReadonlyArray<SubagentClientAgent> | undefined = undefined> {
|
|
75
81
|
/**
|
|
76
82
|
* Current messages in the conversation. When `outputSchema` is supplied,
|
|
77
83
|
* `messages[i].parts.find(p => p.type === 'structured-output')` is typed
|
|
78
84
|
* with the schema's inferred shape — `data: T`, `partial: DeepPartial<T>`.
|
|
85
|
+
* When `subagents` is supplied, a `type: 'subagent'` part narrows on
|
|
86
|
+
* `subagent.name`, and that child's `messages` use the agent's tools.
|
|
87
|
+
*/
|
|
88
|
+
messages: Array<UIMessage<TTools, TData, TSubagents>>;
|
|
89
|
+
/**
|
|
90
|
+
* Live child-agent invocations, nested cards included. Each entry is the
|
|
91
|
+
* same object as the matching `part.subagent`, including `stop()`.
|
|
92
|
+
* When `subagents` is supplied, `name` is one of those agent names.
|
|
79
93
|
*/
|
|
80
|
-
|
|
94
|
+
subagents: Array<SubagentHandles<TSubagents>>;
|
|
81
95
|
/**
|
|
82
96
|
* Send a message and get a response.
|
|
83
97
|
* Can be a simple string or multimodal content with images, audio, etc.
|
package/dist/esm/ui.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createChatUI, type ChatUIComponents, type ChatUIFactoryConfig, type ChatUIHost, type ChatUIQueueItem, type InputProps, type InterruptProps, type LayoutProps, type MessageProps, type PartProps, type QueueProps, type ToolProps, } from './chat-ui/create-ui.js';
|
|
1
|
+
export { createChatUI, type ChatUIComponents, type ChatUIFactoryConfig, type ChatUIHost, type ChatUIQueueItem, type InputProps, type InterruptProps, type LayoutProps, type MessageProps, type PartProps, type QueueProps, type SubagentPartsProps, type SubagentProps, type ToolProps, } from './chat-ui/create-ui.js';
|
|
2
2
|
export { createChatHook } from './chat-ui/create-chat-hook.js';
|
|
3
3
|
export { createChatHookContexts, type ChatUIContexts, } from './chat-ui/create-ui-contexts.js';
|
|
4
4
|
export { Chat, useChatContext, type ChatProps } from './chat-ui/chat.js';
|
package/dist/esm/use-chat.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { AnyClientTool, InterruptDefinition, SchemaInput } from '@tanstack/ai/client';
|
|
2
2
|
import { InferredClientContext } from '@tanstack/ai-client';
|
|
3
3
|
import { UseChatOptions, UseChatReturn } from './types.js';
|
|
4
|
-
export declare function useChat<const TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []
|
|
4
|
+
export declare function useChat<const TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly [], const TSubagents extends ReadonlyArray<{
|
|
5
|
+
name: string;
|
|
6
|
+
}> | undefined = undefined>(options: UseChatOptions<TTools, TSchema, TContext, TInterrupts, TSubagents>): UseChatReturn<TTools, TSchema, TInterrupts, TSubagents>;
|
package/dist/esm/use-chat.js
CHANGED