@agent-native/core 0.26.3 → 0.26.5

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 (63) hide show
  1. package/dist/cli/skills.d.ts.map +1 -1
  2. package/dist/cli/skills.js +4 -1
  3. package/dist/cli/skills.js.map +1 -1
  4. package/dist/client/mcp-app-host.d.ts +1 -0
  5. package/dist/client/mcp-app-host.d.ts.map +1 -1
  6. package/dist/client/mcp-app-host.js +44 -6
  7. package/dist/client/mcp-app-host.js.map +1 -1
  8. package/dist/deploy/build.d.ts.map +1 -1
  9. package/dist/deploy/build.js +44 -7
  10. package/dist/deploy/build.js.map +1 -1
  11. package/dist/mcp/build-server.d.ts.map +1 -1
  12. package/dist/mcp/build-server.js +95 -8
  13. package/dist/mcp/build-server.js.map +1 -1
  14. package/dist/mcp/embed-app.d.ts.map +1 -1
  15. package/dist/mcp/embed-app.js +247 -30
  16. package/dist/mcp/embed-app.js.map +1 -1
  17. package/dist/mcp/server.d.ts +5 -7
  18. package/dist/mcp/server.d.ts.map +1 -1
  19. package/dist/mcp/server.js +16 -12
  20. package/dist/mcp/server.js.map +1 -1
  21. package/dist/server/action-routes.d.ts.map +1 -1
  22. package/dist/server/action-routes.js +23 -7
  23. package/dist/server/action-routes.js.map +1 -1
  24. package/dist/server/auth.d.ts.map +1 -1
  25. package/dist/server/auth.js +69 -38
  26. package/dist/server/auth.js.map +1 -1
  27. package/dist/server/core-routes-plugin.d.ts +12 -1
  28. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  29. package/dist/server/core-routes-plugin.js +48 -44
  30. package/dist/server/core-routes-plugin.js.map +1 -1
  31. package/dist/server/create-server.d.ts.map +1 -1
  32. package/dist/server/create-server.js +3 -1
  33. package/dist/server/create-server.js.map +1 -1
  34. package/dist/server/credential-provider.d.ts +1 -0
  35. package/dist/server/credential-provider.d.ts.map +1 -1
  36. package/dist/server/credential-provider.js +15 -4
  37. package/dist/server/credential-provider.js.map +1 -1
  38. package/dist/server/embed-route.d.ts.map +1 -1
  39. package/dist/server/embed-route.js +28 -2
  40. package/dist/server/embed-route.js.map +1 -1
  41. package/dist/server/embed-session.d.ts.map +1 -1
  42. package/dist/server/embed-session.js +26 -7
  43. package/dist/server/embed-session.js.map +1 -1
  44. package/dist/server/onboarding-html.d.ts.map +1 -1
  45. package/dist/server/onboarding-html.js +52 -5
  46. package/dist/server/onboarding-html.js.map +1 -1
  47. package/dist/server/ssr-handler.d.ts +1 -1
  48. package/dist/server/ssr-handler.d.ts.map +1 -1
  49. package/dist/server/ssr-handler.js +23 -10
  50. package/dist/server/ssr-handler.js.map +1 -1
  51. package/dist/shared/cache-control.d.ts +2 -0
  52. package/dist/shared/cache-control.d.ts.map +1 -0
  53. package/dist/shared/cache-control.js +2 -0
  54. package/dist/shared/cache-control.js.map +1 -0
  55. package/dist/shared/mcp-embed-headers.d.ts +2 -1
  56. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  57. package/dist/shared/mcp-embed-headers.js +3 -1
  58. package/dist/shared/mcp-embed-headers.js.map +1 -1
  59. package/dist/templates/workspace-root/package.json +5 -0
  60. package/docs/content/mcp-protocol.md +0 -1
  61. package/docs/content/template-assets.md +5 -0
  62. package/package.json +2 -2
  63. package/src/templates/workspace-root/package.json +5 -0
