@agent-native/core 0.121.2 → 0.122.0

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 (460) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +139 -0
  3. package/corpus/core/docs/content/actions.mdx +2 -2
  4. package/corpus/core/docs/content/agent-surfaces.mdx +1 -1
  5. package/corpus/core/docs/content/authentication.mdx +2 -0
  6. package/corpus/core/docs/content/deployment.mdx +36 -0
  7. package/corpus/core/docs/content/http-api.mdx +266 -0
  8. package/corpus/core/docs/content/syncing-template-changes.mdx +159 -0
  9. package/corpus/core/package.json +2 -1
  10. package/corpus/core/src/a2a/activity.ts +38 -27
  11. package/corpus/core/src/agent/engine/builder-engine.ts +35 -4
  12. package/corpus/core/src/agent/run-manager.ts +20 -1
  13. package/corpus/core/src/agent/run-store.ts +4 -1
  14. package/corpus/core/src/agent/types.ts +28 -8
  15. package/corpus/core/src/chat-threads/store.ts +45 -0
  16. package/corpus/core/src/checkpoints/index.ts +2 -0
  17. package/corpus/core/src/checkpoints/route-match.ts +13 -0
  18. package/corpus/core/src/cli/create.ts +105 -17
  19. package/corpus/core/src/cli/index.ts +20 -0
  20. package/corpus/core/src/cli/template-baseline.ts +410 -0
  21. package/corpus/core/src/cli/template-sync.ts +1004 -0
  22. package/corpus/core/src/cli/templates-meta.ts +1 -0
  23. package/corpus/core/src/client/AssistantChat.tsx +38 -12
  24. package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +75 -10
  25. package/corpus/core/src/client/chat/message-components.tsx +127 -66
  26. package/corpus/core/src/client/chat/tool-call-display.tsx +29 -5
  27. package/corpus/core/src/client/error-format.ts +18 -0
  28. package/corpus/core/src/client/org/OrgSwitcher.tsx +30 -8
  29. package/corpus/core/src/client/org/TeamPage.tsx +7 -6
  30. package/corpus/core/src/client/sse-event-processor.ts +3 -0
  31. package/corpus/core/src/data-widgets/index.ts +41 -0
  32. package/corpus/core/src/deploy/build.ts +11 -9
  33. package/corpus/core/src/integrations/webhook-handler.ts +63 -9
  34. package/corpus/core/src/org/auto-join-domain.ts +4 -3
  35. package/corpus/core/src/org/context.ts +108 -39
  36. package/corpus/core/src/org/index.ts +5 -0
  37. package/corpus/core/src/org/service-identity.ts +60 -0
  38. package/corpus/core/src/provider-api/index.ts +22 -1
  39. package/corpus/core/src/scripts/docs/search.ts +12 -1
  40. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -4
  41. package/corpus/core/src/server/agent-chat/framework-prompts.ts +38 -66
  42. package/corpus/core/src/server/agent-chat-plugin.ts +17 -10
  43. package/corpus/core/src/server/agents-bundle.ts +84 -5
  44. package/corpus/core/src/server/auth.ts +4 -3
  45. package/corpus/core/src/server/builder-browser.ts +47 -19
  46. package/corpus/core/src/server/core-routes-plugin.ts +2 -2
  47. package/corpus/core/src/server/credential-provider.ts +209 -68
  48. package/corpus/core/src/server/index.ts +3 -0
  49. package/corpus/core/src/server/prompts/framework-core-compact.ts +6 -13
  50. package/corpus/core/src/server/prompts/framework-core.ts +9 -21
  51. package/corpus/core/src/server/prompts/index.ts +0 -1
  52. package/corpus/core/src/server/prompts/shared-rules.ts +19 -11
  53. package/corpus/core/src/server/ssr-handler.ts +13 -2
  54. package/corpus/core/src/settings/user-settings.ts +13 -1
  55. package/corpus/core/src/shared/cache-control.ts +141 -0
  56. package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  57. package/corpus/core/src/templates/chat/_gitignore +1 -0
  58. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  59. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  60. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  61. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  62. package/corpus/core/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  63. package/corpus/core/src/vite/agents-bundle-plugin.ts +7 -6
  64. package/corpus/core/src/vite/client.ts +5 -0
  65. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +4 -5
  66. package/corpus/templates/analytics/.agents/skills/admin-surfaces/SKILL.md +55 -0
  67. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
  68. package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +62 -0
  69. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +85 -0
  70. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +27 -2
  71. package/corpus/templates/analytics/.agents/skills/data-querying/references/inline-chart-embeds.md +139 -0
  72. package/corpus/templates/analytics/.agents/skills/monitoring/SKILL.md +77 -0
  73. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  74. package/corpus/templates/analytics/AGENTS.md +91 -563
  75. package/corpus/templates/analytics/_gitignore +1 -0
  76. package/corpus/templates/analytics/actions/bigquery.ts +12 -4
  77. package/corpus/templates/analytics/actions/generate-chart.ts +5 -5
  78. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -1
  79. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -0
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +1 -0
  82. package/corpus/templates/analytics/changelog/2026-07-24-analytics-finds-saved-dashboards-and-queries-far-more-reliab.md +6 -0
  83. package/corpus/templates/analytics/changelog/2026-07-24-notion-access-errors-now-explain-that-a-page-needs-sharing-w.md +6 -0
  84. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +7 -0
  85. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +191 -30
  86. package/corpus/templates/analytics/server/lib/bigquery.ts +11 -1
  87. package/corpus/templates/analytics/server/lib/notion.ts +15 -4
  88. package/corpus/templates/analytics/server/plugins/agent-chat.ts +10 -0
  89. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  90. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  91. package/corpus/templates/brain/_gitignore +1 -0
  92. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  93. package/corpus/templates/calendar/_gitignore +1 -0
  94. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  95. package/corpus/templates/chat/_gitignore +1 -0
  96. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  97. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +34 -0
  98. package/corpus/templates/clips/AGENTS.md +5 -4
  99. package/corpus/templates/clips/_gitignore +1 -0
  100. package/corpus/templates/clips/actions/cleanup-transcript.ts +5 -0
  101. package/corpus/templates/clips/actions/get-recording-insights.ts +44 -8
  102. package/corpus/templates/clips/actions/get-recording-player-data.ts +39 -70
  103. package/corpus/templates/clips/actions/list-clip-views.ts +2 -4
  104. package/corpus/templates/clips/actions/list-recordings.ts +69 -19
  105. package/corpus/templates/clips/actions/list-viewers.ts +5 -2
  106. package/corpus/templates/clips/actions/regenerate-summary.ts +5 -1
  107. package/corpus/templates/clips/actions/request-transcript.ts +28 -1
  108. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +21 -1
  109. package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +14 -1
  110. package/corpus/templates/clips/app/components/player/insights-panel.tsx +8 -20
  111. package/corpus/templates/clips/app/components/player/recording-views-badge.tsx +335 -0
  112. package/corpus/templates/clips/app/components/player/video-player.tsx +13 -8
  113. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +2 -1
  114. package/corpus/templates/clips/app/i18n/en-US.ts +13 -2
  115. package/corpus/templates/clips/app/lib/capture-permissions.ts +110 -0
  116. package/corpus/templates/clips/app/lib/recording-link.ts +32 -0
  117. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +27 -0
  118. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +46 -15
  119. package/corpus/templates/clips/app/routes/record.tsx +77 -31
  120. package/corpus/templates/clips/app/routes/share.$shareId.tsx +42 -31
  121. package/corpus/templates/clips/changelog/2026-07-24-clip-pages-now-show-a-view-count-with-viewer-avatars-next-to.md +6 -0
  122. package/corpus/templates/clips/changelog/2026-07-24-clip-summaries-read-like-a-description-you-d-write-yourself-.md +6 -0
  123. package/corpus/templates/clips/changelog/2026-07-24-clip-view-counts-now-separate-human-views-from-agent-views-s.md +6 -0
  124. package/corpus/templates/clips/changelog/2026-07-24-clips-actions-can-now-be-called-by-org-service-tokens-so-ext.md +6 -0
  125. package/corpus/templates/clips/changelog/2026-07-24-clips-no-longer-briefly-shows-a-dock-icon-while-launching.md +6 -0
  126. package/corpus/templates/clips/changelog/2026-07-24-fixed-owner-and-editor-share-links-redirecting-to-the-record.md +6 -0
  127. package/corpus/templates/clips/changelog/2026-07-24-meeting-and-note-recordings-now-start-as-a-compact-pill-on-t.md +6 -0
  128. package/corpus/templates/clips/changelog/2026-07-24-new-clips-now-copy-a-shareable-link-instead-of-the-owner-onl.md +6 -0
  129. package/corpus/templates/clips/changelog/2026-07-24-opening-a-share-link-as-the-clip-s-owner-now-goes-straight-t.md +6 -0
  130. package/corpus/templates/clips/changelog/2026-07-24-permissions-and-rewind-controls-now-use-compact-consistent-h.md +6 -0
  131. package/corpus/templates/clips/changelog/2026-07-24-quitting-the-desktop-app-no-longer-shows-a-false-macos-crash.md +6 -0
  132. package/corpus/templates/clips/changelog/2026-07-24-screen-recording-permission-errors-now-name-the-exact-app-to.md +6 -0
  133. package/corpus/templates/clips/changelog/2026-07-24-the-desktop-app-now-copies-a-new-clip-s-share-link-to-your-c.md +6 -0
  134. package/corpus/templates/clips/changelog/2026-07-24-the-recording-toolbar-now-stays-above-other-apps-including-o.md +6 -0
  135. package/corpus/templates/clips/changelog/2026-07-24-transcript-captions-now-use-real-speech-timings-instead-of-a.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-24-video-playback-no-longer-stutters-and-replays-the-last-momen.md +6 -0
  137. package/corpus/templates/clips/chrome-extension/src/background.ts +17 -1
  138. package/corpus/templates/clips/desktop/package.json +2 -0
  139. package/corpus/templates/clips/desktop/src/app.tsx +89 -0
  140. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +9 -3
  141. package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +51 -0
  142. package/corpus/templates/clips/desktop/src/lib/native-notification.ts +44 -0
  143. package/corpus/templates/clips/desktop/src/lib/recording-link.ts +67 -0
  144. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +35 -35
  145. package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +3 -2
  146. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +47 -46
  147. package/corpus/templates/clips/desktop/src/styles.css +127 -78
  148. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +7 -0
  149. package/corpus/templates/clips/desktop/src-tauri/Info.plist +6 -0
  150. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +1 -0
  151. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +7 -3
  152. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -1
  153. package/corpus/templates/clips/desktop/src-tauri/src/main.rs +8 -0
  154. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -10
  155. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +40 -0
  156. package/corpus/templates/clips/server/db/schema.ts +25 -0
  157. package/corpus/templates/clips/server/lib/agent-views.ts +145 -0
  158. package/corpus/templates/clips/server/lib/public-agent-context.ts +7 -0
  159. package/corpus/templates/clips/server/lib/recording-share-grant.ts +79 -0
  160. package/corpus/templates/clips/server/lib/recordings.ts +51 -3
  161. package/corpus/templates/clips/server/plugins/db.ts +23 -0
  162. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +49 -17
  163. package/corpus/templates/clips/shared/recording-link.ts +43 -0
  164. package/corpus/templates/clips/shared/share-attribution.ts +4 -0
  165. package/corpus/templates/clips/shared/share-dashboard-redirect.ts +42 -0
  166. package/corpus/templates/clips/shared/view-analytics.ts +26 -0
  167. package/corpus/templates/content/.agents/skills/content/SKILL.md +5 -0
  168. package/corpus/templates/content/.agents/skills/content/references/local-file-mode.md +135 -0
  169. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +12 -0
  170. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +238 -0
  171. package/corpus/templates/content/.agents/skills/document-editing/references/document-behavior.md +91 -0
  172. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  173. package/corpus/templates/content/AGENTS.md +62 -583
  174. package/corpus/templates/content/_gitignore +1 -0
  175. package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +11 -0
  176. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +50 -8
  177. package/corpus/templates/design/.agents/skills/design-generation/references/code-layers.md +81 -0
  178. package/corpus/templates/design/.agents/skills/design-generation/references/code-workspace.md +42 -0
  179. package/corpus/templates/design/.agents/skills/design-generation/references/editor-extensions.md +34 -0
  180. package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +4 -1
  181. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  182. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
  183. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +8196 -0
  184. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +265 -0
  185. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +642 -0
  186. package/corpus/templates/design/.generated/bridge/motion-preview.generated.ts +571 -0
  187. package/corpus/templates/design/.generated/bridge/nav.generated.ts +91 -0
  188. package/corpus/templates/design/.generated/bridge/sample.generated.ts +23 -0
  189. package/corpus/templates/design/.generated/bridge/shader-fill-preview.generated.ts +263 -0
  190. package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +518 -0
  191. package/corpus/templates/design/.generated/bridge/tweak.generated.ts +20 -0
  192. package/corpus/templates/design/.generated/bridge/zoom.generated.ts +32 -0
  193. package/corpus/templates/design/AGENTS.md +88 -503
  194. package/corpus/templates/design/_gitignore +1 -0
  195. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  196. package/corpus/templates/dispatch/_gitignore +1 -0
  197. package/corpus/templates/dispatch/changelog/2026-07-24-signing-in-now-puts-you-in-your-companys-workspace.md +6 -0
  198. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  199. package/corpus/templates/forms/_gitignore +1 -0
  200. package/corpus/templates/forms/server/lib/public-form-ssr.ts +2 -2
  201. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  202. package/corpus/templates/macros/_gitignore +1 -0
  203. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  204. package/corpus/templates/mail/_gitignore +1 -0
  205. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  206. package/corpus/templates/plan/_gitignore +1 -0
  207. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  208. package/corpus/templates/slides/_gitignore +1 -0
  209. package/corpus/templates/slides/server/plugins/db.ts +4 -0
  210. package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  211. package/corpus/templates/tasks/AGENTS.md +1 -1
  212. package/corpus/templates/tasks/_gitignore +1 -0
  213. package/dist/a2a/activity.d.ts +4 -1
  214. package/dist/a2a/activity.d.ts.map +1 -1
  215. package/dist/a2a/activity.js +27 -16
  216. package/dist/a2a/activity.js.map +1 -1
  217. package/dist/agent/engine/builder-engine.d.ts +1 -0
  218. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  219. package/dist/agent/engine/builder-engine.js +31 -4
  220. package/dist/agent/engine/builder-engine.js.map +1 -1
  221. package/dist/agent/run-manager.d.ts.map +1 -1
  222. package/dist/agent/run-manager.js +18 -1
  223. package/dist/agent/run-manager.js.map +1 -1
  224. package/dist/agent/run-store.d.ts +1 -0
  225. package/dist/agent/run-store.d.ts.map +1 -1
  226. package/dist/agent/run-store.js +2 -1
  227. package/dist/agent/run-store.js.map +1 -1
  228. package/dist/agent/types.d.ts +12 -1
  229. package/dist/agent/types.d.ts.map +1 -1
  230. package/dist/agent/types.js +21 -1
  231. package/dist/agent/types.js.map +1 -1
  232. package/dist/chat-threads/store.d.ts +10 -0
  233. package/dist/chat-threads/store.d.ts.map +1 -1
  234. package/dist/chat-threads/store.js +41 -0
  235. package/dist/chat-threads/store.js.map +1 -1
  236. package/dist/checkpoints/index.d.ts +1 -0
  237. package/dist/checkpoints/index.d.ts.map +1 -1
  238. package/dist/checkpoints/index.js +1 -0
  239. package/dist/checkpoints/index.js.map +1 -1
  240. package/dist/checkpoints/route-match.d.ts +8 -0
  241. package/dist/checkpoints/route-match.d.ts.map +1 -0
  242. package/dist/checkpoints/route-match.js +13 -0
  243. package/dist/checkpoints/route-match.js.map +1 -0
  244. package/dist/cli/create.d.ts +35 -4
  245. package/dist/cli/create.d.ts.map +1 -1
  246. package/dist/cli/create.js +69 -19
  247. package/dist/cli/create.js.map +1 -1
  248. package/dist/cli/index.js +19 -0
  249. package/dist/cli/index.js.map +1 -1
  250. package/dist/cli/template-baseline.d.ts +54 -0
  251. package/dist/cli/template-baseline.d.ts.map +1 -0
  252. package/dist/cli/template-baseline.js +334 -0
  253. package/dist/cli/template-baseline.js.map +1 -0
  254. package/dist/cli/template-sync.d.ts +57 -0
  255. package/dist/cli/template-sync.d.ts.map +1 -0
  256. package/dist/cli/template-sync.js +787 -0
  257. package/dist/cli/template-sync.js.map +1 -0
  258. package/dist/cli/templates-meta.d.ts.map +1 -1
  259. package/dist/cli/templates-meta.js +1 -0
  260. package/dist/cli/templates-meta.js.map +1 -1
  261. package/dist/client/AssistantChat.d.ts +2 -1
  262. package/dist/client/AssistantChat.d.ts.map +1 -1
  263. package/dist/client/AssistantChat.js +38 -10
  264. package/dist/client/AssistantChat.js.map +1 -1
  265. package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
  266. package/dist/client/NewWorkspaceAppFlow.js +32 -2
  267. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  268. package/dist/client/chat/message-components.d.ts +20 -0
  269. package/dist/client/chat/message-components.d.ts.map +1 -1
  270. package/dist/client/chat/message-components.js +81 -46
  271. package/dist/client/chat/message-components.js.map +1 -1
  272. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  273. package/dist/client/chat/tool-call-display.js +14 -6
  274. package/dist/client/chat/tool-call-display.js.map +1 -1
  275. package/dist/client/error-format.d.ts.map +1 -1
  276. package/dist/client/error-format.js +13 -0
  277. package/dist/client/error-format.js.map +1 -1
  278. package/dist/client/org/OrgSwitcher.d.ts +8 -1
  279. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  280. package/dist/client/org/OrgSwitcher.js +3 -2
  281. package/dist/client/org/OrgSwitcher.js.map +1 -1
  282. package/dist/client/org/TeamPage.d.ts.map +1 -1
  283. package/dist/client/org/TeamPage.js +1 -1
  284. package/dist/client/org/TeamPage.js.map +1 -1
  285. package/dist/client/sse-event-processor.d.ts.map +1 -1
  286. package/dist/client/sse-event-processor.js +3 -0
  287. package/dist/client/sse-event-processor.js.map +1 -1
  288. package/dist/collab/awareness.d.ts +2 -2
  289. package/dist/collab/awareness.d.ts.map +1 -1
  290. package/dist/data-widgets/index.d.ts +3 -0
  291. package/dist/data-widgets/index.d.ts.map +1 -1
  292. package/dist/data-widgets/index.js +33 -0
  293. package/dist/data-widgets/index.js.map +1 -1
  294. package/dist/deploy/build.d.ts.map +1 -1
  295. package/dist/deploy/build.js +11 -7
  296. package/dist/deploy/build.js.map +1 -1
  297. package/dist/eject/provider-api-definitions.d.ts +1 -0
  298. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  299. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  300. package/dist/integrations/webhook-handler.js +46 -9
  301. package/dist/integrations/webhook-handler.js.map +1 -1
  302. package/dist/org/auto-join-domain.d.ts +3 -2
  303. package/dist/org/auto-join-domain.d.ts.map +1 -1
  304. package/dist/org/auto-join-domain.js +1 -1
  305. package/dist/org/auto-join-domain.js.map +1 -1
  306. package/dist/org/context.d.ts.map +1 -1
  307. package/dist/org/context.js +84 -28
  308. package/dist/org/context.js.map +1 -1
  309. package/dist/org/index.d.ts +1 -0
  310. package/dist/org/index.d.ts.map +1 -1
  311. package/dist/org/index.js +1 -0
  312. package/dist/org/index.js.map +1 -1
  313. package/dist/org/service-identity.d.ts +43 -0
  314. package/dist/org/service-identity.d.ts.map +1 -0
  315. package/dist/org/service-identity.js +34 -0
  316. package/dist/org/service-identity.js.map +1 -0
  317. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  318. package/dist/provider-api/actions/provider-api.d.ts +13 -11
  319. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  320. package/dist/provider-api/index.d.ts +4 -0
  321. package/dist/provider-api/index.d.ts.map +1 -1
  322. package/dist/provider-api/index.js +17 -1
  323. package/dist/provider-api/index.js.map +1 -1
  324. package/dist/resources/handlers.d.ts +1 -1
  325. package/dist/scripts/docs/search.d.ts.map +1 -1
  326. package/dist/scripts/docs/search.js +12 -1
  327. package/dist/scripts/docs/search.js.map +1 -1
  328. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  329. package/dist/server/agent-chat/context-tools.js +3 -3
  330. package/dist/server/agent-chat/context-tools.js.map +1 -1
  331. package/dist/server/agent-chat/framework-prompts.d.ts +8 -3
  332. package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
  333. package/dist/server/agent-chat/framework-prompts.js +33 -62
  334. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  335. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  336. package/dist/server/agent-chat-plugin.js +16 -10
  337. package/dist/server/agent-chat-plugin.js.map +1 -1
  338. package/dist/server/agents-bundle.d.ts +18 -0
  339. package/dist/server/agents-bundle.d.ts.map +1 -1
  340. package/dist/server/agents-bundle.js +70 -4
  341. package/dist/server/agents-bundle.js.map +1 -1
  342. package/dist/server/auth.d.ts.map +1 -1
  343. package/dist/server/auth.js +4 -3
  344. package/dist/server/auth.js.map +1 -1
  345. package/dist/server/builder-browser.d.ts.map +1 -1
  346. package/dist/server/builder-browser.js +43 -19
  347. package/dist/server/builder-browser.js.map +1 -1
  348. package/dist/server/core-routes-plugin.js +2 -2
  349. package/dist/server/core-routes-plugin.js.map +1 -1
  350. package/dist/server/credential-provider.d.ts +38 -2
  351. package/dist/server/credential-provider.d.ts.map +1 -1
  352. package/dist/server/credential-provider.js +142 -64
  353. package/dist/server/credential-provider.js.map +1 -1
  354. package/dist/server/index.d.ts +1 -1
  355. package/dist/server/index.d.ts.map +1 -1
  356. package/dist/server/index.js +1 -1
  357. package/dist/server/index.js.map +1 -1
  358. package/dist/server/prompts/framework-core-compact.d.ts +1 -1
  359. package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
  360. package/dist/server/prompts/framework-core-compact.js +7 -13
  361. package/dist/server/prompts/framework-core-compact.js.map +1 -1
  362. package/dist/server/prompts/framework-core.d.ts +1 -1
  363. package/dist/server/prompts/framework-core.d.ts.map +1 -1
  364. package/dist/server/prompts/framework-core.js +10 -21
  365. package/dist/server/prompts/framework-core.js.map +1 -1
  366. package/dist/server/prompts/index.d.ts +1 -1
  367. package/dist/server/prompts/index.d.ts.map +1 -1
  368. package/dist/server/prompts/index.js +1 -1
  369. package/dist/server/prompts/index.js.map +1 -1
  370. package/dist/server/prompts/shared-rules.d.ts +16 -10
  371. package/dist/server/prompts/shared-rules.d.ts.map +1 -1
  372. package/dist/server/prompts/shared-rules.js +19 -10
  373. package/dist/server/prompts/shared-rules.js.map +1 -1
  374. package/dist/server/ssr-handler.d.ts +1 -1
  375. package/dist/server/ssr-handler.d.ts.map +1 -1
  376. package/dist/server/ssr-handler.js +10 -3
  377. package/dist/server/ssr-handler.js.map +1 -1
  378. package/dist/settings/user-settings.d.ts.map +1 -1
  379. package/dist/settings/user-settings.js +13 -1
  380. package/dist/settings/user-settings.js.map +1 -1
  381. package/dist/shared/cache-control.d.ts +52 -0
  382. package/dist/shared/cache-control.d.ts.map +1 -1
  383. package/dist/shared/cache-control.js +107 -0
  384. package/dist/shared/cache-control.js.map +1 -1
  385. package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  386. package/dist/templates/chat/_gitignore +1 -0
  387. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  388. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  389. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  390. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  391. package/dist/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  392. package/dist/vite/agents-bundle-plugin.d.ts.map +1 -1
  393. package/dist/vite/agents-bundle-plugin.js +8 -7
  394. package/dist/vite/agents-bundle-plugin.js.map +1 -1
  395. package/dist/vite/client.d.ts.map +1 -1
  396. package/dist/vite/client.js +2 -0
  397. package/dist/vite/client.js.map +1 -1
  398. package/docs/content/actions.mdx +2 -2
  399. package/docs/content/agent-surfaces.mdx +1 -1
  400. package/docs/content/authentication.mdx +2 -0
  401. package/docs/content/deployment.mdx +36 -0
  402. package/docs/content/http-api.mdx +266 -0
  403. package/docs/content/syncing-template-changes.mdx +159 -0
  404. package/package.json +4 -3
  405. package/src/a2a/activity.ts +38 -27
  406. package/src/agent/engine/builder-engine.ts +35 -4
  407. package/src/agent/run-manager.ts +20 -1
  408. package/src/agent/run-store.ts +4 -1
  409. package/src/agent/types.ts +28 -8
  410. package/src/chat-threads/store.ts +45 -0
  411. package/src/checkpoints/index.ts +2 -0
  412. package/src/checkpoints/route-match.ts +13 -0
  413. package/src/cli/create.ts +105 -17
  414. package/src/cli/index.ts +20 -0
  415. package/src/cli/template-baseline.ts +410 -0
  416. package/src/cli/template-sync.ts +1004 -0
  417. package/src/cli/templates-meta.ts +1 -0
  418. package/src/client/AssistantChat.tsx +38 -12
  419. package/src/client/NewWorkspaceAppFlow.tsx +75 -10
  420. package/src/client/chat/message-components.tsx +127 -66
  421. package/src/client/chat/tool-call-display.tsx +29 -5
  422. package/src/client/error-format.ts +18 -0
  423. package/src/client/org/OrgSwitcher.tsx +30 -8
  424. package/src/client/org/TeamPage.tsx +7 -6
  425. package/src/client/sse-event-processor.ts +3 -0
  426. package/src/data-widgets/index.ts +41 -0
  427. package/src/deploy/build.ts +11 -9
  428. package/src/integrations/webhook-handler.ts +63 -9
  429. package/src/org/auto-join-domain.ts +4 -3
  430. package/src/org/context.ts +108 -39
  431. package/src/org/index.ts +5 -0
  432. package/src/org/service-identity.ts +60 -0
  433. package/src/provider-api/index.ts +22 -1
  434. package/src/scripts/docs/search.ts +12 -1
  435. package/src/server/__snapshots__/agent-chat-plugin.surface.spec.ts.snap +25 -36
  436. package/src/server/agent-chat/context-tools.ts +9 -4
  437. package/src/server/agent-chat/framework-prompts.ts +38 -66
  438. package/src/server/agent-chat-plugin.ts +17 -10
  439. package/src/server/agents-bundle.ts +84 -5
  440. package/src/server/auth.ts +4 -3
  441. package/src/server/builder-browser.ts +47 -19
  442. package/src/server/core-routes-plugin.ts +2 -2
  443. package/src/server/credential-provider.ts +209 -68
  444. package/src/server/index.ts +3 -0
  445. package/src/server/prompts/framework-core-compact.ts +6 -13
  446. package/src/server/prompts/framework-core.ts +9 -21
  447. package/src/server/prompts/index.ts +0 -1
  448. package/src/server/prompts/shared-rules.ts +19 -11
  449. package/src/server/ssr-handler.ts +13 -2
  450. package/src/settings/user-settings.ts +13 -1
  451. package/src/shared/cache-control.ts +141 -0
  452. package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  453. package/src/templates/chat/_gitignore +1 -0
  454. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  455. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  456. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +19 -0
  457. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +24 -2
  458. package/src/templates/workspace-core/.agents/skills/visual-answer/SKILL.md +1 -0
  459. package/src/vite/agents-bundle-plugin.ts +7 -6
  460. package/src/vite/client.ts +5 -0
