@assistant-ui/react 0.4.8 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -307,13 +307,17 @@ var ThreadProvider = ({
307
307
  useCallback2(
308
308
  (thread) => {
309
309
  const onThreadUpdate = () => {
310
- context.useThread.setState(
311
- Object.freeze({
312
- isRunning: context.useThreadRuntime.getState().isRunning
313
- }),
314
- true
315
- );
316
- context.useThreadMessages.setState(thread.messages, true);
310
+ if (thread.isRunning !== context.useThread.getState().isRunning) {
311
+ context.useThread.setState(
312
+ Object.freeze({
313
+ isRunning: thread.isRunning
314
+ }),
315
+ true
316
+ );
317
+ }
318
+ if (thread.messages !== context.useThreadMessages.getState()) {
319
+ context.useThreadMessages.setState(thread.messages, true);
320
+ }
317
321
  };
318
322
  onThreadUpdate();
319
323
  return thread.subscribe(onThreadUpdate);
@@ -1169,12 +1173,28 @@ import { memo as memo2 } from "react";
1169
1173
  import { useEffect as useEffect6, useState as useState4 } from "react";
1170
1174
  import { create as create10 } from "zustand";
1171
1175
  import { jsx as jsx13 } from "react/jsx-runtime";
1172
- var DONE_STATUS = { type: "done" };
1176
+ var COMPLETE_STATUS = {
1177
+ type: "complete"
1178
+ };
1179
+ var toContentPartStatus = (message, partIndex, part) => {
1180
+ if (message.role !== "assistant") return COMPLETE_STATUS;
1181
+ const isLastPart = partIndex === message.content.length - 1;
1182
+ if (part.type !== "tool-call") {
1183
+ if ("reason" in message.status && message.status.reason === "tool-calls" && isLastPart)
1184
+ throw new Error(
1185
+ "Encountered unexpected requires-action status. This is likely an internal bug in assistant-ui."
1186
+ );
1187
+ return isLastPart ? message.status : COMPLETE_STATUS;
1188
+ }
1189
+ if (!!part.result) {
1190
+ return COMPLETE_STATUS;
1191
+ }
1192
+ return message.status;
1193
+ };
1173
1194
  var syncContentPart = ({ message }, useContentPart, partIndex) => {
1174
1195
  const part = message.content[partIndex];
1175
1196
  if (!part) return;
1176
- const messageStatus = message.role === "assistant" ? message.status : DONE_STATUS;
1177
- const status = partIndex === message.content.length - 1 ? messageStatus : DONE_STATUS;
1197
+ const status = toContentPartStatus(message, partIndex, part);
1178
1198
  const currentState = useContentPart.getState();
1179
1199
  if (currentState.part === part && currentState.status === status) return;
1180
1200
  useContentPart.setState(
@@ -1327,7 +1347,7 @@ ContentPartPrimitiveDisplay.displayName = "ContentPartPrimitive.Display";
1327
1347
  // src/primitives/contentPart/ContentPartInProgress.tsx
1328
1348
  var ContentPartPrimitiveInProgress = ({ children }) => {
1329
1349
  const { useContentPart } = useContentPartContext();
1330
- const isInProgress = useContentPart((c) => c.status.type === "in_progress");
1350
+ const isInProgress = useContentPart((c) => c.status.type === "running");
1331
1351
  return isInProgress ? children : null;
1332
1352
  };
1333
1353
  ContentPartPrimitiveInProgress.displayName = "ContentPartPrimitive.InProgress";
@@ -1366,10 +1386,16 @@ var MessageContentPartComponent = ({
1366
1386
  const type = part.type;
1367
1387
  switch (type) {
1368
1388
  case "text":
1389
+ if (status.type === "requires-action")
1390
+ throw new Error("Encountered unexpected requires-action status");
1369
1391
  return /* @__PURE__ */ jsx16(Text2, { part, status });
1370
1392
  case "image":
1393
+ if (status.type === "requires-action")
1394
+ throw new Error("Encountered unexpected requires-action status");
1371
1395
  return /* @__PURE__ */ jsx16(Image2, { part, status });
1372
1396
  case "ui":
1397
+ if (status.type === "requires-action")
1398
+ throw new Error("Encountered unexpected requires-action status");
1373
1399
  return /* @__PURE__ */ jsx16(UI, { part, status });
1374
1400
  case "tool-call": {
1375
1401
  const Tool = by_name[part.toolName] || Fallback2;
@@ -1948,6 +1974,184 @@ var generateId = customAlphabet(
1948
1974
  var optimisticPrefix = "__optimistic__";
1949
1975
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1950
1976
 
1977
+ // src/internal.ts
1978
+ var internal_exports = {};
1979
+ __export(internal_exports, {
1980
+ BaseAssistantRuntime: () => BaseAssistantRuntime,
1981
+ MessageRepository: () => MessageRepository,
1982
+ ProxyConfigProvider: () => ProxyConfigProvider,
1983
+ TooltipIconButton: () => TooltipIconButton,
1984
+ generateId: () => generateId,
1985
+ useSmooth: () => useSmooth
1986
+ });
1987
+
1988
+ // src/runtimes/core/BaseAssistantRuntime.tsx
1989
+ var BaseAssistantRuntime = class {
1990
+ constructor(_thread) {
1991
+ this._thread = _thread;
1992
+ this._thread = _thread;
1993
+ }
1994
+ get thread() {
1995
+ return this._thread;
1996
+ }
1997
+ set thread(thread) {
1998
+ this._thread = thread;
1999
+ this.subscriptionHandler();
2000
+ }
2001
+ _subscriptions = /* @__PURE__ */ new Set();
2002
+ subscribe(callback) {
2003
+ this._subscriptions.add(callback);
2004
+ return () => this._subscriptions.delete(callback);
2005
+ }
2006
+ subscriptionHandler = () => {
2007
+ for (const callback of this._subscriptions) callback();
2008
+ };
2009
+ };
2010
+
2011
+ // src/ui/base/tooltip-icon-button.tsx
2012
+ import { forwardRef as forwardRef17 } from "react";
2013
+
2014
+ // src/ui/base/tooltip.tsx
2015
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
2016
+
2017
+ // src/ui/utils/withDefaults.tsx
2018
+ import {
2019
+ forwardRef as forwardRef15
2020
+ } from "react";
2021
+ import classNames from "classnames";
2022
+ import { jsx as jsx25 } from "react/jsx-runtime";
2023
+ var withDefaultProps = ({
2024
+ className,
2025
+ ...defaultProps
2026
+ }) => ({ className: classNameProp, ...props }) => {
2027
+ return {
2028
+ className: classNames(className, classNameProp),
2029
+ ...defaultProps,
2030
+ ...props
2031
+ };
2032
+ };
2033
+ var withDefaults = (Component, defaultProps) => {
2034
+ const getProps = withDefaultProps(defaultProps);
2035
+ const WithDefaults = forwardRef15(
2036
+ (props, ref) => {
2037
+ const ComponentAsAny = Component;
2038
+ return /* @__PURE__ */ jsx25(ComponentAsAny, { ...getProps(props), ref });
2039
+ }
2040
+ );
2041
+ WithDefaults.displayName = "withDefaults(" + (typeof Component === "string" ? Component : Component.displayName) + ")";
2042
+ return WithDefaults;
2043
+ };
2044
+
2045
+ // src/ui/base/tooltip.tsx
2046
+ import { jsx as jsx26 } from "react/jsx-runtime";
2047
+ var Tooltip = (props) => {
2048
+ return /* @__PURE__ */ jsx26(TooltipPrimitive.Provider, { children: /* @__PURE__ */ jsx26(TooltipPrimitive.Root, { ...props }) });
2049
+ };
2050
+ Tooltip.displayName = "Tooltip";
2051
+ var TooltipTrigger = TooltipPrimitive.Trigger;
2052
+ var TooltipContent = withDefaults(TooltipPrimitive.Content, {
2053
+ sideOffset: 4,
2054
+ className: "aui-tooltip-content"
2055
+ });
2056
+ TooltipContent.displayName = "TooltipContent";
2057
+
2058
+ // src/ui/base/button.tsx
2059
+ import { cva } from "class-variance-authority";
2060
+ import { Primitive as Primitive11 } from "@radix-ui/react-primitive";
2061
+ import { forwardRef as forwardRef16 } from "react";
2062
+ import { jsx as jsx27 } from "react/jsx-runtime";
2063
+ var buttonVariants = cva("aui-button", {
2064
+ variants: {
2065
+ variant: {
2066
+ default: "aui-button-primary",
2067
+ outline: "aui-button-outline",
2068
+ ghost: "aui-button-ghost"
2069
+ },
2070
+ size: {
2071
+ default: "aui-button-medium",
2072
+ icon: "aui-button-icon"
2073
+ }
2074
+ },
2075
+ defaultVariants: {
2076
+ variant: "default",
2077
+ size: "default"
2078
+ }
2079
+ });
2080
+ var Button = forwardRef16(
2081
+ ({ className, variant, size, ...props }, ref) => {
2082
+ return /* @__PURE__ */ jsx27(
2083
+ Primitive11.button,
2084
+ {
2085
+ className: buttonVariants({ variant, size, className }),
2086
+ ...props,
2087
+ ref
2088
+ }
2089
+ );
2090
+ }
2091
+ );
2092
+ Button.displayName = "Button";
2093
+
2094
+ // src/ui/base/tooltip-icon-button.tsx
2095
+ import { jsx as jsx28, jsxs as jsxs4 } from "react/jsx-runtime";
2096
+ var TooltipIconButton = forwardRef17(({ children, tooltip, side = "bottom", ...rest }, ref) => {
2097
+ return /* @__PURE__ */ jsxs4(Tooltip, { children: [
2098
+ /* @__PURE__ */ jsx28(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(Button, { variant: "ghost", size: "icon", ...rest, ref, children: [
2099
+ children,
2100
+ /* @__PURE__ */ jsx28("span", { className: "aui-sr-only", children: tooltip })
2101
+ ] }) }),
2102
+ /* @__PURE__ */ jsx28(TooltipContent, { side, children: tooltip })
2103
+ ] });
2104
+ });
2105
+ TooltipIconButton.displayName = "TooltipIconButton";
2106
+
2107
+ // src/runtimes/edge/converters/fromCoreMessage.ts
2108
+ var fromCoreMessages = (message) => {
2109
+ return message.map((message2) => fromCoreMessage(message2));
2110
+ };
2111
+ var fromCoreMessage = (message, {
2112
+ id = generateId(),
2113
+ status = { type: "complete", reason: "unknown" }
2114
+ } = {}) => {
2115
+ const commonProps = {
2116
+ id,
2117
+ createdAt: /* @__PURE__ */ new Date()
2118
+ };
2119
+ const role = message.role;
2120
+ switch (role) {
2121
+ case "assistant":
2122
+ return {
2123
+ ...commonProps,
2124
+ role,
2125
+ content: message.content.map((part) => {
2126
+ if (part.type === "tool-call") {
2127
+ return {
2128
+ ...part,
2129
+ argsText: JSON.stringify(part.args)
2130
+ };
2131
+ }
2132
+ return part;
2133
+ }),
2134
+ status
2135
+ };
2136
+ case "user":
2137
+ return {
2138
+ ...commonProps,
2139
+ role,
2140
+ content: message.content
2141
+ };
2142
+ case "system":
2143
+ return {
2144
+ ...commonProps,
2145
+ role,
2146
+ content: message.content
2147
+ };
2148
+ default: {
2149
+ const unsupportedRole = role;
2150
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
2151
+ }
2152
+ }
2153
+ };
2154
+
1951
2155
  // src/runtimes/utils/MessageRepository.tsx
1952
2156
  var findHead = (message) => {
1953
2157
  if (message.next) return findHead(message.next);
@@ -2038,12 +2242,13 @@ var MessageRepository = class {
2038
2242
  do {
2039
2243
  optimisticId = generateOptimisticId();
2040
2244
  } while (this.messages.has(optimisticId));
2041
- this.addOrUpdateMessage(parentId, {
2042
- ...message,
2043
- id: optimisticId,
2044
- createdAt: /* @__PURE__ */ new Date(),
2045
- ...message.role === "assistant" ? { status: "in_progress" } : void 0
2046
- });
2245
+ this.addOrUpdateMessage(
2246
+ parentId,
2247
+ fromCoreMessage(message, {
2248
+ id: optimisticId,
2249
+ status: { type: "running" }
2250
+ })
2251
+ );
2047
2252
  return optimisticId;
2048
2253
  }
2049
2254
  deleteMessage(messageId, replacementId) {
@@ -2110,136 +2315,6 @@ var MessageRepository = class {
2110
2315
  }
2111
2316
  };
2112
2317
 
2113
- // src/runtimes/core/BaseAssistantRuntime.tsx
2114
- var BaseAssistantRuntime = class {
2115
- constructor(_thread) {
2116
- this._thread = _thread;
2117
- this._thread = _thread;
2118
- }
2119
- get thread() {
2120
- return this._thread;
2121
- }
2122
- set thread(thread) {
2123
- this._thread = thread;
2124
- this.subscriptionHandler();
2125
- }
2126
- _subscriptions = /* @__PURE__ */ new Set();
2127
- subscribe(callback) {
2128
- this._subscriptions.add(callback);
2129
- return () => this._subscriptions.delete(callback);
2130
- }
2131
- subscriptionHandler = () => {
2132
- for (const callback of this._subscriptions) callback();
2133
- };
2134
- };
2135
-
2136
- // src/internal.ts
2137
- var internal_exports = {};
2138
- __export(internal_exports, {
2139
- BaseAssistantRuntime: () => BaseAssistantRuntime,
2140
- MessageRepository: () => MessageRepository,
2141
- ProxyConfigProvider: () => ProxyConfigProvider,
2142
- TooltipIconButton: () => TooltipIconButton,
2143
- generateId: () => generateId,
2144
- useSmooth: () => useSmooth
2145
- });
2146
-
2147
- // src/ui/base/tooltip-icon-button.tsx
2148
- import { forwardRef as forwardRef17 } from "react";
2149
-
2150
- // src/ui/base/tooltip.tsx
2151
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
2152
-
2153
- // src/ui/utils/withDefaults.tsx
2154
- import {
2155
- forwardRef as forwardRef15
2156
- } from "react";
2157
- import classNames from "classnames";
2158
- import { jsx as jsx25 } from "react/jsx-runtime";
2159
- var withDefaultProps = ({
2160
- className,
2161
- ...defaultProps
2162
- }) => ({ className: classNameProp, ...props }) => {
2163
- return {
2164
- className: classNames(className, classNameProp),
2165
- ...defaultProps,
2166
- ...props
2167
- };
2168
- };
2169
- var withDefaults = (Component, defaultProps) => {
2170
- const getProps = withDefaultProps(defaultProps);
2171
- const WithDefaults = forwardRef15(
2172
- (props, ref) => {
2173
- const ComponentAsAny = Component;
2174
- return /* @__PURE__ */ jsx25(ComponentAsAny, { ...getProps(props), ref });
2175
- }
2176
- );
2177
- WithDefaults.displayName = "withDefaults(" + (typeof Component === "string" ? Component : Component.displayName) + ")";
2178
- return WithDefaults;
2179
- };
2180
-
2181
- // src/ui/base/tooltip.tsx
2182
- import { jsx as jsx26 } from "react/jsx-runtime";
2183
- var Tooltip = (props) => {
2184
- return /* @__PURE__ */ jsx26(TooltipPrimitive.Provider, { children: /* @__PURE__ */ jsx26(TooltipPrimitive.Root, { ...props }) });
2185
- };
2186
- Tooltip.displayName = "Tooltip";
2187
- var TooltipTrigger = TooltipPrimitive.Trigger;
2188
- var TooltipContent = withDefaults(TooltipPrimitive.Content, {
2189
- sideOffset: 4,
2190
- className: "aui-tooltip-content"
2191
- });
2192
- TooltipContent.displayName = "TooltipContent";
2193
-
2194
- // src/ui/base/button.tsx
2195
- import { cva } from "class-variance-authority";
2196
- import { Primitive as Primitive11 } from "@radix-ui/react-primitive";
2197
- import { forwardRef as forwardRef16 } from "react";
2198
- import { jsx as jsx27 } from "react/jsx-runtime";
2199
- var buttonVariants = cva("aui-button", {
2200
- variants: {
2201
- variant: {
2202
- default: "aui-button-primary",
2203
- outline: "aui-button-outline",
2204
- ghost: "aui-button-ghost"
2205
- },
2206
- size: {
2207
- default: "aui-button-medium",
2208
- icon: "aui-button-icon"
2209
- }
2210
- },
2211
- defaultVariants: {
2212
- variant: "default",
2213
- size: "default"
2214
- }
2215
- });
2216
- var Button = forwardRef16(
2217
- ({ className, variant, size, ...props }, ref) => {
2218
- return /* @__PURE__ */ jsx27(
2219
- Primitive11.button,
2220
- {
2221
- className: buttonVariants({ variant, size, className }),
2222
- ...props,
2223
- ref
2224
- }
2225
- );
2226
- }
2227
- );
2228
- Button.displayName = "Button";
2229
-
2230
- // src/ui/base/tooltip-icon-button.tsx
2231
- import { jsx as jsx28, jsxs as jsxs4 } from "react/jsx-runtime";
2232
- var TooltipIconButton = forwardRef17(({ children, tooltip, side = "bottom", ...rest }, ref) => {
2233
- return /* @__PURE__ */ jsxs4(Tooltip, { children: [
2234
- /* @__PURE__ */ jsx28(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(Button, { variant: "ghost", size: "icon", ...rest, ref, children: [
2235
- children,
2236
- /* @__PURE__ */ jsx28("span", { className: "aui-sr-only", children: tooltip })
2237
- ] }) }),
2238
- /* @__PURE__ */ jsx28(TooltipContent, { side, children: tooltip })
2239
- ] });
2240
- });
2241
- TooltipIconButton.displayName = "TooltipIconButton";
2242
-
2243
2318
  // src/runtimes/edge/converters/toLanguageModelMessages.ts
2244
2319
  var assistantMessageSplitter = () => {
2245
2320
  const stash = [];
@@ -2460,35 +2535,43 @@ var fromLanguageModelMessages = (lm, { mergeRoundtrips }) => {
2460
2535
  return messages;
2461
2536
  };
2462
2537
 
2463
- // src/runtimes/edge/converters/fromCoreMessage.ts
2464
- var fromCoreMessages = (message) => {
2465
- return message.map((message2) => {
2466
- return {
2467
- id: generateId(),
2468
- createdAt: /* @__PURE__ */ new Date(),
2469
- ...message2.role === "assistant" ? {
2470
- status: { type: "done" }
2471
- } : void 0,
2472
- ...message2
2473
- };
2474
- });
2475
- };
2476
-
2477
2538
  // src/runtimes/edge/converters/toCoreMessages.ts
2478
2539
  var toCoreMessages = (message) => {
2479
- return message.map((message2) => {
2480
- return {
2481
- role: message2.role,
2482
- content: message2.content.map((part) => {
2483
- if (part.type === "ui") throw new Error("UI parts are not supported");
2484
- if (part.type === "tool-call") {
2485
- const { argsText, ...rest } = part;
2486
- return rest;
2487
- }
2488
- return part;
2489
- })
2490
- };
2491
- });
2540
+ return message.map(toCoreMessage);
2541
+ };
2542
+ var toCoreMessage = (message) => {
2543
+ const role = message.role;
2544
+ switch (role) {
2545
+ case "assistant":
2546
+ return {
2547
+ role,
2548
+ content: message.content.map((part) => {
2549
+ if (part.type === "ui") throw new Error("UI parts are not supported");
2550
+ if (part.type === "tool-call") {
2551
+ const { argsText, ...rest } = part;
2552
+ return rest;
2553
+ }
2554
+ return part;
2555
+ })
2556
+ };
2557
+ case "user":
2558
+ return {
2559
+ role,
2560
+ content: message.content.map((part) => {
2561
+ if (part.type === "ui") throw new Error("UI parts are not supported");
2562
+ return part;
2563
+ })
2564
+ };
2565
+ case "system":
2566
+ return {
2567
+ role,
2568
+ content: message.content
2569
+ };
2570
+ default: {
2571
+ const unsupportedRole = role;
2572
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
2573
+ }
2574
+ }
2492
2575
  };
2493
2576
 
2494
2577
  // src/runtimes/edge/converters/fromLanguageModelTools.ts
@@ -2958,9 +3041,10 @@ var parsePartialJson = (json) => {
2958
3041
  };
2959
3042
 
2960
3043
  // src/runtimes/edge/streams/runResultStream.ts
2961
- function runResultStream(initialContent) {
3044
+ function runResultStream() {
2962
3045
  let message = {
2963
- content: initialContent
3046
+ content: [],
3047
+ status: { type: "running" }
2964
3048
  };
2965
3049
  const currentToolCall = { toolCallId: "", argsText: "" };
2966
3050
  return new TransformStream({
@@ -3008,7 +3092,13 @@ function runResultStream(initialContent) {
3008
3092
  break;
3009
3093
  }
3010
3094
  case "error": {
3011
- throw chunk.error;
3095
+ if (chunk.error instanceof Error && chunk.error.name === "AbortError") {
3096
+ message = appendOrUpdateCancel(message);
3097
+ controller.enqueue(message);
3098
+ break;
3099
+ } else {
3100
+ throw chunk.error;
3101
+ }
3012
3102
  }
3013
3103
  default: {
3014
3104
  const unhandledType = chunkType;
@@ -3082,11 +3172,42 @@ var appendOrUpdateToolResult = (message, toolCallId, toolName, result) => {
3082
3172
  };
3083
3173
  var appendOrUpdateFinish = (message, chunk) => {
3084
3174
  const { type, ...rest } = chunk;
3175
+ return {
3176
+ ...message,
3177
+ status: getStatus(chunk),
3178
+ roundtrips: [
3179
+ ...message.roundtrips ?? [],
3180
+ {
3181
+ logprobs: rest.logprobs,
3182
+ usage: rest.usage
3183
+ }
3184
+ ]
3185
+ };
3186
+ };
3187
+ var getStatus = (chunk) => {
3188
+ if (chunk.finishReason === "tool-calls") {
3189
+ return {
3190
+ type: "requires-action",
3191
+ reason: "tool-calls"
3192
+ };
3193
+ } else if (chunk.finishReason === "stop" || chunk.finishReason === "unknown") {
3194
+ return {
3195
+ type: "complete",
3196
+ reason: chunk.finishReason
3197
+ };
3198
+ } else {
3199
+ return {
3200
+ type: "incomplete",
3201
+ reason: chunk.finishReason
3202
+ };
3203
+ }
3204
+ };
3205
+ var appendOrUpdateCancel = (message) => {
3085
3206
  return {
3086
3207
  ...message,
3087
3208
  status: {
3088
- type: "done",
3089
- ...rest
3209
+ type: "incomplete",
3210
+ reason: "cancelled"
3090
3211
  }
3091
3212
  };
3092
3213
  };
@@ -3186,7 +3307,7 @@ var EdgeChatAdapter = class {
3186
3307
  constructor(options) {
3187
3308
  this.options = options;
3188
3309
  }
3189
- async roundtrip(initialContent, { messages, abortSignal, config, onUpdate }) {
3310
+ async run({ messages, abortSignal, config, onUpdate }) {
3190
3311
  const result = await fetch(this.options.api, {
3191
3312
  method: "POST",
3192
3313
  headers: {
@@ -3206,46 +3327,14 @@ var EdgeChatAdapter = class {
3206
3327
  `Edge runtime returned status ${result.status}: ${await result.text()}`
3207
3328
  );
3208
3329
  }
3209
- const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream(initialContent));
3210
- let message;
3330
+ const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream());
3211
3331
  let update;
3212
3332
  for await (update of asAsyncIterable(stream)) {
3213
- message = onUpdate(update);
3333
+ onUpdate(update);
3214
3334
  }
3215
3335
  if (update === void 0)
3216
3336
  throw new Error("No data received from Edge Runtime");
3217
- return [message, update];
3218
- }
3219
- async run({ messages, abortSignal, config, onUpdate }) {
3220
- let roundtripAllowance = this.options.maxToolRoundtrips ?? 1;
3221
- let usage = {
3222
- promptTokens: 0,
3223
- completionTokens: 0
3224
- };
3225
- let result;
3226
- let assistantMessage;
3227
- do {
3228
- [assistantMessage, result] = await this.roundtrip(result?.content ?? [], {
3229
- messages: assistantMessage ? [...messages, assistantMessage] : messages,
3230
- abortSignal,
3231
- config,
3232
- onUpdate
3233
- });
3234
- if (result.status?.type === "done") {
3235
- usage.promptTokens += result.status.usage?.promptTokens ?? 0;
3236
- usage.completionTokens += result.status.usage?.completionTokens ?? 0;
3237
- }
3238
- } while (result.status?.type === "done" && result.status.finishReason === "tool-calls" && result.content.every((c) => c.type !== "tool-call" || !!c.result) && roundtripAllowance-- > 0);
3239
- if (result.status?.type === "done" && usage.promptTokens > 0) {
3240
- result = {
3241
- ...result,
3242
- status: {
3243
- ...result.status,
3244
- usage
3245
- }
3246
- };
3247
- }
3248
- return result;
3337
+ return update;
3249
3338
  }
3250
3339
  };
3251
3340
 
@@ -3259,6 +3348,7 @@ var useEdgeRuntime = ({
3259
3348
  };
3260
3349
 
3261
3350
  // src/runtimes/local/LocalRuntime.tsx
3351
+ var shouldContinue = (result) => result.status?.type === "requires-action" && result.status.reason === "tool-calls" && result.content.every((c) => c.type !== "tool-call" || !!c.result);
3262
3352
  var LocalRuntime = class extends BaseAssistantRuntime {
3263
3353
  _proxyConfigProvider;
3264
3354
  constructor(adapter, options) {
@@ -3292,6 +3382,7 @@ var LocalThreadRuntime = class {
3292
3382
  constructor(configProvider, adapter, options) {
3293
3383
  this.configProvider = configProvider;
3294
3384
  this.adapter = adapter;
3385
+ this.options = options;
3295
3386
  if (options?.initialMessages) {
3296
3387
  let parentId = null;
3297
3388
  const messages = fromCoreMessages(options.initialMessages);
@@ -3335,27 +3426,51 @@ var LocalThreadRuntime = class {
3335
3426
  }
3336
3427
  async startRun(parentId) {
3337
3428
  this.repository.resetHead(parentId);
3338
- const messages = this.repository.getMessages();
3429
+ const id = generateId();
3339
3430
  let message = {
3340
- id: generateId(),
3431
+ id,
3341
3432
  role: "assistant",
3342
- status: { type: "in_progress" },
3433
+ status: { type: "running" },
3343
3434
  content: [{ type: "text", text: "" }],
3344
3435
  createdAt: /* @__PURE__ */ new Date()
3345
3436
  };
3437
+ do {
3438
+ message = await this.performRoundtrip(parentId, message);
3439
+ } while (shouldContinue(message));
3440
+ }
3441
+ async performRoundtrip(parentId, message) {
3442
+ const messages = this.repository.getMessages();
3346
3443
  this.abortController?.abort();
3347
3444
  this.abortController = new AbortController();
3348
- this.repository.addOrUpdateMessage(parentId, { ...message });
3349
- this.notifySubscribers();
3445
+ const initialContent = message.content;
3446
+ const initialRoundtrips = message.roundtrips;
3350
3447
  const updateMessage = (m) => {
3351
3448
  message = {
3352
3449
  ...message,
3353
- ...m
3450
+ ...m.content ? { content: [...initialContent, ...m.content ?? []] } : void 0,
3451
+ status: m.status ?? message.status,
3452
+ ...m.roundtrips?.length ? { roundtrips: [...initialRoundtrips ?? [], ...m.roundtrips] } : void 0
3354
3453
  };
3355
3454
  this.repository.addOrUpdateMessage(parentId, message);
3356
3455
  this.notifySubscribers();
3357
- return message;
3358
3456
  };
3457
+ const maxToolRoundtrips = this.options?.maxToolRoundtrips ?? 1;
3458
+ const toolRoundtrips = message.roundtrips?.length ?? 0;
3459
+ if (toolRoundtrips > maxToolRoundtrips) {
3460
+ updateMessage({
3461
+ status: {
3462
+ type: "incomplete",
3463
+ reason: "tool-calls"
3464
+ }
3465
+ });
3466
+ return message;
3467
+ } else {
3468
+ updateMessage({
3469
+ status: {
3470
+ type: "running"
3471
+ }
3472
+ });
3473
+ }
3359
3474
  try {
3360
3475
  const result = await this.adapter.run({
3361
3476
  messages,
@@ -3363,21 +3478,29 @@ var LocalThreadRuntime = class {
3363
3478
  config: this.configProvider.getModelConfig(),
3364
3479
  onUpdate: updateMessage
3365
3480
  });
3366
- if (result.status?.type === "in_progress")
3481
+ if (result.status?.type === "running")
3367
3482
  throw new Error(
3368
- "Unexpected in_progress status returned from ChatModelAdapter"
3483
+ "Unexpected running status returned from ChatModelAdapter"
3369
3484
  );
3370
3485
  this.abortController = null;
3371
- updateMessage({ status: { type: "done" }, ...result });
3372
- this.repository.addOrUpdateMessage(parentId, { ...message });
3373
- } catch (e) {
3374
- const isAbortError = e instanceof Error && e.name === "AbortError";
3375
- this.abortController = null;
3376
3486
  updateMessage({
3377
- status: isAbortError ? { type: "cancelled" } : { type: "error", error: e }
3487
+ status: { type: "complete", reason: "unknown" },
3488
+ ...result
3378
3489
  });
3379
- if (!isAbortError) throw e;
3490
+ } catch (e) {
3491
+ this.abortController = null;
3492
+ if (e instanceof Error && e.name === "AbortError") {
3493
+ updateMessage({
3494
+ status: { type: "incomplete", reason: "cancelled" }
3495
+ });
3496
+ } else {
3497
+ updateMessage({
3498
+ status: { type: "incomplete", reason: "error", error: e }
3499
+ });
3500
+ throw e;
3501
+ }
3380
3502
  }
3503
+ return message;
3381
3504
  }
3382
3505
  cancelRun() {
3383
3506
  if (!this.abortController) return;
@@ -3392,14 +3515,16 @@ var LocalThreadRuntime = class {
3392
3515
  return () => this._subscriptions.delete(callback);
3393
3516
  }
3394
3517
  addToolResult({ messageId, toolCallId, result }) {
3395
- const { parentId, message } = this.repository.getMessage(messageId);
3518
+ let { parentId, message } = this.repository.getMessage(messageId);
3396
3519
  if (message.role !== "assistant")
3397
3520
  throw new Error("Tried to add tool result to non-assistant message");
3521
+ let added = false;
3398
3522
  let found = false;
3399
3523
  const newContent = message.content.map((c) => {
3400
3524
  if (c.type !== "tool-call") return c;
3401
3525
  if (c.toolCallId !== toolCallId) return c;
3402
3526
  found = true;
3527
+ if (!c.result) added = true;
3403
3528
  return {
3404
3529
  ...c,
3405
3530
  result
@@ -3407,10 +3532,14 @@ var LocalThreadRuntime = class {
3407
3532
  });
3408
3533
  if (!found)
3409
3534
  throw new Error("Tried to add tool result to non-existing tool call");
3410
- this.repository.addOrUpdateMessage(parentId, {
3535
+ message = {
3411
3536
  ...message,
3412
3537
  content: newContent
3413
- });
3538
+ };
3539
+ this.repository.addOrUpdateMessage(parentId, message);
3540
+ if (added && shouldContinue(message)) {
3541
+ this.performRoundtrip(parentId, message);
3542
+ }
3414
3543
  }
3415
3544
  };
3416
3545
 
@@ -3605,7 +3734,7 @@ var Text = ({ status }) => {
3605
3734
  {
3606
3735
  className: classNames2(
3607
3736
  "aui-text",
3608
- status.type === "in_progress" && "aui-text-in-progress"
3737
+ status.type === "running" && "aui-text-in-progress"
3609
3738
  ),
3610
3739
  children: /* @__PURE__ */ jsx33(contentPart_exports.Text, {})
3611
3740
  }
@@ -4131,11 +4260,13 @@ export {
4131
4260
  thread_welcome_default as ThreadWelcome,
4132
4261
  user_action_bar_default as UserActionBar,
4133
4262
  user_message_default as UserMessage,
4263
+ fromCoreMessage,
4134
4264
  fromCoreMessages,
4135
4265
  fromLanguageModelMessages,
4136
4266
  fromLanguageModelTools,
4137
4267
  makeAssistantTool,
4138
4268
  makeAssistantToolUI,
4269
+ toCoreMessage,
4139
4270
  toCoreMessages,
4140
4271
  toLanguageModelMessages,
4141
4272
  toLanguageModelTools,