@assistant-ui/react 0.4.8 → 0.5.2

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.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,35 @@ 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 === Math.max(0, 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
+ };
1194
+ var EMPTY_CONTENT = Object.freeze({ type: "text", text: "" });
1173
1195
  var syncContentPart = ({ message }, useContentPart, partIndex) => {
1174
- const part = message.content[partIndex];
1175
- if (!part) return;
1176
- const messageStatus = message.role === "assistant" ? message.status : DONE_STATUS;
1177
- const status = partIndex === message.content.length - 1 ? messageStatus : DONE_STATUS;
1196
+ let part = message.content[partIndex];
1197
+ if (!part) {
1198
+ if (message.content.length === 0 && partIndex === 0) {
1199
+ part = EMPTY_CONTENT;
1200
+ } else {
1201
+ return;
1202
+ }
1203
+ }
1204
+ const status = toContentPartStatus(message, partIndex, part);
1178
1205
  const currentState = useContentPart.getState();
1179
1206
  if (currentState.part === part && currentState.status === status) return;
1180
1207
  useContentPart.setState(
@@ -1299,7 +1326,7 @@ var ContentPartPrimitiveText = forwardRef7(({ smooth = true, ...rest }, forwarde
1299
1326
  part: { text }
1300
1327
  } = useContentPartText();
1301
1328
  const smoothText = useSmooth(text, smooth);
1302
- return /* @__PURE__ */ jsx14(Primitive4.span, { "data-status": status, ...rest, ref: forwardedRef, children: smoothText });
1329
+ return /* @__PURE__ */ jsx14(Primitive4.span, { "data-status": status.type, ...rest, ref: forwardedRef, children: smoothText });
1303
1330
  });
1304
1331
  ContentPartPrimitiveText.displayName = "ContentPartPrimitive.Text";
1305
1332
 
@@ -1327,7 +1354,7 @@ ContentPartPrimitiveDisplay.displayName = "ContentPartPrimitive.Display";
1327
1354
  // src/primitives/contentPart/ContentPartInProgress.tsx
1328
1355
  var ContentPartPrimitiveInProgress = ({ children }) => {
1329
1356
  const { useContentPart } = useContentPartContext();
1330
- const isInProgress = useContentPart((c) => c.status.type === "in_progress");
1357
+ const isInProgress = useContentPart((c) => c.status.type === "running");
1331
1358
  return isInProgress ? children : null;
1332
1359
  };
1333
1360
  ContentPartPrimitiveInProgress.displayName = "ContentPartPrimitive.InProgress";
@@ -1366,10 +1393,16 @@ var MessageContentPartComponent = ({
1366
1393
  const type = part.type;
1367
1394
  switch (type) {
1368
1395
  case "text":
1396
+ if (status.type === "requires-action")
1397
+ throw new Error("Encountered unexpected requires-action status");
1369
1398
  return /* @__PURE__ */ jsx16(Text2, { part, status });
1370
1399
  case "image":
1400
+ if (status.type === "requires-action")
1401
+ throw new Error("Encountered unexpected requires-action status");
1371
1402
  return /* @__PURE__ */ jsx16(Image2, { part, status });
1372
1403
  case "ui":
1404
+ if (status.type === "requires-action")
1405
+ throw new Error("Encountered unexpected requires-action status");
1373
1406
  return /* @__PURE__ */ jsx16(UI, { part, status });
1374
1407
  case "tool-call": {
1375
1408
  const Tool = by_name[part.toolName] || Fallback2;
@@ -1399,7 +1432,7 @@ var MessagePrimitiveContent = ({
1399
1432
  components
1400
1433
  }) => {
1401
1434
  const { useMessage } = useMessageContext();
1402
- const contentLength = useMessage((s) => s.message.content.length);
1435
+ const contentLength = useMessage((s) => s.message.content.length) || 1;
1403
1436
  return new Array(contentLength).fill(null).map((_, idx) => {
1404
1437
  const partIndex = idx;
1405
1438
  return /* @__PURE__ */ jsx16(
@@ -1703,7 +1736,7 @@ var useThreadViewportAutoScroll = ({
1703
1736
  const div = divRef.current;
1704
1737
  if (!div) return;
1705
1738
  const isAtBottom = useViewport.getState().isAtBottom;
1706
- const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
1739
+ const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight + 1;
1707
1740
  if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
1708
1741
  } else {
1709
1742
  if (newIsAtBottom) {
@@ -1939,6 +1972,40 @@ var ThreadPrimitiveSuggestion = createActionButton(
1939
1972
  // src/runtimes/local/useLocalRuntime.tsx
1940
1973
  import { useInsertionEffect as useInsertionEffect3, useState as useState8 } from "react";
1941
1974
 
1975
+ // src/runtimes/core/BaseAssistantRuntime.tsx
1976
+ var BaseAssistantRuntime = class {
1977
+ constructor(_thread) {
1978
+ this._thread = _thread;
1979
+ this._thread = _thread;
1980
+ }
1981
+ get thread() {
1982
+ return this._thread;
1983
+ }
1984
+ set thread(thread) {
1985
+ this._thread = thread;
1986
+ this.subscriptionHandler();
1987
+ }
1988
+ _subscriptions = /* @__PURE__ */ new Set();
1989
+ subscribe(callback) {
1990
+ this._subscriptions.add(callback);
1991
+ return () => this._subscriptions.delete(callback);
1992
+ }
1993
+ subscriptionHandler = () => {
1994
+ for (const callback of this._subscriptions) callback();
1995
+ };
1996
+ };
1997
+
1998
+ // src/internal.ts
1999
+ var internal_exports = {};
2000
+ __export(internal_exports, {
2001
+ BaseAssistantRuntime: () => BaseAssistantRuntime,
2002
+ MessageRepository: () => MessageRepository,
2003
+ ProxyConfigProvider: () => ProxyConfigProvider,
2004
+ TooltipIconButton: () => TooltipIconButton,
2005
+ generateId: () => generateId,
2006
+ useSmooth: () => useSmooth
2007
+ });
2008
+
1942
2009
  // src/utils/idUtils.tsx
1943
2010
  import { customAlphabet } from "nanoid/non-secure";
1944
2011
  var generateId = customAlphabet(
@@ -1948,6 +2015,54 @@ var generateId = customAlphabet(
1948
2015
  var optimisticPrefix = "__optimistic__";
1949
2016
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1950
2017
 
2018
+ // src/runtimes/edge/converters/fromCoreMessage.ts
2019
+ var fromCoreMessages = (message) => {
2020
+ return message.map((message2) => fromCoreMessage(message2));
2021
+ };
2022
+ var fromCoreMessage = (message, {
2023
+ id = generateId(),
2024
+ status = { type: "complete", reason: "unknown" }
2025
+ } = {}) => {
2026
+ const commonProps = {
2027
+ id,
2028
+ createdAt: /* @__PURE__ */ new Date()
2029
+ };
2030
+ const role = message.role;
2031
+ switch (role) {
2032
+ case "assistant":
2033
+ return {
2034
+ ...commonProps,
2035
+ role,
2036
+ content: message.content.map((part) => {
2037
+ if (part.type === "tool-call") {
2038
+ return {
2039
+ ...part,
2040
+ argsText: JSON.stringify(part.args)
2041
+ };
2042
+ }
2043
+ return part;
2044
+ }),
2045
+ status
2046
+ };
2047
+ case "user":
2048
+ return {
2049
+ ...commonProps,
2050
+ role,
2051
+ content: message.content
2052
+ };
2053
+ case "system":
2054
+ return {
2055
+ ...commonProps,
2056
+ role,
2057
+ content: message.content
2058
+ };
2059
+ default: {
2060
+ const unsupportedRole = role;
2061
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
2062
+ }
2063
+ }
2064
+ };
2065
+
1951
2066
  // src/runtimes/utils/MessageRepository.tsx
1952
2067
  var findHead = (message) => {
1953
2068
  if (message.next) return findHead(message.next);
@@ -2038,12 +2153,13 @@ var MessageRepository = class {
2038
2153
  do {
2039
2154
  optimisticId = generateOptimisticId();
2040
2155
  } 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
- });
2156
+ this.addOrUpdateMessage(
2157
+ parentId,
2158
+ fromCoreMessage(message, {
2159
+ id: optimisticId,
2160
+ status: { type: "running" }
2161
+ })
2162
+ );
2047
2163
  return optimisticId;
2048
2164
  }
2049
2165
  deleteMessage(messageId, replacementId) {
@@ -2110,40 +2226,6 @@ var MessageRepository = class {
2110
2226
  }
2111
2227
  };
2112
2228
 
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
2229
  // src/ui/base/tooltip-icon-button.tsx
2148
2230
  import { forwardRef as forwardRef17 } from "react";
2149
2231
 
@@ -2460,35 +2542,43 @@ var fromLanguageModelMessages = (lm, { mergeRoundtrips }) => {
2460
2542
  return messages;
2461
2543
  };
2462
2544
 
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
2545
  // src/runtimes/edge/converters/toCoreMessages.ts
2478
2546
  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
- });
2547
+ return message.map(toCoreMessage);
2548
+ };
2549
+ var toCoreMessage = (message) => {
2550
+ const role = message.role;
2551
+ switch (role) {
2552
+ case "assistant":
2553
+ return {
2554
+ role,
2555
+ content: message.content.map((part) => {
2556
+ if (part.type === "ui") throw new Error("UI parts are not supported");
2557
+ if (part.type === "tool-call") {
2558
+ const { argsText, ...rest } = part;
2559
+ return rest;
2560
+ }
2561
+ return part;
2562
+ })
2563
+ };
2564
+ case "user":
2565
+ return {
2566
+ role,
2567
+ content: message.content.map((part) => {
2568
+ if (part.type === "ui") throw new Error("UI parts are not supported");
2569
+ return part;
2570
+ })
2571
+ };
2572
+ case "system":
2573
+ return {
2574
+ role,
2575
+ content: message.content
2576
+ };
2577
+ default: {
2578
+ const unsupportedRole = role;
2579
+ throw new Error(`Unknown message role: ${unsupportedRole}`);
2580
+ }
2581
+ }
2492
2582
  };
2493
2583
 
2494
2584
  // src/runtimes/edge/converters/fromLanguageModelTools.ts
@@ -2958,9 +3048,10 @@ var parsePartialJson = (json) => {
2958
3048
  };
2959
3049
 
2960
3050
  // src/runtimes/edge/streams/runResultStream.ts
2961
- function runResultStream(initialContent) {
3051
+ function runResultStream() {
2962
3052
  let message = {
2963
- content: initialContent
3053
+ content: [],
3054
+ status: { type: "running" }
2964
3055
  };
2965
3056
  const currentToolCall = { toolCallId: "", argsText: "" };
2966
3057
  return new TransformStream({
@@ -3008,7 +3099,13 @@ function runResultStream(initialContent) {
3008
3099
  break;
3009
3100
  }
3010
3101
  case "error": {
3011
- throw chunk.error;
3102
+ if (chunk.error instanceof Error && chunk.error.name === "AbortError") {
3103
+ message = appendOrUpdateCancel(message);
3104
+ controller.enqueue(message);
3105
+ break;
3106
+ } else {
3107
+ throw chunk.error;
3108
+ }
3012
3109
  }
3013
3110
  default: {
3014
3111
  const unhandledType = chunkType;
@@ -3082,11 +3179,42 @@ var appendOrUpdateToolResult = (message, toolCallId, toolName, result) => {
3082
3179
  };
3083
3180
  var appendOrUpdateFinish = (message, chunk) => {
3084
3181
  const { type, ...rest } = chunk;
3182
+ return {
3183
+ ...message,
3184
+ status: getStatus(chunk),
3185
+ roundtrips: [
3186
+ ...message.roundtrips ?? [],
3187
+ {
3188
+ logprobs: rest.logprobs,
3189
+ usage: rest.usage
3190
+ }
3191
+ ]
3192
+ };
3193
+ };
3194
+ var getStatus = (chunk) => {
3195
+ if (chunk.finishReason === "tool-calls") {
3196
+ return {
3197
+ type: "requires-action",
3198
+ reason: "tool-calls"
3199
+ };
3200
+ } else if (chunk.finishReason === "stop" || chunk.finishReason === "unknown") {
3201
+ return {
3202
+ type: "complete",
3203
+ reason: chunk.finishReason
3204
+ };
3205
+ } else {
3206
+ return {
3207
+ type: "incomplete",
3208
+ reason: chunk.finishReason
3209
+ };
3210
+ }
3211
+ };
3212
+ var appendOrUpdateCancel = (message) => {
3085
3213
  return {
3086
3214
  ...message,
3087
3215
  status: {
3088
- type: "done",
3089
- ...rest
3216
+ type: "incomplete",
3217
+ reason: "cancelled"
3090
3218
  }
3091
3219
  };
3092
3220
  };
@@ -3186,7 +3314,7 @@ var EdgeChatAdapter = class {
3186
3314
  constructor(options) {
3187
3315
  this.options = options;
3188
3316
  }
3189
- async roundtrip(initialContent, { messages, abortSignal, config, onUpdate }) {
3317
+ async run({ messages, abortSignal, config, onUpdate }) {
3190
3318
  const result = await fetch(this.options.api, {
3191
3319
  method: "POST",
3192
3320
  headers: {
@@ -3206,46 +3334,14 @@ var EdgeChatAdapter = class {
3206
3334
  `Edge runtime returned status ${result.status}: ${await result.text()}`
3207
3335
  );
3208
3336
  }
3209
- const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream(initialContent));
3210
- let message;
3337
+ const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream());
3211
3338
  let update;
3212
3339
  for await (update of asAsyncIterable(stream)) {
3213
- message = onUpdate(update);
3340
+ onUpdate(update);
3214
3341
  }
3215
3342
  if (update === void 0)
3216
3343
  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;
3344
+ return update;
3249
3345
  }
3250
3346
  };
3251
3347
 
@@ -3258,30 +3354,10 @@ var useEdgeRuntime = ({
3258
3354
  return useLocalRuntime(adapter, { initialMessages });
3259
3355
  };
3260
3356
 
3261
- // src/runtimes/local/LocalRuntime.tsx
3262
- var LocalRuntime = class extends BaseAssistantRuntime {
3263
- _proxyConfigProvider;
3264
- constructor(adapter, options) {
3265
- const proxyConfigProvider = new ProxyConfigProvider();
3266
- super(new LocalThreadRuntime(proxyConfigProvider, adapter, options));
3267
- this._proxyConfigProvider = proxyConfigProvider;
3268
- }
3269
- set adapter(adapter) {
3270
- this.thread.adapter = adapter;
3271
- }
3272
- registerModelConfigProvider(provider) {
3273
- return this._proxyConfigProvider.registerModelConfigProvider(provider);
3274
- }
3275
- switchToThread(threadId) {
3276
- if (threadId) {
3277
- throw new Error("LocalRuntime does not yet support switching threads");
3278
- }
3279
- return this.thread = new LocalThreadRuntime(
3280
- this._proxyConfigProvider,
3281
- this.thread.adapter
3282
- );
3283
- }
3284
- };
3357
+ // src/runtimes/local/shouldContinue.tsx
3358
+ var shouldContinue = (result) => result.status?.type === "requires-action" && result.status.reason === "tool-calls" && result.content.every((c) => c.type !== "tool-call" || !!c.result);
3359
+
3360
+ // src/runtimes/local/LocalThreadRuntime.tsx
3285
3361
  var CAPABILITIES = Object.freeze({
3286
3362
  edit: true,
3287
3363
  reload: true,
@@ -3292,6 +3368,7 @@ var LocalThreadRuntime = class {
3292
3368
  constructor(configProvider, adapter, options) {
3293
3369
  this.configProvider = configProvider;
3294
3370
  this.adapter = adapter;
3371
+ this.options = options;
3295
3372
  if (options?.initialMessages) {
3296
3373
  let parentId = null;
3297
3374
  const messages = fromCoreMessages(options.initialMessages);
@@ -3335,27 +3412,51 @@ var LocalThreadRuntime = class {
3335
3412
  }
3336
3413
  async startRun(parentId) {
3337
3414
  this.repository.resetHead(parentId);
3338
- const messages = this.repository.getMessages();
3415
+ const id = generateId();
3339
3416
  let message = {
3340
- id: generateId(),
3417
+ id,
3341
3418
  role: "assistant",
3342
- status: { type: "in_progress" },
3343
- content: [{ type: "text", text: "" }],
3419
+ status: { type: "running" },
3420
+ content: [],
3344
3421
  createdAt: /* @__PURE__ */ new Date()
3345
3422
  };
3423
+ do {
3424
+ message = await this.performRoundtrip(parentId, message);
3425
+ } while (shouldContinue(message));
3426
+ }
3427
+ async performRoundtrip(parentId, message) {
3428
+ const messages = this.repository.getMessages();
3346
3429
  this.abortController?.abort();
3347
3430
  this.abortController = new AbortController();
3348
- this.repository.addOrUpdateMessage(parentId, { ...message });
3349
- this.notifySubscribers();
3431
+ const initialContent = message.content;
3432
+ const initialRoundtrips = message.roundtrips;
3350
3433
  const updateMessage = (m) => {
3351
3434
  message = {
3352
3435
  ...message,
3353
- ...m
3436
+ ...m.content ? { content: [...initialContent, ...m.content ?? []] } : void 0,
3437
+ status: m.status ?? message.status,
3438
+ ...m.roundtrips?.length ? { roundtrips: [...initialRoundtrips ?? [], ...m.roundtrips] } : void 0
3354
3439
  };
3355
3440
  this.repository.addOrUpdateMessage(parentId, message);
3356
3441
  this.notifySubscribers();
3357
- return message;
3358
3442
  };
3443
+ const maxToolRoundtrips = this.options?.maxToolRoundtrips ?? 1;
3444
+ const toolRoundtrips = message.roundtrips?.length ?? 0;
3445
+ if (toolRoundtrips > maxToolRoundtrips) {
3446
+ updateMessage({
3447
+ status: {
3448
+ type: "incomplete",
3449
+ reason: "tool-calls"
3450
+ }
3451
+ });
3452
+ return message;
3453
+ } else {
3454
+ updateMessage({
3455
+ status: {
3456
+ type: "running"
3457
+ }
3458
+ });
3459
+ }
3359
3460
  try {
3360
3461
  const result = await this.adapter.run({
3361
3462
  messages,
@@ -3363,21 +3464,29 @@ var LocalThreadRuntime = class {
3363
3464
  config: this.configProvider.getModelConfig(),
3364
3465
  onUpdate: updateMessage
3365
3466
  });
3366
- if (result.status?.type === "in_progress")
3467
+ if (result.status?.type === "running")
3367
3468
  throw new Error(
3368
- "Unexpected in_progress status returned from ChatModelAdapter"
3469
+ "Unexpected running status returned from ChatModelAdapter"
3369
3470
  );
3370
3471
  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
3472
  updateMessage({
3377
- status: isAbortError ? { type: "cancelled" } : { type: "error", error: e }
3473
+ status: { type: "complete", reason: "unknown" },
3474
+ ...result
3378
3475
  });
3379
- if (!isAbortError) throw e;
3476
+ } catch (e) {
3477
+ this.abortController = null;
3478
+ if (e instanceof Error && e.name === "AbortError") {
3479
+ updateMessage({
3480
+ status: { type: "incomplete", reason: "cancelled" }
3481
+ });
3482
+ } else {
3483
+ updateMessage({
3484
+ status: { type: "incomplete", reason: "error", error: e }
3485
+ });
3486
+ throw e;
3487
+ }
3380
3488
  }
3489
+ return message;
3381
3490
  }
3382
3491
  cancelRun() {
3383
3492
  if (!this.abortController) return;
@@ -3392,14 +3501,16 @@ var LocalThreadRuntime = class {
3392
3501
  return () => this._subscriptions.delete(callback);
3393
3502
  }
3394
3503
  addToolResult({ messageId, toolCallId, result }) {
3395
- const { parentId, message } = this.repository.getMessage(messageId);
3504
+ let { parentId, message } = this.repository.getMessage(messageId);
3396
3505
  if (message.role !== "assistant")
3397
3506
  throw new Error("Tried to add tool result to non-assistant message");
3507
+ let added = false;
3398
3508
  let found = false;
3399
3509
  const newContent = message.content.map((c) => {
3400
3510
  if (c.type !== "tool-call") return c;
3401
3511
  if (c.toolCallId !== toolCallId) return c;
3402
3512
  found = true;
3513
+ if (!c.result) added = true;
3403
3514
  return {
3404
3515
  ...c,
3405
3516
  result
@@ -3407,10 +3518,39 @@ var LocalThreadRuntime = class {
3407
3518
  });
3408
3519
  if (!found)
3409
3520
  throw new Error("Tried to add tool result to non-existing tool call");
3410
- this.repository.addOrUpdateMessage(parentId, {
3521
+ message = {
3411
3522
  ...message,
3412
3523
  content: newContent
3413
- });
3524
+ };
3525
+ this.repository.addOrUpdateMessage(parentId, message);
3526
+ if (added && shouldContinue(message)) {
3527
+ this.performRoundtrip(parentId, message);
3528
+ }
3529
+ }
3530
+ };
3531
+
3532
+ // src/runtimes/local/LocalRuntime.tsx
3533
+ var LocalRuntime = class extends BaseAssistantRuntime {
3534
+ _proxyConfigProvider;
3535
+ constructor(adapter, options) {
3536
+ const proxyConfigProvider = new ProxyConfigProvider();
3537
+ super(new LocalThreadRuntime(proxyConfigProvider, adapter, options));
3538
+ this._proxyConfigProvider = proxyConfigProvider;
3539
+ }
3540
+ set adapter(adapter) {
3541
+ this.thread.adapter = adapter;
3542
+ }
3543
+ registerModelConfigProvider(provider) {
3544
+ return this._proxyConfigProvider.registerModelConfigProvider(provider);
3545
+ }
3546
+ switchToThread(threadId) {
3547
+ if (threadId) {
3548
+ throw new Error("LocalRuntime does not yet support switching threads");
3549
+ }
3550
+ return this.thread = new LocalThreadRuntime(
3551
+ this._proxyConfigProvider,
3552
+ this.thread.adapter
3553
+ );
3414
3554
  }
3415
3555
  };
3416
3556
 
@@ -3605,7 +3745,7 @@ var Text = ({ status }) => {
3605
3745
  {
3606
3746
  className: classNames2(
3607
3747
  "aui-text",
3608
- status.type === "in_progress" && "aui-text-in-progress"
3748
+ status.type === "running" && "aui-text-in-progress"
3609
3749
  ),
3610
3750
  children: /* @__PURE__ */ jsx33(contentPart_exports.Text, {})
3611
3751
  }
@@ -4131,11 +4271,13 @@ export {
4131
4271
  thread_welcome_default as ThreadWelcome,
4132
4272
  user_action_bar_default as UserActionBar,
4133
4273
  user_message_default as UserMessage,
4274
+ fromCoreMessage,
4134
4275
  fromCoreMessages,
4135
4276
  fromLanguageModelMessages,
4136
4277
  fromLanguageModelTools,
4137
4278
  makeAssistantTool,
4138
4279
  makeAssistantToolUI,
4280
+ toCoreMessage,
4139
4281
  toCoreMessages,
4140
4282
  toLanguageModelMessages,
4141
4283
  toLanguageModelTools,