@agent-native/core 0.90.9 → 0.90.11

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 (132) hide show
  1. package/README.md +7 -28
  2. package/corpus/README.md +1 -1
  3. package/corpus/core/CHANGELOG.md +18 -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/durable-background.ts +5 -5
  28. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +40 -8
  29. package/corpus/core/src/agent/engine/anthropic-engine.ts +25 -7
  30. package/corpus/core/src/agent/engine/output-tokens.ts +94 -0
  31. package/corpus/core/src/agent/production-agent.ts +46 -7
  32. package/corpus/core/src/agent/types.ts +3 -2
  33. package/corpus/core/src/client/analytics.ts +17 -3
  34. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +3 -1
  35. package/corpus/core/src/client/blocks/library/wireframe.tsx +6 -1
  36. package/corpus/core/src/db/client.ts +12 -9
  37. package/corpus/core/src/file-upload/builder.ts +10 -23
  38. package/corpus/core/src/file-upload/types.ts +3 -3
  39. package/corpus/core/src/shared/reasoning-effort.ts +23 -0
  40. package/corpus/core/src/styles/blocks.css +7 -0
  41. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +9 -4
  42. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +21 -7
  43. package/corpus/templates/analytics/app/entry.client.tsx +6 -1
  44. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -1
  45. package/corpus/templates/analytics/changelog/2026-07-07-analytics-now-recovers-from-stale-route-chunks-after-deploys.md +6 -0
  46. package/corpus/templates/analytics/changelog/2026-07-07-metric-dashboard-cards-now-show-warehouse-backed-numeric-val.md +6 -0
  47. package/corpus/templates/clips/actions/create-recording.ts +1 -1
  48. package/corpus/templates/clips/actions/finalize-recording.ts +2 -2
  49. package/corpus/templates/clips/actions/import-loom-recording.ts +1 -1
  50. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +1 -1
  51. package/corpus/templates/clips/actions/regenerate-chapters.ts +7 -0
  52. package/corpus/templates/clips/app/hooks/use-auto-title.ts +15 -5
  53. package/corpus/templates/clips/app/routes/download.tsx +12 -4
  54. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -0
  55. package/corpus/templates/clips/changelog/2026-07-07-auto-generated-chapter-requests-now-open-the-matching-agent-.md +6 -0
  56. package/corpus/templates/clips/changelog/2026-07-07-clip-video-uploads-now-compress-in-the-background-while-keeping.md +6 -0
  57. package/corpus/templates/clips/changelog/2026-07-07-desktop-settings-and-fn-dictation-are-more-reliable.md +6 -0
  58. package/corpus/templates/clips/changelog/2026-07-07-desktop-settings-now-includes-a-manual-update-check-with-res.md +6 -0
  59. package/corpus/templates/clips/changelog/2026-07-07-the-clips-desktop-download-page-now-uses-the-agent-native-ap.md +6 -0
  60. package/corpus/templates/clips/desktop/src/app.tsx +95 -8
  61. package/corpus/templates/clips/desktop/src/lib/updater.ts +60 -43
  62. package/corpus/templates/clips/desktop/src/styles.css +5 -0
  63. package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +93 -23
  64. package/corpus/templates/dispatch/changelog/2026-07-07-overview-is-now-just-ask-dispatch-and-a-list-of-apps.md +6 -0
  65. package/dist/agent/durable-background.d.ts +1 -1
  66. package/dist/agent/durable-background.d.ts.map +1 -1
  67. package/dist/agent/durable-background.js +5 -3
  68. package/dist/agent/durable-background.js.map +1 -1
  69. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  70. package/dist/agent/engine/ai-sdk-engine.js +24 -4
  71. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  72. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  73. package/dist/agent/engine/anthropic-engine.js +13 -3
  74. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  75. package/dist/agent/engine/output-tokens.d.ts +27 -0
  76. package/dist/agent/engine/output-tokens.d.ts.map +1 -1
  77. package/dist/agent/engine/output-tokens.js +70 -0
  78. package/dist/agent/engine/output-tokens.js.map +1 -1
  79. package/dist/agent/production-agent.d.ts.map +1 -1
  80. package/dist/agent/production-agent.js +41 -7
  81. package/dist/agent/production-agent.js.map +1 -1
  82. package/dist/agent/types.d.ts +3 -2
  83. package/dist/agent/types.d.ts.map +1 -1
  84. package/dist/agent/types.js.map +1 -1
  85. package/dist/client/analytics.d.ts.map +1 -1
  86. package/dist/client/analytics.js +14 -3
  87. package/dist/client/analytics.js.map +1 -1
  88. package/dist/client/blocks/library/wireframe-kit.d.ts +1 -0
  89. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  90. package/dist/client/blocks/library/wireframe-kit.js +2 -1
  91. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  92. package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
  93. package/dist/client/blocks/library/wireframe.js +6 -1
  94. package/dist/client/blocks/library/wireframe.js.map +1 -1
  95. package/dist/db/client.d.ts.map +1 -1
  96. package/dist/db/client.js +12 -7
  97. package/dist/db/client.js.map +1 -1
  98. package/dist/file-upload/builder.d.ts.map +1 -1
  99. package/dist/file-upload/builder.js +9 -19
  100. package/dist/file-upload/builder.js.map +1 -1
  101. package/dist/file-upload/types.d.ts +3 -3
  102. package/dist/file-upload/types.d.ts.map +1 -1
  103. package/dist/file-upload/types.js.map +1 -1
  104. package/dist/secrets/routes.d.ts +6 -6
  105. package/dist/shared/reasoning-effort.d.ts +1 -0
  106. package/dist/shared/reasoning-effort.d.ts.map +1 -1
  107. package/dist/shared/reasoning-effort.js +18 -0
  108. package/dist/shared/reasoning-effort.js.map +1 -1
  109. package/dist/styles/blocks.css +7 -0
  110. package/docs/content/agent-native-toolkit.mdx +1 -1
  111. package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
  112. package/docs/content/locales/ar-SA/tracking.mdx +3 -3
  113. package/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
  114. package/docs/content/locales/de-DE/tracking.mdx +3 -3
  115. package/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
  116. package/docs/content/locales/es-ES/tracking.mdx +3 -3
  117. package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
  118. package/docs/content/locales/fr-FR/tracking.mdx +3 -3
  119. package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
  120. package/docs/content/locales/hi-IN/tracking.mdx +3 -3
  121. package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
  122. package/docs/content/locales/ja-JP/tracking.mdx +3 -3
  123. package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
  124. package/docs/content/locales/ko-KR/tracking.mdx +3 -3
  125. package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
  126. package/docs/content/locales/pt-BR/tracking.mdx +3 -3
  127. package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
  128. package/docs/content/locales/zh-CN/tracking.mdx +3 -3
  129. package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
  130. package/docs/content/locales/zh-TW/tracking.mdx +3 -3
  131. package/docs/content/tracking.mdx +3 -3
  132. 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.11",
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": {
@@ -260,12 +260,12 @@ export function backgroundRunMarkerExpectsBackgroundRuntime(
260
260
  }
