@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.
package/dist/index.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  ASSISTANT_TAG_NAME,
3
3
  NoodleAssistantElement,
4
4
  registerNoodleAssistant
5
- } from "./chunk-ZPELSHUP.js";
6
- import "./chunk-KRB2SXFD.js";
5
+ } from "./chunk-7WXGZJCA.js";
6
+ import "./chunk-RITHSCTD.js";
7
7
  import "./chunk-3YYTUJPJ.js";
8
8
  import "./chunk-5FUTL2UF.js";
9
9
 
@@ -22644,7 +22644,7 @@ var AssistantChatStateStore = class {
22644
22644
  this.#writeText(event.data.delta);
22645
22645
  return;
22646
22646
  case "tool_proposed":
22647
- this.#writeConfirmation(event.data);
22647
+ this.#writeStandaloneData(() => this.#writeConfirmation(event.data));
22648
22648
  return;
22649
22649
  case "interaction_proposed":
22650
22650
  this.#writeData("confirmation", event.data.id, {
@@ -22653,10 +22653,12 @@ var AssistantChatStateStore = class {
22653
22653
  });
22654
22654
  return;
22655
22655
  case "input_requested":
22656
- this.#writeData("input-request", event.data.id, {
22657
- ...event.data,
22658
- status: "pending"
22659
- });
22656
+ this.#writeStandaloneData(
22657
+ () => this.#writeData("input-request", event.data.id, {
22658
+ ...event.data,
22659
+ status: "pending"
22660
+ })
22661
+ );
22660
22662
  return;
22661
22663
  case "tool_completed":
22662
22664
  this.#writeData("tool-result", event.data.id, event.data);
@@ -22763,6 +22765,12 @@ var AssistantChatStateStore = class {
22763
22765
  #writeConfirmation(data) {
22764
22766
  this.#writeData("confirmation", data.id, { ...data, status: "pending" });
22765
22767
  }
22768
+ #writeStandaloneData(write) {
22769
+ const standalone = this.#operation === void 0;
22770
+ if (standalone) this.#startOperation();
22771
+ write();
22772
+ if (standalone) this.#closeOperation("ready");
22773
+ }
22766
22774
  #writeData(name21, id, data) {
22767
22775
  const operation = this.#operation;
22768
22776
  if (!operation || operation.closed) return;
@@ -23241,6 +23249,7 @@ var DefaultAssistantClient = class {
23241
23249
  #context;
23242
23250
  #modelContext;
23243
23251
  #active;
23252
+ #pendingAppInteractions = /* @__PURE__ */ new Map();
23244
23253
  constructor(options) {
23245
23254
  if (!options.sessionEndpoint) throw new Error("sessionEndpoint is required");
23246
23255
  this.#sessionEndpoint = options.sessionEndpoint;
@@ -23282,6 +23291,7 @@ var DefaultAssistantClient = class {
23282
23291
  }
23283
23292
  await this.#singleFlight(async (signal) => {
23284
23293
  await this.#runChatOperation(signal, async () => {
23294
+ const pendingApp = this.#pendingAppInteractions.get(id);
23285
23295
  const session = this.#session;
23286
23296
  if (!session) {
23287
23297
  throw clientError("confirmation_expired", "assistant session is not active", false);
@@ -23301,32 +23311,67 @@ var DefaultAssistantClient = class {
23301
23311
  ...resolution.action === "accept" && resolution.content !== void 0 ? { content: resolution.content } : {}
23302
23312
  } : { id };
23303
23313
  this.#emit({ event: "interaction_started", data: { id, action: resolution.action } });
23304
- const response = await this.#request(
23305
- endpoint,
23306
- {
23307
- method: "POST",
23308
- headers: authorizedHeaders(session.token, "text/event-stream"),
23309
- body: JSON.stringify(body),
23310
- signal
23311
- },
23312
- "confirmation_failed"
23313
- );
23314
- if (response.status === 401) {
23315
- this.#session = void 0;
23316
- this.#emit({ event: "session_expired", data: {} });
23317
- }
23318
- if (!response.ok) {
23319
- const serverCode = await readStableErrorCode(response);
23320
- const expired = response.status === 401 || response.status === 409;
23321
- throw clientError(
23322
- serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
23323
- `Assistant interaction failed (${response.status})`,
23324
- false,
23325
- response.status
23314
+ try {
23315
+ const response = await this.#request(
23316
+ endpoint,
23317
+ {
23318
+ method: "POST",
23319
+ headers: authorizedHeaders(session.token, "text/event-stream"),
23320
+ body: JSON.stringify(body),
23321
+ signal
23322
+ },
23323
+ "confirmation_failed"
23326
23324
  );
23325
+ if (response.status === 401) {
23326
+ this.#session = void 0;
23327
+ this.#emit({ event: "session_expired", data: {} });
23328
+ }
23329
+ if (!response.ok) {
23330
+ const serverCode = await readStableErrorCode(response);
23331
+ const expired = response.status === 401 || response.status === 409;
23332
+ throw clientError(
23333
+ serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
23334
+ `Assistant interaction failed (${response.status})`,
23335
+ false,
23336
+ response.status
23337
+ );
23338
+ }
23339
+ let completedResult;
23340
+ let nextInteractionId;
23341
+ await this.#consume(response, (event) => {
23342
+ if (event.event === "tool_completed" && event.data.id === id) {
23343
+ completedResult = event.data.result;
23344
+ }
23345
+ if ((event.event === "tool_proposed" || event.event === "input_requested") && event.data.id !== id) {
23346
+ nextInteractionId = event.data.id;
23347
+ }
23348
+ });
23349
+ this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
23350
+ if (pendingApp) {
23351
+ this.#pendingAppInteractions.delete(id);
23352
+ if (nextInteractionId) {
23353
+ this.#pendingAppInteractions.set(nextInteractionId, pendingApp);
23354
+ } else if (resolution.action !== "accept") {
23355
+ pendingApp.resolve(appInteractionStopped(resolution.action));
23356
+ } else if (completedResult !== void 0) {
23357
+ pendingApp.resolve(appToolResult(completedResult));
23358
+ } else {
23359
+ pendingApp.reject(
23360
+ clientError(
23361
+ "invalid_response",
23362
+ "Assistant app interaction completed without a tool result",
23363
+ false
23364
+ )
23365
+ );
23366
+ }
23367
+ }
23368
+ } catch (error51) {
23369
+ if (pendingApp && this.#pendingAppInteractions.get(id) === pendingApp) {
23370
+ this.#pendingAppInteractions.delete(id);
23371
+ pendingApp.reject(error51);
23372
+ }
23373
+ throw error51;
23327
23374
  }
23328
- await this.#consume(response);
23329
- this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
23330
23375
  });
