@agent-native/core 0.26.6 → 0.26.7

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.
Files changed (43) hide show
  1. package/dist/cli/skills.d.ts.map +1 -1
  2. package/dist/cli/skills.js +3 -1
  3. package/dist/cli/skills.js.map +1 -1
  4. package/dist/cli/workspace-dev.d.ts.map +1 -1
  5. package/dist/cli/workspace-dev.js +9 -2
  6. package/dist/cli/workspace-dev.js.map +1 -1
  7. package/dist/client/AgentPanel.d.ts.map +1 -1
  8. package/dist/client/AgentPanel.js +2 -2
  9. package/dist/client/AgentPanel.js.map +1 -1
  10. package/dist/client/agent-chat.d.ts.map +1 -1
  11. package/dist/client/agent-chat.js +6 -5
  12. package/dist/client/agent-chat.js.map +1 -1
  13. package/dist/client/frame.d.ts +1 -0
  14. package/dist/client/frame.d.ts.map +1 -1
  15. package/dist/client/frame.js +20 -6
  16. package/dist/client/frame.js.map +1 -1
  17. package/dist/client/index.d.ts +1 -1
  18. package/dist/client/index.d.ts.map +1 -1
  19. package/dist/client/index.js +1 -1
  20. package/dist/client/index.js.map +1 -1
  21. package/dist/mcp/build-server.js +1 -1
  22. package/dist/mcp/build-server.js.map +1 -1
  23. package/dist/mcp/embed-app.d.ts +3 -0
  24. package/dist/mcp/embed-app.d.ts.map +1 -1
  25. package/dist/mcp/embed-app.js +255 -13
  26. package/dist/mcp/embed-app.js.map +1 -1
  27. package/dist/mcp/server.d.ts.map +1 -1
  28. package/dist/mcp/server.js +5 -10
  29. package/dist/mcp/server.js.map +1 -1
  30. package/dist/server/deep-link.d.ts.map +1 -1
  31. package/dist/server/deep-link.js +16 -1
  32. package/dist/server/deep-link.js.map +1 -1
  33. package/dist/server/security-headers.d.ts.map +1 -1
  34. package/dist/server/security-headers.js +7 -1
  35. package/dist/server/security-headers.js.map +1 -1
  36. package/dist/shared/mcp-embed-headers.d.ts +1 -0
  37. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  38. package/dist/shared/mcp-embed-headers.js +19 -2
  39. package/dist/shared/mcp-embed-headers.js.map +1 -1
  40. package/dist/vite/client.d.ts.map +1 -1
  41. package/dist/vite/client.js +124 -0
  42. package/dist/vite/client.js.map +1 -1
  43. package/package.json +1 -1
