@assistant-ui/react 0.4.7 → 0.5.1

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/index.js CHANGED
@@ -53,11 +53,13 @@ __export(src_exports, {
53
53
  ThreadWelcome: () => thread_welcome_default,
54
54
  UserActionBar: () => user_action_bar_default,
55
55
  UserMessage: () => user_message_default,
56
+ fromCoreMessage: () => fromCoreMessage,
56
57
  fromCoreMessages: () => fromCoreMessages,
57
58
  fromLanguageModelMessages: () => fromLanguageModelMessages,
58
59
  fromLanguageModelTools: () => fromLanguageModelTools,
59
60
  makeAssistantTool: () => makeAssistantTool,
60
61
  makeAssistantToolUI: () => makeAssistantToolUI,
62
+ toCoreMessage: () => toCoreMessage,
61
63
  toCoreMessages: () => toCoreMessages,
62
64
  toLanguageModelMessages: () => toLanguageModelMessages,
63
65
  toLanguageModelTools: () => toLanguageModelTools,
@@ -397,13 +399,17 @@ var ThreadProvider = ({
397
399
  (0, import_react4.useCallback)(
398
400
  (thread) => {
399
401
  const onThreadUpdate = () => {
400
- context.useThread.setState(
401
- Object.freeze({
402
- isRunning: context.useThreadRuntime.getState().isRunning
403
- }),
404
- true
405
- );
406
- context.useThreadMessages.setState(thread.messages, true);
402
+ if (thread.isRunning !== context.useThread.getState().isRunning) {
403
+ context.useThread.setState(
404
+ Object.freeze({
405
+ isRunning: thread.isRunning
406
+ }),
407
+ true
408
+ );
409
+ }
410
+ if (thread.messages !== context.useThreadMessages.getState()) {
411
+ context.useThreadMessages.setState(thread.messages, true);
412
+ }
407
413
  };
408
414
  onThreadUpdate();
409
415
  return thread.subscribe(onThreadUpdate);
@@ -1256,12 +1262,28 @@ var import_react38 = require("react");
1256
1262
  var import_react34 = require("react");
1257
1263
  var import_zustand10 = require("zustand");
1258
1264
  var import_jsx_runtime13 = require("react/jsx-runtime");
1259
- var DONE_STATUS = { type: "done" };
1265
+ var COMPLETE_STATUS = {
1266
+ type: "complete"
1267
+ };
1268
+ var toContentPartStatus = (message, partIndex, part) => {
1269
+ if (message.role !== "assistant") return COMPLETE_STATUS;
1270
+ const isLastPart = partIndex === message.content.length - 1;
1271
+ if (part.type !== "tool-call") {
1272
+ if ("reason" in message.status && message.status.reason === "tool-calls" && isLastPart)
1273
+ throw new Error(
1274
+ "Encountered unexpected requires-action status. This is likely an internal bug in assistant-ui."
1275
+ );
1276
+ return isLastPart ? message.status : COMPLETE_STATUS;
1277
+ }
1278
+ if (!!part.result) {
1279
+ return COMPLETE_STATUS;
1280
+ }
1281
+ return message.status;
1282
+ };
1260
1283
  var syncContentPart = ({ message }, useContentPart, partIndex) => {
1261
1284
  const part = message.content[partIndex];
1262
1285
  if (!part) return;
1263
- const messageStatus = message.role === "assistant" ? message.status : DONE_STATUS;
1264
- const status = partIndex === message.content.length - 1 ? messageStatus : DONE_STATUS;
1286
+ const status = toContentPartStatus(message, partIndex, part);
1265
1287
  const currentState = useContentPart.getState();
1266
1288
  if (currentState.part === part && currentState.status === status) return;
1267
1289
  useContentPart.setState(
@@ -1414,7 +1436,7 @@ ContentPartPrimitiveDisplay.displayName = "ContentPartPrimitive.Display";
1414
1436
  // src/primitives/contentPart/ContentPartInProgress.tsx
1415
1437
  var ContentPartPrimitiveInProgress = ({ children }) => {
1416
1438
  const { useContentPart } = useContentPartContext();
1417
- const isInProgress = useContentPart((c) => c.status.type === "in_progress");
1439
+ const isInProgress = useContentPart((c) => c.status.type === "running");
1418
1440
  return isInProgress ? children : null;
1419
1441
  };
1420
1442
  ContentPartPrimitiveInProgress.displayName = "ContentPartPrimitive.InProgress";
@@ -1453,10 +1475,16 @@ var MessageContentPartComponent = ({
1453
1475
  const type = part.type;
1454
1476
  switch (type) {
1455
1477
  case "text":
1478
+ if (status.type === "requires-action")
1479
+ throw new Error("Encountered unexpected requires-action status");
1456
1480
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text2, { part, status });
1457
1481
  case "image":
1482
+ if (status.type === "requires-action")
1483
+ throw new Error("Encountered unexpected requires-action status");
1458
1484
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Image2, { part, status });
1459
1485
  case "ui":
1486
+ if (status.type === "requires-action")
1487
+ throw new Error("Encountered unexpected requires-action status");
1460
1488
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UI, { part, status });
1461
1489
  case "tool-call": {
1462
1490
  const Tool = by_name[part.toolName] || Fallback2;
@@ -2028,6 +2056,182 @@ var generateId = (0, import_non_secure.customAlphabet)(
2028
2056
  var optimisticPrefix = "__optimistic__";
2029
2057
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
2030
2058
 
2059
+ // src/internal.ts
2060
+ var internal_exports = {};
2061
+ __export(internal_exports, {
2062
+ BaseAssistantRuntime: () => BaseAssistantRuntime,
2063
+ MessageRepository: () => MessageRepository,
2064
+ ProxyConfigProvider: () => ProxyConfigProvider,
2065
+ TooltipIconButton: () => TooltipIconButton,
2066
+ generateId: () => generateId,
2067
+ useSmooth: () => useSmooth
2068
+ });
2069
+
2070
+ // src/runtimes/core/BaseAssistantRuntime.tsx
2071
+ var BaseAssistantRuntime = class {
2072
+ constructor(_thread) {
2073
+ this._thread = _thread;
2074
+ this._thread = _thread;
2075
+ }
2076
+ get thread() {
2077
+ return this._thread;
2078
+ }
2079
+ set thread(thread) {
2080
+ this._thread = thread;
2081
+ this.subscriptionHandler();
2082
+ }
2083
+ _subscriptions = /* @__PURE__ */ new Set();
2084
+ subscribe(callback) {
2085
+ this._subscriptions.add(callback);
2086
+ return () => this._subscriptions.delete(callback);
2087
+ }
2088
+ subscriptionHandler = () => {
2089
+ for (const callback of this._subscriptions) callback();
2090
+ };
2091
+ };
2092
+
2093
+ // src/ui/base/tooltip-icon-button.tsx
2094
+ var import_react52 = require("react");
2095
+
2096
+ // src/ui/base/tooltip.tsx
2097
+ var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"));
2098
+
2099
+ // src/ui/utils/withDefaults.tsx
2100
+ var import_react50 = require("react");
2101
+ var import_classnames = __toESM(require("classnames"));
2102
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2103
+ var withDefaultProps = ({
2104
+ className,
2105
+ ...defaultProps
2106
+ }) => ({ className: classNameProp, ...props }) => {
2107
+ return {
2108
+ className: (0, import_classnames.default)(className, classNameProp),
2109
+ ...defaultProps,
2110
+ ...props
2111
+ };
2112
+ };
2113
+ var withDefaults = (Component, defaultProps) => {
2114
+ const getProps = withDefaultProps(defaultProps);
2115
+ const WithDefaults = (0, import_react50.forwardRef)(
2116
+ (props, ref) => {
2117
+ const ComponentAsAny = Component;
2118
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComponentAsAny, { ...getProps(props), ref });
2119
+ }
2120
+ );
2121
+ WithDefaults.displayName = "withDefaults(" + (typeof Component === "string" ? Component : Component.displayName) + ")";
2122
+ return WithDefaults;
2123
+ };
2124
+
2125
+ // src/ui/base/tooltip.tsx
2126
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2127
+ var Tooltip = (props) => {
2128
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipPrimitive.Provider, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipPrimitive.Root, { ...props }) });
2129
+ };
2130
+ Tooltip.displayName = "Tooltip";
2131
+ var TooltipTrigger = TooltipPrimitive.Trigger;
2132
+ var TooltipContent = withDefaults(TooltipPrimitive.Content, {
2133
+ sideOffset: 4,
2134
+ className: "aui-tooltip-content"
2135
+ });
2136
+ TooltipContent.displayName = "TooltipContent";
2137
+
2138
+ // src/ui/base/button.tsx
2139
+ var import_class_variance_authority = require("class-variance-authority");
2140
+ var import_react_primitive11 = require("@radix-ui/react-primitive");
2141
+ var import_react51 = require("react");
2142
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2143
+ var buttonVariants = (0, import_class_variance_authority.cva)("aui-button", {
2144
+ variants: {
2145
+ variant: {
2146
+ default: "aui-button-primary",
2147
+ outline: "aui-button-outline",
2148
+ ghost: "aui-button-ghost"
2149
+ },
2150
+ size: {
2151
+ default: "aui-button-medium",
2152
+ icon: "aui-button-icon"
2153
+ }
2154
+ },
2155
+ defaultVariants: {
2156
+ variant: "default",
2157
+ size: "default"
2158
+ }
2159
+ });
2160
+ var Button = (0, import_react51.forwardRef)(
2161
+ ({ className, variant, size, ...props }, ref) => {
2162
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2163
+ import_react_primitive11.Primitive.button,
2164
+ {
2165
+ className: buttonVariants({ variant, size, className }),
2166
+ ...props,
2167
+ ref
2168
+ }
2169
+ );
2170
+ }
2171
+ );
2172
+ Button.displayName = "Button";
2173
+
2174
+ // src/ui/base/tooltip-icon-button.tsx
2175
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2176
+ var TooltipIconButton = (0, import_react52.forwardRef)(({ children, tooltip, side = "bottom", ...rest }, ref) => {
2177
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Tooltip, { children: [
2178
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Button, { variant: "ghost", size: "icon", ...rest, ref, children: [
2179
+ children,
2180
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "aui-sr-only", children: tooltip })
2181
+ ] }) }),
2182
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TooltipContent, { side, children: tooltip })
2183
+ ] });
2184
+ });
2185
+ TooltipIconButton.displayName = "TooltipIconButton";
2186
+
2187
+ // src/runtimes/edge/converters/fromCoreMessage.ts
2188
+ var fromCoreMessages = (message) => {
2189
+ return message.map((message2) => fromCoreMessage(message2));
2190
+ };
2191
+ var fromCoreMessage = (message, {
2192
+ id = generateId(),
2193
+ status = { type: "complete", reason: "unknown" }
2194
+ } = {}) => {
2195
+ const commonProps = {
2196
+ id,
2197
+ createdAt: /* @__PURE__ */ new Date()
2198
+ };
2199
+ const role = message.role;
2200
+ switch (role) {
2201
+ case "assistant":
2202
+ return {
2203
+ ...commonProps,
2204
+ role,
2205
+ content: message.content.map((part) => {
2206
+ if (part.type === "tool-call") {
2207
+ return {
2208
+ ...part,
2209
+ argsText: JSON.stringify(part.args)
2210
+ };
2211
+ }
2212
+ return part;
2213
+ }),
2214
+ status
2215
+ };
2216
+ case "user":
2217
+ return {
2218
+ ...commonProps,
2219
+ role,
2220
+ content: message.content
2221
+ };
2222
+ case "system":
2223
+ return {
2224
+ ...commonProps,
2225
+ role,
2226
+ content: message.content
2227
+ };
2228
+ default: {
2229
+ const unsupportedRole = role;
2230
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
2231
+ }
2232
+ }
2233
+ };
2234
+
2031
2235
  // src/runtimes/utils/MessageRepository.tsx
