chatablex-web-sdk 1.0.34 → 1.0.36

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.d.mts CHANGED
@@ -279,8 +279,15 @@ interface AgentLockConfig {
279
279
  allowCancel?: boolean;
280
280
  /** Overlay background opacity, 0–1 (default: 0.3). */
281
281
  opacity?: number;
282
- /** Auto-unlock timeout in ms (default: 30000). 0 disables. */
282
+ /** Auto-unlock timeout for a single tool execution, in ms (default: 30000). 0 disables. */
283
283
  timeout?: number;
284
+ /**
285
+ * Safety auto-unlock timeout for a whole agent turn, in ms (default: 0 =
286
+ * disabled, rely on the host's turn-end signal). When the host drives a
287
+ * turn-level lock (the lock spans the entire agent response, not just one
288
+ * tool), this acts purely as a fallback in case the turn-end signal is lost.
289
+ */
290
+ turnTimeout?: number;
284
291
  /** Delay before actually removing the overlay after unlock, to avoid flicker between consecutive tools (default: 200ms). */
285
292
  debounceUnlock?: number;
286
293
  }
package/dist/index.d.ts CHANGED
@@ -279,8 +279,15 @@ interface AgentLockConfig {
279
279
  allowCancel?: boolean;
280
280
  /** Overlay background opacity, 0–1 (default: 0.3). */
281
281
  opacity?: number;
282
- /** Auto-unlock timeout in ms (default: 30000). 0 disables. */
282
+ /** Auto-unlock timeout for a single tool execution, in ms (default: 30000). 0 disables. */
283
283
  timeout?: number;
284
+ /**
285
+ * Safety auto-unlock timeout for a whole agent turn, in ms (default: 0 =
286
+ * disabled, rely on the host's turn-end signal). When the host drives a
287
+ * turn-level lock (the lock spans the entire agent response, not just one
288
+ * tool), this acts purely as a fallback in case the turn-end signal is lost.
289
+ */
290
+ turnTimeout?: number;
284
291
  /** Delay before actually removing the overlay after unlock, to avoid flicker between consecutive tools (default: 200ms). */
285
292
  debounceUnlock?: number;
286
293
  }
package/dist/index.js CHANGED
@@ -553,8 +553,10 @@ var DEFAULT_CONFIG = {
553
553
  allowCancel: true,
554
554
  opacity: 0.3,
555
555
  timeout: 3e4,
556
+ turnTimeout: 0,
556
557
  debounceUnlock: 200
557
558
  };
559
+ var TURN_EVENT = "agentLock";
558
560
  var OVERLAY_ID = "__chatablex_agent_lock_overlay__";
