@noodleseed/assistant 1.12.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.
@@ -8108,7 +8108,7 @@ var AssistantChatStateStore = class {
8108
8108
  this.#writeText(event.data.delta);
8109
8109
  return;
8110
8110
  case "tool_proposed":
8111
- this.#writeConfirmation(event.data);
8111
+ this.#writeStandaloneData(() => this.#writeConfirmation(event.data));
8112
8112
  return;
8113
8113
  case "interaction_proposed":
8114
8114
  this.#writeData("confirmation", event.data.id, {
@@ -8117,10 +8117,12 @@ var AssistantChatStateStore = class {
8117
8117
  });
8118
8118
  return;
8119
8119
  case "input_requested":
8120
- this.#writeData("input-request", event.data.id, {
8121
- ...event.data,
8122
- status: "pending"
8123
- });
8120
+ this.#writeStandaloneData(
8121
+ () => this.#writeData("input-request", event.data.id, {
8122
+ ...event.data,
8123
+ status: "pending"
8124
+ })
8125
+ );
8124
8126
  return;
8125
8127
  case "tool_completed":
8126
8128
  this.#writeData("tool-result", event.data.id, event.data);
@@ -8227,6 +8229,12 @@ var AssistantChatStateStore = class {
8227
8229
  #writeConfirmation(data) {
8228
8230
  this.#writeData("confirmation", data.id, { ...data, status: "pending" });
8229
8231
  }
8232
+ #writeStandaloneData(write) {
8233
+ const standalone = this.#operation === void 0;
8234
+ if (standalone) this.#startOperation();
8235
+ write();
8236
+ if (standalone) this.#closeOperation("ready");
8237
+ }
8230
8238
  #writeData(name21, id, data) {
8231
8239
  const operation = this.#operation;
8232
8240
  if (!operation || operation.closed) return;
@@ -8705,6 +8713,7 @@ var DefaultAssistantClient = class {
8705
8713
  #context;
8706
8714
  #modelContext;
8707
8715
  #active;
8716
+ #pendingAppInteractions = /* @__PURE__ */ new Map();
8708
8717
  constructor(options) {
8709
8718
  if (!options.sessionEndpoint) throw new Error("sessionEndpoint is required");
8710
8719
  this.#sessionEndpoint = options.sessionEndpoint;
@@ -8746,6 +8755,7 @@ var DefaultAssistantClient = class {
8746
8755
  }
8747
8756
  await this.#singleFlight(async (signal) => {
8748
8757
  await this.#runChatOperation(signal, async () => {
8758
+ const pendingApp = this.#pendingAppInteractions.get(id);
8749
8759
  const session = this.#session;
8750
8760
  if (!session) {
8751
8761
  throw clientError("confirmation_expired", "assistant session is not active", false);
@@ -8765,32 +8775,67 @@ var DefaultAssistantClient = class {
8765
8775
  ...resolution.action === "accept" && resolution.content !== void 0 ? { content: resolution.content } : {}
8766
8776
  } : { id };
8767
8777
  this.#emit({ event: "interaction_started", data: { id, action: resolution.action } });
8768
- const response = await this.#request(
8769
- endpoint,
8770
- {
8771
- method: "POST",
8772
- headers: authorizedHeaders(session.token, "text/event-stream"),
8773
- body: JSON.stringify(body),
8774
- signal
8775
- },
8776
- "confirmation_failed"
8777
- );
8778
- if (response.status === 401) {
8779
- this.#session = void 0;
8780
- this.#emit({ event: "session_expired", data: {} });
8781
- }
8782
- if (!response.ok) {
8783
- const serverCode = await readStableErrorCode(response);
8784
- const expired = response.status === 401 || response.status === 409;
8785
- throw clientError(
8786
- serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
8787
- `Assistant interaction failed (${response.status})`,
8788
- false,
8789
- response.status
8778
+ try {
8779
+ const response = await this.#request(
8780
+ endpoint,
8781
+ {
8782
+ method: "POST",
8783
+ headers: authorizedHeaders(session.token, "text/event-stream"),
8784
+ body: JSON.stringify(body),
8785
+ signal
8786
+ },
8787
+ "confirmation_failed"
8790
8788
  );
8789
+ if (response.status === 401) {
8790
+ this.#session = void 0;
8791
+ this.#emit({ event: "session_expired", data: {} });
8792
+ }
8793
+ if (!response.ok) {
8794
+ const serverCode = await readStableErrorCode(response);
8795
+ const expired = response.status === 401 || response.status === 409;
8796
+ throw clientError(
8797
+ serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
8798
+ `Assistant interaction failed (${response.status})`,
8799
+ false,
8800
+ response.status
8801
+ );
8802
+ }
8803
+ let completedResult;
8804
+ let nextInteractionId;
8805
+ await this.#consume(response, (event) => {
8806
+ if (event.event === "tool_completed" && event.data.id === id) {
8807
+ completedResult = event.data.result;
8808
+ }
8809
+ if ((event.event === "tool_proposed" || event.event === "input_requested") && event.data.id !== id) {
8810
+ nextInteractionId = event.data.id;
8811
+ }
8812
+ });
8813
+ this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
8814
+ if (pendingApp) {
8815
+ this.#pendingAppInteractions.delete(id);
8816
+ if (nextInteractionId) {
8817
+ this.#pendingAppInteractions.set(nextInteractionId, pendingApp);
8818
+ } else if (resolution.action !== "accept") {
8819
+ pendingApp.resolve(appInteractionStopped(resolution.action));
8820
+ } else if (completedResult !== void 0) {
8821
+ pendingApp.resolve(appToolResult(completedResult));
8822
+ } else {
8823
+ pendingApp.reject(
8824
+ clientError(
8825
+ "invalid_response",
8826
+ "Assistant app interaction completed without a tool result",
8827
+ false
8828
+ )
8829
+ );
8830
+ }
8831
+ }
8832
+ } catch (error) {
8833
+ if (pendingApp && this.#pendingAppInteractions.get(id) === pendingApp) {
8834
+ this.#pendingAppInteractions.delete(id);
8835
+ pendingApp.reject(error);
8836
+ }
8837
+ throw error;
8791
8838
  }
8792
- await this.#consume(response);
8793
- this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
8794
8839
  });
