@agent-native/core 0.98.3 → 0.98.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 (230) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +29 -0
  3. package/corpus/core/docs/content/durable-background-runs.mdx +37 -0
  4. package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +2 -0
  5. package/corpus/core/docs/content/locales/de-DE/tracking.mdx +2 -0
  6. package/corpus/core/docs/content/locales/es-ES/tracking.mdx +2 -0
  7. package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +4 -2
  8. package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +2 -0
  9. package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +2 -0
  10. package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +2 -0
  11. package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +2 -0
  12. package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +2 -0
  13. package/corpus/core/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
  14. package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +2 -0
  15. package/corpus/core/docs/content/tracking.mdx +2 -0
  16. package/corpus/core/package.json +1 -1
  17. package/corpus/core/src/agent/durable-background.ts +16 -16
  18. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +25 -8
  19. package/corpus/core/src/agent/engine/anthropic-engine.ts +17 -3
  20. package/corpus/core/src/agent/engine/output-tokens.ts +6 -6
  21. package/corpus/core/src/agent/production-agent.ts +200 -27
  22. package/corpus/core/src/agent/run-manager.ts +81 -1
  23. package/corpus/core/src/agent/run-store.ts +301 -41
  24. package/corpus/core/src/client/AgentPanel.tsx +6 -2
  25. package/corpus/core/src/client/AssistantChat.tsx +364 -69
  26. package/corpus/core/src/client/agent-chat-adapter.ts +169 -1
  27. package/corpus/core/src/client/analytics.ts +12 -0
  28. package/corpus/core/src/client/chat/message-components.tsx +3 -0
  29. package/corpus/core/src/client/chat/tool-call-display.tsx +20 -36
  30. package/corpus/core/src/client/conversation/use-near-bottom-autoscroll.ts +7 -0
  31. package/corpus/core/src/client/extensions/AgentNativeExtensionFrame.tsx +2 -0
  32. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +2 -0
  33. package/corpus/core/src/client/extensions/ExtensionEditor.tsx +9 -2
  34. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +2 -0
  35. package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +2 -0
  36. package/corpus/core/src/client/extensions/portable-extension.ts +2 -0
  37. package/corpus/core/src/client/session-replay.ts +971 -53
  38. package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -3
  39. package/corpus/core/src/client/sse-event-processor.ts +43 -1
  40. package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
  41. package/corpus/core/src/demo/config.ts +6 -6
  42. package/corpus/core/src/demo/fetch-interceptor.ts +34 -2
  43. package/corpus/core/src/demo/redact.ts +71 -158
  44. package/corpus/core/src/extensions/html-shell.ts +3 -0
  45. package/corpus/core/src/extensions/session-replay-iframe.ts +131 -0
  46. package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -20
  47. package/corpus/core/src/session-replay-iframe-protocol.ts +58 -0
  48. package/corpus/core/src/shared/reasoning-effort.ts +35 -0
  49. package/corpus/core/src/styles/agent-conversation.css +26 -0
  50. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
  51. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +67 -16
  52. package/corpus/templates/analytics/AGENTS.md +12 -0
  53. package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
  54. package/corpus/templates/analytics/actions/get-session-replay-events.ts +1 -0
  55. package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
  56. package/corpus/templates/analytics/actions/list-error-issues.ts +1 -0
  57. package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
  58. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -1
  59. package/corpus/templates/analytics/app/global.css +6 -64
  60. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +41 -4
  61. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +143 -121
  62. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +34 -12
  63. package/corpus/templates/analytics/changelog/2026-07-12-analytics-chat-retries-before-showing-a-generic-no-data-mess.md +6 -0
  64. package/corpus/templates/analytics/changelog/2026-07-12-analytics-sessions-search-no-longer-loses-fast-keystrokes-an.md +6 -0
  65. package/corpus/templates/analytics/changelog/2026-07-12-chart-selection-respects-chat-state.md +6 -0
  66. package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-anonymizes-error-reporting-emails.md +6 -0
  67. package/corpus/templates/analytics/changelog/2026-07-12-fixed-session-replays-that-appeared-ultra-wide-hid-recorded-.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-load-faster-in-demo-mode-while-visitor-email.md +6 -0
  69. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-show-iframe-content.md +6 -0
  70. package/corpus/templates/analytics/netlify.toml +0 -3
  71. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +14 -0
  72. package/corpus/templates/analytics/server/lib/error-capture.ts +59 -2
  73. package/corpus/templates/analytics/server/lib/real-data-actions.ts +24 -0
  74. package/corpus/templates/analytics/server/lib/session-replay.ts +2 -9
  75. package/corpus/templates/analytics/server/plugins/agent-chat.ts +39 -6
  76. package/corpus/templates/assets/app/global.css +1 -1
  77. package/corpus/templates/brain/app/global.css +2 -2
  78. package/corpus/templates/brain/changelog/2026-07-12-fix-long-response-progress.md +6 -0
  79. package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +11 -2
  80. package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +14 -2
  81. package/corpus/templates/calendar/changelog/2026-07-12-calendar-responses-can-now-be-saved-with-command-enter-or-ct.md +6 -0
  82. package/corpus/templates/forms/app/components/CloudUpgrade.tsx +1 -1
  83. package/corpus/templates/forms/app/components/ThemeToggle.tsx +22 -6
  84. package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +5 -5
  85. package/corpus/templates/forms/app/components/builder/FieldRenderer.tsx +3 -3
  86. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +16 -16
  87. package/corpus/templates/forms/app/global.css +110 -5
  88. package/corpus/templates/forms/app/pages/AskPage.tsx +3 -3
  89. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +134 -52
  90. package/corpus/templates/forms/app/pages/FormFillPage.tsx +44 -11
  91. package/corpus/templates/forms/app/pages/FormsListPage.tsx +42 -24
  92. package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +28 -15
  93. package/corpus/templates/forms/app/pages/ResponsesPage.tsx +38 -15
  94. package/corpus/templates/forms/app/routes/_app.settings.tsx +1 -1
  95. package/corpus/templates/forms/changelog/2026-07-12-form-builder-surfaces-are-calmer-fields-stay-stable-on-hover.md +6 -0
  96. package/corpus/templates/forms/changelog/2026-07-12-smoother-more-tactile-controls-throughout-animated-icon-and-.md +6 -0
  97. package/corpus/templates/mail/app/components/email/EmailThread.tsx +21 -13
  98. package/corpus/templates/mail/app/components/email/email-iframe-document.ts +18 -0
  99. package/dist/agent/durable-background.d.ts +10 -10
  100. package/dist/agent/durable-background.d.ts.map +1 -1
  101. package/dist/agent/durable-background.js +16 -16
  102. package/dist/agent/durable-background.js.map +1 -1
  103. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  104. package/dist/agent/engine/ai-sdk-engine.js +19 -8
  105. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  106. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  107. package/dist/agent/engine/anthropic-engine.js +11 -3
  108. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  109. package/dist/agent/engine/output-tokens.js +6 -6
  110. package/dist/agent/engine/output-tokens.js.map +1 -1
  111. package/dist/agent/production-agent.d.ts +52 -0
  112. package/dist/agent/production-agent.d.ts.map +1 -1
  113. package/dist/agent/production-agent.js +154 -26
  114. package/dist/agent/production-agent.js.map +1 -1
  115. package/dist/agent/run-manager.d.ts +9 -0
  116. package/dist/agent/run-manager.d.ts.map +1 -1
  117. package/dist/agent/run-manager.js +71 -1
  118. package/dist/agent/run-manager.js.map +1 -1
  119. package/dist/agent/run-store.d.ts +9 -0
  120. package/dist/agent/run-store.d.ts.map +1 -1
  121. package/dist/agent/run-store.js +243 -48
  122. package/dist/agent/run-store.js.map +1 -1
  123. package/dist/client/AgentPanel.d.ts.map +1 -1
  124. package/dist/client/AgentPanel.js +6 -2
  125. package/dist/client/AgentPanel.js.map +1 -1
  126. package/dist/client/AssistantChat.d.ts +21 -0
  127. package/dist/client/AssistantChat.d.ts.map +1 -1
  128. package/dist/client/AssistantChat.js +298 -67
  129. package/dist/client/AssistantChat.js.map +1 -1
  130. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  131. package/dist/client/agent-chat-adapter.js +146 -1
  132. package/dist/client/agent-chat-adapter.js.map +1 -1
  133. package/dist/client/analytics.d.ts.map +1 -1
  134. package/dist/client/analytics.js +11 -0
  135. package/dist/client/analytics.js.map +1 -1
  136. package/dist/client/chat/message-components.d.ts.map +1 -1
  137. package/dist/client/chat/message-components.js +2 -1
  138. package/dist/client/chat/message-components.js.map +1 -1
  139. package/dist/client/chat/tool-call-display.d.ts +3 -1
  140. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  141. package/dist/client/chat/tool-call-display.js +13 -37
  142. package/dist/client/chat/tool-call-display.js.map +1 -1
  143. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +1 -0
  144. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
  145. package/dist/client/conversation/use-near-bottom-autoscroll.js +6 -0
  146. package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
  147. package/dist/client/extensions/AgentNativeExtensionFrame.d.ts.map +1 -1
  148. package/dist/client/extensions/AgentNativeExtensionFrame.js +2 -1
  149. package/dist/client/extensions/AgentNativeExtensionFrame.js.map +1 -1
  150. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  151. package/dist/client/extensions/EmbeddedExtension.js +2 -1
  152. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  153. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
  154. package/dist/client/extensions/ExtensionEditor.js +5 -2
  155. package/dist/client/extensions/ExtensionEditor.js.map +1 -1
  156. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  157. package/dist/client/extensions/ExtensionViewer.js +2 -1
  158. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  159. package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
  160. package/dist/client/extensions/InlineExtensionFrame.js +2 -1
  161. package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
  162. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  163. package/dist/client/extensions/portable-extension.js +2 -0
  164. package/dist/client/extensions/portable-extension.js.map +1 -1
  165. package/dist/client/session-replay.d.ts +12 -3
  166. package/dist/client/session-replay.d.ts.map +1 -1
  167. package/dist/client/session-replay.js +793 -49
  168. package/dist/client/session-replay.js.map +1 -1
  169. package/dist/client/settings/DemoModeSection.js +1 -1
  170. package/dist/client/settings/DemoModeSection.js.map +1 -1
  171. package/dist/client/sse-event-processor.d.ts +5 -0
  172. package/dist/client/sse-event-processor.d.ts.map +1 -1
  173. package/dist/client/sse-event-processor.js +37 -1
  174. package/dist/client/sse-event-processor.js.map +1 -1
  175. package/dist/demo/actions/toggle-demo-mode.js +2 -2
  176. package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
  177. package/dist/demo/config.js +6 -6
  178. package/dist/demo/config.js.map +1 -1
  179. package/dist/demo/fetch-interceptor.d.ts +1 -0
  180. package/dist/demo/fetch-interceptor.d.ts.map +1 -1
  181. package/dist/demo/fetch-interceptor.js +28 -2
  182. package/dist/demo/fetch-interceptor.js.map +1 -1
  183. package/dist/demo/redact.d.ts +14 -7
  184. package/dist/demo/redact.d.ts.map +1 -1
  185. package/dist/demo/redact.js +27 -155
  186. package/dist/demo/redact.js.map +1 -1
  187. package/dist/extensions/html-shell.d.ts.map +1 -1
  188. package/dist/extensions/html-shell.js +2 -0
  189. package/dist/extensions/html-shell.js.map +1 -1
  190. package/dist/extensions/session-replay-iframe.d.ts +10 -0
  191. package/dist/extensions/session-replay-iframe.d.ts.map +1 -0
  192. package/dist/extensions/session-replay-iframe.js +121 -0
  193. package/dist/extensions/session-replay-iframe.js.map +1 -0
  194. package/dist/notifications/routes.d.ts +1 -1
  195. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  196. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  197. package/dist/scripts/agent-engines/list-agent-engines.js +1 -19
  198. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  199. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  200. package/dist/server/transcribe-voice.d.ts +1 -1
  201. package/dist/session-replay-iframe-protocol.d.ts +36 -0
  202. package/dist/session-replay-iframe-protocol.d.ts.map +1 -0
  203. package/dist/session-replay-iframe-protocol.js +24 -0
  204. package/dist/session-replay-iframe-protocol.js.map +1 -0
  205. package/dist/shared/reasoning-effort.d.ts +11 -0
  206. package/dist/shared/reasoning-effort.d.ts.map +1 -1
  207. package/dist/shared/reasoning-effort.js +36 -0
  208. package/dist/shared/reasoning-effort.js.map +1 -1
  209. package/dist/styles/agent-conversation.css +26 -0
  210. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
  211. package/docs/content/durable-background-runs.mdx +37 -0
  212. package/docs/content/locales/ar-SA/tracking.mdx +2 -0
  213. package/docs/content/locales/de-DE/tracking.mdx +2 -0
  214. package/docs/content/locales/es-ES/tracking.mdx +2 -0
  215. package/docs/content/locales/fr-FR/tracking.mdx +4 -2
  216. package/docs/content/locales/hi-IN/tracking.mdx +2 -0
  217. package/docs/content/locales/ja-JP/tracking.mdx +2 -0
  218. package/docs/content/locales/ko-KR/tracking.mdx +2 -0
  219. package/docs/content/locales/pt-BR/tracking.mdx +2 -0
  220. package/docs/content/locales/zh-CN/tracking.mdx +2 -0
  221. package/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
  222. package/docs/content/locales/zh-TW/tracking.mdx +2 -0
  223. package/docs/content/tracking.mdx +2 -0
  224. package/package.json +2 -2
  225. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
  226. package/corpus/core/src/observability/hosted-model-experiment.ts +0 -118
  227. package/dist/observability/hosted-model-experiment.d.ts +0 -39
  228. package/dist/observability/hosted-model-experiment.d.ts.map +0 -1
  229. package/dist/observability/hosted-model-experiment.js +0 -90
  230. package/dist/observability/hosted-model-experiment.js.map +0 -1
