@noodleseed/assistant 1.13.0 → 1.14.0

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.
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  createAssistantClient
4
- } from "../chunk-KRB2SXFD.js";
4
+ } from "../chunk-RITHSCTD.js";
5
5
  import "../chunk-3YYTUJPJ.js";
6
6
  import "../chunk-5FUTL2UF.js";
7
7
 
package/dist/react.cjs CHANGED
@@ -22191,7 +22191,7 @@ function mountAssistantApp(detail, actions, options = {}) {
22191
22191
  const current = options.getDetail?.() ?? detail;
22192
22192
  void bridge.sendSandboxResourceReady({
22193
22193
  html: current.html,
22194
- sandbox: "allow-scripts allow-forms",
22194
+ sandbox: "allow-scripts",
22195
22195
  ...current.resourceMeta ?? {}
22196
22196
  });
22197
22197
  };
@@ -26820,7 +26820,7 @@ var AssistantChatStateStore = class {
26820
26820
  this.#writeText(event.data.delta);
26821
26821
  return;
26822
26822
  case "tool_proposed":
26823
- this.#writeConfirmation(event.data);
26823
+ this.#writeStandaloneData(() => this.#writeConfirmation(event.data));
26824
26824
  return;
26825
26825
  case "interaction_proposed":
26826
26826
  this.#writeData("confirmation", event.data.id, {
@@ -26829,10 +26829,12 @@ var AssistantChatStateStore = class {
26829
26829
  });
26830
26830
  return;
26831
26831
  case "input_requested":
26832
- this.#writeData("input-request", event.data.id, {
26833
- ...event.data,
26834
- status: "pending"
26835
- });
26832
+ this.#writeStandaloneData(
26833
+ () => this.#writeData("input-request", event.data.id, {
26834
+ ...event.data,
26835
+ status: "pending"
26836
+ })
26837
+ );
26836
26838
  return;
26837
26839
  case "tool_completed":
26838
26840
  this.#writeData("tool-result", event.data.id, event.data);
@@ -26939,6 +26941,12 @@ var AssistantChatStateStore = class {
26939
26941
  #writeConfirmation(data) {
26940
26942
  this.#writeData("confirmation", data.id, { ...data, status: "pending" });
26941
26943
  }
26944
+ #writeStandaloneData(write) {
26945
+ const standalone = this.#operation === void 0;
26946
+ if (standalone) this.#startOperation();
26947
+ write();
26948
+ if (standalone) this.#closeOperation("ready");
26949
+ }
26942
26950
  #writeData(name21, id, data) {
26943
26951
  const operation = this.#operation;
26944
26952
  if (!operation || operation.closed) return;
