@assistant-ui/core 0.2.8 → 0.2.10
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/model-context/tool.d.ts +1 -1
- package/dist/model-context/tool.js +1 -1
- package/dist/model-context/tool.js.map +1 -1
- package/dist/model-context/types.js +17 -2
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +12 -2
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +9 -3
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/index.d.ts +8 -2
- package/dist/react/index.js +7 -1
- package/dist/react/model-context/define-mcp-toolkit.d.ts +12 -0
- package/dist/react/model-context/define-mcp-toolkit.d.ts.map +1 -0
- package/dist/react/model-context/define-mcp-toolkit.js +14 -0
- package/dist/react/model-context/define-mcp-toolkit.js.map +1 -0
- package/dist/react/model-context/define-toolkit.d.ts +21 -0
- package/dist/react/model-context/define-toolkit.d.ts.map +1 -0
- package/dist/react/model-context/define-toolkit.js +8 -0
- package/dist/react/model-context/define-toolkit.js.map +1 -0
- package/dist/react/model-context/hitl.d.ts +23 -0
- package/dist/react/model-context/hitl.d.ts.map +1 -0
- package/dist/react/model-context/hitl.js +26 -0
- package/dist/react/model-context/hitl.js.map +1 -0
- package/dist/react/model-context/makeAssistantTool.d.ts +8 -0
- package/dist/react/model-context/makeAssistantTool.d.ts.map +1 -1
- package/dist/react/model-context/makeAssistantTool.js +4 -0
- package/dist/react/model-context/makeAssistantTool.js.map +1 -1
- package/dist/react/model-context/makeAssistantToolUI.d.ts +8 -0
- package/dist/react/model-context/makeAssistantToolUI.d.ts.map +1 -1
- package/dist/react/model-context/makeAssistantToolUI.js +4 -0
- package/dist/react/model-context/makeAssistantToolUI.js.map +1 -1
- package/dist/react/model-context/provider-tool.d.ts +15 -0
- package/dist/react/model-context/provider-tool.d.ts.map +1 -0
- package/dist/react/model-context/provider-tool.js +12 -0
- package/dist/react/model-context/provider-tool.js.map +1 -0
- package/dist/react/model-context/stub-tool.d.ts +12 -0
- package/dist/react/model-context/stub-tool.d.ts.map +1 -0
- package/dist/react/model-context/stub-tool.js +15 -0
- package/dist/react/model-context/stub-tool.js.map +1 -0
- package/dist/react/model-context/toolbox.d.ts +62 -15
- package/dist/react/model-context/toolbox.d.ts.map +1 -1
- package/dist/react/model-context/toolbox.js +19 -1
- package/dist/react/model-context/toolbox.js.map +1 -1
- package/dist/react/model-context/useAssistantTool.d.ts +11 -1
- package/dist/react/model-context/useAssistantTool.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantTool.js +12 -6
- package/dist/react/model-context/useAssistantTool.js.map +1 -1
- package/dist/react/model-context/useAssistantToolUI.d.ts +13 -4
- package/dist/react/model-context/useAssistantToolUI.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantToolUI.js +6 -3
- package/dist/react/model-context/useAssistantToolUI.js.map +1 -1
- package/dist/react/model-context/useAuiToolOverrides.d.ts +22 -0
- package/dist/react/model-context/useAuiToolOverrides.d.ts.map +1 -0
- package/dist/react/model-context/useAuiToolOverrides.js +31 -0
- package/dist/react/model-context/useAuiToolOverrides.js.map +1 -0
- package/dist/react/primitives/part/PartMessages.d.ts +13 -11
- package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
- package/dist/react/primitives/part/PartMessages.js +13 -11
- package/dist/react/primitives/part/PartMessages.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +1 -0
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +28 -0
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +9 -2
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts +2 -0
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +6 -0
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +1 -0
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-adapter.d.ts +2 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -0
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +5 -0
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts +1 -0
- package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/adapter/in-memory.js +3 -0
- package/dist/runtimes/remote-thread-list/adapter/in-memory.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +1 -0
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -0
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +1 -0
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/model-context/tool.ts +1 -1
- package/src/model-context/types.ts +21 -3
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +15 -2
- package/src/react/client/Tools.ts +22 -7
- package/src/react/index.ts +15 -2
- package/src/react/model-context/define-mcp-toolkit.ts +16 -0
- package/src/react/model-context/define-toolkit.test.ts +101 -0
- package/src/react/model-context/define-toolkit.ts +41 -0
- package/src/react/model-context/hitl.ts +27 -0
- package/src/react/model-context/makeAssistantTool.ts +8 -0
- package/src/react/model-context/makeAssistantToolUI.ts +8 -0
- package/src/react/model-context/provider-tool.ts +30 -0
- package/src/react/model-context/stub-tool.ts +14 -0
- package/src/react/model-context/toolbox.test.ts +182 -0
- package/src/react/model-context/toolbox.ts +189 -21
- package/src/react/model-context/useAssistantTool.ts +28 -8
- package/src/react/model-context/useAssistantToolUI.ts +13 -4
- package/src/react/model-context/useAuiToolOverrides.ts +38 -0
- package/src/react/primitives/part/PartMessages.tsx +13 -11
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +43 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +9 -0
- package/src/runtime/api/thread-list-item-runtime.ts +15 -0
- package/src/runtime/interfaces/thread-list-runtime-core.ts +4 -0
- package/src/runtimes/external-store/external-store-adapter.ts +7 -0
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +13 -0
- package/src/runtimes/remote-thread-list/adapter/in-memory.ts +4 -0
- package/src/runtimes/remote-thread-list/types.ts +4 -0
- package/src/store/clients/model-context-client.test.ts +87 -2
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +1 -0
- package/src/store/scopes/thread-list-item.ts +1 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-custom-metadata.test.ts +69 -1
- package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
Tool,
|
|
3
|
+
ToolCallReader,
|
|
4
|
+
ToolDeclaration,
|
|
5
|
+
ToolModelOutputFunction,
|
|
6
|
+
} from "assistant-stream";
|
|
7
|
+
import type { ReactNode } from "react";
|
|
8
|
+
import type {
|
|
9
|
+
ToolCallMessagePartComponent,
|
|
10
|
+
ToolCallMessagePartProps,
|
|
11
|
+
} from "../types/MessagePartComponentTypes";
|
|
3
12
|
|
|
4
13
|
/**
|
|
5
14
|
* Resolves whether a tool's UI should be presented standalone (outside the
|
|
@@ -20,23 +29,96 @@ export const isStandaloneToolDisplay = (
|
|
|
20
29
|
type WithRender<T, TArgs extends Record<string, unknown>, TResult> = T extends {
|
|
21
30
|
type: "frontend" | "human";
|
|
22
31
|
}
|
|
23
|
-
? T &
|
|
32
|
+
? T &
|
|
33
|
+
(T extends { type: "frontend" }
|
|
34
|
+
?
|
|
35
|
+
| { render: ToolCallMessagePartComponent<TArgs, TResult> }
|
|
36
|
+
| {
|
|
37
|
+
render?: ToolCallMessagePartComponent<TArgs, TResult>;
|
|
38
|
+
renderText: ToolCallText<TArgs, TResult>;
|
|
39
|
+
}
|
|
40
|
+
: { render: ToolCallMessagePartComponent<TArgs, TResult> })
|
|
24
41
|
: T & {
|
|
25
42
|
render?: ToolCallMessagePartComponent<TArgs, TResult> | undefined;
|
|
43
|
+
renderText?: ToolCallText<TArgs, TResult> | undefined;
|
|
26
44
|
};
|
|
27
45
|
|
|
46
|
+
type ToolParameters<TArgs extends Record<string, unknown>> =
|
|
47
|
+
ToolDeclaration<TArgs>["parameters"];
|
|
48
|
+
|
|
49
|
+
// ToolExecutionContext is not re-exported from assistant-stream's public entry.
|
|
50
|
+
type ToolExecuteContext = Parameters<
|
|
51
|
+
NonNullable<ToolDeclaration["execute"]>
|
|
52
|
+
>[1];
|
|
53
|
+
|
|
54
|
+
type ToolExecute<TArgs extends Record<string, unknown>, TResult> = (
|
|
55
|
+
args: TArgs,
|
|
56
|
+
context: ToolExecuteContext,
|
|
57
|
+
) => TResult | Promise<TResult>;
|
|
58
|
+
|
|
59
|
+
type ToolStreamCall<TArgs extends Record<string, unknown>, TResult> = (
|
|
60
|
+
reader: ToolCallReader<TArgs, TResult>,
|
|
61
|
+
context: ToolExecuteContext,
|
|
62
|
+
) => void;
|
|
63
|
+
|
|
64
|
+
type ToolCallRunningText<TArgs extends Record<string, unknown>> =
|
|
65
|
+
| ReactNode
|
|
66
|
+
| ((options: { args: TArgs }) => ReactNode);
|
|
67
|
+
|
|
68
|
+
type ToolCallCompleteText<TArgs extends Record<string, unknown>, TResult> =
|
|
69
|
+
| ReactNode
|
|
70
|
+
| ((options: { args: TArgs; result: TResult | undefined }) => ReactNode);
|
|
71
|
+
|
|
72
|
+
export type ToolCallText<TArgs extends Record<string, unknown>, TResult> =
|
|
73
|
+
| {
|
|
74
|
+
running: ToolCallRunningText<TArgs>;
|
|
75
|
+
complete?: ToolCallCompleteText<TArgs, TResult> | undefined;
|
|
76
|
+
}
|
|
77
|
+
| {
|
|
78
|
+
running?: ToolCallRunningText<TArgs> | undefined;
|
|
79
|
+
complete: ToolCallCompleteText<TArgs, TResult>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const resolveToolCallText = <TArgs extends Record<string, unknown>, TResult>(
|
|
83
|
+
text: ToolCallText<TArgs, TResult>,
|
|
84
|
+
part: ToolCallMessagePartProps<TArgs, TResult>,
|
|
85
|
+
): ReactNode => {
|
|
86
|
+
const isRunning =
|
|
87
|
+
part.status?.type === "running" || part.status?.type === "requires-action";
|
|
88
|
+
|
|
89
|
+
if (!isRunning) {
|
|
90
|
+
const value = text.complete;
|
|
91
|
+
if (typeof value !== "function") return value ?? null;
|
|
92
|
+
return value({ args: part.args, result: part.result });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const value = text.running;
|
|
96
|
+
if (typeof value !== "function") return value ?? null;
|
|
97
|
+
return value({ args: part.args });
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const makeToolCallTextComponent = <
|
|
101
|
+
TArgs extends Record<string, unknown>,
|
|
102
|
+
TResult,
|
|
103
|
+
>(
|
|
104
|
+
text: ToolCallText<TArgs, TResult>,
|
|
105
|
+
): ToolCallMessagePartComponent<TArgs, TResult> => {
|
|
106
|
+
return function ToolCallTextComponent(part) {
|
|
107
|
+
return resolveToolCallText(text, part);
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
|
|
28
111
|
/**
|
|
29
112
|
* Tool definition accepted by the React tool registry.
|
|
30
113
|
*
|
|
31
|
-
* Extends the core tool contract with
|
|
32
|
-
*
|
|
33
|
-
* browser and require
|
|
34
|
-
* tools execute server-side and may omit a renderer.
|
|
35
|
-
* required for frontend and human tools and optional for backend tools.
|
|
114
|
+
* Extends the core tool contract with tool-call display options. Human tools
|
|
115
|
+
* rely on `render` to collect input from the user. Frontend tools execute in
|
|
116
|
+
* the browser and require either `render` or `renderText` for their progress
|
|
117
|
+
* and result. Backend tools execute server-side and may omit a renderer.
|
|
36
118
|
*/
|
|
37
119
|
export type ToolDefinition<
|
|
38
|
-
TArgs extends Record<string, unknown>,
|
|
39
|
-
TResult,
|
|
120
|
+
TArgs extends Record<string, unknown> = Record<string, unknown>,
|
|
121
|
+
TResult = unknown,
|
|
40
122
|
> = WithRender<Tool<TArgs, TResult>, TArgs, TResult>;
|
|
41
123
|
|
|
42
124
|
/**
|
|
@@ -63,19 +145,96 @@ export type Toolkit = Record<string, ToolDefinition<any, any>>;
|
|
|
63
145
|
* A tool as authored, before the build splits it: like {@link ToolDefinition}
|
|
64
146
|
* but it may declare `description`, `parameters`, and a server-side `execute`
|
|
65
147
|
* alongside its `render`. The `type` field is **not** authored — the
|
|
66
|
-
* `"use generative"` compiler infers it (`execute:
|
|
67
|
-
*
|
|
68
|
-
*
|
|
148
|
+
* `"use generative"` compiler infers it (`execute: hitlTool()` → human;
|
|
149
|
+
* `execute: providerTool(...)` → provider; `execute` with a `"use client"`
|
|
150
|
+
* directive → frontend; otherwise backend) and writes it back — so declaring it
|
|
151
|
+
* here is a type error.
|
|
69
152
|
*/
|
|
70
|
-
|
|
153
|
+
type OverrideOptionalField<
|
|
154
|
+
T,
|
|
155
|
+
TKey extends keyof T,
|
|
156
|
+
TValue,
|
|
157
|
+
> = undefined extends T[TKey]
|
|
158
|
+
? // Preserve `?: undefined` fields (for variants that explicitly disallow a
|
|
159
|
+
// callback) instead of widening them to accept the override value.
|
|
160
|
+
Exclude<T[TKey], undefined> extends never
|
|
161
|
+
? { [K in TKey]?: undefined }
|
|
162
|
+
: { [K in TKey]?: TValue | undefined }
|
|
163
|
+
: { [K in TKey]: TValue };
|
|
164
|
+
|
|
165
|
+
type OverrideToolDeclarationCallbacks<
|
|
166
|
+
T extends { streamCall?: unknown },
|
|
167
|
+
TArgs extends Record<string, unknown>,
|
|
168
|
+
TResult,
|
|
169
|
+
> = Omit<
|
|
170
|
+
T,
|
|
171
|
+
| "type"
|
|
172
|
+
| "execute"
|
|
173
|
+
| "toModelOutput"
|
|
174
|
+
| "experimental_onSchemaValidationError"
|
|
175
|
+
| "streamCall"
|
|
176
|
+
> & {
|
|
177
|
+
type?: never;
|
|
178
|
+
} & ("execute" extends keyof T
|
|
179
|
+
? OverrideOptionalField<T, "execute", ToolExecute<NoInfer<TArgs>, TResult>>
|
|
180
|
+
: {}) &
|
|
181
|
+
("toModelOutput" extends keyof T
|
|
182
|
+
? OverrideOptionalField<
|
|
183
|
+
T,
|
|
184
|
+
"toModelOutput",
|
|
185
|
+
ToolModelOutputFunction<NoInfer<TArgs>, NoInfer<TResult>>
|
|
186
|
+
>
|
|
187
|
+
: {}) &
|
|
188
|
+
("experimental_onSchemaValidationError" extends keyof T
|
|
189
|
+
? OverrideOptionalField<
|
|
190
|
+
T,
|
|
191
|
+
"experimental_onSchemaValidationError",
|
|
192
|
+
(
|
|
193
|
+
args: unknown,
|
|
194
|
+
context: ToolExecuteContext,
|
|
195
|
+
) => NoInfer<TResult> | Promise<NoInfer<TResult>>
|
|
196
|
+
>
|
|
197
|
+
: {}) &
|
|
198
|
+
OverrideOptionalField<
|
|
199
|
+
T,
|
|
200
|
+
"streamCall",
|
|
201
|
+
ToolStreamCall<TArgs, NoInfer<TResult>>
|
|
202
|
+
>;
|
|
203
|
+
|
|
204
|
+
// Keep the authored shape tied to ToolDeclaration's union variants while
|
|
205
|
+
// overriding callback fields to avoid inference pollution.
|
|
206
|
+
type ToolkitDefinitionInput<
|
|
71
207
|
TArgs extends Record<string, unknown>,
|
|
72
208
|
TResult,
|
|
73
209
|
> = WithRender<
|
|
74
|
-
|
|
210
|
+
ToolDeclaration<TArgs, TResult> extends infer T
|
|
211
|
+
? T extends { streamCall?: unknown }
|
|
212
|
+
? OverrideToolDeclarationCallbacks<T, TArgs, TResult>
|
|
213
|
+
: never
|
|
214
|
+
: never,
|
|
75
215
|
TArgs,
|
|
76
216
|
TResult
|
|
77
|
-
|
|
78
|
-
|
|
217
|
+
>;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* A single entry in a {@link ToolkitDefinition}.
|
|
221
|
+
*
|
|
222
|
+
* Either authored inline (whose `type` the compiler infers) or an already-formed
|
|
223
|
+
* {@link ToolDefinition} produced by a factory whose own build splits it across
|
|
224
|
+
* targets — e.g. `new JSONGenerativeUI({ library }).present()`. The factory case
|
|
225
|
+
* carries a `type`, so it can only match the {@link ToolDefinition} arm of this
|
|
226
|
+
* union.
|
|
227
|
+
*/
|
|
228
|
+
export type ToolkitDefinitionEntry<
|
|
229
|
+
TArgs extends Record<string, unknown> = Record<string, unknown>,
|
|
230
|
+
TResult = unknown,
|
|
231
|
+
> = ToolkitDefinitionInput<TArgs, TResult> | ToolDefinition<any, any>;
|
|
232
|
+
|
|
233
|
+
export type ToolkitDefinitionEntryWithParameters<
|
|
234
|
+
TArgs extends Record<string, unknown> = Record<string, unknown>,
|
|
235
|
+
TResult = unknown,
|
|
236
|
+
> = ToolkitDefinitionInput<TArgs, TResult> & {
|
|
237
|
+
parameters: NonNullable<ToolParameters<TArgs>>;
|
|
79
238
|
};
|
|
80
239
|
|
|
81
240
|
/**
|
|
@@ -83,10 +242,19 @@ export type ToolkitDeclarationDefinition<
|
|
|
83
242
|
* {@link defineToolkit}. Backend entries may carry their server `execute` here;
|
|
84
243
|
* the canonical {@link Toolkit} keeps those fields `undefined`.
|
|
85
244
|
*/
|
|
86
|
-
export type
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
245
|
+
export type ToolkitDefinition<
|
|
246
|
+
TArgsByName extends {
|
|
247
|
+
[K in keyof TArgsByName]: Record<string, unknown>;
|
|
248
|
+
} = Record<string, any>,
|
|
249
|
+
TResultByName extends { [K in keyof TArgsByName]: unknown } = {
|
|
250
|
+
[K in keyof TArgsByName]: any;
|
|
251
|
+
},
|
|
252
|
+
> = {
|
|
253
|
+
[K in keyof TArgsByName]: ToolkitDefinitionEntry<
|
|
254
|
+
TArgsByName[K],
|
|
255
|
+
TResultByName[K]
|
|
256
|
+
>;
|
|
257
|
+
};
|
|
90
258
|
|
|
91
259
|
/** Configuration for the {@link Tools} resource. */
|
|
92
260
|
export type ToolsConfig = {
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useEffect, useMemo } from "react";
|
|
2
2
|
import { useAui } from "@assistant-ui/store";
|
|
3
3
|
import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
|
|
4
4
|
import type { AssistantToolProps as CoreAssistantToolProps } from "../..";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
isStandaloneToolDisplay,
|
|
7
|
+
makeToolCallTextComponent,
|
|
8
|
+
type ToolCallText,
|
|
9
|
+
} from "./toolbox";
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* Props used to register a tool from React.
|
|
13
|
+
*
|
|
14
|
+
* @deprecated Use a toolkit with `Tools({ toolkit })` and register it via
|
|
15
|
+
* `useAui({ tools: Tools({ toolkit }) })` instead. See
|
|
16
|
+
* https://assistant-ui.com/docs/migrations/toolkit-tools.
|
|
9
17
|
*/
|
|
10
18
|
export type AssistantToolProps<
|
|
11
19
|
TArgs extends Record<string, unknown>,
|
|
@@ -13,6 +21,8 @@ export type AssistantToolProps<
|
|
|
13
21
|
> = CoreAssistantToolProps<TArgs, TResult> & {
|
|
14
22
|
/** Component used to render calls to this tool in assistant messages. */
|
|
15
23
|
render?: ToolCallMessagePartComponent<TArgs, TResult> | undefined;
|
|
24
|
+
/** Lightweight text rendered while a tool call is running or complete. */
|
|
25
|
+
renderText?: ToolCallText<TArgs, TResult> | undefined;
|
|
16
26
|
};
|
|
17
27
|
|
|
18
28
|
/**
|
|
@@ -28,6 +38,10 @@ export type AssistantToolProps<
|
|
|
28
38
|
*
|
|
29
39
|
* @param tool - Tool definition and name to register.
|
|
30
40
|
*
|
|
41
|
+
* @deprecated Use a toolkit with `Tools({ toolkit })` and register it via
|
|
42
|
+
* `useAui({ tools: Tools({ toolkit }) })` instead. See
|
|
43
|
+
* https://assistant-ui.com/docs/migrations/toolkit-tools.
|
|
44
|
+
*
|
|
31
45
|
* @example
|
|
32
46
|
* ```tsx
|
|
33
47
|
* const weatherTool = {
|
|
@@ -54,16 +68,22 @@ export const useAssistantTool = <
|
|
|
54
68
|
const aui = useAui();
|
|
55
69
|
|
|
56
70
|
const standalone = isStandaloneToolDisplay(tool);
|
|
71
|
+
const renderTextComponent = useMemo(
|
|
72
|
+
() =>
|
|
73
|
+
tool.renderText ? makeToolCallTextComponent(tool.renderText) : undefined,
|
|
74
|
+
[tool.renderText],
|
|
75
|
+
);
|
|
76
|
+
const render = tool.render ?? renderTextComponent;
|
|
57
77
|
|
|
58
78
|
useEffect(() => {
|
|
59
|
-
if (!
|
|
60
|
-
return aui.tools().setToolUI(tool.toolName,
|
|
61
|
-
}, [aui, tool.toolName,
|
|
79
|
+
if (!render) return undefined;
|
|
80
|
+
return aui.tools().setToolUI(tool.toolName, render, { standalone });
|
|
81
|
+
}, [aui, tool.toolName, render, standalone]);
|
|
62
82
|
|
|
63
83
|
useEffect(() => {
|
|
64
|
-
// `render` and `display` are client-only presentation
|
|
65
|
-
// reach the model.
|
|
66
|
-
const { toolName, render, display, ...rest } = tool;
|
|
84
|
+
// `render`, `renderText`, and `display` are client-only presentation
|
|
85
|
+
// concerns and never reach the model.
|
|
86
|
+
const { toolName, render, renderText, display, ...rest } = tool;
|
|
67
87
|
const context = {
|
|
68
88
|
tools: {
|
|
69
89
|
[toolName]: rest,
|
|
@@ -2,7 +2,13 @@ import { useEffect } from "react";
|
|
|
2
2
|
import { useAui } from "@assistant-ui/store";
|
|
3
3
|
import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Props used to register a renderer for tool-call message parts.
|
|
7
|
+
*
|
|
8
|
+
* @deprecated Put `render`/`renderText` on the matching toolkit entry, or use
|
|
9
|
+
* `MessagePrimitive.Parts` inline tool render overrides for per-message UI.
|
|
10
|
+
* See https://assistant-ui.com/docs/migrations/toolkit-tools.
|
|
11
|
+
*/
|
|
6
12
|
export type AssistantToolUIProps<TArgs, TResult> = {
|
|
7
13
|
/** Name of the tool whose calls should use this renderer. */
|
|
8
14
|
toolName: string;
|
|
@@ -19,11 +25,14 @@ export type AssistantToolUIProps<TArgs, TResult> = {
|
|
|
19
25
|
/**
|
|
20
26
|
* Registers a tool-call renderer while the component is mounted.
|
|
21
27
|
*
|
|
22
|
-
* This only affects rendering. Pair it with {@link
|
|
23
|
-
*
|
|
24
|
-
* definition to the model.
|
|
28
|
+
* This only affects rendering. Pair it with {@link Tools} or a backend tool
|
|
29
|
+
* registry to expose the actual tool definition to the model.
|
|
25
30
|
*
|
|
26
31
|
* @param tool - Tool renderer registration, or `null` to skip registration.
|
|
32
|
+
*
|
|
33
|
+
* @deprecated Put `render`/`renderText` on the matching toolkit entry, or use
|
|
34
|
+
* `MessagePrimitive.Parts` inline tool render overrides for per-message UI.
|
|
35
|
+
* See https://assistant-ui.com/docs/migrations/toolkit-tools.
|
|
27
36
|
*/
|
|
28
37
|
export const useAssistantToolUI = (
|
|
29
38
|
tool: AssistantToolUIProps<any, any> | null,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useAui } from "@assistant-ui/store";
|
|
3
|
+
import type { Tool } from "assistant-stream";
|
|
4
|
+
|
|
5
|
+
type AuiToolOverride<
|
|
6
|
+
TArgs extends Record<string, unknown> = Record<string, unknown>,
|
|
7
|
+
TResult = unknown,
|
|
8
|
+
> = Partial<Tool<TArgs, TResult>>;
|
|
9
|
+
|
|
10
|
+
type AuiToolOverrides = Record<string, AuiToolOverride<any, any>>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Overrides toolkit entries for the current assistant scope.
|
|
14
|
+
*
|
|
15
|
+
* This is intended for dynamic local-state tools whose model-facing contract is
|
|
16
|
+
* declared in a `"use generative"` toolkit file with `execute: stubTool()`, but
|
|
17
|
+
* whose actual executor must close over React state in the mounted component.
|
|
18
|
+
* Keep the override keys stable after mount; dynamic key addition/removal is not
|
|
19
|
+
* currently observed.
|
|
20
|
+
* Overrides are registered at priority 1000, above toolkit defaults. Only one
|
|
21
|
+
* mounted override provider may define a given tool name at a time.
|
|
22
|
+
*
|
|
23
|
+
* @deprecated Experimental, API may change.
|
|
24
|
+
*/
|
|
25
|
+
export function useAuiToolOverrides(overrides: AuiToolOverrides): void {
|
|
26
|
+
const aui = useAui();
|
|
27
|
+
const overridesRef = useRef(overrides);
|
|
28
|
+
overridesRef.current = overrides;
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
return aui.modelContext().register({
|
|
32
|
+
getModelContext: () => ({
|
|
33
|
+
priority: 1000,
|
|
34
|
+
tools: overridesRef.current as Record<string, Tool<any, any>>,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
}, [aui]);
|
|
38
|
+
}
|
|
@@ -34,17 +34,19 @@ const usePartMessages = (): readonly ThreadMessage[] | undefined => {
|
|
|
34
34
|
*
|
|
35
35
|
* @example
|
|
36
36
|
* ```tsx
|
|
37
|
-
* const
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
37
|
+
* const toolkit = {
|
|
38
|
+
* invoke_sub_agent: {
|
|
39
|
+
* type: "backend",
|
|
40
|
+
* render: () => (
|
|
41
|
+
* <PartPrimitive.Messages>
|
|
42
|
+
* {({ message }) => {
|
|
43
|
+
* if (message.role === "user") return <MyUserMessage />;
|
|
44
|
+
* return <MyAssistantMessage />;
|
|
45
|
+
* }}
|
|
46
|
+
* </PartPrimitive.Messages>
|
|
47
|
+
* ),
|
|
48
|
+
* },
|
|
49
|
+
* } satisfies Toolkit;
|
|
48
50
|
* ```
|
|
49
51
|
*/
|
|
50
52
|
export const PartPrimitiveMessagesImpl: FC<PartPrimitiveMessages.Props> = ({
|
|
@@ -508,6 +508,49 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
508
508
|
});
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
public updateCustom(
|
|
512
|
+
threadIdOrRemoteId: string,
|
|
513
|
+
custom: Record<string, unknown> | undefined,
|
|
514
|
+
): Promise<void> {
|
|
515
|
+
const data = this.getItemById(threadIdOrRemoteId);
|
|
516
|
+
if (!data) throw new Error("Thread not found");
|
|
517
|
+
if (data.status === "new") throw new Error("Thread is not yet initialized");
|
|
518
|
+
|
|
519
|
+
if (!this._options.adapter.updateCustom) {
|
|
520
|
+
throw new Error(
|
|
521
|
+
"Remote thread list adapter does not support updating custom metadata",
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return this._state.optimisticUpdate({
|
|
526
|
+
execute: async () => {
|
|
527
|
+
const { remoteId } = await data.initializeTask;
|
|
528
|
+
const adapter = this._options.adapter;
|
|
529
|
+
if (!adapter.updateCustom) {
|
|
530
|
+
throw new Error(
|
|
531
|
+
"Remote thread list adapter does not support updating custom metadata",
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
return adapter.updateCustom(remoteId, custom);
|
|
535
|
+
},
|
|
536
|
+
optimistic: (state) => {
|
|
537
|
+
const data = getThreadData(state, threadIdOrRemoteId);
|
|
538
|
+
if (!data) return state;
|
|
539
|
+
|
|
540
|
+
return {
|
|
541
|
+
...state,
|
|
542
|
+
threadData: {
|
|
543
|
+
...state.threadData,
|
|
544
|
+
[data.id]: {
|
|
545
|
+
...data,
|
|
546
|
+
custom,
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
511
554
|
private async _ensureThreadIsNotMain(threadId: string) {
|
|
512
555
|
if (threadId === this.newThreadId)
|
|
513
556
|
throw new Error("Cannot ensure new thread is not main");
|
|
@@ -14,6 +14,7 @@ import { InMemoryThreadListAdapter } from "../../../runtimes/remote-thread-list/
|
|
|
14
14
|
import { useAssistantCloudThreadHistoryAdapter } from "./AssistantCloudThreadHistoryAdapter";
|
|
15
15
|
import { RuntimeAdapterProvider } from "../RuntimeAdapterProvider";
|
|
16
16
|
import { CloudFileAttachmentAdapter } from "./CloudFileAttachmentAdapter";
|
|
17
|
+
import { isRecord } from "../../../utils/json/is-json";
|
|
17
18
|
|
|
18
19
|
type ThreadData = {
|
|
19
20
|
externalId: string | undefined;
|
|
@@ -26,6 +27,9 @@ type CloudThreadListAdapterOptions = {
|
|
|
26
27
|
delete?: ((threadId: string) => Promise<void>) | undefined;
|
|
27
28
|
};
|
|
28
29
|
|
|
30
|
+
const toCustom = (value: unknown): Record<string, unknown> | undefined =>
|
|
31
|
+
isRecord(value) ? value : undefined;
|
|
32
|
+
|
|
29
33
|
const baseUrl =
|
|
30
34
|
typeof process !== "undefined" &&
|
|
31
35
|
process?.env?.NEXT_PUBLIC_ASSISTANT_BASE_URL;
|
|
@@ -91,6 +95,7 @@ export const useCloudThreadListAdapter = (
|
|
|
91
95
|
remoteId: t.id,
|
|
92
96
|
title: t.title,
|
|
93
97
|
externalId: t.external_id ?? undefined,
|
|
98
|
+
custom: toCustom(t.metadata),
|
|
94
99
|
})),
|
|
95
100
|
};
|
|
96
101
|
},
|
|
@@ -110,6 +115,9 @@ export const useCloudThreadListAdapter = (
|
|
|
110
115
|
rename: async (threadId, newTitle) => {
|
|
111
116
|
return cloud.threads.update(threadId, { title: newTitle });
|
|
112
117
|
},
|
|
118
|
+
updateCustom: async (threadId, custom) => {
|
|
119
|
+
return cloud.threads.update(threadId, { metadata: custom ?? null });
|
|
120
|
+
},
|
|
113
121
|
archive: async (threadId) => {
|
|
114
122
|
return cloud.threads.update(threadId, { is_archived: true });
|
|
115
123
|
},
|
|
@@ -146,6 +154,7 @@ export const useCloudThreadListAdapter = (
|
|
|
146
154
|
remoteId: thread.id,
|
|
147
155
|
title: thread.title,
|
|
148
156
|
externalId: thread.external_id ?? undefined,
|
|
157
|
+
custom: toCustom(thread.metadata),
|
|
149
158
|
};
|
|
150
159
|
},
|
|
151
160
|
|
|
@@ -38,6 +38,7 @@ export type ThreadListItemRuntime = {
|
|
|
38
38
|
|
|
39
39
|
switchTo(options?: { unarchive?: boolean }): Promise<void>;
|
|
40
40
|
rename(newTitle: string): Promise<void>;
|
|
41
|
+
updateCustom(custom: Record<string, unknown> | undefined): Promise<void>;
|
|
41
42
|
archive(): Promise<void>;
|
|
42
43
|
unarchive(): Promise<void>;
|
|
43
44
|
delete(): Promise<void>;
|
|
@@ -74,6 +75,7 @@ export class ThreadListItemRuntimeImpl implements ThreadListItemRuntime {
|
|
|
74
75
|
protected __internal_bindMethods() {
|
|
75
76
|
this.switchTo = this.switchTo.bind(this);
|
|
76
77
|
this.rename = this.rename.bind(this);
|
|
78
|
+
this.updateCustom = this.updateCustom.bind(this);
|
|
77
79
|
this.archive = this.archive.bind(this);
|
|
78
80
|
this.unarchive = this.unarchive.bind(this);
|
|
79
81
|
this.delete = this.delete.bind(this);
|
|
@@ -100,6 +102,19 @@ export class ThreadListItemRuntimeImpl implements ThreadListItemRuntime {
|
|
|
100
102
|
return this._threadListBinding.rename(state.id, newTitle);
|
|
101
103
|
}
|
|
102
104
|
|
|
105
|
+
public updateCustom(
|
|
106
|
+
custom: Record<string, unknown> | undefined,
|
|
107
|
+
): Promise<void> {
|
|
108
|
+
const state = this._core.getState();
|
|
109
|
+
if (!this._threadListBinding.updateCustom) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
"Thread list runtime does not support updating custom metadata",
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return this._threadListBinding.updateCustom(state.id, custom);
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
public archive(): Promise<void> {
|
|
104
119
|
const state = this._core.getState();
|
|
105
120
|
|
|
@@ -44,6 +44,10 @@ export type ThreadListRuntimeCore = {
|
|
|
44
44
|
|
|
45
45
|
detach(threadId: string): Promise<void>;
|
|
46
46
|
rename(threadId: string, newTitle: string): Promise<void>;
|
|
47
|
+
updateCustom?(
|
|
48
|
+
threadId: string,
|
|
49
|
+
custom: Record<string, unknown> | undefined,
|
|
50
|
+
): Promise<void>;
|
|
47
51
|
archive(threadId: string): Promise<void>;
|
|
48
52
|
unarchive(threadId: string): Promise<void>;
|
|
49
53
|
delete(threadId: string): Promise<void>;
|
|
@@ -24,6 +24,7 @@ export type ExternalStoreThreadData<TState extends "regular" | "archived"> = {
|
|
|
24
24
|
remoteId?: string | undefined;
|
|
25
25
|
externalId?: string | undefined;
|
|
26
26
|
title?: string | undefined;
|
|
27
|
+
custom?: Record<string, unknown> | undefined;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
export type ExternalStoreThreadListAdapter = {
|
|
@@ -46,6 +47,12 @@ export type ExternalStoreThreadListAdapter = {
|
|
|
46
47
|
threadId: string,
|
|
47
48
|
newTitle: string,
|
|
48
49
|
) => (Promise<void> | void) | undefined;
|
|
50
|
+
onUpdateCustom?:
|
|
51
|
+
| ((
|
|
52
|
+
threadId: string,
|
|
53
|
+
custom: Record<string, unknown> | undefined,
|
|
54
|
+
) => Promise<void> | void)
|
|
55
|
+
| undefined;
|
|
49
56
|
onArchive?: ((threadId: string) => Promise<void> | void) | undefined;
|
|
50
57
|
onUnarchive?: ((threadId: string) => Promise<void> | void) | undefined;
|
|
51
58
|
onDelete?: ((threadId: string) => Promise<void> | void) | undefined;
|
|
@@ -197,6 +197,19 @@ export class ExternalStoreThreadListRuntimeCore implements ThreadListRuntimeCore
|
|
|
197
197
|
await onRename(threadId, newTitle);
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
public async updateCustom(
|
|
201
|
+
threadId: string,
|
|
202
|
+
custom: Record<string, unknown> | undefined,
|
|
203
|
+
): Promise<void> {
|
|
204
|
+
const onUpdateCustom = this.adapter.onUpdateCustom;
|
|
205
|
+
if (!onUpdateCustom)
|
|
206
|
+
throw new Error(
|
|
207
|
+
"External store adapter does not support updating custom metadata",
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
await onUpdateCustom(threadId, custom);
|
|
211
|
+
}
|
|
212
|
+
|
|
200
213
|
public async detach(): Promise<void> {
|
|
201
214
|
// no-op
|
|
202
215
|
}
|
|
@@ -29,6 +29,10 @@ export type RemoteThreadListAdapter = {
|
|
|
29
29
|
list(params?: RemoteThreadListPageOptions): Promise<RemoteThreadListResponse>;
|
|
30
30
|
|
|
31
31
|
rename(remoteId: string, newTitle: string): Promise<void>;
|
|
32
|
+
updateCustom?(
|
|
33
|
+
remoteId: string,
|
|
34
|
+
custom: Record<string, unknown> | undefined,
|
|
35
|
+
): Promise<void>;
|
|
32
36
|
archive(remoteId: string): Promise<void>;
|
|
33
37
|
unarchive(remoteId: string): Promise<void>;
|
|
34
38
|
delete(remoteId: string): Promise<void>;
|