@syntrologie/adapt-chatbot 2.55.0 → 2.56.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/AdaptiveChatBar.d.ts +18 -0
- package/dist/AdaptiveChatBar.d.ts.map +1 -1
- package/dist/AdaptiveChatBar.interleave.test.d.ts +9 -0
- package/dist/AdaptiveChatBar.interleave.test.d.ts.map +1 -0
- package/dist/AdaptiveChatBar.js +4 -4
- package/dist/AdaptiveChatBarMountable.d.ts +28 -17
- package/dist/AdaptiveChatBarMountable.d.ts.map +1 -1
- package/dist/AdaptiveChatTrail.js +3 -3
- package/dist/AdaptiveChipsStrip.d.ts +20 -20
- package/dist/AdaptiveChipsStrip.js +3 -3
- package/dist/ChatAssistantLit.d.ts +5 -3
- package/dist/ChatAssistantLit.d.ts.map +1 -1
- package/dist/ChatAssistantLit.js +5 -4
- package/dist/ChatTransport.d.ts +10 -5
- package/dist/ChatTransport.d.ts.map +1 -1
- package/dist/Turnstile.d.ts +18 -0
- package/dist/Turnstile.d.ts.map +1 -1
- package/dist/cdn.d.ts +1 -0
- package/dist/cdn.d.ts.map +1 -1
- package/dist/chunk-23E6WZOO.js +882 -0
- package/dist/chunk-23E6WZOO.js.map +7 -0
- package/dist/{chunk-57MPLQOL.js → chunk-7QXC475Y.js} +400 -935
- package/dist/{chunk-57MPLQOL.js.map → chunk-7QXC475Y.js.map} +4 -4
- package/dist/{chunk-TZA7572J.js → chunk-GN7Z5IVP.js} +2 -2
- package/dist/chunk-LY5AGXVD.js +21 -0
- package/dist/{chunk-ETDHHQS3.js → chunk-NMYFYMJI.js} +12 -12
- package/dist/{chunk-ETDHHQS3.js.map → chunk-NMYFYMJI.js.map} +1 -1
- package/dist/{chunk-LJEPZI6Y.js → chunk-WQIDXGGS.js} +2 -2
- package/dist/{chunk-VFWA5W56.js → chunk-XPUHW2YO.js} +44 -7
- package/dist/chunk-XPUHW2YO.js.map +7 -0
- package/dist/chunk-Z3YR4JFE.js +4702 -0
- package/dist/chunk-Z3YR4JFE.js.map +7 -0
- package/dist/editor-lit.js +1 -1
- package/dist/element-session.d.ts +3 -0
- package/dist/element-session.d.ts.map +1 -0
- package/dist/element-session.js +9 -0
- package/dist/element-session.js.map +7 -0
- package/dist/elements/ElementInstanceStore.d.ts +15 -1
- package/dist/elements/ElementInstanceStore.d.ts.map +1 -1
- package/dist/elements/ElementSessionController.d.ts +37 -0
- package/dist/elements/ElementSessionController.d.ts.map +1 -0
- package/dist/elements/ElementSessionController.test.d.ts +2 -0
- package/dist/elements/ElementSessionController.test.d.ts.map +1 -0
- package/dist/elements/TileHandler.d.ts.map +1 -1
- package/dist/elements/createElementStore.d.ts +11 -0
- package/dist/elements/createElementStore.d.ts.map +1 -0
- package/dist/elements/tileLifecycleProps.d.ts +13 -0
- package/dist/elements/tileLifecycleProps.d.ts.map +1 -0
- package/dist/elements/types.d.ts +7 -0
- package/dist/elements/types.d.ts.map +1 -1
- package/dist/hostAgentController.d.ts +65 -0
- package/dist/hostAgentController.d.ts.map +1 -0
- package/dist/hostAgentController.test.d.ts +2 -0
- package/dist/hostAgentController.test.d.ts.map +1 -0
- package/dist/observer/wire.d.ts +54 -0
- package/dist/observer/wire.d.ts.map +1 -0
- package/dist/observer/wire.test.d.ts +2 -0
- package/dist/observer/wire.test.d.ts.map +1 -0
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +832 -172
- package/dist/runtime.js.map +4 -4
- package/dist/schema.d.ts +66 -66
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +75 -76
- package/dist/schema.js.map +3 -3
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -7
- package/dist/chunk-NGV35N4T.js +0 -474
- package/dist/chunk-NGV35N4T.js.map +0 -7
- package/dist/chunk-UVKRO5ER.js +0 -13
- package/dist/chunk-VFWA5W56.js.map +0 -7
- /package/dist/{chunk-TZA7572J.js.map → chunk-GN7Z5IVP.js.map} +0 -0
- /package/dist/{chunk-UVKRO5ER.js.map → chunk-LY5AGXVD.js.map} +0 -0
- /package/dist/{chunk-LJEPZI6Y.js.map → chunk-WQIDXGGS.js.map} +0 -0
package/dist/runtime.js
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ActionHandler,
|
|
3
2
|
AgUiTransport,
|
|
4
3
|
ChatAssistantLitMountable,
|
|
5
|
-
|
|
6
|
-
ItemHandler,
|
|
7
|
-
TileHandler,
|
|
8
|
-
acquireTokenWithChallenge,
|
|
4
|
+
acquireBotCheckTokenForSend,
|
|
9
5
|
decodeMutationEnvelope,
|
|
10
6
|
fetchMountedElements,
|
|
11
7
|
renderFallbackHtml
|
|
12
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-7QXC475Y.js";
|
|
9
|
+
import {
|
|
10
|
+
ElementInstanceStore,
|
|
11
|
+
TileHandler,
|
|
12
|
+
createElementSessionController,
|
|
13
|
+
createTemplateWidgetResolver
|
|
14
|
+
} from "./chunk-23E6WZOO.js";
|
|
13
15
|
import {
|
|
14
16
|
pickPersona
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-XPUHW2YO.js";
|
|
16
18
|
import {
|
|
17
19
|
getElementInstanceStore,
|
|
18
20
|
setElementInstanceStore
|
|
19
21
|
} from "./chunk-EWPPVPJ4.js";
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-WQIDXGGS.js";
|
|
23
|
+
import "./chunk-GN7Z5IVP.js";
|
|
24
|
+
import "./chunk-NMYFYMJI.js";
|
|
23
25
|
import {
|
|
24
26
|
DIVE_DEEPER_EVENT,
|
|
25
27
|
TELEMETRY_DOM_EVENT,
|
|
26
28
|
TILE_MOUNTED_EVENT,
|
|
27
29
|
TILE_UNMOUNTED_EVENT,
|
|
28
30
|
isCanonicalBusEvent,
|
|
31
|
+
reportCardStage,
|
|
29
32
|
stripMountPlumbing
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
import "./chunk-
|
|
33
|
+
} from "./chunk-Z3YR4JFE.js";
|
|
34
|
+
import "./chunk-LY5AGXVD.js";
|
|
32
35
|
|
|
33
36
|
// src/ChatSession.ts
|
|
34
37
|
var _userIdCounter = 0;
|
|
@@ -540,6 +543,9 @@ var ChatTransport = class {
|
|
|
540
543
|
this._firstDeltaAt = null;
|
|
541
544
|
this._runMounts = 0;
|
|
542
545
|
this._runCards = 0;
|
|
546
|
+
/** The mount_* tool of every mount this run fired, in order — which surfaces
|
|
547
|
+
* the concierge chose (a carousel on one turn, separate cards on another). */
|
|
548
|
+
this._runMountTools = [];
|
|
543
549
|
/**
|
|
544
550
|
* Count of RUN_FINISHED events the server still owes us that must be
|
|
545
551
|
* swallowed, not reported — one per interrupt. NOT a boolean: an
|
|
@@ -723,6 +729,7 @@ var ChatTransport = class {
|
|
|
723
729
|
this._firstDeltaAt = null;
|
|
724
730
|
this._runMounts = 0;
|
|
725
731
|
this._runCards = 0;
|
|
732
|
+
this._runMountTools = [];
|
|
726
733
|
this._pendingSuppressedFinishes = 0;
|
|
727
734
|
}
|
|
728
735
|
/**
|
|
@@ -745,9 +752,6 @@ var ChatTransport = class {
|
|
|
745
752
|
const headers2 = {};
|
|
746
753
|
const token = readRuntimeToken(this._config?.runtime);
|
|
747
754
|
if (token) headers2.Authorization = `Bearer ${token}`;
|
|
748
|
-
const cft = await this._acquireTurnstileWithChallenge();
|
|
749
|
-
if (cft) headers2["CF-Turnstile-Token"] = cft;
|
|
750
|
-
if (abort.signal.aborted) return;
|
|
751
755
|
const readIds = () => {
|
|
752
756
|
try {
|
|
753
757
|
const rt = this._config?.runtime;
|
|
@@ -987,6 +991,7 @@ var ChatTransport = class {
|
|
|
987
991
|
this._firstDeltaAt = null;
|
|
988
992
|
this._runMounts = 0;
|
|
989
993
|
this._runCards = 0;
|
|
994
|
+
this._runMountTools = [];
|
|
990
995
|
this._reportAtom("syntro_chat_message_sent", { turn, chars: text.length, via });
|
|
991
996
|
void this._forwardUserMessage(text, id);
|
|
992
997
|
}
|
|
@@ -1093,6 +1098,23 @@ var ChatTransport = class {
|
|
|
1093
1098
|
if (!runtime2) return;
|
|
1094
1099
|
const mutations = decodeMutationEnvelope(payload);
|
|
1095
1100
|
if (mutations !== null) {
|
|
1101
|
+
const config = this._config;
|
|
1102
|
+
if (config?.onElementEnvelope) {
|
|
1103
|
+
void config.onElementEnvelope({
|
|
1104
|
+
type: "syntro.element.mutation",
|
|
1105
|
+
schema_version: "v0",
|
|
1106
|
+
mutations
|
|
1107
|
+
}).then(() => {
|
|
1108
|
+
if (this._config === config)
|
|
1109
|
+
runtime2.events.publish("chatbot.element_mutation_applied", {
|
|
1110
|
+
source: "chat-transport",
|
|
1111
|
+
count: mutations.length
|
|
1112
|
+
});
|
|
1113
|
+
}).catch(() => {
|
|
1114
|
+
console.error("[chat-transport] element mutation apply failed");
|
|
1115
|
+
});
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1096
1118
|
const handler = this._config?.onElementMutation;
|
|
1097
1119
|
if (handler) {
|
|
1098
1120
|
try {
|
|
@@ -1129,13 +1151,15 @@ var ChatTransport = class {
|
|
|
1129
1151
|
}
|
|
1130
1152
|
}
|
|
1131
1153
|
/**
|
|
1132
|
-
* Acquire a Turnstile token
|
|
1133
|
-
*
|
|
1134
|
-
*
|
|
1135
|
-
*
|
|
1154
|
+
* Acquire a Turnstile token for a visitor send. Only reached from
|
|
1155
|
+
* `_ensureConnected`, i.e. on interaction. Returns null without touching
|
|
1156
|
+
* Cloudflare when the build has no sitekey or the backend does not enforce
|
|
1157
|
+
* the check; null also when acquisition fails.
|
|
1136
1158
|
*/
|
|
1137
1159
|
async _acquireTurnstileWithChallenge() {
|
|
1138
|
-
|
|
1160
|
+
if (!this._config) return null;
|
|
1161
|
+
const backendUrl = this._config.backendUrl.replace(/\/$/, "");
|
|
1162
|
+
const { token } = await acquireBotCheckTokenForSend(backendUrl);
|
|
1139
1163
|
return token;
|
|
1140
1164
|
}
|
|
1141
1165
|
// -------------------------------------------------------------------------
|
|
@@ -1309,6 +1333,7 @@ var ChatTransport = class {
|
|
|
1309
1333
|
if (!existing && event.toolCall.name.startsWith("mount_")) {
|
|
1310
1334
|
this._runMounts += 1;
|
|
1311
1335
|
if (/card/i.test(event.toolCall.name)) this._runCards += 1;
|
|
1336
|
+
this._runMountTools.push(event.toolCall.name);
|
|
1312
1337
|
}
|
|
1313
1338
|
if (!existing) {
|
|
1314
1339
|
this._startThinkingCycle(toolNarrationVariants(event.toolCall.name));
|
|
@@ -1406,7 +1431,8 @@ var ChatTransport = class {
|
|
|
1406
1431
|
ttft_ms: (this._firstDeltaAt ?? end) - this._runStartedAt,
|
|
1407
1432
|
total_ms: end - this._runStartedAt,
|
|
1408
1433
|
mounts: this._runMounts,
|
|
1409
|
-
cards: this._runCards
|
|
1434
|
+
cards: this._runCards,
|
|
1435
|
+
mount_tools: [...this._runMountTools]
|
|
1410
1436
|
});
|
|
1411
1437
|
}
|
|
1412
1438
|
this._runStartedAt = 0;
|
|
@@ -1440,6 +1466,38 @@ function findSmartCanvas() {
|
|
|
1440
1466
|
return find(document);
|
|
1441
1467
|
}
|
|
1442
1468
|
|
|
1469
|
+
// src/observer/bus-translate.ts
|
|
1470
|
+
function eventTypeFromName(name) {
|
|
1471
|
+
switch (name) {
|
|
1472
|
+
case "ui.click":
|
|
1473
|
+
return "click";
|
|
1474
|
+
case "ui.submit":
|
|
1475
|
+
return "submit";
|
|
1476
|
+
case "ui.change":
|
|
1477
|
+
return "change";
|
|
1478
|
+
default:
|
|
1479
|
+
return void 0;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
function busEventToRawEvent(e) {
|
|
1483
|
+
if (!e?.name) return null;
|
|
1484
|
+
const ts = typeof e.ts === "number" ? e.ts : Date.now();
|
|
1485
|
+
if (e.source === "posthog") {
|
|
1486
|
+
const original = e.props?.originalEvent;
|
|
1487
|
+
if (typeof original !== "string" || original.length === 0) return null;
|
|
1488
|
+
const src = e.props ?? {};
|
|
1489
|
+
const properties = { ...src };
|
|
1490
|
+
if (Array.isArray(src.elements)) properties.$elements = src.elements;
|
|
1491
|
+
if (typeof src.tagName === "string") properties.$element_tag_name = src.tagName;
|
|
1492
|
+
if (typeof src.pathname === "string") properties.$pathname = src.pathname;
|
|
1493
|
+
if (typeof src.url === "string") properties.$current_url = src.url;
|
|
1494
|
+
const eventType = eventTypeFromName(e.name);
|
|
1495
|
+
if (eventType) properties.$event_type = eventType;
|
|
1496
|
+
return { event: original, timestamp: ts, properties };
|
|
1497
|
+
}
|
|
1498
|
+
return { event: e.name, timestamp: ts, properties: { ...e.props ?? {} } };
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1443
1501
|
// src/observer/allowlist.ts
|
|
1444
1502
|
var MAX_TEXT_LEN = 200;
|
|
1445
1503
|
var SIGNIFICANT_CLICK_TAGS = /* @__PURE__ */ new Set(["button", "a"]);
|
|
@@ -1942,36 +2000,74 @@ function _makeHandle(owner) {
|
|
|
1942
2000
|
};
|
|
1943
2001
|
}
|
|
1944
2002
|
|
|
1945
|
-
// src/observer/
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
return
|
|
1954
|
-
|
|
1955
|
-
return
|
|
1956
|
-
|
|
2003
|
+
// src/observer/wire.ts
|
|
2004
|
+
var PAGE_LEVEL_KINDS = /* @__PURE__ */ new Set(["view", "scroll", "idle", "hesitation", "hover", "nav"]);
|
|
2005
|
+
function buildObserverEnrich(runtimeRef) {
|
|
2006
|
+
return (ev, raw) => {
|
|
2007
|
+
const extract = runtimeRef.getProductIdentity;
|
|
2008
|
+
if (typeof extract !== "function") return ev;
|
|
2009
|
+
if (ev.kind === "click") {
|
|
2010
|
+
const chain = raw.properties.$elements;
|
|
2011
|
+
if (!Array.isArray(chain)) return ev;
|
|
2012
|
+
const id = extract(chain);
|
|
2013
|
+
if (!id) return ev;
|
|
2014
|
+
return {
|
|
2015
|
+
...ev,
|
|
2016
|
+
product: {
|
|
2017
|
+
handle: id.productHandle,
|
|
2018
|
+
url: id.productUrl,
|
|
2019
|
+
...id.productTitle ? { title: id.productTitle } : {}
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
if (!ev.product && PAGE_LEVEL_KINDS.has(ev.kind) && typeof location !== "undefined") {
|
|
2024
|
+
const id = extract([{ href: location.pathname }]);
|
|
2025
|
+
if (!id) return ev;
|
|
2026
|
+
return {
|
|
2027
|
+
...ev,
|
|
2028
|
+
product: {
|
|
2029
|
+
handle: id.productHandle,
|
|
2030
|
+
url: id.productUrl,
|
|
2031
|
+
...id.productTitle ? { title: id.productTitle } : {}
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
return ev;
|
|
2036
|
+
};
|
|
1957
2037
|
}
|
|
1958
|
-
function
|
|
1959
|
-
if (!
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
2038
|
+
function wireObserver(runtime2) {
|
|
2039
|
+
if (typeof window === "undefined" || !runtime2?.events?.subscribe) return () => {
|
|
2040
|
+
};
|
|
2041
|
+
const trimmed = (runtime2.backendUrl ?? "").replace(/\/$/, "");
|
|
2042
|
+
const url = trimmed ? `${trimmed}/api/adaptive/observation` : "/api/adaptive/observation";
|
|
2043
|
+
const runtimeId = (method) => {
|
|
2044
|
+
try {
|
|
2045
|
+
const value = runtime2.telemetry?.[method]?.();
|
|
2046
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
2047
|
+
} catch {
|
|
2048
|
+
return null;
|
|
2049
|
+
}
|
|
2050
|
+
};
|
|
2051
|
+
const token = () => typeof runtime2.token === "string" ? runtime2.token : "";
|
|
2052
|
+
const handle = startObserver({
|
|
2053
|
+
url,
|
|
2054
|
+
token,
|
|
2055
|
+
getDistinctId: () => runtimeId("getDistinctId"),
|
|
2056
|
+
getSessionId: () => runtimeId("getSessionId"),
|
|
2057
|
+
enrich: buildObserverEnrich(runtime2)
|
|
2058
|
+
});
|
|
2059
|
+
window.__syntroObserverStats = () => handle.stats();
|
|
2060
|
+
const unsubscribe = runtime2.events.subscribe({}, (event) => {
|
|
2061
|
+
const raw = busEventToRawEvent(event);
|
|
2062
|
+
if (raw) handle.ingest(raw);
|
|
2063
|
+
});
|
|
2064
|
+
let stopped = false;
|
|
2065
|
+
return () => {
|
|
2066
|
+
if (stopped) return;
|
|
2067
|
+
stopped = true;
|
|
2068
|
+
unsubscribe();
|
|
2069
|
+
handle.stop();
|
|
2070
|
+
};
|
|
1975
2071
|
}
|
|
1976
2072
|
|
|
1977
2073
|
// src/support-chat/registry.ts
|
|
@@ -3067,106 +3163,41 @@ function applyPlaceholder(bar, cfg2) {
|
|
|
3067
3163
|
if (typeof cfg2.maximized === "boolean") {
|
|
3068
3164
|
bar.maximized = cfg2.maximized;
|
|
3069
3165
|
}
|
|
3166
|
+
if (cfg2.chatControl !== void 0) bar.chatControl = cfg2.chatControl;
|
|
3167
|
+
if (typeof cfg2.interleaved === "boolean") bar.interleaved = cfg2.interleaved;
|
|
3070
3168
|
}
|
|
3071
|
-
var
|
|
3072
|
-
var
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
}
|
|
3077
|
-
function
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
if (!uiTemplates) return;
|
|
3083
|
-
const tiles = uiTemplates.tiles;
|
|
3084
|
-
if (!Array.isArray(tiles)) return;
|
|
3085
|
-
for (const t of tiles) {
|
|
3086
|
-
const id = typeof t?.id === "string" ? t.id : null;
|
|
3087
|
-
const widget = typeof t?.widget === "string" ? t.widget : null;
|
|
3088
|
-
if (id && widget) _templateWidgetMap.set(id, widget);
|
|
3089
|
-
}
|
|
3090
|
-
}
|
|
3091
|
-
function getOrCreateElementStore(runtime2) {
|
|
3092
|
-
if (_elementStore) return _elementStore;
|
|
3093
|
-
_elementStore = new ElementInstanceStore({
|
|
3094
|
-
actions: runtime2.actions,
|
|
3095
|
-
// Pass the runtime's event bus so ItemHandler can broadcast
|
|
3096
|
-
// `element.compositional_append` / `_patch` / `_remove` events
|
|
3097
|
-
// to container widgets (chips strip, FAQ accordion, nav tips).
|
|
3098
|
-
events: {
|
|
3099
|
-
publish: runtime2.events.publish.bind(runtime2.events),
|
|
3100
|
-
subscribe: runtime2.events.subscribe?.bind(runtime2.events)
|
|
3101
|
-
},
|
|
3102
|
-
handlers: [new TileHandler(resolveTileWidget), new ActionHandler(), new ItemHandler()],
|
|
3103
|
-
resolveTileWidget
|
|
3104
|
-
});
|
|
3105
|
-
setElementInstanceStore(_elementStore);
|
|
3106
|
-
return _elementStore;
|
|
3169
|
+
var _elementSession = null;
|
|
3170
|
+
var _pendingTemplates;
|
|
3171
|
+
function refreshTemplateWidgetMap(templates) {
|
|
3172
|
+
_pendingTemplates = templates;
|
|
3173
|
+
_elementSession?.configureTemplates(templates);
|
|
3174
|
+
}
|
|
3175
|
+
function getOrCreateElementSession(runtime2) {
|
|
3176
|
+
if (_elementSession) return _elementSession;
|
|
3177
|
+
_elementSession = createElementSessionController({ ...runtime2, templates: _pendingTemplates });
|
|
3178
|
+
setElementInstanceStore(_elementSession.store);
|
|
3179
|
+
return _elementSession;
|
|
3107
3180
|
}
|
|
3108
|
-
var _hydrationStarted = false;
|
|
3109
3181
|
function hydrateOnce(runtime2, backendUrl) {
|
|
3110
|
-
|
|
3111
|
-
_hydrationStarted = true;
|
|
3112
|
-
const store = getOrCreateElementStore(runtime2);
|
|
3182
|
+
const session = getOrCreateElementSession(runtime2);
|
|
3113
3183
|
const trimmed = backendUrl.replace(/\/$/, "");
|
|
3114
3184
|
const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
|
|
3115
|
-
fetchMountedElements({ endpoint, token: runtime2.token })
|
|
3116
|
-
if (!response) return;
|
|
3117
|
-
void store.hydrate(response.mounted_elements);
|
|
3118
|
-
});
|
|
3119
|
-
}
|
|
3120
|
-
var PAGE_LEVEL_KINDS = /* @__PURE__ */ new Set(["view", "scroll", "idle", "hesitation", "hover", "nav"]);
|
|
3121
|
-
function buildObserverEnrich(runtimeRef) {
|
|
3122
|
-
return (ev, raw) => {
|
|
3123
|
-
const extract = runtimeRef.getProductIdentity;
|
|
3124
|
-
if (typeof extract !== "function") return ev;
|
|
3125
|
-
if (ev.kind === "click") {
|
|
3126
|
-
const chain = raw.properties.$elements;
|
|
3127
|
-
if (!Array.isArray(chain)) return ev;
|
|
3128
|
-
const id = extract(chain);
|
|
3129
|
-
if (!id) return ev;
|
|
3130
|
-
return {
|
|
3131
|
-
...ev,
|
|
3132
|
-
product: {
|
|
3133
|
-
handle: id.productHandle,
|
|
3134
|
-
url: id.productUrl,
|
|
3135
|
-
...id.productTitle ? { title: id.productTitle } : {}
|
|
3136
|
-
}
|
|
3137
|
-
};
|
|
3138
|
-
}
|
|
3139
|
-
if (!ev.product && PAGE_LEVEL_KINDS.has(ev.kind) && typeof location !== "undefined") {
|
|
3140
|
-
const id = extract([{ href: location.pathname }]);
|
|
3141
|
-
if (!id) return ev;
|
|
3142
|
-
return {
|
|
3143
|
-
...ev,
|
|
3144
|
-
product: {
|
|
3145
|
-
handle: id.productHandle,
|
|
3146
|
-
url: id.productUrl,
|
|
3147
|
-
...id.productTitle ? { title: id.productTitle } : {}
|
|
3148
|
-
}
|
|
3149
|
-
};
|
|
3150
|
-
}
|
|
3151
|
-
return ev;
|
|
3152
|
-
};
|
|
3185
|
+
session.hydrateOnce(() => fetchMountedElements({ endpoint, token: runtime2.token }));
|
|
3153
3186
|
}
|
|
3154
|
-
var
|
|
3155
|
-
var _nudgeListener = null;
|
|
3187
|
+
var _removeNudgeListener = null;
|
|
3156
3188
|
function wireNudgeSurface(runtime2, backendUrl) {
|
|
3157
|
-
if (
|
|
3158
|
-
|
|
3159
|
-
_nudgeListener = (e) => {
|
|
3189
|
+
if (_removeNudgeListener || typeof document === "undefined") return;
|
|
3190
|
+
const listener = (e) => {
|
|
3160
3191
|
try {
|
|
3161
3192
|
const detail = e.detail;
|
|
3162
3193
|
const isIntent = detail?.phase === "intent";
|
|
3163
3194
|
if (!isIntent) {
|
|
3164
|
-
const
|
|
3195
|
+
const session = getOrCreateElementSession(runtime2);
|
|
3165
3196
|
const trimmed = backendUrl.replace(/\/$/, "");
|
|
3166
3197
|
const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
|
|
3167
3198
|
void fetchMountedElements({ endpoint, token: runtime2.token }).then((response) => {
|
|
3168
3199
|
if (!response) return;
|
|
3169
|
-
void
|
|
3200
|
+
void session.hydrateLegacy(response.mounted_elements, response.session_expires_at);
|
|
3170
3201
|
});
|
|
3171
3202
|
}
|
|
3172
3203
|
if (detail?.suppressToast === true) return;
|
|
@@ -3182,7 +3213,11 @@ function wireNudgeSurface(runtime2, backendUrl) {
|
|
|
3182
3213
|
console.warn("[adaptive-chatbot] nudge surface reaction failed", err);
|
|
3183
3214
|
}
|
|
3184
3215
|
};
|
|
3185
|
-
document.addEventListener("syntro:nudge",
|
|
3216
|
+
document.addEventListener("syntro:nudge", listener);
|
|
3217
|
+
_removeNudgeListener = () => {
|
|
3218
|
+
document.removeEventListener("syntro:nudge", listener);
|
|
3219
|
+
_removeNudgeListener = null;
|
|
3220
|
+
};
|
|
3186
3221
|
}
|
|
3187
3222
|
function configureTransportIfPossible(cfg2) {
|
|
3188
3223
|
if (!cfg2.runtime) return;
|
|
@@ -3193,9 +3228,7 @@ function configureTransportIfPossible(cfg2) {
|
|
|
3193
3228
|
const forwardedProps = elementsActive ? { elementsEnabled: true, uiTemplates: cfg2.uiTemplates } : void 0;
|
|
3194
3229
|
if (elementsActive) publishTemplatesIfPossible(backendUrl, cfg2.uiTemplates, cfg2.runtime?.token);
|
|
3195
3230
|
const runtime2 = cfg2.runtime;
|
|
3196
|
-
const
|
|
3197
|
-
void getOrCreateElementStore(runtime2).apply(mutations);
|
|
3198
|
-
} : void 0;
|
|
3231
|
+
const onElementEnvelope = elementsActive ? (envelope) => getOrCreateElementSession(runtime2).applyLegacyEnvelope(envelope) : void 0;
|
|
3199
3232
|
if (elementsActive) {
|
|
3200
3233
|
hydrateOnce(runtime2, backendUrl);
|
|
3201
3234
|
}
|
|
@@ -3204,7 +3237,7 @@ function configureTransportIfPossible(cfg2) {
|
|
|
3204
3237
|
...cfg2,
|
|
3205
3238
|
backendUrl,
|
|
3206
3239
|
forwardedProps,
|
|
3207
|
-
|
|
3240
|
+
onElementEnvelope,
|
|
3208
3241
|
activeLidSlot: cfg2._syntroSlotName,
|
|
3209
3242
|
personaId: persona?.id,
|
|
3210
3243
|
personaName: persona?.name,
|
|
@@ -3251,46 +3284,19 @@ function wireDiveDeeperListener() {
|
|
|
3251
3284
|
}
|
|
3252
3285
|
var _observerStarted = false;
|
|
3253
3286
|
var _observerRuntime = null;
|
|
3254
|
-
var
|
|
3255
|
-
var _observerBusUnsubscribe = null;
|
|
3287
|
+
var _observerStop = null;
|
|
3256
3288
|
function startObserverIfPossible(cfg2) {
|
|
3257
3289
|
if (typeof window === "undefined") return;
|
|
3258
3290
|
const runtimeRef = cfg2.runtime;
|
|
3259
3291
|
if (!runtimeRef?.events?.subscribe) return;
|
|
3260
3292
|
if (_observerStarted && _observerRuntime === runtimeRef) return;
|
|
3261
3293
|
if (_observerStarted) {
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
_observerBusUnsubscribe = null;
|
|
3265
|
-
_observerHandle = null;
|
|
3294
|
+
_observerStop?.();
|
|
3295
|
+
_observerStop = null;
|
|
3266
3296
|
_observerStarted = false;
|
|
3267
3297
|
}
|
|
3268
|
-
|
|
3269
|
-
const url = trimmed ? `${trimmed}/api/adaptive/observation` : "/api/adaptive/observation";
|
|
3270
|
-
const runtimeId = (method) => {
|
|
3271
|
-
try {
|
|
3272
|
-
const v = runtimeRef.telemetry?.[method]?.();
|
|
3273
|
-
return typeof v === "string" && v.length > 0 ? v : null;
|
|
3274
|
-
} catch {
|
|
3275
|
-
return null;
|
|
3276
|
-
}
|
|
3277
|
-
};
|
|
3278
|
-
const getDistinctId = () => runtimeId("getDistinctId");
|
|
3279
|
-
const getSessionId = () => runtimeId("getSessionId");
|
|
3280
|
-
const token = () => {
|
|
3281
|
-
const t = runtimeRef.token;
|
|
3282
|
-
return typeof t === "string" ? t : "";
|
|
3283
|
-
};
|
|
3284
|
-
const enrich = buildObserverEnrich(runtimeRef);
|
|
3285
|
-
const handle = startObserver({ url, token, getDistinctId, getSessionId, enrich });
|
|
3286
|
-
window.__syntroObserverStats = () => handle.stats();
|
|
3287
|
-
const unsubscribe = runtimeRef.events.subscribe({}, (evt) => {
|
|
3288
|
-
const raw = busEventToRawEvent(evt);
|
|
3289
|
-
if (raw) handle.ingest(raw);
|
|
3290
|
-
});
|
|
3298
|
+
_observerStop = wireObserver(runtimeRef);
|
|
3291
3299
|
_observerRuntime = runtimeRef;
|
|
3292
|
-
_observerHandle = handle;
|
|
3293
|
-
_observerBusUnsubscribe = unsubscribe;
|
|
3294
3300
|
_observerStarted = true;
|
|
3295
3301
|
}
|
|
3296
3302
|
function wireListeners(bar, state) {
|
|
@@ -3359,7 +3365,7 @@ var AdaptiveChatBarMountable = {
|
|
|
3359
3365
|
});
|
|
3360
3366
|
const runtimeEvents = cfg2.runtime ? cfg2.runtime.events : void 0;
|
|
3361
3367
|
const refreshReceipts = () => {
|
|
3362
|
-
const store =
|
|
3368
|
+
const store = _elementSession?.store;
|
|
3363
3369
|
if (store) {
|
|
3364
3370
|
bar.tileReceipts = store.listTileReceipts();
|
|
3365
3371
|
bar.inlineWidgets = store.listInlineWidgets();
|
|
@@ -3472,6 +3478,658 @@ var AdaptiveChipsStripMountable = {
|
|
|
3472
3478
|
}
|
|
3473
3479
|
};
|
|
3474
3480
|
|
|
3481
|
+
// src/hostAgentController.ts
|
|
3482
|
+
var READ_TOOL = "read_brand_view";
|
|
3483
|
+
var MISSING_RESULT_MS = 8e3;
|
|
3484
|
+
var PENDING_MAX_MS = 12e4;
|
|
3485
|
+
var AGENT_TURN_KEY = "syntro/agent-turn";
|
|
3486
|
+
var CARD_HEARTBEAT_PREFIX = "syntro:mcp-card:";
|
|
3487
|
+
var heartbeatPrefix = (sessionRef) => `${CARD_HEARTBEAT_PREFIX}${sessionRef}:`;
|
|
3488
|
+
var CARD_HEARTBEAT_INTERVAL_MS = 2e3;
|
|
3489
|
+
var CARD_SIBLING_WINDOW_MS = 6e3;
|
|
3490
|
+
var CARD_HEARTBEAT_STALE_MS = 6e4;
|
|
3491
|
+
var CARD_SUPERSEDED = "canvas:superseded";
|
|
3492
|
+
var DOCKED_PREFIX = "syntro:mcp-docked:";
|
|
3493
|
+
var DOCKED_FOR_MS = 24 * 60 * 60 * 1e3;
|
|
3494
|
+
function coarsePointer() {
|
|
3495
|
+
try {
|
|
3496
|
+
return typeof matchMedia === "function" && matchMedia("(pointer: coarse)").matches;
|
|
3497
|
+
} catch {
|
|
3498
|
+
return false;
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
function cardStorage() {
|
|
3502
|
+
try {
|
|
3503
|
+
return globalThis.localStorage ?? void 0;
|
|
3504
|
+
} catch {
|
|
3505
|
+
return void 0;
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
var STAR_TOOL = "star_card_tile";
|
|
3509
|
+
function decodeStars(value) {
|
|
3510
|
+
if (!record(value)) return void 0;
|
|
3511
|
+
const out = {};
|
|
3512
|
+
for (const [instanceId, star] of Object.entries(value)) {
|
|
3513
|
+
if (nonempty(instanceId) && record(star) && typeof star.starred === "boolean" && typeof star.updatedAt === "string")
|
|
3514
|
+
out[instanceId] = {
|
|
3515
|
+
starred: star.starred,
|
|
3516
|
+
updatedAt: star.updatedAt,
|
|
3517
|
+
...typeof star.changedAt === "string" ? { changedAt: star.changedAt } : {}
|
|
3518
|
+
};
|
|
3519
|
+
}
|
|
3520
|
+
return out;
|
|
3521
|
+
}
|
|
3522
|
+
function mergeStars(held, incoming) {
|
|
3523
|
+
const out = { ...held ?? {} };
|
|
3524
|
+
for (const [instanceId, next] of Object.entries(incoming)) {
|
|
3525
|
+
const current = out[instanceId];
|
|
3526
|
+
const keepCurrent = current?.changedAt !== void 0 && (next.changedAt === void 0 || current.changedAt > next.changedAt);
|
|
3527
|
+
if (!keepCurrent) out[instanceId] = next;
|
|
3528
|
+
}
|
|
3529
|
+
return out;
|
|
3530
|
+
}
|
|
3531
|
+
var interactionOwners = /* @__PURE__ */ new WeakMap();
|
|
3532
|
+
function hostUiSubscription(value) {
|
|
3533
|
+
return record(value) && typeof value.subscribeHostUi === "function";
|
|
3534
|
+
}
|
|
3535
|
+
function validSession(value) {
|
|
3536
|
+
if (!record(value) || !nonempty(value.session_ref) || !(value.session_expires_at === null || value.session_expires_at === void 0 || typeof value.session_expires_at === "string" && Number.isFinite(Date.parse(value.session_expires_at))) || !(value.verified_templates === null || value.verified_templates === void 0 || record(value.verified_templates)))
|
|
3537
|
+
return false;
|
|
3538
|
+
const tiles = value.verified_templates?.tiles;
|
|
3539
|
+
return tiles === void 0 || tiles === null || Array.isArray(tiles) && tiles.every((tile) => record(tile) && nonempty(tile.id) && nonempty(tile.widget));
|
|
3540
|
+
}
|
|
3541
|
+
function record(value) {
|
|
3542
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3543
|
+
}
|
|
3544
|
+
function nonempty(value) {
|
|
3545
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
3546
|
+
}
|
|
3547
|
+
function expiry(value) {
|
|
3548
|
+
return value === null || typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
3549
|
+
}
|
|
3550
|
+
function decodeAgentTurn(result) {
|
|
3551
|
+
if (!record(result) || !record(result._meta)) return;
|
|
3552
|
+
const payload = result._meta["syntro/agent-turn"];
|
|
3553
|
+
if (!record(payload)) return;
|
|
3554
|
+
if (payload.version !== 1 && payload.version !== 2) return;
|
|
3555
|
+
const sessionRef = payload.sessionRef ?? payload.sessionId;
|
|
3556
|
+
if (!nonempty(sessionRef) || !nonempty(payload.turnId) || !record(payload.uiTemplates) || !record(payload.snapshot))
|
|
3557
|
+
return;
|
|
3558
|
+
const snapshot = payload.snapshot;
|
|
3559
|
+
if (snapshot.schema_version !== "v0" || !Array.isArray(snapshot.mounted_elements) || !expiry(snapshot.session_expires_at))
|
|
3560
|
+
return;
|
|
3561
|
+
const sessionExpiresAt = payload.sessionExpiresAt ?? snapshot.session_expires_at;
|
|
3562
|
+
if (!expiry(sessionExpiresAt)) return;
|
|
3563
|
+
const tiles = payload.uiTemplates.tiles;
|
|
3564
|
+
if (tiles !== void 0 && (!Array.isArray(tiles) || tiles.some(
|
|
3565
|
+
(template) => !record(template) || !nonempty(template.id) || !nonempty(template.widget)
|
|
3566
|
+
)))
|
|
3567
|
+
return;
|
|
3568
|
+
const templates = createTemplateWidgetResolver();
|
|
3569
|
+
templates.refresh(payload.uiTemplates);
|
|
3570
|
+
for (const candidate of snapshot.mounted_elements) {
|
|
3571
|
+
if (record(candidate) && candidate.element_type === "tile" && candidate.state === "active" && (!nonempty(candidate.template_id) || !templates.resolve(candidate.template_id)))
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
const session = {
|
|
3575
|
+
session_ref: sessionRef,
|
|
3576
|
+
session_expires_at: sessionExpiresAt,
|
|
3577
|
+
verified_templates: payload.uiTemplates
|
|
3578
|
+
};
|
|
3579
|
+
const frame = {
|
|
3580
|
+
schema_version: "v1",
|
|
3581
|
+
kind: "snapshot",
|
|
3582
|
+
session_ref: sessionRef,
|
|
3583
|
+
// The turn id IS the dedup id: the runtime commits one snapshot per
|
|
3584
|
+
// accepted request and names it with that request's id.
|
|
3585
|
+
result_id: payload.turnId,
|
|
3586
|
+
session_expires_at: snapshot.session_expires_at,
|
|
3587
|
+
mounted_elements: snapshot.mounted_elements
|
|
3588
|
+
};
|
|
3589
|
+
const issuedAt = typeof payload.issuedAt === "number" && Number.isFinite(payload.issuedAt) ? payload.issuedAt : void 0;
|
|
3590
|
+
const stars = decodeStars(payload.stars);
|
|
3591
|
+
return {
|
|
3592
|
+
session,
|
|
3593
|
+
frame,
|
|
3594
|
+
...issuedAt !== void 0 ? { issuedAt } : {},
|
|
3595
|
+
...stars ? { stars } : {}
|
|
3596
|
+
};
|
|
3597
|
+
}
|
|
3598
|
+
function activateHostAgentController(runtime2, bridge, hostUi, options = {}) {
|
|
3599
|
+
let controller = createElementSessionController(runtime2);
|
|
3600
|
+
let disposed = false;
|
|
3601
|
+
let pending = Promise.resolve();
|
|
3602
|
+
let session;
|
|
3603
|
+
let generation = 0;
|
|
3604
|
+
const retiredScopes = /* @__PURE__ */ new Set();
|
|
3605
|
+
let stopObserver;
|
|
3606
|
+
let readRequested = false;
|
|
3607
|
+
let applied = 0;
|
|
3608
|
+
const cardId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
3609
|
+
let heartbeatKey;
|
|
3610
|
+
let heartbeatTimer;
|
|
3611
|
+
let popOutDecided = false;
|
|
3612
|
+
let born;
|
|
3613
|
+
let showingEarlyRead = false;
|
|
3614
|
+
let answerIssuedAt;
|
|
3615
|
+
let heartbeatSession;
|
|
3616
|
+
let folded = false;
|
|
3617
|
+
function hostSurface() {
|
|
3618
|
+
try {
|
|
3619
|
+
return runtime2.context?.get().surface ?? {};
|
|
3620
|
+
} catch {
|
|
3621
|
+
return {};
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
function readHeartbeat(key) {
|
|
3625
|
+
try {
|
|
3626
|
+
const raw = cardStorage()?.getItem(key);
|
|
3627
|
+
if (!raw) return;
|
|
3628
|
+
const parsed = JSON.parse(raw);
|
|
3629
|
+
if (!record(parsed) || !nonempty(parsed.id) || typeof parsed.ts !== "number") return;
|
|
3630
|
+
return {
|
|
3631
|
+
id: parsed.id,
|
|
3632
|
+
ts: parsed.ts,
|
|
3633
|
+
mode: typeof parsed.mode === "string" ? parsed.mode : void 0,
|
|
3634
|
+
born: typeof parsed.born === "number" ? parsed.born : void 0
|
|
3635
|
+
};
|
|
3636
|
+
} catch {
|
|
3637
|
+
return;
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
function writeHeartbeat() {
|
|
3641
|
+
if (!heartbeatKey) return;
|
|
3642
|
+
try {
|
|
3643
|
+
cardStorage()?.setItem(
|
|
3644
|
+
heartbeatKey,
|
|
3645
|
+
JSON.stringify({ id: cardId, ts: Date.now(), mode: hostSurface().displayMode, born })
|
|
3646
|
+
);
|
|
3647
|
+
} catch {
|
|
3648
|
+
}
|
|
3649
|
+
considerFold();
|
|
3650
|
+
}
|
|
3651
|
+
function considerFold() {
|
|
3652
|
+
if (folded || disposed || !heartbeatSession || born === void 0) return;
|
|
3653
|
+
const surface = hostSurface();
|
|
3654
|
+
if (surface.type !== "mcp-app" || surface.displayMode !== "inline") return;
|
|
3655
|
+
if (!surface.availableDisplayModes || popsOut(surface, heartbeatSession)) return;
|
|
3656
|
+
const mine = born;
|
|
3657
|
+
if (!freshSiblings(heartbeatSession).some((beat) => (beat.born ?? 0) > mine)) return;
|
|
3658
|
+
folded = true;
|
|
3659
|
+
runtime2.events.publish(CARD_SUPERSEDED, { superseded: true });
|
|
3660
|
+
}
|
|
3661
|
+
function pruneHeartbeats() {
|
|
3662
|
+
try {
|
|
3663
|
+
const store = cardStorage();
|
|
3664
|
+
if (!store) return;
|
|
3665
|
+
const stale = [];
|
|
3666
|
+
for (let index = 0; index < store.length; index++) {
|
|
3667
|
+
const key = store.key(index);
|
|
3668
|
+
if (!key?.startsWith(CARD_HEARTBEAT_PREFIX) || key === heartbeatKey) continue;
|
|
3669
|
+
const beat = readHeartbeat(key);
|
|
3670
|
+
if (!beat || Date.now() - beat.ts > CARD_HEARTBEAT_STALE_MS) stale.push(key);
|
|
3671
|
+
}
|
|
3672
|
+
for (const key of stale) store.removeItem(key);
|
|
3673
|
+
} catch {
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
const releaseHeartbeat = () => stopHeartbeat();
|
|
3677
|
+
const onVisibilityChange = () => {
|
|
3678
|
+
if (!heartbeatKey) return;
|
|
3679
|
+
if (document.visibilityState === "hidden") {
|
|
3680
|
+
if (heartbeatTimer !== void 0) {
|
|
3681
|
+
clearInterval(heartbeatTimer);
|
|
3682
|
+
heartbeatTimer = void 0;
|
|
3683
|
+
}
|
|
3684
|
+
return;
|
|
3685
|
+
}
|
|
3686
|
+
if (heartbeatTimer !== void 0) return;
|
|
3687
|
+
writeHeartbeat();
|
|
3688
|
+
heartbeatTimer = setInterval(writeHeartbeat, CARD_HEARTBEAT_INTERVAL_MS);
|
|
3689
|
+
};
|
|
3690
|
+
let unsubscribeModeWatch;
|
|
3691
|
+
function startHeartbeat(sessionRef) {
|
|
3692
|
+
const key = heartbeatPrefix(sessionRef) + cardId;
|
|
3693
|
+
if (heartbeatKey === key) return;
|
|
3694
|
+
if (heartbeatKey) stopHeartbeat();
|
|
3695
|
+
heartbeatKey = key;
|
|
3696
|
+
heartbeatSession = sessionRef;
|
|
3697
|
+
pruneHeartbeats();
|
|
3698
|
+
writeHeartbeat();
|
|
3699
|
+
heartbeatTimer = setInterval(writeHeartbeat, CARD_HEARTBEAT_INTERVAL_MS);
|
|
3700
|
+
let heartbeatMode = hostSurface().displayMode;
|
|
3701
|
+
try {
|
|
3702
|
+
unsubscribeModeWatch = runtime2.context?.subscribe?.(() => {
|
|
3703
|
+
const mode = hostSurface().displayMode;
|
|
3704
|
+
if (mode === heartbeatMode) return;
|
|
3705
|
+
if (heartbeatMode === "pip" && mode === "inline" && heartbeatSession)
|
|
3706
|
+
rememberDocked(heartbeatSession);
|
|
3707
|
+
heartbeatMode = mode;
|
|
3708
|
+
writeHeartbeat();
|
|
3709
|
+
});
|
|
3710
|
+
} catch {
|
|
3711
|
+
}
|
|
3712
|
+
if (typeof window !== "undefined") {
|
|
3713
|
+
window.addEventListener("pagehide", releaseHeartbeat);
|
|
3714
|
+
window.addEventListener("beforeunload", releaseHeartbeat);
|
|
3715
|
+
}
|
|
3716
|
+
if (typeof document !== "undefined")
|
|
3717
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
3718
|
+
}
|
|
3719
|
+
function stopHeartbeat() {
|
|
3720
|
+
if (heartbeatTimer !== void 0) {
|
|
3721
|
+
clearInterval(heartbeatTimer);
|
|
3722
|
+
heartbeatTimer = void 0;
|
|
3723
|
+
}
|
|
3724
|
+
unsubscribeModeWatch?.();
|
|
3725
|
+
unsubscribeModeWatch = void 0;
|
|
3726
|
+
const key = heartbeatKey;
|
|
3727
|
+
heartbeatKey = void 0;
|
|
3728
|
+
if (typeof window !== "undefined") {
|
|
3729
|
+
window.removeEventListener("pagehide", releaseHeartbeat);
|
|
3730
|
+
window.removeEventListener("beforeunload", releaseHeartbeat);
|
|
3731
|
+
}
|
|
3732
|
+
if (typeof document !== "undefined")
|
|
3733
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
3734
|
+
if (!key) return;
|
|
3735
|
+
try {
|
|
3736
|
+
cardStorage()?.removeItem(key);
|
|
3737
|
+
} catch {
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
function freshSiblings(sessionRef) {
|
|
3741
|
+
const siblings = [];
|
|
3742
|
+
try {
|
|
3743
|
+
const store = cardStorage();
|
|
3744
|
+
if (!store) return siblings;
|
|
3745
|
+
const prefix = heartbeatPrefix(sessionRef);
|
|
3746
|
+
for (let index = 0; index < store.length; index++) {
|
|
3747
|
+
const key = store.key(index);
|
|
3748
|
+
if (!key?.startsWith(prefix)) continue;
|
|
3749
|
+
const beat = readHeartbeat(key);
|
|
3750
|
+
if (!beat || beat.id === cardId) continue;
|
|
3751
|
+
if (Date.now() - beat.ts > CARD_SIBLING_WINDOW_MS) continue;
|
|
3752
|
+
siblings.push(beat);
|
|
3753
|
+
}
|
|
3754
|
+
} catch {
|
|
3755
|
+
return siblings;
|
|
3756
|
+
}
|
|
3757
|
+
return siblings;
|
|
3758
|
+
}
|
|
3759
|
+
function considerPopOut(sessionRef) {
|
|
3760
|
+
if (popOutDecided) return;
|
|
3761
|
+
popOutDecided = true;
|
|
3762
|
+
const siblings = freshSiblings(sessionRef);
|
|
3763
|
+
if (siblings.some((beat) => beat.mode !== "inline")) return;
|
|
3764
|
+
const surface = hostSurface();
|
|
3765
|
+
if (surface.type !== "mcp-app" || surface.displayMode !== "inline") return;
|
|
3766
|
+
if (!popsOut(surface, sessionRef)) return;
|
|
3767
|
+
runtime2.events.publish("canvas:request-display-mode", { mode: "pip" });
|
|
3768
|
+
}
|
|
3769
|
+
function popsOut(surface, sessionRef) {
|
|
3770
|
+
if (!surface.availableDisplayModes?.includes("pip")) return false;
|
|
3771
|
+
if (coarsePointer()) return false;
|
|
3772
|
+
return !shopperDocked(sessionRef);
|
|
3773
|
+
}
|
|
3774
|
+
function shopperDocked(sessionRef) {
|
|
3775
|
+
try {
|
|
3776
|
+
const raw = cardStorage()?.getItem(DOCKED_PREFIX + sessionRef);
|
|
3777
|
+
const at = raw ? Number(raw) : Number.NaN;
|
|
3778
|
+
return Number.isFinite(at) && Date.now() - at < DOCKED_FOR_MS;
|
|
3779
|
+
} catch {
|
|
3780
|
+
return false;
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
function rememberDocked(sessionRef) {
|
|
3784
|
+
try {
|
|
3785
|
+
cardStorage()?.setItem(DOCKED_PREFIX + sessionRef, String(Date.now()));
|
|
3786
|
+
} catch {
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
let interactiveState;
|
|
3790
|
+
function interactive(value) {
|
|
3791
|
+
if (disposed || interactiveState === value) return;
|
|
3792
|
+
interactiveState = value;
|
|
3793
|
+
hostUi?.setInteractive?.(value);
|
|
3794
|
+
runtime2.events.publish("host.ui_state", { interactive: value });
|
|
3795
|
+
}
|
|
3796
|
+
function queue(operation) {
|
|
3797
|
+
const expected = generation;
|
|
3798
|
+
pending = pending.then(async () => {
|
|
3799
|
+
if (!disposed && expected === generation) await operation();
|
|
3800
|
+
}).catch(() => {
|
|
3801
|
+
if (!disposed && expected === generation) {
|
|
3802
|
+
interactive(false);
|
|
3803
|
+
runtime2.events.publish("host.ui_error", { reason: "projection_failed" });
|
|
3804
|
+
}
|
|
3805
|
+
});
|
|
3806
|
+
}
|
|
3807
|
+
function scheduleHostRead(sessionRef, why = "reload") {
|
|
3808
|
+
if (disposed || readRequested || typeof bridge.callServerTool !== "function") return;
|
|
3809
|
+
const call = bridge.callServerTool.bind(bridge);
|
|
3810
|
+
readRequested = true;
|
|
3811
|
+
const expected = generation;
|
|
3812
|
+
const readAgain = () => {
|
|
3813
|
+
if (disposed || why !== "turn_started") return;
|
|
3814
|
+
readRequested = false;
|
|
3815
|
+
if (session) scheduleHostRead(session.session_ref);
|
|
3816
|
+
};
|
|
3817
|
+
void Promise.resolve().then(() => {
|
|
3818
|
+
if (disposed) return;
|
|
3819
|
+
if (expected !== generation) return readAgain();
|
|
3820
|
+
queue(async () => {
|
|
3821
|
+
const appliedAtIssue = applied;
|
|
3822
|
+
reportCardStage("read_brand_view_called", { why });
|
|
3823
|
+
void call({ name: READ_TOOL, arguments: { sessionRef } }).then((result) => {
|
|
3824
|
+
reportReadAnswer(why, result);
|
|
3825
|
+
if (disposed) return;
|
|
3826
|
+
if (expected !== generation) return readAgain();
|
|
3827
|
+
if (applied !== appliedAtIssue) {
|
|
3828
|
+
reportCardStage("tool_result_rejected", { reason: "stale" });
|
|
3829
|
+
return;
|
|
3830
|
+
}
|
|
3831
|
+
return consumeToolResult(result, { earlyRead: why === "turn_started" });
|
|
3832
|
+
}).catch((error) => {
|
|
3833
|
+
reportCardStage("read_brand_view_answered", {
|
|
3834
|
+
why,
|
|
3835
|
+
ok: false,
|
|
3836
|
+
withAgentTurn: false,
|
|
3837
|
+
// The host's own words for the refusal: a read that never
|
|
3838
|
+
// reaches the connector leaves no other record of why.
|
|
3839
|
+
reason: readFailureReason(error instanceof Error ? error.message : String(error))
|
|
3840
|
+
});
|
|
3841
|
+
if (why === "turn_started") return readAgain();
|
|
3842
|
+
if (!disposed && expected === generation)
|
|
3843
|
+
runtime2.events.publish("host.ui_error", { reason: "refresh_required" });
|
|
3844
|
+
});
|
|
3845
|
+
});
|
|
3846
|
+
});
|
|
3847
|
+
}
|
|
3848
|
+
function reportReadAnswer(why, result) {
|
|
3849
|
+
const failed = record(result) && result.isError === true;
|
|
3850
|
+
const text = failed ? firstText(result) : void 0;
|
|
3851
|
+
reportCardStage("read_brand_view_answered", {
|
|
3852
|
+
why,
|
|
3853
|
+
ok: !failed,
|
|
3854
|
+
withAgentTurn: decodeAgentTurn(result) !== void 0,
|
|
3855
|
+
...text ? { reason: readFailureReason(text) } : {}
|
|
3856
|
+
});
|
|
3857
|
+
}
|
|
3858
|
+
const missingAfterMs = options.missingResultMs ?? MISSING_RESULT_MS;
|
|
3859
|
+
let missingTimer = setTimeout(
|
|
3860
|
+
reportMissingResult,
|
|
3861
|
+
missingAfterMs
|
|
3862
|
+
);
|
|
3863
|
+
function standDown() {
|
|
3864
|
+
if (missingTimer !== void 0) clearTimeout(missingTimer);
|
|
3865
|
+
missingTimer = void 0;
|
|
3866
|
+
}
|
|
3867
|
+
function reportMissingResult() {
|
|
3868
|
+
missingTimer = void 0;
|
|
3869
|
+
if (disposed) return;
|
|
3870
|
+
reportCardStage("tool_result_missing", { afterMs: missingAfterMs });
|
|
3871
|
+
}
|
|
3872
|
+
function acceptHostUi2(payload) {
|
|
3873
|
+
if (disposed || !record(payload)) return;
|
|
3874
|
+
if (payload.kind === "session") {
|
|
3875
|
+
if (!validSession(payload.session)) {
|
|
3876
|
+
interactive(false);
|
|
3877
|
+
runtime2.events.publish("host.ui_error", { reason: "invalid_session" });
|
|
3878
|
+
return;
|
|
3879
|
+
}
|
|
3880
|
+
const next = payload.session;
|
|
3881
|
+
standDown();
|
|
3882
|
+
if (retiredScopes.has(next.session_ref)) return;
|
|
3883
|
+
if (session && next.session_ref === session.session_ref) {
|
|
3884
|
+
session = next;
|
|
3885
|
+
controller.configureTemplates(next.verified_templates ?? void 0);
|
|
3886
|
+
interactive(true);
|
|
3887
|
+
return;
|
|
3888
|
+
}
|
|
3889
|
+
if (session) retiredScopes.add(session.session_ref);
|
|
3890
|
+
generation++;
|
|
3891
|
+
const shutdown = controller.dispose();
|
|
3892
|
+
controller = createElementSessionController({
|
|
3893
|
+
...runtime2,
|
|
3894
|
+
templates: next.verified_templates ?? void 0,
|
|
3895
|
+
hostScope: { sessionRef: next.session_ref }
|
|
3896
|
+
});
|
|
3897
|
+
pending = shutdown;
|
|
3898
|
+
session = next;
|
|
3899
|
+
stopObserver ?? (stopObserver = wireObserver(runtime2));
|
|
3900
|
+
interactive(true);
|
|
3901
|
+
reportCardStage("session_bound", { sessionRef: next.session_ref });
|
|
3902
|
+
scheduleHostRead(next.session_ref);
|
|
3903
|
+
return;
|
|
3904
|
+
}
|
|
3905
|
+
if (payload.kind !== "frame") return;
|
|
3906
|
+
const active = controller;
|
|
3907
|
+
const frame = payload.frame;
|
|
3908
|
+
queue(async () => {
|
|
3909
|
+
const outcome = await active.acceptHostFrame(payload.frame);
|
|
3910
|
+
if (active !== controller || disposed) return;
|
|
3911
|
+
if (outcome.status === "rejected") {
|
|
3912
|
+
reportCardStage("tool_result_rejected", { reason: outcome.reason });
|
|
3913
|
+
if (outcome.reason === "projection_failed") interactive(false);
|
|
3914
|
+
runtime2.events.publish("host.ui_error", { reason: outcome.reason });
|
|
3915
|
+
} else if (outcome.status === "duplicate") {
|
|
3916
|
+
reportCardStage("tool_result_rejected", {
|
|
3917
|
+
reason: "duplicate",
|
|
3918
|
+
turnId: outcome.resultId
|
|
3919
|
+
});
|
|
3920
|
+
} else if (outcome.status === "applied") {
|
|
3921
|
+
applied++;
|
|
3922
|
+
const tiles = (Array.isArray(frame?.mounted_elements) ? frame.mounted_elements : []).filter(
|
|
3923
|
+
(element) => element.element_type === "tile" && element.state === "active"
|
|
3924
|
+
);
|
|
3925
|
+
reportCardStage("frame_applied", {
|
|
3926
|
+
turnId: outcome.resultId,
|
|
3927
|
+
tiles: tiles.length,
|
|
3928
|
+
templateIds: [...new Set(tiles.map((element) => element.template_id))].filter((id) => typeof id === "string" && id.length > 0 && id.length <= 80).slice(0, 12)
|
|
3929
|
+
});
|
|
3930
|
+
runtime2.events.publish("host.frame_applied", {
|
|
3931
|
+
result_id: outcome.resultId,
|
|
3932
|
+
tiles: tiles.length
|
|
3933
|
+
});
|
|
3934
|
+
if (born === void 0 && tiles.length > 0 && !showingEarlyRead) {
|
|
3935
|
+
born = answerIssuedAt ?? Date.now();
|
|
3936
|
+
writeHeartbeat();
|
|
3937
|
+
}
|
|
3938
|
+
interactive(true);
|
|
3939
|
+
}
|
|
3940
|
+
});
|
|
3941
|
+
}
|
|
3942
|
+
async function consumeToolResult(result, { earlyRead = false } = {}) {
|
|
3943
|
+
if (disposed) return;
|
|
3944
|
+
const turn = decodeAgentTurn(result);
|
|
3945
|
+
if (!turn) {
|
|
3946
|
+
if (record(result) && record(result._meta) && AGENT_TURN_KEY in result._meta)
|
|
3947
|
+
reportCardStage("tool_result_rejected", { reason: "decode_failed" });
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
showingEarlyRead = earlyRead;
|
|
3951
|
+
if (!earlyRead) {
|
|
3952
|
+
answerIssuedAt ?? (answerIssuedAt = turn.issuedAt ?? Date.now());
|
|
3953
|
+
considerPopOut(turn.session.session_ref);
|
|
3954
|
+
}
|
|
3955
|
+
acceptHostUi2({ kind: "session", session: turn.session });
|
|
3956
|
+
acceptHostUi2({ kind: "frame", frame: turn.frame });
|
|
3957
|
+
startHeartbeat(turn.session.session_ref);
|
|
3958
|
+
boundSessionRef = turn.session.session_ref;
|
|
3959
|
+
if (turn.stars) {
|
|
3960
|
+
knownStars = mergeStars(knownStars, turn.stars);
|
|
3961
|
+
publishStars();
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
let boundSessionRef;
|
|
3965
|
+
let knownStars;
|
|
3966
|
+
function publishStars() {
|
|
3967
|
+
if (disposed || !knownStars) return;
|
|
3968
|
+
runtime2.events.publish("host.stars", { stars: { ...knownStars } });
|
|
3969
|
+
}
|
|
3970
|
+
async function requestStar(props) {
|
|
3971
|
+
const instanceId = props?.instanceId;
|
|
3972
|
+
const starred = props?.starred;
|
|
3973
|
+
if (!nonempty(instanceId) || typeof starred !== "boolean") return;
|
|
3974
|
+
const failed = () => {
|
|
3975
|
+
if (!disposed) runtime2.events.publish("host.star_failed", { instanceId });
|
|
3976
|
+
};
|
|
3977
|
+
if (!boundSessionRef || typeof bridge.callServerTool !== "function") return failed();
|
|
3978
|
+
let result;
|
|
3979
|
+
try {
|
|
3980
|
+
result = await bridge.callServerTool({
|
|
3981
|
+
name: STAR_TOOL,
|
|
3982
|
+
arguments: { sessionRef: boundSessionRef, instanceId, starred }
|
|
3983
|
+
});
|
|
3984
|
+
} catch {
|
|
3985
|
+
return failed();
|
|
3986
|
+
}
|
|
3987
|
+
const stored = record(result) && !result.isError ? result.structuredContent : void 0;
|
|
3988
|
+
if (!record(stored) || stored.instanceId !== instanceId || typeof stored.starred !== "boolean" || typeof stored.updatedAt !== "string")
|
|
3989
|
+
return failed();
|
|
3990
|
+
knownStars = mergeStars(knownStars, {
|
|
3991
|
+
[instanceId]: {
|
|
3992
|
+
starred: stored.starred,
|
|
3993
|
+
updatedAt: stored.updatedAt,
|
|
3994
|
+
...typeof stored.changedAt === "string" ? { changedAt: stored.changedAt } : {}
|
|
3995
|
+
}
|
|
3996
|
+
});
|
|
3997
|
+
publishStars();
|
|
3998
|
+
}
|
|
3999
|
+
const stopStarRequests = runtime2.events.subscribe?.(
|
|
4000
|
+
{ names: ["canvas:star-request", "canvas:stars-request"] },
|
|
4001
|
+
(event) => {
|
|
4002
|
+
if (disposed) return;
|
|
4003
|
+
if (event.name === "canvas:stars-request") publishStars();
|
|
4004
|
+
else void requestStar(event.props);
|
|
4005
|
+
}
|
|
4006
|
+
);
|
|
4007
|
+
const deliver = (result) => {
|
|
4008
|
+
standDown();
|
|
4009
|
+
void consumeToolResult(result);
|
|
4010
|
+
};
|
|
4011
|
+
const stopActivity = bridge.subscribeToolActivity?.(standDown);
|
|
4012
|
+
let turnPending;
|
|
4013
|
+
let pendingTimer;
|
|
4014
|
+
function publishTurnPending(value) {
|
|
4015
|
+
if (disposed || turnPending === value) return;
|
|
4016
|
+
turnPending = value;
|
|
4017
|
+
if (pendingTimer !== void 0) clearTimeout(pendingTimer);
|
|
4018
|
+
pendingTimer = value ? setTimeout(() => publishTurnPending(false), PENDING_MAX_MS) : void 0;
|
|
4019
|
+
runtime2.events.publish("host.turn_pending", { pending: value });
|
|
4020
|
+
}
|
|
4021
|
+
const stopPendingRequests = runtime2.events.subscribe?.(
|
|
4022
|
+
{ names: ["canvas:turn-pending-request"] },
|
|
4023
|
+
() => {
|
|
4024
|
+
if (!disposed && turnPending !== void 0)
|
|
4025
|
+
runtime2.events.publish("host.turn_pending", { pending: turnPending });
|
|
4026
|
+
}
|
|
4027
|
+
);
|
|
4028
|
+
const stopToolCall = bridge.subscribeToolCall?.((call) => {
|
|
4029
|
+
if (disposed) return;
|
|
4030
|
+
if (call.phase === "input") {
|
|
4031
|
+
publishTurnPending(true);
|
|
4032
|
+
const sessionRef = call.arguments.sessionRef;
|
|
4033
|
+
if (nonempty(sessionRef) && !session) scheduleHostRead(sessionRef, "turn_started");
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
void Promise.resolve().then(() => queue(async () => publishTurnPending(false)));
|
|
4037
|
+
});
|
|
4038
|
+
const unsubscribe = bridge.subscribeToolResults(deliver, {
|
|
4039
|
+
metadataKey: AGENT_TURN_KEY
|
|
4040
|
+
});
|
|
4041
|
+
return {
|
|
4042
|
+
acceptHostUi: acceptHostUi2,
|
|
4043
|
+
consumeToolResult,
|
|
4044
|
+
whenIdle: async () => {
|
|
4045
|
+
await pending;
|
|
4046
|
+
await controller.whenIdle();
|
|
4047
|
+
},
|
|
4048
|
+
dispose() {
|
|
4049
|
+
if (disposed) return;
|
|
4050
|
+
disposed = true;
|
|
4051
|
+
generation++;
|
|
4052
|
+
if (missingTimer !== void 0) clearTimeout(missingTimer);
|
|
4053
|
+
missingTimer = void 0;
|
|
4054
|
+
stopActivity?.();
|
|
4055
|
+
stopToolCall?.();
|
|
4056
|
+
stopPendingRequests?.();
|
|
4057
|
+
if (pendingTimer !== void 0) clearTimeout(pendingTimer);
|
|
4058
|
+
stopStarRequests?.();
|
|
4059
|
+
stopHeartbeat();
|
|
4060
|
+
stopObserver?.();
|
|
4061
|
+
stopObserver = void 0;
|
|
4062
|
+
unsubscribe();
|
|
4063
|
+
void controller.dispose();
|
|
4064
|
+
}
|
|
4065
|
+
};
|
|
4066
|
+
}
|
|
4067
|
+
var READ_REASON_MAX = 120;
|
|
4068
|
+
function readFailureReason(text) {
|
|
4069
|
+
const flat = text.replace(/\s+/g, " ").replace(/[A-Za-z0-9_\-+/=]{24,}/g, "[id]").trim();
|
|
4070
|
+
return flat.length > READ_REASON_MAX ? `${flat.slice(0, READ_REASON_MAX - 1)}~` : flat || "unknown";
|
|
4071
|
+
}
|
|
4072
|
+
function firstText(result) {
|
|
4073
|
+
if (!Array.isArray(result.content)) return void 0;
|
|
4074
|
+
for (const block of result.content) {
|
|
4075
|
+
if (record(block) && block.type === "text" && typeof block.text === "string") return block.text;
|
|
4076
|
+
}
|
|
4077
|
+
return void 0;
|
|
4078
|
+
}
|
|
4079
|
+
function activateHostAgent(runtime2) {
|
|
4080
|
+
if (!record(runtime2) || !record(runtime2.context) || typeof runtime2.context.get !== "function")
|
|
4081
|
+
return;
|
|
4082
|
+
const context = runtime2.context.get();
|
|
4083
|
+
if (!record(context) || !record(context.surface) || context.surface.type !== "mcp-app") return;
|
|
4084
|
+
if (!record(runtime2.actions) || typeof runtime2.actions.apply !== "function" || typeof runtime2.actions.applyBatch !== "function" || !record(runtime2.events) || typeof runtime2.events.publish !== "function" || typeof window === "undefined")
|
|
4085
|
+
return;
|
|
4086
|
+
const host = window.MCPApp?.bridge;
|
|
4087
|
+
if (typeof host?.subscribeToolResults !== "function") return;
|
|
4088
|
+
const receiver = hostUiSubscription(runtime2.hostUi) ? runtime2.hostUi : void 0;
|
|
4089
|
+
const interactionOwner = /* @__PURE__ */ Symbol("host-view");
|
|
4090
|
+
let interactionCanvas = null;
|
|
4091
|
+
let previousInert = false;
|
|
4092
|
+
let previousDisabled = null;
|
|
4093
|
+
const controller = activateHostAgentController(
|
|
4094
|
+
runtime2,
|
|
4095
|
+
host,
|
|
4096
|
+
receiver ? {
|
|
4097
|
+
setInteractive: (value) => {
|
|
4098
|
+
const canvas = findSmartCanvas();
|
|
4099
|
+
if (!canvas) return;
|
|
4100
|
+
if (interactionCanvas !== canvas) {
|
|
4101
|
+
interactionCanvas = canvas;
|
|
4102
|
+
const previous = interactionOwners.get(canvas);
|
|
4103
|
+
previousInert = previous ? previous.inert : canvas.inert;
|
|
4104
|
+
previousDisabled = previous ? previous.disabled : canvas.getAttribute("aria-disabled");
|
|
4105
|
+
interactionOwners.set(canvas, {
|
|
4106
|
+
owner: interactionOwner,
|
|
4107
|
+
inert: previousInert,
|
|
4108
|
+
disabled: previousDisabled
|
|
4109
|
+
});
|
|
4110
|
+
}
|
|
4111
|
+
if (interactionOwners.get(canvas)?.owner !== interactionOwner) return;
|
|
4112
|
+
canvas.inert = !value || previousInert;
|
|
4113
|
+
canvas.setAttribute("aria-disabled", value ? previousDisabled ?? "false" : "true");
|
|
4114
|
+
}
|
|
4115
|
+
} : void 0
|
|
4116
|
+
);
|
|
4117
|
+
const unsubscribe = receiver?.subscribeHostUi(controller.acceptHostUi);
|
|
4118
|
+
return () => {
|
|
4119
|
+
unsubscribe?.();
|
|
4120
|
+
controller.dispose();
|
|
4121
|
+
if (interactionCanvas && interactionOwners.get(interactionCanvas)?.owner === interactionOwner) {
|
|
4122
|
+
interactionCanvas.inert = previousInert;
|
|
4123
|
+
if (previousDisabled === null) interactionCanvas.removeAttribute("aria-disabled");
|
|
4124
|
+
else interactionCanvas.setAttribute("aria-disabled", previousDisabled);
|
|
4125
|
+
interactionOwners.delete(interactionCanvas);
|
|
4126
|
+
}
|
|
4127
|
+
};
|
|
4128
|
+
}
|
|
4129
|
+
function acceptHostUi(runtime2, payload) {
|
|
4130
|
+
runtime2.acceptHostUi?.(payload);
|
|
4131
|
+
}
|
|
4132
|
+
|
|
3475
4133
|
// src/NavLinkMountable.ts
|
|
3476
4134
|
var STATE_KEY3 = "__syntroNavLinkMount";
|
|
3477
4135
|
var SAFE_NAVIGATION_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
@@ -3656,6 +4314,8 @@ var runtime = {
|
|
|
3656
4314
|
name: "Chat Assistant",
|
|
3657
4315
|
description: "AI chat assistant powered by @syntrologie/chat with SSE transport",
|
|
3658
4316
|
executors: [],
|
|
4317
|
+
onActivate: activateHostAgent,
|
|
4318
|
+
acceptHostUi,
|
|
3659
4319
|
widgets: [
|
|
3660
4320
|
{
|
|
3661
4321
|
id: "adaptive-chatbot:assistant",
|