23331
23376
  });
23332
23377
  }
@@ -23367,12 +23412,29 @@ var DefaultAssistantClient = class {
23367
23412
  response.status
23368
23413
  );
23369
23414
  }
23370
- return response.json();
23415
+ const value = await response.json();
23416
+ const interaction = parseAppInteraction(value);
23417
+ if (!interaction) return value;
23418
+ return new Promise((resolve2, reject) => {
23419
+ const id = interaction.data.id;
23420
+ const replaced = this.#pendingAppInteractions.get(id);
23421
+ if (replaced) {
23422
+ replaced.reject(
23423
+ clientError("invalid_response", "Assistant returned a duplicate app interaction", false)
23424
+ );
23425
+ }
23426
+ this.#pendingAppInteractions.set(id, { resolve: resolve2, reject });
23427
+ this.#emit(interaction);
23428
+ void this.#chat.flush();
23429
+ });
23371
23430
  }
23372
23431
  appSandboxUrl() {
23373
23432
  return this.#session?.endpoints.sandbox;
23374
23433
  }
23375
23434
  resetSession() {
23435
+ this.#rejectPendingAppInteractions(
23436
+ clientError("confirmation_expired", "assistant session is not active", false)
23437
+ );
23376
23438
  this.#session = void 0;
23377
23439
  this.#emit({ event: "session_reset", data: {} });
23378
23440
  }
@@ -23493,12 +23555,13 @@ var DefaultAssistantClient = class {
23493
23555
  });
23494
23556
  return session;
23495
23557
  }
23496
- async #consume(response) {
23558
+ async #consume(response, observe) {
23497
23559
  let streamError;
23498
23560
  try {
23499
23561
  await consumeAssistantEvents(response, (event) => {
23500
23562
  const clientEvent = toAssistantClientEvent(event);
23501
23563
  this.#emit(clientEvent);
23564
+ observe?.(clientEvent);
23502
23565
  if (clientEvent.event !== "error" || typeof clientEvent.data.code !== "string") return;
23503
23566
  streamError = {
23504
23567
  code: clientEvent.data.code,
@@ -23567,6 +23630,10 @@ var DefaultAssistantClient = class {
23567
23630
  }
23568
23631
  }
23569
23632
  }
23633
+ #rejectPendingAppInteractions(error51) {
23634
+ for (const pending of this.#pendingAppInteractions.values()) pending.reject(error51);
23635
+ this.#pendingAppInteractions.clear();
23636
+ }
23570
23637
  };
23571
23638
  function createAssistantClient(options) {
23572
23639
  return new DefaultAssistantClient(options);
@@ -23578,6 +23645,30 @@ function authorizedHeaders(token, accept) {
23578
23645
  Accept: accept
23579
23646
  };
23580
23647
  }
23648
+ function parseAppInteraction(value) {
23649
+ if (!isRecord4(value) || !isRecord4(value.interaction)) return void 0;
23650
+ const event = value.interaction.event;
23651
+ const data = value.interaction.data;
23652
+ if (event !== "tool_proposed" && event !== "input_requested" || !isRecord4(data)) {
23653
+ return void 0;
23654
+ }
23655
+ const parsed = toAssistantClientEvent({ event, data });
23656
+ return parsed.event === "tool_proposed" || parsed.event === "input_requested" ? parsed : void 0;
23657
+ }
23658
+ function appToolResult(result) {
23659
+ const text2 = typeof result === "string" ? result : JSON.stringify(result);
23660
+ return result !== null && typeof result === "object" && !Array.isArray(result) ? {
23661
+ content: [{ type: "text", text: text2 }],
23662
+ structuredContent: result,
23663
+ isError: false
23664
+ } : { content: [{ type: "text", text: text2 }], isError: false };
23665
+ }
23666
+ function appInteractionStopped(action) {
23667
+ return {
23668
+ content: [{ type: "text", text: `interaction_${action}` }],
23669
+ isError: true
23670
+ };
23671
+ }
23581
23672
  function parseSession(value) {
23582
23673
  if (!isRecord4(value) || !isRecord4(value.endpoints)) {
23583
23674
  throw clientError("session_failed", "Assistant session response is invalid", true);