@assistant-ui/react 0.14.5 → 0.14.7
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/LICENSE +21 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/legacy-runtime/AssistantRuntimeProvider.d.ts +8 -2
- package/dist/legacy-runtime/AssistantRuntimeProvider.d.ts.map +1 -1
- package/dist/legacy-runtime/AssistantRuntimeProvider.js.map +1 -1
- package/dist/legacy-runtime/hooks/AssistantContext.d.ts +2 -2
- package/dist/legacy-runtime/hooks/AssistantContext.js +1 -1
- package/dist/legacy-runtime/hooks/AttachmentContext.d.ts +2 -2
- package/dist/legacy-runtime/hooks/AttachmentContext.js +1 -1
- package/dist/legacy-runtime/hooks/ComposerContext.d.ts +2 -2
- package/dist/legacy-runtime/hooks/ComposerContext.js +1 -1
- package/dist/legacy-runtime/hooks/MessageContext.d.ts +3 -3
- package/dist/legacy-runtime/hooks/MessageContext.js +2 -2
- package/dist/legacy-runtime/hooks/MessagePartContext.d.ts +2 -2
- package/dist/legacy-runtime/hooks/MessagePartContext.js +1 -1
- package/dist/legacy-runtime/hooks/ThreadContext.d.ts +4 -4
- package/dist/legacy-runtime/hooks/ThreadContext.js +2 -2
- package/dist/legacy-runtime/hooks/ThreadListItemContext.d.ts +2 -2
- package/dist/legacy-runtime/hooks/ThreadListItemContext.js +1 -1
- package/dist/mcp-apps/McpAppRenderer.d.ts +8 -0
- package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/mcp-apps/McpAppRenderer.js +8 -0
- package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/mcp-apps/McpAppsRemoteHost.d.ts +7 -0
- package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -1
- package/dist/mcp-apps/McpAppsRemoteHost.js +7 -0
- package/dist/mcp-apps/McpAppsRemoteHost.js.map +1 -1
- package/dist/mcp-apps/utils.d.ts +7 -0
- package/dist/mcp-apps/utils.d.ts.map +1 -1
- package/dist/mcp-apps/utils.js +7 -0
- package/dist/mcp-apps/utils.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarCopy.js +6 -1
- package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
- package/dist/primitives/messagePart/MessagePartInProgress.d.ts +1 -5
- package/dist/primitives/messagePart/MessagePartInProgress.d.ts.map +1 -1
- package/dist/primitives/messagePart/MessagePartInProgress.js +1 -7
- package/dist/primitives/messagePart/MessagePartInProgress.js.map +1 -1
- package/dist/primitives/messagePart/useMessagePartData.d.ts +16 -0
- package/dist/primitives/messagePart/useMessagePartData.d.ts.map +1 -1
- package/dist/primitives/messagePart/useMessagePartData.js +16 -0
- package/dist/primitives/messagePart/useMessagePartData.js.map +1 -1
- package/dist/primitives/messagePart/useMessagePartFile.d.ts +15 -0
- package/dist/primitives/messagePart/useMessagePartFile.d.ts.map +1 -1
- package/dist/primitives/messagePart/useMessagePartFile.js +15 -0
- package/dist/primitives/messagePart/useMessagePartFile.js.map +1 -1
- package/dist/primitives/messagePart/useMessagePartImage.d.ts +15 -0
- package/dist/primitives/messagePart/useMessagePartImage.d.ts.map +1 -1
- package/dist/primitives/messagePart/useMessagePartImage.js +15 -0
- package/dist/primitives/messagePart/useMessagePartImage.js.map +1 -1
- package/dist/primitives/messagePart/useMessagePartReasoning.d.ts +15 -0
- package/dist/primitives/messagePart/useMessagePartReasoning.d.ts.map +1 -1
- package/dist/primitives/messagePart/useMessagePartReasoning.js +15 -0
- package/dist/primitives/messagePart/useMessagePartReasoning.js.map +1 -1
- package/dist/primitives/messagePart/useMessagePartSource.d.ts +15 -0
- package/dist/primitives/messagePart/useMessagePartSource.d.ts.map +1 -1
- package/dist/primitives/messagePart/useMessagePartSource.js +15 -0
- package/dist/primitives/messagePart/useMessagePartSource.js.map +1 -1
- package/dist/primitives/messagePart/useMessagePartText.d.ts +15 -0
- package/dist/primitives/messagePart/useMessagePartText.d.ts.map +1 -1
- package/dist/primitives/messagePart/useMessagePartText.js +15 -0
- package/dist/primitives/messagePart/useMessagePartText.js.map +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.js +50 -27
- package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
- package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
- package/dist/utils/smooth/useSmooth.js +27 -10
- package/dist/utils/smooth/useSmooth.js.map +1 -1
- package/package.json +14 -16
- package/src/index.ts +6 -0
- package/src/legacy-runtime/AssistantRuntimeProvider.tsx +8 -2
- package/src/legacy-runtime/hooks/AssistantContext.ts +2 -2
- package/src/legacy-runtime/hooks/AttachmentContext.ts +2 -2
- package/src/legacy-runtime/hooks/ComposerContext.ts +2 -2
- package/src/legacy-runtime/hooks/MessageContext.ts +3 -3
- package/src/legacy-runtime/hooks/MessagePartContext.ts +2 -2
- package/src/legacy-runtime/hooks/ThreadContext.ts +4 -4
- package/src/legacy-runtime/hooks/ThreadListItemContext.ts +2 -2
- package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.test.ts +254 -0
- package/src/mcp-apps/McpAppRenderer.tsx +8 -0
- package/src/mcp-apps/McpAppsRemoteHost.ts +7 -0
- package/src/mcp-apps/utils.ts +7 -0
- package/src/primitives/actionBar/ActionBarCopy.tsx +6 -1
- package/src/primitives/messagePart/MessagePartInProgress.ts +1 -17
- package/src/primitives/messagePart/useMessagePartData.ts +16 -0
- package/src/primitives/messagePart/useMessagePartFile.ts +15 -0
- package/src/primitives/messagePart/useMessagePartImage.ts +15 -0
- package/src/primitives/messagePart/useMessagePartReasoning.ts +15 -0
- package/src/primitives/messagePart/useMessagePartSource.ts +15 -0
- package/src/primitives/messagePart/useMessagePartText.ts +15 -0
- package/src/primitives/thread/useThreadViewportAutoScroll.test.tsx +320 -0
- package/src/primitives/thread/useThreadViewportAutoScroll.ts +59 -29
- package/src/tests/BaseComposerRuntimeCore.test.ts +1 -1
- package/src/utils/smooth/useSmooth.ts +28 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.7",
|
|
4
4
|
"description": "Open-source TypeScript/React library for building production-grade AI chat experiences",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"radix-ui",
|
|
@@ -47,16 +47,9 @@
|
|
|
47
47
|
"README.md"
|
|
48
48
|
],
|
|
49
49
|
"sideEffects": false,
|
|
50
|
-
"scripts": {
|
|
51
|
-
"prepack": "cp ../../README.md /tmp/aui-readme-pack.md && mv /tmp/aui-readme-pack.md ./README.md",
|
|
52
|
-
"postpack": "rm -f ./README.md && ln -s ../../README.md ./README.md",
|
|
53
|
-
"build": "aui-build",
|
|
54
|
-
"test": "vitest run",
|
|
55
|
-
"test:watch": "vitest"
|
|
56
|
-
},
|
|
57
50
|
"dependencies": {
|
|
58
|
-
"@assistant-ui/core": "^0.2.
|
|
59
|
-
"@assistant-ui/store": "^0.2.
|
|
51
|
+
"@assistant-ui/core": "^0.2.4",
|
|
52
|
+
"@assistant-ui/store": "^0.2.11",
|
|
60
53
|
"@assistant-ui/tap": "^0.5.11",
|
|
61
54
|
"@radix-ui/primitive": "^1.1.3",
|
|
62
55
|
"@radix-ui/react-compose-refs": "^1.1.2",
|
|
@@ -64,8 +57,8 @@
|
|
|
64
57
|
"@radix-ui/react-primitive": "^2.1.4",
|
|
65
58
|
"@radix-ui/react-use-callback-ref": "^1.1.1",
|
|
66
59
|
"@radix-ui/react-use-escape-keydown": "^1.1.1",
|
|
67
|
-
"assistant-cloud": "^0.1.
|
|
68
|
-
"assistant-stream": "^0.3.
|
|
60
|
+
"assistant-cloud": "^0.1.28",
|
|
61
|
+
"assistant-stream": "^0.3.15",
|
|
69
62
|
"nanoid": "^5.1.11",
|
|
70
63
|
"radix-ui": "^1.4.3",
|
|
71
64
|
"react-textarea-autosize": "^8.5.9",
|
|
@@ -88,7 +81,6 @@
|
|
|
88
81
|
}
|
|
89
82
|
},
|
|
90
83
|
"devDependencies": {
|
|
91
|
-
"@assistant-ui/x-buildutils": "workspace:*",
|
|
92
84
|
"@testing-library/react": "^16.3.2",
|
|
93
85
|
"@types/json-schema": "^7.0.15",
|
|
94
86
|
"@types/node": "^25.6.0",
|
|
@@ -97,11 +89,12 @@
|
|
|
97
89
|
"jsdom": "^29.1.1",
|
|
98
90
|
"react": "^19.2.5",
|
|
99
91
|
"react-dom": "^19.2.5",
|
|
100
|
-
"vitest": "^4.1.5"
|
|
92
|
+
"vitest": "^4.1.5",
|
|
93
|
+
"@assistant-ui/x-buildutils": "0.0.8"
|
|
101
94
|
},
|
|
102
95
|
"publishConfig": {
|
|
103
96
|
"access": "public",
|
|
104
|
-
"provenance":
|
|
97
|
+
"provenance": true
|
|
105
98
|
},
|
|
106
99
|
"homepage": "https://www.assistant-ui.com/",
|
|
107
100
|
"repository": {
|
|
@@ -111,5 +104,10 @@
|
|
|
111
104
|
},
|
|
112
105
|
"bugs": {
|
|
113
106
|
"url": "https://github.com/assistant-ui/assistant-ui/issues"
|
|
107
|
+
},
|
|
108
|
+
"scripts": {
|
|
109
|
+
"build": "aui-build",
|
|
110
|
+
"test": "vitest run",
|
|
111
|
+
"test:watch": "vitest"
|
|
114
112
|
}
|
|
115
|
-
}
|
|
113
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -378,6 +378,12 @@ export {
|
|
|
378
378
|
type RegisteredTrigger as Unstable_RegisteredTrigger,
|
|
379
379
|
type TriggerBehavior as Unstable_TriggerBehavior,
|
|
380
380
|
} from "./primitives/composer/trigger";
|
|
381
|
+
export type {
|
|
382
|
+
Unstable_DirectiveFormatter,
|
|
383
|
+
Unstable_DirectiveSegment,
|
|
384
|
+
Unstable_TriggerItem,
|
|
385
|
+
} from "@assistant-ui/core";
|
|
386
|
+
export { unstable_defaultDirectiveFormatter } from "@assistant-ui/core";
|
|
381
387
|
|
|
382
388
|
export type { Assistant } from "./augmentations";
|
|
383
389
|
|
|
@@ -10,12 +10,18 @@ import { DevToolsProviderApi } from "../devtools/DevToolsHooks";
|
|
|
10
10
|
export namespace AssistantRuntimeProvider {
|
|
11
11
|
export type Props = PropsWithChildren<{
|
|
12
12
|
/**
|
|
13
|
-
* The runtime to
|
|
13
|
+
* The assistant runtime to expose to descendants. Build one with
|
|
14
|
+
* `useLocalRuntime`, `useExternalStoreRuntime`, or
|
|
15
|
+
* `useAssistantTransportRuntime`.
|
|
14
16
|
*/
|
|
15
17
|
runtime: AssistantRuntime;
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
|
-
*
|
|
20
|
+
* Optional parent `AssistantClient` whose scopes are inherited by the
|
|
21
|
+
* client created for this runtime. Use this when nesting an
|
|
22
|
+
* `AssistantRuntimeProvider` inside another assistant context. Omit this
|
|
23
|
+
* prop when there is no parent client.
|
|
24
|
+
* @defaultValue undefined
|
|
19
25
|
*/
|
|
20
26
|
aui?: AssistantClient;
|
|
21
27
|
}>;
|
|
@@ -6,7 +6,7 @@ import type { ThreadListRuntime } from "../runtime/ThreadListRuntime";
|
|
|
6
6
|
import { createStateHookForRuntime } from "../../context/react/utils/createStateHookForRuntime";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @deprecated Use
|
|
9
|
+
* @deprecated Use {@link useAui} instead. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
10
10
|
*
|
|
11
11
|
* Hook to access the AssistantRuntime from the current context.
|
|
12
12
|
*
|
|
@@ -62,6 +62,6 @@ const useThreadListRuntime = (opt: {
|
|
|
62
62
|
}): ThreadListRuntime | null => useAssistantRuntime(opt)?.threads ?? null;
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* @deprecated Use `useAuiState((s) => s.threads)
|
|
65
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.threads)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
66
66
|
*/
|
|
67
67
|
export const useThreadList = createStateHookForRuntime(useThreadListRuntime);
|
|
@@ -5,7 +5,7 @@ import { createStateHookForRuntime } from "../../context/react/utils/createState
|
|
|
5
5
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @deprecated Use
|
|
8
|
+
* @deprecated Use {@link useAui} with `aui.attachment()` instead. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
9
9
|
*/
|
|
10
10
|
export function useAttachmentRuntime(options?: {
|
|
11
11
|
optional?: false | undefined;
|
|
@@ -84,7 +84,7 @@ export function useMessageAttachmentRuntime(options?: {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
* @deprecated Use `useAuiState((s) => s.attachment)
|
|
87
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.attachment)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
88
88
|
*/
|
|
89
89
|
export const useAttachment = createStateHookForRuntime(useAttachmentRuntime);
|
|
90
90
|
|
|
@@ -5,7 +5,7 @@ import type { ComposerRuntime } from "../runtime/ComposerRuntime";
|
|
|
5
5
|
import { createStateHookForRuntime } from "../../context/react/utils/createStateHookForRuntime";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @deprecated Use
|
|
8
|
+
* @deprecated Use {@link useAui} with `aui.composer()` instead. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
9
9
|
*
|
|
10
10
|
* Hook to access the ComposerRuntime from the current context.
|
|
11
11
|
*
|
|
@@ -87,7 +87,7 @@ export function useComposerRuntime(options?: {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* @deprecated Use `useAuiState((s) => s.composer)
|
|
90
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.composer)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
91
91
|
*
|
|
92
92
|
* Hook to access the current composer state.
|
|
93
93
|
*
|
|
@@ -6,7 +6,7 @@ import { createStateHookForRuntime } from "../../context/react/utils/createState
|
|
|
6
6
|
import type { EditComposerRuntime } from "@assistant-ui/core";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @deprecated Use
|
|
9
|
+
* @deprecated Use {@link useAui} with `aui.message()` instead. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
10
10
|
*
|
|
11
11
|
* Hook to access the MessageRuntime from the current context.
|
|
12
12
|
*
|
|
@@ -76,7 +76,7 @@ export function useMessageRuntime(options?: {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
* @deprecated Use `useAuiState((s) => s.message)
|
|
79
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.message)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
80
80
|
*
|
|
81
81
|
* Hook to access the current message state.
|
|
82
82
|
*
|
|
@@ -120,7 +120,7 @@ const useEditComposerRuntime = (opt: {
|
|
|
120
120
|
}): EditComposerRuntime | null => useMessageRuntime(opt)?.composer ?? null;
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
|
-
* @deprecated Use `useAuiState((s) => s.message.composer)
|
|
123
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.message.composer)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
124
124
|
*/
|
|
125
125
|
export const useEditComposer = createStateHookForRuntime(
|
|
126
126
|
useEditComposerRuntime,
|
|
@@ -5,7 +5,7 @@ import { createStateHookForRuntime } from "../../context/react/utils/createState
|
|
|
5
5
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @deprecated Use
|
|
8
|
+
* @deprecated Use {@link useAui} with `aui.part()` instead. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
9
9
|
*/
|
|
10
10
|
export function useMessagePartRuntime(options?: {
|
|
11
11
|
optional?: false | undefined;
|
|
@@ -27,6 +27,6 @@ export function useMessagePartRuntime(options?: {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* @deprecated Use `useAuiState((s) => s.part)
|
|
30
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.part)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
31
31
|
*/
|
|
32
32
|
export const useMessagePart = createStateHookForRuntime(useMessagePartRuntime);
|
|
@@ -8,7 +8,7 @@ import type { ThreadComposerRuntime } from "@assistant-ui/core";
|
|
|
8
8
|
import { useAui, useAuiEvent, useAuiState } from "@assistant-ui/store";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @deprecated Use
|
|
11
|
+
* @deprecated Use {@link useAui} with `aui.thread()` instead. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
12
12
|
*
|
|
13
13
|
* Hook to access the ThreadRuntime from the current context.
|
|
14
14
|
*
|
|
@@ -58,7 +58,7 @@ export function useThreadRuntime(options?: { optional?: boolean | undefined }) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* @deprecated Use `useAuiState((s) => s.thread)
|
|
61
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.thread)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
62
62
|
*
|
|
63
63
|
* Hook to access the current thread state.
|
|
64
64
|
*
|
|
@@ -92,14 +92,14 @@ const useThreadComposerRuntime = (opt: {
|
|
|
92
92
|
}): ThreadComposerRuntime | null => useThreadRuntime(opt)?.composer ?? null;
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
* @deprecated Use `useAuiState((s) => s.thread.composer)
|
|
95
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.thread.composer)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
96
96
|
*/
|
|
97
97
|
export const useThreadComposer = createStateHookForRuntime(
|
|
98
98
|
useThreadComposerRuntime,
|
|
99
99
|
);
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
|
-
* @deprecated Use `useAuiState((s) => s.thread.modelContext)
|
|
102
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.thread.modelContext)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
103
103
|
*/
|
|
104
104
|
export function useThreadModelContext(options?: {
|
|
105
105
|
optional?: false | undefined;
|
|
@@ -5,7 +5,7 @@ import { createStateHookForRuntime } from "../../context/react/utils/createState
|
|
|
5
5
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @deprecated Use
|
|
8
|
+
* @deprecated Use {@link useAui} with `aui.threadListItem()` instead. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
9
9
|
*/
|
|
10
10
|
export function useThreadListItemRuntime(options?: {
|
|
11
11
|
optional?: false | undefined;
|
|
@@ -29,7 +29,7 @@ export function useThreadListItemRuntime(options?: {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* @deprecated Use `useAuiState((s) => s.threadListItem)
|
|
32
|
+
* @deprecated Use {@link useAuiState}: `useAuiState((s) => s.threadListItem)`. See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
33
33
|
*/
|
|
34
34
|
export const useThreadListItem = createStateHookForRuntime(
|
|
35
35
|
useThreadListItemRuntime,
|
|
@@ -635,4 +635,258 @@ describe("useToolInvocations", () => {
|
|
|
635
635
|
expect(onResult).not.toHaveBeenCalled();
|
|
636
636
|
});
|
|
637
637
|
});
|
|
638
|
+
|
|
639
|
+
it("fires streamCall for already-resolved tool calls loaded after the initial snapshot", async () => {
|
|
640
|
+
const execute = vi.fn(async () => ({ forecast: "ok" }));
|
|
641
|
+
const streamCall = vi.fn();
|
|
642
|
+
const getTools = () => ({
|
|
643
|
+
weatherSearch: {
|
|
644
|
+
parameters: { type: "object", properties: {} },
|
|
645
|
+
execute,
|
|
646
|
+
streamCall,
|
|
647
|
+
} satisfies Tool,
|
|
648
|
+
});
|
|
649
|
+
const onResult = vi.fn();
|
|
650
|
+
const setToolStatuses = vi.fn();
|
|
651
|
+
|
|
652
|
+
const { rerender } = renderHook(
|
|
653
|
+
({ state }: { state: AssistantTransportState }) =>
|
|
654
|
+
useToolInvocations({
|
|
655
|
+
state,
|
|
656
|
+
getTools,
|
|
657
|
+
onResult,
|
|
658
|
+
setToolStatuses,
|
|
659
|
+
}),
|
|
660
|
+
{
|
|
661
|
+
initialProps: {
|
|
662
|
+
state: createState([]),
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
);
|
|
666
|
+
|
|
667
|
+
act(() => {
|
|
668
|
+
rerender({
|
|
669
|
+
state: createState([
|
|
670
|
+
createAssistantMessage(
|
|
671
|
+
'{"query":"London"}',
|
|
672
|
+
{ query: "London" },
|
|
673
|
+
{ result: { source: "history" } },
|
|
674
|
+
),
|
|
675
|
+
]),
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
await waitFor(() => {
|
|
680
|
+
expect(streamCall).toHaveBeenCalledTimes(1);
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
const [reader] = streamCall.mock.calls[0]!;
|
|
684
|
+
await expect(reader.args.get("query")).resolves.toBe("London");
|
|
685
|
+
const response = await reader.response.get();
|
|
686
|
+
expect(response.result).toEqual({ source: "history" });
|
|
687
|
+
|
|
688
|
+
expect(execute).not.toHaveBeenCalled();
|
|
689
|
+
expect(onResult).not.toHaveBeenCalled();
|
|
690
|
+
expect(setToolStatuses).not.toHaveBeenCalled();
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
it("does not fire streamCall for tool calls present in the initial snapshot", async () => {
|
|
694
|
+
const streamCall = vi.fn();
|
|
695
|
+
const getTools = () => ({
|
|
696
|
+
weatherSearch: {
|
|
697
|
+
parameters: { type: "object", properties: {} },
|
|
698
|
+
streamCall,
|
|
699
|
+
} satisfies Tool,
|
|
700
|
+
});
|
|
701
|
+
const onResult = vi.fn();
|
|
702
|
+
const setToolStatuses = vi.fn();
|
|
703
|
+
|
|
704
|
+
renderHook(
|
|
705
|
+
({ state }: { state: AssistantTransportState }) =>
|
|
706
|
+
useToolInvocations({
|
|
707
|
+
state,
|
|
708
|
+
getTools,
|
|
709
|
+
onResult,
|
|
710
|
+
setToolStatuses,
|
|
711
|
+
}),
|
|
712
|
+
{
|
|
713
|
+
initialProps: {
|
|
714
|
+
state: createState([
|
|
715
|
+
createAssistantMessage(
|
|
716
|
+
'{"query":"London"}',
|
|
717
|
+
{ query: "London" },
|
|
718
|
+
{ result: { source: "history" } },
|
|
719
|
+
),
|
|
720
|
+
]),
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
await act(async () => {});
|
|
726
|
+
expect(streamCall).not.toHaveBeenCalled();
|
|
727
|
+
expect(onResult).not.toHaveBeenCalled();
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
it("promotes an in-progress tool call from the initial snapshot when it changes", async () => {
|
|
731
|
+
const execute = vi.fn(async () => ({ forecast: "ok" }));
|
|
732
|
+
const streamCall = vi.fn();
|
|
733
|
+
const getTools = () => ({
|
|
734
|
+
weatherSearch: {
|
|
735
|
+
parameters: { type: "object", properties: {} },
|
|
736
|
+
execute,
|
|
737
|
+
streamCall,
|
|
738
|
+
} satisfies Tool,
|
|
739
|
+
});
|
|
740
|
+
const onResult = vi.fn();
|
|
741
|
+
const setToolStatuses = vi.fn();
|
|
742
|
+
|
|
743
|
+
const { rerender } = renderHook(
|
|
744
|
+
({ state }: { state: AssistantTransportState }) =>
|
|
745
|
+
useToolInvocations({
|
|
746
|
+
state,
|
|
747
|
+
getTools,
|
|
748
|
+
onResult,
|
|
749
|
+
setToolStatuses,
|
|
750
|
+
}),
|
|
751
|
+
{
|
|
752
|
+
initialProps: {
|
|
753
|
+
state: createState([
|
|
754
|
+
createAssistantMessage('{"query":"Lon', { query: "Lon" }),
|
|
755
|
+
]),
|
|
756
|
+
},
|
|
757
|
+
},
|
|
758
|
+
);
|
|
759
|
+
|
|
760
|
+
await act(async () => {});
|
|
761
|
+
expect(streamCall).not.toHaveBeenCalled();
|
|
762
|
+
|
|
763
|
+
act(() => {
|
|
764
|
+
rerender({
|
|
765
|
+
state: createState([
|
|
766
|
+
createAssistantMessage(
|
|
767
|
+
'{"query":"London"}',
|
|
768
|
+
{ query: "London" },
|
|
769
|
+
{ result: { source: "history" } },
|
|
770
|
+
),
|
|
771
|
+
]),
|
|
772
|
+
});
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
await waitFor(() => {
|
|
776
|
+
expect(streamCall).toHaveBeenCalledTimes(1);
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
const [reader] = streamCall.mock.calls[0]!;
|
|
780
|
+
await expect(reader.args.get("query")).resolves.toBe("London");
|
|
781
|
+
const response = await reader.response.get();
|
|
782
|
+
expect(response.result).toEqual({ source: "history" });
|
|
783
|
+
|
|
784
|
+
expect(execute).not.toHaveBeenCalled();
|
|
785
|
+
expect(onResult).not.toHaveBeenCalled();
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
it("does not re-fire streamCall when an initial-snapshot tool call is unchanged in later snapshots", async () => {
|
|
789
|
+
const streamCall = vi.fn();
|
|
790
|
+
const getTools = () => ({
|
|
791
|
+
weatherSearch: {
|
|
792
|
+
parameters: { type: "object", properties: {} },
|
|
793
|
+
streamCall,
|
|
794
|
+
} satisfies Tool,
|
|
795
|
+
});
|
|
796
|
+
const onResult = vi.fn();
|
|
797
|
+
const setToolStatuses = vi.fn();
|
|
798
|
+
|
|
799
|
+
const { rerender } = renderHook(
|
|
800
|
+
({ state }: { state: AssistantTransportState }) =>
|
|
801
|
+
useToolInvocations({
|
|
802
|
+
state,
|
|
803
|
+
getTools,
|
|
804
|
+
onResult,
|
|
805
|
+
setToolStatuses,
|
|
806
|
+
}),
|
|
807
|
+
{
|
|
808
|
+
initialProps: {
|
|
809
|
+
state: createState([
|
|
810
|
+
createAssistantMessage(
|
|
811
|
+
'{"query":"London"}',
|
|
812
|
+
{ query: "London" },
|
|
813
|
+
{ result: { source: "history" } },
|
|
814
|
+
),
|
|
815
|
+
]),
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
act(() => {
|
|
821
|
+
rerender({
|
|
822
|
+
state: createState([
|
|
823
|
+
createAssistantMessage(
|
|
824
|
+
'{"query":"London"}',
|
|
825
|
+
{ query: "London" },
|
|
826
|
+
{ result: { source: "history" } },
|
|
827
|
+
),
|
|
828
|
+
]),
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
await act(async () => {});
|
|
833
|
+
expect(streamCall).not.toHaveBeenCalled();
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
it("does not emit a cancellation onResult for pre-resolved tool calls aborted by reset", async () => {
|
|
837
|
+
const streamCall = vi.fn();
|
|
838
|
+
const getTools = () => ({
|
|
839
|
+
weatherSearch: {
|
|
840
|
+
parameters: { type: "object", properties: {} },
|
|
841
|
+
execute: vi.fn(async () => ({ forecast: "ok" })),
|
|
842
|
+
streamCall,
|
|
843
|
+
} satisfies Tool,
|
|
844
|
+
});
|
|
845
|
+
const onResult = vi.fn();
|
|
846
|
+
const setToolStatuses = vi.fn();
|
|
847
|
+
|
|
848
|
+
const { result, rerender } = renderHook(
|
|
849
|
+
({ state }: { state: AssistantTransportState }) =>
|
|
850
|
+
useToolInvocations({
|
|
851
|
+
state,
|
|
852
|
+
getTools,
|
|
853
|
+
onResult,
|
|
854
|
+
setToolStatuses,
|
|
855
|
+
}),
|
|
856
|
+
{
|
|
857
|
+
initialProps: {
|
|
858
|
+
state: createState([]),
|
|
859
|
+
},
|
|
860
|
+
},
|
|
861
|
+
);
|
|
862
|
+
|
|
863
|
+
act(() => {
|
|
864
|
+
rerender({
|
|
865
|
+
state: createState([
|
|
866
|
+
createAssistantMessage(
|
|
867
|
+
'{"query":"London"}',
|
|
868
|
+
{ query: "London" },
|
|
869
|
+
{ result: { source: "history" } },
|
|
870
|
+
),
|
|
871
|
+
]),
|
|
872
|
+
});
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
await waitFor(() => {
|
|
876
|
+
expect(streamCall).toHaveBeenCalledTimes(1);
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
act(() => {
|
|
880
|
+
result.current.reset();
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
// Flush microtasks through the executor's abort race + the stream
|
|
884
|
+
// pipeline so any cancellation `result` chunk has a chance to land
|
|
885
|
+
// before we assert it didn't.
|
|
886
|
+
for (let i = 0; i < 5; i++) {
|
|
887
|
+
await act(async () => {});
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
expect(onResult).not.toHaveBeenCalled();
|
|
891
|
+
});
|
|
638
892
|
});
|
|
@@ -192,6 +192,14 @@ function InlineRenderer({
|
|
|
192
192
|
);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Creates a tool-call renderer for MCP Apps embedded in assistant messages.
|
|
197
|
+
*
|
|
198
|
+
* Compose this into the `Tools` resource through its `mcpApp` option. When a
|
|
199
|
+
* tool-call part carries `mcp.app` metadata for a `ui://` resource, the
|
|
200
|
+
* renderer loads that resource from the configured host and displays it in a
|
|
201
|
+
* sandboxed frame.
|
|
202
|
+
*/
|
|
195
203
|
export const McpAppRenderer = resource(
|
|
196
204
|
(
|
|
197
205
|
options: McpAppRendererOptions,
|
|
@@ -26,6 +26,13 @@ async function postToHost(
|
|
|
26
26
|
return res.json();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Creates the default HTTP host for MCP App widgets.
|
|
31
|
+
*
|
|
32
|
+
* The host POSTs widget requests to the configured route as `{ method,
|
|
33
|
+
* params }`, using the method names expected by the assistant-ui MCP Apps
|
|
34
|
+
* guide.
|
|
35
|
+
*/
|
|
29
36
|
export const McpAppsRemoteHost = resource(
|
|
30
37
|
(options: McpAppsRemoteHostOptions): McpAppsHost => {
|
|
31
38
|
const optionsRef = tapRef(options);
|
package/src/mcp-apps/utils.ts
CHANGED
|
@@ -6,6 +6,13 @@ import {
|
|
|
6
6
|
|
|
7
7
|
type ToolPartLike = Pick<ToolCallMessagePart, "mcp">;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Returns MCP app metadata for a tool-call part that points at a `ui://`
|
|
11
|
+
* resource.
|
|
12
|
+
*
|
|
13
|
+
* Returns `undefined` when the part has no MCP app metadata or the metadata
|
|
14
|
+
* does not reference an assistant-ui MCP app resource.
|
|
15
|
+
*/
|
|
9
16
|
export function getMcpAppFromToolPart(
|
|
10
17
|
part: ToolPartLike,
|
|
11
18
|
): McpAppMetadata | undefined {
|
|
@@ -38,7 +38,12 @@ const useActionBarPrimitiveCopy = ({
|
|
|
38
38
|
} = {}) => {
|
|
39
39
|
const { copy, disabled } = useActionBarCopy({
|
|
40
40
|
copiedDuration,
|
|
41
|
-
copyToClipboard: (text) =>
|
|
41
|
+
copyToClipboard: (text) => {
|
|
42
|
+
if (typeof navigator === "undefined" || !navigator.clipboard) {
|
|
43
|
+
return Promise.reject(new Error("Clipboard API is unavailable"));
|
|
44
|
+
}
|
|
45
|
+
return navigator.clipboard.writeText(text);
|
|
46
|
+
},
|
|
42
47
|
});
|
|
43
48
|
if (disabled) return null;
|
|
44
49
|
return copy;
|
|
@@ -1,19 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import { useAuiState } from "@assistant-ui/store";
|
|
5
|
-
|
|
6
|
-
export namespace MessagePartPrimitiveInProgress {
|
|
7
|
-
export type Props = PropsWithChildren;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// TODO should this be renamed to IsRunning?
|
|
11
|
-
export const MessagePartPrimitiveInProgress: FC<
|
|
12
|
-
MessagePartPrimitiveInProgress.Props
|
|
13
|
-
> = ({ children }) => {
|
|
14
|
-
const isInProgress = useAuiState((s) => s.part.status.type === "running");
|
|
15
|
-
|
|
16
|
-
return isInProgress ? children : null;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
MessagePartPrimitiveInProgress.displayName = "MessagePartPrimitive.InProgress";
|
|
3
|
+
export { MessagePartPrimitiveInProgress } from "@assistant-ui/core/react";
|
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
import type { DataMessagePart } from "@assistant-ui/core";
|
|
4
4
|
import { useAuiState } from "@assistant-ui/store";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use {@link useAuiState} to select and narrow `s.part`.
|
|
8
|
+
* Return `null` for optional rendering, or throw inside the selector to
|
|
9
|
+
* preserve the old hook's strict behavior.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const part = useAuiState((s) =>
|
|
14
|
+
* s.part.type === "data" && (!name || s.part.name === name)
|
|
15
|
+
* ? s.part
|
|
16
|
+
* : null,
|
|
17
|
+
* );
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
21
|
+
*/
|
|
6
22
|
export const useMessagePartData = <T = any>(name?: string) => {
|
|
7
23
|
const part = useAuiState((s) => {
|
|
8
24
|
if (s.part.type !== "data") {
|
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
import type { FileMessagePart, MessagePartState } from "@assistant-ui/core";
|
|
4
4
|
import { useAuiState } from "@assistant-ui/store";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use {@link useAuiState} to select and narrow `s.part`.
|
|
8
|
+
* Return `null` for optional rendering, or throw inside the selector to
|
|
9
|
+
* preserve the old hook's strict behavior.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const file = useAuiState((s) => {
|
|
14
|
+
* if (s.part.type !== "file") return null;
|
|
15
|
+
* return s.part;
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
20
|
+
*/
|
|
6
21
|
export const useMessagePartFile = () => {
|
|
7
22
|
const file = useAuiState((s) => {
|
|
8
23
|
if (s.part.type !== "file")
|
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
import type { ImageMessagePart, MessagePartState } from "@assistant-ui/core";
|
|
4
4
|
import { useAuiState } from "@assistant-ui/store";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use {@link useAuiState} to select and narrow `s.part`.
|
|
8
|
+
* Return `null` for optional rendering, or throw inside the selector to
|
|
9
|
+
* preserve the old hook's strict behavior.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const image = useAuiState((s) => {
|
|
14
|
+
* if (s.part.type !== "image") return null;
|
|
15
|
+
* return s.part;
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* See the {@link https://assistant-ui.com/docs/migrations/v0-12 migration guide}.
|
|
20
|
+
*/
|
|
6
21
|
export const useMessagePartImage = () => {
|
|
7
22
|
const image = useAuiState((s) => {
|
|
8
23
|
if (s.part.type !== "image")
|