@agent-native/core 0.90.9 → 0.90.10

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 (98) hide show
  1. package/README.md +7 -28
  2. package/corpus/README.md +1 -1
  3. package/corpus/core/CHANGELOG.md +10 -0
  4. package/corpus/core/docs/content/agent-native-toolkit.mdx +1 -1
  5. package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
  6. package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +3 -3
  7. package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
  8. package/corpus/core/docs/content/locales/de-DE/tracking.mdx +3 -3
  9. package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
  10. package/corpus/core/docs/content/locales/es-ES/tracking.mdx +3 -3
  11. package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
  12. package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +3 -3
  13. package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
  14. package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +3 -3
  15. package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
  16. package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +3 -3
  17. package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
  18. package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +3 -3
  19. package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
  20. package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +3 -3
  21. package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
  22. package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +3 -3
  23. package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
  24. package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +3 -3
  25. package/corpus/core/docs/content/tracking.mdx +3 -3
  26. package/corpus/core/package.json +1 -1
  27. package/corpus/core/src/agent/production-agent.ts +15 -4
  28. package/corpus/core/src/client/analytics.ts +17 -3
  29. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +3 -1
  30. package/corpus/core/src/client/blocks/library/wireframe.tsx +6 -1
  31. package/corpus/core/src/file-upload/builder.ts +10 -23
  32. package/corpus/core/src/file-upload/types.ts +3 -3
  33. package/corpus/core/src/styles/blocks.css +7 -0
  34. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +9 -4
  35. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +21 -7
  36. package/corpus/templates/analytics/app/entry.client.tsx +6 -1
  37. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -1
  38. package/corpus/templates/analytics/changelog/2026-07-07-analytics-now-recovers-from-stale-route-chunks-after-deploys.md +6 -0
  39. package/corpus/templates/analytics/changelog/2026-07-07-metric-dashboard-cards-now-show-warehouse-backed-numeric-val.md +6 -0
  40. package/corpus/templates/clips/actions/create-recording.ts +1 -1
  41. package/corpus/templates/clips/actions/finalize-recording.ts +2 -2
  42. package/corpus/templates/clips/actions/import-loom-recording.ts +1 -1
  43. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +1 -1
  44. package/corpus/templates/clips/changelog/2026-07-07-clip-video-uploads-now-compress-in-the-background-while-keeping.md +6 -0
  45. package/corpus/templates/clips/changelog/2026-07-07-desktop-settings-and-fn-dictation-are-more-reliable.md +6 -0
  46. package/corpus/templates/clips/changelog/2026-07-07-desktop-settings-now-includes-a-manual-update-check-with-res.md +6 -0
  47. package/corpus/templates/clips/desktop/src/app.tsx +95 -8
  48. package/corpus/templates/clips/desktop/src/lib/updater.ts +60 -43
  49. package/corpus/templates/clips/desktop/src/styles.css +5 -0
  50. package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +93 -23
  51. package/corpus/templates/dispatch/changelog/2026-07-07-overview-is-now-just-ask-dispatch-and-a-list-of-apps.md +6 -0
  52. package/dist/agent/production-agent.d.ts.map +1 -1
  53. package/dist/agent/production-agent.js +16 -3
  54. package/dist/agent/production-agent.js.map +1 -1
  55. package/dist/client/analytics.d.ts.map +1 -1
  56. package/dist/client/analytics.js +14 -3
  57. package/dist/client/analytics.js.map +1 -1
  58. package/dist/client/blocks/library/wireframe-kit.d.ts +1 -0
  59. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  60. package/dist/client/blocks/library/wireframe-kit.js +2 -1
  61. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  62. package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
  63. package/dist/client/blocks/library/wireframe.js +6 -1
  64. package/dist/client/blocks/library/wireframe.js.map +1 -1
  65. package/dist/collab/routes.d.ts +1 -1
  66. package/dist/file-upload/builder.d.ts.map +1 -1
  67. package/dist/file-upload/builder.js +9 -19
  68. package/dist/file-upload/builder.js.map +1 -1
  69. package/dist/file-upload/types.d.ts +3 -3
  70. package/dist/file-upload/types.d.ts.map +1 -1
  71. package/dist/file-upload/types.js.map +1 -1
  72. package/dist/observability/routes.d.ts +5 -5
  73. package/dist/progress/routes.d.ts +1 -1
  74. package/dist/secrets/routes.d.ts +3 -3
  75. package/dist/styles/blocks.css +7 -0
  76. package/docs/content/agent-native-toolkit.mdx +1 -1
  77. package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
  78. package/docs/content/locales/ar-SA/tracking.mdx +3 -3
  79. package/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
  80. package/docs/content/locales/de-DE/tracking.mdx +3 -3
  81. package/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
  82. package/docs/content/locales/es-ES/tracking.mdx +3 -3
  83. package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
  84. package/docs/content/locales/fr-FR/tracking.mdx +3 -3
  85. package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
  86. package/docs/content/locales/hi-IN/tracking.mdx +3 -3
  87. package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
  88. package/docs/content/locales/ja-JP/tracking.mdx +3 -3
  89. package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
  90. package/docs/content/locales/ko-KR/tracking.mdx +3 -3
  91. package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
  92. package/docs/content/locales/pt-BR/tracking.mdx +3 -3
  93. package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
  94. package/docs/content/locales/zh-CN/tracking.mdx +3 -3
  95. package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
  96. package/docs/content/locales/zh-TW/tracking.mdx +3 -3
  97. package/docs/content/tracking.mdx +3 -3
  98. package/package.json +1 -1