@@ -27417,6 +27425,7 @@ var DefaultAssistantClient = class {
27417
27425
  #context;
27418
27426
  #modelContext;
27419
27427
  #active;
27428
+ #pendingAppInteractions = /* @__PURE__ */ new Map();
27420
27429
  constructor(options) {
27421
27430
  if (!options.sessionEndpoint) throw new Error("sessionEndpoint is required");
27422
27431
  this.#sessionEndpoint = options.sessionEndpoint;
@@ -27458,6 +27467,7 @@ var DefaultAssistantClient = class {
27458
27467
  }
27459
27468
  await this.#singleFlight(async (signal) => {
27460
27469
  await this.#runChatOperation(signal, async () => {
27470
+ const pendingApp = this.#pendingAppInteractions.get(id);
27461
27471
  const session = this.#session;
27462
27472
  if (!session) {
27463
27473
  throw clientError("confirmation_expired", "assistant session is not active", false);
@@ -27477,32 +27487,67 @@ var DefaultAssistantClient = class {
27477
27487
  ...resolution.action === "accept" && resolution.content !== void 0 ? { content: resolution.content } : {}
27478
27488
  } : { id };
27479
27489
  this.#emit({ event: "interaction_started", data: { id, action: resolution.action } });
27480
- const response = await this.#request(
27481
- endpoint,
27482
- {
27483
- method: "POST",
27484
- headers: authorizedHeaders(session.token, "text/event-stream"),
27485
- body: JSON.stringify(body),
27486
- signal
27487
- },
27488
- "confirmation_failed"
27489
- );
27490
- if (response.status === 401) {
27491
- this.#session = void 0;
27492
- this.#emit({ event: "session_expired", data: {} });
27493
- }
27494
- if (!response.ok) {
27495
- const serverCode = await readStableErrorCode(response);
27496
- const expired = response.status === 401 || response.status === 409;
27497
- throw clientError(
27498
- serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
27499
- `Assistant interaction failed (${response.status})`,
27500
- false,
27501
- response.status
27490
+ try {
27491
+ const response = await this.#request(
27492
+ endpoint,
27493
+ {
27494
+ method: "POST",
27495
+ headers: authorizedHeaders(session.token, "text/event-stream"),
27496
+ body: JSON.stringify(body),
27497
+ signal
27498
+ },
27499
+ "confirmation_failed"
27502
27500
  );
27501
+ if (response.status === 401) {
27502
+ this.#session = void 0;
27503
+ this.#emit({ event: "session_expired", data: {} });
27504
+ }
27505
+ if (!response.ok) {
27506
+ const serverCode = await readStableErrorCode(response);
27507
+ const expired = response.status === 401 || response.status === 409;
27508
+ throw clientError(
27509
+ serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
27510
+ `Assistant interaction failed (${response.status})`,
27511
+ false,
27512
+ response.status
27513
+ );
27514
+ }
27515
+ let completedResult;
27516
+ let nextInteractionId;
27517
+ await this.#consume(response, (event) => {
27518
+ if (event.event === "tool_completed" && event.data.id === id) {
27519
+ completedResult = event.data.result;
27520
+ }
27521
+ if ((event.event === "tool_proposed" || event.event === "input_requested") && event.data.id !== id) {
27522
+ nextInteractionId = event.data.id;
27523
+ }
27524
+ });
27525
+ this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
27526
+ if (pendingApp) {
27527
+ this.#pendingAppInteractions.delete(id);
27528
+ if (nextInteractionId) {
27529
+ this.#pendingAppInteractions.set(nextInteractionId, pendingApp);
27530
+ } else if (resolution.action !== "accept") {
27531
+ pendingApp.resolve(appInteractionStopped(resolution.action));
27532
+ } else if (completedResult !== void 0) {
27533
+ pendingApp.resolve(appToolResult(completedResult));
27534
+ } else {
27535
+ pendingApp.reject(
27536
+ clientError(
27537
+ "invalid_response",
27538
+ "Assistant app interaction completed without a tool result",
27539
+ false
27540
+ )
27541
+ );
27542
+ }
27543
+ }
27544
+ } catch (error51) {
27545
+ if (pendingApp && this.#pendingAppInteractions.get(id) === pendingApp) {
27546
+ this.#pendingAppInteractions.delete(id);
27547
+ pendingApp.reject(error51);
27548
+ }
27549
+ throw error51;
27503
27550
  }
27504
- await this.#consume(response);
27505
- this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
27506
27551
  });
27507
27552
  });
27508
27553
  }
@@ -27543,12 +27588,29 @@ var DefaultAssistantClient = class {
27543
27588
  response.status
27544
27589
  );
27545
27590
  }
27546
- return response.json();
27591
+ const value = await response.json();
27592
+ const interaction = parseAppInteraction(value);
27593
+ if (!interaction) return value;
27594
+ return new Promise((resolve2, reject) => {
27595
+ const id = interaction.data.id;
27596
+ const replaced = this.#pendingAppInteractions.get(id);
27597
+ if (replaced) {
27598
+ replaced.reject(
27599
+ clientError("invalid_response", "Assistant returned a duplicate app interaction", false)
27600
+ );
27601
+ }
27602
+ this.#pendingAppInteractions.set(id, { resolve: resolve2, reject });
27603
+ this.#emit(interaction);
27604
+ void this.#chat.flush();
27605
+ });
27547
27606
  }
