@yushaw/sanqian-chat 0.2.25 → 0.2.27

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.
@@ -922,7 +922,8 @@ declare class ChatPanel {
922
922
  private saveState;
923
923
  private getSdk;
924
924
  /**
925
- * Resolve HITL runId. Prefer explicit runId from renderer; fallback to latest active stream runId.
925
+ * Resolve HITL runId with deterministic binding for concurrent streams.
926
+ * Priority: explicit runId -> streamId-bound runId -> single active stream fallback.
926
927
  */
927
928
  private resolveHitlRunId;
928
929
  /**
@@ -922,7 +922,8 @@ declare class ChatPanel {
922
922
  private saveState;
923
923
  private getSdk;
924
924
  /**
925
- * Resolve HITL runId. Prefer explicit runId from renderer; fallback to latest active stream runId.
925
+ * Resolve HITL runId with deterministic binding for concurrent streams.
926
+ * Priority: explicit runId -> streamId-bound runId -> single active stream fallback.
926
927
  */
927
928
  private resolveHitlRunId;
928
929
  /**
@@ -366,6 +366,32 @@ var import_electron = require("electron");
366
366
  var import_fs = __toESM(require("fs"));
367
367
  var import_os = __toESM(require("os"));
368
368
  var import_path = __toESM(require("path"));
369
+
370
+ // src/main/hitl.ts
371
+ function resolveHitlRunIdFromStreams(params, activeStreams) {
372
+ if (params.runId) {
373
+ return params.runId;
374
+ }
375
+ if (params.streamId) {
376
+ const stream = activeStreams.get(params.streamId);
377
+ if (!stream || stream.cancelled) {
378
+ return null;
379
+ }
380
+ return stream.runId ?? null;
381
+ }
382
+ const activeRunIds = /* @__PURE__ */ new Set();
383
+ for (const stream of activeStreams.values()) {
384
+ if (stream.cancelled || !stream.runId) continue;
385
+ activeRunIds.add(stream.runId);
386
+ if (activeRunIds.size > 1) {
387
+ return null;
388
+ }
389
+ }
390
+ const first = activeRunIds.values().next();
391
+ return first.done ? null : first.value;
392
+ }
393
+
394
+ // src/main/FloatingWindow.ts
369
395
  var ipcHandlersRegistered = false;
370
396
  var activeInstance = null;
371
397
  var setActiveInstance = (instance) => {
@@ -399,16 +425,8 @@ var FloatingWindow = class _FloatingWindow {
399
425
  import_electron.app.whenReady().then(() => this.registerShortcut());
400
426
  }
401
427
  }
