@vellumai/assistant 0.8.12 → 0.9.0-staging.2

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 (442) hide show
  1. package/AGENTS.md +0 -14
  2. package/ARCHITECTURE.md +45 -45
  3. package/README.md +1 -1
  4. package/bun.lock +200 -154
  5. package/docs/architecture/integrations.md +3 -3
  6. package/docs/architecture/memory.md +2 -2
  7. package/docs/architecture/security.md +10 -10
  8. package/docs/runbook-trusted-contacts.md +12 -12
  9. package/docs/skills.md +6 -6
  10. package/docs/workflows-testing.md +221 -0
  11. package/docs/workflows.md +510 -0
  12. package/examples/plugins/echo/README.md +5 -5
  13. package/knip.json +2 -0
  14. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +105 -0
  15. package/node_modules/@vellumai/gateway-client/src/index.ts +12 -0
  16. package/openapi.yaml +7197 -5708
  17. package/package.json +8 -4
  18. package/scripts/generate-openapi.ts +66 -114
  19. package/src/__tests__/access-request-seed-content-blocks.test.ts +213 -0
  20. package/src/__tests__/adaptive-thinking-repair.test.ts +32 -3
  21. package/src/__tests__/agent-loop-output-hooks.test.ts +183 -0
  22. package/src/__tests__/agent-loop-regrowth-guard.test.ts +506 -0
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  24. package/src/__tests__/agent-wake-override-profile.test.ts +77 -0
  25. package/src/__tests__/app-compiler.test.ts +7 -1
  26. package/src/__tests__/app-dir-path-guard.test.ts +27 -3
  27. package/src/__tests__/app-executors.test.ts +43 -0
  28. package/src/__tests__/approval-cascade.test.ts +0 -5
  29. package/src/__tests__/approval-routes-http.test.ts +91 -0
  30. package/src/__tests__/assistant-stream-state.test.ts +107 -0
  31. package/src/__tests__/browser-fill-credential.test.ts +3 -3
  32. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -1
  33. package/src/__tests__/compaction-events.test.ts +63 -7
  34. package/src/__tests__/compaction-trail-store.test.ts +74 -1
  35. package/src/__tests__/compaction.benchmark.test.ts +63 -41
  36. package/src/__tests__/compactor-low-watermark-cut.test.ts +349 -0
  37. package/src/__tests__/context-window-manager-compact-retry.test.ts +64 -0
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -5
  39. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -5
  40. package/src/__tests__/conversation-history-web-search.test.ts +7 -0
  41. package/src/__tests__/conversation-process-callsite.test.ts +0 -5
  42. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -5
  43. package/src/__tests__/conversation-queue.test.ts +0 -5
  44. package/src/__tests__/conversation-slash-queue.test.ts +0 -5
  45. package/src/__tests__/conversation-slash-unknown.test.ts +0 -5
  46. package/src/__tests__/conversation-speed-override.test.ts +0 -5
  47. package/src/__tests__/conversation-surfaces-data-persist.test.ts +97 -0
  48. package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
  49. package/src/__tests__/conversation-usage.test.ts +2 -0
  50. package/src/__tests__/conversation-workspace-injection.test.ts +0 -5
  51. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -5
  52. package/src/__tests__/credential-broker-browser-fill.test.ts +2 -2
  53. package/src/__tests__/credential-broker-server-use.test.ts +2 -2
  54. package/src/__tests__/credential-broker.test.ts +1 -1
  55. package/src/__tests__/credential-prompt-route.test.ts +417 -0
  56. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  57. package/src/__tests__/credential-vault.test.ts +37 -0
  58. package/src/__tests__/db-schedule-syntax-migration.test.ts +24 -0
  59. package/src/__tests__/dynamic-page-surface.test.ts +219 -0
  60. package/src/__tests__/empty-state-greeting-cache.test.ts +94 -0
  61. package/src/__tests__/gateway-flag-listener.test.ts +24 -7
  62. package/src/__tests__/guardian-action-sweep.test.ts +56 -219
  63. package/src/__tests__/guardian-routing-invariants.test.ts +138 -0
  64. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  65. package/src/__tests__/list-messages-hidden-metadata.test.ts +99 -0
  66. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +87 -1
  67. package/src/__tests__/llm-resolver.test.ts +115 -0
  68. package/src/__tests__/managed-profile-guard.test.ts +6 -5
  69. package/src/__tests__/max-tokens-continue-hook.test.ts +184 -0
  70. package/src/__tests__/media-generate-image.test.ts +20 -9
  71. package/src/__tests__/mock-gateway-ipc.ts +23 -0
  72. package/src/__tests__/model-intents.test.ts +1 -1
  73. package/src/__tests__/normalize-onboarding.test.ts +26 -0
  74. package/src/__tests__/notification-decision-strategy.test.ts +4 -2
  75. package/src/__tests__/notification-telegram-adapter.test.ts +21 -3
  76. package/src/__tests__/pending-interactions-resolved-event.test.ts +62 -0
  77. package/src/__tests__/post-turn-tool-result-truncation.test.ts +72 -18
  78. package/src/__tests__/require-fresh-approval.test.ts +425 -1
  79. package/src/__tests__/resolve-app-id.test.ts +56 -0
  80. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -0
  81. package/src/__tests__/schedule-routes-workflow-validation.test.ts +408 -0
  82. package/src/__tests__/schedule-routes.test.ts +257 -4
  83. package/src/__tests__/schedule-store.test.ts +60 -0
  84. package/src/__tests__/schedule-tools.test.ts +247 -2
  85. package/src/__tests__/skill-execute-input.test.ts +85 -0
  86. package/src/__tests__/skill-secret-handling-guard.test.ts +21 -20
  87. package/src/__tests__/skills.test.ts +3 -3
  88. package/src/__tests__/slack-app-setup-skill-regression.test.ts +1 -1
  89. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  90. package/src/__tests__/subagent-tool-gate-mode.test.ts +547 -0
  91. package/src/__tests__/system-prompt.test.ts +1 -1
  92. package/src/__tests__/task-progress-nudge-hook.test.ts +372 -0
  93. package/src/__tests__/task-scheduler.test.ts +299 -0
  94. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +209 -0
  95. package/src/__tests__/tool-result-spool.test.ts +3 -1
  96. package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +181 -0
  97. package/src/__tests__/workspace-migration-103-upgrade-quality-profile-to-opus-4-8.test.ts +174 -0
  98. package/src/agent/compaction-circuit.ts +11 -0
  99. package/src/agent/loop.ts +181 -12
  100. package/src/api/constants/call-sites.ts +12 -0
  101. package/src/api/events/assistant-thinking-delta.ts +10 -0
  102. package/src/api/events/usage-update.ts +7 -0
  103. package/src/api/index.ts +4 -1
  104. package/src/api/responses/memory-v3-selection-log.ts +18 -11
  105. package/src/approvals/approval-primitive.ts +2 -2
  106. package/src/background-wake/background-wake-routes.test.ts +5 -2
  107. package/src/bundler/compiler-tools.ts +1 -1
  108. package/src/bundler/package-resolver.ts +0 -1
  109. package/src/calls/call-domain.ts +1 -1
  110. package/src/calls/guardian-action-sweep.ts +16 -93
  111. package/src/cli/AGENTS.md +4 -0
  112. package/src/cli/commands/__tests__/schedules.test.ts +430 -1
  113. package/src/cli/commands/credentials.ts +28 -24
  114. package/src/cli/commands/image-generation.ts +23 -9
  115. package/src/cli/commands/notifications.ts +1 -1
  116. package/src/cli/commands/plugins.ts +89 -46
  117. package/src/cli/commands/schedules.ts +384 -11
  118. package/src/cli/lib/__tests__/inspect-plugin.test.ts +69 -5
  119. package/src/cli/lib/__tests__/install-from-github.test.ts +15 -0
  120. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +81 -4
  121. package/src/cli/lib/inspect-plugin.ts +62 -1
  122. package/src/cli/lib/install-from-github.ts +52 -5
  123. package/src/cli/lib/upgrade-plugin.ts +18 -0
  124. package/src/config/__tests__/workflows-schema.test.ts +60 -0
  125. package/src/config/bundled-skills/acp/SKILL.md +2 -2
  126. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  127. package/src/config/bundled-skills/app-builder/tools/app-create.ts +6 -1
  128. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +7 -1
  129. package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +7 -1
  130. package/src/config/bundled-skills/app-builder/tools/app-update.ts +10 -1
  131. package/src/config/bundled-skills/image-studio/SKILL.md +66 -19
  132. package/src/config/bundled-skills/image-studio/TOOLS.json +1 -6
  133. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +22 -3
  134. package/src/config/bundled-skills/personal-page/SKILL.md +57 -0
  135. package/src/config/bundled-skills/personal-page/TOOLS.json +27 -0
  136. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +17 -0
  137. package/src/config/bundled-skills/schedule/SKILL.md +7 -2
  138. package/src/config/bundled-skills/schedule/TOOLS.json +48 -4
  139. package/src/config/bundled-skills/workflows/SKILL.md +214 -0
  140. package/src/config/bundled-skills/workflows/TOOLS.json +84 -0
  141. package/src/config/bundled-skills/workflows/tools/manage-workflows.ts +12 -0
  142. package/src/config/bundled-skills/workflows/tools/run-workflow.ts +12 -0
  143. package/src/config/bundled-tool-registry.ts +14 -2
  144. package/src/config/call-site-defaults.ts +5 -0
  145. package/src/config/feature-flag-registry.json +12 -4
  146. package/src/config/llm-context-resolution.ts +8 -0
  147. package/src/config/llm-resolver.ts +30 -0
  148. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +22 -0
  149. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +16 -0
  150. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +77 -0
  151. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +57 -0
  152. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +28 -0
  153. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +234 -0
  154. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +48 -0
  155. package/src/config/preloaded-apps/personal-page/src/components/media.ts +16 -0
  156. package/src/config/preloaded-apps/personal-page/src/index.html +20 -0
  157. package/src/config/preloaded-apps/personal-page/src/main.tsx +7 -0
  158. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +82 -0
  159. package/src/config/preloaded-apps/personal-page/src/styles.css +759 -0
  160. package/src/config/schema.ts +2 -0
  161. package/src/config/schemas/call-site-catalog.ts +7 -0
  162. package/src/config/schemas/heartbeat.ts +4 -1
  163. package/src/config/schemas/llm.ts +33 -26
  164. package/src/config/schemas/memory-retrospective.ts +19 -0
  165. package/src/config/schemas/platform.ts +8 -0
  166. package/src/config/schemas/services.ts +5 -2
  167. package/src/config/schemas/workflows.ts +42 -0
  168. package/src/config/skills.ts +3 -3
  169. package/src/context/compactor.ts +273 -39
  170. package/src/context/post-turn-tool-result-truncation.ts +23 -6
  171. package/src/context/tool-result-spool.ts +12 -17
  172. package/src/credential-execution/executable-discovery.ts +1 -1
  173. package/src/credential-execution/process-manager.ts +37 -3
  174. package/src/credential-execution/prompted-credential.ts +205 -0
  175. package/src/daemon/conversation-agent-loop-handlers.ts +14 -0
  176. package/src/daemon/conversation-process.ts +11 -2
  177. package/src/daemon/conversation-surfaces.ts +167 -3
  178. package/src/daemon/conversation-tool-setup.ts +103 -26
  179. package/src/daemon/conversation-usage.ts +2 -0
  180. package/src/daemon/conversation.ts +115 -11
  181. package/src/daemon/handlers/shared.ts +26 -14
  182. package/src/daemon/host-cu-proxy.ts +15 -12
  183. package/src/daemon/host-file-proxy.ts +15 -12
  184. package/src/daemon/host-transfer-proxy.ts +30 -24
  185. package/src/daemon/lifecycle.ts +40 -3
  186. package/src/daemon/message-protocol.ts +3 -0
  187. package/src/daemon/message-types/messages.ts +2 -10
  188. package/src/daemon/message-types/workflows.ts +49 -0
  189. package/src/daemon/parse-actual-tokens-from-error.test.ts +62 -1
  190. package/src/daemon/parse-actual-tokens-from-error.ts +43 -4
  191. package/src/daemon/process-message.ts +6 -0
  192. package/src/daemon/tool-setup-types.ts +57 -0
  193. package/src/daemon/wake-conversation-ops.ts +18 -0
  194. package/src/heartbeat/heartbeat-run-store.ts +8 -2
  195. package/src/home/feed-types.ts +1 -1
  196. package/src/ipc/gateway-flag-listener.ts +28 -6
  197. package/src/mcp/mcp-auth-state.ts +8 -20
  198. package/src/media/__tests__/image-models.test.ts +57 -0
  199. package/src/media/image-models.ts +66 -0
  200. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +38 -0
  201. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +12 -2
  202. package/src/memory/__tests__/memory-retrospective-job.test.ts +911 -34
  203. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +227 -5
  204. package/src/memory/__tests__/memory-retrospective-state.test.ts +195 -0
  205. package/src/memory/__tests__/preloaded-apps.test.ts +85 -0
  206. package/src/memory/auto-analysis-enqueue.ts +14 -1
  207. package/src/memory/compaction-log-store-clickhouse.ts +6 -4
  208. package/src/memory/conversation-crud.ts +9 -2
  209. package/src/memory/conversation-disk-view.ts +1 -1
  210. package/src/memory/conversation-queries.ts +22 -7
  211. package/src/memory/db-init.ts +20 -0
  212. package/src/memory/db-maintenance.ts +16 -0
  213. package/src/memory/embedding-runtime-manager.ts +1 -1
  214. package/src/memory/llm-request-log-source-clickhouse.ts +112 -14
  215. package/src/memory/llm-request-log-source-local.ts +19 -1
  216. package/src/memory/llm-request-log-source.ts +35 -6
  217. package/src/memory/llm-request-log-store.ts +90 -2
  218. package/src/memory/memory-retrospective-constants.ts +9 -0
  219. package/src/memory/memory-retrospective-enqueue.ts +3 -6
  220. package/src/memory/memory-retrospective-fork-boundary.ts +94 -0
  221. package/src/memory/memory-retrospective-job.ts +500 -208
  222. package/src/memory/memory-retrospective-startup-cleanup.ts +97 -19
  223. package/src/memory/memory-retrospective-state.ts +85 -2
  224. package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +40 -0
  225. package/src/memory/migrations/282-schedule-inference-profile.test.ts +77 -0
  226. package/src/memory/migrations/282-schedule-inference-profile.ts +26 -0
  227. package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +102 -0
  228. package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.ts +53 -0
  229. package/src/memory/migrations/284-workflow-runs.ts +51 -0
  230. package/src/memory/migrations/285-schedule-workflow-mode.ts +26 -0
  231. package/src/memory/migrations/286-workflow-run-trust.ts +27 -0
  232. package/src/memory/migrations/287-conversation-origin-channel-index.ts +15 -0
  233. package/src/memory/migrations/288-backfill-origin-channel-from-bindings.ts +43 -0
  234. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +115 -0
  235. package/src/memory/migrations/290-schedule-capabilities.test.ts +77 -0
  236. package/src/memory/migrations/290-schedule-capabilities.ts +25 -0
  237. package/src/memory/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +96 -0
  238. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +571 -0
  239. package/src/memory/migrations/index.ts +10 -0
  240. package/src/memory/preloaded-apps.ts +116 -0
  241. package/src/memory/schema/infrastructure.ts +4 -0
  242. package/src/memory/schema/memory-core.ts +4 -0
  243. package/src/memory/v2/__tests__/concept-page-frontmatter-schema.test.ts +45 -0
  244. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +11 -7
  245. package/src/memory/v2/__tests__/page-store.test.ts +13 -2
  246. package/src/memory/v2/__tests__/qdrant.test.ts +24 -0
  247. package/src/memory/v2/frontmatter-sweep.ts +7 -6
  248. package/src/memory/v2/page-store.ts +4 -3
  249. package/src/memory/v2/qdrant.ts +42 -3
  250. package/src/memory/v2/types.ts +16 -10
  251. package/src/messaging/draft-store.ts +1 -1
  252. package/src/notifications/access-request-copy.ts +200 -113
  253. package/src/notifications/adapters/slack.ts +250 -111
  254. package/src/notifications/adapters/telegram.ts +7 -44
  255. package/src/notifications/approval-card-builder.ts +93 -0
  256. package/src/notifications/broadcaster.ts +74 -0
  257. package/src/notifications/conversation-pairing.ts +8 -6
  258. package/src/notifications/copy-composer.ts +32 -26
  259. package/src/notifications/decision-engine.ts +59 -7
  260. package/src/notifications/guardian-question-mode.ts +145 -155
  261. package/src/notifications/home-feed-side-effect.ts +28 -11
  262. package/src/notifications/notification-utils.ts +66 -0
  263. package/src/notifications/signal.ts +6 -0
  264. package/src/notifications/tool-approval-copy.ts +142 -0
  265. package/src/notifications/types.ts +19 -0
  266. package/src/permissions/threshold.ts +11 -0
  267. package/src/plugin-api/types.ts +16 -4
  268. package/src/plugins/defaults/compaction/window-manager.ts +44 -0
  269. package/src/plugins/defaults/index.ts +46 -0
  270. package/src/plugins/defaults/max-tokens-continue/continue-state-store.ts +53 -0
  271. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +80 -0
  272. package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +20 -0
  273. package/src/plugins/defaults/max-tokens-continue/package.json +14 -0
  274. package/src/plugins/defaults/memory-retrieval/hooks/__tests__/user-prompt-submit.test.ts +37 -0
  275. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +29 -1
  276. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +8 -3
  277. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +4 -2
  278. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +28 -18
  279. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +67 -0
  280. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +122 -22
  281. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +2 -0
  282. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +63 -1
  283. package/src/plugins/defaults/memory-v3-shadow/injector.ts +61 -18
  284. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +1 -1
  285. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +39 -10
  286. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +34 -1
  287. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +112 -47
  288. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +78 -15
  289. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +206 -0
  290. package/src/plugins/defaults/task-progress-nudge/package.json +15 -0
  291. package/src/prompts/__tests__/system-prompt.test.ts +100 -1
  292. package/src/prompts/__tests__/task-progress-hint-section.test.ts +5 -7
  293. package/src/prompts/normalize-onboarding.ts +2 -0
  294. package/src/prompts/persona-resolver.ts +3 -0
  295. package/src/prompts/system-prompt.ts +51 -2
  296. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +3 -1
  297. package/src/prompts/templates/system-sections.ts +8 -3
  298. package/src/providers/call-site-routing.ts +6 -3
  299. package/src/providers/fireworks/client.ts +3 -0
  300. package/src/providers/inference/auth.ts +52 -46
  301. package/src/providers/model-intents.ts +2 -2
  302. package/src/providers/openai/__tests__/coerce-object-args.test.ts +105 -0
  303. package/src/providers/openai/chat-completions-provider.ts +47 -9
  304. package/src/providers/openai/coerce-object-args.ts +104 -0
  305. package/src/providers/retry.ts +8 -5
  306. package/src/providers/types.ts +10 -0
  307. package/src/runtime/__tests__/agent-wake.test.ts +629 -7
  308. package/src/runtime/access-request-helper.ts +16 -9
  309. package/src/runtime/agent-wake.ts +302 -51
  310. package/src/runtime/assistant-stream-state.ts +141 -8
  311. package/src/runtime/background-job-runner.ts +9 -0
  312. package/src/runtime/channel-approval-types.ts +1 -0
  313. package/src/runtime/channel-invite-transports/telegram.ts +6 -5
  314. package/src/runtime/channel-invite-transports/voice.ts +2 -2
  315. package/src/runtime/channel-invite-types.ts +4 -2
  316. package/src/runtime/channel-retry-sweep.ts +19 -41
  317. package/src/runtime/finalize-event-delivery.ts +72 -0
  318. package/src/runtime/guardian-action-message-composer.ts +0 -54
  319. package/src/runtime/http-server.ts +6 -14
  320. package/src/runtime/http-types.ts +0 -1
  321. package/src/runtime/message-composer-types.ts +0 -9
  322. package/src/runtime/middleware/__tests__/rate-limiter.test.ts +63 -0
  323. package/src/runtime/middleware/auth.ts +27 -3
  324. package/src/runtime/middleware/rate-limiter.ts +28 -1
  325. package/src/runtime/migrations/vbundle-builder.ts +6 -5
  326. package/src/runtime/pending-interactions.ts +20 -1
  327. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +232 -173
  328. package/src/runtime/routes/__tests__/plugins-routes.test.ts +18 -0
  329. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +436 -0
  330. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +11 -0
  331. package/src/runtime/routes/approval-routes.ts +35 -8
  332. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -1
  333. package/src/runtime/routes/btw-routes.ts +37 -1
  334. package/src/runtime/routes/channel-delivery-routes.ts +11 -7
  335. package/src/runtime/routes/channel-route-definitions.ts +3 -0
  336. package/src/runtime/routes/channel-route-shared.ts +3 -1
  337. package/src/runtime/routes/consolidation-routes.ts +17 -13
  338. package/src/runtime/routes/conversation-compaction-routes.ts +159 -119
  339. package/src/runtime/routes/conversation-list-routes.ts +41 -4
  340. package/src/runtime/routes/conversation-query-routes.ts +196 -11
  341. package/src/runtime/routes/conversation-routes.ts +15 -1
  342. package/src/runtime/routes/credential-prompt-routes.ts +39 -17
  343. package/src/runtime/routes/empty-state-greeting-cache.ts +65 -0
  344. package/src/runtime/routes/heartbeat-routes.ts +18 -13
  345. package/src/runtime/routes/image-generation-routes.ts +20 -2
  346. package/src/runtime/routes/inbound-message-handler.ts +13 -12
  347. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +32 -31
  348. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +7 -5
  349. package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -21
  350. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
  351. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +6 -15
  352. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +1 -1
  353. package/src/runtime/routes/index.ts +6 -0
  354. package/src/runtime/routes/log-export/AGENTS.md +1 -1
  355. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  356. package/src/runtime/routes/migration-routes.ts +5 -9
  357. package/src/runtime/routes/plugins-routes.ts +26 -0
  358. package/src/runtime/routes/ps-routes.ts +10 -8
  359. package/src/runtime/routes/retrospective-routes.ts +235 -0
  360. package/src/runtime/routes/runs-pagination.ts +75 -0
  361. package/src/runtime/routes/schedule-routes.ts +367 -59
  362. package/src/runtime/routes/sounds-config-routes.ts +239 -0
  363. package/src/runtime/routes/surface-action-routes.ts +84 -4
  364. package/src/runtime/routes/workflow-routes.test.ts +372 -0
  365. package/src/runtime/routes/workflow-routes.ts +363 -0
  366. package/src/runtime/routes/workspace-routes.test.ts +61 -1
  367. package/src/runtime/routes/workspace-routes.ts +26 -1
  368. package/src/runtime/services/__tests__/analyze-conversation.test.ts +38 -0
  369. package/src/runtime/services/analyze-conversation.ts +26 -13
  370. package/src/schedule/inference-profile.ts +28 -0
  371. package/src/schedule/schedule-store.ts +152 -4
  372. package/src/schedule/scheduler-types.ts +6 -0
  373. package/src/schedule/scheduler.ts +96 -0
  374. package/src/security/secret-allowlist.ts +1 -1
  375. package/src/skills/path-classifier.ts +1 -1
  376. package/src/tools/apps/executors.ts +23 -0
  377. package/src/tools/apps/resolve-app-id.ts +42 -0
  378. package/src/tools/browser/browser-execution.ts +9 -11
  379. package/src/tools/credentials/broker.ts +4 -4
  380. package/src/tools/credentials/vault.ts +26 -137
  381. package/src/tools/executor.ts +69 -0
  382. package/src/tools/flag-gated-tools.test.ts +76 -0
  383. package/src/tools/permission-checker.ts +8 -1
  384. package/src/tools/registry.ts +51 -0
  385. package/src/tools/schedule/create.ts +77 -1
  386. package/src/tools/schedule/list.ts +1 -0
  387. package/src/tools/schedule/update.ts +73 -1
  388. package/src/tools/skills/execute.ts +56 -0
  389. package/src/tools/terminal/shell.ts +1 -1
  390. package/src/tools/ui-surface/definitions.ts +91 -2
  391. package/src/tools/workflows/manage-workflows.ts +183 -0
  392. package/src/tools/workflows/run-workflow.test.ts +442 -0
  393. package/src/tools/workflows/run-workflow.ts +88 -0
  394. package/src/types/onboarding-context.ts +2 -0
  395. package/src/usage/attribution.ts +24 -0
  396. package/src/util/canonicalize-identity.ts +12 -3
  397. package/src/util/platform.ts +17 -17
  398. package/src/watcher/__tests__/engine.test.ts +24 -0
  399. package/src/watcher/__tests__/telemetry.test.ts +135 -0
  400. package/src/watcher/engine.ts +7 -0
  401. package/src/watcher/telemetry.ts +74 -0
  402. package/src/workflows/capabilities.test.ts +365 -0
  403. package/src/workflows/capabilities.ts +359 -0
  404. package/src/workflows/deterministic-stringify.ts +27 -0
  405. package/src/workflows/engine-integration.test.ts +656 -0
  406. package/src/workflows/engine.test.ts +1144 -0
  407. package/src/workflows/engine.ts +1078 -0
  408. package/src/workflows/fanout-load.test.ts +168 -0
  409. package/src/workflows/journal-store.test.ts +369 -0
  410. package/src/workflows/journal-store.ts +470 -0
  411. package/src/workflows/leaf-runner.test.ts +704 -0
  412. package/src/workflows/leaf-runner.ts +589 -0
  413. package/src/workflows/library.test.ts +134 -0
  414. package/src/workflows/library.ts +124 -0
  415. package/src/workflows/run-manager.test.ts +711 -0
  416. package/src/workflows/run-manager.ts +593 -0
  417. package/src/workflows/sandbox-escape.test.ts +339 -0
  418. package/src/workflows/sandbox.test.ts +251 -0
  419. package/src/workflows/sandbox.ts +447 -0
  420. package/src/workspace/adaptive-thinking-repair.ts +33 -11
  421. package/src/workspace/migrations/021-move-signals-to-workspace.ts +1 -1
  422. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +1 -1
  423. package/src/workspace/migrations/026-backfill-install-meta.ts +1 -1
  424. package/src/workspace/migrations/030-seed-pkb-autoinject.ts +2 -1
  425. package/src/workspace/migrations/031-drop-user-md.ts +1 -4
  426. package/src/workspace/migrations/048-remove-workspace-hooks.ts +1 -1
  427. package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +5 -2
  428. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +1 -1
  429. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +8 -2
  430. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +41 -14
  431. package/src/workspace/migrations/102-preserve-heartbeat-enabled-for-existing-workspaces.ts +69 -0
  432. package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +83 -0
  433. package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +133 -0
  434. package/src/workspace/migrations/registry.ts +6 -0
  435. package/src/workspace/migrations/runner.ts +1 -1
  436. package/tsconfig.json +1 -1
  437. package/src/__tests__/guardian-action-copy-generator.test.ts +0 -200
  438. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -579
  439. package/src/__tests__/guardian-action-store.test.ts +0 -106
  440. package/src/daemon/guardian-action-generators.ts +0 -71
  441. package/src/memory/guardian-action-store.ts +0 -484
  442. package/src/runtime/guardian-action-grant-minter.ts +0 -150