@@ -23,7 +23,7 @@ being rebuilt in slightly different ways every time.
23
23
  <Screen
24
24
  surface="desktop"
25
25
  html={
26
- "<div style='min-height:560px;box-sizing:border-box;padding:24px;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><span class='wf-pill'>Org</span><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
26
+ "<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
27
27
  }
28
28
  />
29
29
  </WireframeBlock>
@@ -200,7 +200,7 @@ configureTracking({
200
200
  endpoint: "https://analytics.example.com/api/analytics/track",
201
201
  sessionReplay: {
202
202
  enabled: true,
203
- sampleRate: 0.1,
203
+ sampleRate: 1,
204
204
  },
205
205
  getDefaultProps: (_event, props) => ({
206
206
  ...props,
@@ -218,14 +218,14 @@ As raízes dos modelos do Agent Native já chamam `configureTracking()`. As impl
218
218
  VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
219
219
  VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
220
220
  VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
221
- VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=0.1
221
+ VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=1
222
222
  ```
223
223
 
224
224
  O auxiliar do navegador também realiza uma leitura best-effort e não bloqueante da sessão de autenticação atual do Agent Native. O replay é, por padrão, exclusivo para usuários conectados: quando `sessionReplay` está habilitado, a gravação não começa a menos que a sessão seja resolvida para um endereço de e-mail de usuário. Replays de usuários conectados incluem `userId`/`userEmail` baseados em e-mail, além de `orgId`.
225
225
 
226
226
  Defina `sessionReplay.requireSignedInUser: false` ou `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false` apenas para uma implantação de replay anônimo intencional. Quando o controle de autenticação está desabilitado, as gravações anônimas permanecem consultáveis por visitante anônimo, sessão, aplicativo/modelo, hostname e caminho.
227
227
 
228
- O replay de sessão é amostrado de forma determinística por sessão do navegador. Um `sampleRate` de `0.1` registra cerca de 10% das sessões elegíveis; use `1` quando a população elegível for intencionalmente pequena, como em dogfooding somente para usuários conectados.
228
+ O replay de sessão é amostrado de forma determinística por sessão do navegador. Um `sampleRate` de `1` registra todas as sessões elegíveis; use valores menores, como `0.1`, quando a população elegível for intencionalmente ampla.
229
229
 
230
230
  Os padrões de privacidade são intencionalmente conservadores, mas ainda úteis para a reprodução:
231
231
 
@@ -23,7 +23,7 @@ being rebuilt in slightly different ways every time.
23
23
  <Screen
24
24
  surface="desktop"
25
25
  html={
26
- "<div style='min-height:560px;box-sizing:border-box;padding:24px;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><span class='wf-pill'>Org</span><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
26
+ "<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
27
27
  }
28
28
  />
29
29
  </WireframeBlock>
@@ -200,7 +200,7 @@ configureTracking({
200
200
  endpoint: "https://analytics.example.com/api/analytics/track",
201
201
  sessionReplay: {
202
202
  enabled: true,
203
- sampleRate: 0.1,
203
+ sampleRate: 1,
204
204
  },
205
205
  getDefaultProps: (_event, props) => ({
206
206
  ...props,
@@ -218,14 +218,14 @@ Agent Native 模板根已经调用了 `configureTracking()`。托管模板部署
218
218
  VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
219
219
  VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
220
220
  VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
221
- VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=0.1
221
+ VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=1
222
222
  ```
223
223
 
224
224
  浏览器端辅助函数还会尽力地、非阻塞地读取当前 Agent Native 认证会话。默认情况下,重放仅限已登录用户:启用 `sessionReplay` 后,除非会话解析出用户邮箱地址,否则不会开始录制。已登录用户的重放会包含基于邮箱的 `userId`/`userEmail` 以及 `orgId`。
225
225
 
226
226
  仅在有意进行匿名重放部署时,才设置 `sessionReplay.requireSignedInUser: false` 或 `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false`。禁用认证门控后,匿名录制仍可按匿名访客、会话、应用/模板、主机名和路径进行查询。
227
227
 
228
- 会话重放按浏览器会话确定性采样。`sampleRate` 为 `0.1` 时,会记录约 10% 的符合条件的会话;当符合条件的用户群体本就很小时(例如仅限登录用户的内部测试),可使用 `1`。
228
+ 会话重放按浏览器会话确定性采样。`sampleRate` 为 `1` 时,会记录所有符合条件的会话;当符合条件的用户群体有意较大时,可使用较低值,例如 `0.1`。
229
229
 
230
230
  隐私默认设置刻意保持保守,但仍能满足回放的可用性:
231
231
 
@@ -23,7 +23,7 @@ being rebuilt in slightly different ways every time.
23
23
  <Screen
24
24
  surface="desktop"
25
25
  html={
26
- "<div style='min-height:560px;box-sizing:border-box;padding:24px;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><span class='wf-pill'>Org</span><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
26
+ "<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
27
27
  }
28
28
  />
29
29
  </WireframeBlock>
@@ -200,7 +200,7 @@ configureTracking({
200
200
  endpoint: "https://analytics.example.com/api/analytics/track",
201
201
  sessionReplay: {
202
202
  enabled: true,
203
- sampleRate: 0.1,
203
+ sampleRate: 1,
204
204
  },
205
205
  getDefaultProps: (_event, props) => ({
206
206
  ...props,
@@ -218,14 +218,14 @@ Agent Native 範本根目錄已經呼叫了 `configureTracking()`。託管範本
218
218
  VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
219
219
  VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
220
220
  VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
221
- VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=0.1
221
+ VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=1
222
222
  ```
223
223
 
224
224
  瀏覽器輔助程式也會盡力執行、非阻塞式讀取目前的 Agent Native 驗證工作階段。重播預設僅限已登入使用者:當 `sessionReplay` 啟用時,除非工作階段解析出使用者電子郵件地址,否則不會開始錄製。已登入使用者的重播包含以電子郵件為基礎的 `userId`/`userEmail` 以及 `orgId`。
225
225
 
226
226
  僅在刻意進行匿名重播部署時,才設定 `sessionReplay.requireSignedInUser: false` 或 `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false`。停用驗證閘控後,匿名錄製仍可依匿名訪客、工作階段、應用程式/範本、主機名稱與路徑進行查詢。
227
227
 
228
- 工作階段重播是依瀏覽器工作階段進行確定性取樣的。`sampleRate` 為 `0.1` 表示大約記錄 10% 符合條件的工作階段;當符合條件的母體刻意較小時(例如僅限已登入使用者的內部試用),可使用 `1`。
228
+ 工作階段重播是依瀏覽器工作階段進行確定性取樣的。`sampleRate` 為 `1` 表示記錄所有符合條件的工作階段;當符合條件的母體刻意較大時,可使用較低值,例如 `0.1`。
229
229
 
230
230
  隱私預設值刻意設計得保守,但仍足以支援播放:
231
231
 
@@ -200,7 +200,7 @@ configureTracking({
200
200
  endpoint: "https://analytics.example.com/api/analytics/track",
201
201
  sessionReplay: {
202
202
  enabled: true,
203
- sampleRate: 0.1,
203
+ sampleRate: 1,
204
204
  },
205
205
  getDefaultProps: (_event, props) => ({
206
206
  ...props,
@@ -218,14 +218,14 @@ Agent Native template roots already call `configureTracking()`. Hosted template
218
218
  VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
219
219
  VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
220
220
  VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
221
- VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=0.1
221
+ VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=1
222
222
  ```
223
223
 
224
224
  The browser helper also performs a best-effort, non-blocking read of the current Agent Native auth session. Replay is signed-in-only by default: when `sessionReplay` is enabled, recording does not start unless the session resolves to a user email address. Signed-in replays include email-backed `userId`/`userEmail` plus `orgId`.
225
225
 
226
226
  Set `sessionReplay.requireSignedInUser: false` or `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false` only for an intentional anonymous replay deployment. When auth gating is disabled, anonymous recordings remain queryable by anonymous visitor, session, app/template, hostname, and path.
227
227
 
228
- Session replay is sampled deterministically per browser session. A `sampleRate` of `0.1` records about 10% of eligible sessions; use `1` when the eligible population is intentionally small, such as logged-in-only dogfooding.
228
+ Session replay is sampled deterministically per browser session. A `sampleRate` of `1` records all eligible sessions; use lower values, such as `0.1`, when the eligible population is intentionally broad.
229
229
 
230
230
  Privacy defaults are intentionally conservative but still useful for playback:
231
231
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.90.9",
3
+ "version": "0.90.10",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -1015,6 +1015,7 @@ const TOOL_INPUT_ACTIVITY_INTERVAL_MS = 1500;
1015
1015
  const ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS = 90_000;
1016
1016
  const ACTION_PREPARATION_ZERO_BYTE_RESTART_LIMIT = 2;
1017
1017
  const MODEL_STREAM_NO_PROGRESS_TIMEOUT_MS = 90_000;
1018
+ const EMPTY_FINAL_RESPONSE_RETRY_LIMIT = 1;
1018
1019
  const MAIN_CHAT_INTERNAL_CONTINUATION_LIMIT = 6;
1019
1020
  const RUN_BUDGET_EXHAUSTED_ERROR_CODE = "run_budget_exhausted";
1020
1021
  const RUN_BUDGET_EXHAUSTED_MESSAGE =
@@ -2733,6 +2734,7 @@ export async function runAgentLoop(opts: {
2733
2734
  }
2734
2735
 
2735
2736
  let finalGuardRetries = 0;
2737
+ let emptyFinalResponseRetries = 0;
2736
2738
  let iterations = 0;
2737
2739
 
2738
2740
  // Set when an in-loop processor aborts via `abort()` / throws a `TripWire`.
@@ -3349,16 +3351,24 @@ export async function runAgentLoop(opts: {
3349
3351
  // text — typically when reasoning consumes the entire output-token
3350
3352
  // budget. Without a final text part the SSE stream still ends with a
3351
3353
  // clean `done`, which renders as a totally empty assistant bubble.
3352
- // Surface a plain-language error so the user knows what happened.
3353
- if (
3354
+ // Retry once so a transient reasoning-budget miss can still finish; if
3355
+ // the retry also has no visible content, surface a plain-language error.
3356
+ const hasEmptyFinalResponse =
3354
3357
  !guardEmittedFallback &&
3355
3358
  collectTextParts(assistantContentForHistory).trim().length === 0 &&
3356
- streamedAssistantText.trim().length === 0
3357
- ) {
3359
+ streamedAssistantText.trim().length === 0;
3360
+ if (hasEmptyFinalResponse) {
3361
+ if (emptyFinalResponseRetries < EMPTY_FINAL_RESPONSE_RETRY_LIMIT) {
3362
+ emptyFinalResponseRetries += 1;
3363
+ appendAgentLoopContinuation(messages, "max_tokens");
3364
+ continue;
3365
+ }
3358
3366
  send({
3359
3367
  type: "text",
3360
3368
  text: "The model returned an empty response. This usually means reasoning used the full output-token budget. Try again, or pick a different model from the model menu.",
3361
3369
  });
3370
+ } else {
3371
+ emptyFinalResponseRetries = 0;
3362
3372
  }
3363
3373
  break;
3364
3374
  }
@@ -3369,6 +3379,7 @@ export async function runAgentLoop(opts: {
3369
3379
  // finalGuardRetries stays at 1 from a prior cycle and the guard is
3370
3380
  // permanently disabled for the rest of a long multi-step run.
3371
3381
  finalGuardRetries = 0;
3382
+ emptyFinalResponseRetries = 0;
3372
3383
 
3373
3384
  flushUnstreamedAssistantText();
3374
3385
 
@@ -1005,8 +1005,16 @@ function configuredSessionReplayOptions(
1005
1005
  config: boolean | SessionReplayOptions | undefined,
1006
1006
  tracking: { endpoint?: string; publicKey?: string } = {},
1007
1007
  ): SessionReplayOptions | null {
1008
- const publicKey = tracking.publicKey || _agentNativeAnalyticsPublicKey;
1009
- const trackingEndpoint = tracking.endpoint || _agentNativeAnalyticsEndpoint;
1008
+ const env = (import.meta.env as Record<string, string | undefined>) ?? {};
1009
+ const publicKey =
1010
+ tracking.publicKey ||
1011
+ _agentNativeAnalyticsPublicKey ||
1012
+ env.VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY;
1013
+ const trackingEndpoint =
1014
+ tracking.endpoint ||
1015
+ _agentNativeAnalyticsEndpoint ||
1016
+ env.VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT ||
1017
+ (publicKey ? AGENT_NATIVE_ANALYTICS_DEFAULT_ENDPOINT : undefined);
1010
1018
  const endpoint = trackingEndpoint
1011
1019
  ? replayEndpointFromTrackingEndpoint(trackingEndpoint)
1012
1020
  : undefined;
@@ -1034,7 +1042,13 @@ function configuredSessionReplayOptions(
1034
1042
  if (config.enabled === false) return null;
1035
1043
  return withTrackingDefaults(config);
1036
1044
  }
1037
- return sessionReplayEnabledFromEnv() ? withTrackingDefaults({}) : null;
1045
+ const autoEnabledByAnalyticsKey =
1046
+ !!publicKey &&
1047
+ (typeof window === "undefined" ||
1048
+ !isLocalAnalyticsHostname(window.location.hostname));
1049
+ return sessionReplayEnabledFromEnv() || autoEnabledByAnalyticsKey
1050
+ ? withTrackingDefaults({})
1051
+ : null;
1038
1052
  }
1039
1053
 
1040
1054
  function replayExtraPropertiesWithDefaults(
@@ -121,6 +121,7 @@ export function useIsDark(): boolean {
121
121
  */
122
122
  export const KitConfigContext = createContext<{
123
123
  skeleton?: boolean;
124
+ flushFrame?: boolean;
124
125
  sketch?: number;
125
126
  theme?: "light" | "dark";
126
127
  style?: "sketchy" | "clean";
@@ -195,6 +196,7 @@ export function Screen({
195
196
  const isSkeleton = skeleton || Boolean(cfg.skeleton);
196
197
  const wfStyle = cfg.style ?? "sketchy";
197
198
  const wfTheme = theme ?? cfg.theme ?? "light";
199
+ const effectivePad = cfg.flushFrame ? 0 : pad;
198
200
  void sketch;
199
201
  return (
200
202
  <div
@@ -218,7 +220,7 @@ export function Screen({
218
220
  lineHeight: 1.25,
219
221
  display: "flex",
220
222
  flexDirection: "column",
221
- padding: pad,
223
+ padding: effectivePad,
222
224
  boxSizing: "border-box",
223
225
  overflow: "hidden",
224
226
  ...style,
@@ -414,7 +414,12 @@ function KitArtboard({
414
414
  caption={data.caption}
415
415
  render={({ theme, style }) => (
416
416
  <KitConfigContext.Provider
417
- value={{ skeleton: data.skeleton, theme, style }}
417
+ value={{
418
+ skeleton: data.skeleton,
419
+ flushFrame: !showFrame,
420
+ theme,
421
+ style,
422
+ }}
418
423
  >
419
424
  {renderKitScreen(data.screen ?? [])}
420
425
  </KitConfigContext.Provider>
@@ -13,14 +13,6 @@ const LARGE_FILE_THRESHOLD_BYTES = 30 * 1024 * 1024;
13
13
  const UPLOAD_TIMEOUT_MS = 120_000;
14
14
  const SMALL_FILE_RETRY_DELAYS_MS = [600, 1800];
15
15
 
16
- function enabledFlag(value: unknown): boolean {
17
- return /^(true|1|yes|on)$/i.test(String(value || "").trim());
18
- }
19
-
20
- function stableUrlOptInEnabled(): boolean {
21
- return enabledFlag(process.env.CLIPS_STABLE_URL_OPTIN);
22
- }
23
-
24
16
  function builderUploadHost(): string {
25
17
  return (
26
18
  process.env.BUILDER_APP_HOST ||
@@ -52,12 +44,9 @@ function fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {
52
44
  );
53
45
  }
54
46
 
55
- function setSkipCompressionQueryParams(url: URL): void {
56
- url.searchParams.set("skipCompressionWait", "true");
57
- url.searchParams.set("skipCompression", "true");
58
- if (stableUrlOptInEnabled()) {
59
- url.searchParams.set("stableUrl", "true");
60
- }
47
+ function setStableUrlQueryParam(url: URL): void {
48
+ // Stable URLs let Builder compress asynchronously without changing the media URL.
49
+ url.searchParams.set("stableUrl", "true");
61
50
  }
62
51
 
63
52
  function setRecordAssetQueryParam(
@@ -121,7 +110,7 @@ async function uploadLargeFileViaSignedUrl(
121
110
  assetId,
122
111
  input.filename,
123
112
  {
124
- skipCompressionWait: input.skipCompressionWait,
113
+ stableUrl: input.stableUrl,
125
114
  recordAsset: input.recordAsset,
126
115
  },
127
116
  );
@@ -177,12 +166,12 @@ async function completeBuilderUpload(
177
166
  privateKey: string,
178
167
  assetId: string,
179
168
  filename: string | undefined,
180
- options?: { skipCompressionWait?: boolean; recordAsset?: boolean },
169
+ options?: { stableUrl?: boolean; recordAsset?: boolean },
181
170
  ): Promise<{ url: string; id?: string }> {
182
171
  const host = builderUploadHost();
183
172
  const url = new URL("/api/v1/upload/complete", host);
184
- if (options?.skipCompressionWait) {
185
- setSkipCompressionQueryParams(url);
173
+ if (options?.stableUrl) {
174
+ setStableUrlQueryParam(url);
186
175
  }
187
176
  setRecordAssetQueryParam(url, options?.recordAsset);
188
177
  const res = await fetchWithTimeout(url.toString(), {
@@ -287,8 +276,8 @@ export const builderFileUploadProvider: FileUploadProvider = {
287
276
 
288
277
  const url = new URL("/api/v1/upload", builderUploadHost());
289
278
  if (filename) url.searchParams.set("name", filename);
290
- if (input.skipCompressionWait) {
291
- setSkipCompressionQueryParams(url);
279
+ if (input.stableUrl) {
280
+ setStableUrlQueryParam(url);
292
281
  }
293
282
  setRecordAssetQueryParam(url, input.recordAsset);
294
283
 
@@ -429,9 +418,7 @@ export const builderFileUploadProvider: FileUploadProvider = {
429
418
  assetId,
430
419
  filename,
431
420
  {
432
- skipCompressionWait:
433
- options?.skipCompressionWait ||
434
- session.meta.skipCompressionWait === true,
421
+ stableUrl: options?.stableUrl || session.meta.stableUrl === true,
435
422
  recordAsset:
436
423
  options?.recordAsset ??
437
424
  (session.meta.recordAsset === false ? false : undefined),
@@ -16,8 +16,8 @@ export interface FileUploadInput {
16
16
  mimeType?: string;
17
17
  /** Optional owner email for per-user scoping in fallback storage. */
18
18
  ownerEmail?: string;
19
- /** Builder.io upload hint: return after asset registration instead of waiting for server-side compression. */
20
- skipCompressionWait?: boolean;
19
+ /** Builder.io upload hint: return one stable URL while compression finishes asynchronously. */
20
+ stableUrl?: boolean;
21
21
  /** Builder.io upload hint: set false for internal artifacts that should not appear in the asset library. */
22
22
  recordAsset?: boolean;
23
23
  }
@@ -81,7 +81,7 @@ export interface FileUploadProvider {
81
81
  completeSession(
82
82
  session: ResumableUploadSession,
83
83
  filename: string,
84
- options?: { skipCompressionWait?: boolean; recordAsset?: boolean },
84
+ options?: { stableUrl?: boolean; recordAsset?: boolean },
85
85
  ): Promise<string>;
86
86
  };
87
87
  }
@@ -1007,6 +1007,13 @@
1007
1007
  min-height: 100%;
1008
1008
  }
1009
1009
 
1010
+ .plan-html-frame[data-frame="hide"]:not([data-render-mode="design"])
1011
+ > .plan-html-frame-content
1012
+ > :first-child {
1013
+ margin: 0 !important;
1014
+ padding: 0 !important;
1015
+ }
1016
+
1010
1017
  .plan-html-frame[data-prototype-live="true"] {
1011
1018
  overflow: auto;
1012
1019
  }
@@ -106,12 +106,17 @@ agent answers about browser recordings in the Analytics template.
106
106
 
107
107
  ## Capture Defaults
108
108
 
109
- - Replay is off unless enabled by config/env.
110
- - Consumers can enable replay directly with
109
+ - Replay is on by default for signed-in hosted users when
110
+ `VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY` or `configureTracking({ key })` is
111
+ present. The default sample rate is 100% of eligible sessions.
112
+ - Replay remains off when no first-party analytics key is configured, and it is
113
+ not auto-enabled on localhost/local dev. Consumers can still enable replay
114
+ directly with
111
115
  `configureTracking({ key, endpoint, sessionReplay: { enabled: true } })`.
116
+ - Apps can opt out with `configureTracking({ sessionReplay: false })`.
112
117
  - Agent Native templates already call `configureTracking()` in their roots;
113
- hosted template deployments can usually enable replay with Vite/Netlify env
114
- vars on the recorded site.
118
+ hosted template deployments only need the normal Agent Native Analytics
119
+ Vite/Netlify env vars on the recorded site.
115
120
  - Inputs are masked by default. Page text is visible unless marked with
116
121
  `.an-mask` or `data-an-mask`.
117
122
  - Use `.an-block`, `.an-ignore`, `data-an-block`, or `data-an-ignore` for
@@ -155,6 +155,24 @@ export function formatMetricValue(
155
155
  : String(raw ?? "-");
156
156
  }
157
157
 
158
+ function isNumericLikeValue(value: unknown): boolean {
159
+ if (typeof value === "number") return Number.isFinite(value);
160
+ return (
161
+ typeof value === "string" &&
162
+ value.trim() !== "" &&
163
+ Number.isFinite(Number(value))
164
+ );
165
+ }
166
+
167
+ export function detectMetricValueColumn(
168
+ row: Record<string, unknown>,
169
+ configuredKey?: string,
170
+ ): string {
171
+ const cols = Object.keys(row);
172
+ if (configuredKey && cols.includes(configuredKey)) return configuredKey;
173
+ return cols.find((key) => isNumericLikeValue(row[key])) || cols[0] || "";
174
+ }
175
+
158
176
  function parsePrometheusSeriesLabel(label: string): {
159
177
  metric: string;
160
178
  labels: Record<string, string>;
@@ -804,7 +822,7 @@ function detectKeys(
804
822
  if (yKeys.length === 0) {
805
823
  for (const c of cols) {
806
824
  if (c === xKey) continue;
807
- if (typeof sample[c] === "number") yKeys.push(c);
825
+ if (isNumericLikeValue(sample[c])) yKeys.push(c);
808
826
  }
809
827
  }
810
828
  if (yKeys.length === 0 && cols.length > 1) {
@@ -1120,14 +1138,10 @@ function MetricRenderer({
1120
1138
  panel: SqlPanel;
1121
1139
  }) {
1122
1140
  const row = rows[0];
1123
- const cols = Object.keys(row);
1124
- const valueCol =
1125
- panel.config?.yKey ||
1126
- cols.find((c) => typeof row[c] === "number") ||
1127
- cols[0];
1141
+ const valueCol = detectMetricValueColumn(row, panel.config?.yKey);
1128
1142
 
1129
1143
  let raw: unknown;
1130
- if (rows.length > 1 && typeof row[valueCol] === "number") {
1144
+ if (rows.length > 1 && isNumericLikeValue(row[valueCol])) {
1131
1145
  raw = rows.reduce((sum, r) => sum + (Number(r[valueCol]) || 0), 0);
1132
1146
  } else {
1133
1147
  raw = row[valueCol];
@@ -1,7 +1,12 @@
1
- import { appBasePath } from "@agent-native/core/client/api-path";
1
+ import {
2
+ appBasePath,
3
+ installRouteChunkRecovery,
4
+ } from "@agent-native/core/client";
2
5
  import { hydrateRoot } from "react-dom/client";
3
6
  import { HydratedRouter } from "react-router/dom";
4
7
 
8
+ installRouteChunkRecovery();
9
+
5
10
  const basePath = appBasePath();
6
11
  const pathname = window.location.pathname;
7
12
  const routerBasePath =
@@ -546,7 +546,7 @@ configureTracking({
546
546
  sessionReplay: {
547
547
  enabled: true,
548
548
  requireSignedInUser: true,
549
- sampleRate: 0.1,
549
+ sampleRate: 1,
550
550
  },
551
551
  getDefaultProps: (_event, props) => ({
552
552
  ...props,
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Analytics now recovers from stale route chunks after deploys instead of leaving dashboards stuck on failed module loads.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Metric dashboard cards now show warehouse-backed numeric values correctly when query results return numbers as strings.
@@ -113,7 +113,7 @@ export default defineAction({
113
113
  sessionId: session.sessionId,
114
114
  meta: {
115
115
  ...session.meta,
116
- skipCompressionWait: true,
116
+ stableUrl: true,
117
117
  recordAsset: false,
118
118
  },
119
119
  bytesUploaded: 0,
@@ -596,7 +596,7 @@ export default defineAction({
596
596
  typeof resumableSession.meta.filename === "string"
597
597
  ? resumableSession.meta.filename
598
598
  : "",
599
- { skipCompressionWait: true, recordAsset: false },
599
+ { stableUrl: true, recordAsset: false },
600
600
  );
601
601
  debugLog("[finalize] resumable upload completed", { id, videoUrl });
602
602
  try {
@@ -966,7 +966,7 @@ export default defineAction({
966
966
  filename: `${id}.${videoFormat}`,
967
967
  mimeType,
968
968
  ownerEmail,
969
- skipCompressionWait: true,
969
+ stableUrl: true,
970
970
  recordAsset: false,
971
971
  });
972
972
  } catch (err) {
@@ -296,7 +296,7 @@ export default defineAction({
296
296
  filename: `${id}.mp4`,
297
297
  mimeType: media.mimeType,
298
298
  ownerEmail,
299
- skipCompressionWait: true,
299
+ stableUrl: true,
300
300
  recordAsset: false,
301
301
  });
302
302
 
@@ -218,7 +218,7 @@ export async function ensureRecordingSeekable(params: {
218
218
  filename: `${recordingId}.${videoFormat}`,
219
219
  mimeType,
220
220
  ownerEmail,
221
- skipCompressionWait: true,
221
+ stableUrl: true,
222
222
  recordAsset: false,
223
223
  });
224
224
 
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Clip video uploads now compress in the background while keeping a single stable playback URL.