@@ -70,7 +70,8 @@ export function embedApp(options = {}) {
70
70
  <div class="message">Preparing app</div>
71
71
  </section>
72
72
  </main>
73
- <script type="module">
73
+ <script>
74
+ (async () => {
74
75
  const body = document.body;
75
76
  const stage = document.querySelector("[data-stage]");
76
77
  const titleEl = document.querySelector("[data-title-label]");
@@ -84,6 +85,11 @@ export function embedApp(options = {}) {
84
85
  const frameReadyMessageDelays = [0, 200, 500, 1500, 3000, 7000, 15000, 30000];
85
86
  const frameReadyTimeoutMs = 45000;
86
87
  const frameLoadTimeoutMs = 45000;
88
+ const defaultOpenAiBridgeWaitMs = 200;
89
+ const chatGptOpenAiBridgeWaitMs = 5000;
90
+ const openAiBridgePollMs = 50;
91
+ const nativeBridgeInitializeTimeoutMs = 5000;
92
+ const nativeBridgeRequestTimeoutMs = 30000;
87
93
  let app = null;
88
94
  let openAiBridge = null;
89
95
  let toolInput = {};
@@ -366,8 +372,23 @@ export function embedApp(options = {}) {
366
372
  };
367
373
  }
368
374
 
375
+ function installReactRefreshPreambleFallback() {
376
+ window.__vite_plugin_react_preamble_installed__ = true;
377
+ if (typeof window.$RefreshReg$ !== "function") {
378
+ window.$RefreshReg$ = function() {};
379
+ }
380
+ if (typeof window.$RefreshSig$ !== "function") {
381
+ window.$RefreshSig$ = function() {
382
+ return function(type) {
383
+ return type;
384
+ };
385
+ };
386
+ }
387
+ }
388
+
369
389
  function installExternalEmbedRuntime(config) {
370
390
  window.__AGENT_NATIVE_EXTERNAL_EMBED = config;
391
+ installReactRefreshPreambleFallback();
371
392
  try {
372
393
  if (config.target) {
373
394
  window.history.replaceState(window.history.state, "", config.target);
@@ -536,7 +557,7 @@ export function embedApp(options = {}) {
536
557
  }
537
558
 
538
559
  function relativeSpecifierToAppUrl(specifier, config, baseUrl) {
539
- if (typeof specifier !== "string" || !/^\\.\\.?\//.test(specifier)) {
560
+ if (typeof specifier !== "string" || !/^\\.\\.?\\//.test(specifier)) {
540
561
  return specifier;
541
562
  }
542
563
  try {
@@ -931,6 +952,7 @@ export function embedApp(options = {}) {
931
952
  function shouldSelfNavigateToApp() {
932
953
  const render = renderModeSource();
933
954
  const mode = render.mode;
955
+ if (isClaudeMcpContentHost()) return true;
934
956
  if (mode === "iframe" || mode === "nested") return false;
935
957
  if (render.nested || render.frame === "iframe") return false;
936
958
  return true;
@@ -940,9 +962,10 @@ export function embedApp(options = {}) {
940
962
  const render = renderModeSource();
941
963
  const mode = render.mode;
942
964
  return (
965
+ isClaudeMcpContentHost() ||
966
+ isChatGptSandboxHost() ||
943
967
  mode === "transplant" ||
944
- render.frame === "transplant" ||
945
- isClaudeMcpContentHost()
968
+ render.frame === "transplant"
946
969
  );
947
970
  }
948
971
 
@@ -958,7 +981,7 @@ export function embedApp(options = {}) {
958
981
  try {
959
982
  const host = window.location.hostname || "";
960
983
  const appParam = new URL(window.location.href).searchParams.get("app");
961
- return /(^|\\.)oaiusercontent\\.com$/i.test(host) || appParam === "chatgpt";
984
+ return /^[^.]+\\.web-sandbox\\.oaiusercontent\\.com$/i.test(host) || appParam === "chatgpt";
962
985
  } catch {
963
986
  return false;
964
987
  }
@@ -1166,7 +1189,7 @@ export function embedApp(options = {}) {
1166
1189
  const selfNavigate = shouldSelfNavigateToApp();
1167
1190
  const embedUrl = withChatBridgeParam(launchUrl);
1168
1191
  if (selfNavigate && isEmbedStartUrl(embedUrl)) {
1169
- if (isClaudeMcpContentHost() && shouldTransplantAppDocument()) {
1192
+ if (shouldTransplantAppDocument()) {
1170
1193
  await transplantAppDocument(embedUrl);
1171
1194
  } else if (shouldRenderControlledAppFrame()) {
1172
1195
  renderFrame(embedUrl);
@@ -1188,7 +1211,7 @@ export function embedApp(options = {}) {
1188
1211
  }
1189
1212
  const startUrl = withChatBridgeParam(data.startUrl);
1190
1213
  if (selfNavigate) {
1191
- if (isClaudeMcpContentHost() && shouldTransplantAppDocument()) {
1214
+ if (shouldTransplantAppDocument()) {
1192
1215
  await transplantAppDocument(startUrl);
1193
1216
  } else if (shouldRenderControlledAppFrame()) {
1194
1217
  renderFrame(startUrl);
@@ -1235,7 +1258,8 @@ export function embedApp(options = {}) {
1235
1258
  }
1236
1259
 
1237
1260
  function updateTitle(data) {
1238
- const label = data.label || data.app || data.view || body.dataset.appTitle || "App";
1261
+ const record = objectValue(data);
1262
+ const label = record.label || record.app || record.view || body.dataset.appTitle || "App";
1239
1263
  titleEl.textContent = String(label);
1240
1264
  }
1241
1265
 
@@ -1245,6 +1269,17 @@ export function embedApp(options = {}) {
1245
1269
  : null;
1246
1270
  }
1247
1271
 
1272
+ function isChatGptHostHint() {
1273
+ try {
1274
+ if (new URLSearchParams(window.location.search).get("app") === "chatgpt") return true;
1275
+ } catch (_err) {}
1276
+ try {
1277
+ return /chatgpt/i.test(String(navigator.userAgent || ""));
1278
+ } catch (_err) {
1279
+ return false;
1280
+ }
1281
+ }
1282
+
1248
1283
  function openAiToolResultParams(bridge) {
1249
1284
  const params = {};
1250
1285
  if (bridge && bridge.toolOutput !== undefined) {
@@ -1287,16 +1322,30 @@ export function embedApp(options = {}) {
1287
1322
  if (existing) return Promise.resolve(existing);
1288
1323
  return new Promise((resolve) => {
1289
1324
  let settled = false;
1325
+ let pollTimer = 0;
1290
1326
  const finish = (bridge) => {
1291
1327
  if (settled) return;
1292
1328
  settled = true;
1293
1329
  window.removeEventListener("openai:set_globals", onGlobals);
1294
1330
  clearTimeout(timer);
1331
+ clearTimeout(pollTimer);
1295
1332
  resolve(bridge || readOpenAiBridge());
1296
1333
  };
1334
+ const poll = () => {
1335
+ const bridge = readOpenAiBridge();
1336
+ if (bridge) {
1337
+ finish(bridge);
1338
+ return;
1339
+ }
1340
+ pollTimer = window.setTimeout(poll, openAiBridgePollMs);
1341
+ };
1297
1342
  const onGlobals = () => finish(readOpenAiBridge());
1298
- const timer = setTimeout(() => finish(null), 200);
1343
+ const timer = window.setTimeout(
1344
+ () => finish(null),
1345
+ isChatGptHostHint() ? chatGptOpenAiBridgeWaitMs : defaultOpenAiBridgeWaitMs
1346
+ );
1299
1347
  window.addEventListener("openai:set_globals", onGlobals, { passive: true });
1348
+ pollTimer = window.setTimeout(poll, openAiBridgePollMs);
1300
1349
  });
1301
1350
  }
1302
1351
 
@@ -1305,6 +1354,183 @@ export function embedApp(options = {}) {
1305
1354
  if (bridge && (!appFrame || openAiBridge)) syncOpenAiBridge(bridge);
1306
1355
  }, { passive: true });
1307
1356
 
1357
+ function createNativeMcpAppsBridge() {
1358
+ let rpcId = 0;
1359
+ let connected = false;
1360
+ let hostContext = {};
1361
+ const pendingRequests = new Map();
1362
+
1363
+ function rpcNotify(method, params) {
1364
+ window.parent.postMessage({ jsonrpc: "2.0", method, params: params || {} }, "*");
1365
+ }
1366
+
1367
+ function rpcRequest(method, params, timeoutMs) {
1368
+ return new Promise((resolve, reject) => {
1369
+ const id = ++rpcId;
1370
+ const timer = window.setTimeout(() => {
1371
+ pendingRequests.delete(id);
1372
+ reject(new Error("MCP Apps bridge request timed out: " + method));
1373
+ }, timeoutMs || nativeBridgeRequestTimeoutMs);
1374
+ pendingRequests.set(id, { resolve, reject, timer });
1375
+ window.parent.postMessage(
1376
+ { jsonrpc: "2.0", id, method, params: params || {} },
1377
+ "*"
1378
+ );
1379
+ });
1380
+ }
1381
+
1382
+ function settleRpcResponse(message) {
1383
+ const pending = pendingRequests.get(message.id);
1384
+ if (!pending) return true;
1385
+ pendingRequests.delete(message.id);
1386
+ clearTimeout(pending.timer);
1387
+ if (message.error) {
1388
+ const error = new Error(message.error.message || "MCP Apps bridge request failed.");
1389
+ error.data = message.error.data;
1390
+ pending.reject(error);
1391
+ return true;
1392
+ }
1393
+ pending.resolve(message.result);
1394
+ return true;
1395
+ }
1396
+
1397
+ function notificationParams(message) {
1398
+ return message && typeof message.params === "object" && message.params
1399
+ ? message.params
1400
+ : {};
1401
+ }
1402
+
1403
+ function toolInputNotificationParams(params) {
1404
+ if (params && typeof params.arguments === "object" && params.arguments) {
1405
+ return params;
1406
+ }
1407
+ if (params && typeof params.input === "object" && params.input) {
1408
+ return { arguments: params.input };
1409
+ }
1410
+ return { arguments: objectValue(params) };
1411
+ }
1412
+
1413
+ const nativeApp = {
1414
+ ontoolinput: null,
1415
+ ontoolresult: null,
1416
+ onhostcontextchanged: null,
1417
+ getHostContext() {
1418
+ return hostContext.context || hostContext;
1419
+ },
1420
+ getHostCapabilities() {
1421
+ return hostContext.capabilities || { tools: true, messaging: true };
1422
+ },
1423
+ getHostVersion() {
1424
+ return hostContext.protocolVersion || "mcp-apps-postmessage";
1425
+ },
1426
+ async connect() {
1427
+ if (connected) return hostContext;
1428
+ connected = true;
1429
+ window.addEventListener("message", onMessage, { passive: true });
1430
+ const result = await rpcRequest(
1431
+ "ui/initialize",
1432
+ {
1433
+ appInfo: { name: "Agent Native Embed", version: "1.0.0" },
1434
+ appCapabilities: {},
1435
+ protocolVersion: "2026-01-26"
1436
+ },
1437
+ nativeBridgeInitializeTimeoutMs
1438
+ );
1439
+ hostContext = objectValue(result);
1440
+ rpcNotify("ui/notifications/initialized", {});
1441
+ if (typeof nativeApp.onhostcontextchanged === "function") {
1442
+ nativeApp.onhostcontextchanged(hostContext);
1443
+ }
1444
+ return hostContext;
1445
+ },
1446
+ async callServerTool(request) {
1447
+ const record = objectValue(request);
1448
+ return await rpcRequest("tools/call", {
1449
+ name: record.name,
1450
+ arguments: objectValue(record.arguments)
1451
+ });
1452
+ },
1453
+ async updateModelContext(params) {
1454
+ return await rpcRequest("ui/update-model-context", objectValue(params));
1455
+ },
1456
+ async openLink(params) {
1457
+ const url = typeof (params && params.url) === "string" ? params.url : "";
1458
+ if (!url) return { isError: true };
1459
+ window.open(url, "_blank", "noopener,noreferrer");
1460
+ return { ok: true };
1461
+ },
1462
+ async requestDisplayMode(params) {
1463
+ return await rpcRequest("ui/request-display-mode", objectValue(params));
1464
+ },
1465
+ sendSizeChanged(params) {
1466
+ rpcNotify("ui/notifications/size-changed", objectValue(params));
1467
+ },
1468
+ async sendMessage(params) {
1469
+ return await rpcRequest("ui/message", objectValue(params));
1470
+ }
1471
+ };
1472
+
1473
+ function onMessage(event) {
1474
+ if (event.source !== window.parent) return;
1475
+ const message = event.data;
1476
+ if (!message || message.jsonrpc !== "2.0") return;
1477
+ if (typeof message.id === "number" || typeof message.id === "string") {
1478
+ settleRpcResponse(message);
1479
+ return;
1480
+ }
1481
+ if (typeof message.method !== "string") return;
1482
+ const params = notificationParams(message);
1483
+ if (message.method === "ui/notifications/tool-input") {
1484
+ if (typeof nativeApp.ontoolinput === "function") {
1485
+ nativeApp.ontoolinput(toolInputNotificationParams(params));
1486
+ }
1487
+ return;
1488
+ }
1489
+ if (message.method === "ui/notifications/tool-result") {
1490
+ if (typeof nativeApp.ontoolresult === "function") {
1491
+ nativeApp.ontoolresult(params);
1492
+ }
1493
+ return;
1494
+ }
1495
+ if (
1496
+ message.method === "ui/notifications/host-context" ||
1497
+ message.method === "ui/notifications/context"
1498
+ ) {
1499
+ hostContext = objectValue(params);
1500
+ if (typeof nativeApp.onhostcontextchanged === "function") {
1501
+ nativeApp.onhostcontextchanged(hostContext);
1502
+ }
1503
+ }
1504
+ }
1505
+
1506
+ return nativeApp;
1507
+ }
1508
+
1509
+ async function startNativeMcpAppsBridge() {
1510
+ app = createNativeMcpAppsBridge();
1511
+ app.ontoolinput = (params) => {
1512
+ toolInput = params.arguments || {};
1513
+ };
1514
+ app.ontoolresult = (params) => {
1515
+ const data = parseToolResult(params);
1516
+ toolResultData = objectValue(data);
1517
+ openUrl = openLinkFrom(params, data);
1518
+ openStartUrl = embedStartUrlFrom(params, data);
1519
+ updateTitle(data);
1520
+ updateOpenButton();
1521
+ void launchEmbed();
1522
+ };
1523
+ app.onhostcontextchanged = () => {
1524
+ updateDisplayButton();
1525
+ notifyHostHeight();
1526
+ sendHostContext();
1527
+ };
1528
+ await app.connect();
1529
+ updateDisplayButton();
1530
+ notifyHostHeight();
1531
+ sendHostContext();
1532
+ }
1533
+
1308
1534
  async function startMcpAppsBridge() {
1309
1535
  const { App } = await import("${MCP_APP_IMPORT}");
1310
1536
  app = new App(
@@ -1335,10 +1561,21 @@ export function embedApp(options = {}) {
1335
1561
  sendHostContext();
1336
1562
  }
1337
1563
 
1338
- const initialOpenAiBridge = await waitForOpenAiBridge();
1339
- if (!syncOpenAiBridge(initialOpenAiBridge)) {
1340
- await startMcpAppsBridge();
1564
+ try {
1565
+ const initialOpenAiBridge = await waitForOpenAiBridge();
1566
+ if (!syncOpenAiBridge(initialOpenAiBridge)) {
1567
+ try {
1568
+ await startNativeMcpAppsBridge();
1569
+ } catch (nativeErr) {
1570
+ console.warn("[agent-native] native MCP Apps bridge failed", nativeErr);
1571
+ await startMcpAppsBridge();
1572
+ }
1573
+ }
1574
+ } catch (err) {
1575
+ console.error("[agent-native] MCP app shell failed", err);
1576
+ setMessage(err && err.message ? err.message : "Could not initialize app.");
1341
1577
  }
1578
+ })();
1342
1579
  </script>
1343
1580
  </body>
1344
1581
  </html>`,
@@ -1346,14 +1583,19 @@ export function embedApp(options = {}) {
1346
1583
  connectDomains: [
1347
1584
  "https://esm.sh",
1348
1585
  MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,
1586
+ ...(options.connectDomains ?? []),
1349
1587
  ...(options.frameDomains ?? []),
1350
1588
  ],
1351
1589
  resourceDomains: [
1352
1590
  "https://esm.sh",
1353
1591
  MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,
1592
+ ...(options.resourceDomains ?? []),
1354
1593
  ...(options.frameDomains ?? []),
1355
1594
  ],
1356
- baseUriDomains: [MCP_APP_REQUEST_ORIGIN_CSP_SOURCE],
1595
+ baseUriDomains: [
1596
+ MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,
1597
+ ...(options.baseUriDomains ?? []),
1598
+ ],
1357
1599
  frameDomains,
1358
1600
  },
1359
1601
  prefersBorder: false,