@assistant-ui/react 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -1972,7 +1972,7 @@ var ThreadPrimitiveSuggestion = createActionButton(
1972
1972
  );
1973
1973
 
1974
1974
  // src/runtimes/local/useLocalRuntime.tsx
1975
- var import_react53 = require("react");
1975
+ var import_react54 = require("react");
1976
1976
 
1977
1977
  // src/utils/idUtils.tsx
1978
1978
  var import_non_secure = require("nanoid/non-secure");
@@ -2273,163 +2273,8 @@ var TooltipIconButton = (0, import_react52.forwardRef)(({ children, tooltip, sid
2273
2273
  });
2274
2274
  TooltipIconButton.displayName = "TooltipIconButton";
2275
2275
 
2276
- // src/runtimes/local/LocalRuntime.tsx
2277
- var LocalRuntime = class extends BaseAssistantRuntime {
2278
- _proxyConfigProvider;
2279
- constructor(adapter) {
2280
- const proxyConfigProvider = new ProxyConfigProvider();
2281
- super(new LocalThreadRuntime(proxyConfigProvider, adapter));
2282
- this._proxyConfigProvider = proxyConfigProvider;
2283
- }
2284
- set adapter(adapter) {
2285
- this.thread.adapter = adapter;
2286
- }
2287
- registerModelConfigProvider(provider) {
2288
- return this._proxyConfigProvider.registerModelConfigProvider(provider);
2289
- }
2290
- switchToThread(threadId) {
2291
- if (threadId) {
2292
- throw new Error("LocalRuntime does not yet support switching threads");
2293
- }
2294
- return this.thread = new LocalThreadRuntime(
2295
- this._proxyConfigProvider,
2296
- this.thread.adapter
2297
- );
2298
- }
2299
- };
2300
- var CAPABILITIES = Object.freeze({
2301
- edit: true,
2302
- reload: true,
2303
- cancel: true,
2304
- copy: true
2305
- });
2306
- var LocalThreadRuntime = class {
2307
- constructor(configProvider, adapter) {
2308
- this.configProvider = configProvider;
2309
- this.adapter = adapter;
2310
- }
2311
- _subscriptions = /* @__PURE__ */ new Set();
2312
- abortController = null;
2313
- repository = new MessageRepository();
2314
- capabilities = CAPABILITIES;
2315
- get messages() {
2316
- return this.repository.getMessages();
2317
- }
2318
- get isRunning() {
2319
- return this.abortController != null;
2320
- }
2321
- getBranches(messageId) {
2322
- return this.repository.getBranches(messageId);
2323
- }
2324
- switchToBranch(branchId) {
2325
- this.repository.switchToBranch(branchId);
2326
- this.notifySubscribers();
2327
- }
2328
- async append(message) {
2329
- if (message.role !== "user")
2330
- throw new Error(
2331
- "Only appending user messages are supported in LocalRuntime. This is likely an internal bug in assistant-ui."
2332
- );
2333
- const userMessageId = generateId();
2334
- const userMessage = {
2335
- id: userMessageId,
2336
- role: "user",
2337
- content: message.content,
2338
- createdAt: /* @__PURE__ */ new Date()
2339
- };
2340
- this.repository.addOrUpdateMessage(message.parentId, userMessage);
2341
- await this.startRun(userMessageId);
2342
- }
2343
- async startRun(parentId) {
2344
- this.repository.resetHead(parentId);
2345
- const messages = this.repository.getMessages();
2346
- const message = {
2347
- id: generateId(),
2348
- role: "assistant",
2349
- status: { type: "in_progress" },
2350
- content: [{ type: "text", text: "" }],
2351
- createdAt: /* @__PURE__ */ new Date()
2352
- };
2353
- this.repository.addOrUpdateMessage(parentId, { ...message });
2354
- this.abortController?.abort();
2355
- this.abortController = new AbortController();
2356
- this.notifySubscribers();
2357
- try {
2358
- const updateHandler = ({ content }) => {
2359
- message.content = content;
2360
- this.repository.addOrUpdateMessage(parentId, { ...message });
2361
- this.notifySubscribers();
2362
- };
2363
- const result = await this.adapter.run({
2364
- messages,
2365
- abortSignal: this.abortController.signal,
2366
- config: this.configProvider.getModelConfig(),
2367
- onUpdate: updateHandler
2368
- });
2369
- if (result !== void 0) {
2370
- updateHandler(result);
2371
- }
2372
- if (result.status?.type === "in_progress")
2373
- throw new Error(
2374
- "Unexpected in_progress status returned from ChatModelAdapter"
2375
- );
2376
- message.status = result.status ?? { type: "done" };
2377
- this.repository.addOrUpdateMessage(parentId, { ...message });
2378
- } catch (e) {
2379
- message.status = { type: "error", error: e };
2380
- this.repository.addOrUpdateMessage(parentId, { ...message });
2381
- throw e;
2382
- } finally {
2383
- this.abortController = null;
2384
- this.notifySubscribers();
2385
- }
2386
- }
2387
- cancelRun() {
2388
- if (!this.abortController) return;
2389
- this.abortController.abort();
2390
- this.abortController = null;
2391
- }
2392
- notifySubscribers() {
2393
- for (const callback of this._subscriptions) callback();
2394
- }
2395
- subscribe(callback) {
2396
- this._subscriptions.add(callback);
2397
- return () => this._subscriptions.delete(callback);
2398
- }
2399
- addToolResult({ messageId, toolCallId, result }) {
2400
- const { parentId, message } = this.repository.getMessage(messageId);
2401
- if (message.role !== "assistant")
2402
- throw new Error("Tried to add tool result to non-assistant message");
2403
- let found = false;
2404
- const newContent = message.content.map((c) => {
2405
- if (c.type !== "tool-call") return c;
2406
- if (c.toolCallId !== toolCallId) return c;
2407
- found = true;
2408
- return {
2409
- ...c,
2410
- result
2411
- };
2412
- });
2413
- if (!found)
2414
- throw new Error("Tried to add tool result to non-existing tool call");
2415
- this.repository.addOrUpdateMessage(parentId, {
2416
- ...message,
2417
- content: newContent
2418
- });
2419
- }
2420
- };
2421
-
2422
- // src/runtimes/local/useLocalRuntime.tsx
2423
- var useLocalRuntime = (adapter) => {
2424
- const [runtime] = (0, import_react53.useState)(() => new LocalRuntime(adapter));
2425
- (0, import_react53.useInsertionEffect)(() => {
2426
- runtime.adapter = adapter;
2427
- });
2428
- return runtime;
2429
- };
2430
-
2431
2276
  // src/runtimes/edge/useEdgeRuntime.ts
2432
- var import_react54 = require("react");
2277
+ var import_react53 = require("react");
2433
2278
 
2434
2279
  // src/runtimes/edge/converters/toCoreMessages.ts
2435
2280
  var toCoreMessages = (message) => {
@@ -2459,6 +2304,7 @@ var toLanguageModelTools = (tools) => {
2459
2304
 
2460
2305
  // src/runtimes/edge/streams/assistantDecoderStream.ts
2461
2306
  function assistantDecoderStream() {
2307
+ const toolCallNames = /* @__PURE__ */ new Map();
2462
2308
  let currentToolCall;
2463
2309
  return new TransformStream({
2464
2310
  transform(chunk, controller) {
@@ -2483,6 +2329,7 @@ function assistantDecoderStream() {
2483
2329
  }
2484
2330
  case "1" /* ToolCallBegin */: {
2485
2331
  const { id, name } = value;
2332
+ toolCallNames.set(id, name);
2486
2333
  currentToolCall = { id, name, argsText: "" };
2487
2334
  break;
2488
2335
  }
@@ -2498,6 +2345,16 @@ function assistantDecoderStream() {
2498
2345
  });
2499
2346
  break;
2500
2347
  }
2348
+ case "3" /* ToolCallResult */: {
2349
+ controller.enqueue({
2350
+ type: "tool-result",
2351
+ toolCallType: "function",
2352
+ toolCallId: value.id,
2353
+ toolName: toolCallNames.get(value.id),
2354
+ result: value.result
2355
+ });
2356
+ break;
2357
+ }
2501
2358
  case "F" /* Finish */: {
2502
2359
  controller.enqueue({
2503
2360
  type: "finish",
@@ -2884,9 +2741,9 @@ var parsePartialJson = (json) => {
2884
2741
  };
2885
2742
 
2886
2743
  // src/runtimes/edge/streams/runResultStream.ts
2887
- function runResultStream() {
2744
+ function runResultStream(initialContent) {
2888
2745
  let message = {
2889
- content: []
2746
+ content: initialContent
2890
2747
  };
2891
2748
  const currentToolCall = { toolCallId: "", argsText: "" };
2892
2749
  return new TransformStream({
@@ -3069,6 +2926,7 @@ function toolResultStream(tools) {
3069
2926
  }
3070
2927
  case "text-delta":
3071
2928
  case "tool-call-delta":
2929
+ case "tool-result":
3072
2930
  case "finish":
3073
2931
  case "error":
3074
2932
  break;
@@ -3102,7 +2960,7 @@ var EdgeChatAdapter = class {
3102
2960
  constructor(options) {
3103
2961
  this.options = options;
3104
2962
  }
3105
- async run({ messages, abortSignal, config, onUpdate }) {
2963
+ async roundtrip(initialContent, { messages, abortSignal, config, onUpdate }) {
3106
2964
  const result = await fetch(this.options.api, {
3107
2965
  method: "POST",
3108
2966
  headers: {
@@ -3117,21 +2975,56 @@ var EdgeChatAdapter = class {
3117
2975
  }),
3118
2976
  signal: abortSignal
3119
2977
  });
3120
- const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream());
2978
+ const stream = result.body.pipeThrough(new TextDecoderStream()).pipeThrough(chunkByLineStream()).pipeThrough(assistantDecoderStream()).pipeThrough(toolResultStream(config.tools)).pipeThrough(runResultStream(initialContent));
2979
+ let message;
3121
2980
  let update;
3122
2981
  for await (update of asAsyncIterable(stream)) {
3123
- onUpdate(update);
2982
+ message = onUpdate(update);
3124
2983
  }
3125
2984
  if (update === void 0)
3126
2985
  throw new Error("No data received from Edge Runtime");
3127
- return update;
2986
+ return [message, update];
2987
+ }
2988
+ async run({ messages, abortSignal, config, onUpdate }) {
2989
+ let roundtripAllowance = this.options.maxToolRoundtrips ?? 1;
2990
+ let usage = {
2991
+ promptTokens: 0,
2992
+ completionTokens: 0
2993
+ };
2994
+ let result;
2995
+ let assistantMessage;
2996
+ do {
2997
+ [assistantMessage, result] = await this.roundtrip(result?.content ?? [], {
2998
+ messages: assistantMessage ? [...messages, assistantMessage] : messages,
2999
+ abortSignal,
3000
+ config,
3001
+ onUpdate
3002
+ });
3003
+ if (result.status?.type === "done") {
3004
+ usage.promptTokens += result.status.usage?.promptTokens ?? 0;
3005
+ usage.completionTokens += result.status.usage?.completionTokens ?? 0;
3006
+ }
3007
+ } while (result.status?.type === "done" && result.status.finishReason === "tool-calls" && result.content.every((c) => c.type !== "tool-call" || !!c.result) && roundtripAllowance-- > 0);
3008
+ if (result.status?.type === "done" && usage.promptTokens > 0) {
3009
+ result = {
3010
+ ...result,
3011
+ status: {
3012
+ ...result.status,
3013
+ usage
3014
+ }
3015
+ };
3016
+ }
3017
+ return result;
3128
3018
  }
3129
3019
  };
3130
3020
 
3131
3021
  // src/runtimes/edge/useEdgeRuntime.ts
3132
- var useEdgeRuntime = (options) => {
3133
- const [adapter] = (0, import_react54.useState)(() => new EdgeChatAdapter(options));
3134
- return useLocalRuntime(adapter);
3022
+ var useEdgeRuntime = ({
3023
+ initialMessages,
3024
+ ...options
3025
+ }) => {
3026
+ const [adapter] = (0, import_react53.useState)(() => new EdgeChatAdapter(options));
3027
+ return useLocalRuntime(adapter, { initialMessages });
3135
3028
  };
3136
3029
 
3137
3030
  // src/runtimes/edge/converters/toLanguageModelMessages.ts
@@ -3358,14 +3251,179 @@ var fromLanguageModelMessages = (lm, mergeRoundtrips) => {
3358
3251
  var fromCoreMessages = (message) => {
3359
3252
  return message.map((message2) => {
3360
3253
  return {
3361
- ...message2,
3362
3254
  id: generateId(),
3363
3255
  createdAt: /* @__PURE__ */ new Date(),
3364
3256
  ...message2.role === "assistant" ? {
3365
3257
  status: { type: "done" }
3366
- } : void 0
3258
+ } : void 0,
3259
+ ...message2
3260
+ };
3261
+ });
3262
+ };
3263
+
3264
+ // src/runtimes/local/LocalRuntime.tsx
3265
+ var LocalRuntime = class extends BaseAssistantRuntime {
3266
+ _proxyConfigProvider;
3267
+ constructor(adapter, options) {
3268
+ const proxyConfigProvider = new ProxyConfigProvider();
3269
+ super(new LocalThreadRuntime(proxyConfigProvider, adapter, options));
3270
+ this._proxyConfigProvider = proxyConfigProvider;
3271
+ }
3272
+ set adapter(adapter) {
3273
+ this.thread.adapter = adapter;
3274
+ }
3275
+ registerModelConfigProvider(provider) {
3276
+ return this._proxyConfigProvider.registerModelConfigProvider(provider);
3277
+ }
3278
+ switchToThread(threadId) {
3279
+ if (threadId) {
3280
+ throw new Error("LocalRuntime does not yet support switching threads");
3281
+ }
3282
+ return this.thread = new LocalThreadRuntime(
3283
+ this._proxyConfigProvider,
3284
+ this.thread.adapter
3285
+ );
3286
+ }
3287
+ };
3288
+ var CAPABILITIES = Object.freeze({
3289
+ edit: true,
3290
+ reload: true,
3291
+ cancel: true,
3292
+ copy: true
3293
+ });
3294
+ var LocalThreadRuntime = class {
3295
+ constructor(configProvider, adapter, options) {
3296
+ this.configProvider = configProvider;
3297
+ this.adapter = adapter;
3298
+ if (options?.initialMessages) {
3299
+ let parentId = null;
3300
+ const messages = fromCoreMessages(options.initialMessages);
3301
+ for (const message of messages) {
3302
+ this.repository.addOrUpdateMessage(parentId, message);
3303
+ parentId = message.id;
3304
+ }
3305
+ }
3306
+ }
3307
+ _subscriptions = /* @__PURE__ */ new Set();
3308
+ abortController = null;
3309
+ repository = new MessageRepository();
3310
+ capabilities = CAPABILITIES;
3311
+ get messages() {
3312
+ return this.repository.getMessages();
3313
+ }
3314
+ get isRunning() {
3315
+ return this.abortController != null;
3316
+ }
3317
+ getBranches(messageId) {
3318
+ return this.repository.getBranches(messageId);
3319
+ }
3320
+ switchToBranch(branchId) {
3321
+ this.repository.switchToBranch(branchId);
3322
+ this.notifySubscribers();
3323
+ }
3324
+ async append(message) {
3325
+ if (message.role !== "user")
3326
+ throw new Error(
3327
+ "Only appending user messages are supported in LocalRuntime. This is likely an internal bug in assistant-ui."
3328
+ );
3329
+ const userMessageId = generateId();
3330
+ const userMessage = {
3331
+ id: userMessageId,
3332
+ role: "user",
3333
+ content: message.content,
3334
+ createdAt: /* @__PURE__ */ new Date()
3335
+ };
3336
+ this.repository.addOrUpdateMessage(message.parentId, userMessage);
3337
+ await this.startRun(userMessageId);
3338
+ }
3339
+ async startRun(parentId) {
3340
+ this.repository.resetHead(parentId);
3341
+ const messages = this.repository.getMessages();
3342
+ const message = {
3343
+ id: generateId(),
3344
+ role: "assistant",
3345
+ status: { type: "in_progress" },
3346
+ content: [{ type: "text", text: "" }],
3347
+ createdAt: /* @__PURE__ */ new Date()
3367
3348
  };
3349
+ this.repository.addOrUpdateMessage(parentId, { ...message });
3350
+ this.abortController?.abort();
3351
+ this.abortController = new AbortController();
3352
+ this.notifySubscribers();
3353
+ try {
3354
+ const updateHandler = ({ content }) => {
3355
+ message.content = content;
3356
+ const newMessage = { ...message };
3357
+ this.repository.addOrUpdateMessage(parentId, newMessage);
3358
+ this.notifySubscribers();
3359
+ return newMessage;
3360
+ };
3361
+ const result = await this.adapter.run({
3362
+ messages,
3363
+ abortSignal: this.abortController.signal,
3364
+ config: this.configProvider.getModelConfig(),
3365
+ onUpdate: updateHandler
3366
+ });
3367
+ if (result !== void 0) {
3368
+ updateHandler(result);
3369
+ }
3370
+ if (result.status?.type === "in_progress")
3371
+ throw new Error(
3372
+ "Unexpected in_progress status returned from ChatModelAdapter"
3373
+ );
3374
+ message.status = result.status ?? { type: "done" };
3375
+ this.repository.addOrUpdateMessage(parentId, { ...message });
3376
+ } catch (e) {
3377
+ message.status = { type: "error", error: e };
3378
+ this.repository.addOrUpdateMessage(parentId, { ...message });
3379
+ throw e;
3380
+ } finally {
3381
+ this.abortController = null;
3382
+ this.notifySubscribers();
3383
+ }
3384
+ }
3385
+ cancelRun() {
3386
+ if (!this.abortController) return;
3387
+ this.abortController.abort();
3388
+ this.abortController = null;
3389
+ }
3390
+ notifySubscribers() {
3391
+ for (const callback of this._subscriptions) callback();
3392
+ }
3393
+ subscribe(callback) {
3394
+ this._subscriptions.add(callback);
3395
+ return () => this._subscriptions.delete(callback);
3396
+ }
3397
+ addToolResult({ messageId, toolCallId, result }) {
3398
+ const { parentId, message } = this.repository.getMessage(messageId);
3399
+ if (message.role !== "assistant")
3400
+ throw new Error("Tried to add tool result to non-assistant message");
3401
+ let found = false;
3402
+ const newContent = message.content.map((c) => {
3403
+ if (c.type !== "tool-call") return c;
3404
+ if (c.toolCallId !== toolCallId) return c;
3405
+ found = true;
3406
+ return {
3407
+ ...c,
3408
+ result
3409
+ };
3410
+ });
3411
+ if (!found)
3412
+ throw new Error("Tried to add tool result to non-existing tool call");
3413
+ this.repository.addOrUpdateMessage(parentId, {
3414
+ ...message,
3415
+ content: newContent
3416
+ });
3417
+ }
3418
+ };
3419
+
3420
+ // src/runtimes/local/useLocalRuntime.tsx
3421
+ var useLocalRuntime = (adapter, options) => {
3422
+ const [runtime] = (0, import_react54.useState)(() => new LocalRuntime(adapter, options));
3423
+ (0, import_react54.useInsertionEffect)(() => {
3424
+ runtime.adapter = adapter;
3368
3425
  });
3426
+ return runtime;
3369
3427
  };
3370
3428
 
3371
3429
  // src/ui/thread-config.tsx
@@ -3963,10 +4021,7 @@ var ThreadScrollToBottom = (0, import_react64.forwardRef)((props, ref) => {
3963
4021
  thread: { scrollToBottom: { tooltip = "Scroll to bottom" } = {} } = {}
3964
4022
  } = {}
3965
4023
  } = useThreadConfig();
3966
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(thread_exports.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(ThreadScrollToBottomIconButton, { tooltip, ...props, ref, children: [
3967
- "|",
3968
- props.children ?? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react5.ArrowDownIcon, {})
3969
- ] }) });
4024
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(thread_exports.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ThreadScrollToBottomIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react5.ArrowDownIcon, {}) }) });
3970
4025
  });
3971
4026
  ThreadScrollToBottom.displayName = "ThreadScrollToBottom";
3972
4027
  var exports11 = {