2032
2236
  var findHead = (message) => {
2033
2237
  if (message.next) return findHead(message.next);
@@ -2118,12 +2322,13 @@ var MessageRepository = class {
2118
2322
  do {
2119
2323
  optimisticId = generateOptimisticId();
2120
2324
  } while (this.messages.has(optimisticId));
2121
- this.addOrUpdateMessage(parentId, {
2122
- ...message,
2123
- id: optimisticId,
2124
- createdAt: /* @__PURE__ */ new Date(),
2125
- ...message.role === "assistant" ? { status: "in_progress" } : void 0
2126
- });
2325
+ this.addOrUpdateMessage(
2326
+ parentId,
2327
+ fromCoreMessage(message, {
2328
+ id: optimisticId,
2329
+ status: { type: "running" }
2330
+ })
2331
+ );
2127
2332
  return optimisticId;
2128
2333
  }
2129
2334
  deleteMessage(messageId, replacementId) {
@@ -2190,134 +2395,6 @@ var MessageRepository = class {
2190
2395
  }
2191
2396
  };
2192
2397
 
2193
- // src/runtimes/core/BaseAssistantRuntime.tsx
2194
- var BaseAssistantRuntime = class {
2195
- constructor(_thread) {
2196
- this._thread = _thread;
2197
- this._thread = _thread;
2198
- }
2199
- get thread() {
2200
- return this._thread;
2201
- }
2202
- set thread(thread) {
2203
- this._thread = thread;
2204
- this.subscriptionHandler();
2205
- }
2206
- _subscriptions = /* @__PURE__ */ new Set();
2207
- subscribe(callback) {
2208
- this._subscriptions.add(callback);
2209
- return () => this._subscriptions.delete(callback);
2210
- }
2211
- subscriptionHandler = () => {
2212
- for (const callback of this._subscriptions) callback();
2213
- };
2214
- };
2215
-
2216
- // src/internal.ts
2217
- var internal_exports = {};
2218
- __export(internal_exports, {
2219
- BaseAssistantRuntime: () => BaseAssistantRuntime,
2220
- MessageRepository: () => MessageRepository,
2221
- ProxyConfigProvider: () => ProxyConfigProvider,
2222
- TooltipIconButton: () => TooltipIconButton,
2223
- generateId: () => generateId,
2224
- useSmooth: () => useSmooth
2225
- });
2226
-
2227
- // src/ui/base/tooltip-icon-button.tsx
2228
- var import_react52 = require("react");
2229
-
2230
- // src/ui/base/tooltip.tsx
2231
- var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"));
2232
-
2233
- // src/ui/utils/withDefaults.tsx
2234
- var import_react50 = require("react");
2235
- var import_classnames = __toESM(require("classnames"));
2236
- var import_jsx_runtime25 = require("react/jsx-runtime");
2237
- var withDefaultProps = ({
2238
- className,
2239
- ...defaultProps
2240
- }) => ({ className: classNameProp, ...props }) => {
2241
- return {
2242
- className: (0, import_classnames.default)(className, classNameProp),
2243
- ...defaultProps,
2244
- ...props
2245
- };
2246
- };
2247
- var withDefaults = (Component, defaultProps) => {
2248
- const getProps = withDefaultProps(defaultProps);
2249
- const WithDefaults = (0, import_react50.forwardRef)(
2250
- (props, ref) => {
2251
- const ComponentAsAny = Component;
2252
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComponentAsAny, { ...getProps(props), ref });
2253
- }
2254
- );
2255
- WithDefaults.displayName = "withDefaults(" + (typeof Component === "string" ? Component : Component.displayName) + ")";
2256
- return WithDefaults;
2257
- };
2258
-
2259
- // src/ui/base/tooltip.tsx
2260
- var import_jsx_runtime26 = require("react/jsx-runtime");
2261
- var Tooltip = (props) => {
2262
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipPrimitive.Provider, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipPrimitive.Root, { ...props }) });
2263
- };
2264
- Tooltip.displayName = "Tooltip";
2265
- var TooltipTrigger = TooltipPrimitive.Trigger;
2266
- var TooltipContent = withDefaults(TooltipPrimitive.Content, {
2267
- sideOffset: 4,
2268
- className: "aui-tooltip-content"
2269
- });
2270
- TooltipContent.displayName = "TooltipContent";
2271
-
2272
- // src/ui/base/button.tsx
2273
- var import_class_variance_authority = require("class-variance-authority");
2274
- var import_react_primitive11 = require("@radix-ui/react-primitive");
2275
- var import_react51 = require("react");
2276
- var import_jsx_runtime27 = require("react/jsx-runtime");
2277
- var buttonVariants = (0, import_class_variance_authority.cva)("aui-button", {
2278
- variants: {
2279
- variant: {
2280
- default: "aui-button-primary",
2281
- outline: "aui-button-outline",
2282
- ghost: "aui-button-ghost"
2283
- },
2284
- size: {
2285
- default: "aui-button-medium",
2286
- icon: "aui-button-icon"
2287
- }
2288
- },
2289
- defaultVariants: {
2290
- variant: "default",
2291
- size: "default"
2292
- }
2293
- });
2294
- var Button = (0, import_react51.forwardRef)(
2295
- ({ className, variant, size, ...props }, ref) => {
2296
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2297
- import_react_primitive11.Primitive.button,
2298
- {
2299
- className: buttonVariants({ variant, size, className }),
2300
- ...props,
2301
- ref
2302
- }
2303
- );
2304
- }
2305
- );
2306
- Button.displayName = "Button";
2307
-
2308
- // src/ui/base/tooltip-icon-button.tsx
2309
- var import_jsx_runtime28 = require("react/jsx-runtime");
2310
- var TooltipIconButton = (0, import_react52.forwardRef)(({ children, tooltip, side = "bottom", ...rest }, ref) => {
2311
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Tooltip, { children: [
2312
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Button, { variant: "ghost", size: "icon", ...rest, ref, children: [
2313
- children,
2314
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "aui-sr-only", children: tooltip })
2315
- ] }) }),
2316
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TooltipContent, { side, children: tooltip })
2317
- ] });
2318
- });
2319
- TooltipIconButton.displayName = "TooltipIconButton";
2320
-
2321
2398
  // src/runtimes/edge/converters/toLanguageModelMessages.ts
