@assistant-ui/react 0.11.34 → 0.11.36

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.
Files changed (216) hide show
  1. package/dist/augmentations.d.ts +9 -0
  2. package/dist/augmentations.d.ts.map +1 -1
  3. package/dist/client/AssistantClient.d.ts +13 -57
  4. package/dist/client/AssistantClient.d.ts.map +1 -1
  5. package/dist/client/AssistantClient.js +49 -26
  6. package/dist/client/AssistantClient.js.map +1 -1
  7. package/dist/client/ModelContext.d.ts +8 -0
  8. package/dist/client/ModelContext.d.ts.map +1 -0
  9. package/dist/client/ModelContext.js +21 -0
  10. package/dist/client/ModelContext.js.map +1 -0
  11. package/dist/client/ModelContextClient.d.ts +7 -0
  12. package/dist/client/ModelContextClient.d.ts.map +1 -0
  13. package/dist/client/ModelContextClient.js +18 -0
  14. package/dist/client/ModelContextClient.js.map +1 -0
  15. package/dist/client/ToolUIClient.d.ts.map +1 -1
  16. package/dist/client/ToolUIClient.js +45 -3
  17. package/dist/client/ToolUIClient.js.map +1 -1
  18. package/dist/client/ToolUIContext.d.ts +4 -0
  19. package/dist/client/ToolUIContext.d.ts.map +1 -0
  20. package/dist/client/ToolUIContext.js +20 -0
  21. package/dist/client/ToolUIContext.js.map +1 -0
  22. package/dist/client/Tools.d.ts +10 -0
  23. package/dist/client/Tools.d.ts.map +1 -0
  24. package/dist/client/Tools.js +55 -0
  25. package/dist/client/Tools.js.map +1 -0
  26. package/dist/client/types/ModelContext.d.ts +12 -0
  27. package/dist/client/types/ModelContext.d.ts.map +1 -0
  28. package/dist/client/types/ModelContext.js +1 -0
  29. package/dist/client/types/ModelContext.js.map +1 -0
  30. package/dist/client/types/ThreadList.d.ts.map +1 -1
  31. package/dist/client/types/ToolUI.d.ts +12 -1
  32. package/dist/client/types/ToolUI.d.ts.map +1 -1
  33. package/dist/client/types/Tools.d.ts +9 -0
  34. package/dist/client/types/Tools.d.ts.map +1 -0
  35. package/dist/client/types/Tools.js +1 -0
  36. package/dist/client/types/Tools.js.map +1 -0
  37. package/dist/context/providers/AttachmentByIndexProvider.d.ts.map +1 -1
  38. package/dist/context/providers/AttachmentByIndexProvider.js +20 -24
  39. package/dist/context/providers/AttachmentByIndexProvider.js.map +1 -1
  40. package/dist/context/providers/MessageByIndexProvider.d.ts.map +1 -1
  41. package/dist/context/providers/MessageByIndexProvider.js +27 -29
  42. package/dist/context/providers/MessageByIndexProvider.js.map +1 -1
  43. package/dist/context/providers/MessageProvider.d.ts.map +1 -1
  44. package/dist/context/providers/MessageProvider.js +11 -13
  45. package/dist/context/providers/MessageProvider.js.map +1 -1
  46. package/dist/context/providers/PartByIndexProvider.d.ts.map +1 -1
  47. package/dist/context/providers/PartByIndexProvider.js +11 -13
  48. package/dist/context/providers/PartByIndexProvider.js.map +1 -1
  49. package/dist/context/providers/TextMessagePartProvider.d.ts.map +1 -1
  50. package/dist/context/providers/TextMessagePartProvider.js +11 -13
  51. package/dist/context/providers/TextMessagePartProvider.js.map +1 -1
  52. package/dist/context/providers/ThreadListItemProvider.d.ts.map +1 -1
  53. package/dist/context/providers/ThreadListItemProvider.js +41 -45
  54. package/dist/context/providers/ThreadListItemProvider.js.map +1 -1
  55. package/dist/context/react/AssistantApiContext.d.ts +33 -4
  56. package/dist/context/react/AssistantApiContext.d.ts.map +1 -1
  57. package/dist/context/react/AssistantApiContext.js +35 -17
  58. package/dist/context/react/AssistantApiContext.js.map +1 -1
  59. package/dist/context/react/index.d.ts +1 -1
  60. package/dist/context/react/index.d.ts.map +1 -1
  61. package/dist/context/react/index.js +5 -1
  62. package/dist/context/react/index.js.map +1 -1
  63. package/dist/legacy-runtime/AssistantRuntimeProvider.d.ts.map +1 -1
  64. package/dist/legacy-runtime/AssistantRuntimeProvider.js +7 -9
  65. package/dist/legacy-runtime/AssistantRuntimeProvider.js.map +1 -1
  66. package/dist/legacy-runtime/RuntimeAdapter.d.ts +7 -0
  67. package/dist/legacy-runtime/RuntimeAdapter.d.ts.map +1 -0
  68. package/dist/legacy-runtime/RuntimeAdapter.js +20 -0
  69. package/dist/legacy-runtime/RuntimeAdapter.js.map +1 -0
  70. package/dist/legacy-runtime/client/ThreadListRuntimeClient.d.ts +2 -0
  71. package/dist/legacy-runtime/client/ThreadListRuntimeClient.d.ts.map +1 -1
  72. package/dist/legacy-runtime/client/ThreadListRuntimeClient.js +6 -2
  73. package/dist/legacy-runtime/client/ThreadListRuntimeClient.js.map +1 -1
  74. package/dist/legacy-runtime/hooks/AssistantContext.d.ts +14 -1
  75. package/dist/legacy-runtime/hooks/AssistantContext.d.ts.map +1 -1
  76. package/dist/legacy-runtime/hooks/AssistantContext.js +1 -1
  77. package/dist/legacy-runtime/hooks/AssistantContext.js.map +1 -1
  78. package/dist/legacy-runtime/hooks/AttachmentContext.d.ts +6 -0
  79. package/dist/legacy-runtime/hooks/AttachmentContext.d.ts.map +1 -1
  80. package/dist/legacy-runtime/hooks/AttachmentContext.js.map +1 -1
  81. package/dist/legacy-runtime/hooks/ComposerContext.d.ts +41 -2
  82. package/dist/legacy-runtime/hooks/ComposerContext.d.ts.map +1 -1
  83. package/dist/legacy-runtime/hooks/ComposerContext.js.map +1 -1
  84. package/dist/legacy-runtime/hooks/MessageContext.d.ts +36 -2
  85. package/dist/legacy-runtime/hooks/MessageContext.d.ts.map +1 -1
  86. package/dist/legacy-runtime/hooks/MessageContext.js.map +1 -1
  87. package/dist/legacy-runtime/hooks/MessagePartContext.d.ts +6 -0
  88. package/dist/legacy-runtime/hooks/MessagePartContext.d.ts.map +1 -1
  89. package/dist/legacy-runtime/hooks/MessagePartContext.js.map +1 -1
  90. package/dist/legacy-runtime/hooks/ThreadContext.d.ts +26 -1
  91. package/dist/legacy-runtime/hooks/ThreadContext.d.ts.map +1 -1
  92. package/dist/legacy-runtime/hooks/ThreadContext.js.map +1 -1
  93. package/dist/legacy-runtime/hooks/ThreadListItemContext.d.ts +6 -0
  94. package/dist/legacy-runtime/hooks/ThreadListItemContext.d.ts.map +1 -1
  95. package/dist/legacy-runtime/hooks/ThreadListItemContext.js.map +1 -1
  96. package/dist/legacy-runtime/runtime-cores/assistant-transport/index.d.ts +2 -2
  97. package/dist/legacy-runtime/runtime-cores/assistant-transport/index.d.ts.map +1 -1
  98. package/dist/legacy-runtime/runtime-cores/assistant-transport/index.js +4 -2
  99. package/dist/legacy-runtime/runtime-cores/assistant-transport/index.js.map +1 -1
  100. package/dist/legacy-runtime/runtime-cores/assistant-transport/types.d.ts +2 -0
  101. package/dist/legacy-runtime/runtime-cores/assistant-transport/types.d.ts.map +1 -1
  102. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts +3 -0
  103. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  104. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +14 -4
  105. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  106. package/dist/legacy-runtime/runtime-cores/core/AssistantRuntimeCore.d.ts +1 -0
  107. package/dist/legacy-runtime/runtime-cores/core/AssistantRuntimeCore.d.ts.map +1 -1
  108. package/dist/legacy-runtime/runtime-cores/core/BaseAssistantRuntimeCore.d.ts +1 -0
  109. package/dist/legacy-runtime/runtime-cores/core/BaseAssistantRuntimeCore.d.ts.map +1 -1
  110. package/dist/legacy-runtime/runtime-cores/core/BaseAssistantRuntimeCore.js +3 -0
  111. package/dist/legacy-runtime/runtime-cores/core/BaseAssistantRuntimeCore.js.map +1 -1
  112. package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadListRuntimeCore.d.ts +4 -1
  113. package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadListRuntimeCore.d.ts.map +1 -1
  114. package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadListRuntimeCore.js +2 -2
  115. package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadListRuntimeCore.js.map +1 -1
  116. package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.d.ts.map +1 -1
  117. package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.js +7 -1
  118. package/dist/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.js.map +1 -1
  119. package/dist/legacy-runtime/runtime-cores/external-store/auto-status.d.ts +2 -12
  120. package/dist/legacy-runtime/runtime-cores/external-store/auto-status.d.ts.map +1 -1
  121. package/dist/legacy-runtime/runtime-cores/external-store/auto-status.js +45 -15
  122. package/dist/legacy-runtime/runtime-cores/external-store/auto-status.js.map +1 -1
  123. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts +2 -0
  124. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts.map +1 -1
  125. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js +4 -2
  126. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js.map +1 -1
  127. package/dist/legacy-runtime/runtime-cores/local/LocalThreadListRuntimeCore.d.ts +4 -1
  128. package/dist/legacy-runtime/runtime-cores/local/LocalThreadListRuntimeCore.d.ts.map +1 -1
  129. package/dist/legacy-runtime/runtime-cores/local/LocalThreadListRuntimeCore.js +2 -2
  130. package/dist/legacy-runtime/runtime-cores/local/LocalThreadListRuntimeCore.js.map +1 -1
  131. package/dist/legacy-runtime/runtime-cores/utils/MessageRepository.js +1 -1
  132. package/dist/legacy-runtime/runtime-cores/utils/MessageRepository.js.map +1 -1
  133. package/dist/model-context/index.d.ts +2 -0
  134. package/dist/model-context/index.d.ts.map +1 -1
  135. package/dist/model-context/index.js +6 -0
  136. package/dist/model-context/index.js.map +1 -1
  137. package/dist/model-context/makeAssistantVisible.js +1 -1
  138. package/dist/model-context/makeAssistantVisible.js.map +1 -1
  139. package/dist/model-context/toolbox.d.ts +28 -0
  140. package/dist/model-context/toolbox.d.ts.map +1 -0
  141. package/dist/model-context/toolbox.js +15 -0
  142. package/dist/model-context/toolbox.js.map +1 -0
  143. package/dist/model-context/useAssistantInstructions.js +1 -1
  144. package/dist/model-context/useAssistantInstructions.js.map +1 -1
  145. package/dist/model-context/useAssistantTool.js +1 -1
  146. package/dist/model-context/useAssistantTool.js.map +1 -1
  147. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  148. package/dist/primitives/message/MessageParts.js +2 -2
  149. package/dist/primitives/message/MessageParts.js.map +1 -1
  150. package/dist/primitives/message/MessagePartsGrouped.d.ts.map +1 -1
  151. package/dist/primitives/message/MessagePartsGrouped.js +2 -2
  152. package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
  153. package/dist/tests/setup.js +8 -11
  154. package/dist/tests/setup.js.map +1 -1
  155. package/dist/utils/tap-store/derived-scopes.d.ts +81 -0
  156. package/dist/utils/tap-store/derived-scopes.d.ts.map +1 -0
  157. package/dist/utils/tap-store/derived-scopes.js +67 -0
  158. package/dist/utils/tap-store/derived-scopes.js.map +1 -0
  159. package/dist/utils/tap-store/index.d.ts +1 -0
  160. package/dist/utils/tap-store/index.d.ts.map +1 -1
  161. package/dist/utils/tap-store/index.js +4 -0
  162. package/dist/utils/tap-store/index.js.map +1 -1
  163. package/dist/utils/tap-store/tap-api.js +1 -1
  164. package/dist/utils/tap-store/tap-api.js.map +1 -1
  165. package/package.json +9 -9
  166. package/src/augmentations.ts +12 -0
  167. package/src/client/AssistantClient.ts +64 -38
  168. package/src/client/ModelContext.ts +28 -0
  169. package/src/client/ModelContextClient.ts +16 -0
  170. package/src/client/ToolUIClient.ts +50 -3
  171. package/src/client/ToolUIContext.ts +22 -0
  172. package/src/client/Tools.ts +68 -0
  173. package/src/client/types/ModelContext.ts +15 -0
  174. package/src/client/types/ThreadList.ts +4 -0
  175. package/src/client/types/ToolUI.ts +10 -1
  176. package/src/client/types/Tools.ts +11 -0
  177. package/src/context/providers/AttachmentByIndexProvider.tsx +21 -25
  178. package/src/context/providers/MessageByIndexProvider.tsx +31 -33
  179. package/src/context/providers/MessageProvider.tsx +12 -14
  180. package/src/context/providers/PartByIndexProvider.tsx +12 -14
  181. package/src/context/providers/TextMessagePartProvider.tsx +12 -14
  182. package/src/context/providers/ThreadListItemProvider.tsx +42 -46
  183. package/src/context/react/AssistantApiContext.tsx +69 -29
  184. package/src/context/react/index.ts +5 -1
  185. package/src/legacy-runtime/AssistantRuntimeProvider.tsx +7 -9
  186. package/src/legacy-runtime/RuntimeAdapter.ts +19 -0
  187. package/src/legacy-runtime/client/ThreadListRuntimeClient.ts +10 -1
  188. package/src/legacy-runtime/hooks/AssistantContext.ts +16 -2
  189. package/src/legacy-runtime/hooks/AttachmentContext.ts +6 -0
  190. package/src/legacy-runtime/hooks/ComposerContext.ts +41 -2
  191. package/src/legacy-runtime/hooks/MessageContext.ts +37 -2
  192. package/src/legacy-runtime/hooks/MessagePartContext.ts +6 -0
  193. package/src/legacy-runtime/hooks/ThreadContext.ts +27 -1
  194. package/src/legacy-runtime/hooks/ThreadListItemContext.ts +6 -0
  195. package/src/legacy-runtime/runtime-cores/assistant-transport/index.ts +2 -0
  196. package/src/legacy-runtime/runtime-cores/assistant-transport/types.ts +3 -0
  197. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.tsx +35 -14
  198. package/src/legacy-runtime/runtime-cores/core/AssistantRuntimeCore.tsx +1 -0
  199. package/src/legacy-runtime/runtime-cores/core/BaseAssistantRuntimeCore.tsx +4 -0
  200. package/src/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadListRuntimeCore.tsx +4 -2
  201. package/src/legacy-runtime/runtime-cores/external-store/ExternalStoreThreadRuntimeCore.tsx +7 -1
  202. package/src/legacy-runtime/runtime-cores/external-store/auto-status.tsx +49 -16
  203. package/src/legacy-runtime/runtime-cores/external-store/external-message-converter.tsx +4 -0
  204. package/src/legacy-runtime/runtime-cores/local/LocalThreadListRuntimeCore.tsx +4 -2
  205. package/src/legacy-runtime/runtime-cores/utils/MessageRepository.tsx +1 -1
  206. package/src/model-context/index.ts +9 -0
  207. package/src/model-context/makeAssistantVisible.tsx +1 -1
  208. package/src/model-context/toolbox.tsx +37 -0
  209. package/src/model-context/useAssistantInstructions.tsx +1 -1
  210. package/src/model-context/useAssistantTool.tsx +1 -1
  211. package/src/primitives/message/MessageParts.tsx +3 -2
  212. package/src/primitives/message/MessagePartsGrouped.tsx +3 -2
  213. package/src/tests/setup.ts +2 -8
  214. package/src/utils/tap-store/derived-scopes.ts +185 -0
  215. package/src/utils/tap-store/index.ts +9 -0
  216. package/src/utils/tap-store/tap-api.ts +1 -1
