@assistant-ui/core 0.2.2 → 0.2.4

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 (105) hide show
  1. package/dist/model-context/tool.d.ts +25 -0
  2. package/dist/model-context/tool.d.ts.map +1 -1
  3. package/dist/model-context/tool.js +25 -0
  4. package/dist/model-context/tool.js.map +1 -1
  5. package/dist/react/AssistantRuntimeProvider.d.ts +33 -0
  6. package/dist/react/AssistantRuntimeProvider.d.ts.map +1 -1
  7. package/dist/react/AssistantRuntimeProvider.js +22 -0
  8. package/dist/react/AssistantRuntimeProvider.js.map +1 -1
  9. package/dist/react/client/DataRenderers.d.ts +7 -0
  10. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  11. package/dist/react/client/DataRenderers.js +7 -0
  12. package/dist/react/client/DataRenderers.js.map +1 -1
  13. package/dist/react/client/Tools.d.ts +12 -0
  14. package/dist/react/client/Tools.d.ts.map +1 -1
  15. package/dist/react/client/Tools.js +8 -0
  16. package/dist/react/client/Tools.js.map +1 -1
  17. package/dist/react/index.d.ts +1 -0
  18. package/dist/react/index.d.ts.map +1 -1
  19. package/dist/react/index.js +1 -0
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/react/model-context/makeAssistantDataUI.d.ts +13 -0
  22. package/dist/react/model-context/makeAssistantDataUI.d.ts.map +1 -1
  23. package/dist/react/model-context/makeAssistantDataUI.js +6 -0
  24. package/dist/react/model-context/makeAssistantDataUI.js.map +1 -1
  25. package/dist/react/model-context/makeAssistantTool.d.ts +15 -0
  26. package/dist/react/model-context/makeAssistantTool.d.ts.map +1 -1
  27. package/dist/react/model-context/makeAssistantTool.js +8 -0
  28. package/dist/react/model-context/makeAssistantTool.js.map +1 -1
  29. package/dist/react/model-context/makeAssistantToolUI.d.ts +15 -0
  30. package/dist/react/model-context/makeAssistantToolUI.d.ts.map +1 -1
  31. package/dist/react/model-context/makeAssistantToolUI.js +8 -0
  32. package/dist/react/model-context/makeAssistantToolUI.js.map +1 -1
  33. package/dist/react/model-context/toolbox.d.ts +29 -0
  34. package/dist/react/model-context/toolbox.d.ts.map +1 -1
  35. package/dist/react/model-context/useAssistantDataUI.d.ts +9 -0
  36. package/dist/react/model-context/useAssistantDataUI.d.ts.map +1 -1
  37. package/dist/react/model-context/useAssistantDataUI.js +6 -0
  38. package/dist/react/model-context/useAssistantDataUI.js.map +1 -1
  39. package/dist/react/model-context/useAssistantTool.d.ts +34 -0
  40. package/dist/react/model-context/useAssistantTool.d.ts.map +1 -1
  41. package/dist/react/model-context/useAssistantTool.js +30 -0
  42. package/dist/react/model-context/useAssistantTool.js.map +1 -1
  43. package/dist/react/model-context/useAssistantToolUI.d.ts +12 -0
  44. package/dist/react/model-context/useAssistantToolUI.d.ts.map +1 -1
  45. package/dist/react/model-context/useAssistantToolUI.js +9 -0
  46. package/dist/react/model-context/useAssistantToolUI.js.map +1 -1
  47. package/dist/react/model-context/useToolArgsStatus.d.ts +29 -0
  48. package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
  49. package/dist/react/model-context/useToolArgsStatus.js +24 -0
  50. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  51. package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
  52. package/dist/react/primitive-hooks/useActionBarCopy.js +4 -3
  53. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  54. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  55. package/dist/react/primitives/message/MessageGroupedParts.js +2 -1
  56. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  57. package/dist/react/primitives/message/MessageParts.js +8 -2
  58. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  59. package/dist/react/primitives/messagePart/MessagePartInProgress.d.ts +6 -0
  60. package/dist/react/primitives/messagePart/MessagePartInProgress.d.ts.map +1 -0
  61. package/dist/react/primitives/messagePart/MessagePartInProgress.js +7 -0
  62. package/dist/react/primitives/messagePart/MessagePartInProgress.js.map +1 -0
  63. package/dist/react/runtimes/useToolInvocations.d.ts +9 -0
  64. package/dist/react/runtimes/useToolInvocations.d.ts.map +1 -1
  65. package/dist/react/runtimes/useToolInvocations.js +318 -264
  66. package/dist/react/runtimes/useToolInvocations.js.map +1 -1
  67. package/dist/react/types/MessagePartComponentTypes.d.ts +11 -0
  68. package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
  69. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +1 -0
  70. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  71. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +11 -0
  72. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  73. package/dist/store/clients/model-context-client.d.ts.map +1 -1
  74. package/dist/store/clients/model-context-client.js +24 -4
  75. package/dist/store/clients/model-context-client.js.map +1 -1
  76. package/dist/store/scopes/model-context.d.ts +4 -1
  77. package/dist/store/scopes/model-context.d.ts.map +1 -1
  78. package/dist/types/message.d.ts +22 -0
  79. package/dist/types/message.d.ts.map +1 -1
  80. package/package.json +10 -9
  81. package/src/model-context/tool.ts +25 -0
  82. package/src/react/AssistantRuntimeProvider.tsx +33 -0
  83. package/src/react/client/DataRenderers.ts +7 -0
  84. package/src/react/client/Tools.ts +10 -0
  85. package/src/react/index.ts +1 -0
  86. package/src/react/model-context/makeAssistantDataUI.ts +13 -0
  87. package/src/react/model-context/makeAssistantTool.ts +15 -0
  88. package/src/react/model-context/makeAssistantToolUI.ts +15 -0
  89. package/src/react/model-context/toolbox.ts +32 -1
  90. package/src/react/model-context/useAssistantDataUI.ts +9 -0
  91. package/src/react/model-context/useAssistantTool.ts +34 -0
  92. package/src/react/model-context/useAssistantToolUI.ts +12 -0
  93. package/src/react/model-context/useToolArgsStatus.ts +29 -0
  94. package/src/react/primitive-hooks/useActionBarCopy.ts +9 -5
  95. package/src/react/primitives/message/MessageGroupedParts.tsx +2 -1
  96. package/src/react/primitives/message/MessageParts.tsx +20 -14
  97. package/src/react/primitives/messagePart/MessagePartInProgress.ts +15 -0
  98. package/src/react/runtimes/useToolInvocations.ts +410 -341
  99. package/src/react/types/MessagePartComponentTypes.ts +11 -0
  100. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +11 -0
  101. package/src/store/clients/model-context-client.test.ts +108 -0
  102. package/src/store/clients/model-context-client.ts +36 -6
  103. package/src/store/scopes/model-context.ts +4 -1
  104. package/src/tests/external-store-thread-runtime-core.test.ts +113 -0
  105. package/src/types/message.ts +22 -0