2322
2399
  var assistantMessageSplitter = () => {
2323
2400
  const stash = [];
@@ -2538,35 +2615,43 @@ var fromLanguageModelMessages = (lm, { mergeRoundtrips }) => {
2538
2615
  return messages;
2539
2616
  };
2540
2617
 
2541
- // src/runtimes/edge/converters/fromCoreMessage.ts
2542
- var fromCoreMessages = (message) => {
2543
- return message.map((message2) => {
2544
- return {
2545
- id: generateId(),
2546
- createdAt: /* @__PURE__ */ new Date(),
2547
- ...message2.role === "assistant" ? {
2548
- status: { type: "done" }
2549
- } : void 0,
2550
- ...message2
2551
- };
2552
- });
2553
- };
2554
-
2555
2618
  // src/runtimes/edge/converters/toCoreMessages.ts
2556
2619
  var toCoreMessages = (message) => {
2557
- return message.map((message2) => {
2558
- return {
2559
- role: message2.role,
2560
- content: message2.content.map((part) => {
2561
- if (part.type === "ui") throw new Error("UI parts are not supported");
2562
- if (part.type === "tool-call") {
2563
- const { argsText, ...rest } = part;
2564
- return rest;
2565
- }
2566
- return part;
2567
- })
2568
- };
2569
- });
2620
+ return message.map(toCoreMessage);
2621
+ };
2622
+ var toCoreMessage = (message) => {
2623
+ const role = message.role;
2624
+ switch (role) {
2625
+ case "assistant":
2626
+ return {
2627
+ role,
2628
+ content: message.content.map((part) => {
2629
+ if (part.type === "ui") throw new Error("UI parts are not supported");
2630
+ if (part.type === "tool-call") {
2631
+ const { argsText, ...rest } = part;
2632
+ return rest;
2633
+ }
2634
+ return part;
2635
+ })
2636
+ };
2637
+ case "user":
2638
+ return {
2639
+ role,
2640
+ content: message.content.map((part) => {
2641
+ if (part.type === "ui") throw new Error("UI parts are not supported");
2642
+ return part;
2643
+ })
2644
+ };
2645
+ case "system":
2646
+ return {
2647
+ role,
2648
+ content: message.content
2649
+ };
2650
+ default: {
2651
+ const unsupportedRole = role;
2652
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
2653
+ }
2654
+ }
2570
2655
  };
2571
2656
 
2572
2657
  // src/runtimes/edge/converters/fromLanguageModelTools.ts
@@ -3036,9 +3121,10 @@ var parsePartialJson = (json) => {
3036
3121
  };
3037
3122
 
3038
3123
  // src/runtimes/edge/streams/runResultStream.ts
3039
- function runResultStream(initialContent) {
3124
+ function runResultStream() {
3040
3125
  let message = {
3041
- content: initialContent
3126
+ content: [],
3127
+ status: { type: "running" }
3042
3128
  };
3043
3129
  const currentToolCall = { toolCallId: "", argsText: "" };
3044
3130
  return new TransformStream({
@@ -3086,7 +3172,13 @@ function runResultStream(initialContent) {
3086
3172
  break;
3087
3173
  }
3088
3174
  case "error": {
3089
- throw chunk.error;
3175
+ if (chunk.error instanceof Error && chunk.error.name === "AbortError") {
3176
+ message = appendOrUpdateCancel(message);
3177
+ controller.enqueue(message);
3178
+ break;
3179
+ } else {
3180
+ throw chunk.error;
3181
+ }
3090
3182
  }
3091
3183
  default: {
3092
3184
  const unhandledType = chunkType;
@@ -3160,11 +3252,42 @@ var appendOrUpdateToolResult = (message, toolCallId, toolName, result) => {
3160
3252
  };
3161
3253
  var appendOrUpdateFinish = (message, chunk) => {
3162
3254
  const { type, ...rest } = chunk;
3255
+ return {
3256
+ ...message,
3257
+ status: getStatus(chunk),
3258
+ roundtrips: [
3259
+ ...message.roundtrips ?? [],
3260
+ {
3261
+ logprobs: rest.logprobs,
3262
+ usage: rest.usage
3263
+ }
3264
+ ]
3265
+ };
3266
+ };
3267
+ var getStatus = (chunk) => {
3268
+ if (chunk.finishReason === "tool-calls") {
3269
+ return {
3270
+ type: "requires-action",
3271
+ reason: "tool-calls"
3272
+ };
3273
+ } else if (chunk.finishReason === "stop" || chunk.finishReason === "unknown") {
3274
+ return {
3275
+ type: "complete",
3276
+ reason: chunk.finishReason
3277
+ };
3278
+ } else {
3279
+ return {
3280
+ type: "incomplete",
3281
+ reason: chunk.finishReason
3282
+ };
3283
+ }
3284
+ };
3285
+ var appendOrUpdateCancel = (message) => {
3163
3286
  return {
3164
3287
  ...message,
3165
3288
  status: {
3166
- type: "done",
3167
- ...rest
3289
+ type: "incomplete",
3290
+ reason: "cancelled"
3168
3291
  }
3169
3292
  };
3170
3293
  };
@@ -3264,7 +3387,7 @@ var EdgeChatAdapter = class {
3264
3387
  constructor(options) {
3265
3388
  this.options = options;
3266
3389
  }
3267
- async roundtrip(initialContent, { messages, abortSignal, config, onUpdate }) {
3390
+ async run({ messages, abortSignal, config, onUpdate }) {
3268
3391
  const result = await fetch(this.options.api, {
3269
3392
  method: "POST",
3270
3393
  headers: {
@@ -3284,46 +3407,14 @@ var EdgeChatAdapter = class {
3284
3407
  `Edge runtime returned status ${result.status}: ${await result.text()}`
3285
3408
  );
3286
3409
  }
3287
- const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream(initialContent));
3288
- let message;
3410
+ const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream());
3289
3411
  let update;
3290
3412
  for await (update of asAsyncIterable(stream)) {
3291
- message = onUpdate(update);
3413
+ onUpdate(update);
3292
3414
  }
3293
3415
  if (update === void 0)
3294
3416
  throw new Error("No data received from Edge Runtime");
3295
- return [message, update];
3296
- }
3297
- async run({ messages, abortSignal, config, onUpdate }) {
3298
- let roundtripAllowance = this.options.maxToolRoundtrips ?? 1;
3299
- let usage = {
3300
- promptTokens: 0,
3301
- completionTokens: 0
3302
- };
3303
- let result;
3304
- let assistantMessage;
3305
- do {
3306
- [assistantMessage, result] = await this.roundtrip(result?.content ?? [], {
3307
- messages: assistantMessage ? [...messages, assistantMessage] : messages,
3308
- abortSignal,
3309
- config,
3310
- onUpdate
3311
- });
3312
- if (result.status?.type === "done") {
3313
- usage.promptTokens += result.status.usage?.promptTokens ?? 0;
3314
- usage.completionTokens += result.status.usage?.completionTokens ?? 0;
3315
- }
3316
- } while (result.status?.type === "done" && result.status.finishReason === "tool-calls" && result.content.every((c) => c.type !== "tool-call" || !!c.result) && roundtripAllowance-- > 0);
3317
- if (result.status?.type === "done" && usage.promptTokens > 0) {
3318
- result = {
3319
- ...result,
3320
- status: {
3321
- ...result.status,
3322
- usage
3323
- }
3324
- };
3325
- }
3326
- return result;
3417
+ return update;
3327
3418
  }
3328
3419
  };
3329
3420
 
@@ -3337,6 +3428,7 @@ var useEdgeRuntime = ({
3337
3428
  };
3338
3429
 
3339
3430
  // src/runtimes/local/LocalRuntime.tsx
3431
+ var shouldContinue = (result) => result.status?.type === "requires-action" && result.status.reason === "tool-calls" && result.content.every((c) => c.type !== "tool-call" || !!c.result);
3340
3432
  var LocalRuntime = class extends BaseAssistantRuntime {
3341
3433
  _proxyConfigProvider;
3342
3434
  constructor(adapter, options) {
@@ -3370,6 +3462,7 @@ var LocalThreadRuntime = class {
3370
3462
  constructor(configProvider, adapter, options) {
3371
3463
  this.configProvider = configProvider;
3372
3464
  this.adapter = adapter;
3465
+ this.options = options;
3373
3466
  if (options?.initialMessages) {
3374
3467
  let parentId = null;
3375
3468
  const messages = fromCoreMessages(options.initialMessages);
@@ -3413,27 +3506,51 @@ var LocalThreadRuntime = class {
3413
3506
  }
3414
3507
  async startRun(parentId) {
3415
3508
  this.repository.resetHead(parentId);
3416
- const messages = this.repository.getMessages();
3509
+ const id = generateId();
3417
3510
  let message = {
3418
- id: generateId(),
3511
+ id,
3419
3512
  role: "assistant",
3420
- status: { type: "in_progress" },
3513
+ status: { type: "running" },
3421
3514
  content: [{ type: "text", text: "" }],
3422
3515
  createdAt: /* @__PURE__ */ new Date()
3423
3516
  };
3517
+ do {
3518
+ message = await this.performRoundtrip(parentId, message);
3519
+ } while (shouldContinue(message));
3520
+ }
3521
+ async performRoundtrip(parentId, message) {
3522
+ const messages = this.repository.getMessages();
3424
3523
  this.abortController?.abort();
3425
3524
  this.abortController = new AbortController();
3426
- this.repository.addOrUpdateMessage(parentId, { ...message });
3427
- this.notifySubscribers();
3525
+ const initialContent = message.content;
3526
+ const initialRoundtrips = message.roundtrips;
3428
3527
  const updateMessage = (m) => {
3429
3528
  message = {
3430
3529
  ...message,
3431
- ...m
3530
+ ...m.content ? { content: [...initialContent, ...m.content ?? []] } : void 0,
3531
+ status: m.status ?? message.status,
3532
+ ...m.roundtrips?.length ? { roundtrips: [...initialRoundtrips ?? [], ...m.roundtrips] } : void 0
3432
3533
  };
3433
3534
  this.repository.addOrUpdateMessage(parentId, message);
3434
3535
  this.notifySubscribers();
3435
- return message;
3436
3536
  };
3537
+ const maxToolRoundtrips = this.options?.maxToolRoundtrips ?? 1;
3538
+ const toolRoundtrips = message.roundtrips?.length ?? 0;
3539
+ if (toolRoundtrips > maxToolRoundtrips) {
3540
+ updateMessage({
3541
+ status: {
3542
+ type: "incomplete",
3543
+ reason: "tool-calls"
3544
+ }
3545
+ });
3546
+ return message;
3547
+ } else {
3548
+ updateMessage({
3549
+ status: {
3550
+ type: "running"
3551
+ }
3552
+ });
3553
+ }
3437
3554
  try {
3438
3555
  const result = await this.adapter.run({
3439
3556
  messages,
@@ -3441,21 +3558,29 @@ var LocalThreadRuntime = class {
3441
3558
  config: this.configProvider.getModelConfig(),
3442
3559
  onUpdate: updateMessage
3443
3560
  });
3444
- if (result.status?.type === "in_progress")
3561
+ if (result.status?.type === "running")
3445
3562
  throw new Error(
3446
- "Unexpected in_progress status returned from ChatModelAdapter"
3563
+ "Unexpected running status returned from ChatModelAdapter"
3447
3564
  );
3448
3565
  this.abortController = null;
3449
- updateMessage({ status: { type: "done" }, ...result });
3450
- this.repository.addOrUpdateMessage(parentId, { ...message });
3451
- } catch (e) {
3452
- const isAbortError = e instanceof Error && e.name === "AbortError";
3453
- this.abortController = null;
3454
3566
  updateMessage({
3455
- status: isAbortError ? { type: "cancelled" } : { type: "error", error: e }
3567
+ status: { type: "complete", reason: "unknown" },
3568
+ ...result
3456
3569
  });
3457
- if (!isAbortError) throw e;
3570
+ } catch (e) {
3571
+ this.abortController = null;
3572
+ if (e instanceof Error && e.name === "AbortError") {
3573
+ updateMessage({
3574
+ status: { type: "incomplete", reason: "cancelled" }
3575
+ });
3576
+ } else {
3577
+ updateMessage({
3578
+ status: { type: "incomplete", reason: "error", error: e }
3579
+ });
3580
+ throw e;
3581
+ }
3458
3582
  }
3583
+ return message;
3459
3584
  }
3460
3585
  cancelRun() {
3461
3586
  if (!this.abortController) return;
@@ -3470,14 +3595,16 @@ var LocalThreadRuntime = class {
3470
3595
  return () => this._subscriptions.delete(callback);
3471
3596
  }
3472
3597
  addToolResult({ messageId, toolCallId, result }) {
3473
- const { parentId, message } = this.repository.getMessage(messageId);
3598
+ let { parentId, message } = this.repository.getMessage(messageId);
3474
3599
  if (message.role !== "assistant")
3475
3600
  throw new Error("Tried to add tool result to non-assistant message");
3601
+ let added = false;
3476
3602
  let found = false;
3477
3603
  const newContent = message.content.map((c) => {
3478
3604
  if (c.type !== "tool-call") return c;
3479
3605
  if (c.toolCallId !== toolCallId) return c;
3480
3606
  found = true;
3607
+ if (!c.result) added = true;
3481
3608
  return {
3482
3609
  ...c,
3483
3610
  result
@@ -3485,10 +3612,14 @@ var LocalThreadRuntime = class {
3485
3612
  });
3486
3613
  if (!found)
3487
3614
  throw new Error("Tried to add tool result to non-existing tool call");
3488
- this.repository.addOrUpdateMessage(parentId, {
3615
+ message = {
3489
3616
  ...message,
3490
3617
  content: newContent
3491
- });
3618
+ };
3619
+ this.repository.addOrUpdateMessage(parentId, message);
3620
+ if (added && shouldContinue(message)) {
3621
+ this.performRoundtrip(parentId, message);
3622
+ }
3492
3623
  }
3493
3624
  };
3494
3625
 
@@ -3683,7 +3814,7 @@ var Text = ({ status }) => {
3683
3814
  {
3684
3815
  className: (0, import_classnames2.default)(
3685
3816
  "aui-text",
3686
- status.type === "in_progress" && "aui-text-in-progress"
3817
+ status.type === "running" && "aui-text-in-progress"
3687
3818
  ),
3688
3819
  children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(contentPart_exports.Text, {})
3689
3820
  }
@@ -4210,11 +4341,13 @@ var assistant_modal_default = Object.assign(AssistantModal, exports12);
4210
4341
  ThreadWelcome,
4211
4342
  UserActionBar,
4212
4343
  UserMessage,
4344
+ fromCoreMessage,
4213
4345
  fromCoreMessages,
4214
4346
  fromLanguageModelMessages,
4215
4347
  fromLanguageModelTools,
4216
4348
  makeAssistantTool,
4217
4349
  makeAssistantToolUI,
4350
+ toCoreMessage,
4218
4351
  toCoreMessages,
4219
4352
  toLanguageModelMessages,
4220
4353
  toLanguageModelTools,