@agent-native/core 0.131.5 → 0.131.7

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 (350) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +70 -0
  3. package/corpus/core/docs/content/agent-native-toolkit.mdx +13 -6
  4. package/corpus/core/docs/content/cloneable-saas.mdx +5 -5
  5. package/corpus/core/docs/content/creating-templates.mdx +9 -0
  6. package/corpus/core/docs/content/deployment.mdx +18 -12
  7. package/corpus/core/docs/content/doctor.mdx +8 -1
  8. package/corpus/core/docs/content/drop-in-agent.mdx +1 -1
  9. package/corpus/core/docs/content/extensions.mdx +18 -18
  10. package/corpus/core/docs/content/faq.mdx +4 -4
  11. package/corpus/core/docs/content/key-concepts.mdx +30 -21
  12. package/corpus/core/docs/content/security.mdx +2 -2
  13. package/corpus/core/docs/content/template-brain-developers.mdx +4 -1
  14. package/corpus/core/docs/content/template-mail-developers.mdx +4 -1
  15. package/corpus/core/docs/content/what-is-agent-native.mdx +6 -6
  16. package/corpus/core/package.json +1 -1
  17. package/corpus/core/src/a2a/client.ts +449 -66
  18. package/corpus/core/src/a2a/correlation.ts +31 -0
  19. package/corpus/core/src/a2a/invoke.ts +4 -2
  20. package/corpus/core/src/a2a/types.ts +4 -0
  21. package/corpus/core/src/action.ts +3 -0
  22. package/corpus/core/src/agent/action-continuation-guidance.ts +2 -1
  23. package/corpus/core/src/agent/engine/registry.ts +98 -6
  24. package/corpus/core/src/agent/production-agent.ts +151 -18
  25. package/corpus/core/src/agent/run-loop-with-resume.ts +190 -3
  26. package/corpus/core/src/agent/run-manager.ts +117 -41
  27. package/corpus/core/src/agent/thread-debug-history.ts +86 -0
  28. package/corpus/core/src/agent/types.ts +3 -1
  29. package/corpus/core/src/cli/create.ts +11 -1
  30. package/corpus/core/src/cli/templates-meta.ts +2 -2
  31. package/corpus/core/src/client/agent-chat-adapter.ts +91 -13
  32. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +11 -9
  33. package/corpus/core/src/client/sse-event-processor.ts +17 -3
  34. package/corpus/core/src/db/client.ts +57 -17
  35. package/corpus/core/src/guards/no-env-credentials.ts +2 -0
  36. package/corpus/core/src/integrations/adapters/slack.ts +8 -3
  37. package/corpus/core/src/localization/default-messages.ts +44 -0
  38. package/corpus/core/src/observability/traces.ts +78 -5
  39. package/corpus/core/src/scripts/call-agent.ts +294 -11
  40. package/corpus/core/src/scripts/describe-workspace-apps.ts +2 -2
  41. package/corpus/core/src/secrets/crypto.ts +156 -35
  42. package/corpus/core/src/secrets/storage.ts +64 -26
  43. package/corpus/core/src/server/agent-capabilities.ts +1 -1
  44. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +113 -7
  45. package/corpus/core/src/server/agent-chat/context-tools.ts +2 -0
  46. package/corpus/core/src/server/agent-chat/plugin-options.ts +34 -1
  47. package/corpus/core/src/server/agent-chat/prompt-resources.ts +1 -1
  48. package/corpus/core/src/server/agent-chat-plugin.ts +91 -59
  49. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  50. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  51. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  54. package/corpus/core/src/vite/client.ts +1 -0
  55. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +5 -4
  56. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +6 -4
  57. package/corpus/templates/analytics/AGENTS.md +7 -4
  58. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -3
  59. package/corpus/templates/analytics/changelog/2026-07-30-delegated-analytics-questions-now-return-a-useful-current-me.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-07-30-scheduled-dashboard-emails-complete-every-panel-without-pool.md +6 -0
  61. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +28 -1
  62. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +18 -11
  63. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +4 -4
  64. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -5
  65. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +6 -2
  66. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +11 -4
  67. package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +49 -31
  68. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +16 -8
  69. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -3
  70. package/corpus/templates/analytics/server/lib/production-serverless-runtime.ts +11 -0
  71. package/corpus/templates/analytics/server/lib/real-data-actions.ts +10 -0
  72. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -2
  73. package/corpus/templates/analytics/server/plugins/analytics-alert-jobs.ts +2 -1
  74. package/corpus/templates/analytics/server/plugins/dashboard-report-jobs.ts +2 -1
  75. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +1 -12
  76. package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +54 -6
  77. package/corpus/templates/brain/.agents/skills/brain/SKILL.md +20 -9
  78. package/corpus/templates/brain/.agents/skills/ingestion-and-connectors/SKILL.md +33 -1
  79. package/corpus/templates/brain/AGENTS.md +3 -1
  80. package/corpus/templates/brain/README.md +4 -1
  81. package/corpus/templates/brain/actions/_schemas.ts +30 -8
  82. package/corpus/templates/brain/actions/ask-brain.ts +124 -14
  83. package/corpus/templates/brain/actions/create-source.ts +18 -2
  84. package/corpus/templates/brain/actions/enqueue-captures-distillation.ts +8 -123
  85. package/corpus/templates/brain/actions/enqueue-distillation.ts +6 -127
  86. package/corpus/templates/brain/actions/import-capture.ts +17 -5
  87. package/corpus/templates/brain/actions/import-transcript.ts +17 -5
  88. package/corpus/templates/brain/actions/update-source.ts +25 -5
  89. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +1 -1
  90. package/corpus/templates/brain/changelog/2026-07-30-blessed-resources-can-feed-cited-company-answers.md +6 -0
  91. package/corpus/templates/brain/changelog/2026-07-30-the-left-sidebar-no-longer-shows-a-blank-organization-placeh.md +6 -0
  92. package/corpus/templates/brain/server/lib/brain.ts +49 -19
  93. package/corpus/templates/brain/server/lib/distillation-queue.ts +147 -0
  94. package/corpus/templates/brain/server/lib/source-policy.ts +264 -0
  95. package/corpus/templates/brain/server/plugins/agent-chat.ts +3 -2
  96. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +116 -19
  97. package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +51 -0
  98. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  99. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +3 -1
  100. package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +6 -0
  101. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +72 -8
  102. package/corpus/templates/content/changelog/2026-07-30-the-slash-command-hint-now-stays-on-only-the-active-empty-li.md +6 -0
  103. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +506 -11
  104. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +148 -17
  105. package/corpus/templates/design/app/components/design/canvas-interactions/design-canvas-interactions.ts +357 -0
  106. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +7 -466
  107. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +15 -311
  108. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +19 -997
  109. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +8 -1216
  110. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +31 -38
  111. package/corpus/templates/design/package.json +0 -1
  112. package/corpus/templates/dispatch/AGENTS.md +8 -0
  113. package/corpus/templates/dispatch/DEVELOPING.md +29 -0
  114. package/corpus/templates/dispatch/actions/view-screen.ts +34 -2
  115. package/corpus/templates/dispatch/app/i18n-data.ts +457 -0
  116. package/corpus/templates/dispatch/changelog/2026-07-30-delegated-dispatch-work-continues-reliably-in-the-background.md +6 -0
  117. package/corpus/templates/dispatch/changelog/2026-07-30-find-failed-runs-across-apps.md +6 -0
  118. package/corpus/templates/dispatch/netlify.toml +3 -0
  119. package/corpus/templates/plan/actions/get-visual-plan.ts +10 -6
  120. package/corpus/templates/plan/actions/patch-visual-plan-source.ts +117 -1
  121. package/corpus/templates/plan/actions/update-visual-plan.ts +56 -14
  122. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
  123. package/corpus/templates/plan/changelog/2026-07-30-plan-agents-recover-with-targeted-writes.md +6 -0
  124. package/corpus/templates/plan/shared/plan-content.ts +35 -0
  125. package/corpus/templates/slides/.agents/skills/analytics-data-for-decks/SKILL.md +8 -12
  126. package/corpus/templates/slides/AGENTS.md +4 -4
  127. package/corpus/templates/slides/actions/create-deck.ts +1 -1
  128. package/corpus/templates/slides/actions/duplicate-deck.ts +19 -4
  129. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -10
  130. package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +12 -1
  131. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +30 -13
  132. package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +35 -0
  133. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +63 -56
  134. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +21 -76
  135. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1110 -292
  136. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +53 -0
  137. package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +235 -18
  138. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +4 -1
  139. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +11 -0
  140. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +129 -0
  141. package/corpus/templates/slides/app/components/editor/selection-overlay-measurement.ts +70 -0
  142. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +519 -65
  143. package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +36 -426
  144. package/corpus/templates/slides/app/components/visual-editor/DrawOverlay.tsx +19 -458
  145. package/corpus/templates/slides/app/context/DeckContext.tsx +179 -72
  146. package/corpus/templates/slides/app/global.css +105 -0
  147. package/corpus/templates/slides/app/i18n/en-US.ts +8 -0
  148. package/corpus/templates/slides/app/lib/deck-editor-loading.ts +26 -0
  149. package/corpus/templates/slides/app/lib/mermaid-blocks.ts +27 -0
  150. package/corpus/templates/slides/app/pages/DeckEditor.tsx +71 -38
  151. package/corpus/templates/slides/app/pages/Index.tsx +98 -41
  152. package/corpus/templates/slides/changelog/2026-07-30-deck-loading-no-longer-flashes-an-unavailable-message.md +6 -0
  153. package/corpus/templates/slides/changelog/2026-07-30-duplicating-a-deck-from-the-deck-list-now-opens-the-copy-imm.md +6 -0
  154. package/corpus/templates/slides/changelog/2026-07-30-layout-overflow-warning-is-readable-and-dismissible.md +6 -0
  155. package/corpus/templates/slides/changelog/2026-07-30-new-decks-now-start-with-an-empty-slide-list-when-no-slides-.md +6 -0
  156. package/corpus/templates/slides/changelog/2026-07-30-shared-canvas-annotations.md +6 -0
  157. package/corpus/templates/slides/changelog/2026-07-30-slide-objects-can-be-moved-as-a-group-copied-and-pasted-with.md +6 -0
  158. package/corpus/templates/slides/changelog/2026-07-30-slide-text-editing-and-object-controls-now-match-google-slides.md +6 -0
  159. package/corpus/templates/slides/changelog/2026-07-30-style-panel-now-scrolls-with-speaker-notes-open-shows-the-sl.md +6 -0
  160. package/corpus/templates/slides/changelog/2026-07-30-top-toolbar-controls-now-use-consistent-sizing-with-undo-and.md +6 -0
  161. package/corpus/templates/slides/netlify.toml +3 -1
  162. package/corpus/templates/slides/package.json +0 -1
  163. package/corpus/templates/slides/server/lib/chat-attachments.ts +18 -0
  164. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
  165. package/corpus/templates/slides/vite.config.ts +0 -1
  166. package/corpus/toolkit/CHANGELOG.md +13 -0
  167. package/corpus/toolkit/README.md +19 -0
  168. package/corpus/toolkit/agent-native.eject.json +38 -0
  169. package/corpus/toolkit/package.json +29 -1
  170. package/corpus/toolkit/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
  171. package/corpus/toolkit/src/canvas-annotations/DrawOverlay.tsx +1233 -0
  172. package/corpus/toolkit/src/canvas-annotations/index.ts +15 -0
  173. package/corpus/toolkit/src/canvas-annotations/types.ts +14 -0
  174. package/corpus/toolkit/src/canvas-interactions/canvas-interactions.ts +933 -0
  175. package/corpus/toolkit/src/canvas-interactions/index.ts +67 -0
  176. package/corpus/toolkit/src/design-tweaks/scrub-input-utils.ts +311 -0
  177. package/corpus/toolkit/src/design-tweaks/scrub-input.tsx +491 -0
  178. package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +26 -171
  179. package/corpus/toolkit/src/index.ts +1 -0
  180. package/dist/a2a/client.d.ts +23 -0
  181. package/dist/a2a/client.d.ts.map +1 -1
  182. package/dist/a2a/client.js +309 -44
  183. package/dist/a2a/client.js.map +1 -1
  184. package/dist/a2a/correlation.d.ts +1 -0
  185. package/dist/a2a/correlation.d.ts.map +1 -1
  186. package/dist/a2a/correlation.js +27 -0
  187. package/dist/a2a/correlation.js.map +1 -1
  188. package/dist/a2a/invoke.d.ts.map +1 -1
  189. package/dist/a2a/invoke.js +4 -2
  190. package/dist/a2a/invoke.js.map +1 -1
  191. package/dist/a2a/types.d.ts +4 -0
  192. package/dist/a2a/types.d.ts.map +1 -1
  193. package/dist/a2a/types.js.map +1 -1
  194. package/dist/action.d.ts +3 -0
  195. package/dist/action.d.ts.map +1 -1
  196. package/dist/action.js.map +1 -1
  197. package/dist/agent/action-continuation-guidance.d.ts.map +1 -1
  198. package/dist/agent/action-continuation-guidance.js +2 -1
  199. package/dist/agent/action-continuation-guidance.js.map +1 -1
  200. package/dist/agent/engine/registry.d.ts.map +1 -1
  201. package/dist/agent/engine/registry.js +82 -8
  202. package/dist/agent/engine/registry.js.map +1 -1
  203. package/dist/agent/production-agent.d.ts +40 -1
  204. package/dist/agent/production-agent.d.ts.map +1 -1
  205. package/dist/agent/production-agent.js +113 -15
  206. package/dist/agent/production-agent.js.map +1 -1
  207. package/dist/agent/run-loop-with-resume.d.ts +21 -0
  208. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  209. package/dist/agent/run-loop-with-resume.js +163 -4
  210. package/dist/agent/run-loop-with-resume.js.map +1 -1
  211. package/dist/agent/run-manager.d.ts +16 -9
  212. package/dist/agent/run-manager.d.ts.map +1 -1
  213. package/dist/agent/run-manager.js +93 -42
  214. package/dist/agent/run-manager.js.map +1 -1
  215. package/dist/agent/thread-debug-history.d.ts +10 -0
  216. package/dist/agent/thread-debug-history.d.ts.map +1 -0
  217. package/dist/agent/thread-debug-history.js +68 -0
  218. package/dist/agent/thread-debug-history.js.map +1 -0
  219. package/dist/agent/types.d.ts +3 -1
  220. package/dist/agent/types.d.ts.map +1 -1
  221. package/dist/agent/types.js.map +1 -1
  222. package/dist/cli/create.d.ts.map +1 -1
  223. package/dist/cli/create.js +6 -1
  224. package/dist/cli/create.js.map +1 -1
  225. package/dist/cli/templates-meta.js +2 -2
  226. package/dist/cli/templates-meta.js.map +1 -1
  227. package/dist/client/agent-chat-adapter.d.ts +1 -1
  228. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  229. package/dist/client/agent-chat-adapter.js +76 -13
  230. package/dist/client/agent-chat-adapter.js.map +1 -1
  231. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  232. package/dist/client/resources/McpIntegrationDialog.js +1 -1
  233. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  234. package/dist/client/sse-event-processor.d.ts.map +1 -1
  235. package/dist/client/sse-event-processor.js +12 -3
  236. package/dist/client/sse-event-processor.js.map +1 -1
  237. package/dist/collab/routes.d.ts +1 -1
  238. package/dist/db/client.d.ts.map +1 -1
  239. package/dist/db/client.js +48 -17
  240. package/dist/db/client.js.map +1 -1
  241. package/dist/guards/no-env-credentials.d.ts.map +1 -1
  242. package/dist/guards/no-env-credentials.js +2 -0
  243. package/dist/guards/no-env-credentials.js.map +1 -1
  244. package/dist/integrations/adapters/slack.js +7 -3
  245. package/dist/integrations/adapters/slack.js.map +1 -1
  246. package/dist/localization/default-messages.d.ts +43 -0
  247. package/dist/localization/default-messages.d.ts.map +1 -1
  248. package/dist/localization/default-messages.js +43 -0
  249. package/dist/localization/default-messages.js.map +1 -1
  250. package/dist/observability/traces.d.ts +3 -1
  251. package/dist/observability/traces.d.ts.map +1 -1
  252. package/dist/observability/traces.js +73 -4
  253. package/dist/observability/traces.js.map +1 -1
  254. package/dist/progress/routes.d.ts +1 -1
  255. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  256. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  257. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  258. package/dist/scripts/call-agent.d.ts.map +1 -1
  259. package/dist/scripts/call-agent.js +237 -12
  260. package/dist/scripts/call-agent.js.map +1 -1
  261. package/dist/scripts/describe-workspace-apps.js +2 -2
  262. package/dist/scripts/describe-workspace-apps.js.map +1 -1
  263. package/dist/secrets/crypto.d.ts +36 -21
  264. package/dist/secrets/crypto.d.ts.map +1 -1
  265. package/dist/secrets/crypto.js +134 -33
  266. package/dist/secrets/crypto.js.map +1 -1
  267. package/dist/secrets/storage.d.ts +6 -6
  268. package/dist/secrets/storage.d.ts.map +1 -1
  269. package/dist/secrets/storage.js +43 -26
  270. package/dist/secrets/storage.js.map +1 -1
  271. package/dist/server/agent-capabilities.js +1 -1
  272. package/dist/server/agent-capabilities.js.map +1 -1
  273. package/dist/server/agent-chat/action-filters-a2a.d.ts +17 -3
  274. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  275. package/dist/server/agent-chat/action-filters-a2a.js +94 -3
  276. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  277. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  278. package/dist/server/agent-chat/context-tools.js +2 -0
  279. package/dist/server/agent-chat/context-tools.js.map +1 -1
  280. package/dist/server/agent-chat/plugin-options.d.ts +23 -0
  281. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  282. package/dist/server/agent-chat/plugin-options.js +4 -1
  283. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  284. package/dist/server/agent-chat/prompt-resources.js +1 -1
  285. package/dist/server/agent-chat/prompt-resources.js.map +1 -1
  286. package/dist/server/agent-chat-plugin.d.ts +2 -1
  287. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  288. package/dist/server/agent-chat-plugin.js +79 -56
  289. package/dist/server/agent-chat-plugin.js.map +1 -1
  290. package/dist/server/realtime-token.d.ts +1 -1
  291. package/dist/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  292. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  293. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  294. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  295. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  296. package/dist/vite/client.d.ts.map +1 -1
  297. package/dist/vite/client.js +1 -0
  298. package/dist/vite/client.js.map +1 -1
  299. package/docs/content/agent-native-toolkit.mdx +13 -6
  300. package/docs/content/cloneable-saas.mdx +5 -5
  301. package/docs/content/creating-templates.mdx +9 -0
  302. package/docs/content/deployment.mdx +18 -12
  303. package/docs/content/doctor.mdx +8 -1
  304. package/docs/content/drop-in-agent.mdx +1 -1
  305. package/docs/content/extensions.mdx +18 -18
  306. package/docs/content/faq.mdx +4 -4
  307. package/docs/content/key-concepts.mdx +30 -21
  308. package/docs/content/security.mdx +2 -2
  309. package/docs/content/template-brain-developers.mdx +4 -1
  310. package/docs/content/template-mail-developers.mdx +4 -1
  311. package/docs/content/what-is-agent-native.mdx +6 -6
  312. package/package.json +3 -3
  313. package/src/a2a/client.ts +449 -66
  314. package/src/a2a/correlation.ts +31 -0
  315. package/src/a2a/invoke.ts +4 -2
  316. package/src/a2a/types.ts +4 -0
  317. package/src/action.ts +3 -0
  318. package/src/agent/action-continuation-guidance.ts +2 -1
  319. package/src/agent/engine/registry.ts +98 -6
  320. package/src/agent/production-agent.ts +151 -18
  321. package/src/agent/run-loop-with-resume.ts +190 -3
  322. package/src/agent/run-manager.ts +117 -41
  323. package/src/agent/thread-debug-history.ts +86 -0
  324. package/src/agent/types.ts +3 -1
  325. package/src/cli/create.ts +11 -1
  326. package/src/cli/templates-meta.ts +2 -2
  327. package/src/client/agent-chat-adapter.ts +91 -13
  328. package/src/client/resources/McpIntegrationDialog.tsx +11 -9
  329. package/src/client/sse-event-processor.ts +17 -3
  330. package/src/db/client.ts +57 -17
  331. package/src/guards/no-env-credentials.ts +2 -0
  332. package/src/integrations/adapters/slack.ts +8 -3
  333. package/src/localization/default-messages.ts +44 -0
  334. package/src/observability/traces.ts +78 -5
  335. package/src/scripts/call-agent.ts +294 -11
  336. package/src/scripts/describe-workspace-apps.ts +2 -2
  337. package/src/secrets/crypto.ts +156 -35
  338. package/src/secrets/storage.ts +64 -26
  339. package/src/server/agent-capabilities.ts +1 -1
  340. package/src/server/agent-chat/action-filters-a2a.ts +113 -7
  341. package/src/server/agent-chat/context-tools.ts +2 -0
  342. package/src/server/agent-chat/plugin-options.ts +34 -1
  343. package/src/server/agent-chat/prompt-resources.ts +1 -1
  344. package/src/server/agent-chat-plugin.ts +91 -59
  345. package/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  346. package/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  347. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  348. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  349. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  350. package/src/vite/client.ts +1 -0