@@ -13,6 +13,7 @@ import { useState, useRef, useMemo } from "react";
13
13
  import {
14
14
  AssistantMessageAccumulator,
15
15
  DataStreamDecoder,
16
+ AssistantTransportDecoder,
16
17
  unstable_createInitialMessage as createInitialMessage,
17
18
  } from "assistant-stream";
18
19
  import {
@@ -30,12 +31,14 @@ import { ToolExecutionStatus, useToolInvocations } from "./useToolInvocations";
30
31
  import { toAISDKTools, getEnabledTools, createRequestHeaders } from "./utils";
31
32
  import { useRemoteThreadListRuntime } from "../remote-thread-list/useRemoteThreadListRuntime";
32
33
  import { InMemoryThreadListAdapter } from "../remote-thread-list/adapter/in-memory";
33
- import { useAssistantApi } from "../../../context/react";
34
+ import { useAssistantApi, useAssistantState } from "../../../context/react";
35
+ import { UserExternalState } from "../../../augmentations";
34
36
 
35
37
  const symbolAssistantTransportExtras = Symbol("assistant-transport-extras");
36
38
  type AssistantTransportExtras = {
37
39
  [symbolAssistantTransportExtras]: true;
38
40
  sendCommand: (command: AssistantTransportCommand) => void;
41
+ state: UserExternalState;
39
42
  };
40
43
 
41
44
  const asAssistantTransportExtras = (
@@ -63,6 +66,18 @@ export const useAssistantTransportSendCommand = () => {
63
66
  };
64
67
  };
65
68
 
69
+ export function useAssistantTransportState(): UserExternalState;
70
+ export function useAssistantTransportState<T>(
71
+ selector: (state: UserExternalState) => T,
72
+ ): T;
73
+ export function useAssistantTransportState<T>(
74
+ selector: (state: UserExternalState) => T = (t) => t as T,
75
+ ): T | UserExternalState {
76
+ return useAssistantState(({ thread }) =>
77
+ selector(asAssistantTransportExtras(thread.extras).state),
78
+ );
79
+ }
80
+
66
81
  const useAssistantTransportThreadRuntime = <T,>(
67
82
  options: AssistantTransportOptions<T>,
68
83
  ): AssistantRuntime => {
@@ -114,21 +129,26 @@ const useAssistantTransportThreadRuntime = <T,>(
114
129
  throw new Error("Response body is null");
115
130
  }
116
131
 
132
+ // Select decoder based on protocol option
133
+ const protocol = options.protocol ?? "data-stream";
134
+ const decoder =
135
+ protocol === "assistant-transport"
136
+ ? new AssistantTransportDecoder()
137
+ : new DataStreamDecoder();
138
+
117
139
  let err: string | undefined;
118
- const stream = response.body
119
- .pipeThrough(new DataStreamDecoder())
120
- .pipeThrough(
121
- new AssistantMessageAccumulator({
122
- initialMessage: createInitialMessage({
123
- unstable_state:
124
- (agentStateRef.current as ReadonlyJSONValue) ?? null,
125
- }),
126
- throttle: isResume,
127
- onError: (error) => {
128
- err = error;
129
- },
140
+ const stream = response.body.pipeThrough(decoder).pipeThrough(
141
+ new AssistantMessageAccumulator({
142
+ initialMessage: createInitialMessage({
143
+ unstable_state:
144
+ (agentStateRef.current as ReadonlyJSONValue) ?? null,
130
145
  }),
131
- );
146
+ throttle: isResume,
147
+ onError: (error) => {
148
+ err = error;
149
+ },
150
+ }),
151
+ );
132
152
 
133
153
  let markedDelivered = false;
134
154
 
@@ -206,6 +226,7 @@ const useAssistantTransportThreadRuntime = <T,>(
206
226
  sendCommand: (command: AssistantTransportCommand) => {
207
227
  commandQueue.enqueue(command);
208
228
  },
229
+ state: agentStateRef.current as UserExternalState,
209
230
  } satisfies AssistantTransportExtras,
210
231
  onNew: async (message: AppendMessage): Promise<void> => {
211
232
  if (message.role !== "user")
@@ -7,6 +7,7 @@ export type AssistantRuntimeCore = {
7
7
  readonly threads: ThreadListRuntimeCore;
8
8
 
9
9
  registerModelContextProvider: (provider: ModelContextProvider) => Unsubscribe;
10
+ getModelContextProvider: () => ModelContextProvider;
10
11
 
11
12
  /**
12
13
  * EXPERIMENTAL: A component that is rendered inside the AssistantRuntimeProvider.
@@ -13,4 +13,8 @@ export abstract class BaseAssistantRuntimeCore implements AssistantRuntimeCore {
13
13
  ): Unsubscribe {
14
14
  return this._contextProvider.registerModelContextProvider(provider);
15
15
  }
16
+
17
+ public getModelContextProvider(): ModelContextProvider {
18
+ return this._contextProvider;
19
+ }
16
20
  }
@@ -212,8 +212,10 @@ export class ExternalStoreThreadListRuntimeCore
212
212
  onDelete(threadId);
213
213
  }
214
214
 
215
- public initialize(): never {
216
- throw new Error("Method not implemented.");
215
+ public initialize(
216
+ threadId: string,
217
+ ): Promise<{ remoteId: string; externalId: string | undefined }> {
218
+ return Promise.resolve({ remoteId: threadId, externalId: undefined });
217
219
  }
218
220
 
219
221
  public generateTitle(): never {
@@ -162,7 +162,13 @@ export class ExternalStoreThreadRuntimeCore
162
162
  if (!store.convertMessage) return m;
163
163
 
164
164
  const isLast = idx === store.messages!.length - 1;
165
- const autoStatus = getAutoStatus(isLast, isRunning, false, false);
165
+ const autoStatus = getAutoStatus(
166
+ isLast,
167
+ isRunning,
168
+ false,
169
+ false,
170
+ undefined,
171
+ );
166
172
 
167
173
  if (
168
174
  cache &&
@@ -1,34 +1,67 @@
1
+ import { ReadonlyJSONValue } from "assistant-stream/utils";
1
2
  import { MessageStatus } from "../../../types";
2
3
 
3
- const AUTO_STATUS_RUNNING = Object.freeze({ type: "running" });
4
- const AUTO_STATUS_COMPLETE = Object.freeze({
5
- type: "complete",
6
- reason: "unknown",
7
- });
4
+ const symbolAutoStatus = Symbol("autoStatus");
8
5
 
9
- const AUTO_STATUS_PENDING = Object.freeze({
10
- type: "requires-action",
11
- reason: "tool-calls",
12
- });
6
+ const AUTO_STATUS_RUNNING = Object.freeze(
7
+ Object.assign({ type: "running" as const }, { [symbolAutoStatus]: true }),
8
+ );
9
+ const AUTO_STATUS_COMPLETE = Object.freeze(
10
+ Object.assign(
11
+ {
12
+ type: "complete" as const,
13
+ reason: "unknown" as const,
14
+ },
15
+ { [symbolAutoStatus]: true },
16
+ ),
17
+ );
13
18
 
14
- const AUTO_STATUS_INTERRUPT = Object.freeze({
15
- type: "requires-action",
16
- reason: "interrupt",
17
- });
19
+ const AUTO_STATUS_PENDING = Object.freeze(
20
+ Object.assign(
21
+ {
22
+ type: "requires-action" as const,
23
+ reason: "tool-calls" as const,
24
+ },
25
+ { [symbolAutoStatus]: true },
26
+ ),
27
+ );
28
+
29
+ const AUTO_STATUS_INTERRUPT = Object.freeze(
30
+ Object.assign(
31
+ {
32
+ type: "requires-action" as const,
33
+ reason: "interrupt" as const,
34
+ },
35
+ { [symbolAutoStatus]: true },
36
+ ),
37
+ );
18
38
 
19
39
  export const isAutoStatus = (status: MessageStatus) =>
20
- status === AUTO_STATUS_RUNNING || status === AUTO_STATUS_COMPLETE;
40
+ (status as any)[symbolAutoStatus] === true;
21
41
 
22
42
  export const getAutoStatus = (
23
43
  isLast: boolean,
24
44
  isRunning: boolean,
25
45
  hasInterruptedToolCalls: boolean,
26
46
  hasPendingToolCalls: boolean,
27
- ) =>
28
- isLast && isRunning
47
+ error?: ReadonlyJSONValue,
48
+ ): MessageStatus => {
49
+ if (isLast && error) {
50
+ return Object.assign(
51
+ {
52
+ type: "incomplete" as const,
53
+ reason: "error" as const,
54
+ error: error,
55
+ },
56
+ { [symbolAutoStatus]: true },
57
+ );
58
+ }
59
+
60
+ return isLast && isRunning
29
61
  ? AUTO_STATUS_RUNNING
30
62
  : hasInterruptedToolCalls
31
63
  ? AUTO_STATUS_INTERRUPT
32
64
  : hasPendingToolCalls
33
65
  ? AUTO_STATUS_PENDING
34
66
  : AUTO_STATUS_COMPLETE;
67
+ };
@@ -10,6 +10,7 @@ import { fromThreadMessageLike, ThreadMessageLike } from "./ThreadMessageLike";
10
10
  import { getAutoStatus, isAutoStatus } from "./auto-status";
11
11
  import { ThreadMessage, ToolCallMessagePart } from "../../../types";
12
12
  import { ToolExecutionStatus } from "../assistant-transport/useToolInvocations";
13
+ import { ReadonlyJSONValue } from "assistant-stream/utils";
13
14
 
14
15
  export namespace useExternalMessageConverter {
15
16
  export type Message =
@@ -30,6 +31,7 @@ export namespace useExternalMessageConverter {
30
31
 
31
32
  export type Metadata = {
32
33
  readonly toolStatuses?: Record<string, ToolExecutionStatus>;
34
+ readonly error?: ReadonlyJSONValue;
33
35
  };
34
36
 
35
37
  export type Callback<T> = (
@@ -263,6 +265,7 @@ export const convertExternalMessages = <T extends WeakKey>(
263
265
  isRunning,
264
266
  hasSuspendedToolCalls,
265
267
  hasPendingToolCalls,
268
+ isLast ? metadata.error : undefined,
266
269
  );
267
270
  const newMessage = fromThreadMessageLike(
268
271
  joined,
@@ -348,6 +351,7 @@ export const useExternalMessageConverter = <T extends WeakKey>({
348
351
  isRunning,
349
352
  hasSuspendedToolCalls,
350
353
  hasPendingToolCalls,
354
+ isLast ? state.metadata.error : undefined,
351
355
  );
352
356
 
353
357
  if (
@@ -104,8 +104,10 @@ export class LocalThreadListRuntimeCore
104
104
  throw new Error("Method not implemented.");
105
105
  }
106
106
 
107
- public initialize(): never {
108
- throw new Error("Method not implemented.");
107
+ public initialize(
108
+ threadId: string,
109
+ ): Promise<{ remoteId: string; externalId: string | undefined }> {
110
+ return Promise.resolve({ remoteId: threadId, externalId: undefined });
109
111
  }
110
112
 
111
113
  public generateTitle(): never {
@@ -67,7 +67,7 @@ export const ExportedMessageRepository = {
67
67
  fromThreadMessageLike(
68
68
  m,
69
69
  generateId(),
70
- getAutoStatus(false, false, false, false),
70
+ getAutoStatus(false, false, false, false, undefined),
71
71
  ),
72
72
  );
73
73
 
@@ -19,5 +19,14 @@ export { tool } from "./tool";
19
19
 
20
20
  export { makeAssistantVisible } from "./makeAssistantVisible";
21
21
 
22
+ export {
23
+ Toolkit,
24
+ type ToolDefinition,
25
+ type ToolkitFallback,
26
+ type ToolkitLayout,
27
+ } from "./toolbox";
28
+
29
+ export { Tools } from "../client/Tools";
30
+
22
31
  export * from "./registry";
23
32
  export * from "./frame";
@@ -76,7 +76,7 @@ export const makeAssistantVisible = <T extends ComponentType<any>>(
76
76
 
77
77
  const { clickable, editable } = config ?? {};
78
78
  useEffect(() => {
79
- return api.registerModelContextProvider({
79
+ return api.modelContext().register({
80
80
  getModelContext: () => {
81
81
  return {
82
82
  tools: {
@@ -0,0 +1,37 @@
1
+ "use client";
2
+
3
+ import type { ComponentType, ReactNode } from "react";
4
+ import type { Tool } from "assistant-stream";
5
+ import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
6
+
7
+ export type ToolDefinition<
8
+ TArgs extends Record<string, unknown>,
9
+ TResult,
10
+ > = Tool<TArgs, TResult> & {
11
+ render?: ToolCallMessagePartComponent<TArgs, TResult> | undefined;
12
+ };
13
+
14
+ export const FallbackSymbol = Symbol("Toolkit.Fallback");
15
+ export const LayoutSymbol = Symbol("Toolkit.Layout");
16
+
17
+ export type ToolkitFallback = {
18
+ render: ToolCallMessagePartComponent<unknown, unknown>;
19
+ };
20
+
21
+ export type ToolkitLayout = {
22
+ render: ComponentType<{ children: ReactNode }>;
23
+ };
24
+
25
+ export type Toolkit = Record<string, ToolDefinition<any, any>> & {
26
+ [FallbackSymbol]?: ToolkitFallback;
27
+ [LayoutSymbol]?: ToolkitLayout;
28
+ };
29
+
30
+ export const Toolkit = {
31
+ Fallback: FallbackSymbol,
32
+ Layout: LayoutSymbol,
33
+ } as const;
34
+
35
+ export type ToolsConfig = {
36
+ toolkit: Toolkit;
37
+ };
@@ -27,7 +27,7 @@ export const useAssistantInstructions = (
27
27
  const config = {
28
28
  system: instruction,
29
29
  };
30
- return api.registerModelContextProvider({
30
+ return api.modelContext().register({
31
31
  getModelContext: () => config,
32
32
  });
33
33
  }, [api, instruction, disabled]);
@@ -33,7 +33,7 @@ export const useAssistantTool = <
33
33
  [toolName]: rest,
34
34
  },
35
35
  };
36
- return api.registerModelContextProvider({
36
+ return api.modelContext().register({
37
37
  getModelContext: () => context,
38
38
  });
39
39
  }, [api, tool]);
@@ -196,8 +196,9 @@ const ToolUIDisplay = ({
196
196
  Fallback: ToolCallMessagePartComponent | undefined;
197
197
  } & ToolCallMessagePartProps) => {
198
198
  const Render = useAssistantState(({ toolUIs }) => {
199
- const Render = toolUIs[props.toolName] ?? Fallback;
200
- if (Array.isArray(Render)) return Render[0];
199
+ const Render =
200
+ toolUIs.tools[props.toolName] ?? toolUIs.fallback ?? Fallback;
201
+ if (Array.isArray(Render)) return Render[0] ?? Fallback;
201
202
  return Render;
202
203
  });
203
204
  if (!Render) return null;
@@ -221,8 +221,9 @@ const ToolUIDisplay = ({
221
221
  Fallback: ToolCallMessagePartComponent | undefined;
222
222
  } & ToolCallMessagePartProps) => {
223
223
  const Render = useAssistantState(({ toolUIs }) => {
224
- const Render = toolUIs[props.toolName] ?? Fallback;
225
- if (Array.isArray(Render)) return Render[0];
224
+ const Render =
225
+ toolUIs.tools[props.toolName] ?? toolUIs.fallback ?? Fallback;
226
+ if (Array.isArray(Render)) return Render[0] ?? Fallback;
226
227
  return Render;
227
228
  });
228
229
  if (!Render) return null;
@@ -1,11 +1,5 @@
1
1
  // This file contains setup code for tests
2
2
  import { vi } from "vitest";
3
3
 
4
- // Set up global mocks if needed
5
- // Using a fixed date to avoid recursive calls
6
- const OriginalDate = global.Date;
7
- const fixedDate = new OriginalDate("2023-01-01");
8
- global.Date = vi.fn(() => fixedDate) as any;
9
- global.Date.now = vi.fn(() => fixedDate.getTime());
10
-
11
- // Add any other global setup needed for tests
4
+ // Use Vitest's built-in to mock Date
5
+ vi.setSystemTime(new Date("2023-01-01"));
@@ -0,0 +1,185 @@
1
+ import { resource, tapEffect } from "@assistant-ui/tap";
2
+ import { tapMemo, tapRef, tapResource, tapResources } from "@assistant-ui/tap";
3
+ import { createAssistantApiField } from "../../context/react/AssistantApiContext";
4
+ import type {
5
+ AssistantApi,
6
+ AssistantApiField,
7
+ } from "../../context/react/AssistantApiContext";
8
+ import type {
9
+ AssistantEvent,
10
+ AssistantEventCallback,
11
+ AssistantEventSelector,
12
+ } from "../../types/EventTypes";
13
+ import type { ResourceElement, Unsubscribe } from "@assistant-ui/tap";
14
+
15
+ /**
16
+ * Extract the API return type from an AssistantApiField
17
+ */
18
+ type ExtractApiType<T> =
19
+ T extends AssistantApiField<infer TApi, any> ? TApi : never;
20
+
21
+ /**
22
+ * Extract the metadata type from an AssistantApiField
23
+ *
24
+ * Used in DerivedScopesInput to validate that each field's source/query types match
25
+ * the expected types from AssistantApi.
26
+ */
27
+ type ExtractMeta<T> =
28
+ T extends AssistantApiField<any, infer TMeta> ? TMeta : never;
29
+
30
+ /**
31
+ * Get only the field names from AssistantApi (exclude method names)
32
+ */
33
+ type AssistantApiFieldNames = {
34
+ [K in keyof AssistantApi]: AssistantApi[K] extends { source: any; query: any }
35
+ ? K
36
+ : never;
37
+ }[keyof AssistantApi];
38
+
39
+ /**
40
+ * Configuration for a derived scope field - infers types from the actual values provided
41
+ */
42
+ export type DerivedScopeConfig<TSource extends string | null, TQuery, TApi> = {
43
+ source: TSource;
44
+ query: TQuery;
45
+ get: () => TApi;
46
+ };
47
+
48
+ /**
49
+ * Type for the special `on` callback function
50
+ */
51
+ export type OnCallbackFn = <TEvent extends AssistantEvent>(
52
+ selector: AssistantEventSelector<TEvent>,
53
+ callback: AssistantEventCallback<TEvent>,
54
+ ) => Unsubscribe;
55
+
56
+ /**
57
+ * Type for the special `subscribe` callback function
58
+ */
59
+ export type SubscribeCallbackFn = (listener: () => void) => Unsubscribe;
60
+
61
+ /**
62
+ * Type for the special `flushSync` callback function
63
+ */
64
+ export type FlushSyncCallbackFn = () => void;
65
+
66
+ /**
67
+ * Type for special non-field functions in AssistantApi
68
+ */
69
+ export type SpecialCallbacks = {
70
+ on?: OnCallbackFn;
71
+ subscribe?: SubscribeCallbackFn;
72
+ flushSync?: FlushSyncCallbackFn;
73
+ };
74
+
75
+ /**
76
+ * Type for the scopes parameter - allows both DerivedScope elements and special callbacks.
77
+ * Field names are restricted to valid AssistantApi field names.
78
+ * TypeScript validates that the source/query/get types match the expected field type.
79
+ */
80
+ export type DerivedScopesInput = {
81
+ [K in AssistantApiFieldNames]?: ResourceElement<
82
+ AssistantApiField<
83
+ ExtractApiType<AssistantApi[K]>,
84
+ {
85
+ source: ExtractMeta<AssistantApi[K]>["source"];
86
+ query: ExtractMeta<AssistantApi[K]>["query"];
87
+ }
88
+ >
89
+ >;
90
+ } & SpecialCallbacks;
91
+
92
+ /**
93
+ * DerivedScope resource - memoizes an AssistantApiField based on source and query.
94
+ * The get callback always calls the most recent version (useEffectEvent pattern).
95
+ * TypeScript infers TSource, TQuery, and TApi from the config object.
96
+ * Validation happens at the DerivedScopesInput level.
97
+ */
98
+ export const DerivedScope = resource(
99
+ <TSource extends string | null, TQuery, TApi>(
100
+ config: DerivedScopeConfig<TSource, TQuery, TApi>,
101
+ ): AssistantApiField<
102
+ TApi,
103
+ {
104
+ source: TSource;
105
+ query: TQuery;
106
+ }
107
+ > => {
108
+ const getRef = tapRef(config.get);
109
+ tapEffect(() => {
110
+ getRef.current = config.get;
111
+ });
112
+
113
+ return tapMemo(() => {
114
+ return createAssistantApiField({
115
+ source: config.source,
116
+ query: config.query,
117
+ get: () => getRef.current(),
118
+ });
119
+ }, [config.source, JSON.stringify(config.query)]);
120
+ },
121
+ );
122
+
123
+ /**
124
+ * Helper resource to wrap each scope field - stable resource identity for proper memoization.
125
+ * Creating this outside the map ensures tapResources can properly track and memoize each field.
126
+ */
127
+ const ScopeFieldWithNameResource = resource(
128
+ (config: {
129
+ fieldName: string;
130
+ scopeElement: ReturnType<typeof DerivedScope>;
131
+ }) => {
132
+ const field = tapResource(config.scopeElement);
133
+ return tapMemo(
134
+ () => [config.fieldName, field] as const,
135
+ [config.fieldName, field],
136
+ );
137
+ },
138
+ );
139
+
140
+ /**
141
+ * DerivedScopes resource - takes an object of DerivedScope resource elements and special callbacks,
142
+ * and returns a Partial<AssistantApi> with all the derived fields.
143
+ */
144
+ export const DerivedScopes = resource(
145
+ (scopes: DerivedScopesInput): Partial<AssistantApi> => {
146
+ const { on, subscribe, flushSync, ...scopeFields } = scopes;
147
+ const callbacksRef = tapRef({ on, subscribe, flushSync });
148
+ tapEffect(() => {
149
+ callbacksRef.current = { on, subscribe, flushSync };
150
+ });
151
+
152
+ const results = tapResources(
153
+ Object.entries(scopeFields).map(([fieldName, scopeElement]) =>
154
+ ScopeFieldWithNameResource(
155
+ {
156
+ fieldName,
157
+ scopeElement: scopeElement as ReturnType<typeof DerivedScope>,
158
+ },
159
+ { key: fieldName },
160
+ ),
161
+ ),
162
+ );
163
+
164
+ return tapMemo(() => {
165
+ const result = Object.fromEntries(results) as Partial<AssistantApi>;
166
+
167
+ const {
168
+ on: onCb,
169
+ subscribe: subCb,
170
+ flushSync: flushCb,
171
+ } = callbacksRef.current;
172
+
173
+ if (onCb) {
174
+ result.on = <TEvent extends AssistantEvent>(
175
+ selector: AssistantEventSelector<TEvent>,
176
+ callback: AssistantEventCallback<TEvent>,
177
+ ) => onCb(selector, callback);
178
+ }
179
+ if (subCb) result.subscribe = (listener) => subCb(listener);
180
+ if (flushCb) result.flushSync = () => flushCb();
181
+
182
+ return result;
183
+ }, [...results]);
184
+ },
185
+ );
@@ -1,2 +1,11 @@
1
1
  export { type Store, asStore } from "./store";
2
2
  export { tapApi, type ApiObject } from "./tap-api";
3
+ export {
4
+ DerivedScope,
5
+ type DerivedScopeConfig,
6
+ type OnCallbackFn,
7
+ type SubscribeCallbackFn,
8
+ type FlushSyncCallbackFn,
9
+ type SpecialCallbacks,
10
+ type DerivedScopesInput,
11
+ } from "./derived-scopes";
@@ -40,7 +40,7 @@ export const tapApi = <TApi extends ApiObject & { getState: () => any }>(
40
40
  key?: string | undefined;
41
41
  },
42
42
  ) => {
43
- const ref = tapRef(() => api);
43
+ const ref = tapRef(api);
44
44
  tapEffect(() => {
45
45
  ref.current = api;
46
46
  });