559
561
  var BLOCKED_EVENTS = [
560
562
  "mousedown",
@@ -580,13 +582,14 @@ function blockEvent(e) {
580
582
  e.stopPropagation();
581
583
  e.preventDefault();
582
584
  }
583
- function createAgentLockModule(_bridge, userConfig = {}) {
585
+ function createAgentLockModule(bridge, userConfig = {}) {
584
586
  const cfg = { ...DEFAULT_CONFIG, ...userConfig };
585
587
  const logoSrc = cfg.logoUrl || bee_default;
586
588
  const listeners = /* @__PURE__ */ new Map();
587
589
  let overlayEl = null;
588
590
  let locked = false;
589
591
  let lockCount = 0;
592
+ let turnActive = false;
590
593
  let timeoutTimer = null;
591
594
  let debounceTimer = null;
592
595
  let currentMessage = cfg.message;
@@ -697,6 +700,7 @@ function createAgentLockModule(_bridge, userConfig = {}) {
697
700
  if (!locked) return;
698
701
  locked = false;
699
702
  lockCount = 0;
703
+ turnActive = false;
700
704
  clearTimeoutTimer();
701
705
  clearDebounceTimer();
702
706
  if (cfg.mode === "overlay") {
@@ -704,11 +708,34 @@ function createAgentLockModule(_bridge, userConfig = {}) {
704
708
  }
705
709
  emit("unlock", { requestId });
706
710
  }
711
+ function maybeUnlock(requestId) {
712
+ if (turnActive || lockCount > 0) return;
713
+ forceUnlock(requestId);
714
+ }
715
+ function scheduleDebouncedUnlock(requestId) {
716
+ clearDebounceTimer();
717
+ debounceTimer = setTimeout(() => maybeUnlock(requestId), cfg.debounceUnlock);
718
+ }
707
719
  function handleCancel() {
708
720
  const rid = void 0;
709
721
  forceUnlock(rid);
710
722
  emit("cancel", { requestId: rid });
711
723
  }
724
+ function setTurn(active) {
725
+ if (!cfg.enabled) return;
726
+ if (active) {
727
+ turnActive = true;
728
+ clearDebounceTimer();
729
+ if (!locked) {
730
+ doLock(cfg.message, cfg.turnTimeout);
731
+ } else {
732
+ startTimeout(cfg.turnTimeout);
733
+ }
734
+ } else {
735
+ turnActive = false;
736
+ if (lockCount === 0) scheduleDebouncedUnlock();
737
+ }
738
+ }
712
739
  function lock(opts) {
713
740
  if (!cfg.enabled) return;
714
741
  const msg = opts?.message ?? cfg.message;
@@ -734,32 +761,32 @@ function createAgentLockModule(_bridge, userConfig = {}) {
734
761
  clearDebounceTimer();
735
762
  lockCount++;
736
763
  if (!locked) {
737
- doLock(cfg.message, cfg.timeout, requestId);
764
+ doLock(cfg.message, turnActive ? cfg.turnTimeout : cfg.timeout, requestId);
738
765
  }
739
766
  }
740
767
  function _autoUnlock(requestId) {
741
768
  if (!cfg.enabled) return;
742
769
  lockCount = Math.max(0, lockCount - 1);
743
770
  if (lockCount === 0) {
744
- clearDebounceTimer();
745
- debounceTimer = setTimeout(() => {
746
- if (lockCount === 0) {
747
- forceUnlock(requestId);
748
- }
749
- }, cfg.debounceUnlock);
771
+ scheduleDebouncedUnlock(requestId);
750
772
  }
751
773
  }
752
774
  function _destroy() {
775
+ if (removeTurnListener) removeTurnListener();
753
776
  forceUnlock();
754
777
  listeners.clear();
755
778
  }
779
+ const removeTurnListener = bridge.addEventListener(TURN_EVENT, (data) => {
780
+ const active = !!data?.active;
781
+ setTurn(active);
782
+ });
756
783
  return { lock, unlock, isLocked, on, off, _autoLock, _autoUnlock, _destroy };
757
784
  }
758
785
 
759
786
  // package.json
760
787
  var package_default = {
761
788
  name: "chatablex-web-sdk",
762
- version: "1.0.34",
789
+ version: "1.0.36",
763
790
  description: "ChatableX Web SDK for AI App WebUI development. Provides bridge communication with the ChatableX Flutter client.",
764
791
  main: "dist/index.js",
765
792
  module: "dist/index.mjs",
package/dist/index.mjs CHANGED
@@ -521,8 +521,10 @@ var DEFAULT_CONFIG = {
521
521
  allowCancel: true,
522
522
  opacity: 0.3,
523
523
  timeout: 3e4,
524
+ turnTimeout: 0,
524
525
  debounceUnlock: 200
525
526
  };
527
+ var TURN_EVENT = "agentLock";
526
528
  var OVERLAY_ID = "__chatablex_agent_lock_overlay__";
527
529
  var BLOCKED_EVENTS = [
528
530
  "mousedown",
@@ -548,13 +550,14 @@ function blockEvent(e) {
548
550
  e.stopPropagation();
549
551
  e.preventDefault();
550
552
  }
551
- function createAgentLockModule(_bridge, userConfig = {}) {
553
+ function createAgentLockModule(bridge, userConfig = {}) {
552
554
  const cfg = { ...DEFAULT_CONFIG, ...userConfig };
553
555
  const logoSrc = cfg.logoUrl || bee_default;
554
556
  const listeners = /* @__PURE__ */ new Map();
555
557
  let overlayEl = null;
556
558
  let locked = false;
557
559
  let lockCount = 0;
560
+ let turnActive = false;
558
561
  let timeoutTimer = null;
559
562
  let debounceTimer = null;
560
563
  let currentMessage = cfg.message;
@@ -665,6 +668,7 @@ function createAgentLockModule(_bridge, userConfig = {}) {
665
668
  if (!locked) return;
666
669
  locked = false;
667
670
  lockCount = 0;
671
+ turnActive = false;
668
672
  clearTimeoutTimer();
669
673
  clearDebounceTimer();
670
674
  if (cfg.mode === "overlay") {
@@ -672,11 +676,34 @@ function createAgentLockModule(_bridge, userConfig = {}) {
672
676
  }
673
677
  emit("unlock", { requestId });
674
678
  }
679
+ function maybeUnlock(requestId) {
680
+ if (turnActive || lockCount > 0) return;
681
+ forceUnlock(requestId);
682
+ }
683
+ function scheduleDebouncedUnlock(requestId) {
684
+ clearDebounceTimer();
685
+ debounceTimer = setTimeout(() => maybeUnlock(requestId), cfg.debounceUnlock);
686
+ }
675
687
  function handleCancel() {
676
688
  const rid = void 0;
677
689
  forceUnlock(rid);
678
690
  emit("cancel", { requestId: rid });
679
691
  }
692
+ function setTurn(active) {
693
+ if (!cfg.enabled) return;
694
+ if (active) {
695
+ turnActive = true;
696
+ clearDebounceTimer();
697
+ if (!locked) {
698
+ doLock(cfg.message, cfg.turnTimeout);
699
+ } else {
700
+ startTimeout(cfg.turnTimeout);
701
+ }
702
+ } else {
703
+ turnActive = false;
704
+ if (lockCount === 0) scheduleDebouncedUnlock();
705
+ }
706
+ }
680
707
  function lock(opts) {
681
708
  if (!cfg.enabled) return;
682
709
  const msg = opts?.message ?? cfg.message;
@@ -702,32 +729,32 @@ function createAgentLockModule(_bridge, userConfig = {}) {
702
729
  clearDebounceTimer();
703
730
  lockCount++;
704
731
  if (!locked) {
705
- doLock(cfg.message, cfg.timeout, requestId);
732
+ doLock(cfg.message, turnActive ? cfg.turnTimeout : cfg.timeout, requestId);
706
733
  }
707
734
  }
708
735
  function _autoUnlock(requestId) {
709
736
  if (!cfg.enabled) return;
710
737
  lockCount = Math.max(0, lockCount - 1);
711
738
  if (lockCount === 0) {
712
- clearDebounceTimer();
713
- debounceTimer = setTimeout(() => {
714
- if (lockCount === 0) {
715
- forceUnlock(requestId);
716
- }
717
- }, cfg.debounceUnlock);
739
+ scheduleDebouncedUnlock(requestId);
718
740
  }
719
741
  }
720
742
  function _destroy() {
743
+ if (removeTurnListener) removeTurnListener();
721
744
  forceUnlock();
722
745
  listeners.clear();
723
746
  }
747
+ const removeTurnListener = bridge.addEventListener(TURN_EVENT, (data) => {
748
+ const active = !!data?.active;
749
+ setTurn(active);
750
+ });
724
751
  return { lock, unlock, isLocked, on, off, _autoLock, _autoUnlock, _destroy };
725
752
  }
726
753
 
727
754
  // package.json
728
755
  var package_default = {
729
756
  name: "chatablex-web-sdk",
730
- version: "1.0.34",
757
+ version: "1.0.36",
731
758
  description: "ChatableX Web SDK for AI App WebUI development. Provides bridge communication with the ChatableX Flutter client.",
732
759
  main: "dist/index.js",
733
760
  module: "dist/index.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatablex-web-sdk",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
4
4
  "description": "ChatableX Web SDK for AI App WebUI development. Provides bridge communication with the ChatableX Flutter client.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -16,9 +16,17 @@ const DEFAULT_CONFIG: Required<AgentLockConfig> = {
16
16
  allowCancel: true,
17
17
  opacity: 0.3,
18
18
  timeout: 30_000,
19
+ turnTimeout: 0,
19
20
  debounceUnlock: 200,
20
21
  };
21
22
 
23
+ /**
24
+ * Bridge event pushed by the Flutter host to lock the UI for the *entire* agent
25
+ * turn (from the moment the agent starts responding until the turn ends),
26
+ * rather than only during each individual tool execution. Payload: `{ active }`.
27
+ */
28
+ const TURN_EVENT = 'agentLock';
29
+
22
30
  const OVERLAY_ID = '__chatablex_agent_lock_overlay__';
23
31
 
24
32
  /**
@@ -55,7 +63,7 @@ export interface AgentLockModule extends ChatableXAgentLock {
55
63
  }
56
64
 
57
65
  export function createAgentLockModule(
58
- _bridge: Bridge,
66
+ bridge: Bridge,
59
67
  userConfig: AgentLockConfig = {},
60
68
  ): AgentLockModule {
61
69
  const cfg: Required<AgentLockConfig> = { ...DEFAULT_CONFIG, ...userConfig };
@@ -65,6 +73,12 @@ export function createAgentLockModule(
65
73
  let overlayEl: HTMLDivElement | null = null;
66
74
  let locked = false;
67
75
  let lockCount = 0;
76
+ /**
77
+ * True while an agent *turn* is in progress (driven by the host's
78
+ * {@link TURN_EVENT}). Keeps the overlay up across the whole response — and
79
+ * across the gaps between individual tool calls — until the turn ends.
80
+ */
81
+ let turnActive = false;
68
82
  let timeoutTimer: ReturnType<typeof setTimeout> | null = null;
69
83
  let debounceTimer: ReturnType<typeof setTimeout> | null = null;
70
84
  let currentMessage = cfg.message;
@@ -181,6 +195,7 @@ export function createAgentLockModule(
181
195
  if (!locked) return;
182
196
  locked = false;
183
197
  lockCount = 0;
198
+ turnActive = false;
184
199
  clearTimeoutTimer();
185
200
  clearDebounceTimer();
186
201
  if (cfg.mode === 'overlay') {
@@ -189,12 +204,51 @@ export function createAgentLockModule(
189
204
  emit('unlock', { requestId });
190
205
  }
191
206
 
207
+ /**
208
+ * Release the lock only when nothing is still holding it — i.e. no agent turn
209
+ * is in progress and no tool execution is outstanding. This is what keeps the
210
+ * overlay from flickering off between tools or mid-turn.
211
+ */
212
+ function maybeUnlock(requestId?: string): void {
213
+ if (turnActive || lockCount > 0) return;
214
+ forceUnlock(requestId);
215
+ }
216
+
217
+ function scheduleDebouncedUnlock(requestId?: string): void {
218
+ clearDebounceTimer();
219
+ debounceTimer = setTimeout(() => maybeUnlock(requestId), cfg.debounceUnlock);
220
+ }
221
+
192
222
  function handleCancel(): void {
193
223
  const rid = undefined; // auto mode tracks this externally
224
+ // Explicit user cancel wins over any in-progress turn/tool tracking.
194
225
  forceUnlock(rid);
195
226
  emit('cancel', { requestId: rid });
196
227
  }
197
228
 
229
+ /**
230
+ * Turn-level lock driven by the host (see {@link TURN_EVENT}). Holds the
231
+ * overlay for the entire agent response; tool-level auto lock/unlock nests
232
+ * inside without tearing the overlay down.
233
+ */
234
+ function setTurn(active: boolean): void {
235
+ if (!cfg.enabled) return;
236
+ if (active) {
237
+ turnActive = true;
238
+ clearDebounceTimer();
239
+ if (!locked) {
240
+ doLock(cfg.message, cfg.turnTimeout);
241
+ } else {
242
+ // Already locked by a tool — extend its timeout to the (longer) turn
243
+ // budget so a 30s tool timeout can't drop the overlay mid-turn.
244
+ startTimeout(cfg.turnTimeout);
245
+ }
246
+ } else {
247
+ turnActive = false;
248
+ if (lockCount === 0) scheduleDebouncedUnlock();
249
+ }
250
+ }
251
+
198
252
  // Public API -----------------------------------------------------------------
199
253
 
200
254
  function lock(opts?: { message?: string; timeout?: number }): void {
@@ -229,7 +283,9 @@ export function createAgentLockModule(
229
283
  clearDebounceTimer();
230
284
  lockCount++;
231
285
  if (!locked) {
232
- doLock(cfg.message, cfg.timeout, requestId);
286
+ // Inside a turn the (longer) turn budget governs; standalone tool calls
287
+ // keep the per-tool timeout.
288
+ doLock(cfg.message, turnActive ? cfg.turnTimeout : cfg.timeout, requestId);
233
289
  }
234
290
  }
235
291
 
@@ -237,19 +293,21 @@ export function createAgentLockModule(
237
293
  if (!cfg.enabled) return;
238
294
  lockCount = Math.max(0, lockCount - 1);
239
295
  if (lockCount === 0) {
240
- clearDebounceTimer();
241
- debounceTimer = setTimeout(() => {
242
- if (lockCount === 0) {
243
- forceUnlock(requestId);
244
- }
245
- }, cfg.debounceUnlock);
296
+ scheduleDebouncedUnlock(requestId);
246
297
  }
247
298
  }
248
299
 
249
300
  function _destroy(): void {
301
+ if (removeTurnListener) removeTurnListener();
250
302
  forceUnlock();
251
303
  listeners.clear();
252
304
  }
253
305
 
306
+ // Listen for host-driven turn lock/unlock. Payload shape: `{ active: boolean }`.
307
+ const removeTurnListener = bridge.addEventListener(TURN_EVENT, (data) => {
308
+ const active = !!(data as { active?: unknown } | undefined)?.active;
309
+ setTurn(active);
310
+ });
311
+
254
312
  return { lock, unlock, isLocked, on, off, _autoLock, _autoUnlock, _destroy };
255
313
  }
package/src/types.ts CHANGED
@@ -354,8 +354,15 @@ export interface AgentLockConfig {
354
354
  allowCancel?: boolean;
355
355
  /** Overlay background opacity, 0–1 (default: 0.3). */
356
356
  opacity?: number;
357
- /** Auto-unlock timeout in ms (default: 30000). 0 disables. */
357
+ /** Auto-unlock timeout for a single tool execution, in ms (default: 30000). 0 disables. */
358
358
  timeout?: number;
359
+ /**
360
+ * Safety auto-unlock timeout for a whole agent turn, in ms (default: 0 =
361
+ * disabled, rely on the host's turn-end signal). When the host drives a
362
+ * turn-level lock (the lock spans the entire agent response, not just one
363
+ * tool), this acts purely as a fallback in case the turn-end signal is lost.
364
+ */
365
+ turnTimeout?: number;
359
366
  /** Delay before actually removing the overlay after unlock, to avoid flicker between consecutive tools (default: 200ms). */
360
367
  debounceUnlock?: number;
361
368
  }