@assistant-ui/react 0.4.7 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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,