@@ -37,3 +37,4 @@ data/.sessions.json
37
37
  learnings.md
38
38
 
39
39
  .vercel/
40
+ .agent-native/
@@ -96,10 +96,18 @@ export default defineAction({
96
96
  "BigQuery isn't connected for this workspace yet. Open Settings -> Data sources and add BIGQUERY_PROJECT_ID + GOOGLE_APPLICATION_CREDENTIALS_JSON (a service-account JSON key).",
97
97
  );
98
98
  }
99
- if (
100
- /BigQuery (API|poll) error/i.test(msg) ||
101
- /BigQuery query timed out/i.test(msg)
102
- ) {
99
+ // A timeout means the SQL was valid but slow. Routing it through the schema-error
100
+ // branch below told the model to go re-inspect the schema and rerun, which turns
101
+ // one slow query into a loop of 60-second attempts.
102
+ if (/BigQuery query timed out/i.test(msg)) {
103
+ return {
104
+ error: "bigquery_query_timeout",
105
+ message: extractBigQueryMessage(msg),
106
+ recoverable: true,
107
+ hint: "The SQL was valid but exceeded the 60-second warehouse budget. Do NOT inspect the schema and do NOT rerun this query as-is. Make it cheaper: narrow the date range, add a LIMIT, aggregate in SQL instead of returning raw rows, or filter on a partition/cluster column. If the full scan is genuinely required, run it through run-code with background: true instead of retrying here.",
108
+ };
109
+ }
110
+ if (/BigQuery (API|poll) error/i.test(msg)) {
103
111
  // Recoverable: hand the real error back to the model so it can inspect
104
112
  // the schema and self-correct, instead of force-ending the turn.
105
113
  return {
@@ -303,16 +303,16 @@ export function renderStaticChartSvg({
303
303
  * user's chair, the chat said "I'll do something else" and no chart appeared.
304
304
  *
305
305
  * For in-chat data questions the right answer is always the live `/chart`
306
- * embed (see AGENTS.md "Inline Charts in Chat"). Only `save-analysis`
307
- * artifacts need a static image, and those flows have full data in hand
308
- * before they call here.
306
+ * embed (see the `data-querying` skill's "Inline Charts In Chat" section for
307
+ * the full shape). Only `save-analysis` artifacts need a static image, and
308
+ * those flows have full data in hand before they call here.
309
309
  */
310
310
  const CHART_FALLBACK_HINT =
311
- "If you're answering an in-chat data question, do not retry generate-chart. Switch to the live /chart embed described in AGENTS.md ('Inline Charts in Chat') — it accepts a SqlPanel object directly and doesn't require pre-stringified JSON params. Only use generate-chart when you're building a save-analysis artifact.";
311
+ "If you're answering an in-chat data question, do not retry generate-chart. Switch to the live /chart embed instead — it accepts a SqlPanel object directly and doesn't require pre-stringified JSON params. See the data-querying skill's \"Inline Charts In Chat\" section for the embed syntax. Only use generate-chart when you're building a save-analysis artifact.";
312
312
 
313
313
  export default defineAction({
314
314
  description:
315
- "Render a static chart image to the media directory **for save-analysis artifacts only**. Uses PNG when the native renderer is available and a portable SVG fallback otherwise. For an in-chat answer to a data question, do NOT call this — emit a live `/chart` embed instead (see AGENTS.md 'Inline Charts in Chat'). The static image path exists for analyses that need to render outside this app (exports, archived reports). If validation here fails, switch to the live embed rather than retrying.",
315
+ 'Render a static chart image to the media directory **for save-analysis artifacts only**. Uses PNG when the native renderer is available and a portable SVG fallback otherwise. For an in-chat answer to a data question, do NOT call this — emit a live `/chart` embed instead (see the data-querying skill\'s "Inline Charts In Chat" section for the embed syntax). The static image path exists for analyses that need to render outside this app (exports, archived reports). If validation here fails, switch to the live embed rather than retrying.',
316
316
  schema: z.object({
317
317
  title: z.string().optional().describe("Chart title (required)"),
318
318
  labels: z.string().optional().describe("JSON array of x-axis labels"),
@@ -119,6 +119,9 @@ const CHART_LEGEND_PROPS = {
119
119
  } as const;
120
120
 
121
121
  const CHART_RESIZE_DEBOUNCE_MS = 50;
122
+ // Recharts' default series animation duration, plus room for the debounced
123
+ // resize callback that follows a lazy-loaded panel's first layout pass.
124
+ const CHART_ENTRY_ANIMATION_MS = 1500 + CHART_RESIZE_DEBOUNCE_MS * 2;
122
125
  const LEGEND_ACTION_CLOSE_DELAY_MS = 600;
123
126
 
124
127
  type ChartSize = {
@@ -136,12 +139,38 @@ export function hasChartSizeChanged(
136
139
  );
137
140
  }
138
141
 
142
+ export function shouldDisableChartAnimation(
143
+ entryAnimationSettled: boolean,
144
+ previous: ChartSize | null,
145
+ next: ChartSize,
146
+ ): boolean {
147
+ return entryAnimationSettled && hasChartSizeChanged(previous, next);
148
+ }
149
+
139
150
  function useChartResizeAnimation() {
140
151
  const [isAnimationActive, setIsAnimationActive] = useState(true);
141
152
  const firstSizeRef = useRef<ChartSize | null>(null);
153
+ // Switching Recharts to isAnimationActive=false mid-flight freezes the line's
154
+ // stroke-dasharray at whatever partial length it reached, leaving the series
155
+ // invisible forever. Lazy-loaded panels reflow right after mounting, so the
156
+ // entry animation has to be allowed to finish before a resize can disable it.
157
+ const entryAnimationSettledRef = useRef(false);
158
+ useEffect(() => {
159
+ const timer = setTimeout(() => {
160
+ entryAnimationSettledRef.current = true;
161
+ }, CHART_ENTRY_ANIMATION_MS);
162
+ return () => clearTimeout(timer);
163
+ }, []);
164
+
142
165
  const handleResize = useCallback((width: number, height: number) => {
143
166
  const nextSize = { width, height };
144
- if (hasChartSizeChanged(firstSizeRef.current, nextSize)) {
167
+ if (
168
+ shouldDisableChartAnimation(
169
+ entryAnimationSettledRef.current,
170
+ firstSizeRef.current,
171
+ nextSize,
172
+ )
173
+ ) {
145
174
  setIsAnimationActive(false);
146
175
  }
147
176
  firstSizeRef.current = nextSize;
@@ -259,6 +259,9 @@ export function DashboardFilterBar({
259
259
  className="group rounded-lg bg-card px-3 py-2"
260
260
  >
261
261
  <div className="flex flex-wrap items-end justify-between gap-3">
262
+ <span className="self-center text-xs font-medium text-muted-foreground group-data-[state=open]:hidden">
263
+ {t("sqlDashboard.filters")}
264
+ </span>
262
265
  <CollapsibleContent className="min-w-0 flex-1">
263
266
  <div className="flex flex-wrap gap-3 items-end">
264
267
  {uniqueFilters.map((f) => (
@@ -272,7 +272,7 @@ export function SqlChartCard({
272
272
  data-dragging={isDragSource ? "true" : undefined}
273
273
  className="dashboard-section-card group relative mt-2 first:mt-0"
274
274
  >
275
- <div className="flex items-center gap-2 border-b border-border pb-2">
275
+ <div className="flex items-center gap-2 pb-2">
276
276
  <h2 className="text-base font-semibold flex-1">{panel.title}</h2>
277
277
  {editable ? (
278
278
  <div className="flex items-center gap-1 opacity-0 group-hover:opacity-100">
@@ -1538,6 +1538,7 @@ function SqlDashboardPageContent({
1538
1538
  resourceId={dashboardId}
1539
1539
  resourceTitle={dashboard.name}
1540
1540
  variant="compact"
1541
+ triggerClassName="border-0 bg-accent text-accent-foreground hover:bg-accent/80 hover:text-accent-foreground"
1541
1542
  shareUrl={dashboardShareUrl}
1542
1543
  shareTabs={{
1543
1544
  tabs: [
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Analytics finds saved dashboards and queries far more reliably, and answers list and cohort questions in one query instead of grinding for minutes
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Notion access errors now explain that a page needs sharing with the integration, instead of naming an unrelated integration label
@@ -35,6 +35,13 @@ export const INITIAL_TOOL_NAMES = [
35
35
  "bigquery",
36
36
  "search-bigquery-schema",
37
37
  "list-data-dictionary",
38
+ // Bulk/cohort readers. Without these on the first surface a "list X excluding Y"
39
+ // question cannot reach any tool that answers it in one call, so the agent pays a
40
+ // tool-search round trip (~15 KB of results) before it can even start — or worse,
41
+ // enumerates the cohort page by page through whatever it can already see.
42
+ "provider-api-request",
43
+ "query-staged-dataset",
44
+ "hubspot-records",
38
45
  "navigate",
39
46
  ];
40
47
 
@@ -68,7 +68,8 @@ export type AnalyticsQueryCatalogCandidate =
68
68
  panelTitle: string;
69
69
  panelDescription?: string;
70
70
  source?: string;
71
- query: string | Record<string, unknown>;
71
+ /** Absent for extension/embed panels, which are matched on title and description. */
72
+ query?: string | Record<string, unknown>;
72
73
  timeScope?: string;
73
74
  }
74
75
  | {
@@ -105,43 +106,135 @@ function compactQuery(value: unknown): string | Record<string, unknown> | null {
105
106
  return null;
106
107
  }
107
108
 
108
- function searchTerms(search: string): string[] {
109
- const normalized = search
109
+ // Analytics vocabulary the corpus spells out but users abbreviate (or vice versa).
110
+ // Expansions match at reduced weight so they break ties without outranking a literal hit.
111
+ const SYNONYM_EXPANSIONS: Record<string, string[]> = {
112
+ account: ["company", "customer", "org"],
113
+ active: ["engaged"],
114
+ arr: ["annual", "recurring", "revenue"],
115
+ churn: ["cancel", "attrition", "downgrade"],
116
+ csql: ["sale", "qualified", "lead", "opportunity"],
117
+ customer: ["account", "company"],
118
+ dau: ["daily", "active", "user"],
119
+ deal: ["opportunity", "pipeline"],
120
+ error: ["5xx", "4xx", "exception", "failure", "fault"],
121
+ icp: ["ideal", "customer", "profile"],
122
+ mau: ["monthly", "active", "user"],
123
+ mql: ["marketing", "qualified", "lead"],
124
+ mrr: ["monthly", "recurring", "revenue"],
125
+ pageview: ["page", "view", "traffic", "session"],
126
+ pipeline: ["deal", "opportunity", "forecast"],
127
+ poc: ["proof", "concept", "trial", "pilot"],
128
+ revenue: ["bookings", "arr", "mrr", "won"],
129
+ signup: ["registration", "created", "onboard"],
130
+ traffic: ["pageview", "session", "visit"],
131
+ usage: ["active", "engagement"],
132
+ user: ["member", "person", "seat"],
133
+ wau: ["weekly", "active", "user"],
134
+ };
135
+
136
+ // Metric-shaped words that appear in a large share of titles and so discriminate
137
+ // almost nothing on their own. Scored down rather than dropped: "error rate" must
138
+ // still beat "rate", but four unrelated "... Rate" entries must not tie above the
139
+ // panel that actually matches "error".
140
+ const LOW_INFORMATION_TERMS = new Set([
141
+ "average",
142
+ "percent",
143
+ "percentage",
144
+ "rate",
145
+ "ratio",
146
+ "score",
147
+ "value",
148
+ "volume",
149
+ ]);
150
+
151
+ // Cheap plural folding. The corpus writes "Template"/"Deal" while users type
152
+ // "templates"/"deals"; exact substring matching missed every one of those.
153
+ function stem(token: string): string {
154
+ if (token.length > 4 && token.endsWith("ies"))
155
+ return `${token.slice(0, -3)}y`;
156
+ if (token.length > 4 && token.endsWith("sses")) return token.slice(0, -2);
157
+ if (token.length > 3 && token.endsWith("s") && !token.endsWith("ss")) {
158
+ return token.slice(0, -1);
159
+ }
160
+ return token;
161
+ }
162
+
163
+ // Splits camelCase and snake_case so warehouse identifiers are searchable:
164
+ // `dim_hs_deals` -> dim, hs, deal.
165
+ function tokenize(value: string): string[] {
166
+ return value
167
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
110
168
  .toLowerCase()
111
169
  .replace(/[^a-z0-9]+/g, " ")
112
- .trim();
113
- if (!normalized) return [];
114
- const meaningful = normalized
170
+ .trim()
115
171
  .split(/\s+/)
116
- .filter((term) => term.length > 1 && !STOP_WORDS.has(term));
117
- return meaningful.length ? Array.from(new Set(meaningful)) : [normalized];
172
+ .filter(Boolean)
173
+ .map(stem);
174
+ }
175
+
176
+ function searchTerms(search: string): string[] {
177
+ const tokens = tokenize(search);
178
+ if (!tokens.length) return [];
179
+ const meaningful = tokens.filter(
180
+ (term) => term.length > 1 && !STOP_WORDS.has(term),
181
+ );
182
+ return Array.from(new Set(meaningful.length ? meaningful : tokens));
183
+ }
184
+
185
+ function expandedTerms(primary: string[]): string[] {
186
+ const primarySet = new Set(primary);
187
+ const expanded = new Set<string>();
188
+ for (const term of primary) {
189
+ for (const synonym of SYNONYM_EXPANSIONS[term] ?? []) {
190
+ const stemmed = stem(synonym);
191
+ if (!primarySet.has(stemmed)) expanded.add(stemmed);
192
+ }
193
+ }
194
+ return [...expanded];
118
195
  }
119
196
 
197
+ // SQL bodies run to 12k chars; scoring only needs the leading identifiers.
198
+ const MAX_SCORED_FIELD_CHARS = 4_000;
199
+
120
200
  function matchScore(
121
201
  search: string,
122
202
  weightedFields: Array<{ value: unknown; weight: number }>,
123
203
  ): { score: number; matchedTerms: string[] } {
124
204
  const terms = searchTerms(search);
125
205
  if (!terms.length) return { score: 0, matchedTerms: [] };
206
+ const synonyms = expandedTerms(terms);
126
207
 
127
208
  const normalizedSearch = search.toLowerCase().trim();
128
209
  const matched = new Set<string>();
129
210
  let score = 0;
130
211
  for (const field of weightedFields) {
131
- const value = text(field.value).toLowerCase();
132
- if (!value) continue;
133
- if (normalizedSearch.length > 2 && value.includes(normalizedSearch)) {
212
+ const raw = text(field.value).slice(0, MAX_SCORED_FIELD_CHARS);
213
+ if (!raw) continue;
214
+ const lowered = raw.toLowerCase();
215
+ const tokens = new Set(tokenize(raw));
216
+
217
+ if (normalizedSearch.length > 2 && lowered.includes(normalizedSearch)) {
134
218
  score += field.weight * 4;
135
219
  }
136
220
  for (const term of terms) {
137
- if (!value.includes(term)) continue;
221
+ if (!tokens.has(term) && !lowered.includes(term)) continue;
138
222
  matched.add(term);
139
- score += field.weight;
223
+ score += field.weight * (LOW_INFORMATION_TERMS.has(term) ? 0.3 : 1);
224
+ }
225
+ for (const synonym of synonyms) {
226
+ if (!tokens.has(synonym)) continue;
227
+ score += field.weight * 0.4;
140
228
  }
141
229
  }
142
230
 
143
- if (matched.size === terms.length) score += 40;
144
- return { score, matchedTerms: [...matched] };
231
+ // Proportional, not all-or-nothing: a 7-word question could never hit the old
232
+ // full-coverage bonus, so long real questions collapsed to near-random scores.
233
+ // Damped for short queries — at full strength every one-of-one-token match tied
234
+ // at the same score, so generic "... Rate" entries mass-tied above exact panels.
235
+ const coverageWeight = Math.min(terms.length, 3) / 3;
236
+ score += 40 * (matched.size / terms.length) * coverageWeight;
237
+ return { score: Math.round(score), matchedTerms: [...matched] };
145
238
  }
146
239
 
147
240
  function dashboardPanelCandidates(args: {
@@ -156,9 +249,15 @@ function dashboardPanelCandidates(args: {
156
249
  ? (args.config.panels as DashboardPanel[])
157
250
  : [];
158
251
 
252
+ const wantsDemo = /\bdemo\b|node exporter/i.test(args.search);
253
+
159
254
  return panels.flatMap((panel) => {
255
+ // 38k of the ~39k indexed panels are clones of the demo Node Exporter dashboard.
256
+ // They drown real saved work and are never the answer to a real data question.
257
+ if (!wantsDemo && text(panel.source) === "demo") return [];
258
+ // Panels without SQL (extensions, embeds) used to be dropped outright, which hid
259
+ // 61% of real dashboards from search even when their titles matched exactly.
160
260
  const query = compactQuery(panel.sql);
161
- if (!query) return [];
162
261
  const panelConfig =
163
262
  panel.config &&
164
263
  typeof panel.config === "object" &&
@@ -174,20 +273,49 @@ function dashboardPanelCandidates(args: {
174
273
  { value: args.dashboardDescription, weight: 6 },
175
274
  { value: panel.source, weight: 5 },
176
275
  {
177
- value: typeof query === "string" ? query : JSON.stringify(query),
178
- weight: 2,
276
+ // Weighted 2 against a title's 24, this 12x discount hid every panel whose
277
+ // match lived only in its SQL — the majority of them.
278
+ value: query
279
+ ? typeof query === "string"
280
+ ? query
281
+ : JSON.stringify(query)
282
+ : "",
283
+ weight: 8,
179
284
  },
180
285
  ]);
286
+ // Prefer the general panel over a narrower variant ("Signups" over "Clip Share
287
+ // Signups 30d"), but cap it: the original uncapped -12/token buried long,
288
+ // well-named panels under short vague ones.
181
289
  const requestedTerms = new Set(searchTerms(args.search));
182
- const titleSpecificityPenalty =
183
- searchTerms(panelTitle).filter((term) => !requestedTerms.has(term))
184
- .length * 12;
290
+ const unmatchedTitleTerms = searchTerms(panelTitle).filter(
291
+ (term) => !requestedTerms.has(term),
292
+ ).length;
293
+ const titleSpecificityPenalty = Math.min(unmatchedTitleTerms, 4) * 4;
294
+ // A panel with no SQL costs the agent another call to become useful, so it must
295
+ // not outrank an equally-relevant runnable one. Waived when the title is clearly
296
+ // on-topic: real questions carry clause words no title contains, so requiring
297
+ // full coverage here never fires and buries exact-topic panels.
298
+ const titleMatchedTerms = matchScore(args.search, [
299
+ { value: panelTitle, weight: 1 },
300
+ ]).matchedTerms;
301
+ const strongTitleTerms = titleMatchedTerms.filter(
302
+ (term) => !LOW_INFORMATION_TERMS.has(term),
303
+ ).length;
304
+ const titleIsOnTopic =
305
+ requestedTerms.size > 0 &&
306
+ (strongTitleTerms >= 2 ||
307
+ titleMatchedTerms.length / requestedTerms.size >= 0.6);
308
+ const missingQueryPenalty = query || titleIsOnTopic ? 0 : 10;
185
309
  const aggregateIntent =
186
310
  /\b(how many|count|number|total)\b/i.test(args.search) &&
187
311
  text(panel.chartType) === "metric"
188
312
  ? 20
189
313
  : 0;
190
- const score = rawScore - titleSpecificityPenalty + aggregateIntent;
314
+ const score =
315
+ rawScore -
316
+ titleSpecificityPenalty -
317
+ missingQueryPenalty +
318
+ aggregateIntent;
191
319
  if (score <= 0) return [];
192
320
 
193
321
  return [
@@ -205,7 +333,7 @@ function dashboardPanelCandidates(args: {
205
333
  panelTitle,
206
334
  ...(panelDescription ? { panelDescription } : {}),
207
335
  ...(text(panel.source) ? { source: text(panel.source) } : {}),
208
- query,
336
+ ...(query ? { query } : {}),
209
337
  ...(text(panelConfig.timeScope)
210
338
  ? { timeScope: text(panelConfig.timeScope) }
211
339
  : {}),
@@ -270,6 +398,26 @@ function dictionaryCandidates(
270
398
  });
271
399
  }
272
400
 
401
+ function candidateIsRunnable(
402
+ candidate: AnalyticsQueryCatalogCandidate,
403
+ ): boolean {
404
+ return candidate.kind === "dashboard-panel"
405
+ ? Boolean(candidate.query)
406
+ : Boolean(candidate.queryTemplate);
407
+ }
408
+
409
+ function candidateDedupeKey(candidate: AnalyticsQueryCatalogCandidate): string {
410
+ if (candidate.kind === "data-dictionary") return `dict:${candidate.id}`;
411
+ const query =
412
+ typeof candidate.query === "string"
413
+ ? candidate.query
414
+ : JSON.stringify(candidate.query ?? "");
415
+ return `panel:${candidate.panelTitle.toLowerCase()}:${query
416
+ .replace(/\s+/g, " ")
417
+ .trim()
418
+ .toLowerCase()}`;
419
+ }
420
+
273
421
  export function rankAnalyticsQueryCatalog(args: {
274
422
  search: string;
275
423
  dashboards: Array<{
@@ -296,13 +444,26 @@ export function rankAnalyticsQueryCatalog(args: {
296
444
  ...dictionaryCandidates(args.dictionaryEntries, args.search),
297
445
  ];
298
446
 
299
- return candidates
300
- .sort((a, b) => {
301
- if (b.score !== a.score) return b.score - a.score;
302
- if (a.kind !== b.kind) return a.kind === "data-dictionary" ? -1 : 1;
303
- return JSON.stringify(a).localeCompare(JSON.stringify(b));
304
- })
305
- .slice(0, args.limit);
447
+ const ranked = candidates.sort((a, b) => {
448
+ if (b.score !== a.score) return b.score - a.score;
449
+ // Prefer something the agent can run over something it must look up again.
450
+ const aRunnable = candidateIsRunnable(a);
451
+ const bRunnable = candidateIsRunnable(b);
452
+ if (aRunnable !== bRunnable) return aRunnable ? -1 : 1;
453
+ if (a.kind !== b.kind) return a.kind === "data-dictionary" ? -1 : 1;
454
+ return JSON.stringify(a).localeCompare(JSON.stringify(b));
455
+ });
456
+
457
+ // Cloned dashboards produce near-identical panels that otherwise eat every slot.
458
+ const seen = new Set<string>();
459
+ const deduped: AnalyticsQueryCatalogCandidate[] = [];
460
+ for (const candidate of ranked) {
461
+ if (deduped.length >= args.limit) break;
462
+ if (seen.has(candidateDedupeKey(candidate))) continue;
463
+ seen.add(candidateDedupeKey(candidate));
464
+ deduped.push(candidate);
465
+ }
466
+ return deduped;
306
467
  }
307
468
 
308
469
  async function listDictionaryEntries(args: {
@@ -239,6 +239,8 @@ export interface QueryResult {
239
239
  schema: { name: string; type: string }[];
240
240
  bytesProcessed: number;
241
241
  cached?: boolean;
242
+ /** True when BigQuery matched more rows than this first page returned. */
243
+ truncated?: boolean;
242
244
  }
243
245
 
244
246
  export interface RunQueryOptions {
@@ -516,11 +518,19 @@ export async function runQuery(
516
518
  const rows = data.rows ? rowsToObjects(data.rows, fields) : [];
517
519
  const bytesProcessed = parseInt(data.totalBytesProcessed || "0", 10);
518
520
 
521
+ // BigQuery reports the full match count; `rows` only holds the first page. Reporting
522
+ // rows.length as the total made every partial result look complete to the agent.
523
+ const reportedTotal = Number.parseInt(data.totalRows || "", 10);
524
+ const totalRows = Number.isFinite(reportedTotal)
525
+ ? reportedTotal
526
+ : rows.length;
527
+
519
528
  const result: QueryResult = {
520
529
  rows,
521
- totalRows: rows.length,
530
+ totalRows,
522
531
  schema,
523
532
  bytesProcessed,
533
+ ...(totalRows > rows.length ? { truncated: true } : {}),
524
534
  };
525
535
 
526
536
  setL1(cacheKey, result);
@@ -39,6 +39,19 @@ async function getApiKey(): Promise<string> {
39
39
  return credential.value;
40
40
  }
41
41
 
42
+ // The name Notion reports for a token is whatever label its creator typed in, so it
43
+ // routinely names an unrelated product. Never restate it as the current workspace.
44
+ const NOTION_ACCESS_HINT =
45
+ "This usually means the page or database was never shared with the Notion integration behind NOTION_API_KEY, not that the id is wrong. Fix it in Notion: open the page, then ••• → Connections → add the integration. The integration's Notion-side label may not match this app or workspace.";
46
+
47
+ function notionApiError(status: number, body: string): Error {
48
+ const suffix =
49
+ status === 401 || status === 403 || status === 404
50
+ ? ` ${NOTION_ACCESS_HINT}`
51
+ : "";
52
+ return new Error(`Notion API error ${status}: ${body}${suffix}`);
53
+ }
54
+
42
55
  async function notionGet(path: string): Promise<unknown> {
43
56
  const res = await fetch(`${NOTION_API}${path}`, {
44
57
  headers: {
@@ -47,8 +60,7 @@ async function notionGet(path: string): Promise<unknown> {
47
60
  },
48
61
  });
49
62
  if (!res.ok) {
50
- const text = await res.text();
51
- throw new Error(`Notion API error ${res.status}: ${text}`);
63
+ throw notionApiError(res.status, await res.text());
52
64
  }
53
65
  return res.json();
54
66
  }
@@ -64,8 +76,7 @@ async function notionPost(path: string, body: unknown): Promise<unknown> {
64
76
  body: JSON.stringify(body),
65
77
  });
66
78
  if (!res.ok) {
67
- const text = await res.text();
68
- throw new Error(`Notion API error ${res.status}: ${text}`);
79
+ throw notionApiError(res.status, await res.text());
69
80
  }
70
81
  return res.json();
71
82
  }
@@ -73,6 +73,11 @@ export const NON_ANALYTICS_FALLBACK_FINAL_MESSAGE =
73
73
  export function analyticsSourceGuidanceOpening(): string {
74
74
  return (
75
75
  "<data-source-guidance>\n" +
76
+ // Measured in production: this ran in under 1% of data threads while the
77
+ // equivalent instruction sat ~7000 words deep. Threads that did call it used
78
+ // roughly a third the tool calls. Keep it first and keep it imperative.
79
+ "START HERE — For any question about a metric, cohort, list, count, or trend, your FIRST tool call is `search-analytics-query-catalog`. This is the analytics equivalent of grepping a codebase before writing new code: someone has very likely already built and saved the query you need, and its saved SQL tells you the exact source, table, and column names so you do not have to discover them. Adapt the closest saved query to the requested filters and time window, run it once, and stop. Only fall back to schema discovery or provider catalogs when the catalog search returns nothing usable — and never run more than one schema-discovery pass before querying. " +
80
+ 'ONE BOUNDED CALL — List, filter, count, and cohort questions ("which X, excluding Y") are a single query, not a loop. Express the include filter, the exclude filter, and the aggregation in one SQL statement or one `run-code` script that filters server-side. Never page through a cohort across separate tool calls and never fan out per item to apply a filter; that is what turns a ten-second answer into a twenty-minute one. ' +
76
81
  "Apply real-data requirements only when presenting analytics results, source records, or derived metrics. Do not call data-source tools for workflow migration, recurring-job setup, UI/code fixes, settings help, conceptual planning, or other non-data tasks unless the user explicitly asks for data. " +
77
82
  NON_ANALYTICS_REQUEST_GUIDANCE +
78
83
  BOUNDED_STRUCTURED_LOOKUP_GUIDANCE +
@@ -734,6 +739,11 @@ export default createAgentChatPlugin({
734
739
  "Analytics has one user-facing artifact type: dashboards. Dashboards are JSON configs rendered by the built-in dashboard components, and an extension is a dashboard block—not a separate Analytics result. " +
735
740
  'If the user\'s requested dashboard, saved analysis/report, visualization, interaction model, custom layout, or bespoke workflow cannot be faithfully represented within the native dashboard components/config fields, do not hand-wave, force an approximate JSON dashboard, or route to source-code changes. In production mode, automatically create a sandboxed extension with `create-extension`, then immediately call `update-dashboard` to embed it as one or more `chartType: "extension"` panels with `config.extensionId`. ' +
736
741
  "After creating the dashboard, briefly tell the user that a dashboard block uses an embedded extension because the request needed bespoke UI/code. Never leave a newly created extension standalone, never create a separate saved analysis for the same request, and never direct the user to an Extensions page from Analytics. Legacy analyses may be read or updated only for compatibility with an existing deep link.\n" +
742
+ // The extension-first default above is deliberate, but it must not swallow
743
+ // an explicit ask for a code change: without this carve-out the agent
744
+ // silently substitutes an extension for "open a PR adding a dual-axis
745
+ // chart type" and the user never learns the handoff exists.
746
+ "That extension-first default governs what you build on your own initiative. It does not override an explicit request for a source-code change: when the user asks for the capability natively in the product, asks to change app chrome or a shared component, or asks for a PR, branch, or code change in so many words, call `connect-builder` with their request verbatim instead of substituting an extension. When you have just built an extension for something that plainly belongs in the product — a chart type or interaction other dashboards would reuse — add one sentence offering the `connect-builder` handoff, and only call it if they take you up on it.\n" +
737
747
  "</analytics-artifact-guidance>";
738
748
 
739
749
  return `${sourceGuidance}\n\n${artifactGuidance}\n\n${analyticsDataDictionaryRoutingContext()}`;
@@ -56,7 +56,29 @@ install → refresh scaffold skills → verify, then fix **app** code only.
56
56
  - Runs `skills update scaffold --project`
57
57
  - Runs `typecheck` when the project has that script
58
58
 
59
- 3. **If upgrade or typecheck fails**
59
+ 3. **Pull upstream template changes (optional, separate from the bump)**
60
+
61
+ `agent-native upgrade` moves package versions. It never touches files that
62
+ were copied out of a template at scaffold time, so template fixes and
63
+ improvements do not arrive with a bump.
64
+
65
+ ```bash
66
+ agent-native template status # recorded ref vs latest, drift counts
67
+ agent-native template diff # what upstream changed, read-only
68
+ agent-native template sync # 3-way merge it into the app
69
+ ```
70
+
71
+ `sync` defaults to the ref matching the installed `@agent-native/core`, so
72
+ run it after `upgrade`. It merges per file against a pristine baseline
73
+ stored in `refs/agent-native/template-baseline/<app-path>`; files upstream
74
+ did not touch are left alone, and real collisions get conflict markers.
75
+ After resolving markers, run `agent-native template accept` — the baseline
76
+ deliberately does not advance past an unresolved merge.
77
+
78
+ Apps scaffolded before provenance existed have no baseline. Create one
79
+ with `agent-native template baseline` before the first sync.
80
+
81
+ 4. **If upgrade or typecheck fails**
60
82
 
61
83
  - Read the concrete error
62
84
  - Fix **app** source, actions, config, or env — not framework packages
@@ -68,7 +90,7 @@ install → refresh scaffold skills → verify, then fix **app** code only.
68
90
  copied component; do not use that path to reproduce framework runtime
69
91
  behavior or hide version skew.
70
92
 
71
- 4. **Dry-run / partial runs**
93
+ 5. **Dry-run / partial runs**
72
94
 
73
95
  ```bash
74
96
  agent-native upgrade --dry-run
@@ -56,7 +56,29 @@ install → refresh scaffold skills → verify, then fix **app** code only.
56
56
  - Runs `skills update scaffold --project`
57
57
  - Runs `typecheck` when the project has that script
58
58
 
59
- 3. **If upgrade or typecheck fails**
59
+ 3. **Pull upstream template changes (optional, separate from the bump)**
60
+
61
+ `agent-native upgrade` moves package versions. It never touches files that
62
+ were copied out of a template at scaffold time, so template fixes and
63
+ improvements do not arrive with a bump.
64
+
65
+ ```bash
66
+ agent-native template status # recorded ref vs latest, drift counts
67
+ agent-native template diff # what upstream changed, read-only
68
+ agent-native template sync # 3-way merge it into the app
69
+ ```
70
+
71
+ `sync` defaults to the ref matching the installed `@agent-native/core`, so
72
+ run it after `upgrade`. It merges per file against a pristine baseline
73
+ stored in `refs/agent-native/template-baseline/<app-path>`; files upstream
74
+ did not touch are left alone, and real collisions get conflict markers.
75
+ After resolving markers, run `agent-native template accept` — the baseline
76
+ deliberately does not advance past an unresolved merge.
77
+
78
+ Apps scaffolded before provenance existed have no baseline. Create one
79
+ with `agent-native template baseline` before the first sync.
80
+
81
+ 4. **If upgrade or typecheck fails**
60
82
 
61
83
  - Read the concrete error
62
84
  - Fix **app** source, actions, config, or env — not framework packages
@@ -68,7 +90,7 @@ install → refresh scaffold skills → verify, then fix **app** code only.
68
90
  copied component; do not use that path to reproduce framework runtime
69
91
  behavior or hide version skew.
70
92
 
71
- 4. **Dry-run / partial runs**
93
+ 5. **Dry-run / partial runs**
72
94
 
73
95
  ```bash
74
96
  agent-native upgrade --dry-run
@@ -10,3 +10,4 @@ data/*.db-shm
10
10
  data/*.db-wal
11
11
  .env
12
12
  .env.local
13
+ .agent-native/