@@ -87,6 +87,7 @@ export function embedApp(options = {}) {
87
87
  let app = null;
88
88
  let openAiBridge = null;
89
89
  let toolInput = {};
90
+ let toolResultData = {};
90
91
  let openUrl = "";
91
92
  let openStartUrl = "";
92
93
  let startedFor = "";
@@ -170,6 +171,28 @@ export function embedApp(options = {}) {
170
171
  return parseJson(text, {});
171
172
  }
172
173
 
174
+ function metadataRecord(value) {
175
+ const meta = value && typeof value === "object" && !Array.isArray(value)
176
+ ? value._meta
177
+ : null;
178
+ return meta && typeof meta === "object" && !Array.isArray(meta)
179
+ ? meta
180
+ : null;
181
+ }
182
+
183
+ function toolResultMeta(params) {
184
+ if (!params || typeof params !== "object") return {};
185
+ const direct = metadataRecord(params);
186
+ if (direct) return direct;
187
+ if (params.result && typeof params.result === "object") {
188
+ return toolResultMeta(params.result);
189
+ }
190
+ if (params.toolResult && typeof params.toolResult === "object") {
191
+ return toolResultMeta(params.toolResult);
192
+ }
193
+ return {};
194
+ }
195
+
173
196
  function openLinkRecordFrom(value) {
174
197
  return value && typeof value === "object" && !Array.isArray(value)
175
198
  ? value
@@ -198,7 +221,8 @@ export function embedApp(options = {}) {
198
221
  }
199
222
 
200
223
  function openLinkFrom(params, data) {
201
- const openLink = params && params._meta && params._meta["agent-native/openLink"];
224
+ const meta = toolResultMeta(params);
225
+ const openLink = meta["agent-native/openLink"];
202
226
  const metaUrl = openLinkWebUrlFrom(openLink);
203
227
  const record = data && typeof data === "object" ? data : {};
204
228
  const structuredOpenLinkUrl = openLinkWebUrlFrom(record.openLink);
@@ -214,13 +238,13 @@ export function embedApp(options = {}) {
214
238
  }
215
239
 
216
240
  function embedStartUrlFrom(params, data) {
217
- const embedStart =
218
- params && params._meta && params._meta["agent-native/embedStart"];
241
+ const meta = toolResultMeta(params);
242
+ const embedStart = meta["agent-native/embedStart"];
219
243
  const embedStartRecord =
220
244
  embedStart && typeof embedStart === "object" && !Array.isArray(embedStart)
221
245
  ? embedStart
222
246
  : {};
223
- const openLink = params && params._meta && params._meta["agent-native/openLink"];
247
+ const openLink = meta["agent-native/openLink"];
224
248
  const metaUrl = openLinkWebUrlFrom(openLink);
225
249
  const record = data && typeof data === "object" ? data : {};
226
250
  return firstEmbedStartUrl([
@@ -491,22 +515,149 @@ export function embedApp(options = {}) {
491
515
  next.remove();
492
516
  }
493
517
 
494
- function rootRelativeSpecifiersToAbsolute(code, appOrigin) {
495
- return String(code).replace(/(["'])\\/(?!\\/)/g, "$1" + appOrigin + "/");
518
+ function rootRelativeSpecifierToAppUrl(specifier, config) {
519
+ if (typeof specifier !== "string" || !specifier.startsWith("/") || specifier.startsWith("//")) {
520
+ return specifier;
521
+ }
522
+ try {
523
+ const url = new URL(specifier, config.origin);
524
+ if (config.token) url.searchParams.set(config.embedTokenParam, config.token);
525
+ if (config.chatBridgeActive) url.searchParams.set(config.chatBridgeParam, "1");
526
+ return url.toString();
527
+ } catch (_err) {
528
+ return specifier;
529
+ }
530
+ }
531
+
532
+ function rootRelativeSpecifiersToAbsolute(code, config) {
533
+ return String(code).replace(/(["'])\\/(?!\\/)([^"']*)/g, (_match, quote, rest) => {
534
+ return quote + rootRelativeSpecifierToAppUrl("/" + rest, config);
535
+ });
496
536
  }
497
537
 
498
- function moduleCodeToClassicAsync(code, appOrigin) {
499
- return rootRelativeSpecifiersToAbsolute(code, appOrigin)
538
+ function relativeSpecifierToAppUrl(specifier, config, baseUrl) {
539
+ if (typeof specifier !== "string" || !/^\\.\\.?\//.test(specifier)) {
540
+ return specifier;
541
+ }
542
+ try {
543
+ const url = new URL(specifier, baseUrl || config.baseHref);
544
+ if (url.origin === config.origin) {
545
+ if (config.token) url.searchParams.set(config.embedTokenParam, config.token);
546
+ if (config.chatBridgeActive) url.searchParams.set(config.chatBridgeParam, "1");
547
+ }
548
+ return url.toString();
549
+ } catch (_err) {
550
+ return specifier;
551
+ }
552
+ }
553
+
554
+ function relativeModuleSpecifiersToAbsolute(code, config, baseUrl) {
555
+ return String(code)
556
+ .replace(/(\\bimport\\s+(?:[^"']+?\\s+from\\s+)?)(["'])(\\.\\.?\\/[^"']*)\\2/g, (_match, prefix, quote, specifier) => {
557
+ return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;
558
+ })
559
+ .replace(/(\\bimport\\s*\\(\\s*)(["'])(\\.\\.?\\/[^"']*)\\2/g, (_match, prefix, quote, specifier) => {
560
+ return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;
561
+ })
562
+ .replace(/(\\bexport\\s+[^"']*?\\s+from\\s+)(["'])(\\.\\.?\\/[^"']*)\\2/g, (_match, prefix, quote, specifier) => {
563
+ return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;
564
+ });
565
+ }
566
+
567
+ function stripDevOnlyModuleImports(code) {
568
+ return String(code).replace(
569
+ /\\bimport\\s+(?:[^"']+\\s+from\\s+)?["'][^"']*(?:virtual:react-router\\/inject-hmr-runtime|__x00__virtual:react-router\\/inject-hmr-runtime)[^"']*["']\\s*;?/g,
570
+ ""
571
+ );
572
+ }
573
+
574
+ function namedImportBindings(specifierList) {
575
+ return String(specifierList)
576
+ .split(",")
577
+ .map((part) => {
578
+ const trimmed = part.trim();
579
+ if (!trimmed) return "";
580
+ return trimmed.replace(
581
+ /^([A-Za-z_$][\\w$]*)\\s+as\\s+([A-Za-z_$][\\w$]*)$/,
582
+ "$1: $2"
583
+ );
584
+ })
585
+ .filter(Boolean)
586
+ .join(", ");
587
+ }
588
+
589
+ function moduleCodeToClassicAsync(code, config, baseUrl) {
590
+ return relativeModuleSpecifiersToAbsolute(
591
+ rootRelativeSpecifiersToAbsolute(stripDevOnlyModuleImports(code), config),
592
+ config,
593
+ baseUrl
594
+ )
595
+ .replace(
596
+ /\\bimport\\s+([A-Za-z_$][\\w$]*)\\s*,\\s*\\*\\s+as\\s+([A-Za-z_$][\\w$]*)\\s+from\\s+(["'][^"']+["'])\\s*;?/g,
597
+ "const $2 = await import($3); const $1 = $2.default;"
598
+ )
599
+ .replace(
600
+ /\\bimport\\s+([A-Za-z_$][\\w$]*)\\s*,\\s*\\{([\\s\\S]*?)\\}\\s*from\\s+(["'][^"']+["'])\\s*;?/g,
601
+ (_match, defaultName, specifiers, source) =>
602
+ "const { default: " +
603
+ defaultName +
604
+ (namedImportBindings(specifiers) ? ", " + namedImportBindings(specifiers) : "") +
605
+ " } = await import(" +
606
+ source +
607
+ ");"
608
+ )
609
+ .replace(
610
+ /\\bimport\\s+\\{([\\s\\S]*?)\\}\\s*from\\s+(["'][^"']+["'])\\s*;?/g,
611
+ (_match, specifiers, source) =>
612
+ "const { " + namedImportBindings(specifiers) + " } = await import(" + source + ");"
613
+ )
500
614
  .replace(
501
615
  /\\bimport\\s+\\*\\s+as\\s+([A-Za-z_$][\\w$]*)\\s+from\\s+(["'][^"']+["'])\\s*;?/g,
502
616
  "const $1 = await import($2);"
503
617
  )
618
+ .replace(
619
+ /\\bimport\\s+([A-Za-z_$][\\w$]*)\\s+from\\s+(["'][^"']+["'])\\s*;?/g,
620
+ "const { default: $1 } = await import($2);"
621
+ )
504
622
  .replace(/\\bimport\\s+(["'][^"']+["'])\\s*;?/g, "await import($1);")
505
623
  .replace(/\\bimport\\((["'][^"']+["'])\\)\\s*;?/g, "await import($1);");
506
624
  }
507
625
 
508
- function runModuleScriptAsClassic(script, appOrigin) {
509
- const code = moduleCodeToClassicAsync(script.textContent || "", appOrigin);
626
+ function scriptSourceUrl(script, config) {
627
+ const raw = script.getAttribute("src") || "";
628
+ if (!raw) return "";
629
+ try {
630
+ const url = new URL(raw, config.baseHref);
631
+ if (url.origin === config.origin) {
632
+ if (config.token) url.searchParams.set(config.embedTokenParam, config.token);
633
+ if (config.chatBridgeActive) url.searchParams.set(config.chatBridgeParam, "1");
634
+ }
635
+ return url.toString();
636
+ } catch (_err) {
637
+ return raw;
638
+ }
639
+ }
640
+
641
+ async function moduleScriptCode(script, config) {
642
+ const src = scriptSourceUrl(script, config);
643
+ if (!src) return script.textContent || "";
644
+ const response = await fetch(src, {
645
+ credentials: "omit",
646
+ headers: { Accept: "text/javascript, application/javascript, */*" }
647
+ });
648
+ if (!response.ok) {
649
+ throw new Error("Module script returned HTTP " + response.status + ".");
650
+ }
651
+ return await response.text();
652
+ }
653
+
654
+ async function runModuleScriptAsClassic(script, config) {
655
+ const sourceUrl = scriptSourceUrl(script, config) || config.baseHref;
656
+ const code = moduleCodeToClassicAsync(
657
+ await moduleScriptCode(script, config),
658
+ config,
659
+ sourceUrl
660
+ );
510
661
  const runner = document.createElement("script");
511
662
  runner.textContent =
512
663
  "(async()=>{" +
@@ -516,7 +667,7 @@ export function embedApp(options = {}) {
516
667
  runner.remove();
517
668
  }
518
669
 
519
- function mountTransplantedHtml(html, appUrl) {
670
+ async function mountTransplantedHtml(html, appUrl) {
520
671
  const config = embedConfigForAppUrl(appUrl);
521
672
  installExternalEmbedRuntime(config);
522
673
  const parsed = new DOMParser().parseFromString(
@@ -534,30 +685,69 @@ export function embedApp(options = {}) {
534
685
  if (isRunnableClassicScript(script)) runClassicScript(script);
535
686
  }
536
687
  for (const script of scripts) {
537
- if (isModuleScript(script)) runModuleScriptAsClassic(script, appUrl.origin);
688
+ if (isModuleScript(script)) await runModuleScriptAsClassic(script, config);
538
689
  }
539
690
  }
540
691
 
692
+ function absoluteUrl(value, base) {
693
+ try {
694
+ return new URL(value, base).toString();
695
+ } catch {
696
+ return "";
697
+ }
698
+ }
699
+
700
+ async function resolveTransplantAppDocumentSource(src) {
701
+ if (!isEmbedStartUrl(src)) {
702
+ return { url: new URL(src), response: null };
703
+ }
704
+ const response = await fetch(src, {
705
+ credentials: "omit",
706
+ redirect: "follow",
707
+ headers: {
708
+ Accept: "application/json",
709
+ "X-Agent-Native-Embed-Transplant": "1"
710
+ }
711
+ });
712
+ const contentType = response.headers.get("content-type") || "";
713
+ if (response.ok && /\\bapplication\\/json\\b/i.test(contentType)) {
714
+ const data = await response.json();
715
+ const location = typeof data.location === "string" ? data.location : "";
716
+ const url = absoluteUrl(location, src);
717
+ if (url) return { url: new URL(withChatBridgeParam(url)), response: null };
718
+ throw new Error("Embedded app did not return a launch URL.");
719
+ }
720
+ return {
721
+ url: new URL(response.url || src),
722
+ response
723
+ };
724
+ }
725
+
541
726
  async function transplantAppDocument(src) {
542
727
  clearFrameReadyTimer();
543
728
  clearFrameLoadTimer();
544
729
  appFrame = null;
545
730
  lastFrameSrc = src;
546
731
  setMessage("Loading app");
547
- const response = await fetch(src, {
732
+ const source = await resolveTransplantAppDocumentSource(src);
733
+ const response = source.response || await fetch(source.url.href, {
548
734
  credentials: "omit",
549
735
  redirect: "follow",
550
736
  headers: { Accept: "text/html" }
551
737
  });
552
738
  if (!response.ok) {
739
+ if (response.status === 401 && isEmbedStartUrl(src)) {
740
+ refreshExpiredEmbedSession();
741
+ return;
742
+ }
553
743
  throw new Error("Embedded app returned HTTP " + response.status + ".");
554
744
  }
555
745
  const html = await response.text();
556
- const appUrl = new URL(response.url || src);
746
+ const appUrl = source.url || new URL(response.url || src);
557
747
  try {
558
748
  window.history.replaceState(window.history.state, "", localPathFromUrl(appUrl, false));
559
749
  } catch {}
560
- mountTransplantedHtml(html, appUrl);
750
+ await mountTransplantedHtml(html, appUrl);
561
751
  notifyHostHeightRepeatedly();
562
752
  }
563
753
 
@@ -567,6 +757,28 @@ export function embedApp(options = {}) {
567
757
  return toolInput.embed === true || toolInput.embed === "true";
568
758
  }
569
759
 
760
+ function renderModeSource() {
761
+ const input = objectValue(toolInput);
762
+ const result = objectValue(toolResultData);
763
+ return {
764
+ mode: typeof input.embedMode === "string"
765
+ ? input.embedMode
766
+ : typeof input.renderMode === "string"
767
+ ? input.renderMode
768
+ : typeof result.embedMode === "string"
769
+ ? result.embedMode
770
+ : typeof result.renderMode === "string"
771
+ ? result.renderMode
772
+ : "",
773
+ frame: typeof input.frame === "string"
774
+ ? input.frame
775
+ : typeof result.frame === "string"
776
+ ? result.frame
777
+ : "",
778
+ nested: input.nested === true || result.nested === true
779
+ };
780
+ }
781
+
570
782
  function supportedDisplayMode(mode) {
571
783
  if (openAiBridge && typeof openAiBridge.requestDisplayMode === "function") {
572
784
  return mode === "inline" || mode === "fullscreen" || mode === "pip";
@@ -717,25 +929,19 @@ export function embedApp(options = {}) {
717
929
  }
718
930
 
719
931
  function shouldSelfNavigateToApp() {
720
- const mode = typeof toolInput.embedMode === "string"
721
- ? toolInput.embedMode
722
- : typeof toolInput.renderMode === "string"
723
- ? toolInput.renderMode
724
- : "";
932
+ const render = renderModeSource();
933
+ const mode = render.mode;
725
934
  if (mode === "iframe" || mode === "nested") return false;
726
- if (toolInput.nested === true || toolInput.frame === "iframe") return false;
935
+ if (render.nested || render.frame === "iframe") return false;
727
936
  return true;
728
937
  }
729
938
 
730
939
  function shouldTransplantAppDocument() {
731
- const mode = typeof toolInput.embedMode === "string"
732
- ? toolInput.embedMode
733
- : typeof toolInput.renderMode === "string"
734
- ? toolInput.renderMode
735
- : "";
940
+ const render = renderModeSource();
941
+ const mode = render.mode;
736
942
  return (
737
943
  mode === "transplant" ||
738
- toolInput.frame === "transplant" ||
944
+ render.frame === "transplant" ||
739
945
  isClaudeMcpContentHost()
740
946
  );
741
947
  }
@@ -852,15 +1058,24 @@ export function embedApp(options = {}) {
852
1058
  const message = typeof chat.message === "string" ? chat.message : "";
853
1059
  if (!message.trim()) return;
854
1060
  const context = typeof chat.context === "string" ? chat.context.trim() : "";
1061
+ const content = Array.isArray(chat.content) && chat.content.length
1062
+ ? chat.content
1063
+ : [{ type: "text", text: message }];
855
1064
  try {
856
1065
  if (openAiBridge && typeof openAiBridge.setWidgetState === "function") {
1066
+ const contextContent = context
1067
+ ? [{ type: "text", text: context }, ...content.filter((part) => part && part.type !== "text")]
1068
+ : content.filter((part) => part && part.type !== "text");
857
1069
  openAiBridge.setWidgetState({
858
1070
  ...objectValue(openAiBridge.widgetState),
859
- agentNativeChatContext: context || null
1071
+ agentNativeChatContext: context || null,
1072
+ agentNativeModelContext: { content: contextContent }
860
1073
  });
861
1074
  } else if (app && typeof app.updateModelContext === "function") {
862
1075
  await app.updateModelContext({
863
- content: context ? [{ type: "text", text: context }] : []
1076
+ content: context
1077
+ ? [{ type: "text", text: context }, ...content.filter((part) => part && part.type !== "text")]
1078
+ : content.filter((part) => part && part.type !== "text")
864
1079
  });
865
1080
  }
866
1081
  } catch (err) {
@@ -877,7 +1092,7 @@ export function embedApp(options = {}) {
877
1092
  if (!app || typeof app.sendMessage !== "function") return;
878
1093
  const result = await app.sendMessage({
879
1094
  role: "user",
880
- content: [{ type: "text", text: message }]
1095
+ content
881
1096
  });
882
1097
  if (result && result.isError) {
883
1098
  console.warn("[agent-native] MCP host rejected chat message", result);
@@ -1051,6 +1266,7 @@ export function embedApp(options = {}) {
1051
1266
  toolInput = objectValue(bridge.toolInput);
1052
1267
  const params = openAiToolResultParams(bridge);
1053
1268
  const data = parseToolResult(params);
1269
+ toolResultData = objectValue(data);
1054
1270
  openUrl = openLinkFrom(params, data);
1055
1271
  openStartUrl = embedStartUrlFrom(params, data);
1056
1272
  updateTitle(data);
@@ -1101,6 +1317,7 @@ export function embedApp(options = {}) {
1101
1317
  };
1102
1318
  app.ontoolresult = (params) => {
1103
1319
  const data = parseToolResult(params);
1320
+ toolResultData = objectValue(data);
1104
1321
  openUrl = openLinkFrom(params, data);
1105
1322
  openStartUrl = embedStartUrlFrom(params, data);
1106
1323
  updateTitle(data);