@@ -57,10 +57,21 @@ export type ToolCallMessagePartProps<
57
57
  TResult = unknown,
58
58
  > = MessagePartState &
59
59
  ToolCallMessagePart<TArgs, TResult> & {
60
+ /**
61
+ * Sets the result for this tool-call message part.
62
+ *
63
+ * Use when the renderer, rather than a tool `execute` function, is the
64
+ * source of the result.
65
+ */
60
66
  addResult: (result: TResult | ToolResponse<TResult>) => void;
67
+ /**
68
+ * Supplies the payload requested by `context.human(...)` and resumes the
69
+ * paused frontend tool execution.
70
+ */
61
71
  resume: (payload: unknown) => void;
62
72
  };
63
73
 
74
+ /** Component used to render a tool-call message part. */
64
75
  export type ToolCallMessagePartComponent<
65
76
  TArgs = any,
66
77
  TResult = any,
@@ -53,6 +53,7 @@ export class ExternalStoreThreadRuntimeCore
53
53
  implements ThreadRuntimeCore
54
54
  {
55
55
  private _assistantOptimisticId: string | null = null;
56
+ private _lastSyncedMessageIds = new Set<string>();
56
57
 
57
58
  private _capabilities: RuntimeCapabilities = {
58
59
  switchToBranch: false,
@@ -170,6 +171,7 @@ export class ExternalStoreThreadRuntimeCore
170
171
  // Clear and import the message repository
171
172
  this.repository.clear();
172
173
  this._assistantOptimisticId = null;
174
+ this._lastSyncedMessageIds = new Set();
173
175
  this.repository.import(store.messageRepository);
174
176
 
175
177
  messages = this.repository.getMessages();
@@ -222,6 +224,12 @@ export class ExternalStoreThreadRuntimeCore
222
224
  return newMessage;
223
225
  });