@@ -5,74 +5,105 @@
5
5
  * post-generation enforcement to ensure required directives always appear.
6
6
  */
7
7
 
8
- // ── Local string utilities ──────────────────────────────────────────────────
9
- //
10
- // Tiny helpers duplicated from copy-composer to keep this module
11
- // dependency-free (avoiding a circular import with copy-composer, which
12
- // imports access-request helpers for its templates).
13
-
14
- function str(value: unknown, fallback: string): string {
15
- if (typeof value === "string" && value.length > 0) return value;
16
- return fallback;
8
+ import { z } from "zod";
9
+
10
+ import { buildApprovalCardBlocks } from "./approval-card-builder.js";
11
+ import {
12
+ nonEmpty,
13
+ sanitizeIdentityField,
14
+ sanitizeMessagePreview,
15
+ } from "./notification-utils.js";
16
+
17
+ // ── Zod schema for access-request payloads ──────────────────────────────────
18
+
19
+ /** Accepts string, null, or any other type — coerces non-strings to undefined. */
20
+ const optStr = z
21
+ .unknown()
22
+ .transform((v) => (typeof v === "string" ? v : undefined));
23
+
24
+ /** Accepts boolean or any other type — coerces non-true to undefined. */
25
+ const optBool = z.unknown().transform((v) => (v === true ? true : undefined));
26
+
27
+ export const AccessRequestPayloadSchema = z.object({
28
+ requestId: optStr,
29
+ requestCode: optStr,
30
+ sourceChannel: optStr,
31
+ conversationExternalId: optStr,
32
+ actorExternalId: optStr,
33
+ actorDisplayName: optStr,
34
+ actorUsername: optStr,
35
+ senderIdentifier: optStr,
36
+ guardianBindingChannel: optStr,
37
+ guardianResolutionSource: optStr,
38
+ previousMemberStatus: optStr,
39
+ messagePreview: optStr,
40
+ isStranger: optBool,
41
+ isRestricted: optBool,
42
+ messageTs: optStr,
43
+ });
44
+
45
+ export type ParsedAccessRequestPayload = z.infer<
46
+ typeof AccessRequestPayloadSchema
47
+ >;
48
+
49
+ export function parseAccessRequestPayload(
50
+ payload: Record<string, unknown>,
51
+ ): ParsedAccessRequestPayload {
52
+ return AccessRequestPayloadSchema.parse(payload);
17
53
  }
18
54
 
19
- function nonEmpty(value: string | undefined): string | undefined {
20
- if (typeof value !== "string") return undefined;
21
- const trimmed = value.trim();
22
- return trimmed.length > 0 ? trimmed : undefined;
55
+ // ── Warnings ────────────────────────────────────────────────────────────────
56
+
57
+ /**
58
+ * Build a list of human-readable warning strings for an access request.
59
+ * Used by both the Slack Block Kit card and the plain-text contract.
60
+ */
61
+ export function buildAccessRequestWarnings(
62
+ p: ParsedAccessRequestPayload,
63
+ ): string[] {
64
+ const warnings: string[] = [];
65
+ if (p.previousMemberStatus === "revoked") {
66
+ warnings.push("This user was previously revoked.");
67
+ }
68
+ if (p.isStranger) {
69
+ warnings.push("External Slack user (not in this workspace).");
70
+ }
71
+ if (p.isRestricted) {
72
+ warnings.push("Guest / restricted account.");
73
+ }
74
+ return warnings;
23
75
  }
24
76
 
25
- // ── Identity sanitization ───────────────────────────────────────────────────
77
+ // ── Slack conversation helpers ───────────────────────────────────────────────
26
78
 
27
- const IDENTITY_FIELD_MAX_LENGTH = 120;
79
+ /** Slack DM conversation IDs start with `D` followed by alphanumeric chars. */
80
+ export function isSlackDmConversation(conversationExternalId: string): boolean {
81
+ return /^D[A-Z0-9]+$/i.test(conversationExternalId);
82
+ }
28
83
 
29
84
  /**
30
- * Sanitize an untrusted identity field for inclusion in notification copy.
31
- *
32
- * - Strips control characters (U+0000–U+001F, U+007F–U+009F) and newlines.
33
- * - Clamps to IDENTITY_FIELD_MAX_LENGTH characters.
34
- * - Wraps in quotes to neutralize instruction-like payload text.
85
+ * Build a Slack message permalink from a channel ID and message timestamp.
86
+ * Format: https://slack.com/archives/{channelId}/p{ts_without_dot}
87
+ * Workspace-agnostic resolves for any authenticated Slack viewer.
35
88
  */
36
- export function sanitizeIdentityField(value: string): string {
37
- const stripped = value.replace(/[\x00-\x1f\x7f-\x9f\r\n]+/g, " ").trim();
38
- const clamped =
39
- stripped.length > IDENTITY_FIELD_MAX_LENGTH
40
- ? stripped.slice(0, IDENTITY_FIELD_MAX_LENGTH) + ""
41
- : stripped;
42
- return clamped;
89
+ export function buildSlackMessagePermalink(
90
+ conversationExternalId: string,
91
+ messageTs: string,
92
+ ): string {
93
+ return `https://slack.com/archives/${conversationExternalId}/p${messageTs.replace(".", "")}`;
43
94
  }
44
95
 
45
- export function buildAccessRequestIdentityLine(
46
- payload: Record<string, unknown>,
47
- ): string {
48
- const requester = sanitizeIdentityField(
49
- str(payload.senderIdentifier, "Someone"),
50
- );
51
- const sourceChannel =
52
- typeof payload.sourceChannel === "string"
53
- ? payload.sourceChannel
54
- : undefined;
55
- const callerName = nonEmpty(
56
- typeof payload.actorDisplayName === "string"
57
- ? payload.actorDisplayName
58
- : undefined,
59
- );
60
- const actorUsername = nonEmpty(
61
- typeof payload.actorUsername === "string"
62
- ? payload.actorUsername
63
- : undefined,
64
- );
65
- const actorExternalId = nonEmpty(
66
- typeof payload.actorExternalId === "string"
67
- ? payload.actorExternalId
68
- : undefined,
69
- );
96
+ /** Internal typed implementation — avoids re-parsing when called from
97
+ * buildAccessRequestContractText which has already parsed the payload. */
98
+ function buildIdentityLineFromParsed(p: ParsedAccessRequestPayload): string {
99
+ const requester = sanitizeIdentityField(p.senderIdentifier || "Someone");
100
+ const callerName = nonEmpty(p.actorDisplayName);
101
+ const actorUsername = nonEmpty(p.actorUsername);
102
+ const actorExternalId = nonEmpty(p.actorExternalId);
70
103
 
71
- if (sourceChannel === "phone" && callerName) {
104
+ if (p.sourceChannel === "phone" && callerName) {
72
105
  const safeName = sanitizeIdentityField(callerName);
73
- const safeId = sanitizeIdentityField(
74
- str(payload.actorExternalId, requester),
75
- );
106
+ const safeId = sanitizeIdentityField(p.actorExternalId || requester);
76
107
  return `${safeName} (${safeId}) is calling and requesting access to the assistant.`;
77
108
  }
78
109
 
@@ -84,11 +115,10 @@ export function buildAccessRequestIdentityLine(
84
115
  const sanitizedExternalId = actorExternalId
85
116
  ? sanitizeIdentityField(actorExternalId)
86
117
  : undefined;
87
- // When the requester is a raw Slack user ID (e.g. the fallback path in
88
- // access-request-helper sets senderIdentifier to the raw actorExternalId),
89
- // format it as a Slack mention so it renders as a clickable display name.
118
+ // When the requester is a raw Slack user ID, format it as a Slack mention
119
+ // so Slack auto-renders it as a clickable display name.
90
120
  const formattedRequester =
91
- sourceChannel === "slack" && /^U[A-Z0-9]+$/i.test(requester)
121
+ p.sourceChannel === "slack" && /^U[A-Z0-9]+$/i.test(requester)
92
122
  ? `<@${requester}>`
93
123
  : requester;
94
124
  const parts = [formattedRequester];
@@ -100,39 +130,23 @@ export function buildAccessRequestIdentityLine(
100
130
  sanitizedExternalId !== requester &&
101
131
  sanitizedExternalId !== sanitizedUsername
102
132
  ) {
103
- // For Slack, use the <@U...> mention format so Slack auto-renders
104
- // the user ID as a clickable display name.
105
133
  const formattedId =
106
- sourceChannel === "slack" && /^U[A-Z0-9]+$/i.test(sanitizedExternalId)
134
+ p.sourceChannel === "slack" && /^U[A-Z0-9]+$/i.test(sanitizedExternalId)
107
135
  ? `<@${sanitizedExternalId}>`
108
136
  : `[${sanitizedExternalId}]`;
109
137
  parts.push(formattedId);
110
138
  }
111
- if (sourceChannel) {
112
- parts.push(`via ${sourceChannel}`);
139
+ if (p.sourceChannel) {
140
+ parts.push(`via ${p.sourceChannel}`);
113
141
  }
114
142
 
115
143
  return `${parts.join(" ")} is requesting access to the assistant.`;
116
144
  }
117
145
 
118
- // ── Message preview ─────────────────────────────────────────────────────────
119
-
120
- export const MESSAGE_PREVIEW_MAX_LENGTH = 200;
121
-
122
- /**
123
- * Sanitize an untrusted message preview for inclusion in notification copy.
124
- *
125
- * Like {@link sanitizeIdentityField} but uses the higher
126
- * MESSAGE_PREVIEW_MAX_LENGTH limit (200 chars) instead of the identity
127
- * field limit (120 chars).
128
- */
129
- export function sanitizeMessagePreview(value: string): string {
130
- const stripped = value.replace(/[\x00-\x1f\x7f-\x9f\r\n]+/g, " ").trim();
131
- const clamped =
132
- stripped.length > MESSAGE_PREVIEW_MAX_LENGTH
133
- ? stripped.slice(0, MESSAGE_PREVIEW_MAX_LENGTH) + "…"
134
- : stripped;
135
- return clamped;
146
+ export function buildAccessRequestIdentityLine(
147
+ payload: Record<string, unknown>,
148
+ ): string {
149
+ return buildIdentityLineFromParsed(parseAccessRequestPayload(payload));
136
150
  }
137
151
 
138
152
  /**
@@ -142,13 +156,10 @@ export function sanitizeMessagePreview(value: string): string {
142
156
  *
143
157
  * Returns `undefined` when no usable preview is available.
144
158
  */
145
- function buildAccessRequestMessagePreview(
146
- payload: Record<string, unknown>,
159
+ function buildMessagePreviewFromParsed(
160
+ p: ParsedAccessRequestPayload,
147
161
  ): string | undefined {
148
- const raw =
149
- typeof payload.messagePreview === "string"
150
- ? payload.messagePreview
151
- : undefined;
162
+ const raw = p.messagePreview;
152
163
  if (!raw) return undefined;
153
164
 
154
165
  const sanitized = sanitizeMessagePreview(raw);
@@ -252,32 +263,35 @@ export function hasInviteFlowDirective(text: string | undefined): boolean {
252
263
  export function buildAccessRequestContractText(
253
264
  payload: Record<string, unknown>,
254
265
  ): string {
255
- const requestCode = nonEmpty(
256
- typeof payload.requestCode === "string" ? payload.requestCode : undefined,
257
- );
258
- const previousMemberStatus =
259
- typeof payload.previousMemberStatus === "string"
260
- ? payload.previousMemberStatus
261
- : undefined;
262
-
263
- const guardianResolutionSource =
264
- typeof payload.guardianResolutionSource === "string"
265
- ? payload.guardianResolutionSource
266
- : undefined;
267
- const sourceChannel =
268
- typeof payload.sourceChannel === "string"
269
- ? payload.sourceChannel
270
- : undefined;
266
+ const p = parseAccessRequestPayload(payload);
267
+ const requestCode = nonEmpty(p.requestCode);
271
268
 
272
269
  const lines: string[] = [];
273
- lines.push(buildAccessRequestIdentityLine(payload));
274
- const preview = buildAccessRequestMessagePreview(payload);
270
+ lines.push(buildIdentityLineFromParsed(p));
271
+
272
+ const preview = buildMessagePreviewFromParsed(p);
275
273
  if (preview) {
276
274
  lines.push(preview);
277
275
  }
278
- if (previousMemberStatus === "revoked") {
279
- lines.push("Note: this user was previously revoked.");
276
+
277
+ // Unified warnings: revoked status + trust signals.
278
+ for (const warning of buildAccessRequestWarnings(p)) {
279
+ lines.push(`Note: ${warning.charAt(0).toLowerCase()}${warning.slice(1)}`);
280
280
  }
281
+
282
+ // Conversation context: source channel + permalink when available.
283
+ if (p.sourceChannel === "slack" && p.conversationExternalId) {
284
+ const permalink = p.messageTs
285
+ ? buildSlackMessagePermalink(p.conversationExternalId, p.messageTs)
286
+ : undefined;
287
+ const isDm = isSlackDmConversation(p.conversationExternalId);
288
+ const channelLabel = isDm ? "Direct message" : p.conversationExternalId;
289
+ const source = permalink
290
+ ? `Source: Slack — ${channelLabel} (${permalink})`
291
+ : `Source: Slack — ${channelLabel}`;
292
+ lines.push(source);
293
+ }
294
+
281
295
  if (requestCode) {
282
296
  const code = requestCode.toUpperCase();
283
297
  lines.push(
@@ -285,14 +299,87 @@ export function buildAccessRequestContractText(
285
299
  );
286
300
  }
287
301
  lines.push(buildAccessRequestInviteDirective());
302
+
288
303
  if (
289
- (guardianResolutionSource === "vellum-anchor" ||
290
- guardianResolutionSource === "none") &&
291
- sourceChannel
304
+ (p.guardianResolutionSource === "vellum-anchor" ||
305
+ p.guardianResolutionSource === "none") &&
306
+ p.sourceChannel
292
307
  ) {
293
308
  lines.push(
294
- `Note: You haven't verified your identity on ${sourceChannel} yet. If this was you trying to message your assistant, say "help me verify as guardian on ${sourceChannel}" to set up direct access.`,
309
+ `Note: You haven't verified your identity on ${p.sourceChannel} yet. If this was you trying to message your assistant, say "help me verify as guardian on ${p.sourceChannel}" to set up direct access.`,
295
310
  );
296
311
  }
297
312
  return lines.join("\n");
298
313
  }
314
+
315
+ // ── Seed content blocks (Surface-based rendering) ───────────────────────────
316
+
317
+ /**
318
+ * Build structured content blocks for an access request notification seed
319
+ * message. Produces a `ui_surface` card block that the web/macOS/iOS apps
320
+ * render as an interactive card via `SurfaceRouter → CardSurface`, plus a
321
+ * plain-text fallback block for search, CLI display, and backward-compatible
322
+ * clients that don't support surfaces.
323
+ */
324
+ export function buildAccessRequestSeedContentBlocks(
325
+ payload: Record<string, unknown>,
326
+ ): unknown[] {
327
+ const p = parseAccessRequestPayload(payload);
328
+
329
+ const rawName = nonEmpty(p.actorDisplayName) ?? nonEmpty(p.senderIdentifier);
330
+ const displayName = rawName ? sanitizeIdentityField(rawName) : "Someone";
331
+
332
+ const metadata: Array<{ label: string; value: string }> = [];
333
+
334
+ if (p.actorUsername) {
335
+ metadata.push({
336
+ label: "Username",
337
+ value: `@${sanitizeIdentityField(p.actorUsername)}`,
338
+ });
339
+ }
340
+
341
+ if (p.sourceChannel === "slack" && p.conversationExternalId) {
342
+ const isDm = isSlackDmConversation(p.conversationExternalId);
343
+ metadata.push({
344
+ label: "Source",
345
+ value: isDm
346
+ ? "Slack — Direct message"
347
+ : `Slack — #${p.conversationExternalId}`,
348
+ });
349
+ } else if (p.sourceChannel) {
350
+ metadata.push({ label: "Source", value: p.sourceChannel });
351
+ }
352
+
353
+ const warnings = buildAccessRequestWarnings(p);
354
+ const bodyParts: string[] = [];
355
+
356
+ if (p.messagePreview) {
357
+ bodyParts.push(`> "${sanitizeMessagePreview(p.messagePreview)}"`);
358
+ }
359
+ for (const w of warnings) {
360
+ bodyParts.push(`⚠️ ${w}`);
361
+ }
362
+ if (p.sourceChannel === "slack" && p.conversationExternalId && p.messageTs) {
363
+ const permalink = buildSlackMessagePermalink(
364
+ p.conversationExternalId,
365
+ p.messageTs,
366
+ );
367
+ bodyParts.push(`[View message](${permalink})`);
368
+ }
369
+
370
+ const body =
371
+ bodyParts.length > 0
372
+ ? bodyParts.join("\n\n")
373
+ : "No additional context available.";
374
+
375
+ return buildApprovalCardBlocks({
376
+ surfaceIdPrefix: "access-request",
377
+ cardTitle: "Access Request",
378
+ requesterName: displayName,
379
+ subtitle: "Requesting access to the assistant",
380
+ body,
381
+ metadata,
382
+ requestId: p.requestId,
383
+ fallbackText: buildAccessRequestContractText(payload),
384
+ });
385
+ }