@assistant-ui/react 0.11.21 → 0.11.22
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/augmentations.d.ts +20 -9
- package/dist/augmentations.d.ts.map +1 -1
- package/dist/client/AssistantClient.d.ts +6 -7
- package/dist/client/AssistantClient.d.ts.map +1 -1
- package/dist/client/AssistantClient.js +9 -4
- package/dist/client/AssistantClient.js.map +1 -1
- package/dist/client/NoOpComposerClient.d.ts +9 -0
- package/dist/client/NoOpComposerClient.d.ts.map +1 -0
- package/dist/client/NoOpComposerClient.js +59 -0
- package/dist/client/NoOpComposerClient.js.map +1 -0
- package/dist/client/ThreadMessageClient.d.ts +14 -0
- package/dist/client/ThreadMessageClient.d.ts.map +1 -0
- package/dist/client/ThreadMessageClient.js +140 -0
- package/dist/client/ThreadMessageClient.js.map +1 -0
- package/dist/client/types/Part.d.ts +5 -0
- package/dist/client/types/Part.d.ts.map +1 -1
- package/dist/client/types/Thread.d.ts +8 -0
- package/dist/client/types/Thread.d.ts.map +1 -1
- package/dist/context/providers/MessageProvider.d.ts +1 -8
- package/dist/context/providers/MessageProvider.d.ts.map +1 -1
- package/dist/context/providers/MessageProvider.js +4 -181
- package/dist/context/providers/MessageProvider.js.map +1 -1
- package/dist/context/providers/TextMessagePartProvider.d.ts.map +1 -1
- package/dist/context/providers/TextMessagePartProvider.js +3 -1
- package/dist/context/providers/TextMessagePartProvider.js.map +1 -1
- package/dist/context/react/AssistantApiContext.d.ts +3 -1
- package/dist/context/react/AssistantApiContext.d.ts.map +1 -1
- package/dist/context/react/AssistantApiContext.js +17 -4
- package/dist/context/react/AssistantApiContext.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -1
- package/dist/internal.js.map +1 -1
- package/dist/legacy-runtime/client/MessagePartRuntimeClient.d.ts.map +1 -1
- package/dist/legacy-runtime/client/MessagePartRuntimeClient.js +9 -10
- package/dist/legacy-runtime/client/MessagePartRuntimeClient.js.map +1 -1
- package/dist/legacy-runtime/client/ThreadRuntimeClient.d.ts.map +1 -1
- package/dist/legacy-runtime/client/ThreadRuntimeClient.js +6 -0
- package/dist/legacy-runtime/client/ThreadRuntimeClient.js.map +1 -1
- package/dist/legacy-runtime/hooks/AssistantContext.js +1 -1
- package/dist/legacy-runtime/hooks/AssistantContext.js.map +1 -1
- package/dist/legacy-runtime/hooks/AttachmentContext.d.ts.map +1 -1
- package/dist/legacy-runtime/hooks/AttachmentContext.js +1 -1
- package/dist/legacy-runtime/hooks/AttachmentContext.js.map +1 -1
- package/dist/legacy-runtime/hooks/ComposerContext.d.ts.map +1 -1
- package/dist/legacy-runtime/hooks/ComposerContext.js +1 -1
- package/dist/legacy-runtime/hooks/ComposerContext.js.map +1 -1
- package/dist/legacy-runtime/hooks/MessageContext.d.ts.map +1 -1
- package/dist/legacy-runtime/hooks/MessageContext.js +1 -1
- package/dist/legacy-runtime/hooks/MessageContext.js.map +1 -1
- package/dist/legacy-runtime/hooks/MessagePartContext.js +1 -1
- package/dist/legacy-runtime/hooks/MessagePartContext.js.map +1 -1
- package/dist/legacy-runtime/hooks/ThreadContext.js +1 -1
- package/dist/legacy-runtime/hooks/ThreadContext.js.map +1 -1
- package/dist/legacy-runtime/hooks/ThreadListItemContext.js +1 -1
- package/dist/legacy-runtime/hooks/ThreadListItemContext.js.map +1 -1
- package/dist/legacy-runtime/runtime/MessagePartRuntime.d.ts +6 -0
- package/dist/legacy-runtime/runtime/MessagePartRuntime.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime/MessagePartRuntime.js +13 -0
- package/dist/legacy-runtime/runtime/MessagePartRuntime.js.map +1 -1
- package/dist/legacy-runtime/runtime/ThreadRuntime.d.ts +1 -0
- package/dist/legacy-runtime/runtime/ThreadRuntime.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/types.d.ts +2 -0
- package/dist/legacy-runtime/runtime-cores/assistant-transport/types.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +5 -2
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.d.ts +2 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js +3 -3
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts +9 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js +48 -7
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/core/BaseThreadRuntimeCore.d.ts +2 -1
- package/dist/legacy-runtime/runtime-cores/core/BaseThreadRuntimeCore.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/core/BaseThreadRuntimeCore.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/core/ThreadRuntimeCore.d.ts +6 -1
- package/dist/legacy-runtime/runtime-cores/core/ThreadRuntimeCore.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreAdapter.d.ts +5 -1
- package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreAdapter.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.d.ts +2 -1
- package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.js +6 -1
- package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/auto-status.d.ts +4 -1
- package/dist/legacy-runtime/runtime-cores/external-store/auto-status.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/auto-status.js +5 -1
- package/dist/legacy-runtime/runtime-cores/external-store/auto-status.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.d.ts +3 -2
- package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.js +6 -4
- package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts +8 -3
- package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js +20 -6
- package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/local/LocalThreadRuntimeCore.d.ts +2 -1
- package/dist/legacy-runtime/runtime-cores/local/LocalThreadRuntimeCore.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/local/LocalThreadRuntimeCore.js +3 -0
- package/dist/legacy-runtime/runtime-cores/local/LocalThreadRuntimeCore.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/remote-thread-list/EMPTY_THREAD_CORE.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/remote-thread-list/EMPTY_THREAD_CORE.js +3 -0
- package/dist/legacy-runtime/runtime-cores/remote-thread-list/EMPTY_THREAD_CORE.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts +2 -0
- package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts +2 -0
- package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/utils/MessageRepository.js +1 -1
- package/dist/legacy-runtime/runtime-cores/utils/MessageRepository.js.map +1 -1
- package/dist/model-context/frame/AssistantFrameProvider.d.ts.map +1 -1
- package/dist/model-context/frame/AssistantFrameProvider.js +6 -1
- package/dist/model-context/frame/AssistantFrameProvider.js.map +1 -1
- package/dist/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/primitives/message/MessageParts.js +12 -3
- package/dist/primitives/message/MessageParts.js.map +1 -1
- package/dist/primitives/message/MessagePartsGrouped.d.ts.map +1 -1
- package/dist/primitives/message/MessagePartsGrouped.js +11 -2
- package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
- package/dist/types/AssistantTypes.d.ts +2 -2
- package/dist/types/AssistantTypes.d.ts.map +1 -1
- package/dist/types/MessagePartComponentTypes.d.ts +1 -0
- package/dist/types/MessagePartComponentTypes.d.ts.map +1 -1
- package/dist/types/MessagePartTypes.d.ts +1 -0
- package/dist/types/MessagePartTypes.d.ts.map +1 -1
- package/dist/utils/smooth/SmoothContext.d.ts +6 -6
- package/package.json +2 -2
- package/src/augmentations.ts +21 -24
- package/src/client/AssistantClient.ts +15 -8
- package/src/client/NoOpComposerClient.tsx +56 -0
- package/src/client/ThreadMessageClient.tsx +161 -0
- package/src/client/types/Attachment.ts +1 -1
- package/src/client/types/Composer.ts +1 -1
- package/src/client/types/Message.ts +1 -1
- package/src/client/types/Part.ts +7 -1
- package/src/client/types/Thread.ts +11 -1
- package/src/client/types/ThreadListItem.ts +1 -1
- package/src/context/providers/MessageProvider.tsx +4 -222
- package/src/context/providers/TextMessagePartProvider.tsx +3 -1
- package/src/context/react/AssistantApiContext.tsx +27 -5
- package/src/index.ts +3 -0
- package/src/internal.ts +4 -0
- package/src/legacy-runtime/client/MessagePartRuntimeClient.ts +12 -13
- package/src/legacy-runtime/client/ThreadRuntimeClient.ts +6 -0
- package/src/legacy-runtime/hooks/AssistantContext.ts +1 -1
- package/src/legacy-runtime/hooks/AttachmentContext.ts +3 -1
- package/src/legacy-runtime/hooks/ComposerContext.ts +3 -1
- package/src/legacy-runtime/hooks/MessageContext.ts +3 -1
- package/src/legacy-runtime/hooks/MessagePartContext.ts +1 -1
- package/src/legacy-runtime/hooks/ThreadContext.ts +1 -1
- package/src/legacy-runtime/hooks/ThreadListItemContext.ts +1 -1
- package/src/legacy-runtime/runtime/MessagePartRuntime.ts +23 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/types.ts +2 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.tsx +10 -3
- package/src/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.ts +4 -2
- package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts +73 -6
- package/src/legacy-runtime/runtime-cores/core/BaseThreadRuntimeCore.tsx +2 -0
- package/src/legacy-runtime/runtime-cores/core/ThreadRuntimeCore.tsx +7 -1
- package/src/legacy-runtime/runtime-cores/external-store/ExternalStoreAdapter.tsx +4 -1
- package/src/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.tsx +8 -1
- package/src/legacy-runtime/runtime-cores/external-store/auto-status.tsx +11 -3
- package/src/legacy-runtime/runtime-cores/external-store/createMessageConverter.tsx +9 -2
- package/src/legacy-runtime/runtime-cores/external-store/external-message-converter.tsx +33 -5
- package/src/legacy-runtime/runtime-cores/local/LocalThreadRuntimeCore.tsx +5 -0
- package/src/legacy-runtime/runtime-cores/remote-thread-list/EMPTY_THREAD_CORE.tsx +4 -0
- package/src/legacy-runtime/runtime-cores/utils/MessageRepository.tsx +1 -1
- package/src/model-context/frame/AssistantFrameProvider.ts +5 -0
- package/src/primitives/message/MessageParts.tsx +11 -3
- package/src/primitives/message/MessagePartsGrouped.tsx +10 -2
- package/src/types/AssistantTypes.ts +2 -2
- package/src/types/MessagePartComponentTypes.tsx +1 -0
- package/src/types/MessagePartTypes.ts +1 -0
@@ -30,6 +30,12 @@ export type MessagePartRuntime = {
|
|
30
30
|
*/
|
31
31
|
addToolResult(result: any | ToolResponse<any>): void;
|
32
32
|
|
33
|
+
/**
|
34
|
+
* Resume an interrupted tool call with a payload.
|
35
|
+
* This is useful when a tool has interrupted its execution and is waiting for user input.
|
36
|
+
*/
|
37
|
+
resumeToolCall(payload: unknown): void;
|
38
|
+
|
33
39
|
readonly path: MessagePartRuntimePath;
|
34
40
|
getState(): MessagePartState;
|
35
41
|
subscribe(callback: () => void): Unsubscribe;
|
@@ -50,6 +56,7 @@ export class MessagePartRuntimeImpl implements MessagePartRuntime {
|
|
50
56
|
|
51
57
|
protected __internal_bindMethods() {
|
52
58
|
this.addToolResult = this.addToolResult.bind(this);
|
59
|
+
this.resumeToolCall = this.resumeToolCall.bind(this);
|
53
60
|
this.getState = this.getState.bind(this);
|
54
61
|
this.subscribe = this.subscribe.bind(this);
|
55
62
|
}
|
@@ -88,6 +95,22 @@ export class MessagePartRuntimeImpl implements MessagePartRuntime {
|
|
88
95
|
});
|
89
96
|
}
|
90
97
|
|
98
|
+
public resumeToolCall(payload: unknown) {
|
99
|
+
const state = this.contentBinding.getState();
|
100
|
+
if (!state) throw new Error("Message part is not available");
|
101
|
+
|
102
|
+
if (state.type !== "tool-call")
|
103
|
+
throw new Error("Tried to resume tool call on non-tool message part");
|
104
|
+
|
105
|
+
if (!this.threadApi) throw new Error("Thread API is not available");
|
106
|
+
|
107
|
+
const toolCallId = state.toolCallId;
|
108
|
+
this.threadApi.getState().resumeToolCall({
|
109
|
+
toolCallId,
|
110
|
+
payload,
|
111
|
+
});
|
112
|
+
}
|
113
|
+
|
91
114
|
public subscribe(callback: () => void) {
|
92
115
|
return this.contentBinding.subscribe(callback);
|
93
116
|
}
|
@@ -2,6 +2,7 @@ import { ReadonlyJSONValue } from "assistant-stream/utils";
|
|
2
2
|
import { ThreadMessage } from "../../../types";
|
3
3
|
import { AttachmentAdapter, ThreadHistoryAdapter } from "..";
|
4
4
|
import { UserCommands } from "../../../augmentations";
|
5
|
+
import type { ToolExecutionStatus } from "./useToolInvocations";
|
5
6
|
|
6
7
|
// Message part types
|
7
8
|
export type TextPart = {
|
@@ -56,6 +57,7 @@ export type AssistantTransportState = {
|
|
56
57
|
export type AssistantTransportConnectionMetadata = {
|
57
58
|
pendingCommands: AssistantTransportCommand[];
|
58
59
|
isSending: boolean;
|
60
|
+
toolStatuses: Record<string, ToolExecutionStatus>;
|
59
61
|
};
|
60
62
|
|
61
63
|
export type AssistantTransportStateConverter<T> = (
|
package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.tsx
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
"use client";
|
2
2
|
|
3
3
|
import {
|
4
|
-
ReadonlyJSONObject,
|
5
|
-
ReadonlyJSONValue,
|
4
|
+
type ReadonlyJSONObject,
|
5
|
+
type ReadonlyJSONValue,
|
6
6
|
asAsyncIterableStream,
|
7
7
|
} from "assistant-stream/utils";
|
8
8
|
import { AppendMessage } from "../../../types";
|
@@ -26,7 +26,7 @@ import {
|
|
26
26
|
import { useCommandQueue } from "./commandQueue";
|
27
27
|
import { useRunManager } from "./runManager";
|
28
28
|
import { useConvertedState } from "./useConvertedState";
|
29
|
-
import { useToolInvocations } from "./useToolInvocations";
|
29
|
+
import { ToolExecutionStatus, useToolInvocations } from "./useToolInvocations";
|
30
30
|
import { toAISDKTools, getEnabledTools, createRequestHeaders } from "./utils";
|
31
31
|
import { useRemoteThreadListRuntime } from "../remote-thread-list/useRemoteThreadListRuntime";
|
32
32
|
import { InMemoryThreadListAdapter } from "../remote-thread-list/adapter/in-memory";
|
@@ -177,6 +177,11 @@ const useAssistantTransportThreadRuntime = <T,>(
|
|
177
177
|
},
|
178
178
|
});
|
179
179
|
|
180
|
+
// Tool execution status state
|
181
|
+
const [toolStatuses, setToolStatuses] = useState<
|
182
|
+
Record<string, ToolExecutionStatus>
|
183
|
+
>({});
|
184
|
+
|
180
185
|
// Reactive conversion of agent state + connection metadata → UI state
|
181
186
|
const pendingCommands = useMemo(
|
182
187
|
() => [...commandQueue.state.inTransit, ...commandQueue.state.queued],
|
@@ -187,6 +192,7 @@ const useAssistantTransportThreadRuntime = <T,>(
|
|
187
192
|
agentStateRef.current,
|
188
193
|
pendingCommands,
|
189
194
|
runManager.isRunning,
|
195
|
+
toolStatuses,
|
190
196
|
);
|
191
197
|
|
192
198
|
// Create runtime
|
@@ -266,6 +272,7 @@ const useAssistantTransportThreadRuntime = <T,>(
|
|
266
272
|
state: converted,
|
267
273
|
getTools: () => runtime.thread.getModelContext().tools,
|
268
274
|
onResult: commandQueue.enqueue,
|
275
|
+
setToolStatuses,
|
269
276
|
});
|
270
277
|
|
271
278
|
return runtime;
|
@@ -4,15 +4,17 @@ import type {
|
|
4
4
|
AssistantTransportState,
|
5
5
|
AssistantTransportStateConverter,
|
6
6
|
} from "./types";
|
7
|
+
import type { ToolExecutionStatus } from "./useToolInvocations";
|
7
8
|
|
8
9
|
export function useConvertedState<T>(
|
9
10
|
converter: AssistantTransportStateConverter<T>,
|
10
11
|
agentState: T,
|
11
12
|
pendingCommands: AssistantTransportCommand[],
|
12
13
|
isSending: boolean,
|
14
|
+
toolStatuses: Record<string, ToolExecutionStatus>,
|
13
15
|
): AssistantTransportState {
|
14
16
|
return useMemo(
|
15
|
-
() => converter(agentState, { pendingCommands, isSending }),
|
16
|
-
[converter, agentState, pendingCommands, isSending],
|
17
|
+
() => converter(agentState, { pendingCommands, isSending, toolStatuses }),
|
18
|
+
[converter, agentState, pendingCommands, isSending, toolStatuses],
|
17
19
|
);
|
18
20
|
}
|
@@ -12,7 +12,7 @@ import type {
|
|
12
12
|
} from "./types";
|
13
13
|
import {
|
14
14
|
AssistantMetaTransformStream,
|
15
|
-
ReadonlyJSONValue,
|
15
|
+
type ReadonlyJSONValue,
|
16
16
|
} from "assistant-stream/utils";
|
17
17
|
|
18
18
|
const isArgsTextComplete = (argsText: string) => {
|
@@ -28,12 +28,24 @@ type UseToolInvocationsParams = {
|
|
28
28
|
state: AssistantTransportState;
|
29
29
|
getTools: () => Record<string, Tool> | undefined;
|
30
30
|
onResult: (command: AssistantTransportCommand) => void;
|
31
|
+
setToolStatuses: (
|
32
|
+
updater:
|
33
|
+
| Record<string, ToolExecutionStatus>
|
34
|
+
| ((
|
35
|
+
prev: Record<string, ToolExecutionStatus>,
|
36
|
+
) => Record<string, ToolExecutionStatus>),
|
37
|
+
) => void;
|
31
38
|
};
|
32
39
|
|
40
|
+
export type ToolExecutionStatus =
|
41
|
+
| { type: "executing" }
|
42
|
+
| { type: "interrupt"; payload: unknown };
|
43
|
+
|
33
44
|
export function useToolInvocations({
|
34
45
|
state,
|
35
46
|
getTools,
|
36
47
|
onResult,
|
48
|
+
setToolStatuses,
|
37
49
|
}: UseToolInvocationsParams) {
|
38
50
|
const lastToolStates = useRef<
|
39
51
|
Record<
|
@@ -46,12 +58,39 @@ export function useToolInvocations({
|
|
46
58
|
>
|
47
59
|
>({});
|
48
60
|
|
61
|
+
const interruptedToolsRef = useRef<
|
62
|
+
Map<
|
63
|
+
string,
|
64
|
+
{
|
65
|
+
resolve: (payload: unknown) => void;
|
66
|
+
reject: (reason: unknown) => void;
|
67
|
+
}
|
68
|
+
>
|
69
|
+
>(new Map());
|
70
|
+
|
49
71
|
const acRef = useRef<AbortController>(new AbortController());
|
50
72
|
const [controller] = useState(() => {
|
51
73
|
const [stream, controller] = createAssistantStreamController();
|
52
74
|
const transform = unstable_toolResultStream(
|
53
75
|
getTools,
|
54
76
|
() => acRef.current?.signal ?? new AbortController().signal,
|
77
|
+
(toolCallId: string, payload: unknown) => {
|
78
|
+
return new Promise<unknown>((resolve, reject) => {
|
79
|
+
// Reject previous interrupt if it exists
|
80
|
+
const previous = interruptedToolsRef.current.get(toolCallId);
|
81
|
+
if (previous) {
|
82
|
+
previous.reject(
|
83
|
+
new Error("Interrupt was superseded by a new interrupt"),
|
84
|
+
);
|
85
|
+
}
|
86
|
+
|
87
|
+
interruptedToolsRef.current.set(toolCallId, { resolve, reject });
|
88
|
+
setToolStatuses((prev) => ({
|
89
|
+
...prev,
|
90
|
+
[toolCallId]: { type: "interrupt", payload },
|
91
|
+
}));
|
92
|
+
});
|
93
|
+
},
|
55
94
|
);
|
56
95
|
stream
|
57
96
|
.pipeThrough(transform)
|
@@ -72,6 +111,13 @@ export function useToolInvocations({
|
|
72
111
|
isError: chunk.isError,
|
73
112
|
...(chunk.artifact && { artifact: chunk.artifact }),
|
74
113
|
});
|
114
|
+
|
115
|
+
// Clear status when result is set
|
116
|
+
setToolStatuses((prev) => {
|
117
|
+
const next = { ...prev };
|
118
|
+
delete next[chunk.meta.toolCallId];
|
119
|
+
return next;
|
120
|
+
});
|
75
121
|
}
|
76
122
|
},
|
77
123
|
}),
|
@@ -159,15 +205,36 @@ export function useToolInvocations({
|
|
159
205
|
}
|
160
206
|
}, [state, controller, onResult]);
|
161
207
|
|
208
|
+
const abort = () => {
|
209
|
+
interruptedToolsRef.current.forEach(({ reject }) => {
|
210
|
+
reject(new Error("Tool execution aborted"));
|
211
|
+
});
|
212
|
+
interruptedToolsRef.current.clear();
|
213
|
+
setToolStatuses({});
|
214
|
+
|
215
|
+
acRef.current.abort();
|
216
|
+
acRef.current = new AbortController();
|
217
|
+
};
|
218
|
+
|
162
219
|
return {
|
163
220
|
reset: () => {
|
164
|
-
|
165
|
-
acRef.current = new AbortController();
|
221
|
+
abort();
|
166
222
|
isInititialState.current = true;
|
167
223
|
},
|
168
|
-
abort
|
169
|
-
|
170
|
-
|
224
|
+
abort,
|
225
|
+
resume: (toolCallId: string, payload: unknown) => {
|
226
|
+
const handlers = interruptedToolsRef.current.get(toolCallId);
|
227
|
+
if (handlers) {
|
228
|
+
interruptedToolsRef.current.delete(toolCallId);
|
229
|
+
setToolStatuses((prev) => {
|
230
|
+
const next = { ...prev };
|
231
|
+
delete next[toolCallId];
|
232
|
+
return next;
|
233
|
+
});
|
234
|
+
handlers.resolve(payload);
|
235
|
+
} else {
|
236
|
+
throw new Error(`Tool call ${toolCallId} is not interrupted`);
|
237
|
+
}
|
171
238
|
},
|
172
239
|
};
|
173
240
|
}
|
@@ -6,6 +6,7 @@ import {
|
|
6
6
|
import { DefaultThreadComposerRuntimeCore } from "../composer/DefaultThreadComposerRuntimeCore";
|
7
7
|
import {
|
8
8
|
AddToolResultOptions,
|
9
|
+
ResumeToolCallOptions,
|
9
10
|
ThreadSuggestion,
|
10
11
|
SubmitFeedbackOptions,
|
11
12
|
ThreadRuntimeCore,
|
@@ -46,6 +47,7 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
|
|
46
47
|
public abstract startRun(config: StartRunConfig): void;
|
47
48
|
public abstract resumeRun(config: ResumeRunConfig): void;
|
48
49
|
public abstract addToolResult(options: AddToolResultOptions): void;
|
50
|
+
public abstract resumeToolCall(options: ResumeToolCallOptions): void;
|
49
51
|
public abstract cancelRun(): void;
|
50
52
|
public abstract unstable_loadExternalState(state: any): void;
|
51
53
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ReadonlyJSONValue } from "assistant-stream/utils";
|
1
|
+
import type { ReadonlyJSONValue } from "assistant-stream/utils";
|
2
2
|
import { ModelContext } from "../../../model-context";
|
3
3
|
import { AppendMessage, ThreadMessage } from "../../../types";
|
4
4
|
import { RunConfig } from "../../../types/AssistantTypes";
|
@@ -33,6 +33,11 @@ export type AddToolResultOptions = {
|
|
33
33
|
artifact?: ReadonlyJSONValue | undefined;
|
34
34
|
};
|
35
35
|
|
36
|
+
export type ResumeToolCallOptions = {
|
37
|
+
toolCallId: string;
|
38
|
+
payload: unknown;
|
39
|
+
};
|
40
|
+
|
36
41
|
export type SubmitFeedbackOptions = {
|
37
42
|
messageId: string;
|
38
43
|
type: "negative" | "positive";
|
@@ -86,6 +91,7 @@ export type ThreadRuntimeCore = Readonly<{
|
|
86
91
|
cancelRun: () => void;
|
87
92
|
|
88
93
|
addToolResult: (options: AddToolResultOptions) => void;
|
94
|
+
resumeToolCall: (options: ResumeToolCallOptions) => void;
|
89
95
|
|
90
96
|
speak: (messageId: string) => void;
|
91
97
|
stopSpeaking: () => void;
|
@@ -10,7 +10,7 @@ import { FeedbackAdapter } from "../adapters/feedback/FeedbackAdapter";
|
|
10
10
|
import { SpeechSynthesisAdapter } from "../adapters/speech/SpeechAdapterTypes";
|
11
11
|
import { ThreadMessageLike } from "./ThreadMessageLike";
|
12
12
|
import { ExportedMessageRepository } from "../utils/MessageRepository";
|
13
|
-
import { ReadonlyJSONValue } from "assistant-stream/utils";
|
13
|
+
import type { ReadonlyJSONValue } from "assistant-stream/utils";
|
14
14
|
|
15
15
|
export type ExternalStoreThreadData<TState extends "regular" | "archived"> = {
|
16
16
|
status: TState;
|
@@ -77,6 +77,9 @@ type ExternalStoreAdapterBase<T> = {
|
|
77
77
|
onAddToolResult?:
|
78
78
|
| ((options: AddToolResultOptions) => Promise<void> | void)
|
79
79
|
| undefined;
|
80
|
+
onResumeToolCall?:
|
81
|
+
| ((options: { toolCallId: string; payload: unknown }) => void)
|
82
|
+
| undefined;
|
80
83
|
convertMessage?: ExternalStoreMessageConverter<T> | undefined;
|
81
84
|
adapters?:
|
82
85
|
| {
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import {
|
2
2
|
AddToolResultOptions,
|
3
3
|
ResumeRunConfig,
|
4
|
+
ResumeToolCallOptions,
|
4
5
|
StartRunConfig,
|
5
6
|
ThreadSuggestion,
|
6
7
|
} from "../core/ThreadRuntimeCore";
|
@@ -161,7 +162,7 @@ export class ExternalStoreThreadRuntimeCore
|
|
161
162
|
if (!store.convertMessage) return m;
|
162
163
|
|
163
164
|
const isLast = idx === store.messages!.length - 1;
|
164
|
-
const autoStatus = getAutoStatus(isLast, isRunning, false);
|
165
|
+
const autoStatus = getAutoStatus(isLast, isRunning, false, false);
|
165
166
|
|
166
167
|
if (
|
167
168
|
cache &&
|
@@ -309,6 +310,12 @@ export class ExternalStoreThreadRuntimeCore
|
|
309
310
|
this._store.onAddToolResult?.(options);
|
310
311
|
}
|
311
312
|
|
313
|
+
public resumeToolCall(options: ResumeToolCallOptions) {
|
314
|
+
if (!this._store.onResumeToolCall)
|
315
|
+
throw new Error("Runtime does not support resuming tool calls.");
|
316
|
+
this._store.onResumeToolCall(options);
|
317
|
+
}
|
318
|
+
|
312
319
|
public override reset(initialMessages?: readonly ThreadMessageLike[]) {
|
313
320
|
const repo = new MessageRepository();
|
314
321
|
repo.import(ExportedMessageRepository.fromArray(initialMessages ?? []));
|
@@ -11,16 +11,24 @@ const AUTO_STATUS_PENDING = Object.freeze({
|
|
11
11
|
reason: "tool-calls",
|
12
12
|
});
|
13
13
|
|
14
|
+
const AUTO_STATUS_SUSPENDED = Object.freeze({
|
15
|
+
type: "requires-action",
|
16
|
+
reason: "interrupt",
|
17
|
+
});
|
18
|
+
|
14
19
|
export const isAutoStatus = (status: MessageStatus) =>
|
15
20
|
status === AUTO_STATUS_RUNNING || status === AUTO_STATUS_COMPLETE;
|
16
21
|
|
17
22
|
export const getAutoStatus = (
|
18
23
|
isLast: boolean,
|
19
24
|
isRunning: boolean,
|
25
|
+
hasSuspendedToolCalls: boolean,
|
20
26
|
hasPendingToolCalls: boolean,
|
21
27
|
) =>
|
22
28
|
isLast && isRunning
|
23
29
|
? AUTO_STATUS_RUNNING
|
24
|
-
:
|
25
|
-
?
|
26
|
-
:
|
30
|
+
: hasSuspendedToolCalls
|
31
|
+
? AUTO_STATUS_SUSPENDED
|
32
|
+
: hasPendingToolCalls
|
33
|
+
? AUTO_STATUS_PENDING
|
34
|
+
: AUTO_STATUS_COMPLETE;
|
@@ -16,20 +16,27 @@ export const createMessageConverter = <T extends object>(
|
|
16
16
|
messages,
|
17
17
|
isRunning,
|
18
18
|
joinStrategy,
|
19
|
+
metadata,
|
19
20
|
}: {
|
20
21
|
messages: T[];
|
21
22
|
isRunning: boolean;
|
22
23
|
joinStrategy?: "concat-content" | "none" | undefined;
|
24
|
+
metadata?: useExternalMessageConverter.Metadata;
|
23
25
|
}) => {
|
24
26
|
return useExternalMessageConverter<T>({
|
25
27
|
callback,
|
26
28
|
messages,
|
27
29
|
isRunning,
|
28
30
|
joinStrategy,
|
31
|
+
metadata,
|
29
32
|
});
|
30
33
|
},
|
31
|
-
toThreadMessages: (
|
32
|
-
|
34
|
+
toThreadMessages: (
|
35
|
+
messages: T[],
|
36
|
+
isRunning = false,
|
37
|
+
metadata: useExternalMessageConverter.Metadata = {},
|
38
|
+
) => {
|
39
|
+
return convertExternalMessages(messages, callback, isRunning, metadata);
|
33
40
|
},
|
34
41
|
toOriginalMessages: (
|
35
42
|
input: ThreadState | ThreadMessage | ThreadMessage["content"][number],
|
@@ -9,6 +9,7 @@ import {
|
|
9
9
|
import { fromThreadMessageLike, ThreadMessageLike } from "./ThreadMessageLike";
|
10
10
|
import { getAutoStatus, isAutoStatus } from "./auto-status";
|
11
11
|
import { ToolCallMessagePart } from "../../../types";
|
12
|
+
import { ToolExecutionStatus } from "../assistant-transport/useToolInvocations";
|
12
13
|
|
13
14
|
export namespace useExternalMessageConverter {
|
14
15
|
export type Message =
|
@@ -26,7 +27,14 @@ export namespace useExternalMessageConverter {
|
|
26
27
|
isError?: boolean;
|
27
28
|
};
|
28
29
|
|
29
|
-
export type
|
30
|
+
export type Metadata = {
|
31
|
+
readonly toolStatuses?: Record<string, ToolExecutionStatus>;
|
32
|
+
};
|
33
|
+
|
34
|
+
export type Callback<T> = (
|
35
|
+
message: T,
|
36
|
+
metadata: Metadata,
|
37
|
+
) => Message | Message[];
|
30
38
|
}
|
31
39
|
|
32
40
|
type CallbackResult<T> = {
|
@@ -218,10 +226,11 @@ export const convertExternalMessages = <T extends WeakKey>(
|
|
218
226
|
messages: T[],
|
219
227
|
callback: useExternalMessageConverter.Callback<T>,
|
220
228
|
isRunning: boolean,
|
229
|
+
metadata: useExternalMessageConverter.Metadata,
|
221
230
|
) => {
|
222
231
|
const callbackResults: CallbackResult<T>[] = [];
|
223
232
|
for (const message of messages) {
|
224
|
-
const output = callback(message);
|
233
|
+
const output = callback(message, metadata);
|
225
234
|
const outputs = Array.isArray(output) ? output : [output];
|
226
235
|
const result = { input: message, outputs };
|
227
236
|
callbackResults.push(result);
|
@@ -232,12 +241,22 @@ export const convertExternalMessages = <T extends WeakKey>(
|
|
232
241
|
return chunks.map((message, idx) => {
|
233
242
|
const isLast = idx === chunks.length - 1;
|
234
243
|
const joined = joinExternalMessages(message.outputs);
|
244
|
+
const hasSuspendedToolCalls =
|
245
|
+
typeof joined.content === "object" &&
|
246
|
+
joined.content.some(
|
247
|
+
(c) => c.type === "tool-call" && c.result === undefined,
|
248
|
+
);
|
235
249
|
const hasPendingToolCalls =
|
236
250
|
typeof joined.content === "object" &&
|
237
251
|
joined.content.some(
|
238
252
|
(c) => c.type === "tool-call" && c.result === undefined,
|
239
253
|
);
|
240
|
-
const autoStatus = getAutoStatus(
|
254
|
+
const autoStatus = getAutoStatus(
|
255
|
+
isLast,
|
256
|
+
isRunning,
|
257
|
+
hasSuspendedToolCalls,
|
258
|
+
hasPendingToolCalls,
|
259
|
+
);
|
241
260
|
const newMessage = fromThreadMessageLike(
|
242
261
|
joined,
|
243
262
|
idx.toString(),
|
@@ -253,14 +272,17 @@ export const useExternalMessageConverter = <T extends WeakKey>({
|
|
253
272
|
messages,
|
254
273
|
isRunning,
|
255
274
|
joinStrategy,
|
275
|
+
metadata,
|
256
276
|
}: {
|
257
277
|
callback: useExternalMessageConverter.Callback<T>;
|
258
278
|
messages: T[];
|
259
279
|
isRunning: boolean;
|
260
280
|
joinStrategy?: "concat-content" | "none" | undefined;
|
281
|
+
metadata?: useExternalMessageConverter.Metadata | undefined;
|
261
282
|
}) => {
|
262
283
|
const state = useMemo(
|
263
284
|
() => ({
|
285
|
+
metadata: metadata ?? {},
|
264
286
|
callback,
|
265
287
|
callbackCache: new WeakMap<T, CallbackResult<T>>(),
|
266
288
|
chunkCache: new WeakMap<
|
@@ -269,7 +291,7 @@ export const useExternalMessageConverter = <T extends WeakKey>({
|
|
269
291
|
>(),
|
270
292
|
converterCache: new ThreadMessageConverter(),
|
271
293
|
}),
|
272
|
-
[callback],
|
294
|
+
[callback, metadata],
|
273
295
|
);
|
274
296
|
|
275
297
|
return useMemo(() => {
|
@@ -277,7 +299,7 @@ export const useExternalMessageConverter = <T extends WeakKey>({
|
|
277
299
|
for (const message of messages) {
|
278
300
|
let result = state.callbackCache.get(message);
|
279
301
|
if (!result) {
|
280
|
-
const output = state.callback(message);
|
302
|
+
const output = state.callback(message, state.metadata);
|
281
303
|
const outputs = Array.isArray(output) ? output : [output];
|
282
304
|
result = { input: message, outputs };
|
283
305
|
state.callbackCache.set(message, result);
|
@@ -304,6 +326,11 @@ export const useExternalMessageConverter = <T extends WeakKey>({
|
|
304
326
|
const isLast = idx === chunks.length - 1;
|
305
327
|
|
306
328
|
const joined = joinExternalMessages(message.outputs);
|
329
|
+
const hasSuspendedToolCalls =
|
330
|
+
typeof joined.content === "object" &&
|
331
|
+
joined.content.some(
|
332
|
+
(c) => c.type === "tool-call" && c.result === undefined,
|
333
|
+
);
|
307
334
|
const hasPendingToolCalls =
|
308
335
|
typeof joined.content === "object" &&
|
309
336
|
joined.content.some(
|
@@ -312,6 +339,7 @@ export const useExternalMessageConverter = <T extends WeakKey>({
|
|
312
339
|
const autoStatus = getAutoStatus(
|
313
340
|
isLast,
|
314
341
|
isRunning,
|
342
|
+
hasSuspendedToolCalls,
|
315
343
|
hasPendingToolCalls,
|
316
344
|
);
|
317
345
|
|
@@ -5,6 +5,7 @@ import { shouldContinue } from "./shouldContinue";
|
|
5
5
|
import { LocalRuntimeOptionsBase } from "./LocalRuntimeOptions";
|
6
6
|
import {
|
7
7
|
AddToolResultOptions,
|
8
|
+
ResumeToolCallOptions,
|
8
9
|
ThreadSuggestion,
|
9
10
|
ThreadRuntimeCore,
|
10
11
|
StartRunConfig,
|
@@ -463,4 +464,8 @@ export class LocalThreadRuntimeCore
|
|
463
464
|
this.performRoundtrip(parentId, message, this._lastRunConfig);
|
464
465
|
}
|
465
466
|
}
|
467
|
+
|
468
|
+
public resumeToolCall(_options: ResumeToolCallOptions) {
|
469
|
+
throw new Error("Local runtime does not support resuming tool calls.");
|
470
|
+
}
|
466
471
|
}
|
@@ -133,6 +133,11 @@ export class AssistantFrameProvider {
|
|
133
133
|
? await tool.execute(message.args, {
|
134
134
|
toolCallId: message.id,
|
135
135
|
abortSignal: new AbortController().signal,
|
136
|
+
interrupt: async () => {
|
137
|
+
throw new Error(
|
138
|
+
"Tool interrupt is not supported in frame context",
|
139
|
+
);
|
140
|
+
},
|
136
141
|
})
|
137
142
|
: undefined;
|
138
143
|
} catch (e) {
|
@@ -241,11 +241,19 @@ const MessagePartComponent: FC<MessagePartComponentProps> = ({
|
|
241
241
|
|
242
242
|
const type = part.type;
|
243
243
|
if (type === "tool-call") {
|
244
|
-
const addResult =
|
244
|
+
const addResult = api.part().addToolResult;
|
245
|
+
const resume = api.part().resumeToolCall;
|
245
246
|
if ("Override" in tools)
|
246
|
-
return <tools.Override {...part} addResult={addResult} />;
|
247
|
+
return <tools.Override {...part} addResult={addResult} resume={resume} />;
|
247
248
|
const Tool = tools.by_name?.[part.toolName] ?? tools.Fallback;
|
248
|
-
return
|
249
|
+
return (
|
250
|
+
<ToolUIDisplay
|
251
|
+
{...part}
|
252
|
+
Fallback={Tool}
|
253
|
+
addResult={addResult}
|
254
|
+
resume={resume}
|
255
|
+
/>
|
256
|
+
);
|
249
257
|
}
|
250
258
|
|
251
259
|
if (part.status?.type === "requires-action")
|
@@ -267,10 +267,18 @@ const MessagePartComponent: FC<MessagePartComponentProps> = ({
|
|
267
267
|
const type = part.type;
|
268
268
|
if (type === "tool-call") {
|
269
269
|
const addResult = (result: any) => api.part().addToolResult(result);
|
270
|
+
const resume = api.part().resumeToolCall;
|
270
271
|
if ("Override" in tools)
|
271
|
-
return <tools.Override {...part} addResult={addResult} />;
|
272
|
+
return <tools.Override {...part} addResult={addResult} resume={resume} />;
|
272
273
|
const Tool = tools.by_name?.[part.toolName] ?? tools.Fallback;
|
273
|
-
return
|
274
|
+
return (
|
275
|
+
<ToolUIDisplay
|
276
|
+
{...part}
|
277
|
+
Fallback={Tool}
|
278
|
+
addResult={addResult}
|
279
|
+
resume={resume}
|
280
|
+
/>
|
281
|
+
);
|
274
282
|
}
|
275
283
|
|
276
284
|
if (part.status?.type === "requires-action")
|
@@ -64,7 +64,7 @@ export type MessagePartStatus =
|
|
64
64
|
export type ToolCallMessagePartStatus =
|
65
65
|
| {
|
66
66
|
readonly type: "requires-action";
|
67
|
-
readonly reason: "
|
67
|
+
readonly reason: "interrupt";
|
68
68
|
}
|
69
69
|
| MessagePartStatus;
|
70
70
|
|
@@ -74,7 +74,7 @@ export type MessageStatus =
|
|
74
74
|
}
|
75
75
|
| {
|
76
76
|
readonly type: "requires-action";
|
77
|
-
readonly reason: "tool-calls";
|
77
|
+
readonly reason: "tool-calls" | "interrupt";
|
78
78
|
}
|
79
79
|
| {
|
80
80
|
readonly type: "complete";
|
@@ -44,6 +44,7 @@ export type ToolCallMessagePartProps<
|
|
44
44
|
> = MessagePartState &
|
45
45
|
ToolCallMessagePart<TArgs, TResult> & {
|
46
46
|
addResult: (result: TResult | ToolResponse<TResult>) => void;
|
47
|
+
resume: (payload: unknown) => void;
|
47
48
|
};
|
48
49
|
|
49
50
|
export type ToolCallMessagePartComponent<
|