261
261
 
262
262
  export function shouldUseBackgroundFunctionTimeoutForWorker(
263
- marker: unknown,
263
+ _marker: unknown,
264
264
  ): boolean {
265
- return (
266
- isInBackgroundFunctionRuntime() ||
267
- backgroundRunMarkerExpectsBackgroundRuntime(marker)
268
- );
265
+ // The dispatch marker says which URL the foreground targeted, not where the
266
+ // request actually landed. Only the worker runtime proof can safely lift the
267
+ // hosted 40s clamp to the 15-minute background-function budget.
268
+ return isInBackgroundFunctionRuntime();
269
269
  }
270
270
 
271
271
  export function backgroundRuntimeDiagnosticDetail(marker: unknown): string {
@@ -19,7 +19,10 @@ import {
19
19
  } from "../../server/credential-provider.js";
20
20
  import { normalizeReasoningEffortForModel } from "../../shared/reasoning-effort.js";
21
21
  import { AI_SDK_MODEL_CONFIG, type AISDKProvider } from "../model-config.js";
22
- import { resolveMaxOutputTokensForEngine } from "./output-tokens.js";
22
+ import {
23
+ clampThinkingBudgetTokens,
24
+ resolveMaxOutputTokensForEngine,
25
+ } from "./output-tokens.js";
23
26
  import {
24
27
  engineToolsToAISDK,
25
28
  engineMessagesToAISDK,
@@ -262,16 +265,34 @@ class AISDKEngine implements AgentEngine {
262
265
  toolResultImages: this.capabilities.vision,
263
266
  });
264
267
 
268
+ // Resolved once so both `maxOutputTokens` (below, in the streamText call)
269
+ // and the thinking-budget headroom clamp agree on the same ceiling.
270
+ const resolvedMaxOutputTokens = resolveMaxOutputTokensForEngine(
271
+ this.name,
272
+ opts.maxOutputTokens,
273
+ opts.model,
274
+ );
275
+
265
276
  // Build providerOptions for Anthropic-native features when using Anthropic provider
266
277
  const providerOpts: Record<string, unknown> = {};
267
278
  if (this.provider === "anthropic" && opts.providerOptions?.anthropic) {
268
279
  const anthropicOpts = opts.providerOptions.anthropic;
269
280
  if (anthropicOpts.thinking) {
281
+ // Only the "enabled" config carries a numeric budgetTokens; clamp it
282
+ // so thinking can't consume the entire maxOutputTokens budget and
283
+ // leave zero room for the actual response ("adaptive" thinking has
284
+ // no budgetTokens field at all per @ai-sdk/anthropic's schema).
270
285
  providerOpts.anthropic = {
271
286
  ...((providerOpts.anthropic as object) ?? {}),
272
287
  thinking: {
273
288
  type: "enabled",
274
- budgetTokens: anthropicOpts.thinking.budgetTokens,
289
+ budgetTokens:
290
+ typeof anthropicOpts.thinking.budgetTokens === "number"
291
+ ? clampThinkingBudgetTokens(
292
+ anthropicOpts.thinking.budgetTokens,
293
+ resolvedMaxOutputTokens,
294
+ )
295
+ : anthropicOpts.thinking.budgetTokens,
275
296
  },
276
297
  };
277
298
  }
@@ -309,11 +330,26 @@ class AISDKEngine implements AgentEngine {
309
330
  // Gemini 3.x models reject thinkingBudget — they require thinkingLevel.
310
331
  // Gemini 2.5.x models use thinkingBudget (integer token count or -1).
311
332
  const isGemini3 = /^gemini-3/.test(opts.model);
333
+ const thinkingBudget = googleThinkingBudget(reasoningEffort);
312
334
  providerOpts.google = {
313
335
  ...((providerOpts.google as object) ?? {}),
314
336
  thinkingConfig: isGemini3
315
337
  ? { thinkingLevel: gemini3ThinkingLevel(reasoningEffort) }
316
- : { thinkingBudget: googleThinkingBudget(reasoningEffort) },
338
+ : {
339
+ // Unlike Anthropic's adaptive thinking, Gemini 2.5's
340
+ // thinkingBudget IS a concrete numeric token count, so the
341
+ // same headroom clamp applies: at "max" effort this maps to
342
+ // 32000 tokens, which can equal (or exceed) a small
343
+ // maxOutputTokens cap and leave zero room for the actual
344
+ // response. Preserve Gemini's -1 "dynamic" sentinel.
345
+ thinkingBudget:
346
+ thinkingBudget > 0
347
+ ? clampThinkingBudgetTokens(
348
+ thinkingBudget,
349
+ resolvedMaxOutputTokens,
350
+ )
351
+ : thinkingBudget,
352
+ },
317
353
  };
318
354
  }
319
355
  }
@@ -326,11 +362,7 @@ class AISDKEngine implements AgentEngine {
326
362
  system: opts.systemPrompt,
327
363
  messages,
328
364
  tools: aiSdkTools,
329
- maxOutputTokens: resolveMaxOutputTokensForEngine(
330
- this.name,
331
- opts.maxOutputTokens,
332
- opts.model,
333
- ),
365
+ maxOutputTokens: resolvedMaxOutputTokens,
334
366
  ...(opts.temperature !== undefined
335
367
  ? { temperature: opts.temperature }
336
368
  : {}),
@@ -19,7 +19,10 @@ import {
19
19
  LLM_MISSING_CREDENTIALS_ERROR_CODE,
20
20
  LLM_MISSING_CREDENTIALS_MESSAGE,
21
21
  } from "./credential-errors.js";
22
- import { resolveMaxOutputTokensForEngine } from "./output-tokens.js";
22
+ import {
23
+ clampThinkingBudgetTokens,
24
+ resolveMaxOutputTokensForEngine,
25
+ } from "./output-tokens.js";
23
26
  import {
24
27
  engineToolsToAnthropic,
25
28
  engineMessagesToAnthropic,
@@ -67,12 +70,31 @@ class AnthropicEngine implements AgentEngine {
67
70
  const messages = engineMessagesToAnthropic(opts.messages);
68
71
  const anthropicOpts = opts.providerOptions?.anthropic;
69
72
 
73
+ // Resolved once so both max_tokens and the thinking-budget headroom
74
+ // clamp below agree on the same ceiling.
75
+ const resolvedMaxOutputTokens = resolveMaxOutputTokensForEngine(
76
+ this.name,
77
+ opts.maxOutputTokens,
78
+ opts.model,
79
+ );
80
+
70
81
  // Build extra body params for Anthropic-native features
71
82
  const extra: Record<string, unknown> = {};
72
83
  if (anthropicOpts?.thinking) {
73
84
  extra.thinking = {
74
85
  type: anthropicOpts.thinking.type,
75
- budget_tokens: anthropicOpts.thinking.budgetTokens,
86
+ // Only the "enabled" config carries a numeric budget_tokens; clamp it
87
+ // so thinking can't consume the entire max_tokens budget and leave
88
+ // zero room for the actual response ("adaptive" thinking has no
89
+ // budget_tokens field at all, so it passes through unclamped).
90
+ budget_tokens:
91
+ anthropicOpts.thinking.type === "enabled" &&
92
+ typeof anthropicOpts.thinking.budgetTokens === "number"
93
+ ? clampThinkingBudgetTokens(
94
+ anthropicOpts.thinking.budgetTokens,
95
+ resolvedMaxOutputTokens,
96
+ )
97
+ : anthropicOpts.thinking.budgetTokens,
76
98
  };
77
99
  }
78
100
  if (anthropicOpts?.topK !== undefined) {
@@ -139,11 +161,7 @@ class AnthropicEngine implements AgentEngine {
139
161
 
140
162
  const requestParams: any = {
141
163
  model: opts.model,
142
- max_tokens: resolveMaxOutputTokensForEngine(
143
- this.name,
144
- opts.maxOutputTokens,
145
- opts.model,
146
- ),
164
+ max_tokens: resolvedMaxOutputTokens,
147
165
  system: systemBlocks,
148
166
  tools: cachedTools.length > 0 ? cachedTools : undefined,
149
167
  messages: cachedMessages,
@@ -13,6 +13,100 @@ export const DEFAULT_AI_SDK_MAX_OUTPUT_TOKENS = 4096;
13
13
  export const DEFAULT_ANTHROPIC_MAX_OUTPUT_TOKENS = 8192;
14
14
  export const DEFAULT_BUILDER_MAX_OUTPUT_TOKENS = 8192;
15
15
 
16
+ // ---------------------------------------------------------------------------
17
+ // Main interactive chat path
18
+ //
19
+ // The per-engine defaults above (4096-8192) exist for internal/eval/
20
+ // observational-memory callers that intentionally want a small explicit cap.
21
+ // The main interactive chat turn (the one the end user is staring at) needs
22
+ // real headroom: on long-context or reasoning-heavy turns, a tiny completion
23
+ // budget means extended thinking alone can consume the entire response,
24
+ // leaving zero tokens for visible text/tool calls ("empty response" bug).
25
+ // These helpers give the chat path a much higher floor while staying at or
26
+ // under each model's documented ceiling — they never lower the ceiling.
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /** Cap for the first attempt of an interactive chat turn. */
30
+ export const MAIN_CHAT_MAX_OUTPUT_TOKENS_CAP = 32_000;
31
+ /**
32
+ * Cap used only when retrying a turn that came back with an empty final
33
+ * response (see production-agent.ts's empty-final-response retry). Higher
34
+ * than the first-attempt cap so the retry meaningfully raises the ceiling.
35
+ */
36
+ export const EMPTY_RESPONSE_RETRY_MAX_OUTPUT_TOKENS_CAP = 64_000;
37
+
38
+ /**
39
+ * Resolve the max_output_tokens floor for the first attempt of an
40
+ * interactive chat turn: min(model ceiling, 32K). Always at or above the
41
+ * flat per-engine defaults above, regardless of whether the model is known.
42
+ */
43
+ export function resolveMainChatMaxOutputTokens(modelId?: string): number {
44
+ return Math.min(
45
+ getMaxOutputTokensForModel(modelId),
46
+ MAIN_CHAT_MAX_OUTPUT_TOKENS_CAP,
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Resolve the max_output_tokens to use when retrying a turn after an empty
52
+ * final response: min(model ceiling, 64K).
53
+ */
54
+ export function resolveEmptyResponseRetryMaxOutputTokens(
55
+ modelId?: string,
56
+ ): number {
57
+ return Math.min(
58
+ getMaxOutputTokensForModel(modelId),
59
+ EMPTY_RESPONSE_RETRY_MAX_OUTPUT_TOKENS_CAP,
60
+ );
61
+ }
62
+
63
+ // ---------------------------------------------------------------------------
64
+ // Extended-thinking budget headroom
65
+ //
66
+ // Anthropic's `thinking: { type: "enabled", budget_tokens }` config requires
67
+ // budget_tokens >= 1024 and STRICTLY LESS THAN max_tokens (confirmed against
68
+ // the installed @anthropic-ai/sdk@0.90.0 type defs — see ThinkingConfigEnabled
69
+ // in resources/messages/messages.d.ts). budget_tokens counts toward
70
+ // max_tokens, so an unclamped large budget can leave too little (or zero)
71
+ // room for the actual visible completion. This clamp guarantees at least
72
+ // max(8000, 40% of maxOutputTokens) tokens of non-thinking headroom.
73
+ //
74
+ // Note: this only applies to the explicit numeric-budget "enabled" config.
75
+ // Anthropic's `type: "adaptive"` thinking config (used by the
76
+ // reasoningEffort -> output_config.effort mapping in anthropic-engine.ts /
77
+ // ai-sdk-engine.ts) has NO budget_tokens field at all per the SDK types, so
78
+ // there is nothing to clamp there — those callers rely on the raised
79
+ // maxOutputTokens ceiling above instead.
80
+ // ---------------------------------------------------------------------------
81
+
82
+ /** Anthropic's documented minimum extended-thinking budget. */
83
+ export const ANTHROPIC_MIN_THINKING_BUDGET_TOKENS = 1024;
84
+
85
+ /**
86
+ * Clamp a requested Anthropic thinking budget so it leaves guaranteed
87
+ * headroom under `maxOutputTokens` for non-thinking output, and stays within
88
+ * the provider's valid range (>= 1024, < maxOutputTokens).
89
+ */
90
+ export function clampThinkingBudgetTokens(
91
+ requestedBudgetTokens: number,
92
+ maxOutputTokens: number,
93
+ ): number | undefined {
94
+ if (maxOutputTokens <= ANTHROPIC_MIN_THINKING_BUDGET_TOKENS) {
95
+ return undefined;
96
+ }
97
+ const headroom = Math.max(8000, Math.round(0.4 * maxOutputTokens));
98
+ const budgetCapForHeadroom = Math.max(
99
+ ANTHROPIC_MIN_THINKING_BUDGET_TOKENS,
100
+ maxOutputTokens - headroom,
101
+ );
102
+ // budget_tokens must stay strictly below max_tokens per the API contract.
103
+ const strictUpperBound = maxOutputTokens - 1;
104
+ return Math.max(
105
+ ANTHROPIC_MIN_THINKING_BUDGET_TOKENS,
106
+ Math.min(requestedBudgetTokens, budgetCapForHeadroom, strictUpperBound),
107
+ );
108
+ }
109
+
16
110
  function parsePositiveInteger(value: unknown): number | null {
17
111
  if (typeof value === "string" && value.trim() === "") return null;
18
112
  const n =
@@ -45,6 +45,7 @@ import { fireInternalDispatch } from "../server/self-dispatch.js";
45
45
  import {
46
46
  isReasoningEffort,
47
47
  normalizeReasoningEffortForModel,
48
+ stepDownReasoningEffort,
48
49
  type ReasoningEffort,
49
50
  } from "../shared/reasoning-effort.js";
50
51
  import { actionPreparationContinuationNote } from "./action-continuation-guidance.js";
@@ -77,7 +78,11 @@ import {
77
78
  normalizeModelForEngine,
78
79
  isResolvedEngineUsableForRequest,
79
80
  } from "./engine/index.js";
80
- import { resolveMaxOutputTokensForEngine } from "./engine/output-tokens.js";
81
+ import {
82
+ resolveEmptyResponseRetryMaxOutputTokens,
83
+ resolveMainChatMaxOutputTokens,
84
+ resolveMaxOutputTokensForEngine,
85
+ } from "./engine/output-tokens.js";
81
86
  import { PROVIDER_TO_ENV } from "./engine/provider-env-vars.js";
82
87
  import {
83
88
  backfillEngineMessagesToolResults,
@@ -1015,6 +1020,10 @@ const TOOL_INPUT_ACTIVITY_INTERVAL_MS = 1500;
1015
1020
  const ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS = 90_000;
1016
1021
  const ACTION_PREPARATION_ZERO_BYTE_RESTART_LIMIT = 2;
1017
1022
  const MODEL_STREAM_NO_PROGRESS_TIMEOUT_MS = 90_000;
1023
+ // Raised from 1 -> 2 now that each retry actually adapts (raises the token
1024
+ // ceiling and steps reasoning effort down a tier) instead of re-issuing the
1025
+ // exact same doomed request twice.
1026
+ const EMPTY_FINAL_RESPONSE_RETRY_LIMIT = 2;
1018
1027
  const MAIN_CHAT_INTERNAL_CONTINUATION_LIMIT = 6;
1019
1028
  const RUN_BUDGET_EXHAUSTED_ERROR_CODE = "run_budget_exhausted";
1020
1029
  const RUN_BUDGET_EXHAUSTED_MESSAGE =
@@ -2733,7 +2742,14 @@ export async function runAgentLoop(opts: {
2733
2742
  }
2734
2743
 
2735
2744
  let finalGuardRetries = 0;
2745
+ let emptyFinalResponseRetries = 0;
2736
2746
  let iterations = 0;
2747
+ // Overridden (raised tokens, lowered effort) only after an empty-final-
2748
+ // response retry below — kept separate from `opts.maxOutputTokens`/
2749
+ // `opts.reasoningEffort` so the very first attempt is unaffected and later
2750
+ // tool-loop turns revert to the caller's original request after a success.
2751
+ let effectiveMaxOutputTokens = opts.maxOutputTokens;
2752
+ let effectiveReasoningEffort = opts.reasoningEffort;
2737
2753
 
2738
2754
  // Set when an in-loop processor aborts via `abort()` / throws a `TripWire`.
2739
2755
  // The loop emits the `tripwire` event, surfaces the reason as a final
@@ -2843,10 +2859,10 @@ export async function runAgentLoop(opts: {
2843
2859
  abortSignal: signal,
2844
2860
  maxOutputTokens: resolveMaxOutputTokensForEngine(
2845
2861
  engine.name,
2846
- opts.maxOutputTokens,
2862
+ effectiveMaxOutputTokens,
2847
2863
  model,
2848
2864
  ),
2849
- reasoningEffort: opts.reasoningEffort,
2865
+ reasoningEffort: effectiveReasoningEffort,
2850
2866
  providerOptions: opts.providerOptions,
2851
2867
  };
2852
2868
 
@@ -3349,16 +3365,33 @@ export async function runAgentLoop(opts: {
3349
3365
  // text — typically when reasoning consumes the entire output-token
3350
3366
  // budget. Without a final text part the SSE stream still ends with a
3351
3367
  // clean `done`, which renders as a totally empty assistant bubble.
3352
- // Surface a plain-language error so the user knows what happened.
3353
- if (
3368
+ // Retry so a reasoning-budget miss can still finish; each retry raises
3369
+ // the token ceiling and steps reasoning effort down a tier so it's not
3370
+ // just re-issuing the identical doomed request. If retries also come
3371
+ // back empty, surface a plain-language error.
3372
+ const hasEmptyFinalResponse =
3354
3373
  !guardEmittedFallback &&
3355
3374
  collectTextParts(assistantContentForHistory).trim().length === 0 &&
3356
- streamedAssistantText.trim().length === 0
3357
- ) {
3375
+ streamedAssistantText.trim().length === 0;
3376
+ if (hasEmptyFinalResponse) {
3377
+ if (emptyFinalResponseRetries < EMPTY_FINAL_RESPONSE_RETRY_LIMIT) {
3378
+ emptyFinalResponseRetries += 1;
3379
+ effectiveMaxOutputTokens =
3380
+ resolveEmptyResponseRetryMaxOutputTokens(model);
3381
+ effectiveReasoningEffort = stepDownReasoningEffort(
3382
+ effectiveReasoningEffort,
3383
+ );
3384
+ appendAgentLoopContinuation(messages, "max_tokens");
3385
+ continue;
3386
+ }
3358
3387
  send({
3359
3388
  type: "text",
3360
3389
  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
3390
  });
3391
+ } else {
3392
+ emptyFinalResponseRetries = 0;
3393
+ effectiveMaxOutputTokens = opts.maxOutputTokens;
3394
+ effectiveReasoningEffort = opts.reasoningEffort;
3362
3395
  }
3363
3396
  break;
3364
3397
  }
@@ -3369,6 +3402,7 @@ export async function runAgentLoop(opts: {
3369
3402
  // finalGuardRetries stays at 1 from a prior cycle and the guard is
3370
3403
  // permanently disabled for the rest of a long multi-step run.
3371
3404
  finalGuardRetries = 0;
3405
+ emptyFinalResponseRetries = 0;
3372
3406
 
3373
3407
  flushUnstreamedAssistantText();
3374
3408
 
@@ -6784,6 +6818,11 @@ export function createProductionAgentHandler(
6784
6818
  orgId: getRequestOrgId() ?? null,
6785
6819
  attachments: requestAttachments,
6786
6820
  reasoningEffort,
6821
+ // The interactive chat turn needs real completion headroom — the
6822
+ // flat per-engine defaults (4096-8192) exist for internal/eval
6823
+ // callers and are far below what a hard, long-context turn needs
6824
+ // once extended thinking is in play. See output-tokens.ts.
6825
+ maxOutputTokens: resolveMainChatMaxOutputTokens(effectiveModel),
6787
6826
  providerOptions: options.providerOptions,
6788
6827
  executionMode: requestMode,
6789
6828
  maxIterations: loopSettings.maxIterations,
@@ -180,8 +180,9 @@ export interface AgentChatRequest {
180
180
  continuationCount?: number;
181
181
  /**
182
182
  * True when the dispatcher expects the self-POST to land in a real
183
- * Netlify `-background` function (15-min budget) rather than the ~60s
184
- * synchronous function. See `shouldUseBackgroundFunctionTimeoutForWorker`.
183
+ * Netlify `-background` function rather than the ~60s synchronous function.
184
+ * This is diagnostic only; the 15-minute budget is unlocked by the worker's
185
+ * actual runtime marker.
185
186
  */
186
187
  backgroundFunctionRuntimeExpected?: boolean;
187
188
  /**