@syntrologie/adapt-chatbot 2.8.0-canary.576 → 2.8.0-canary.577

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.
@@ -1 +1 @@
1
- {"version":3,"file":"hostAgentController.d.ts","sourceRoot":"","sources":["../src/hostAgentController.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC9B,oBAAoB,CAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,EACnC,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACjC,MAAM,IAAI,CAAC;IACd;;;;;;OAMG;IACH,cAAc,CAAC,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAClG;AAiBD,UAAU,oBAAoB;IAC5B,cAAc,CAAC,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7C;AA4ID,oFAAoF;AACpF,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,oBAAoB;4BAiGE,OAAO,KAAG,IAAI;gCAgEJ,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;;;EA+BjE;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CA4D5E;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAC1B,OAAO,EAAE;IAAE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,EACtD,OAAO,EAAE,OAAO,GACf,IAAI,CAEN"}
1
+ {"version":3,"file":"hostAgentController.d.ts","sourceRoot":"","sources":["../src/hostAgentController.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC9B,oBAAoB,CAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,EACnC,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACjC,MAAM,IAAI,CAAC;IACd;;;;;;OAMG;IACH,cAAc,CAAC,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAClG;AA8ED,UAAU,oBAAoB;IAC5B,cAAc,CAAC,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7C;AA4ID,oFAAoF;AACpF,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,oBAAoB;4BA4QE,OAAO,KAAG,IAAI;gCAgEJ,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;;;EAmCjE;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CA4D5E;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAC1B,OAAO,EAAE;IAAE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,EACtD,OAAO,EAAE,OAAO,GACf,IAAI,CAEN"}
package/dist/runtime.js CHANGED
@@ -3479,6 +3479,18 @@ var AdaptiveChipsStripMountable = {
3479
3479
 
3480
3480
  // src/hostAgentController.ts
3481
3481
  var READ_TOOL = "read_brand_view";
3482
+ var CARD_HEARTBEAT_PREFIX = "syntro:mcp-card:";
3483
+ var heartbeatPrefix = (sessionRef) => `${CARD_HEARTBEAT_PREFIX}${sessionRef}:`;
3484
+ var CARD_HEARTBEAT_INTERVAL_MS = 2e3;
3485
+ var CARD_SIBLING_WINDOW_MS = 6e3;
3486
+ var CARD_HEARTBEAT_STALE_MS = 6e4;
3487
+ function cardStorage() {
3488
+ try {
3489
+ return globalThis.localStorage ?? void 0;
3490
+ } catch {
3491
+ return void 0;
3492
+ }
3493
+ }
3482
3494
  var interactionOwners = /* @__PURE__ */ new WeakMap();
3483
3495
  function hostUiSubscription(value) {
3484
3496
  return record(value) && typeof value.subscribeHostUi === "function";
@@ -3549,6 +3561,135 @@ function activateHostAgentController(runtime2, bridge, hostUi) {
3549
3561
  let stopObserver;
3550
3562
  let readRequested = false;
3551
3563
  let applied = 0;
3564
+ const cardId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
3565
+ let heartbeatKey;
3566
+ let heartbeatTimer;
3567
+ let popOutDecided = false;
3568
+ function hostSurface() {
3569
+ try {
3570
+ return runtime2.context?.get().surface ?? {};
3571
+ } catch {
3572
+ return {};
3573
+ }
3574
+ }
3575
+ function readHeartbeat(key) {
3576
+ try {
3577
+ const raw = cardStorage()?.getItem(key);
3578
+ if (!raw) return;
3579
+ const parsed = JSON.parse(raw);
3580
+ if (!record(parsed) || !nonempty(parsed.id) || typeof parsed.ts !== "number") return;
3581
+ return {
3582
+ id: parsed.id,
3583
+ ts: parsed.ts,
3584
+ mode: typeof parsed.mode === "string" ? parsed.mode : void 0
3585
+ };
3586
+ } catch {
3587
+ return;
3588
+ }
3589
+ }
3590
+ function writeHeartbeat() {
3591
+ if (!heartbeatKey) return;
3592
+ try {
3593
+ cardStorage()?.setItem(
3594
+ heartbeatKey,
3595
+ JSON.stringify({ id: cardId, ts: Date.now(), mode: hostSurface().displayMode })
3596
+ );
3597
+ } catch {
3598
+ }
3599
+ }
3600
+ function pruneHeartbeats() {
3601
+ try {
3602
+ const store = cardStorage();
3603
+ if (!store) return;
3604
+ const stale = [];
3605
+ for (let index = 0; index < store.length; index++) {
3606
+ const key = store.key(index);
3607
+ if (!key?.startsWith(CARD_HEARTBEAT_PREFIX) || key === heartbeatKey) continue;
3608
+ const beat = readHeartbeat(key);
3609
+ if (!beat || Date.now() - beat.ts > CARD_HEARTBEAT_STALE_MS) stale.push(key);
3610
+ }
3611
+ for (const key of stale) store.removeItem(key);
3612
+ } catch {
3613
+ }
3614
+ }
3615
+ const releaseHeartbeat = () => stopHeartbeat();
3616
+ const onVisibilityChange = () => {
3617
+ if (!heartbeatKey) return;
3618
+ if (document.visibilityState === "hidden") {
3619
+ if (heartbeatTimer !== void 0) {
3620
+ clearInterval(heartbeatTimer);
3621
+ heartbeatTimer = void 0;
3622
+ }
3623
+ return;
3624
+ }
3625
+ if (heartbeatTimer !== void 0) return;
3626
+ writeHeartbeat();
3627
+ heartbeatTimer = setInterval(writeHeartbeat, CARD_HEARTBEAT_INTERVAL_MS);
3628
+ };
3629
+ function startHeartbeat(sessionRef) {
3630
+ const key = heartbeatPrefix(sessionRef) + cardId;
3631
+ if (heartbeatKey === key) return;
3632
+ if (heartbeatKey) stopHeartbeat();
3633
+ heartbeatKey = key;
3634
+ pruneHeartbeats();
3635
+ writeHeartbeat();
3636
+ heartbeatTimer = setInterval(writeHeartbeat, CARD_HEARTBEAT_INTERVAL_MS);
3637
+ if (typeof window !== "undefined") {
3638
+ window.addEventListener("pagehide", releaseHeartbeat);
3639
+ window.addEventListener("beforeunload", releaseHeartbeat);
3640
+ }
3641
+ if (typeof document !== "undefined")
3642
+ document.addEventListener("visibilitychange", onVisibilityChange);
3643
+ }
3644
+ function stopHeartbeat() {
3645
+ if (heartbeatTimer !== void 0) {
3646
+ clearInterval(heartbeatTimer);
3647
+ heartbeatTimer = void 0;
3648
+ }
3649
+ const key = heartbeatKey;
3650
+ heartbeatKey = void 0;
3651
+ if (typeof window !== "undefined") {
3652
+ window.removeEventListener("pagehide", releaseHeartbeat);
3653
+ window.removeEventListener("beforeunload", releaseHeartbeat);
3654
+ }
3655
+ if (typeof document !== "undefined")
3656
+ document.removeEventListener("visibilitychange", onVisibilityChange);
3657
+ if (!key) return;
3658
+ try {
3659
+ cardStorage()?.removeItem(key);
3660
+ } catch {
3661
+ }
3662
+ }
3663
+ function freshSiblings(sessionRef) {
3664
+ const siblings = [];
3665
+ try {
3666
+ const store = cardStorage();
3667
+ if (!store) return siblings;
3668
+ const prefix = heartbeatPrefix(sessionRef);
3669
+ for (let index = 0; index < store.length; index++) {
3670
+ const key = store.key(index);
3671
+ if (!key?.startsWith(prefix)) continue;
3672
+ const beat = readHeartbeat(key);
3673
+ if (!beat || beat.id === cardId) continue;
3674
+ if (Date.now() - beat.ts > CARD_SIBLING_WINDOW_MS) continue;
3675
+ siblings.push(beat);
3676
+ }
3677
+ } catch {
3678
+ return siblings;
3679
+ }
3680
+ return siblings;
3681
+ }
3682
+ function considerPopOut(sessionRef) {
3683
+ if (popOutDecided) return;
3684
+ popOutDecided = true;
3685
+ const siblings = freshSiblings(sessionRef);
3686
+ if (siblings.length === 0) return;
3687
+ if (siblings.some((beat) => beat.mode !== "inline")) return;
3688
+ const surface = hostSurface();
3689
+ if (surface.type !== "mcp-app" || surface.displayMode !== "inline") return;
3690
+ if (!surface.availableDisplayModes?.includes("pip")) return;
3691
+ runtime2.events.publish("canvas:request-display-mode", { mode: "pip" });
3692
+ }
3552
3693
  let interactiveState;
3553
3694
  function interactive(value) {
3554
3695
  if (disposed || interactiveState === value) return;
@@ -3636,8 +3777,10 @@ function activateHostAgentController(runtime2, bridge, hostUi) {
3636
3777
  if (disposed) return;
3637
3778
  const turn = decodeAgentTurn(result);
3638
3779
  if (!turn) return;
3780
+ considerPopOut(turn.session.session_ref);
3639
3781
  acceptHostUi2({ kind: "session", session: turn.session });
3640
3782
  acceptHostUi2({ kind: "frame", frame: turn.frame });
3783
+ startHeartbeat(turn.session.session_ref);
3641
3784
  }
3642
3785
  const deliver = (result) => {
3643
3786
  void consumeToolResult(result);
@@ -3656,6 +3799,7 @@ function activateHostAgentController(runtime2, bridge, hostUi) {
3656
3799
  if (disposed) return;
3657
3800
  disposed = true;
3658
3801
  generation++;
3802
+ stopHeartbeat();
3659
3803
  stopObserver?.();
3660
3804
  stopObserver = void 0;
3661
3805
  unsubscribe();