@@ -0,0 +1,147 @@
1
+ import { writeAppState } from "@agent-native/core/application-state";
2
+ import { and, desc, eq, inArray } from "drizzle-orm";
3
+
4
+ import { getDb, schema } from "../db/index.js";
5
+ import {
6
+ nanoid,
7
+ nowIso,
8
+ parseJson,
9
+ readBrainAgentGuidance,
10
+ serializeDistillationQueue,
11
+ stableJson,
12
+ } from "./brain.js";
13
+
14
+ type CaptureRow = typeof schema.brainRawCaptures.$inferSelect;
15
+ type BrainAgentGuidance = Awaited<
16
+ ReturnType<typeof readBrainAgentGuidance>
17
+ >["guidance"];
18
+
19
+ async function writeDistillationRequest(values: {
20
+ captureId: string;
21
+ queueId: string;
22
+ sourceId: string;
23
+ requestedAt: string;
24
+ instructions?: string | null;
25
+ guidance: BrainAgentGuidance;
26
+ }) {
27
+ await writeAppState(`brain-distill-request-${values.captureId}`, {
28
+ kind: "distill-capture",
29
+ captureId: values.captureId,
30
+ queueId: values.queueId,
31
+ sourceId: values.sourceId,
32
+ requestedAt: values.requestedAt,
33
+ instructions: values.instructions ?? null,
34
+ guidance: values.guidance,
35
+ message:
36
+ `Distill Brain capture ${values.captureId} for ${values.guidance.identity.companyName ?? "this workspace"}. ` +
37
+ `Apply the Brain settings guidance in context. Use get-capture with ` +
38
+ `includeRawContent=true when you need exact quote validation, extract ` +
39
+ `only durable company knowledge with exact evidence quotes, ` +
40
+ `call write-knowledge for supported entries or proposals, then call ` +
41
+ `mark-capture-distilled when finished. If the capture is personal or ` +
42
+ `out of scope, call mark-capture-distilled with status ignored.`,
43
+ });
44
+ }
45
+
46
+ export async function enqueueCaptureDistillation(values: {
47
+ capture: CaptureRow;
48
+ priority?: number;
49
+ instructions?: string;
50
+ payload?: Record<string, unknown>;
51
+ guidance?: BrainAgentGuidance;
52
+ }) {
53
+ const guidance = values.guidance ?? (await readBrainAgentGuidance()).guidance;
54
+ const db = getDb();
55
+ const now = nowIso();
56
+ const [existing] = await db
57
+ .select()
58
+ .from(schema.brainIngestQueue)
59
+ .where(
60
+ and(
61
+ eq(schema.brainIngestQueue.captureId, values.capture.id),
62
+ eq(schema.brainIngestQueue.operation, "distill"),
63
+ inArray(schema.brainIngestQueue.status, ["queued", "processing"]),
64
+ ),
65
+ )
66
+ .orderBy(desc(schema.brainIngestQueue.updatedAt))
67
+ .limit(1);
68
+
69
+ if (existing) {
70
+ if (values.capture.status !== "distilling") {
71
+ await db
72
+ .update(schema.brainRawCaptures)
73
+ .set({ status: "distilling", updatedAt: now })
74
+ .where(eq(schema.brainRawCaptures.id, values.capture.id));
75
+ }
76
+ const payload = parseJson<Record<string, unknown>>(
77
+ existing.payloadJson,
78
+ {},
79
+ );
80
+ const existingInstructions =
81
+ typeof payload.instructions === "string"
82
+ ? payload.instructions
83
+ : undefined;
84
+ await writeDistillationRequest({
85
+ captureId: values.capture.id,
86
+ queueId: existing.id,
87
+ sourceId: values.capture.sourceId,
88
+ requestedAt: now,
89
+ instructions: values.instructions ?? existingInstructions,
90
+ guidance,
91
+ });
92
+ return {
93
+ queueItem: serializeDistillationQueue(existing),
94
+ existing: true,
95
+ guidance: guidance.distillation,
96
+ };
97
+ }
98
+
99
+ const id = nanoid();
100
+ const priority = values.priority ?? 50;
101
+ await db.insert(schema.brainIngestQueue).values({
102
+ id,
103
+ sourceId: values.capture.sourceId,
104
+ captureId: values.capture.id,
105
+ operation: "distill",
106
+ status: "queued",
107
+ priority,
108
+ attempts: 0,
109
+ payloadJson: stableJson({
110
+ ...(values.payload ?? {}),
111
+ instructions: values.instructions,
112
+ }),
113
+ error: null,
114
+ runAfter: null,
115
+ createdAt: now,
116
+ updatedAt: now,
117
+ });
118
+ await db
119
+ .update(schema.brainRawCaptures)
120
+ .set({ status: "distilling", updatedAt: now })
121
+ .where(eq(schema.brainRawCaptures.id, values.capture.id));
122
+ await writeDistillationRequest({
123
+ captureId: values.capture.id,
124
+ queueId: id,
125
+ sourceId: values.capture.sourceId,
126
+ requestedAt: now,
127
+ instructions: values.instructions ?? null,
128
+ guidance,
129
+ });
130
+
131
+ return {
132
+ queueItem: {
133
+ id,
134
+ sourceId: values.capture.sourceId,
135
+ captureId: values.capture.id,
136
+ status: "queued" as const,
137
+ priority,
138
+ attempts: 0,
139
+ error: null,
140
+ runAfter: null,
141
+ createdAt: now,
142
+ updatedAt: now,
143
+ },
144
+ existing: false,
145
+ guidance: guidance.distillation,
146
+ };
147
+ }
@@ -0,0 +1,264 @@
1
+ import { accessFilter } from "@agent-native/core/sharing";
2
+ import { and, inArray } from "drizzle-orm";
3
+
4
+ import { getDb, schema } from "../db/index.js";
5
+ import { parseJson } from "./brain.js";
6
+
7
+ export type SourceTrustTier = "blessed" | "standard" | "untrusted";
8
+ export type SourceConflictBehavior =
9
+ | "prefer-higher-authority"
10
+ | "surface-conflicts"
11
+ | "require-review";
12
+
13
+ export interface SourceAnswerPolicy {
14
+ trustTier: SourceTrustTier;
15
+ answerEligible: boolean;
16
+ authority: number;
17
+ freshnessWindowDays: number | null;
18
+ reviewRequired: boolean;
19
+ conflictBehavior: SourceConflictBehavior;
20
+ }
21
+
22
+ export interface SourcePolicySnapshot extends SourceAnswerPolicy {
23
+ sourceId: string;
24
+ provider: string;
25
+ lastSyncedAt: string | null;
26
+ updatedAt: string;
27
+ }
28
+
29
+ export interface EvaluatedSourceAnswerPolicy extends SourceAnswerPolicy {
30
+ sourceIds: string[];
31
+ eligible: boolean;
32
+ freshness: "fresh" | "stale" | "not-configured";
33
+ exclusionReasons: Array<"answer-ineligible" | "stale" | "review-required">;
34
+ }
35
+
36
+ export const DEFAULT_SOURCE_ANSWER_POLICY: SourceAnswerPolicy = {
37
+ trustTier: "standard",
38
+ answerEligible: true,
39
+ authority: 50,
40
+ freshnessWindowDays: null,
41
+ reviewRequired: false,
42
+ conflictBehavior: "prefer-higher-authority",
43
+ };
44
+
45
+ function isRecord(value: unknown): value is Record<string, unknown> {
46
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
47
+ }
48
+
49
+ function isTrustTier(value: unknown): value is SourceTrustTier {
50
+ return ["blessed", "standard", "untrusted"].includes(String(value));
51
+ }
52
+
53
+ function isConflictBehavior(value: unknown): value is SourceConflictBehavior {
54
+ return [
55
+ "prefer-higher-authority",
56
+ "surface-conflicts",
57
+ "require-review",
58
+ ].includes(String(value));
59
+ }
60
+
61
+ function boundedInteger(
62
+ value: unknown,
63
+ fallback: number,
64
+ min: number,
65
+ max: number,
66
+ ) {
67
+ const parsed =
68
+ typeof value === "number"
69
+ ? value
70
+ : typeof value === "string" && value.trim()
71
+ ? Number(value)
72
+ : Number.NaN;
73
+ if (!Number.isFinite(parsed)) return fallback;
74
+ return Math.max(min, Math.min(max, Math.round(parsed)));
75
+ }
76
+
77
+ export function normalizeSourceAnswerPolicy(
78
+ value: unknown,
79
+ base: SourceAnswerPolicy = DEFAULT_SOURCE_ANSWER_POLICY,
80
+ ): SourceAnswerPolicy {
81
+ if (!isRecord(value)) return { ...base };
82
+ const trustTier = isTrustTier(value.trustTier)
83
+ ? value.trustTier
84
+ : base.trustTier;
85
+ const tierChanged =
86
+ isTrustTier(value.trustTier) && trustTier !== base.trustTier;
87
+ const answerEligible =
88
+ typeof value.answerEligible === "boolean"
89
+ ? value.answerEligible
90
+ : tierChanged
91
+ ? trustTier !== "untrusted"
92
+ : base.answerEligible;
93
+ const reviewRequired =
94
+ typeof value.reviewRequired === "boolean"
95
+ ? value.reviewRequired
96
+ : tierChanged
97
+ ? trustTier === "untrusted"
98
+ : base.reviewRequired;
99
+ const freshnessWindowDays =
100
+ value.freshnessWindowDays === null
101
+ ? null
102
+ : value.freshnessWindowDays === undefined
103
+ ? base.freshnessWindowDays
104
+ : boundedInteger(value.freshnessWindowDays, 0, 0, 3650);
105
+
106
+ return {
107
+ trustTier,
108
+ answerEligible,
109
+ authority: boundedInteger(value.authority, base.authority, 0, 100),
110
+ freshnessWindowDays,
111
+ reviewRequired,
112
+ conflictBehavior: isConflictBehavior(value.conflictBehavior)
113
+ ? value.conflictBehavior
114
+ : base.conflictBehavior,
115
+ };
116
+ }
117
+
118
+ export function sourceAnswerPolicyFromConfig(
119
+ config: Record<string, unknown>,
120
+ ): SourceAnswerPolicy {
121
+ return normalizeSourceAnswerPolicy(config.answerPolicy);
122
+ }
123
+
124
+ export function withSourceAnswerPolicy(
125
+ config: Record<string, unknown>,
126
+ input: unknown,
127
+ ): Record<string, unknown> {
128
+ const current = sourceAnswerPolicyFromConfig(config);
129
+ return {
130
+ ...config,
131
+ answerPolicy: normalizeSourceAnswerPolicy(input, current),
132
+ };
133
+ }
134
+
135
+ export async function loadAccessibleSourcePolicySnapshots(
136
+ sourceIds: string[],
137
+ ): Promise<Map<string, SourcePolicySnapshot>> {
138
+ const ids = Array.from(new Set(sourceIds.filter(Boolean)));
139
+ if (!ids.length) return new Map();
140
+ const rows = await getDb()
141
+ .select()
142
+ .from(schema.brainSources)
143
+ .where(
144
+ and(
145
+ accessFilter(schema.brainSources, schema.brainSourceShares),
146
+ inArray(schema.brainSources.id, ids),
147
+ ),
148
+ );
149
+ return new Map(
150
+ rows.map((row) => [
151
+ row.id,
152
+ {
153
+ sourceId: row.id,
154
+ provider: row.provider,
155
+ lastSyncedAt: row.lastSyncedAt,
156
+ updatedAt: row.updatedAt,
157
+ ...sourceAnswerPolicyFromConfig(
158
+ parseJson<Record<string, unknown>>(row.configJson, {}),
159
+ ),
160
+ },
161
+ ]),
162
+ );
163
+ }
164
+
165
+ const TRUST_RANK: Record<SourceTrustTier, number> = {
166
+ blessed: 3,
167
+ standard: 2,
168
+ untrusted: 1,
169
+ };
170
+
171
+ function primaryPolicy(policies: SourcePolicySnapshot[]): SourceAnswerPolicy {
172
+ const [primary] = [...policies].sort(
173
+ (left, right) =>
174
+ TRUST_RANK[right.trustTier] - TRUST_RANK[left.trustTier] ||
175
+ right.authority - left.authority,
176
+ );
177
+ return primary ?? DEFAULT_SOURCE_ANSWER_POLICY;
178
+ }
179
+
180
+ export function evaluateSourceAnswerPolicy(args: {
181
+ sourceIds: string[];
182
+ sourcePolicies: Map<string, SourcePolicySnapshot>;
183
+ contentUpdatedAt: string;
184
+ resultType: "knowledge" | "capture";
185
+ reviewed?: boolean;
186
+ now?: Date;
187
+ }): EvaluatedSourceAnswerPolicy {
188
+ const sourceIds = Array.from(new Set(args.sourceIds.filter(Boolean)));
189
+ const effectivePolicies = sourceIds.length
190
+ ? sourceIds.map(
191
+ (id) =>
192
+ args.sourcePolicies.get(id) ?? {
193
+ sourceId: id,
194
+ provider: "legacy",
195
+ lastSyncedAt: null,
196
+ updatedAt: args.contentUpdatedAt,
197
+ ...DEFAULT_SOURCE_ANSWER_POLICY,
198
+ },
199
+ )
200
+ : [
201
+ {
202
+ sourceId: "",
203
+ provider: "legacy",
204
+ lastSyncedAt: null,
205
+ updatedAt: args.contentUpdatedAt,
206
+ ...DEFAULT_SOURCE_ANSWER_POLICY,
207
+ },
208
+ ];
209
+ const primary = primaryPolicy(effectivePolicies);
210
+ const now = (args.now ?? new Date()).getTime();
211
+ const updatedAt = Date.parse(args.contentUpdatedAt);
212
+ const stale = effectivePolicies.some((policy) => {
213
+ if (policy.freshnessWindowDays === null) return false;
214
+ if (!Number.isFinite(updatedAt)) return true;
215
+ return now - updatedAt > policy.freshnessWindowDays * 24 * 60 * 60 * 1000;
216
+ });
217
+ const answerIneligible = effectivePolicies.some(
218
+ (policy) => !policy.answerEligible,
219
+ );
220
+ const missingRequiredReview =
221
+ !args.reviewed &&
222
+ effectivePolicies.some(
223
+ (policy) =>
224
+ policy.reviewRequired || policy.conflictBehavior === "require-review",
225
+ );
226
+ const exclusionReasons: EvaluatedSourceAnswerPolicy["exclusionReasons"] = [];
227
+ if (answerIneligible) exclusionReasons.push("answer-ineligible");
228
+ if (stale) exclusionReasons.push("stale");
229
+ if (missingRequiredReview) exclusionReasons.push("review-required");
230
+
231
+ return {
232
+ ...primary,
233
+ sourceIds,
234
+ reviewRequired: effectivePolicies.some((policy) => policy.reviewRequired),
235
+ freshnessWindowDays: effectivePolicies.reduce<number | null>(
236
+ (minimum, policy) => {
237
+ if (policy.freshnessWindowDays === null) return minimum;
238
+ return minimum === null
239
+ ? policy.freshnessWindowDays
240
+ : Math.min(minimum, policy.freshnessWindowDays);
241
+ },
242
+ null,
243
+ ),
244
+ eligible: exclusionReasons.length === 0,
245
+ freshness: effectivePolicies.every(
246
+ (policy) => policy.freshnessWindowDays === null,
247
+ )
248
+ ? "not-configured"
249
+ : stale
250
+ ? "stale"
251
+ : "fresh",
252
+ exclusionReasons,
253
+ };
254
+ }
255
+
256
+ export function compareEvaluatedSourcePolicies(
257
+ left: EvaluatedSourceAnswerPolicy,
258
+ right: EvaluatedSourceAnswerPolicy,
259
+ ) {
260
+ return (
261
+ TRUST_RANK[right.trustTier] - TRUST_RANK[left.trustTier] ||
262
+ right.authority - left.authority
263
+ );
264
+ }
@@ -48,15 +48,16 @@ export default createAgentChatPlugin({
48
48
  codeExecution: { production: "sandboxed" },
49
49
  systemPrompt: `You are the Brain institutional-knowledge agent.
50
50
 
51
- Use actions as the source of truth. Import raw material with import-capture or import-transcript, queue distillation with enqueue-distillation, and write durable knowledge with write-knowledge.
51
+ Use actions as the source of truth. Import raw material with import-capture or import-transcript, which queue distillation by default, use enqueue-distillation to retry or explicitly queue an existing capture, and write durable knowledge with write-knowledge.
52
52
 
53
53
  Important rules:
54
54
  - Before answering, searching broadly, or distilling, call get-brain-settings when you do not already have current settings. Apply its guidance for assistant name, company name, tone, source policy, citation requirements, publish tier, pre-save capture sanitization, redaction, and distillation instructions.
55
55
  - Evidence quotes must be exact substrings of a raw capture. Use get-capture with includeRawContent=true only when you need exact quote validation; normal capture reads are redacted by default.
56
56
  - No vector database exists; search-knowledge uses SQL text matching.
57
57
  - Source policy matters: strict means answer from reviewed knowledge only; balanced means raw captures are fallback context when reviewed knowledge is thin; exploratory means raw captures and sources may be surfaced as clearly labeled leads.
58
+ - Source answer policy is enforced separately from the workspace retrieval mode. For approved FAQs, docs, or other source-owner-published resources, create a generic source with policy.trustTier=blessed and choose answer eligibility, authority, freshness, review, and conflict behavior deliberately. Prefer blessed, higher-authority eligible sources in cited answers; never answer from stale or answer-ineligible sources.
58
59
  - Company-tier knowledge may create a proposal instead of publishing immediately, depending on settings.
59
- - Slack and Granola sources are configurable v1 connectors. Generic transcript import is always available.
60
+ - Slack and Granola sources are configurable v1 connectors. Generic capture and transcript import are always available.
60
61
  - Source/read actions are convenience readers, not provider capability limits. Before any provider API request, call list-connection-providers and inspect the matching provider. If configured is not true, do not attempt the request; explain that the connection needs setup or repair and include setupLink. Jira is queried on demand through the provider API rather than indexed as a Brain source. For ad hoc provider analysis that needs an endpoint, filter, payload, pagination mode, or API version not modeled by a Brain action, call provider-api-catalog/provider-api-docs, then provider-api-request against the provider's real HTTP API. Use connectionId for a specific shared grant and accountId for a specific OAuth account.
61
62
  - For broad searches, joins, classification, source-corpus counts, or absence claims across provider records, fetch every relevant page or an explicitly bounded cohort, stage/save large responses with stageAs/saveToFile/fetchAllPages, then use query-staged-dataset or run-code to reduce the corpus. Report source, filters, row counts, pagination, truncation, and gaps.`,
62
63
  a2aMessageFallback: async ({ text }) => tryAnswerBrainA2AQuestion(text),
@@ -11,11 +11,21 @@ import {
11
11
  BrainCaptureBlockedError,
12
12
  createCapture,
13
13
  parseJson,
14
+ retireUpstreamDeletedCapture,
14
15
  serializeCapture,
15
16
  sha256Hex,
16
17
  } from "../../../../lib/brain.js";
18
+ import { enqueueCaptureDistillation } from "../../../../lib/distillation-queue.js";
17
19
  import { resolveMeetingMemberEmails } from "../../../../lib/meeting-audience.js";
18
20
 
21
+ const captureKindSchema = z.enum([
22
+ "transcript",
23
+ "note",
24
+ "message",
25
+ "document",
26
+ "generic",
27
+ ]);
28
+
19
29
  const segmentSchema = z
20
30
  .object({
21
31
  startMs: z.coerce.number().int().min(0).optional(),
@@ -29,17 +39,40 @@ const rawCapturePayloadSchema = z
29
39
  .object({
30
40
  sourceKey: z.string().min(1),
31
41
  externalId: z.string().min(1),
32
- title: z.string().min(1),
42
+ title: z.string().min(1).optional(),
43
+ kind: captureKindSchema.optional(),
44
+ content: z.string().optional(),
33
45
  participants: z.array(z.unknown()).default([]),
46
+ capturedAt: z.string().optional(),
34
47
  occurredAt: z.string().optional(),
35
48
  transcript: z.string().optional(),
36
49
  segments: z.array(segmentSchema).optional(),
37
50
  sourceUrl: z.string().url().optional(),
38
51
  tags: z.array(z.string()).default([]),
52
+ metadata: z.record(z.string(), z.unknown()).default({}),
39
53
  raw: z.unknown().optional(),
54
+ deleted: z.boolean().default(false),
40
55
  })
41
- .refine((payload) => payload.transcript?.trim() || payload.segments?.length, {
42
- message: "Provide transcript or segments",
56
+ .superRefine((payload, context) => {
57
+ if (payload.deleted) return;
58
+ if (!payload.title) {
59
+ context.addIssue({
60
+ code: "custom",
61
+ message: "Provide title",
62
+ path: ["title"],
63
+ });
64
+ }
65
+ if (
66
+ !payload.content?.trim() &&
67
+ !payload.transcript?.trim() &&
68
+ !payload.segments?.length
69
+ ) {
70
+ context.addIssue({
71
+ code: "custom",
72
+ message: "Provide content, transcript, or segments",
73
+ path: ["content"],
74
+ });
75
+ }
43
76
  });
44
77
 
45
78
  function bearerToken(event: H3Event) {
@@ -50,6 +83,7 @@ function bearerToken(event: H3Event) {
50
83
  }
51
84
 
52
85
  function textFromPayload(payload: z.infer<typeof rawCapturePayloadSchema>) {
86
+ if (payload.content?.trim()) return payload.content.trim();
53
87
  if (payload.transcript?.trim()) return payload.transcript.trim();
54
88
  return (payload.segments ?? [])
55
89
  .map((segment) => {
@@ -60,6 +94,33 @@ function textFromPayload(payload: z.infer<typeof rawCapturePayloadSchema>) {
60
94
  .trim();
61
95
  }
62
96
 
97
+ function kindFromPayload(payload: z.infer<typeof rawCapturePayloadSchema>) {
98
+ if (payload.kind) return payload.kind;
99
+ if (payload.transcript?.trim() || payload.segments?.length) {
100
+ return "transcript" as const;
101
+ }
102
+ return "generic" as const;
103
+ }
104
+
105
+ function metadataFromPayload(
106
+ payload: z.infer<typeof rawCapturePayloadSchema>,
107
+ kind: z.infer<typeof captureKindSchema>,
108
+ ) {
109
+ const metadata = {
110
+ ...payload.metadata,
111
+ sourceKey: payload.sourceKey,
112
+ sourceUrl: payload.sourceUrl,
113
+ tags: payload.tags,
114
+ };
115
+ if (kind !== "transcript") return metadata;
116
+ return {
117
+ ...metadata,
118
+ participants: payload.participants,
119
+ segments: payload.segments ?? [],
120
+ raw: payload.raw,
121
+ };
122
+ }
123
+
63
124
  function sourceKeyConfigPattern(sourceKey: string) {
64
125
  return `%"sourceKey":${JSON.stringify(sourceKey)}%`;
65
126
  }
@@ -112,6 +173,22 @@ export default defineEventHandler(async (event) => {
112
173
  orgId: source.orgId ?? undefined,
113
174
  },
114
175
  async () => {
176
+ if (payload.deleted) {
177
+ const retired = await retireUpstreamDeletedCapture({
178
+ sourceId: source.id,
179
+ externalId: payload.externalId,
180
+ provider: source.provider,
181
+ });
182
+ return {
183
+ ok: true,
184
+ sourceId: source.id,
185
+ capture: null,
186
+ deleted: true,
187
+ retired,
188
+ };
189
+ }
190
+
191
+ const kind = kindFromPayload(payload);
115
192
  const memberEmails = resolveMeetingMemberEmails(
116
193
  payload.participants,
117
194
  source.ownerEmail,
@@ -121,23 +198,19 @@ export default defineEventHandler(async (event) => {
121
198
  capture = await createCapture({
122
199
  sourceId: source.id,
123
200
  externalId: payload.externalId,
124
- title: payload.title,
125
- kind: "transcript",
201
+ title: payload.title!,
202
+ kind,
126
203
  content: textFromPayload(payload),
127
- capturedAt: payload.occurredAt,
128
- metadata: {
129
- sourceKey: payload.sourceKey,
130
- participants: payload.participants,
131
- segments: payload.segments ?? [],
132
- sourceUrl: payload.sourceUrl,
133
- tags: payload.tags,
134
- raw: payload.raw,
135
- },
136
- audience: {
137
- kind: "meeting",
138
- memberEmails,
139
- upstreamRefHash: payload.externalId,
140
- },
204
+ capturedAt: payload.capturedAt ?? payload.occurredAt,
205
+ metadata: metadataFromPayload(payload, kind),
206
+ audience:
207
+ kind === "transcript"
208
+ ? {
209
+ kind: "meeting",
210
+ memberEmails,
211
+ upstreamRefHash: payload.externalId,
212
+ }
213
+ : undefined,
141
214
  });
142
215
  } catch (error) {
143
216
  if (!(error instanceof BrainCaptureBlockedError)) throw error;
@@ -149,10 +222,34 @@ export default defineEventHandler(async (event) => {
149
222
  };
150
223
  }
151
224
 
225
+ const distillation =
226
+ capture.status === "distilled" || capture.status === "ignored"
227
+ ? null
228
+ : await enqueueCaptureDistillation({
229
+ capture,
230
+ priority: 50,
231
+ payload: {
232
+ sourceKey: payload.sourceKey,
233
+ externalId: payload.externalId,
234
+ },
235
+ });
236
+
152
237
  return {
153
238
  ok: true,
154
239
  sourceId: source.id,
155
240
  capture: serializeCapture(capture),
241
+ distillation: distillation
242
+ ? {
243
+ queued: true,
244
+ queueId: distillation.queueItem.id,
245
+ existing: distillation.existing,
246
+ }
247
+ : {
248
+ queued: false,
249
+ queueId: null,
250
+ existing: false,
251
+ reason: `already-${capture.status}`,
252
+ },
156
253
  };
157
254
  },
158
255
  );
@@ -0,0 +1,51 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react";
3
+
4
+ import { Button } from "@/components/ui/button";
5
+ import {
6
+ Popover,
7
+ PopoverContent,
8
+ PopoverTrigger,
9
+ } from "@/components/ui/popover";
10
+ import { cn } from "@/lib/utils";
11
+
12
+ export function GoogleOAuthIdentityNotice({
13
+ className,
14
+ }: {
15
+ className?: string;
16
+ }) {
17
+ const t = useT();
18
+ return (
19
+ <Popover>
20
+ <PopoverTrigger asChild>
21
+ <Button
22
+ type="button"
23
+ variant="ghost"
24
+ size="sm"
25
+ className={cn(
26
+ "h-auto gap-1 px-0 py-0 text-[11px] font-normal text-muted-foreground/70 hover:bg-transparent hover:text-muted-foreground",
27
+ className,
28
+ )}
29
+ >
30
+ <IconInfoCircle className="size-3" />
31
+ {t("meetingsRoute.googleMayShowWarning")}
32
+ </Button>
33
+ </PopoverTrigger>
34
+ <PopoverContent align="start" className="w-72 text-start">
35
+ <div className="flex items-start gap-2.5">
36
+ <div className="mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-md bg-amber-500/15 text-amber-300">
37
+ <IconAlertTriangle className="size-3.5" />
38
+ </div>
39
+ <div className="space-y-1.5">
40
+ <p className="text-[13px] font-medium text-foreground">
41
+ {t("meetingsRoute.googleNotVerifiedTitle")}
42
+ </p>
43
+ <p className="text-xs leading-relaxed text-muted-foreground">
44
+ {t("meetingsRoute.googleWarningBeforeAdvanced")}
45
+ </p>
46
+ </div>
47
+ </div>
48
+ </PopoverContent>
49
+ </Popover>
50
+ );
51
+ }
@@ -1498,6 +1498,10 @@ All notable user-facing changes to Clips are documented here. Open it any time f
1498
1498
  calendarNeedsReconnect:
1499
1499
  "Google Calendar needs to be reconnected to keep showing your upcoming meetings.",
1500
1500
  connectGoogleCalendar: "Connect Google Calendar",
1501
+ googleMayShowWarning: "Review Google access",
1502
+ googleNotVerifiedTitle: "Verify the app before connecting",
1503
+ googleWarningBeforeAdvanced:
1504
+ "Confirm the app name and requested Calendar access match the Clips deployment you trust. If Google shows an unverified-app warning or the identity looks unfamiliar, stop and contact your workspace administrator.",
1501
1505
  desktopReminder:
1502
1506
  "Connect Google Calendar, keep Clips Desktop open, then click Start notes from the reminder or the menu bar when your meeting begins.",
1503
1507
  getDesktopApp: "Get desktop app",