@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.
package/dist/client.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AssistantClientError,
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
  export {
package/dist/index.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
  };
@@ -26817,7 +26817,7 @@ var AssistantChatStateStore = class {
26817
26817
  this.#writeText(event.data.delta);
26818
26818
  return;
26819
26819
  case "tool_proposed":
26820
- this.#writeConfirmation(event.data);
26820
+ this.#writeStandaloneData(() => this.#writeConfirmation(event.data));
26821
26821
  return;
26822
26822
  case "interaction_proposed":
26823
26823
  this.#writeData("confirmation", event.data.id, {
@@ -26826,10 +26826,12 @@ var AssistantChatStateStore = class {
26826
26826
  });
26827
26827
  return;
26828
26828
  case "input_requested":
26829
- this.#writeData("input-request", event.data.id, {
26830
- ...event.data,
26831
- status: "pending"
26832
- });
26829
+ this.#writeStandaloneData(
26830
+ () => this.#writeData("input-request", event.data.id, {
26831
+ ...event.data,
26832
+ status: "pending"
26833
+ })
26834
+ );
26833
26835
  return;
26834
26836
  case "tool_completed":
26835
26837
  this.#writeData("tool-result", event.data.id, event.data);
@@ -26936,6 +26938,12 @@ var AssistantChatStateStore = class {
26936
26938
  #writeConfirmation(data) {
26937
26939
  this.#writeData("confirmation", data.id, { ...data, status: "pending" });
26938
26940
  }
26941
+ #writeStandaloneData(write) {
26942
+ const standalone = this.#operation === void 0;
26943
+ if (standalone) this.#startOperation();
26944
+ write();
26945
+ if (standalone) this.#closeOperation("ready");
26946
+ }
26939
26947
  #writeData(name21, id, data) {
26940
26948
  const operation = this.#operation;
26941
26949
  if (!operation || operation.closed) return;
@@ -27414,6 +27422,7 @@ var DefaultAssistantClient = class {
27414
27422
  #context;
27415
27423
  #modelContext;
27416
27424
  #active;
27425
+ #pendingAppInteractions = /* @__PURE__ */ new Map();
27417
27426
  constructor(options) {
27418
27427
  if (!options.sessionEndpoint) throw new Error("sessionEndpoint is required");
27419
27428
  this.#sessionEndpoint = options.sessionEndpoint;
@@ -27455,6 +27464,7 @@ var DefaultAssistantClient = class {
27455
27464
  }
27456
27465
  await this.#singleFlight(async (signal) => {
27457
27466
  await this.#runChatOperation(signal, async () => {
27467
+ const pendingApp = this.#pendingAppInteractions.get(id);
27458
27468
  const session = this.#session;
27459
27469
  if (!session) {
27460
27470
  throw clientError("confirmation_expired", "assistant session is not active", false);
@@ -27474,32 +27484,67 @@ var DefaultAssistantClient = class {
27474
27484
  ...resolution.action === "accept" && resolution.content !== void 0 ? { content: resolution.content } : {}
27475
27485
  } : { id };
27476
27486
  this.#emit({ event: "interaction_started", data: { id, action: resolution.action } });
27477
- const response = await this.#request(
27478
- endpoint,
27479
- {
27480
- method: "POST",
27481
- headers: authorizedHeaders(session.token, "text/event-stream"),
27482
- body: JSON.stringify(body),
27483
- signal
27484
- },
27485
- "confirmation_failed"
27486
- );
27487
- if (response.status === 401) {
27488
- this.#session = void 0;
27489
- this.#emit({ event: "session_expired", data: {} });
27490
- }
27491
- if (!response.ok) {
27492
- const serverCode = await readStableErrorCode(response);
27493
- const expired = response.status === 401 || response.status === 409;
27494
- throw clientError(
27495
- serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
27496
- `Assistant interaction failed (${response.status})`,
27497
- false,
27498
- response.status
27487
+ try {
27488
+ const response = await this.#request(
27489
+ endpoint,
27490
+ {
27491
+ method: "POST",
27492
+ headers: authorizedHeaders(session.token, "text/event-stream"),
27493
+ body: JSON.stringify(body),
27494
+ signal
27495
+ },
27496
+ "confirmation_failed"
27499
27497
  );
27498
+ if (response.status === 401) {
27499
+ this.#session = void 0;
27500
+ this.#emit({ event: "session_expired", data: {} });
27501
+ }
27502
+ if (!response.ok) {
27503
+ const serverCode = await readStableErrorCode(response);
27504
+ const expired = response.status === 401 || response.status === 409;
27505
+ throw clientError(
27506
+ serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
27507
+ `Assistant interaction failed (${response.status})`,
27508
+ false,
27509
+ response.status
27510
+ );
27511
+ }
27512
+ let completedResult;
27513
+ let nextInteractionId;
27514
+ await this.#consume(response, (event) => {
27515
+ if (event.event === "tool_completed" && event.data.id === id) {
27516
+ completedResult = event.data.result;
27517
+ }
27518
+ if ((event.event === "tool_proposed" || event.event === "input_requested") && event.data.id !== id) {
27519
+ nextInteractionId = event.data.id;
27520
+ }
27521
+ });
27522
+ this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
27523
+ if (pendingApp) {
27524
+ this.#pendingAppInteractions.delete(id);
27525
+ if (nextInteractionId) {
27526
+ this.#pendingAppInteractions.set(nextInteractionId, pendingApp);
27527
+ } else if (resolution.action !== "accept") {
27528
+ pendingApp.resolve(appInteractionStopped(resolution.action));
27529
+ } else if (completedResult !== void 0) {
27530
+ pendingApp.resolve(appToolResult(completedResult));
27531
+ } else {
27532
+ pendingApp.reject(
27533
+ clientError(
27534
+ "invalid_response",
27535
+ "Assistant app interaction completed without a tool result",
27536
+ false
27537
+ )
27538
+ );
27539
+ }
27540
+ }
27541
+ } catch (error51) {
27542
+ if (pendingApp && this.#pendingAppInteractions.get(id) === pendingApp) {
27543
+ this.#pendingAppInteractions.delete(id);
27544
+ pendingApp.reject(error51);
27545
+ }
27546
+ throw error51;
27500
27547
  }
27501
- await this.#consume(response);
27502
- this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
27503
27548
  });