@@ -15,8 +15,6 @@ import {
15
15
  normalizeModelForEngine,
16
16
  } from "../../agent/engine/index.js";
17
17
  import type { ActionTool } from "../../agent/types.js";
18
- import { resolveHostedDefaultModelExperiment } from "../../observability/hosted-model-experiment.js";
19
- import { getRequestUserEmail } from "../../server/request-context.js";
20
18
  import { getSetting } from "../../settings/index.js";
21
19
 
22
20
  export const tool: ActionTool = {
@@ -84,24 +82,13 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
84
82
  ? current?.model
85
83
  : undefined;
86
84
  const currentEngineName = currentEntry?.name ?? "anthropic";
87
- let currentModel =
85
+ const currentModel =
88
86
  currentEntry && !envUnavailable
89
87
  ? normalizeModelForEngine(
90
88
  currentEntry,
91
89
  currentModelCandidate ?? currentEntry.defaultModel,
92
90
  )
93
91
  : (currentModelCandidate ?? DEFAULT_MODEL);
94
- const hostedExperiment =
95
- currentEntry && !currentModelCandidate
96
- ? resolveHostedDefaultModelExperiment({
97
- userId: getRequestUserEmail(),
98
- engineName: currentEntry.name,
99
- isDefaultModelSelection: true,
100
- supportedModels: currentEntry.supportedModels,
101
- })
102
- : null;
103
- if (hostedExperiment) currentModel = hostedExperiment.model;
104
-
105
92
  const result = {
106
93
  engines: engines.map((e) => ({
107
94
  name: e.name,
@@ -119,12 +106,6 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
119
106
  : {
120
107
  engine: currentEngineName,
121
108
  model: currentModel,
122
- ...(hostedExperiment
123
- ? {
124
- modelSelectionSource: "experiment",
125
- experimentAssignment: hostedExperiment.assignment,
126
- }
127
- : {}),
128
109
  },
129
110
  };
130
111
 
@@ -0,0 +1,58 @@
1
+ export const SESSION_REPLAY_IFRAME_ATTRIBUTE =
2
+ "data-agent-native-session-replay";
3
+ export const SESSION_REPLAY_IFRAME_PROBE = "agent-native-session-replay:probe";
4
+ export const SESSION_REPLAY_IFRAME_START = "agent-native-session-replay:start";
5
+ export const SESSION_REPLAY_IFRAME_STOP = "agent-native-session-replay:stop";
6
+
7
+ export interface SessionReplayIframePrivacyOptions {
8
+ blockSelector: string;
9
+ ignoreSelector: string;
10
+ maskTextClass?: string | RegExp;
11
+ maskTextSelector: string;
12
+ maskAllInputs: boolean;
13
+ maskInputOptions?: Record<string, boolean>;
14
+ recordCanvas: boolean;
15
+ collectFonts: boolean;
16
+ inlineImages: boolean;
17
+ sampling: Record<string, unknown>;
18
+ }
19
+
20
+ export interface SessionReplayIframeProbeMessage {
21
+ type: typeof SESSION_REPLAY_IFRAME_PROBE;
22
+ }
23
+
24
+ export interface SessionReplayIframeStartMessage {
25
+ type: typeof SESSION_REPLAY_IFRAME_START;
26
+ options: SessionReplayIframePrivacyOptions;
27
+ }
28
+
29
+ export interface SessionReplayIframeStopMessage {
30
+ type: typeof SESSION_REPLAY_IFRAME_STOP;
31
+ }
32
+
33
+ export type SessionReplayIframeMessage =
34
+ | SessionReplayIframeProbeMessage
35
+ | SessionReplayIframeStartMessage
36
+ | SessionReplayIframeStopMessage;
37
+
38
+ /**
39
+ * `srcdoc` HTML came from the immediate parent, so that parent already owns the
40
+ * document being rendered. Server-rendered extension URLs are stricter: only a
41
+ * parent on the render URL's origin may activate recording. That supports
42
+ * custom app domains without allowing an external embed host to make an opaque
43
+ * extension frame disclose its DOM through rrweb's postMessage transport.
44
+ */
45
+ export function isTrustedSessionReplayIframeParentOrigin(
46
+ parentOrigin: string,
47
+ frameHref: string,
48
+ ): boolean {
49
+ if (frameHref === "about:srcdoc") {
50
+ return parentOrigin !== "null" && parentOrigin !== "";
51
+ }
52
+ try {
53
+ const frameOrigin = new URL(frameHref).origin;
54
+ return frameOrigin !== "null" && parentOrigin === frameOrigin;
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
@@ -170,6 +170,41 @@ function isClaudeReasoningModel(model: string) {
170
170
  return opusMatch ? parseInt(opusMatch[1], 10) >= 6 : false;
171
171
  }
172
172
 
173
+ /**
174
+ * Anthropic's adaptive-thinking API is only available on the newer Claude
175
+ * model families. Claude Haiku 4.5 is reasoning-capable, but it still
176
+ * requires the legacy manual `budget_tokens` configuration.
177
+ */
178
+ export function supportsClaudeAdaptiveThinking(model: string | undefined) {
179
+ if (!model) return false;
180
+ const id = model.toLowerCase().replace(/^anthropic\//, "");
181
+ if (id.includes("fable-5") || id.includes("mythos-5")) return true;
182
+ if (id.includes("sonnet-5") || id.includes("sonnet-4-6")) return true;
183
+ const opusMatch = id.match(/opus-4[-.](\d+)/);
184
+ return opusMatch ? parseInt(opusMatch[1], 10) >= 6 : false;
185
+ }
186
+
187
+ /**
188
+ * Map the shared reasoning ladder to Anthropic's manual thinking budgets for
189
+ * models that do not support adaptive thinking (currently Claude Haiku 4.5).
190
+ */
191
+ export function anthropicManualThinkingBudget(effort: ReasoningEffort) {
192
+ switch (effort) {
193
+ case "low":
194
+ return 1_024;
195
+ case "medium":
196
+ return 4_096;
197
+ case "high":
198
+ return 8_000;
199
+ case "xhigh":
200
+ return 16_000;
201
+ case "max":
202
+ return 32_000;
203
+ default:
204
+ return 4_096;
205
+ }
206
+ }
207
+
173
208
  function supportsClaudeXHigh(model: string) {
174
209
  const id = model.toLowerCase().replace(/^anthropic\//, "");
175
210
  // Models that support the xhigh effort tier (built-in extended thinking via
@@ -493,6 +493,32 @@
493
493
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 1.5rem);
494
494
  }
495
495
 
496
+ .agent-chat-collapse {
497
+ display: grid;
498
+ grid-template-rows: 1fr;
499
+ opacity: 1;
500
+ transition:
501
+ grid-template-rows 200ms var(--ease-collapse),
502
+ opacity 150ms ease-out;
503
+ }
504
+
505
+ .agent-chat-collapse[data-state="closed"] {
506
+ grid-template-rows: 0fr;
507
+ opacity: 0;
508
+ pointer-events: none;
509
+ }
510
+
511
+ .agent-chat-collapse__content {
512
+ min-height: 0;
513
+ overflow: hidden;
514
+ }
515
+
516
+ @media (prefers-reduced-motion: reduce) {
517
+ .agent-chat-collapse {
518
+ transition-duration: 0.01ms;
519
+ }
520
+ }
521
+
496
522
  /* ─── Agent-Markdown (AssistantChat react-markdown render surface) ─────────── */
497
523
  /* These classes are applied by the SmoothMarkdownText/MarkdownText components */
498
524
  /* in the AssistantChat/AssistantChatInner tree. The shiki dual-theme rules */
@@ -158,21 +158,6 @@ The agent loop reads active experiments via `resolveActiveExperimentConfig()` an
158
158
 
159
159
  Compute results with `POST /_agent-native/observability/experiments/:id/results`.
160
160
 
161
- #### First-party hosted default-model rollout
162
-
163
- First-party apps on `agent-native.com` automatically run the July 2026
164
- default-model experiment for authenticated users on the Builder engine:
165
-
166
- - 80% `claude-sonnet-5`
167
- - 20% `gpt-5-6-luna`
168
- - Assignment is sticky by normalized user email and shared across templates.
169
- - The rollout applies only when the user, app, and deployment have not selected
170
- a model. Explicit model choices and BYO provider engines always win.
171
- - Set `AGENT_NATIVE_HOSTED_MODEL_EXPERIMENT=off` for an emergency rollback, or
172
- `true` to exercise the rollout on a non-first-party preview.
173
- - `$ai_generation` tracking includes `experiment_id`,
174
- `experiment_variant`, and `model_selection_source` for central analysis.
175
-
176
161
  In production, experiment management routes require the caller's email in the
177
162
  comma-separated `AGENT_NATIVE_EXPERIMENT_ADMIN_EMAILS` allowlist. This gate is
178
163
  separate from normal app/org admin roles because an experiment affects every
@@ -102,9 +102,9 @@ agent answers about browser recordings in the Analytics template.
102
102
  - Wait for all replay chunks (`isComplete`) before constructing the rrweb
103
103
  `Replayer`. Progressive chunk publishes should only update the loading bar;
104
104
  rebuilding the player mid-load desyncs the scrubber and playhead.
105
- - Pass events to `Replayer` untouched. rrweb rebuilds them in a sandboxed iframe;
106
- pre-processing DOM, stylesheet, resource, or mutation payloads makes playback
107
- diverge from the captured page. In particular, never rewrite `href`, `src`,
105
+ - Pass normal events to `Replayer` untouched. rrweb rebuilds them in a sandboxed
106
+ iframe; pre-processing DOM, stylesheet, resource, or mutation payloads makes
107
+ playback diverge from the captured page. In particular, never rewrite `href`, `src`,
108
108
  `_cssText`, CSS `url()`, or Meta URLs to `about:blank`; that exact remediation
109
109
  broke historical replay CSS in PR #2040. Handle request privacy at capture or
110
110
  the sandbox boundary instead of mutating stored rrweb events. Historical
@@ -112,19 +112,59 @@ agent answers about browser recordings in the Analytics template.
112
112
  requests for accurate rendering; the viewer accepts that fidelity tradeoff,
113
113
  uses rrweb's script-disabled sandbox plus `referrerpolicy="no-referrer"`, and
114
114
  must never add credentials or proxy those URLs through a privileged server.
115
- - Let rrweb own normal iframe sizing via Meta / ViewportResize, and keep the
116
- outer wrapper in that same coordinate system for fit-to-stage scaling. Some
117
- legacy recordings contain demonstrably corrupt 4,000–7,500px-wide viewport
118
- values from ordinary desktop sessions. Only widths of at least 4,000px with
119
- aspect ratios above 4:1 are recovered to a 16:10 viewport; real 32:9 and
120
- mobile portrait captures remain untouched. The resize handler applies the
121
- recovery to **both** rrweb's iframe and the outer stage.
122
- Never remove this recovery, clamp only one layer, or broadly rewrite event
123
- geometry: those changes repeatedly recreated the ribbon/clipping regression.
124
- - Keep the realistic fidelity and malformed-viewport tests in
125
- `SessionDetailPage.spec.ts`. Do not change their expectations merely to bless
126
- a new sanitizer or raw ultra-wide sizing; validate the affected replay in a
127
- browser first.
115
+ - Capture-time URL scrubbing must preserve load-bearing DOM resource attributes:
116
+ `src`, `srcset`, `poster`, `data`, and `href` only on resource links such as
117
+ stylesheets, preloads, and icons. Signed CDN query parameters are part of the
118
+ resource identity; redacting them produces missing CSS, fonts, images, and
119
+ oversized fallback icons. Keep scrubbing Meta/navigation URLs, anchor hrefs,
120
+ and console/network diagnostics. Captured `_cssText` and CSS `@import`/`url()`
121
+ values must remain byte-identical.
122
+ - rrweb rebuilds into an `about:srcdoc` iframe, which inherits the Analytics
123
+ document's CSP. Analytics currently sends no CSP header; if a future change
124
+ adds restrictive `style-src`, `font-src`, or `img-src` directives, verify
125
+ historical replays and resolve external imports/fonts at capture before
126
+ blocking the recorded resource origins. Do not diagnose current font loss as
127
+ CSP without checking the deployed response headers first.
128
+ - Let rrweb own iframe sizing entirely via Meta / ViewportResize, and keep the
129
+ outer wrapper on the exact same raw dimensions for fit-to-stage scaling.
130
+ Player geometry and pointer coordinates are fully stock and untouched — do
131
+ not add width/aspect-ratio "recovery" heuristics or pointer-coordinate
132
+ projection. There is no such thing as a stored recording with corrupt
133
+ viewport geometry: a census of all production recordings found zero stored
134
+ widths >= 3,000px. The 2026-07 "ultra-wide replay" bugs (stages rendered
135
+ 3,000–9,500px wide, frozen/teleporting cursors, giant icons) were caused
136
+ entirely by demo mode's fetch interceptor: its number redactor faked any
137
+ integer >= 1000 inside raw replay JSON at *view* time, corrupting Meta /
138
+ ViewportResize widths, pointer x/y coordinates, and numeric values inside
139
+ `_cssText` and SVG attributes before rrweb ever saw the payload (heights
140
+ below 1000 stayed real, which is why the symptom looked like a viewport
141
+ problem rather than a redaction bug — two different sessions that both
142
+ stored a 1,152px width read back as the same 4,491px, a deterministic
143
+ salted-hash fingerprint of the redactor, not two coincidentally identical
144
+ malformed recordings). This is fixed in
145
+ `packages/core/src/demo/fetch-interceptor.ts`: raw replay payload and
146
+ manifest URLs are skipped from demo number redaction entirely, and must
147
+ never be routed through it again. Do not reintroduce viewport clamping or
148
+ pointer-coordinate projection in the player — they can now only corrupt
149
+ genuine future recordings (for example, a real 3440x900 ultrawide browser
150
+ window, or a short vertical window under 1,000px tall).
151
+ - Keep rrweb's stock cursor stylesheet and its hotspot transform. During
152
+ playback, hide the viewer's native pointer over Analytics' transparent
153
+ click-to-pause overlay so it cannot masquerade as a frozen recorded cursor.
154
+ - Keep rrweb's recorded focus handling enabled. Focus and focus-visible state
155
+ affect menus, forms, and keyboard UX; disabling `triggerFocus` makes a valid
156
+ snapshot diverge from the source page.
157
+ - `insertStyleRules` may suppress known toast/snackbar containers only. Never
158
+ hide generic framework primitives such as
159
+ `[data-radix-popper-content-wrapper]`: Radix dropdowns, selects, tooltips,
160
+ and other real recorded product UI all share that wrapper.
161
+ - Keep the realistic-fidelity purity/pass-through tests in
162
+ `SessionDetailPage.spec.ts` — raw event identity, raw viewport dimensions,
163
+ and raw resize-state derivation (including the 3,189x885 tripwire against
164
+ reintroducing a clamp) — as regression guards against reintroducing any
165
+ viewport "recovery" or pointer-projection heuristic. Do not change their
166
+ expectations merely to bless a new sanitizer or clamp; validate the affected
167
+ replay in a browser first.
128
168
  - The event timeline soft-highlights the active marker, auto-scrolls it into
129
169
  view (pausing briefly after manual scroll), and supports search. It appears
130
170
  beside the player from ~880px content width upward.
@@ -161,3 +201,14 @@ agent answers about browser recordings in the Analytics template.
161
201
  `.an-mask` or `data-an-mask`.
162
202
  - Use `.an-block`, `.an-ignore`, `data-an-block`, or `data-an-ignore` for
163
203
  sensitive zones that should not be captured.
204
+ - A definitive upload `409` abandons only the conflicted replay identity and
205
+ immediately starts rrweb again under a fresh per-tab id, producing a new
206
+ Meta + FullSnapshot for long-lived SPA tabs. Recovery is limited to one
207
+ restart until an upload succeeds so a misconfigured endpoint cannot loop;
208
+ Analytics tracks the content-free `session replay upload rejected` lifecycle
209
+ event so conflicts and recovery success are measurable.
210
+ - Do not label an old recording "corrupt" from pointer coordinates, unknown
211
+ mutation node ids, or changing Meta geometry alone. Those shapes can be
212
+ legitimate with scrolling, iframes/shadow DOM, navigation, and resize. A
213
+ historical-artifact notice needs a durable capture/ingest marker or another
214
+ low-false-positive invariant; do not guess from playback heuristics.
@@ -106,6 +106,18 @@ details live in `.agents/skills/`.
106
106
  / `$ai_latency`, `status`, `tool_calls`, `successful_tools`, `failed_tools`,
107
107
  and `$ai_error` / `error_message`. Do not expect prompts, tool args, or model
108
108
  responses in these tracked events by default.
109
+ - External MCP callers should use `ask_app` as the default for multi-step
110
+ Analytics work. It can resolve a person's known email, correlate sessions
111
+ with captured errors, mint a temporary replay-context link, and inspect the
112
+ timeline, page navigation, console diagnostics, failed network requests, and
113
+ clicks when needed. The authenticated connector catalog is the fast fallback
114
+ and exposes only bounded, user/org-scoped read actions for incident triage:
115
+ `list-session-recordings`, `get-session-replay-summary`,
116
+ `get-session-replay-events`, `query-agent-native-analytics`,
117
+ `list-error-issues`, and `get-error-issue`. Fetch the summary before raw
118
+ events, use the event filters/limits to keep the response bounded, and do not
119
+ add replay blob or dashboard mutation actions to this catalog without an
120
+ explicit security review.
109
121
  - `/agents` is the Analytics home for admin surfaces. The default Monitoring
110
122
  view embeds the shared observability dashboard for traces, conversations,
111
123
  evals, experiments, and feedback. `/agents?view=dashboards` shows the
@@ -28,6 +28,7 @@ export default defineAction({
28
28
  }),
29
29
  http: { method: "GET" },
30
30
  readOnly: true,
31
+ publicAgent: { expose: true, readOnly: true, requiresAuth: true },
31
32
  run: async (args) => {
32
33
  return getErrorIssue(resolveScope(), args.id, {
33
34
  eventsLimit: args.eventsLimit,
@@ -40,6 +40,7 @@ export default defineAction({
40
40
  }),
41
41
  http: { method: "GET" },
42
42
  readOnly: true,
43
+ publicAgent: { expose: true, readOnly: true, requiresAuth: true },
43
44
  run: async (args) => {
44
45
  return getSessionReplayEvents(args.recordingId, resolveScope(), {
45
46
  startSeq: args.startSeq,
@@ -21,6 +21,7 @@ export default defineAction({
21
21
  }),
22
22
  http: { method: "GET" },
23
23
  readOnly: true,
24
+ publicAgent: { expose: true, readOnly: true, requiresAuth: true },
24
25
  run: async (args) => {
25
26
  return getSessionReplaySummary(args.recordingId, resolveScope());
26
27
  },
@@ -34,6 +34,7 @@ export default defineAction({
34
34
  }),
35
35
  http: { method: "GET" },
36
36
  readOnly: true,
37
+ publicAgent: { expose: true, readOnly: true, requiresAuth: true },
37
38
  run: async (args) => {
38
39
  return listErrorIssues(resolveScope(), args);
39
40
  },
@@ -58,6 +58,7 @@ export default defineAction({
58
58
  }),
59
59
  http: { method: "GET" },
60
60
  readOnly: true,
61
+ publicAgent: { expose: true, readOnly: true, requiresAuth: true },
61
62
  run: async (args) => {
62
63
  return listSessionRecordings(resolveScope(), args);
63
64
  },
@@ -33,7 +33,8 @@ export default defineAction({
33
33
  ),
34
34
  }),
35
35
  readOnly: true,
36
- http: false,
36
+ http: { method: "GET" },
37
+ publicAgent: { expose: true, readOnly: true, requiresAuth: true },
37
38
  run: async (args) => {
38
39
  return queryFirstPartyAnalytics(args.sql, resolveScope());
39
40
  },
@@ -186,7 +186,7 @@
186
186
  .analytics-chat-intro {
187
187
  display: grid;
188
188
  width: 100%;
189
- max-width: min(570px, 90%);
189
+ max-width: min(684px, 90%);
190
190
  gap: 0.5rem;
191
191
  margin: 0 auto 1rem;
192
192
  text-align: center;
@@ -223,7 +223,7 @@
223
223
  [data-agent-empty-state="centered"]
224
224
  .agent-plan-mode-callout {
225
225
  width: 100%;
226
- max-width: min(570px, 90%);
226
+ max-width: min(684px, 90%);
227
227
  padding: 0;
228
228
  }
229
229
 
@@ -245,72 +245,14 @@
245
245
  transform-origin: top left;
246
246
  }
247
247
 
248
- /* First-party visitor-cursor styles for rrweb playback. These are bundled
249
- statically so the cursor stays visible even if the lazily imported
250
- `@rrweb/replay/dist/style.css` sheet fails to load, and they replace the
251
- default black arrow sprite with an app-styled indicator. The cursor lives
252
- inside `.replayer-wrapper`, so it scales with the fit-to-stage transform. */
253
- .an-replay-stage-root .replayer-mouse {
254
- position: absolute;
255
- z-index: 2;
256
- width: 1.125rem;
257
- height: 1.5rem;
258
- border-radius: 0;
259
- background: transparent;
260
- background-image: none;
261
- box-shadow: none;
262
- transform: none;
263
- transition:
264
- left 80ms linear,
265
- top 80ms linear;
266
- pointer-events: none;
267
- }
268
-
269
- .an-replay-stage-root .replayer-mouse::before {
270
- content: "";
271
- position: absolute;
272
- inset: 0;
273
- background: hsl(0 0% 100%);
274
- clip-path: polygon(0 0, 0 77%, 30% 57%, 48% 100%, 68% 92%, 50% 51%, 92% 51%);
275
- filter: drop-shadow(0 0 1px hsl(0 0% 0% / 0.95))
276
- drop-shadow(0 1px 3px hsl(0 0% 0% / 0.35));
277
- }
278
-
248
+ /* IMPORTANT: Keep rrweb's stock SVG arrow. Only suppress its permanently
249
+ visible purple ::after disc, which can otherwise read as the cursor itself
250
+ when the arrow is small. The stock .active animation still supplies the
251
+ brief click halo. Do not replace the arrow with an app-colored dot. */
279
252
  .an-replay-stage-root .replayer-mouse::after {
280
- content: "";
281
- position: absolute;
282
- left: -0.5rem;
283
- top: -0.5rem;
284
- width: 1rem;
285
- height: 1rem;
286
- border-radius: 9999px;
287
- border: 2px solid hsl(217 91% 60%);
288
- background: transparent;
289
253
  opacity: 0;
290
254
  }
291
255
 
292
- /* rrweb toggles `.active` on mouse interactions; pulse a click ripple. */
293
- .an-replay-stage-root .replayer-mouse.active::after {
294
- animation: an-replay-mouse-click 0.4s ease-out 1;
295
- }
296
-
297
- @keyframes an-replay-mouse-click {
298
- 0% {
299
- opacity: 0.5;
300
- transform: scale(1);
301
- }
302
- 100% {
303
- opacity: 0;
304
- transform: scale(3.5);
305
- }
306
- }
307
-
308
- .an-replay-stage-root .replayer-mouse-tail {
309
- position: absolute;
310
- inset: 0;
311
- pointer-events: none;
312
- }
313
-
314
256
  .analytics-session-snippet .plan-code-surface {
315
257
  border: 0;
316
258
  border-radius: 0;
@@ -1,12 +1,14 @@
1
1
  import {
2
+ SIDEBAR_STATE_CHANGE_EVENT,
2
3
  deleteClientAppState,
3
4
  readClientAppState,
4
5
  removeAgentChatContextItem,
5
6
  setAgentChatContextItem,
6
7
  setClientAppState,
8
+ type AgentSidebarStateChangeDetail,
7
9
  useAgentChatContext,
8
10
  } from "@agent-native/core/client";
9
- import { useCallback, useEffect } from "react";
11
+ import { useCallback, useEffect, useState } from "react";
10
12
 
11
13
  import { TAB_ID } from "@/lib/tab-id";
12
14
 
@@ -120,10 +122,22 @@ function parsePanelSelection(
120
122
  }
121
123
  }
122
124
 
125
+ function isAgentSidebarOpenInDocument(): boolean {
126
+ if (typeof document === "undefined") return false;
127
+ return Boolean(
128
+ document.querySelector(
129
+ '.agent-sidebar-panel[data-agent-sidebar-state="open"]',
130
+ ),
131
+ );
132
+ }
133
+
123
134
  export function useDashboardChatContext(
124
135
  args: DashboardChatContextArgs,
125
136
  ): DashboardChatContextResult {
126
137
  const { id, kind, title, panelCount, canEdit } = args;
138
+ const [isAgentSidebarOpen, setIsAgentSidebarOpen] = useState(
139
+ isAgentSidebarOpenInDocument,
140
+ );
127
141
  const { items } = useAgentChatContext();
128
142
  const panelContext = items.find(
129
143
  (item) => item.key === DASHBOARD_PANEL_CONTEXT_KEY,
@@ -132,7 +146,9 @@ export function useDashboardChatContext(
132
146
  ? parsePanelSelection(panelContext.context)
133
147
  : null;
134
148
  const selectedPanelId =
135
- id && panelSelection?.dashboardId === id ? panelSelection.panelId : null;
149
+ isAgentSidebarOpen && id && panelSelection?.dashboardId === id
150
+ ? panelSelection.panelId
151
+ : null;
136
152
  const hasSelectedPanel = selectedPanelId !== null;
137
153
 
138
154
  const selectPanelForChat = useCallback(
@@ -141,6 +157,7 @@ export function useDashboardChatContext(
141
157
  options: SelectDashboardPanelOptions = {},
142
158
  ) => {
143
159
  if (!id) return;
160
+ if (options.openSidebar !== true && !isAgentSidebarOpen) return;
144
161
  const displayDashboardTitle = title?.trim() || id;
145
162
  const displayPanelTitle = panel.panelTitle.trim() || panel.panelId;
146
163
  const contextLines = [
@@ -166,7 +183,7 @@ export function useDashboardChatContext(
166
183
  key: DASHBOARD_PANEL_CONTEXT_KEY,
167
184
  title: displayPanelTitle,
168
185
  context: contextLines.join("\n"),
169
- openSidebar: options.openSidebar ?? true,
186
+ openSidebar: options.openSidebar === true,
170
187
  focus: options.focus ?? false,
171
188
  });
172
189
  setClientAppState(
@@ -191,9 +208,29 @@ export function useDashboardChatContext(
191
208
  },
192
209
  ).catch(() => {});
193
210
  },
194
- [id, kind, title],
211
+ [id, isAgentSidebarOpen, kind, title],
195
212
  );
196
213
 
214
+ useEffect(() => {
215
+ const handleSidebarStateChange = (event: Event) => {
216
+ const detail = (event as CustomEvent<AgentSidebarStateChangeDetail>)
217
+ .detail;
218
+ if (typeof detail?.open === "boolean") {
219
+ setIsAgentSidebarOpen(detail.open);
220
+ }
221
+ };
222
+
223
+ window.addEventListener(
224
+ SIDEBAR_STATE_CHANGE_EVENT,
225
+ handleSidebarStateChange,
226
+ );
227
+ return () =>
228
+ window.removeEventListener(
229
+ SIDEBAR_STATE_CHANGE_EVENT,
230
+ handleSidebarStateChange,
231
+ );
232
+ }, []);
233
+
197
234
  useEffect(() => {
198
235
  if (!id) return;
199
236
  const displayTitle = title?.trim() || id;