27548
27607
  appSandboxUrl() {
27549
27608
  return this.#session?.endpoints.sandbox;
27550
27609
  }
27551
27610
  resetSession() {
27611
+ this.#rejectPendingAppInteractions(
27612
+ clientError("confirmation_expired", "assistant session is not active", false)
27613
+ );
27552
27614
  this.#session = void 0;
27553
27615
  this.#emit({ event: "session_reset", data: {} });
27554
27616
  }
@@ -27669,12 +27731,13 @@ var DefaultAssistantClient = class {
27669
27731
  });
27670
27732
  return session;
27671
27733
  }
27672
- async #consume(response) {
27734
+ async #consume(response, observe) {
27673
27735
  let streamError;
27674
27736
  try {
27675
27737
  await consumeAssistantEvents(response, (event) => {
27676
27738
  const clientEvent = toAssistantClientEvent(event);
27677
27739
  this.#emit(clientEvent);
27740
+ observe?.(clientEvent);
27678
27741
  if (clientEvent.event !== "error" || typeof clientEvent.data.code !== "string") return;
27679
27742
  streamError = {
27680
27743
  code: clientEvent.data.code,
@@ -27743,6 +27806,10 @@ var DefaultAssistantClient = class {
27743
27806
  }
27744
27807
  }
27745
27808
  }
27809
+ #rejectPendingAppInteractions(error51) {
27810
+ for (const pending of this.#pendingAppInteractions.values()) pending.reject(error51);
27811
+ this.#pendingAppInteractions.clear();
27812
+ }
27746
27813
  };
27747
27814
  function createAssistantClient(options) {
27748
27815
  return new DefaultAssistantClient(options);
@@ -27754,6 +27821,30 @@ function authorizedHeaders(token, accept) {
27754
27821
  Accept: accept
27755
27822
  };
27756
27823
  }
27824
+ function parseAppInteraction(value) {
27825
+ if (!isRecord4(value) || !isRecord4(value.interaction)) return void 0;
27826
+ const event = value.interaction.event;
27827
+ const data = value.interaction.data;
27828
+ if (event !== "tool_proposed" && event !== "input_requested" || !isRecord4(data)) {
27829
+ return void 0;
27830
+ }
27831
+ const parsed = toAssistantClientEvent({ event, data });
27832
+ return parsed.event === "tool_proposed" || parsed.event === "input_requested" ? parsed : void 0;
27833
+ }
27834
+ function appToolResult(result) {
27835
+ const text3 = typeof result === "string" ? result : JSON.stringify(result);
27836
+ return result !== null && typeof result === "object" && !Array.isArray(result) ? {
27837
+ content: [{ type: "text", text: text3 }],
27838
+ structuredContent: result,
27839
+ isError: false
27840
+ } : { content: [{ type: "text", text: text3 }], isError: false };
27841
+ }
27842
+ function appInteractionStopped(action) {
27843
+ return {
27844
+ content: [{ type: "text", text: `interaction_${action}` }],
27845
+ isError: true
27846
+ };
27847
+ }
27757
27848
  function parseSession(value) {
27758
27849
  if (!isRecord4(value) || !isRecord4(value.endpoints)) {
27759
27850
  throw clientError("session_failed", "Assistant session response is invalid", true);
@@ -30969,7 +31060,6 @@ var AssistantElementEventController = class {
30969
31060
  return;
30970
31061
  }
30971
31062
  if (name21 === "tool_proposed" || name21 === "interaction_proposed") {
30972
- if (!this.#streamKind) return;
30973
31063
  this.#appendToolProposal(
30974
31064
  String(data.id ?? ""),
30975
31065
  String(data.tool ?? "action"),
@@ -30981,7 +31071,6 @@ var AssistantElementEventController = class {
30981
31071
  return;
30982
31072
  }
30983
31073
  if (name21 === "input_requested" && isRecord5(data.requestedSchema)) {
30984
- if (!this.#streamKind) return;
30985
31074
  this.#appendInputRequest(
30986
31075
  String(data.id ?? ""),
30987
31076
  String(data.message ?? "More information is required"),