@agent-native/core 0.131.4 → 0.131.6

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 (330) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +69 -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 +14 -10
  7. package/corpus/core/docs/content/docs-components.mdx +491 -0
  8. package/corpus/core/docs/content/doctor.mdx +8 -1
  9. package/corpus/core/docs/content/drop-in-agent.mdx +1 -1
  10. package/corpus/core/docs/content/extensions.mdx +18 -18
  11. package/corpus/core/docs/content/faq.mdx +4 -4
  12. package/corpus/core/docs/content/key-concepts.mdx +30 -21
  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/types.ts +4 -0
  20. package/corpus/core/src/action.ts +3 -0
  21. package/corpus/core/src/agent/engine/registry.ts +45 -5
  22. package/corpus/core/src/agent/production-agent.ts +151 -18
  23. package/corpus/core/src/agent/run-loop-with-resume.ts +190 -3
  24. package/corpus/core/src/agent/run-manager.ts +117 -41
  25. package/corpus/core/src/agent/thread-debug-history.ts +86 -0
  26. package/corpus/core/src/agent/types.ts +3 -1
  27. package/corpus/core/src/cli/create.ts +11 -1
  28. package/corpus/core/src/cli/templates-meta.ts +2 -2
  29. package/corpus/core/src/client/agent-chat-adapter.ts +91 -13
  30. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +11 -9
  31. package/corpus/core/src/client/sse-event-processor.ts +17 -3
  32. package/corpus/core/src/db/client.ts +57 -17
  33. package/corpus/core/src/integrations/adapters/slack.ts +8 -3
  34. package/corpus/core/src/localization/default-messages.ts +44 -0
  35. package/corpus/core/src/observability/traces.ts +78 -5
  36. package/corpus/core/src/scripts/call-agent.ts +290 -9
  37. package/corpus/core/src/scripts/describe-workspace-apps.ts +2 -2
  38. package/corpus/core/src/secrets/crypto.ts +126 -34
  39. package/corpus/core/src/secrets/storage.ts +61 -25
  40. package/corpus/core/src/server/agent-capabilities.ts +1 -1
  41. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +111 -7
  42. package/corpus/core/src/server/agent-chat/context-tools.ts +2 -0
  43. package/corpus/core/src/server/agent-chat/plugin-options.ts +34 -1
  44. package/corpus/core/src/server/agent-chat/prompt-resources.ts +1 -1
  45. package/corpus/core/src/server/agent-chat-plugin.ts +91 -59
  46. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +14 -7
  47. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +14 -7
  48. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  49. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  50. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -7
  51. package/corpus/core/src/vite/client.ts +1 -0
  52. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +5 -4
  53. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +6 -4
  54. package/corpus/templates/analytics/AGENTS.md +6 -4
  55. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -3
  56. package/corpus/templates/analytics/changelog/2026-07-30-scheduled-dashboard-emails-complete-every-panel-without-pool.md +6 -0
  57. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +28 -1
  58. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +18 -11
  59. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +4 -4
  60. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -5
  61. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +6 -2
  62. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +11 -4
  63. package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +49 -31
  64. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +16 -8
  65. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -3
  66. package/corpus/templates/analytics/server/lib/production-serverless-runtime.ts +11 -0
  67. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -2
  68. package/corpus/templates/analytics/server/plugins/analytics-alert-jobs.ts +2 -1
  69. package/corpus/templates/analytics/server/plugins/dashboard-report-jobs.ts +2 -1
  70. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +1 -12
  71. package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +54 -6
  72. package/corpus/templates/brain/.agents/skills/brain/SKILL.md +20 -9
  73. package/corpus/templates/brain/.agents/skills/ingestion-and-connectors/SKILL.md +33 -1
  74. package/corpus/templates/brain/AGENTS.md +3 -1
  75. package/corpus/templates/brain/README.md +4 -1
  76. package/corpus/templates/brain/actions/_schemas.ts +30 -8
  77. package/corpus/templates/brain/actions/ask-brain.ts +124 -14
  78. package/corpus/templates/brain/actions/create-source.ts +18 -2
  79. package/corpus/templates/brain/actions/enqueue-captures-distillation.ts +8 -123
  80. package/corpus/templates/brain/actions/enqueue-distillation.ts +6 -127
  81. package/corpus/templates/brain/actions/import-capture.ts +17 -5
  82. package/corpus/templates/brain/actions/import-transcript.ts +17 -5
  83. package/corpus/templates/brain/actions/update-source.ts +25 -5
  84. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +1 -1
  85. package/corpus/templates/brain/changelog/2026-07-30-blessed-resources-can-feed-cited-company-answers.md +6 -0
  86. package/corpus/templates/brain/changelog/2026-07-30-the-left-sidebar-no-longer-shows-a-blank-organization-placeh.md +6 -0
  87. package/corpus/templates/brain/server/lib/brain.ts +49 -19
  88. package/corpus/templates/brain/server/lib/distillation-queue.ts +147 -0
  89. package/corpus/templates/brain/server/lib/source-policy.ts +264 -0
  90. package/corpus/templates/brain/server/plugins/agent-chat.ts +3 -2
  91. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +116 -19
  92. package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +51 -0
  93. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  94. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +3 -1
  95. package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +6 -0
  96. package/corpus/templates/content/.agents/skills/content-product-development/SKILL.md +47 -0
  97. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +72 -8
  98. package/corpus/templates/content/changelog/2026-07-30-the-slash-command-hint-now-stays-on-only-the-active-empty-li.md +6 -0
  99. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +506 -11
  100. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +148 -17
  101. package/corpus/templates/design/app/components/design/canvas-interactions/design-canvas-interactions.ts +357 -0
  102. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +7 -466
  103. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +15 -311
  104. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +19 -997
  105. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +8 -1216
  106. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +31 -38
  107. package/corpus/templates/design/package.json +0 -1
  108. package/corpus/templates/dispatch/AGENTS.md +8 -0
  109. package/corpus/templates/dispatch/DEVELOPING.md +29 -0
  110. package/corpus/templates/dispatch/actions/view-screen.ts +34 -2
  111. package/corpus/templates/dispatch/app/i18n-data.ts +457 -0
  112. package/corpus/templates/dispatch/changelog/2026-07-30-delegated-dispatch-work-continues-reliably-in-the-background.md +6 -0
  113. package/corpus/templates/dispatch/changelog/2026-07-30-find-failed-runs-across-apps.md +6 -0
  114. package/corpus/templates/dispatch/netlify.toml +3 -0
  115. package/corpus/templates/slides/.agents/skills/analytics-data-for-decks/SKILL.md +8 -12
  116. package/corpus/templates/slides/AGENTS.md +4 -4
  117. package/corpus/templates/slides/actions/duplicate-deck.ts +19 -4
  118. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -10
  119. package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +12 -1
  120. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +30 -13
  121. package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +35 -0
  122. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +63 -56
  123. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +21 -76
  124. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1110 -292
  125. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +53 -0
  126. package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +235 -18
  127. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +4 -1
  128. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +11 -0
  129. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +129 -0
  130. package/corpus/templates/slides/app/components/editor/selection-overlay-measurement.ts +70 -0
  131. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +519 -65
  132. package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +36 -426
  133. package/corpus/templates/slides/app/components/visual-editor/DrawOverlay.tsx +19 -458
  134. package/corpus/templates/slides/app/context/DeckContext.tsx +179 -72
  135. package/corpus/templates/slides/app/global.css +105 -0
  136. package/corpus/templates/slides/app/i18n/en-US.ts +8 -0
  137. package/corpus/templates/slides/app/lib/deck-editor-loading.ts +26 -0
  138. package/corpus/templates/slides/app/lib/mermaid-blocks.ts +27 -0
  139. package/corpus/templates/slides/app/pages/DeckEditor.tsx +71 -38
  140. package/corpus/templates/slides/app/pages/Index.tsx +98 -41
  141. package/corpus/templates/slides/changelog/2026-07-30-deck-loading-no-longer-flashes-an-unavailable-message.md +6 -0
  142. package/corpus/templates/slides/changelog/2026-07-30-duplicating-a-deck-from-the-deck-list-now-opens-the-copy-imm.md +6 -0
  143. package/corpus/templates/slides/changelog/2026-07-30-layout-overflow-warning-is-readable-and-dismissible.md +6 -0
  144. package/corpus/templates/slides/changelog/2026-07-30-shared-canvas-annotations.md +6 -0
  145. package/corpus/templates/slides/changelog/2026-07-30-slide-objects-can-be-moved-as-a-group-copied-and-pasted-with.md +6 -0
  146. package/corpus/templates/slides/changelog/2026-07-30-slide-text-editing-and-object-controls-now-match-google-slides.md +6 -0
  147. package/corpus/templates/slides/changelog/2026-07-30-style-panel-now-scrolls-with-speaker-notes-open-shows-the-sl.md +6 -0
  148. package/corpus/templates/slides/changelog/2026-07-30-top-toolbar-controls-now-use-consistent-sizing-with-undo-and.md +6 -0
  149. package/corpus/templates/slides/netlify.toml +3 -1
  150. package/corpus/templates/slides/package.json +0 -1
  151. package/corpus/templates/slides/server/lib/chat-attachments.ts +18 -0
  152. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
  153. package/corpus/templates/slides/vite.config.ts +0 -1
  154. package/corpus/toolkit/CHANGELOG.md +13 -0
  155. package/corpus/toolkit/README.md +19 -0
  156. package/corpus/toolkit/agent-native.eject.json +38 -0
  157. package/corpus/toolkit/package.json +29 -1
  158. package/corpus/toolkit/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
  159. package/corpus/toolkit/src/canvas-annotations/DrawOverlay.tsx +1233 -0
  160. package/corpus/toolkit/src/canvas-annotations/index.ts +15 -0
  161. package/corpus/toolkit/src/canvas-annotations/types.ts +14 -0
  162. package/corpus/toolkit/src/canvas-interactions/canvas-interactions.ts +933 -0
  163. package/corpus/toolkit/src/canvas-interactions/index.ts +67 -0
  164. package/corpus/toolkit/src/design-tweaks/scrub-input-utils.ts +311 -0
  165. package/corpus/toolkit/src/design-tweaks/scrub-input.tsx +491 -0
  166. package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +26 -171
  167. package/corpus/toolkit/src/index.ts +1 -0
  168. package/dist/a2a/client.d.ts +23 -0
  169. package/dist/a2a/client.d.ts.map +1 -1
  170. package/dist/a2a/client.js +309 -44
  171. package/dist/a2a/client.js.map +1 -1
  172. package/dist/a2a/correlation.d.ts +1 -0
  173. package/dist/a2a/correlation.d.ts.map +1 -1
  174. package/dist/a2a/correlation.js +27 -0
  175. package/dist/a2a/correlation.js.map +1 -1
  176. package/dist/a2a/types.d.ts +4 -0
  177. package/dist/a2a/types.d.ts.map +1 -1
  178. package/dist/a2a/types.js.map +1 -1
  179. package/dist/action.d.ts +3 -0
  180. package/dist/action.d.ts.map +1 -1
  181. package/dist/action.js.map +1 -1
  182. package/dist/agent/engine/registry.d.ts.map +1 -1
  183. package/dist/agent/engine/registry.js +34 -7
  184. package/dist/agent/engine/registry.js.map +1 -1
  185. package/dist/agent/production-agent.d.ts +40 -1
  186. package/dist/agent/production-agent.d.ts.map +1 -1
  187. package/dist/agent/production-agent.js +113 -15
  188. package/dist/agent/production-agent.js.map +1 -1
  189. package/dist/agent/run-loop-with-resume.d.ts +21 -0
  190. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  191. package/dist/agent/run-loop-with-resume.js +163 -4
  192. package/dist/agent/run-loop-with-resume.js.map +1 -1
  193. package/dist/agent/run-manager.d.ts +16 -9
  194. package/dist/agent/run-manager.d.ts.map +1 -1
  195. package/dist/agent/run-manager.js +93 -42
  196. package/dist/agent/run-manager.js.map +1 -1
  197. package/dist/agent/thread-debug-history.d.ts +10 -0
  198. package/dist/agent/thread-debug-history.d.ts.map +1 -0
  199. package/dist/agent/thread-debug-history.js +68 -0
  200. package/dist/agent/thread-debug-history.js.map +1 -0
  201. package/dist/agent/types.d.ts +3 -1
  202. package/dist/agent/types.d.ts.map +1 -1
  203. package/dist/agent/types.js.map +1 -1
  204. package/dist/cli/create.d.ts.map +1 -1
  205. package/dist/cli/create.js +6 -1
  206. package/dist/cli/create.js.map +1 -1
  207. package/dist/cli/templates-meta.js +2 -2
  208. package/dist/cli/templates-meta.js.map +1 -1
  209. package/dist/client/agent-chat-adapter.d.ts +1 -1
  210. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  211. package/dist/client/agent-chat-adapter.js +76 -13
  212. package/dist/client/agent-chat-adapter.js.map +1 -1
  213. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  214. package/dist/client/resources/McpIntegrationDialog.js +1 -1
  215. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  216. package/dist/client/sse-event-processor.d.ts.map +1 -1
  217. package/dist/client/sse-event-processor.js +12 -3
  218. package/dist/client/sse-event-processor.js.map +1 -1
  219. package/dist/collab/awareness.d.ts +2 -2
  220. package/dist/collab/awareness.d.ts.map +1 -1
  221. package/dist/db/client.d.ts.map +1 -1
  222. package/dist/db/client.js +48 -17
  223. package/dist/db/client.js.map +1 -1
  224. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  225. package/dist/integrations/adapters/slack.js +7 -3
  226. package/dist/integrations/adapters/slack.js.map +1 -1
  227. package/dist/localization/default-messages.d.ts +43 -0
  228. package/dist/localization/default-messages.d.ts.map +1 -1
  229. package/dist/localization/default-messages.js +43 -0
  230. package/dist/localization/default-messages.js.map +1 -1
  231. package/dist/notifications/routes.d.ts +2 -2
  232. package/dist/observability/traces.d.ts +3 -1
  233. package/dist/observability/traces.d.ts.map +1 -1
  234. package/dist/observability/traces.js +73 -4
  235. package/dist/observability/traces.js.map +1 -1
  236. package/dist/progress/routes.d.ts +1 -1
  237. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  238. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  239. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  240. package/dist/resources/handlers.d.ts +1 -1
  241. package/dist/scripts/call-agent.d.ts.map +1 -1
  242. package/dist/scripts/call-agent.js +233 -10
  243. package/dist/scripts/call-agent.js.map +1 -1
  244. package/dist/scripts/describe-workspace-apps.js +2 -2
  245. package/dist/scripts/describe-workspace-apps.js.map +1 -1
  246. package/dist/secrets/crypto.d.ts +31 -21
  247. package/dist/secrets/crypto.d.ts.map +1 -1
  248. package/dist/secrets/crypto.js +108 -33
  249. package/dist/secrets/crypto.js.map +1 -1
  250. package/dist/secrets/storage.d.ts +3 -5
  251. package/dist/secrets/storage.d.ts.map +1 -1
  252. package/dist/secrets/storage.js +40 -25
  253. package/dist/secrets/storage.js.map +1 -1
  254. package/dist/server/agent-capabilities.js +1 -1
  255. package/dist/server/agent-capabilities.js.map +1 -1
  256. package/dist/server/agent-chat/action-filters-a2a.d.ts +17 -3
  257. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  258. package/dist/server/agent-chat/action-filters-a2a.js +92 -3
  259. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  260. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  261. package/dist/server/agent-chat/context-tools.js +2 -0
  262. package/dist/server/agent-chat/context-tools.js.map +1 -1
  263. package/dist/server/agent-chat/plugin-options.d.ts +23 -0
  264. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  265. package/dist/server/agent-chat/plugin-options.js +4 -1
  266. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  267. package/dist/server/agent-chat/prompt-resources.js +1 -1
  268. package/dist/server/agent-chat/prompt-resources.js.map +1 -1
  269. package/dist/server/agent-chat-plugin.d.ts +2 -1
  270. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  271. package/dist/server/agent-chat-plugin.js +79 -56
  272. package/dist/server/agent-chat-plugin.js.map +1 -1
  273. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  274. package/dist/templates/default/.agents/skills/secrets/SKILL.md +14 -7
  275. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +14 -7
  276. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  277. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  278. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -7
  279. package/dist/vite/client.d.ts.map +1 -1
  280. package/dist/vite/client.js +1 -0
  281. package/dist/vite/client.js.map +1 -1
  282. package/docs/content/agent-native-toolkit.mdx +13 -6
  283. package/docs/content/cloneable-saas.mdx +5 -5
  284. package/docs/content/creating-templates.mdx +9 -0
  285. package/docs/content/deployment.mdx +14 -10
  286. package/docs/content/docs-components.mdx +491 -0
  287. package/docs/content/doctor.mdx +8 -1
  288. package/docs/content/drop-in-agent.mdx +1 -1
  289. package/docs/content/extensions.mdx +18 -18
  290. package/docs/content/faq.mdx +4 -4
  291. package/docs/content/key-concepts.mdx +30 -21
  292. package/docs/content/template-brain-developers.mdx +4 -1
  293. package/docs/content/template-mail-developers.mdx +4 -1
  294. package/docs/content/what-is-agent-native.mdx +6 -6
  295. package/package.json +2 -2
  296. package/src/a2a/client.ts +449 -66
  297. package/src/a2a/correlation.ts +31 -0
  298. package/src/a2a/types.ts +4 -0
  299. package/src/action.ts +3 -0
  300. package/src/agent/engine/registry.ts +45 -5
  301. package/src/agent/production-agent.ts +151 -18
  302. package/src/agent/run-loop-with-resume.ts +190 -3
  303. package/src/agent/run-manager.ts +117 -41
  304. package/src/agent/thread-debug-history.ts +86 -0
  305. package/src/agent/types.ts +3 -1
  306. package/src/cli/create.ts +11 -1
  307. package/src/cli/templates-meta.ts +2 -2
  308. package/src/client/agent-chat-adapter.ts +91 -13
  309. package/src/client/resources/McpIntegrationDialog.tsx +11 -9
  310. package/src/client/sse-event-processor.ts +17 -3
  311. package/src/db/client.ts +57 -17
  312. package/src/integrations/adapters/slack.ts +8 -3
  313. package/src/localization/default-messages.ts +44 -0
  314. package/src/observability/traces.ts +78 -5
  315. package/src/scripts/call-agent.ts +290 -9
  316. package/src/scripts/describe-workspace-apps.ts +2 -2
  317. package/src/secrets/crypto.ts +126 -34
  318. package/src/secrets/storage.ts +61 -25
  319. package/src/server/agent-capabilities.ts +1 -1
  320. package/src/server/agent-chat/action-filters-a2a.ts +111 -7
  321. package/src/server/agent-chat/context-tools.ts +2 -0
  322. package/src/server/agent-chat/plugin-options.ts +34 -1
  323. package/src/server/agent-chat/prompt-resources.ts +1 -1
  324. package/src/server/agent-chat-plugin.ts +91 -59
  325. package/src/templates/default/.agents/skills/secrets/SKILL.md +14 -7
  326. package/src/templates/headless/.agents/skills/secrets/SKILL.md +14 -7
  327. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  328. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  329. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -7
  330. package/src/vite/client.ts +1 -0
