@agent-native/core 0.79.20 → 0.79.22

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 (141) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +16 -0
  3. package/corpus/core/docs/content/deployment.md +133 -0
  4. package/corpus/core/docs/content/faq.md +1 -1
  5. package/corpus/core/docs/content/multi-app-workspace.md +2 -0
  6. package/corpus/core/docs/content/tracking.md +3 -3
  7. package/corpus/core/package.json +1 -1
  8. package/corpus/core/src/agent/engine/openai-compatible-endpoint.ts +25 -0
  9. package/corpus/core/src/agent/engine/provider-env-vars.ts +2 -0
  10. package/corpus/core/src/agent/engine/registry.ts +59 -11
  11. package/corpus/core/src/client/FeedbackButton.tsx +11 -1
  12. package/corpus/core/src/client/agent-engine-key.ts +57 -10
  13. package/corpus/core/src/client/analytics.ts +78 -27
  14. package/corpus/core/src/client/blocks/library/HighlightedCode.tsx +1 -1
  15. package/corpus/core/src/client/index.ts +2 -0
  16. package/corpus/core/src/client/session-replay.ts +159 -17
  17. package/corpus/core/src/client/settings/SettingsPanel.tsx +119 -4
  18. package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +5 -0
  19. package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +8 -3
  20. package/corpus/core/src/scripts/agent-engines/test-agent-engine.ts +54 -6
  21. package/corpus/core/src/server/agent-engine-api-key-route.ts +83 -12
  22. package/corpus/core/src/server/core-routes-plugin.ts +26 -2
  23. package/corpus/core/src/styles/blocks.css +23 -7
  24. package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -1
  25. package/corpus/templates/analytics/app/components/layout/MobileNav.tsx +5 -10
  26. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +22 -4
  27. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +64 -50
  28. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +38 -0
  29. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-sync.ts +89 -0
  30. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +138 -59
  31. package/corpus/templates/analytics/changelog/2026-06-27-dashboard-charts-drag-smoothly-when-rearranging-panels.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-06-27-dashboard-email-reports-still-send-when-the-live-screenshot-.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-06-27-fixed-dashboard-edits-so-charts-no-longer-briefly-snap-back-.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-06-27-session-replay-lists-now-show-only-signed-in-recordings-with.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-06-27-sidebar-loading-placeholders-are-visible-in-light-mode.md +6 -0
  37. package/corpus/templates/analytics/netlify.toml +4 -0
  38. package/corpus/templates/analytics/scripts/seed-session-replay.ts +1 -0
  39. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +1 -0
  40. package/corpus/templates/analytics/server/lib/dashboard-report.ts +120 -29
  41. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +1 -1
  42. package/corpus/templates/analytics/server/lib/session-replay.ts +158 -46
  43. package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
  44. package/corpus/templates/assets/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
  45. package/corpus/templates/clips/app/components/capture-install-options.tsx +0 -9
  46. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +20 -4
  47. package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +6 -2
  48. package/corpus/templates/clips/changelog/2026-06-27-clips-no-longer-shows-desktop-app-prompts-on-mobile-screens.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-06-27-desktop-storage-setup-flow.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-06-27-recorder-download-options-now-show-the-chrome-extension-and-.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-06-27-recorder-setup-mobile-capture-options.md +6 -0
  52. package/corpus/templates/clips/chrome-extension/package.json +1 -1
  53. package/corpus/templates/clips/chrome-extension/src/sentry.ts +17 -1
  54. package/corpus/templates/clips/desktop/package.json +1 -0
  55. package/corpus/templates/clips/desktop/scripts/check-tauri-prereqs.mjs +45 -0
  56. package/corpus/templates/clips/desktop/src/app.tsx +32 -3
  57. package/corpus/templates/clips/desktop/src/lib/sentry.ts +71 -0
  58. package/corpus/templates/clips/desktop/src/main.tsx +2 -0
  59. package/corpus/templates/clips/desktop/src/styles.css +67 -0
  60. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -1
  61. package/corpus/templates/clips/desktop/src-tauri/build.rs +29 -0
  62. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
  63. package/corpus/templates/clips/desktop/src-tauri/src/logfile.rs +1 -0
  64. package/corpus/templates/clips/desktop/src-tauri/src/sentry_report.rs +142 -0
  65. package/corpus/templates/clips/desktop/vite.config.ts +66 -0
  66. package/corpus/templates/design/app/components/layout/Layout.tsx +1 -1
  67. package/corpus/templates/design/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
  68. package/corpus/templates/forms/actions/export-responses.ts +3 -2
  69. package/corpus/templates/forms/actions/list-responses.ts +2 -1
  70. package/corpus/templates/forms/actions/response-insights.ts +13 -4
  71. package/corpus/templates/forms/changelog/2026-06-27-anonymous-feedback-no-longer-shows-internal-agent-native-ano.md +6 -0
  72. package/corpus/templates/forms/server/handlers/submissions.ts +5 -8
  73. package/corpus/templates/forms/server/lib/integrations.ts +9 -6
  74. package/corpus/templates/forms/shared/submitter-email.ts +20 -0
  75. package/corpus/templates/forms/shared/types.ts +1 -1
  76. package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +49 -10
  77. package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
  78. package/corpus/templates/slides/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
  79. package/dist/agent/engine/openai-compatible-endpoint.d.ts +3 -0
  80. package/dist/agent/engine/openai-compatible-endpoint.d.ts.map +1 -0
  81. package/dist/agent/engine/openai-compatible-endpoint.js +23 -0
  82. package/dist/agent/engine/openai-compatible-endpoint.js.map +1 -0
  83. package/dist/agent/engine/provider-env-vars.d.ts +1 -0
  84. package/dist/agent/engine/provider-env-vars.d.ts.map +1 -1
  85. package/dist/agent/engine/provider-env-vars.js +1 -0
  86. package/dist/agent/engine/provider-env-vars.js.map +1 -1
  87. package/dist/agent/engine/registry.d.ts.map +1 -1
  88. package/dist/agent/engine/registry.js +39 -12
  89. package/dist/agent/engine/registry.js.map +1 -1
  90. package/dist/client/FeedbackButton.d.ts.map +1 -1
  91. package/dist/client/FeedbackButton.js +6 -1
  92. package/dist/client/FeedbackButton.js.map +1 -1
  93. package/dist/client/agent-engine-key.d.ts +14 -0
  94. package/dist/client/agent-engine-key.d.ts.map +1 -1
  95. package/dist/client/agent-engine-key.js +35 -10
  96. package/dist/client/agent-engine-key.js.map +1 -1
  97. package/dist/client/analytics.d.ts.map +1 -1
  98. package/dist/client/analytics.js +71 -24
  99. package/dist/client/analytics.js.map +1 -1
  100. package/dist/client/blocks/library/HighlightedCode.d.ts +1 -1
  101. package/dist/client/blocks/library/HighlightedCode.js +1 -1
  102. package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
  103. package/dist/client/index.d.ts +1 -1
  104. package/dist/client/index.d.ts.map +1 -1
  105. package/dist/client/index.js +1 -1
  106. package/dist/client/index.js.map +1 -1
  107. package/dist/client/session-replay.d.ts +1 -1
  108. package/dist/client/session-replay.d.ts.map +1 -1
  109. package/dist/client/session-replay.js +115 -17
  110. package/dist/client/session-replay.js.map +1 -1
  111. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  112. package/dist/client/settings/SettingsPanel.js +42 -6
  113. package/dist/client/settings/SettingsPanel.js.map +1 -1
  114. package/dist/collab/routes.d.ts +2 -2
  115. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  116. package/dist/notifications/routes.d.ts +1 -1
  117. package/dist/observability/routes.d.ts +7 -7
  118. package/dist/progress/routes.d.ts +1 -1
  119. package/dist/resources/handlers.d.ts +1 -1
  120. package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -1
  121. package/dist/scripts/agent-engines/manage-agent-engine.js +4 -0
  122. package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
  123. package/dist/scripts/agent-engines/set-agent-engine.d.ts.map +1 -1
  124. package/dist/scripts/agent-engines/set-agent-engine.js +5 -4
  125. package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
  126. package/dist/scripts/agent-engines/test-agent-engine.d.ts.map +1 -1
  127. package/dist/scripts/agent-engines/test-agent-engine.js +37 -5
  128. package/dist/scripts/agent-engines/test-agent-engine.js.map +1 -1
  129. package/dist/server/agent-engine-api-key-route.d.ts +5 -5
  130. package/dist/server/agent-engine-api-key-route.d.ts.map +1 -1
  131. package/dist/server/agent-engine-api-key-route.js +71 -11
  132. package/dist/server/agent-engine-api-key-route.js.map +1 -1
  133. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  134. package/dist/server/core-routes-plugin.js +20 -3
  135. package/dist/server/core-routes-plugin.js.map +1 -1
  136. package/dist/styles/blocks.css +23 -7
  137. package/docs/content/deployment.md +133 -0
  138. package/docs/content/faq.md +1 -1
  139. package/docs/content/multi-app-workspace.md +2 -0
  140. package/docs/content/tracking.md +3 -3
  141. package/package.json +1 -1