224
226
 
227
+ const nextIds = new Set(messages.map((m) => m.id));
228
+ for (const prevId of this._lastSyncedMessageIds) {
229
+ if (!nextIds.has(prevId)) this.repository.deleteMessage(prevId);
230
+ }
231
+ this._lastSyncedMessageIds = nextIds;
232
+
225
233
  for (let i = 0; i < messages.length; i++) {
226
234
  const message = messages[i]!;
227
235
  const parent = messages[i - 1];
@@ -336,6 +344,7 @@ export class ExternalStoreThreadRuntimeCore
336
344
  previousMessage.id === messages.at(-1)?.id // ensure the previous message is a leaf node
337
345
  ) {
338
346
  this.repository.deleteMessage(previousMessage.id);
347
+ this._lastSyncedMessageIds.delete(previousMessage.id);
339
348
  if (!this.composer.text.trim()) {
340
349
  this.composer.setText(getThreadMessageText(previousMessage));
341
350
  }
@@ -364,6 +373,7 @@ export class ExternalStoreThreadRuntimeCore
364
373
  }
365
374
 
366
375
  public override reset(initialMessages?: readonly ThreadMessageLike[]) {
376
+ this._lastSyncedMessageIds = new Set();
367
377
  const repo = new MessageRepository();
368
378
  repo.import(ExportedMessageRepository.fromArray(initialMessages ?? []));
369
379
  this.updateMessages(repo.getMessages());
@@ -371,6 +381,7 @@ export class ExternalStoreThreadRuntimeCore
371
381
 
372
382
  public override import(data: ExportedMessageRepository) {
373
383
  this._assistantOptimisticId = null;
384
+ this._lastSyncedMessageIds = new Set();
374
385
 
375
386
  super.import(data);
376
387
 
@@ -0,0 +1,108 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { createResourceRoot } from "@assistant-ui/tap";
3
+ import type { Tool } from "assistant-stream";
4
+ import { ModelContext } from "./model-context-client";
5
+ import type {
6
+ ModelContext as ModelContextValue,
7
+ ModelContextProvider,
8
+ } from "../../model-context/types";
9
+
10
+ const tick = () => new Promise<void>((resolve) => setTimeout(resolve, 0));
11
+
12
+ const provider = (ctx: ModelContextValue): ModelContextProvider => ({
13
+ getModelContext: () => ctx,
14
+ });
15
+
16
+ const stubTool = (): Tool<any, any> =>
17
+ ({ description: "", parameters: {} as any }) as unknown as Tool<any, any>;
18
+
19
+ const render = () => {
20
+ const root = createResourceRoot();
21
+ const sub = root.render(ModelContext());
22
+ return { sub, unmount: () => root.unmount() };
23
+ };
24
+
25
+ describe("ModelContext", () => {
26
+ it("starts with undefined modelName and an empty toolNames array", () => {
27
+ const { sub, unmount } = render();
28
+ try {
29
+ const state = sub.getValue().getState();
30
+ expect(state.modelName).toBeUndefined();
31
+ expect(state.toolNames).toEqual([]);
32
+ } finally {
33
+ unmount();
34
+ }
35
+ });
36
+
37
+ it("reflects modelName from a registered provider", async () => {
38
+ const { sub, unmount } = render();
39
+ try {
40
+ sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
41
+ await tick();
42
+
43
+ expect(sub.getValue().getState().modelName).toBe("gpt-4");
44
+ } finally {
45
+ unmount();
46
+ }
47
+ });
48
+
49
+ it("reflects tool names from a registered provider", async () => {
50
+ const { sub, unmount } = render();
51
+ try {
52
+ sub
53
+ .getValue()
54
+ .register(provider({ tools: { foo: stubTool(), bar: stubTool() } }));
55
+ await tick();
56
+
57
+ expect(sub.getValue().getState().toolNames).toEqual(["bar", "foo"]);
58
+ } finally {
59
+ unmount();
60
+ }
61
+ });
62
+
63
+ it("keeps the same state reference when an extra provider does not change the merged values", async () => {
64
+ const { sub, unmount } = render();
65
+ try {
66
+ sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
67
+ await tick();
68
+ const before = sub.getValue().getState();
69
+
70
+ sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
71
+ await tick();
72
+ const after = sub.getValue().getState();
73
+
74
+ expect(after).toBe(before);
75
+ } finally {
76
+ unmount();
77
+ }
78
+ });
79
+
80
+ it("clears modelName when the last contributing provider unsubscribes", async () => {
81
+ const { sub, unmount } = render();
82
+ try {
83
+ const unsubscribe = sub
84
+ .getValue()
85
+ .register(provider({ config: { modelName: "gpt-4" } }));
86
+ await tick();
87
+ expect(sub.getValue().getState().modelName).toBe("gpt-4");
88
+
89
+ unsubscribe();
90
+ await tick();
91
+ expect(sub.getValue().getState().modelName).toBeUndefined();
92
+ expect(sub.getValue().getState().toolNames).toEqual([]);
93
+ } finally {
94
+ unmount();
95
+ }
96
+ });
97
+
98
+ it("reflects modelName synchronously after register without awaiting", () => {
99
+ const { sub, unmount } = render();
100
+ try {
101
+ sub.getValue().register(provider({ config: { modelName: "gpt-4" } }));
102
+
103
+ expect(sub.getValue().getState().modelName).toBe("gpt-4");
104
+ } finally {
105
+ unmount();
106
+ }
107
+ });
108
+ });
@@ -1,18 +1,48 @@
1
- import { resource, tapMemo, tapState } from "@assistant-ui/tap";
1
+ import { resource, tapEffect, tapMemo, tapState } from "@assistant-ui/tap";
2
2
  import type { ClientOutput } from "@assistant-ui/store";
3
3
  import { CompositeContextProvider } from "../../utils/composite-context-provider";
4
4
  import type { ModelContextState } from "../scopes/model-context";
5
5
 
6
- const version = 1;
6
+ const EMPTY_TOOL_NAMES: readonly string[] = [];
7
+
8
+ const INITIAL_STATE: ModelContextState = {
9
+ modelName: undefined,
10
+ toolNames: EMPTY_TOOL_NAMES,
11
+ };
12
+
13
+ const toolNamesEqual = (a: readonly string[], b: readonly string[]): boolean =>
14
+ a === b || (a.length === b.length && a.every((v, i) => v === b[i]));
15
+
16
+ const deriveState = (
17
+ composite: CompositeContextProvider,
18
+ prev: ModelContextState,
19
+ ): ModelContextState => {
20
+ const ctx = composite.getModelContext();
21
+ const modelName = ctx.config?.modelName;
22
+ const keys = ctx.tools ? Object.keys(ctx.tools).sort() : EMPTY_TOOL_NAMES;
23
+ const toolNames = keys.length ? keys : EMPTY_TOOL_NAMES;
24
+
25
+ if (modelName === prev.modelName && toolNamesEqual(toolNames, prev.toolNames))
26
+ return prev;
27
+
28
+ return { modelName, toolNames };
29
+ };
7
30
 
8
31
  export const ModelContext = resource((): ClientOutput<"modelContext"> => {
9
- const [state] = tapState<ModelContextState>(
10
- () => ({ version: version + 1 }) as unknown as ModelContextState,
11
- );
12
32
  const composite = tapMemo(() => new CompositeContextProvider(), []);
33
+ const [state, setState] = tapState<ModelContextState>(() =>
34
+ deriveState(composite, INITIAL_STATE),
35
+ );
36
+
37
+ tapEffect(() => {
38
+ setState((prev) => deriveState(composite, prev));
39
+ return composite.subscribe(() => {
40
+ setState((prev) => deriveState(composite, prev));
41
+ });
42
+ }, [composite]);
13
43
 
14
44
  return {
15
- getState: () => state,
45
+ getState: () => deriveState(composite, state),
16
46
  getModelContext: () => composite.getModelContext(),
17
47
  subscribe: (callback) => composite.subscribe(callback),
18
48
  register: (provider) => composite.registerModelContextProvider(provider),
@@ -1,7 +1,10 @@
1
1
  import type { Unsubscribe } from "../../types/unsubscribe";
2
2
  import type { ModelContextProvider } from "../../model-context/types";
3
3
 
4
- export type ModelContextState = Record<string, never>;
4
+ export type ModelContextState = {
5
+ readonly modelName?: string | undefined;
6
+ readonly toolNames: readonly string[];
7
+ };
5
8
 
6
9
  export type ModelContextMethods = ModelContextProvider & {
7
10
  getState(): ModelContextState;
@@ -150,3 +150,116 @@ describe("ExternalStoreThreadRuntimeCore - state reference stability", () => {
150
150
  expect(runtime.capabilities).toBe(capsBefore);
151
151
  });
152
152
  });
153
+
154
+ describe("ExternalStoreThreadRuntimeCore - messages reconciliation", () => {
155
+ const user = { id: "u", role: "user" as const, content: [] };
156
+
157
+ it("drops ids that disappear between syncs (same length, swapped assistant id)", () => {
158
+ const a1 = { id: "a1", role: "assistant" as const, content: [] };
159
+ const a2 = { id: "a2", role: "assistant" as const, content: [] };
160
+
161
+ const runtime = new ExternalStoreThreadRuntimeCore(
162
+ mockContextProvider,
163
+ makeStore({ messages: [user, a1] }),
164
+ );
165
+
166
+ runtime.__internal_setAdapter(makeStore({ messages: [user, a2] }));
167
+
168
+ const exported = runtime.export();
169
+ expect(exported.messages.map((m) => m.message.id)).toEqual(["u", "a2"]);
170
+ const userChildren = exported.messages
171
+ .filter((m) => m.parentId === "u")
172
+ .map((m) => m.message.id);
173
+ expect(userChildren).toEqual(["a2"]);
174
+ });
175
+
176
+ it("keeps prior ids when they remain in the new sync", () => {
177
+ const a = { id: "a", role: "assistant" as const, content: [] };
178
+
179
+ const runtime = new ExternalStoreThreadRuntimeCore(
180
+ mockContextProvider,
181
+ makeStore({ messages: [user, a] }),
182
+ );
183
+
184
+ runtime.__internal_setAdapter(makeStore({ messages: [user, a] }));
185
+
186
+ expect(runtime.export().messages.map((m) => m.message.id)).toEqual([
187
+ "u",
188
+ "a",
189
+ ]);
190
+ });
191
+
192
+ it("removes trailing messages dropped from the new sync", () => {
193
+ const a = { id: "a", role: "assistant" as const, content: [] };
194
+ const u2 = { id: "u2", role: "user" as const, content: [] };
195
+
196
+ const runtime = new ExternalStoreThreadRuntimeCore(
197
+ mockContextProvider,
198
+ makeStore({ messages: [user, a, u2] }),
199
+ );
200
+
201
+ runtime.__internal_setAdapter(makeStore({ messages: [user, a] }));
202
+
203
+ expect(runtime.export().messages.map((m) => m.message.id)).toEqual([
204
+ "u",
205
+ "a",
206
+ ]);
207
+ });
208
+
209
+ it("does not crash on the next sync after cancelRun removes a leaf user", () => {
210
+ const userWithText = {
211
+ id: "u",
212
+ role: "user" as const,
213
+ content: [{ type: "text" as const, text: "hi" }],
214
+ };
215
+
216
+ const runtime = new ExternalStoreThreadRuntimeCore(
217
+ mockContextProvider,
218
+ makeStore({
219
+ messages: [userWithText],
220
+ onCancel: vi.fn(),
221
+ isRunning: true,
222
+ }),
223
+ );
224
+
225
+ runtime.cancelRun();
226
+
227
+ expect(() => {
228
+ runtime.__internal_setAdapter(makeStore({ messages: [] }));
229
+ }).not.toThrow();
230
+ });
231
+
232
+ it("drops phantom sibling when convertMessage swaps the assistant id", () => {
233
+ type Raw = { id: string; role: "user" | "assistant"; text: string };
234
+ const rawU: Raw = { id: "u", role: "user", text: "hi" };
235
+ const rawA1: Raw = { id: "client_id", role: "assistant", text: "" };
236
+ const rawA2: Raw = { id: "server_id", role: "assistant", text: "" };
237
+
238
+ const convertMessage = (m: Raw) => ({
239
+ id: m.id,
240
+ role: m.role,
241
+ content: [{ type: "text" as const, text: m.text }],
242
+ });
243
+
244
+ const runtime = new ExternalStoreThreadRuntimeCore(
245
+ mockContextProvider,
246
+ makeStore({
247
+ messages: [rawU, rawA1] as any,
248
+ convertMessage: convertMessage as any,
249
+ }),
250
+ );
251
+
252
+ runtime.__internal_setAdapter(
253
+ makeStore({
254
+ messages: [rawU, rawA2] as any,
255
+ convertMessage: convertMessage as any,
256
+ }),
257
+ );
258
+
259
+ const userChildren = runtime
260
+ .export()
261
+ .messages.filter((m) => m.parentId === "u")
262
+ .map((m) => m.message.id);
263
+ expect(userChildren).toEqual(["server_id"]);
264
+ });
265
+ });
@@ -92,18 +92,38 @@ export type ToolCallMessagePart<
92
92
  TArgs = ReadonlyJSONObject,
93
93
  TResult = unknown,
94
94
  > = {
95
+ /** Identifies this part as a tool call. */
95
96
  readonly type: "tool-call";
97
+ /** Stable identifier for this invocation of the tool. */
96
98
  readonly toolCallId: string;
99
+ /** Name of the tool requested by the model. */
97
100
  readonly toolName: string;
101
+ /**
102
+ * Arguments supplied by the model. During streaming this is a partial parse:
103
+ * fields may be missing or incomplete. From a tool-call renderer, use
104
+ * `useToolArgsStatus` to detect which fields are still arriving.
105
+ */
98
106
  readonly args: TArgs;
107
+ /** Result returned by the tool, if it has completed. */
99
108
  readonly result?: TResult | undefined;
109
+ /** Whether the result represents a tool execution error. */
100
110
  readonly isError?: boolean | undefined;
111
+ /** Raw JSON argument text streamed by the model. */
101
112
  readonly argsText: string;
113
+ /** UI-only artifact associated with the tool result. */
102
114
  readonly artifact?: unknown;
115
+ /** MCP app metadata associated with this tool call, when present. */
103
116
  readonly mcp?: ToolCallMessagePartMcpMetadata;
117
+ /** Content returned to the model for this tool result. */
104
118
  readonly modelContent?: readonly ToolModelContentPart[] | undefined;
119
+ /** Human-input request that must be resolved before the run can continue. */
105
120
  readonly interrupt?: { type: "human"; payload: unknown };
121
+ /** Parent message-part ID when this part belongs to a nested structure. */
106
122
  readonly parentId?: string;
123
+ /**
124
+ * Nested thread messages produced by this tool call, for example a sub-agent
125
+ * conversation.
126
+ */
107
127
  readonly messages?: readonly ThreadMessage[];
108
128
  };
109
129
 
@@ -143,7 +163,9 @@ export type MessagePartStatus =
143
163
 
144
164
  export type ToolCallMessagePartStatus =
145
165
  | {
166
+ /** The tool call is waiting for UI or human input before continuing. */
146
167
  readonly type: "requires-action";
168
+ /** Reason the tool call requires action. */
147
169
  readonly reason: "interrupt";
148
170
  }
149
171
  | MessagePartStatus;