@@ -1,18 +1,11 @@
1
1
  import { defineAction } from "@agent-native/core";
2
- import { writeAppState } from "@agent-native/core/application-state";
3
- import { and, desc, eq, inArray } from "drizzle-orm";
4
2
  import { z } from "zod";
5
3
 
6
- import { getDb, schema } from "../server/db/index.js";
7
4
  import {
8
5
  getAccessibleCapture,
9
- nanoid,
10
- nowIso,
11
- parseJson,
12
6
  readBrainAgentGuidance,
13
- serializeDistillationQueue,
14
- stableJson,
15
7
  } from "../server/lib/brain.js";
8
+ import { enqueueCaptureDistillation } from "../server/lib/distillation-queue.js";
16
9
  import { redactSensitiveText } from "../server/lib/search.js";
17
10
  import { optionalJsonRecordSchema, stringArrayCliSchema } from "./_schemas.js";
18
11
 
@@ -20,33 +13,6 @@ type BrainAgentGuidance = Awaited<
20
13
  ReturnType<typeof readBrainAgentGuidance>
21
14
  >["guidance"];
22
15
 
23
- async function writeDistillationRequest(values: {
24
- captureId: string;
25
- queueId: string;
26
- sourceId: string;
27
- requestedAt: string;
28
- instructions?: string | null;
29
- guidance: BrainAgentGuidance;
30
- }) {
31
- await writeAppState(`brain-distill-request-${values.captureId}`, {
32
- kind: "distill-capture",
33
- captureId: values.captureId,
34
- queueId: values.queueId,
35
- sourceId: values.sourceId,
36
- requestedAt: values.requestedAt,
37
- instructions: values.instructions ?? null,
38
- guidance: values.guidance,
39
- message:
40
- `Distill Brain capture ${values.captureId} for ${values.guidance.identity.companyName ?? "this workspace"}. ` +
41
- `Apply the Brain settings guidance in context. Use get-capture with ` +
42
- `includeRawContent=true when you need exact quote validation, extract ` +
43
- `only durable company knowledge with exact evidence quotes, ` +
44
- `call write-knowledge for supported entries or proposals, then call ` +
45
- `mark-capture-distilled when finished. If the capture is personal or ` +
46
- `out of scope, call mark-capture-distilled with status ignored.`,
47
- });
48
- }
49
-
50
16
  function errorMessage(error: unknown) {
51
17
  const message = error instanceof Error ? error.message : String(error);
52
18
  return redactSensitiveText(message);
@@ -84,101 +50,20 @@ async function enqueueOneCapture(values: {
84
50
  };
85
51
  }
86
52
 
87
- const db = getDb();
88
- const now = nowIso();
89
- const [existing] = await db
90
- .select()
91
- .from(schema.brainIngestQueue)
92
- .where(
93
- and(
94
- eq(schema.brainIngestQueue.captureId, values.captureId),
95
- eq(schema.brainIngestQueue.operation, "distill"),
96
- inArray(schema.brainIngestQueue.status, ["queued", "processing"]),
97
- ),
98
- )
99
- .orderBy(desc(schema.brainIngestQueue.updatedAt))
100
- .limit(1);
101
-
102
- if (existing) {
103
- if (access.capture.status !== "distilling") {
104
- await db
105
- .update(schema.brainRawCaptures)
106
- .set({ status: "distilling", updatedAt: now })
107
- .where(eq(schema.brainRawCaptures.id, values.captureId));
108
- }
109
- const payload = parseJson<Record<string, unknown>>(
110
- existing.payloadJson,
111
- {},
112
- );
113
- const existingInstructions =
114
- typeof payload.instructions === "string"
115
- ? payload.instructions
116
- : undefined;
117
- await writeDistillationRequest({
118
- captureId: values.captureId,
119
- queueId: existing.id,
120
- sourceId: access.capture.sourceId,
121
- requestedAt: now,
122
- instructions: values.instructions ?? existingInstructions,
123
- guidance: values.guidance,
124
- });
125
- return {
126
- captureId: values.captureId,
127
- sourceId: access.capture.sourceId,
128
- outcome: "existing" as const,
129
- existing: true,
130
- queueItem: serializeDistillationQueue(existing),
131
- };
132
- }
133
-
134
- const id = nanoid();
135
- await db.insert(schema.brainIngestQueue).values({
136
- id,
137
- sourceId: access.capture.sourceId,
138
- captureId: access.capture.id,
139
- operation: "distill",
140
- status: "queued",
53
+ const result = await enqueueCaptureDistillation({
54
+ capture: access.capture,
141
55
  priority: values.priority,
142
- attempts: 0,
143
- payloadJson: stableJson({
144
- ...(values.payload ?? {}),
145
- instructions: values.instructions,
146
- }),
147
- error: null,
148
- runAfter: null,
149
- createdAt: now,
150
- updatedAt: now,
151
- });
152
- await db
153
- .update(schema.brainRawCaptures)
154
- .set({ status: "distilling", updatedAt: now })
155
- .where(eq(schema.brainRawCaptures.id, values.captureId));
156
- await writeDistillationRequest({
157
- captureId: values.captureId,
158
- queueId: id,
159
- sourceId: access.capture.sourceId,
160
- requestedAt: now,
161
- instructions: values.instructions ?? null,
56
+ instructions: values.instructions,
57
+ payload: values.payload,
162
58
  guidance: values.guidance,
163
59
  });
164
60
 
165
61
  return {
166
62
  captureId: values.captureId,
167
63
  sourceId: access.capture.sourceId,
168
- outcome: "queued" as const,
169
- existing: false,
170
- queueItem: {
171
- id,
172
- sourceId: access.capture.sourceId,
173
- captureId: values.captureId,
174
- status: "queued" as const,
175
- priority: values.priority,
176
- attempts: 0,
177
- error: null,
178
- runAfter: null,
179
- createdAt: now,
180
- updatedAt: now,
181
- },
64
+ outcome: result.existing ? ("existing" as const) : ("queued" as const),
65
+ existing: result.existing,
66
+ queueItem: result.queueItem,
182
67
  };
183
68
  } catch (error) {
184
69
  return {
@@ -1,47 +1,10 @@
1
1
  import { defineAction } from "@agent-native/core";
2
- import { writeAppState } from "@agent-native/core/application-state";
3
- import { and, desc, eq, inArray } from "drizzle-orm";
4
2
  import { z } from "zod";
5
3
 
6
- import { getDb, schema } from "../server/db/index.js";
7
- import {
8
- getAccessibleCapture,
9
- nanoid,
10
- nowIso,
11
- parseJson,
12
- readBrainAgentGuidance,
13
- serializeDistillationQueue,
14
- stableJson,
15
- } from "../server/lib/brain.js";
4
+ import { getAccessibleCapture } from "../server/lib/brain.js";
5
+ import { enqueueCaptureDistillation } from "../server/lib/distillation-queue.js";
16
6
  import { optionalJsonRecordSchema } from "./_schemas.js";
17
7
 
18
- async function writeDistillationRequest(values: {
19
- captureId: string;
20
- queueId: string;
21
- sourceId: string;
22
- requestedAt: string;
23
- instructions?: string | null;
24
- guidance: Awaited<ReturnType<typeof readBrainAgentGuidance>>["guidance"];
25
- }) {
26
- await writeAppState(`brain-distill-request-${values.captureId}`, {
27
- kind: "distill-capture",
28
- captureId: values.captureId,
29
- queueId: values.queueId,
30
- sourceId: values.sourceId,
31
- requestedAt: values.requestedAt,
32
- instructions: values.instructions ?? null,
33
- guidance: values.guidance,
34
- message:
35
- `Distill Brain capture ${values.captureId} for ${values.guidance.identity.companyName ?? "this workspace"}. ` +
36
- `Apply the Brain settings guidance in context. Use get-capture with ` +
37
- `includeRawContent=true when you need exact quote validation, extract ` +
38
- `only durable company knowledge with exact evidence quotes, ` +
39
- `call write-knowledge for supported entries or proposals, then call ` +
40
- `mark-capture-distilled when finished. If the capture is personal or ` +
41
- `out of scope, call mark-capture-distilled with status ignored.`,
42
- });
43
- }
44
-
45
8
  export default defineAction({
46
9
  description:
47
10
  "Queue a raw capture for distillation into durable Brain knowledge.",
@@ -52,7 +15,6 @@ export default defineAction({
52
15
  payload: optionalJsonRecordSchema,
53
16
  }),
54
17
  run: async (args) => {
55
- const { guidance } = await readBrainAgentGuidance();
56
18
  const access = await getAccessibleCapture(args.captureId);
57
19
  if (!access) throw new Error(`No access to capture ${args.captureId}`);
58
20
  if (
@@ -63,94 +25,11 @@ export default defineAction({
63
25
  `Capture ${args.captureId} is already ${access.capture.status}`,
64
26
  );
65
27
  }
66
- const db = getDb();
67
- const now = nowIso();
68
- const [existing] = await db
69
- .select()
70
- .from(schema.brainIngestQueue)
71
- .where(
72
- and(
73
- eq(schema.brainIngestQueue.captureId, args.captureId),
74
- eq(schema.brainIngestQueue.operation, "distill"),
75
- inArray(schema.brainIngestQueue.status, ["queued", "processing"]),
76
- ),
77
- )
78
- .orderBy(desc(schema.brainIngestQueue.updatedAt))
79
- .limit(1);
80
- if (existing) {
81
- if (access.capture.status !== "distilling") {
82
- await db
83
- .update(schema.brainRawCaptures)
84
- .set({ status: "distilling", updatedAt: now })
85
- .where(eq(schema.brainRawCaptures.id, args.captureId));
86
- }
87
- const payload = parseJson<Record<string, unknown>>(
88
- existing.payloadJson,
89
- {},
90
- );
91
- const existingInstructions =
92
- typeof payload.instructions === "string"
93
- ? payload.instructions
94
- : undefined;
95
- await writeDistillationRequest({
96
- captureId: args.captureId,
97
- queueId: existing.id,
98
- sourceId: access.capture.sourceId,
99
- requestedAt: now,
100
- instructions: args.instructions ?? existingInstructions,
101
- guidance,
102
- });
103
- return {
104
- queueItem: serializeDistillationQueue(existing),
105
- existing: true,
106
- guidance: guidance.distillation,
107
- };
108
- }
109
- const id = nanoid();
110
- await db.insert(schema.brainIngestQueue).values({
111
- id,
112
- sourceId: access.capture.sourceId,
113
- captureId: access.capture.id,
114
- operation: "distill",
115
- status: "queued",
28
+ return enqueueCaptureDistillation({
29
+ capture: access.capture,
116
30
  priority: args.priority,
117
- attempts: 0,
118
- payloadJson: stableJson({
119
- ...(args.payload ?? {}),
120
- instructions: args.instructions,
121
- }),
122
- error: null,
123
- runAfter: null,
124
- createdAt: now,
125
- updatedAt: now,
126
- });
127
- await db
128
- .update(schema.brainRawCaptures)
129
- .set({ status: "distilling", updatedAt: now })
130
- .where(eq(schema.brainRawCaptures.id, args.captureId));
131
- await writeDistillationRequest({
132
- captureId: args.captureId,
133
- queueId: id,
134
- sourceId: access.capture.sourceId,
135
- requestedAt: now,
136
- instructions: args.instructions ?? null,
137
- guidance,
31
+ instructions: args.instructions,
32
+ payload: args.payload,
138
33
  });
139
- return {
140
- queueItem: {
141
- id,
142
- sourceId: access.capture.sourceId,
143
- captureId: args.captureId,
144
- status: "queued",
145
- priority: args.priority,
146
- attempts: 0,
147
- error: null,
148
- runAfter: null,
149
- createdAt: now,
150
- updatedAt: now,
151
- },
152
- existing: false,
153
- guidance: guidance.distillation,
154
- };
155
34
  },
156
35
  });
@@ -8,6 +8,7 @@ import {
8
8
  serializeCapture,
9
9
  serializeSource,
10
10
  } from "../server/lib/brain.js";
11
+ import { enqueueCaptureDistillation } from "../server/lib/distillation-queue.js";
11
12
  import { captureKindSchema, optionalJsonRecordSchema } from "./_schemas.js";
12
13
 
13
14
  export default defineAction({
@@ -49,15 +50,26 @@ export default defineAction({
49
50
  source: source ? serializeSource(source) : undefined,
50
51
  capture: undefined,
51
52
  sensitivityReceipt: error.receipt,
52
- nextAction: undefined,
53
+ distillation: undefined,
53
54
  };
54
55
  }
56
+ const distillation =
57
+ args.enqueueDistillation &&
58
+ capture.status !== "distilled" &&
59
+ capture.status !== "ignored"
60
+ ? await enqueueCaptureDistillation({ capture })
61
+ : undefined;
62
+ const serializedCapture = serializeCapture(capture);
55
63
  return {
56
64
  source: source ? serializeSource(source) : undefined,
57
- capture: serializeCapture(capture),
58
- nextAction: args.enqueueDistillation
59
- ? "Call enqueue-distillation with this captureId."
60
- : undefined,
65
+ capture: distillation
66
+ ? {
67
+ ...serializedCapture,
68
+ status: "distilling",
69
+ updatedAt: distillation.queueItem.updatedAt,
70
+ }
71
+ : serializedCapture,
72
+ distillation,
61
73
  };
62
74
  },
63
75
  });
@@ -9,6 +9,7 @@ import {
9
9
  serializeCapture,
10
10
  serializeSource,
11
11
  } from "../server/lib/brain.js";
12
+ import { enqueueCaptureDistillation } from "../server/lib/distillation-queue.js";
12
13
  import { optionalJsonRecordSchema } from "./_schemas.js";
13
14
 
14
15
  export default defineAction({
@@ -68,15 +69,26 @@ export default defineAction({
68
69
  source: source ? serializeSource(source) : undefined,
69
70
  capture: undefined,
70
71
  sensitivityReceipt: error.receipt,
71
- nextAction: undefined,
72
+ distillation: undefined,
72
73
  };
73
74
  }
75
+ const distillation =
76
+ args.enqueueDistillation &&
77
+ capture.status !== "distilled" &&
78
+ capture.status !== "ignored"
79
+ ? await enqueueCaptureDistillation({ capture })
80
+ : undefined;
81
+ const serializedCapture = serializeCapture(capture);
74
82
  return {
75
83
  source: source ? serializeSource(source) : undefined,
76
- capture: serializeCapture(capture),
77
- nextAction: args.enqueueDistillation
78
- ? "Call enqueue-distillation with this captureId."
79
- : undefined,
84
+ capture: distillation
85
+ ? {
86
+ ...serializedCapture,
87
+ status: "distilling",
88
+ updatedAt: distillation.queueItem.updatedAt,
89
+ }
90
+ : serializedCapture,
91
+ distillation,
80
92
  };
81
93
  },
82
94
  });
@@ -11,17 +11,27 @@ import {
11
11
  stableJson,
12
12
  } from "../server/lib/brain.js";
13
13
  import { assertSourceWorkspaceConnectionAvailable } from "../server/lib/source-credentials.js";
14
+ import { withSourceAnswerPolicy } from "../server/lib/source-policy.js";
14
15
  import { normalizeSlackChannelConfig } from "../shared/slack-source-config.js";
15
- import { optionalJsonRecordSchema } from "./_schemas.js";
16
+ import {
17
+ optionalJsonRecordSchema,
18
+ sourceAnswerPolicySchema,
19
+ } from "./_schemas.js";
16
20
 
17
21
  export default defineAction({
18
- description: "Update a Brain source's title, status, config, or cursor.",
22
+ description:
23
+ "Update a Brain source's title, status, config, cursor, or trusted-answer policy.",
19
24
  schema: z.object({
20
25
  id: z.string().min(1),
21
26
  title: z.string().min(1).optional(),
22
27
  status: z.enum(["active", "paused", "archived", "error"]).optional(),
23
28
  config: optionalJsonRecordSchema,
24
29
  cursor: optionalJsonRecordSchema,
30
+ policy: sourceAnswerPolicySchema
31
+ .optional()
32
+ .describe(
33
+ "Merge trust, answer eligibility, authority, freshness, review, or conflict behavior into the source answer policy",
34
+ ),
25
35
  }),
26
36
  run: async (args) => {
27
37
  const access = await assertAccess("brain-source", args.id, "editor");
@@ -29,13 +39,23 @@ export default defineAction({
29
39
  const updates: Record<string, unknown> = { updatedAt: nowIso() };
30
40
  if (args.title !== undefined) updates.title = args.title;
31
41
  if (args.status !== undefined) updates.status = args.status;
32
- if (args.config !== undefined) {
42
+ if (args.config !== undefined || args.policy !== undefined) {
33
43
  let nextConfig: Record<string, unknown> = {
34
44
  ...parseJson<Record<string, unknown>>(existing.configJson, {}),
35
- ...args.config,
45
+ ...(args.config ?? {}),
36
46
  };
47
+ if (
48
+ args.policy !== undefined ||
49
+ (args.config &&
50
+ Object.prototype.hasOwnProperty.call(args.config, "answerPolicy"))
51
+ ) {
52
+ nextConfig = withSourceAnswerPolicy(
53
+ nextConfig,
54
+ args.policy ?? nextConfig.answerPolicy,
55
+ );
56
+ }
37
57
  if (existing.provider === "slack") {
38
- nextConfig = normalizeSlackChannelConfig(nextConfig, args.config);
58
+ nextConfig = normalizeSlackChannelConfig(nextConfig, args.config ?? {});
39
59
  }
40
60
  const workspaceConnectionId =
41
61
  typeof nextConfig.workspaceConnectionId === "string"
@@ -432,7 +432,7 @@ export function Sidebar({
432
432
  <div className="mt-auto shrink-0">
433
433
  {!collapsed ? (
434
434
  <div className="px-3 py-2">
435
- <OrgSwitcher reserveSpace />
435
+ <OrgSwitcher />
436
436
  </div>
437
437
  ) : null}
438
438
 
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Blessed FAQs, docs, and other resources can publish updates to Brain for automatic distillation and cited, policy-aware answers.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ The left sidebar no longer shows a blank organization placeholder in its footer.
@@ -693,6 +693,12 @@ async function findUpstreamDeletionReceipt(
693
693
  : null;
694
694
  }
695
695
 
696
+ function captureMetadataFingerprint(metadata: Record<string, unknown>) {
697
+ const comparable = { ...metadata };
698
+ delete comparable.captureSanitization;
699
+ return stableJson(comparable);
700
+ }
701
+
696
702
  export async function createCapture(values: {
697
703
  id?: string;
698
704
  sourceId: string;
@@ -773,13 +779,31 @@ export async function createCapture(values: {
773
779
  throw new BrainCaptureBlockedError(receipt);
774
780
  }
775
781
  const nextContentHash = await contentHash(sanitized.content);
782
+ const nextMetadataJson = stableJson(sanitized.metadata);
776
783
  const nextCapturedAt = values.capturedAt ?? existing?.capturedAt ?? now;
777
784
  const contentChanged = existing?.contentHash !== nextContentHash;
785
+ const metadataChanged = Boolean(
786
+ existing &&
787
+ captureMetadataFingerprint(
788
+ parseJson<Record<string, unknown>>(existing.metadataJson, {}),
789
+ ) !== captureMetadataFingerprint(sanitized.metadata),
790
+ );
778
791
  const indexedMetadataChanged = Boolean(
779
792
  existing &&
780
793
  (existing.title !== sanitized.title ||
781
794
  existing.capturedAt !== nextCapturedAt),
782
795
  );
796
+ const derivedInputChanged =
797
+ !existing || contentChanged || metadataChanged || indexedMetadataChanged;
798
+ const nextStatus =
799
+ values.status ??
800
+ (derivedInputChanged ? "queued" : (existing?.status ?? "queued"));
801
+ const nextDistilledAt =
802
+ values.status === "distilled"
803
+ ? now
804
+ : values.status !== undefined || derivedInputChanged
805
+ ? null
806
+ : (existing?.distilledAt ?? null);
783
807
  const captureId = existing?.id ?? id;
784
808
  try {
785
809
  if (!existing) {
@@ -791,11 +815,11 @@ export async function createCapture(values: {
791
815
  kind: values.kind,
792
816
  content: sanitized.content,
793
817
  contentHash: nextContentHash,
794
- metadataJson: stableJson(sanitized.metadata),
818
+ metadataJson: nextMetadataJson,
795
819
  capturedAt: nextCapturedAt,
796
820
  importedBy: requireUserEmail(),
797
- status: values.status ?? "queued",
798
- distilledAt: values.status === "distilled" ? now : null,
821
+ status: nextStatus,
822
+ distilledAt: nextDistilledAt,
799
823
  sensitivityDisposition: "pending",
800
824
  sensitivityPolicyVersion: sanitized.decision.policyVersion,
801
825
  audienceAclHash: null,
@@ -875,10 +899,10 @@ export async function createCapture(values: {
875
899
  kind: values.kind,
876
900
  content: sanitized.content,
877
901
  contentHash: nextContentHash,
878
- metadataJson: stableJson(sanitized.metadata),
902
+ metadataJson: nextMetadataJson,
879
903
  capturedAt: nextCapturedAt,
880
- status: values.status ?? "queued",
881
- distilledAt: values.status === "distilled" ? now : null,
904
+ status: nextStatus,
905
+ distilledAt: nextDistilledAt,
882
906
  sensitivityDisposition: "allowed",
883
907
  sensitivityPolicyVersion: sanitized.decision.policyVersion,
884
908
  audienceAclHash: audience.aclHash,
@@ -901,7 +925,7 @@ export async function createCapture(values: {
901
925
  if (receipt) throw new BrainCaptureBlockedError(receipt);
902
926
  throw new Error("Capture finalization was blocked");
903
927
  }
904
- if (existing?.contentHash && contentChanged) {
928
+ if (existing?.contentHash && derivedInputChanged) {
905
929
  await invalidateDerivedForCapture(captureId);
906
930
  }
907
931
  const [capture] = await db
@@ -909,14 +933,13 @@ export async function createCapture(values: {
909
933
  .from(schema.brainRawCaptures)
910
934
  .where(eq(schema.brainRawCaptures.id, captureId))
911
935
  .limit(1);
912
- const invalidationReason =
913
- !existing || contentChanged || indexedMetadataChanged
914
- ? "content-changed"
915
- : existing.audienceAclHash !== audience.aclHash
916
- ? "access-changed"
917
- : existing.sensitivityPolicyVersion !== sanitized.decision.policyVersion
918
- ? "sensitivity-changed"
919
- : null;
936
+ const invalidationReason = derivedInputChanged
937
+ ? "content-changed"
938
+ : existing.audienceAclHash !== audience.aclHash
939
+ ? "access-changed"
940
+ : existing.sensitivityPolicyVersion !== sanitized.decision.policyVersion
941
+ ? "sensitivity-changed"
942
+ : null;
920
943
  if (!invalidationReason) return capture;
921
944
  try {
922
945
  await enqueueCaptureInvalidation({
@@ -1495,10 +1518,17 @@ async function evidenceSourceReviewPolicy(
1495
1518
  ),
1496
1519
  );
1497
1520
  if (sources.length !== sourceIds.length) return "required";
1498
- const values = sources.map(
1499
- (source) =>
1500
- parseJson<Record<string, unknown>>(source.configJson, {}).reviewRequired,
1501
- );
1521
+ const values = sources.map((source) => {
1522
+ const config = parseJson<Record<string, unknown>>(source.configJson, {});
1523
+ const answerPolicy =
1524
+ config.answerPolicy &&
1525
+ typeof config.answerPolicy === "object" &&
1526
+ !Array.isArray(config.answerPolicy)
1527
+ ? (config.answerPolicy as Record<string, unknown>)
1528
+ : null;
1529
+ if (answerPolicy?.conflictBehavior === "require-review") return true;
1530
+ return answerPolicy?.reviewRequired ?? config.reviewRequired;
1531
+ });
1502
1532
  if (values.includes(true)) return "required";
1503
1533
  return values.every((value) => value === false) ? "disabled" : "legacy";
1504
1534
  }