@@ -15,6 +15,18 @@ const PROVIDER_ENV_VAR = {
15
15
  };
16
16
  /** Event other parts of the agent UI listen for to re-check the LLM gate. */
17
17
  const CONFIGURED_CHANGED_EVENT = "agent-engine:configured-changed";
18
+ function resolveProviderEnvVar(provider, key) {
19
+ const envVar = key?.trim() || (provider ? PROVIDER_ENV_VAR[provider] : "");
20
+ if (!envVar) {
21
+ throw new Error("Choose an API key provider first.");
22
+ }
23
+ return envVar;
24
+ }
25
+ function dispatchConfiguredChanged() {
26
+ if (typeof window !== "undefined") {
27
+ window.dispatchEvent(new CustomEvent(CONFIGURED_CHANGED_EVENT));
28
+ }
29
+ }
18
30
  /**
19
31
  * Persist a provider API key for the current owner. Resolves on success.
20
32
  * Throws an Error with a readable message on failure. On success it also
@@ -22,18 +34,33 @@ const CONFIGURED_CHANGED_EVENT = "agent-engine:configured-changed";
22
34
  * out of its "needs setup" state without a reload.
23
35
  */
24
36
  export async function saveAgentEngineApiKey({ provider, key, apiKey, scope, }) {
25
- const trimmed = apiKey.trim();
26
- if (!trimmed) {
37
+ if (!apiKey.trim()) {
27
38
  throw new Error("Enter an API key first.");
28
39
  }
29
- const envVar = key?.trim() || (provider ? PROVIDER_ENV_VAR[provider] : "");
30
- if (!envVar) {
31
- throw new Error("Choose an API key provider first.");
40
+ await saveAgentEngineProviderSettings({ provider, key, apiKey, scope });
41
+ }
42
+ /**
43
+ * Persist provider-specific settings for the current owner. This intentionally
44
+ * stays narrow: API keys for built-in BYOK providers, plus OpenAI's optional
45
+ * compatible endpoint URL. Values are stored server-side in scoped secrets.
46
+ */
47
+ export async function saveAgentEngineProviderSettings({ provider, key, apiKey, baseUrl, clearBaseUrl, scope, }) {
48
+ const trimmed = apiKey?.trim() ?? "";
49
+ const endpoint = baseUrl?.trim() ?? "";
50
+ if (!trimmed && !endpoint && !clearBaseUrl) {
51
+ throw new Error("Enter an API key or endpoint URL first.");
32
52
  }
53
+ const envVar = resolveProviderEnvVar(provider, key);
33
54
  const res = await fetch(agentNativePath("/_agent-native/agent-engine/api-key"), {
34
55
  method: "POST",
35
56
  headers: { "Content-Type": "application/json" },
36
- body: JSON.stringify({ key: envVar, value: trimmed, scope }),
57
+ body: JSON.stringify({
58
+ key: envVar,
59
+ ...(trimmed ? { value: trimmed } : {}),
60
+ ...(endpoint ? { baseUrl: endpoint } : {}),
61
+ ...(clearBaseUrl ? { clearBaseUrl: true } : {}),
62
+ scope,
63
+ }),
37
64
  });
38
65
  if (!res.ok) {
39
66
  const message = await res
@@ -43,10 +70,8 @@ export async function saveAgentEngineApiKey({ provider, key, apiKey, scope, }) {
43
70
  throw new Error(message ??
44
71
  (res.status === 401
45
72
  ? "Sign in to save a key, or connect Builder instead."
46
- : `Could not save the key (HTTP ${res.status}).`));
47
- }
48
- if (typeof window !== "undefined") {
49
- window.dispatchEvent(new CustomEvent(CONFIGURED_CHANGED_EVENT));
73
+ : `Could not save provider settings (HTTP ${res.status}).`));
50
74
  }
75
+ dispatchConfiguredChanged();
51
76
  }
52
77
  //# sourceMappingURL=agent-engine-key.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-engine-key.js","sourceRoot":"","sources":["../../src/client/agent-engine-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAKhD,MAAM,gBAAgB,GAAwC;IAC5D,SAAS,EAAE,mBAAmB;IAC9B,MAAM,EAAE,gBAAgB;CACzB,CAAC;AAEF,6EAA6E;AAC7E,MAAM,wBAAwB,GAAG,iCAAiC,CAAC;AASnE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,EAC1C,QAAQ,EACR,GAAG,EACH,MAAM,EACN,KAAK,GACwB;IAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CAAC,qCAAqC,CAAC,EACtD;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;KAC7D,CACF,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,MAAM,GAAG;aACtB,IAAI,EAAE;aACN,IAAI,CAAC,CAAC,IAAwB,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;aAC/C,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,OAAO;YACL,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG;gBACjB,CAAC,CAAC,oDAAoD;gBACtD,CAAC,CAAC,gCAAgC,GAAG,CAAC,MAAM,IAAI,CAAC,CACtD,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAClE,CAAC;AACH,CAAC","sourcesContent":["/**\n * Agent engine API-key helpers (browser).\n *\n * Named client helper for storing a bring-your-own provider key (Anthropic,\n * OpenAI, etc.) so the agent chat can run without a Builder connection or an\n * account. The key is persisted by the framework under the matching provider\n * key (e.g. ANTHROPIC_API_KEY) for the current user or org, exactly like the\n * LLM settings panel does — UI code should call this instead of hand-writing\n * a fetch to framework routes.\n */\n\nimport { agentNativePath } from \"./api-path.js\";\n\n/** Providers that can be configured with a single pasted API key. */\nexport type AgentEngineProvider = \"anthropic\" | \"openai\";\n\nconst PROVIDER_ENV_VAR: Record<AgentEngineProvider, string> = {\n anthropic: \"ANTHROPIC_API_KEY\",\n openai: \"OPENAI_API_KEY\",\n};\n\n/** Event other parts of the agent UI listen for to re-check the LLM gate. */\nconst CONFIGURED_CHANGED_EVENT = \"agent-engine:configured-changed\";\n\nexport interface SaveAgentEngineApiKeyOptions {\n provider?: AgentEngineProvider;\n key?: string;\n apiKey: string;\n scope?: \"user\" | \"org\";\n}\n\n/**\n * Persist a provider API key for the current owner. Resolves on success.\n * Throws an Error with a readable message on failure. On success it also\n * dispatches `agent-engine:configured-changed` so any open agent chat flips\n * out of its \"needs setup\" state without a reload.\n */\nexport async function saveAgentEngineApiKey({\n provider,\n key,\n apiKey,\n scope,\n}: SaveAgentEngineApiKeyOptions): Promise<void> {\n const trimmed = apiKey.trim();\n if (!trimmed) {\n throw new Error(\"Enter an API key first.\");\n }\n const envVar = key?.trim() || (provider ? PROVIDER_ENV_VAR[provider] : \"\");\n if (!envVar) {\n throw new Error(\"Choose an API key provider first.\");\n }\n const res = await fetch(\n agentNativePath(\"/_agent-native/agent-engine/api-key\"),\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ key: envVar, value: trimmed, scope }),\n },\n );\n if (!res.ok) {\n const message = await res\n .json()\n .then((body: { error?: string }) => body?.error)\n .catch(() => null);\n throw new Error(\n message ??\n (res.status === 401\n ? \"Sign in to save a key, or connect Builder instead.\"\n : `Could not save the key (HTTP ${res.status}).`),\n );\n }\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(CONFIGURED_CHANGED_EVENT));\n }\n}\n"]}
1
+ {"version":3,"file":"agent-engine-key.js","sourceRoot":"","sources":["../../src/client/agent-engine-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAKhD,MAAM,gBAAgB,GAAwC;IAC5D,SAAS,EAAE,mBAAmB;IAC9B,MAAM,EAAE,gBAAgB;CACzB,CAAC;AAEF,6EAA6E;AAC7E,MAAM,wBAAwB,GAAG,iCAAiC,CAAC;AAkBnE,SAAS,qBAAqB,CAC5B,QAAyC,EACzC,GAAuB;IAEvB,MAAM,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,yBAAyB;IAChC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,EAC1C,QAAQ,EACR,GAAG,EACH,MAAM,EACN,KAAK,GACwB;IAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,+BAA+B,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,EACpD,QAAQ,EACR,GAAG,EACH,MAAM,EACN,OAAO,EACP,YAAY,EACZ,KAAK,GACkC;IACvC,MAAM,OAAO,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CAAC,qCAAqC,CAAC,EACtD;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,GAAG,EAAE,MAAM;YACX,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,KAAK;SACN,CAAC;KACH,CACF,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,MAAM,GAAG;aACtB,IAAI,EAAE;aACN,IAAI,CAAC,CAAC,IAAwB,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;aAC/C,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,OAAO;YACL,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG;gBACjB,CAAC,CAAC,oDAAoD;gBACtD,CAAC,CAAC,0CAA0C,GAAG,CAAC,MAAM,IAAI,CAAC,CAChE,CAAC;IACJ,CAAC;IACD,yBAAyB,EAAE,CAAC;AAC9B,CAAC","sourcesContent":["/**\n * Agent engine API-key helpers (browser).\n *\n * Named client helper for storing a bring-your-own provider key (Anthropic,\n * OpenAI, etc.) so the agent chat can run without a Builder connection or an\n * account. The key is persisted by the framework under the matching provider\n * key (e.g. ANTHROPIC_API_KEY) for the current user or org, exactly like the\n * LLM settings panel does — UI code should call this instead of hand-writing\n * a fetch to framework routes.\n */\n\nimport { agentNativePath } from \"./api-path.js\";\n\n/** Providers that can be configured with a single pasted API key. */\nexport type AgentEngineProvider = \"anthropic\" | \"openai\";\n\nconst PROVIDER_ENV_VAR: Record<AgentEngineProvider, string> = {\n anthropic: \"ANTHROPIC_API_KEY\",\n openai: \"OPENAI_API_KEY\",\n};\n\n/** Event other parts of the agent UI listen for to re-check the LLM gate. */\nconst CONFIGURED_CHANGED_EVENT = \"agent-engine:configured-changed\";\n\nexport interface SaveAgentEngineApiKeyOptions {\n provider?: AgentEngineProvider;\n key?: string;\n apiKey: string;\n scope?: \"user\" | \"org\";\n}\n\nexport interface SaveAgentEngineProviderSettingsOptions {\n provider?: AgentEngineProvider;\n key?: string;\n apiKey?: string;\n baseUrl?: string;\n clearBaseUrl?: boolean;\n scope?: \"user\" | \"org\";\n}\n\nfunction resolveProviderEnvVar(\n provider: AgentEngineProvider | undefined,\n key: string | undefined,\n): string {\n const envVar = key?.trim() || (provider ? PROVIDER_ENV_VAR[provider] : \"\");\n if (!envVar) {\n throw new Error(\"Choose an API key provider first.\");\n }\n return envVar;\n}\n\nfunction dispatchConfiguredChanged(): void {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(CONFIGURED_CHANGED_EVENT));\n }\n}\n\n/**\n * Persist a provider API key for the current owner. Resolves on success.\n * Throws an Error with a readable message on failure. On success it also\n * dispatches `agent-engine:configured-changed` so any open agent chat flips\n * out of its \"needs setup\" state without a reload.\n */\nexport async function saveAgentEngineApiKey({\n provider,\n key,\n apiKey,\n scope,\n}: SaveAgentEngineApiKeyOptions): Promise<void> {\n if (!apiKey.trim()) {\n throw new Error(\"Enter an API key first.\");\n }\n await saveAgentEngineProviderSettings({ provider, key, apiKey, scope });\n}\n\n/**\n * Persist provider-specific settings for the current owner. This intentionally\n * stays narrow: API keys for built-in BYOK providers, plus OpenAI's optional\n * compatible endpoint URL. Values are stored server-side in scoped secrets.\n */\nexport async function saveAgentEngineProviderSettings({\n provider,\n key,\n apiKey,\n baseUrl,\n clearBaseUrl,\n scope,\n}: SaveAgentEngineProviderSettingsOptions): Promise<void> {\n const trimmed = apiKey?.trim() ?? \"\";\n const endpoint = baseUrl?.trim() ?? \"\";\n if (!trimmed && !endpoint && !clearBaseUrl) {\n throw new Error(\"Enter an API key or endpoint URL first.\");\n }\n const envVar = resolveProviderEnvVar(provider, key);\n const res = await fetch(\n agentNativePath(\"/_agent-native/agent-engine/api-key\"),\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n key: envVar,\n ...(trimmed ? { value: trimmed } : {}),\n ...(endpoint ? { baseUrl: endpoint } : {}),\n ...(clearBaseUrl ? { clearBaseUrl: true } : {}),\n scope,\n }),\n },\n );\n if (!res.ok) {\n const message = await res\n .json()\n .then((body: { error?: string }) => body?.error)\n .catch(() => null);\n throw new Error(\n message ??\n (res.status === 401\n ? \"Sign in to save a key, or connect Builder instead.\"\n : `Could not save provider settings (HTTP ${res.status}).`),\n );\n }\n dispatchConfiguredChanged();\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/client/analytics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/client/analytics.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,9 @@ let _trackingIdentity = null;
16
16
  let _trackingIdentityResolved = false;
17
17
  let _trackingSessionRefresh = null;
18
18
  let _trackingSessionRefreshInstalled = false;
19
+ let _sessionReplayOptions = null;
20
+ let _sessionReplayIdentitySnapshot = null;
21
+ let _sessionReplayStartPromise = null;
19
22
  // Buffer for setSentryUser calls made before Sentry has initialized.
20
23
  // `undefined` means "no pending update"; `null` means "pending clear".
21
24
  let _pendingSentryUser = undefined;
@@ -171,17 +174,41 @@ function installLlmConnectionRefresh() {
171
174
  function readTrackingString(value) {
172
175
  return typeof value === "string" && value.trim() ? value.trim() : undefined;
173
176
  }
177
+ function stopSessionReplayForAuthClear(previousIdentity) {
178
+ if (!_sessionReplayOptions?.requireSignedInUser) {
179
+ _sessionReplayIdentitySnapshot = null;
180
+ return;
181
+ }
182
+ if (!previousIdentity?.userEmail)
183
+ return;
184
+ _sessionReplayIdentitySnapshot = previousIdentity;
185
+ void import("./session-replay.js")
186
+ .then((mod) => mod.stopSessionReplay("auth-cleared"))
187
+ .catch(() => {
188
+ // Auth clearing should never fail because replay cleanup failed.
189
+ })
190
+ .finally(() => {
191
+ if (_sessionReplayIdentitySnapshot === previousIdentity) {
192
+ _sessionReplayIdentitySnapshot = null;
193
+ }
194
+ });
195
+ }
196
+ function clearTrackingIdentity() {
197
+ const previousIdentity = _trackingIdentity;
198
+ stopSessionReplayForAuthClear(previousIdentity);
199
+ _trackingIdentity = null;
200
+ }
174
201
  function setTrackingIdentityFromSession(data) {
175
202
  const session = data;
176
203
  if (!session || typeof session !== "object" || session.error) {
177
- _trackingIdentity = null;
204
+ clearTrackingIdentity();
178
205
  return;
179
206
  }
180
207
  const email = readTrackingString(session.email);
181
208
  const authUserId = readTrackingString(session.userId);
182
209
  const userId = email || authUserId;
183
210
  if (!userId) {
184
- _trackingIdentity = null;
211
+ clearTrackingIdentity();
185
212
  return;
186
213
  }
187
214
  const userName = readTrackingString(session.name);
@@ -205,7 +232,7 @@ function refreshTrackingAuthSession() {
205
232
  setTrackingIdentityFromSession(data);
206
233
  })
207
234
  .catch(() => {
208
- _trackingIdentity = null;
235
+ clearTrackingIdentity();
209
236
  })
210
237
  .finally(() => {
211
238
  _trackingIdentityResolved = true;
@@ -222,8 +249,7 @@ function installTrackingAuthSessionRefresh() {
222
249
  void refreshTrackingAuthSession();
223
250
  });
224
251
  }
225
- function applyTrackingIdentity(properties) {
226
- const identity = _trackingIdentity;
252
+ function applyTrackingIdentity(properties, identity = _trackingIdentity) {
227
253
  if (!identity)
228
254
  return properties;
229
255
  let next = properties;
@@ -633,21 +659,29 @@ function ensureSentry() {
633
659
  * for filtering Sentry by tenant.
634
660
  */
635
661
  export function setSentryUser(user, orgId) {
662
+ let shouldRetryReplay = false;
636
663
  if (user) {
637
664
  const userId = user.email || user.id;
638
- _trackingIdentity = userId
639
- ? {
665
+ if (userId) {
666
+ _trackingIdentity = {
640
667
  userId,
641
668
  ...(user.email ? { userEmail: user.email } : {}),
642
669
  ...(user.username ? { userName: user.username } : {}),
643
670
  orgId: orgId ?? null,
644
- }
645
- : null;
671
+ };
672
+ }
673
+ else {
674
+ clearTrackingIdentity();
675
+ }
676
+ shouldRetryReplay = Boolean(user.email);
646
677
  }
647
678
  else {
648
- _trackingIdentity = null;
679
+ clearTrackingIdentity();
649
680
  }
650
681
  _trackingIdentityResolved = true;
682
+ if (shouldRetryReplay && _sessionReplayOptions?.requireSignedInUser) {
683
+ void startConfiguredSessionReplay(_sessionReplayOptions);
684
+ }
651
685
  if (_sentryInitialized) {
652
686
  Sentry.setUser(user);
653
687
  if (orgId !== undefined) {
@@ -753,7 +787,14 @@ function sessionReplayRequiresSignedInUserFromEnv() {
753
787
  const env = import.meta.env ?? {};
754
788
  const value = env.VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH ||
755
789
  env.VITE_SESSION_REPLAY_REQUIRE_AUTH;
756
- return /^(1|true|yes|on)$/i.test((value ?? "").trim());
790
+ const normalized = (value ?? "").trim();
791
+ if (!normalized)
792
+ return undefined;
793
+ if (/^(1|true|yes|on)$/i.test(normalized))
794
+ return true;
795
+ if (/^(0|false|no|off)$/i.test(normalized))
796
+ return false;
797
+ return undefined;
757
798
  }
758
799
  function configuredSessionReplayOptions(config, tracking = {}) {
759
800
  const publicKey = tracking.publicKey || _agentNativeAnalyticsPublicKey;
@@ -768,7 +809,8 @@ function configuredSessionReplayOptions(config, tracking = {}) {
768
809
  ...(endpoint && !options.endpoint ? { endpoint } : {}),
769
810
  ...options,
770
811
  requireSignedInUser: options.requireSignedInUser ??
771
- sessionReplayRequiresSignedInUserFromEnv(),
812
+ sessionReplayRequiresSignedInUserFromEnv() ??
813
+ true,
772
814
  ...(extraProperties ? { extraProperties } : {}),
773
815
  };
774
816
  };
@@ -792,7 +834,7 @@ function replayExtraPropertiesWithDefaults(source) {
792
834
  : {};
793
835
  const props = rawProps && typeof rawProps === "object" ? rawProps : {};
794
836
  const withDefaults = _getDefaultProps?.("session_replay", props) ?? props;
795
- return applyTrackingIdentity(withDefaults);
837
+ return applyTrackingIdentity(withDefaults, _trackingIdentity ?? _sessionReplayIdentitySnapshot);
796
838
  };
797
839
  }
798
840
  function replayEndpointFromTrackingEndpoint(value) {
@@ -824,12 +866,13 @@ function maybeInstallSessionReplay(config, tracking) {
824
866
  const options = configuredSessionReplayOptions(config, tracking);
825
867
  if (!options)
826
868
  return;
869
+ _sessionReplayOptions = options;
827
870
  void startConfiguredSessionReplay(options);
828
871
  }
829
872
  async function waitForSessionReplayAuthIfRequired(options) {
830
873
  if (!options.requireSignedInUser)
831
874
  return true;
832
- if (_trackingIdentity?.userId)
875
+ if (_trackingIdentity?.userEmail)
833
876
  return true;
834
877
  try {
835
878
  if (_trackingSessionRefresh) {
@@ -842,19 +885,23 @@ async function waitForSessionReplayAuthIfRequired(options) {
842
885
  catch {
843
886
  // best-effort; missing identity below keeps replay off
844
887
  }
845
- return !!_trackingIdentity?.userId;
888
+ return !!_trackingIdentity?.userEmail;
846
889
  }
847
890
  async function startConfiguredSessionReplay(options) {
848
- if (!(await waitForSessionReplayAuthIfRequired(options))) {
849
- return { started: false, reason: "missing-user-id" };
850
- }
851
- try {
891
+ if (_sessionReplayStartPromise)
892
+ return _sessionReplayStartPromise;
893
+ _sessionReplayStartPromise = (async () => {
894
+ if (!(await waitForSessionReplayAuthIfRequired(options))) {
895
+ return { started: false, reason: "missing-user-id" };
896
+ }
852
897
  const mod = await import("./session-replay.js");
853
898
  return mod.startSessionReplay(options);
854
- }
855
- catch {
856
- return { started: false, reason: "import-failed" };
857
- }
899
+ })()
900
+ .catch(() => ({ started: false, reason: "import-failed" }))
901
+ .finally(() => {
902
+ _sessionReplayStartPromise = null;
903
+ });
904
+ return _sessionReplayStartPromise;
858
905
  }
859
906
  export async function startSessionReplay(options = {}) {
860
907
  const configured = configuredSessionReplayOptions(options) ?? options;
@@ -874,7 +921,7 @@ export async function maybeStartSessionReplay(options = {}) {
874
921
  }
875
922
  export async function stopSessionReplay(reason = "manual") {
876
923
  const mod = await import("./session-replay.js");
877
- mod.stopSessionReplay(reason);
924
+ await mod.stopSessionReplay(reason);
878
925
  }
879
926
  function inferTemplateName(properties) {
880
927
  const envTemplate = import.meta.env