402
- resolveHitlRunId(runId) {
403
- if (runId) return runId;
404
- const streams = Array.from(this.activeStreams.values());
405
- for (let i = streams.length - 1; i >= 0; i -= 1) {
406
- const stream = streams[i];
407
- if (stream && stream.runId && !stream.cancelled) {
408
- return stream.runId;
409
- }
410
- }
411
- return null;
428
+ resolveHitlRunId(params) {
429
+ return resolveHitlRunIdFromStreams(params, this.activeStreams);
412
430
  }
413
431
  /**
414
432
  * Get SDK instance from either getClient or getSdk
@@ -746,7 +764,7 @@ var FloatingWindow = class _FloatingWindow {
746
764
  });
747
765
  import_electron.ipcMain.handle("sanqian-chat:hitlResponse", (_, params) => {
748
766
  const sdk = activeInstance ? _FloatingWindow.getSdkFromOptions(activeInstance.options) : null;
749
- const runId = activeInstance?.resolveHitlRunId(params.runId) ?? null;
767
+ const runId = activeInstance?.resolveHitlRunId({ runId: params.runId, streamId: params.streamId }) ?? null;
750
768
  if (sdk && runId) {
751
769
  sdk.sendHitlResponse(runId, params.response);
752
770
  } else if (activeInstance?.options.devMode) {
@@ -1700,18 +1718,11 @@ var ChatPanel = class {
1700
1718
  return client;
1701
1719
  }
1702
1720
  /**
1703
- * Resolve HITL runId. Prefer explicit runId from renderer; fallback to latest active stream runId.
1721
+ * Resolve HITL runId with deterministic binding for concurrent streams.
1722
+ * Priority: explicit runId -> streamId-bound runId -> single active stream fallback.
1704
1723
  */
1705
- resolveHitlRunId(runId) {
1706
- if (runId) return runId;
1707
- const streams = Array.from(this.activeStreams.values());
1708
- for (let i = streams.length - 1; i >= 0; i -= 1) {
1709
- const stream = streams[i];
1710
- if (stream && stream.runId && !stream.cancelled) {
1711
- return stream.runId;
1712
- }
1713
- }
1714
- return null;
1724
+ resolveHitlRunId(params) {
1725
+ return resolveHitlRunIdFromStreams(params, this.activeStreams);
1715
1726
  }
1716
1727
  /**
1717
1728
  * Setup session resource event forwarding from SDK to renderer
@@ -1875,7 +1886,7 @@ var ChatPanel = class {
1875
1886
  });
1876
1887
  import_electron2.ipcMain.handle("sanqian-chat:hitlResponse", (_, params) => {
1877
1888
  const sdk = activeInstance2?.getSdk();
1878
- const runId = activeInstance2?.resolveHitlRunId(params.runId) ?? null;
1889
+ const runId = activeInstance2?.resolveHitlRunId({ runId: params.runId, streamId: params.streamId }) ?? null;
1879
1890
  if (sdk && runId) {
1880
1891
  sdk.sendHitlResponse(runId, params.response);
1881
1892
  } else if (activeInstance2?.config.devMode) {
@@ -335,6 +335,32 @@ import { BrowserWindow, globalShortcut, screen, ipcMain, app } from "electron";
335
335
  import fs from "fs";
336
336
  import os from "os";
337
337
  import path from "path";
338
+
339
+ // src/main/hitl.ts
340
+ function resolveHitlRunIdFromStreams(params, activeStreams) {
341
+ if (params.runId) {
342
+ return params.runId;
343
+ }
344
+ if (params.streamId) {
345
+ const stream = activeStreams.get(params.streamId);
346
+ if (!stream || stream.cancelled) {
347
+ return null;
348
+ }
349
+ return stream.runId ?? null;
350
+ }
351
+ const activeRunIds = /* @__PURE__ */ new Set();
352
+ for (const stream of activeStreams.values()) {
353
+ if (stream.cancelled || !stream.runId) continue;
354
+ activeRunIds.add(stream.runId);
355
+ if (activeRunIds.size > 1) {
356
+ return null;
357
+ }
358
+ }
359
+ const first = activeRunIds.values().next();
360
+ return first.done ? null : first.value;
361
+ }
362
+
363
+ // src/main/FloatingWindow.ts
338
364
  var ipcHandlersRegistered = false;
339
365
  var activeInstance = null;
340
366
  var setActiveInstance = (instance) => {
@@ -368,16 +394,8 @@ var FloatingWindow = class _FloatingWindow {
368
394
  app.whenReady().then(() => this.registerShortcut());
369
395
  }
370
396
  }
371
- resolveHitlRunId(runId) {
372
- if (runId) return runId;
373
- const streams = Array.from(this.activeStreams.values());
374
- for (let i = streams.length - 1; i >= 0; i -= 1) {
375
- const stream = streams[i];
376
- if (stream && stream.runId && !stream.cancelled) {
377
- return stream.runId;
378
- }
379
- }
380
- return null;
397
+ resolveHitlRunId(params) {
398
+ return resolveHitlRunIdFromStreams(params, this.activeStreams);
381
399
  }
382
400
  /**
383
401
  * Get SDK instance from either getClient or getSdk
@@ -715,7 +733,7 @@ var FloatingWindow = class _FloatingWindow {
715
733
  });
716
734
  ipcMain.handle("sanqian-chat:hitlResponse", (_, params) => {
717
735
  const sdk = activeInstance ? _FloatingWindow.getSdkFromOptions(activeInstance.options) : null;
718
- const runId = activeInstance?.resolveHitlRunId(params.runId) ?? null;
736
+ const runId = activeInstance?.resolveHitlRunId({ runId: params.runId, streamId: params.streamId }) ?? null;
719
737
  if (sdk && runId) {
720
738
  sdk.sendHitlResponse(runId, params.response);
721
739
  } else if (activeInstance?.options.devMode) {
@@ -1675,18 +1693,11 @@ var ChatPanel = class {
1675
1693
  return client;
1676
1694
  }
1677
1695
  /**
1678
- * Resolve HITL runId. Prefer explicit runId from renderer; fallback to latest active stream runId.
1696
+ * Resolve HITL runId with deterministic binding for concurrent streams.
1697
+ * Priority: explicit runId -> streamId-bound runId -> single active stream fallback.
1679
1698
  */
1680
- resolveHitlRunId(runId) {
1681
- if (runId) return runId;
1682
- const streams = Array.from(this.activeStreams.values());
1683
- for (let i = streams.length - 1; i >= 0; i -= 1) {
1684
- const stream = streams[i];
1685
- if (stream && stream.runId && !stream.cancelled) {
1686
- return stream.runId;
1687
- }
1688
- }
1689
- return null;
1699
+ resolveHitlRunId(params) {
1700
+ return resolveHitlRunIdFromStreams(params, this.activeStreams);
1690
1701
  }
1691
1702
  /**
1692
1703
  * Setup session resource event forwarding from SDK to renderer
@@ -1850,7 +1861,7 @@ var ChatPanel = class {
1850
1861
  });
1851
1862
  ipcMain2.handle("sanqian-chat:hitlResponse", (_, params) => {
1852
1863
  const sdk = activeInstance2?.getSdk();
1853
- const runId = activeInstance2?.resolveHitlRunId(params.runId) ?? null;
1864
+ const runId = activeInstance2?.resolveHitlRunId({ runId: params.runId, streamId: params.streamId }) ?? null;
1854
1865
  if (sdk && runId) {
1855
1866
  sdk.sendHitlResponse(runId, params.response);
1856
1867
  } else if (activeInstance2?.config.devMode) {
@@ -853,11 +853,13 @@ function useChat(options) {
853
853
  clearPendingCancel();
854
854
  }, [clearPendingCancel, resetStreamBuffers]);
855
855
  const sendHitlResponse = (0, import_react.useCallback)((response) => {
856
- adapter.sendHitlResponse?.(
857
- response,
858
- currentRunIdRef.current ?? void 0,
859
- pendingInterruptStreamIdRef.current ?? void 0
860
- );
856
+ const runId = currentRunIdRef.current ?? void 0;
857
+ const streamId = pendingInterruptStreamIdRef.current ?? void 0;
858
+ if (streamId) {
859
+ adapter.sendHitlResponse?.(response, runId, streamId);
860
+ return;
861
+ }
862
+ adapter.sendHitlResponse?.(response, runId);
861
863
  }, [adapter]);
862
864
  const approveHitl = (0, import_react.useCallback)((remember = false) => {
863
865
  sendHitlResponse({ approved: true, remember });
@@ -765,11 +765,13 @@ function useChat(options) {
765
765
  clearPendingCancel();
766
766
  }, [clearPendingCancel, resetStreamBuffers]);
767
767
  const sendHitlResponse = useCallback((response) => {
768
- adapter.sendHitlResponse?.(
769
- response,
770
- currentRunIdRef.current ?? void 0,
771
- pendingInterruptStreamIdRef.current ?? void 0
772
- );
768
+ const runId = currentRunIdRef.current ?? void 0;
769
+ const streamId = pendingInterruptStreamIdRef.current ?? void 0;
770
+ if (streamId) {
771
+ adapter.sendHitlResponse?.(response, runId, streamId);
772
+ return;
773
+ }
774
+ adapter.sendHitlResponse?.(response, runId);
773
775
  }, [adapter]);
774
776
  const approveHitl = useCallback((remember = false) => {
775
777
  sendHitlResponse({ approved: true, remember });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yushaw/sanqian-chat",
3
- "version": "0.2.25",
3
+ "version": "0.2.27",
4
4
  "description": "Floating chat window SDK for Sanqian AI Assistant",
5
5
  "main": "./dist/main/index.js",
6
6
  "types": "./dist/main/index.d.ts",