8795
8840
  });
8796
8841
  }
@@ -8831,12 +8876,29 @@ var DefaultAssistantClient = class {
8831
8876
  response.status
8832
8877
  );
8833
8878
  }
8834
- return response.json();
8879
+ const value = await response.json();
8880
+ const interaction = parseAppInteraction(value);
8881
+ if (!interaction) return value;
8882
+ return new Promise((resolve2, reject) => {
8883
+ const id = interaction.data.id;
8884
+ const replaced = this.#pendingAppInteractions.get(id);
8885
+ if (replaced) {
8886
+ replaced.reject(
8887
+ clientError("invalid_response", "Assistant returned a duplicate app interaction", false)
8888
+ );
8889
+ }
8890
+ this.#pendingAppInteractions.set(id, { resolve: resolve2, reject });
8891
+ this.#emit(interaction);
8892
+ void this.#chat.flush();
8893
+ });
8835
8894
  }
8836
8895
  appSandboxUrl() {
8837
8896
  return this.#session?.endpoints.sandbox;
8838
8897
  }
8839
8898
  resetSession() {
8899
+ this.#rejectPendingAppInteractions(
8900
+ clientError("confirmation_expired", "assistant session is not active", false)
8901
+ );
8840
8902
  this.#session = void 0;
8841
8903
  this.#emit({ event: "session_reset", data: {} });
8842
8904
  }
@@ -8957,12 +9019,13 @@ var DefaultAssistantClient = class {
8957
9019
  });
8958
9020
  return session;
8959
9021
  }
8960
- async #consume(response) {
9022
+ async #consume(response, observe) {
8961
9023
  let streamError;
8962
9024
  try {
8963
9025
  await consumeAssistantEvents(response, (event) => {
8964
9026
  const clientEvent = toAssistantClientEvent(event);
8965
9027
  this.#emit(clientEvent);
9028
+ observe?.(clientEvent);
8966
9029
  if (clientEvent.event !== "error" || typeof clientEvent.data.code !== "string") return;
8967
9030
  streamError = {
8968
9031
  code: clientEvent.data.code,
@@ -9031,6 +9094,10 @@ var DefaultAssistantClient = class {
9031
9094
  }
9032
9095
  }
9033
9096
  }
9097
+ #rejectPendingAppInteractions(error) {
9098
+ for (const pending of this.#pendingAppInteractions.values()) pending.reject(error);
9099
+ this.#pendingAppInteractions.clear();
9100
+ }
9034
9101
  };
9035
9102
  function createAssistantClient(options) {
9036
9103
  return new DefaultAssistantClient(options);
@@ -9042,6 +9109,30 @@ function authorizedHeaders(token, accept) {
9042
9109
  Accept: accept
9043
9110
  };
9044
9111
  }
9112
+ function parseAppInteraction(value) {
9113
+ if (!isRecord4(value) || !isRecord4(value.interaction)) return void 0;
9114
+ const event = value.interaction.event;
9115
+ const data = value.interaction.data;
9116
+ if (event !== "tool_proposed" && event !== "input_requested" || !isRecord4(data)) {
9117
+ return void 0;
9118
+ }
9119
+ const parsed = toAssistantClientEvent({ event, data });
9120
+ return parsed.event === "tool_proposed" || parsed.event === "input_requested" ? parsed : void 0;
9121
+ }
9122
+ function appToolResult(result) {
9123
+ const text2 = typeof result === "string" ? result : JSON.stringify(result);
9124
+ return result !== null && typeof result === "object" && !Array.isArray(result) ? {
9125
+ content: [{ type: "text", text: text2 }],
9126
+ structuredContent: result,
9127
+ isError: false
9128
+ } : { content: [{ type: "text", text: text2 }], isError: false };
9129
+ }
9130
+ function appInteractionStopped(action) {
9131
+ return {
9132
+ content: [{ type: "text", text: `interaction_${action}` }],
9133
+ isError: true
9134
+ };
9135
+ }
9045
9136
  function parseSession(value) {
9046
9137
  if (!isRecord4(value) || !isRecord4(value.endpoints)) {
9047
9138
  throw clientError("session_failed", "Assistant session response is invalid", true);
@@ -9091,4 +9182,4 @@ export {
9091
9182
  AssistantClientError,
9092
9183
  createAssistantClient
9093
9184
  };
9094
- //# sourceMappingURL=chunk-KRB2SXFD.js.map
9185
+ //# sourceMappingURL=chunk-RITHSCTD.js.map