27504
27549
  });
27505
27550
  }
@@ -27540,12 +27585,29 @@ var DefaultAssistantClient = class {
27540
27585
  response.status
27541
27586
  );
27542
27587
  }
27543
- return response.json();
27588
+ const value = await response.json();
27589
+ const interaction = parseAppInteraction(value);
27590
+ if (!interaction) return value;
27591
+ return new Promise((resolve2, reject) => {
27592
+ const id = interaction.data.id;
27593
+ const replaced = this.#pendingAppInteractions.get(id);
27594
+ if (replaced) {
27595
+ replaced.reject(
27596
+ clientError("invalid_response", "Assistant returned a duplicate app interaction", false)
27597
+ );
27598
+ }
27599
+ this.#pendingAppInteractions.set(id, { resolve: resolve2, reject });
27600
+ this.#emit(interaction);
27601
+ void this.#chat.flush();
27602
+ });
27544
27603
  }
27545
27604
  appSandboxUrl() {
27546
27605
  return this.#session?.endpoints.sandbox;
27547
27606
  }
27548
27607
  resetSession() {
27608
+ this.#rejectPendingAppInteractions(
27609
+ clientError("confirmation_expired", "assistant session is not active", false)
27610
+ );
27549
27611
  this.#session = void 0;
27550
27612
  this.#emit({ event: "session_reset", data: {} });
27551
27613
  }
@@ -27666,12 +27728,13 @@ var DefaultAssistantClient = class {
27666
27728
  });
27667
27729
  return session;
27668
27730
  }
27669
- async #consume(response) {
27731
+ async #consume(response, observe) {
27670
27732
  let streamError;
27671
27733
  try {
27672
27734
  await consumeAssistantEvents(response, (event) => {
27673
27735
  const clientEvent = toAssistantClientEvent(event);
27674
27736
  this.#emit(clientEvent);
27737
+ observe?.(clientEvent);
27675
27738
  if (clientEvent.event !== "error" || typeof clientEvent.data.code !== "string") return;
27676
27739
  streamError = {
27677
27740
  code: clientEvent.data.code,
@@ -27740,6 +27803,10 @@ var DefaultAssistantClient = class {
27740
27803
  }
27741
27804
  }
27742
27805
  }
27806
+ #rejectPendingAppInteractions(error51) {
27807
+ for (const pending of this.#pendingAppInteractions.values()) pending.reject(error51);
27808
+ this.#pendingAppInteractions.clear();
27809
+ }
27743
27810
  };
27744
27811
  function createAssistantClient(options) {
27745
27812
  return new DefaultAssistantClient(options);
@@ -27751,6 +27818,30 @@ function authorizedHeaders(token, accept) {
27751
27818
  Accept: accept
27752
27819
  };
27753
27820
  }
27821
+ function parseAppInteraction(value) {
27822
+ if (!isRecord4(value) || !isRecord4(value.interaction)) return void 0;
27823
+ const event = value.interaction.event;
27824
+ const data = value.interaction.data;
27825
+ if (event !== "tool_proposed" && event !== "input_requested" || !isRecord4(data)) {
27826
+ return void 0;
27827
+ }
27828
+ const parsed = toAssistantClientEvent({ event, data });
27829
+ return parsed.event === "tool_proposed" || parsed.event === "input_requested" ? parsed : void 0;
27830
+ }
27831
+ function appToolResult(result) {
27832
+ const text3 = typeof result === "string" ? result : JSON.stringify(result);
27833
+ return result !== null && typeof result === "object" && !Array.isArray(result) ? {
27834
+ content: [{ type: "text", text: text3 }],
27835
+ structuredContent: result,
27836
+ isError: false
27837
+ } : { content: [{ type: "text", text: text3 }], isError: false };
27838
+ }
27839
+ function appInteractionStopped(action) {
27840
+ return {
27841
+ content: [{ type: "text", text: `interaction_${action}` }],
27842
+ isError: true
27843
+ };
27844
+ }
27754
27845
  function parseSession(value) {
27755
27846
  if (!isRecord4(value) || !isRecord4(value.endpoints)) {
27756
27847
  throw clientError("session_failed", "Assistant session response is invalid", true);
@@ -30966,7 +31057,6 @@ var AssistantElementEventController = class {
30966
31057
  return;
30967
31058
  }
30968
31059
  if (name21 === "tool_proposed" || name21 === "interaction_proposed") {
30969
- if (!this.#streamKind) return;
30970
31060
  this.#appendToolProposal(
30971
31061
  String(data.id ?? ""),
30972
31062
  String(data.tool ?? "action"),
@@ -30978,7 +31068,6 @@ var AssistantElementEventController = class {
30978
31068
  return;
30979
31069
  }
30980
31070
  if (name21 === "input_requested" && isRecord5(data.requestedSchema)) {
30981
- if (!this.#streamKind) return;
30982
31071
  this.#appendInputRequest(
30983
31072
  String(data.id ?? ""),
30984
31073
  String(data.message ?? "More information is required"),