@assistant-ui/react 0.15.24 → 0.15.25
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/hooks/useToolCallElapsed.d.ts +3 -1
- package/dist/hooks/useToolCallElapsed.d.ts.map +1 -1
- package/dist/hooks/useToolCallElapsed.js +7 -8
- package/dist/hooks/useToolCallElapsed.js.map +1 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/model-context/makeAssistantVisible.d.ts +1 -0
- package/dist/model-context/makeAssistantVisible.d.ts.map +1 -1
- package/dist/model-context/makeAssistantVisible.js +31 -12
- package/dist/model-context/makeAssistantVisible.js.map +1 -1
- package/dist/primitives/composer/ComposerInput.d.ts +1 -1
- package/dist/primitives/composer/ComposerInput.js +1 -1
- package/dist/primitives/composer/ComposerInput.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopover.d.ts +11 -11
- package/dist/primitives/composer/trigger/TriggerPopover.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopover.js +62 -60
- package/dist/primitives/composer/trigger/TriggerPopover.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverAction.d.ts +8 -8
- package/dist/primitives/composer/trigger/TriggerPopoverAction.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverAction.js +6 -6
- package/dist/primitives/composer/trigger/TriggerPopoverAction.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverCategories.d.ts +3 -3
- package/dist/primitives/composer/trigger/TriggerPopoverCategories.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverCategories.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverDirective.d.ts +9 -9
- package/dist/primitives/composer/trigger/TriggerPopoverDirective.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverDirective.js +7 -7
- package/dist/primitives/composer/trigger/TriggerPopoverDirective.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverItems.d.ts +5 -5
- package/dist/primitives/composer/trigger/TriggerPopoverItems.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverItems.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts +8 -8
- package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js +8 -8
- package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js.map +1 -1
- package/dist/primitives/composer/trigger/index.d.ts +1 -1
- package/dist/primitives/composer.d.ts +20 -1
- package/dist/primitives/composer.d.ts.map +1 -1
- package/dist/primitives/composer.js +8 -1
- package/dist/primitives/composer.js.map +1 -1
- package/dist/primitives/thread/ThreadLoadEarlier.d.ts +19 -0
- package/dist/primitives/thread/ThreadLoadEarlier.d.ts.map +1 -0
- package/dist/primitives/thread/ThreadLoadEarlier.js +36 -0
- package/dist/primitives/thread/ThreadLoadEarlier.js.map +1 -0
- package/dist/primitives/thread/ThreadMessages.d.ts +1 -1
- package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadMessages.js +2 -2
- package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.js +111 -2
- package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
- package/dist/primitives/thread.d.ts +2 -0
- package/dist/primitives/thread.d.ts.map +1 -1
- package/dist/primitives/thread.js +5 -2
- package/dist/primitives/thread.js.map +1 -1
- package/dist/sandbox-host/SandboxHost.d.ts.map +1 -1
- package/dist/sandbox-host/SandboxHost.js +6 -1
- package/dist/sandbox-host/SandboxHost.js.map +1 -1
- package/dist/unstable/useMessageStallDetection.d.ts.map +1 -1
- package/dist/unstable/useMessageStallDetection.js +10 -6
- package/dist/unstable/useMessageStallDetection.js.map +1 -1
- package/dist/utils/smooth/useSmooth.js +6 -6
- package/dist/utils/smooth/useSmooth.js.map +1 -1
- package/package.json +5 -4
- package/src/hooks/useToolCallElapsed.test.tsx +35 -0
- package/src/hooks/useToolCallElapsed.ts +9 -7
- package/src/index.ts +28 -3
- package/src/model-context/makeAssistantVisible.test.tsx +315 -5
- package/src/model-context/makeAssistantVisible.tsx +43 -7
- package/src/primitives/composer/ComposerInput.tsx +1 -1
- package/src/primitives/composer/trigger/TriggerPopover.tsx +11 -11
- package/src/primitives/composer/trigger/TriggerPopoverAction.tsx +10 -13
- package/src/primitives/composer/trigger/TriggerPopoverCategories.tsx +2 -2
- package/src/primitives/composer/trigger/TriggerPopoverDirective.tsx +11 -14
- package/src/primitives/composer/trigger/TriggerPopoverExports.test.ts +61 -0
- package/src/primitives/composer/trigger/TriggerPopoverItems.tsx +3 -3
- package/src/primitives/composer/trigger/TriggerPopoverRootContext.tsx +8 -8
- package/src/primitives/composer.ts +21 -1
- package/src/primitives/message/MessageRoot.test.tsx +125 -2
- package/src/primitives/thread/ThreadLoadEarlier.tsx +35 -0
- package/src/primitives/thread/ThreadMessages.tsx +1 -0
- package/src/primitives/thread/useThreadViewportAutoScroll.test.tsx +256 -5
- package/src/primitives/thread/useThreadViewportAutoScroll.ts +147 -1
- package/src/primitives/thread.ts +2 -0
- package/src/sandbox-host/SandboxHost.test.tsx +34 -0
- package/src/sandbox-host/SandboxHost.tsx +8 -4
- package/src/tests/toolCallTiming.test.tsx +19 -2
- package/src/unstable/useMessageStallDetection.test.tsx +40 -0
- package/src/unstable/useMessageStallDetection.ts +10 -6
- package/src/utils/smooth/useSmooth.test.tsx +16 -5
- package/src/utils/smooth/useSmooth.ts +7 -7
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { renderToString } from "react-dom/server";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
const { message } = vi.hoisted(() => ({
|
|
7
|
+
message: {
|
|
8
|
+
status: { type: "running" as const },
|
|
9
|
+
content: [{ type: "text" as const, text: "streaming" }],
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
vi.mock("@assistant-ui/store", async (importOriginal) => ({
|
|
14
|
+
...(await importOriginal<typeof import("@assistant-ui/store")>()),
|
|
15
|
+
useAuiState: (selector: (state: { message: typeof message }) => unknown) =>
|
|
16
|
+
selector({ message }),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock("@assistant-ui/store/internal", async (importOriginal) => ({
|
|
20
|
+
...(await importOriginal<typeof import("@assistant-ui/store/internal")>()),
|
|
21
|
+
useShallowSelector: <T,>(selector: T) => selector,
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
import { unstable_useMessageStallDetection } from "./useMessageStallDetection";
|
|
25
|
+
|
|
26
|
+
describe("unstable_useMessageStallDetection", () => {
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.restoreAllMocks();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("does not read the wall clock during server render", () => {
|
|
32
|
+
const nowSpy = vi.spyOn(Date, "now");
|
|
33
|
+
const Probe = () => (
|
|
34
|
+
<span>{String(unstable_useMessageStallDetection().stalled)}</span>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(renderToString(<Probe />)).toBe("<span>false</span>");
|
|
38
|
+
expect(nowSpy).not.toHaveBeenCalled();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -57,9 +57,9 @@ export function unstable_useMessageStallDetection(
|
|
|
57
57
|
);
|
|
58
58
|
|
|
59
59
|
const running = activity[0] === true;
|
|
60
|
-
const lastActivityRef = useRef(
|
|
60
|
+
const lastActivityRef = useRef(0);
|
|
61
61
|
const [stalled, setStalled] = useState(false);
|
|
62
|
-
const [,
|
|
62
|
+
const [now, setNow] = useState(0);
|
|
63
63
|
|
|
64
64
|
useEffect(() => {
|
|
65
65
|
if (!running) return undefined;
|
|
@@ -73,26 +73,30 @@ export function unstable_useMessageStallDetection(
|
|
|
73
73
|
return undefined;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
const stall = () => {
|
|
77
|
+
setNow(Date.now());
|
|
78
|
+
setStalled(true);
|
|
79
|
+
};
|
|
76
80
|
const sinceActivity = Date.now() - lastActivityRef.current;
|
|
77
81
|
if (sinceActivity >= thresholdMs) {
|
|
78
|
-
|
|
82
|
+
stall();
|
|
79
83
|
return undefined;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
setStalled(false);
|
|
83
|
-
const id = setTimeout(
|
|
87
|
+
const id = setTimeout(stall, thresholdMs - sinceActivity);
|
|
84
88
|
return () => clearTimeout(id);
|
|
85
89
|
}, [running, activity, thresholdMs]);
|
|
86
90
|
|
|
87
91
|
useEffect(() => {
|
|
88
92
|
if (!stalled) return undefined;
|
|
89
|
-
const id = setInterval(() =>
|
|
93
|
+
const id = setInterval(() => setNow(Date.now()), 1000);
|
|
90
94
|
return () => clearInterval(id);
|
|
91
95
|
}, [stalled]);
|
|
92
96
|
|
|
93
97
|
if (!stalled) return { stalled: false, stalledForMs: 0 };
|
|
94
98
|
return {
|
|
95
99
|
stalled: true,
|
|
96
|
-
stalledForMs: Math.max(0,
|
|
100
|
+
stalledForMs: Math.max(0, now - lastActivityRef.current),
|
|
97
101
|
};
|
|
98
102
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** @vitest-environment jsdom */
|
|
2
2
|
import { act, renderHook } from "@testing-library/react";
|
|
3
|
+
import { renderToString } from "react-dom/server";
|
|
3
4
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
5
|
import type {
|
|
5
6
|
MessagePartState,
|
|
@@ -68,7 +69,7 @@ const driveAndCount = (minCommitMs: number) => {
|
|
|
68
69
|
.spyOn(globalThis, "cancelAnimationFrame")
|
|
69
70
|
.mockImplementation(() => {});
|
|
70
71
|
let now = 1000;
|
|
71
|
-
const nowSpy = vi.spyOn(
|
|
72
|
+
const nowSpy = vi.spyOn(performance, "now").mockImplementation(() => now);
|
|
72
73
|
|
|
73
74
|
const state = runningState("0123456789");
|
|
74
75
|
const { result, unmount } = renderHook(() =>
|
|
@@ -105,6 +106,16 @@ describe("useSmooth", () => {
|
|
|
105
106
|
Reflect.deleteProperty(window, "matchMedia");
|
|
106
107
|
});
|
|
107
108
|
|
|
109
|
+
it("does not read the wall clock during server render", () => {
|
|
110
|
+
const nowSpy = vi.spyOn(Date, "now");
|
|
111
|
+
const Probe = () => (
|
|
112
|
+
<span>{useSmooth(runningState("streaming"), true).text}</span>
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
expect(renderToString(<Probe />)).toBe("<span></span>");
|
|
116
|
+
expect(nowSpy).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
|
|
108
119
|
it("returns the input state unchanged when disabled", () => {
|
|
109
120
|
const state = textState("hello");
|
|
110
121
|
const { result } = renderHook(() => useSmooth(state, false));
|
|
@@ -189,8 +200,8 @@ describe("useSmooth", () => {
|
|
|
189
200
|
return raf.length;
|
|
190
201
|
});
|
|
191
202
|
vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
|
|
192
|
-
let now =
|
|
193
|
-
vi.spyOn(
|
|
203
|
+
let now = 0;
|
|
204
|
+
vi.spyOn(performance, "now").mockImplementation(() => now);
|
|
194
205
|
|
|
195
206
|
const frame = () => {
|
|
196
207
|
if (raf.length === 0) return;
|
|
@@ -246,7 +257,7 @@ describe("useSmooth", () => {
|
|
|
246
257
|
});
|
|
247
258
|
vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
|
|
248
259
|
let now = 1000;
|
|
249
|
-
vi.spyOn(
|
|
260
|
+
vi.spyOn(performance, "now").mockImplementation(() => now);
|
|
250
261
|
|
|
251
262
|
const frame = () => {
|
|
252
263
|
if (raf.length === 0) return;
|
|
@@ -297,7 +308,7 @@ describe("useSmooth", () => {
|
|
|
297
308
|
});
|
|
298
309
|
vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
|
|
299
310
|
let now = 1000;
|
|
300
|
-
vi.spyOn(
|
|
311
|
+
vi.spyOn(performance, "now").mockImplementation(() => now);
|
|
301
312
|
|
|
302
313
|
const frame = () => {
|
|
303
314
|
if (raf.length === 0) return;
|
|
@@ -49,8 +49,8 @@ const DEFAULT_MAX_CHAR_INTERVAL_MS = 5;
|
|
|
49
49
|
|
|
50
50
|
class TextStreamAnimator {
|
|
51
51
|
private animationFrameId: number | null = null;
|
|
52
|
-
private lastUpdateTime: number =
|
|
53
|
-
public lastCommitTime: number =
|
|
52
|
+
private lastUpdateTime: number = 0;
|
|
53
|
+
public lastCommitTime: number = -Infinity;
|
|
54
54
|
|
|
55
55
|
public targetText: string = "";
|
|
56
56
|
public drainMs: number = DEFAULT_DRAIN_MS;
|
|
@@ -68,7 +68,7 @@ class TextStreamAnimator {
|
|
|
68
68
|
|
|
69
69
|
start() {
|
|
70
70
|
if (this.animationFrameId !== null) return;
|
|
71
|
-
this.lastUpdateTime =
|
|
71
|
+
this.lastUpdateTime = performance.now();
|
|
72
72
|
this.animate();
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -80,7 +80,7 @@ class TextStreamAnimator {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
private animate = () => {
|
|
83
|
-
const currentTime =
|
|
83
|
+
const currentTime = performance.now();
|
|
84
84
|
const deltaTime = currentTime - this.lastUpdateTime;
|
|
85
85
|
let timeToConsume = deltaTime;
|
|
86
86
|
|
|
@@ -214,8 +214,8 @@ export const useSmooth = (
|
|
|
214
214
|
}
|
|
215
215
|
}, [smoothStatusStore, enabled, text, displayedText, state.status]);
|
|
216
216
|
|
|
217
|
-
const [animatorRef] = useState
|
|
218
|
-
new TextStreamAnimator(displayedText, setText),
|
|
217
|
+
const [animatorRef] = useState(
|
|
218
|
+
() => new TextStreamAnimator(displayedText, setText),
|
|
219
219
|
);
|
|
220
220
|
|
|
221
221
|
useEffect(() => {
|
|
@@ -240,7 +240,7 @@ export const useSmooth = (
|
|
|
240
240
|
if (state.status.type === "running") {
|
|
241
241
|
animatorRef.currentText = "";
|
|
242
242
|
animatorRef.targetText = text;
|
|
243
|
-
animatorRef.lastCommitTime =
|
|
243
|
+
animatorRef.lastCommitTime = -Infinity;
|
|
244
244
|
animatorRef.start();
|
|
245
245
|
} else {
|
|
246
246
|
animatorRef.currentText = text;
|