@vellumai/assistant 0.5.6 → 0.5.8

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/.env.example +16 -2
  2. package/ARCHITECTURE.md +6 -75
  3. package/Dockerfile +3 -2
  4. package/README.md +0 -2
  5. package/bun.lock +0 -414
  6. package/docker-entrypoint.sh +9 -0
  7. package/docs/architecture/keychain-broker.md +45 -240
  8. package/docs/architecture/memory.md +13 -11
  9. package/docs/architecture/security.md +0 -17
  10. package/docs/credential-execution-service.md +2 -2
  11. package/node_modules/@vellumai/ces-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/ces-contracts/src/error.ts +1 -1
  13. package/node_modules/@vellumai/ces-contracts/src/grants.ts +1 -1
  14. package/node_modules/@vellumai/ces-contracts/src/handles.ts +1 -1
  15. package/node_modules/@vellumai/ces-contracts/src/index.ts +1 -1
  16. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +120 -1
  17. package/node_modules/@vellumai/credential-storage/package.json +1 -0
  18. package/node_modules/@vellumai/egress-proxy/package.json +1 -0
  19. package/package.json +2 -3
  20. package/src/__tests__/actor-token-service.test.ts +0 -114
  21. package/src/__tests__/approval-cascade.test.ts +0 -1
  22. package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
  23. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  24. package/src/__tests__/browser-skill-endstate.test.ts +6 -5
  25. package/src/__tests__/btw-routes.test.ts +0 -39
  26. package/src/__tests__/call-controller.test.ts +0 -1
  27. package/src/__tests__/call-domain.test.ts +0 -128
  28. package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
  29. package/src/__tests__/ces-startup-timeout.test.ts +40 -0
  30. package/src/__tests__/channel-approval-routes.test.ts +0 -5
  31. package/src/__tests__/channel-readiness-service.test.ts +1 -60
  32. package/src/__tests__/checker.test.ts +4 -2
  33. package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
  34. package/src/__tests__/config-schema-cmd.test.ts +0 -2
  35. package/src/__tests__/config-schema.test.ts +3 -1
  36. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -1
  37. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  38. package/src/__tests__/conversation-agent-loop.test.ts +2 -4
  39. package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
  40. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -1
  41. package/src/__tests__/conversation-error.test.ts +15 -1
  42. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  43. package/src/__tests__/conversation-messaging-secret-redirect.test.ts +1 -1
  44. package/src/__tests__/conversation-pre-run-repair.test.ts +0 -1
  45. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -1
  46. package/src/__tests__/conversation-queue.test.ts +0 -1
  47. package/src/__tests__/conversation-skill-tools.test.ts +0 -54
  48. package/src/__tests__/conversation-slash-queue.test.ts +0 -1
  49. package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
  50. package/src/__tests__/conversation-title-service.test.ts +87 -0
  51. package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
  52. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
  53. package/src/__tests__/credential-execution-client.test.ts +5 -2
  54. package/src/__tests__/credential-execution-feature-gates.test.ts +59 -30
  55. package/src/__tests__/credential-execution-managed-contract.test.ts +35 -20
  56. package/src/__tests__/credential-security-e2e.test.ts +1 -67
  57. package/src/__tests__/credential-security-invariants.test.ts +6 -50
  58. package/src/__tests__/credentials-cli.test.ts +82 -3
  59. package/src/__tests__/daemon-credential-client.test.ts +123 -0
  60. package/src/__tests__/db-migration-rollback.test.ts +2015 -1
  61. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -0
  62. package/src/__tests__/docker-signing-key-bootstrap.test.ts +34 -143
  63. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
  64. package/src/__tests__/gateway-client-managed-outbound.test.ts +79 -1
  65. package/src/__tests__/guardian-routing-state.test.ts +0 -5
  66. package/src/__tests__/host-shell-tool.test.ts +6 -7
  67. package/src/__tests__/http-user-message-parity.test.ts +3 -103
  68. package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
  69. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
  70. package/src/__tests__/intent-routing.test.ts +0 -13
  71. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
  72. package/src/__tests__/journal-context.test.ts +335 -0
  73. package/src/__tests__/keychain-broker-client.test.ts +161 -22
  74. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -3
  75. package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
  76. package/src/__tests__/memory-lifecycle-e2e.test.ts +70 -25
  77. package/src/__tests__/memory-recall-quality.test.ts +48 -17
  78. package/src/__tests__/memory-regressions.test.ts +408 -363
  79. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -3
  80. package/src/__tests__/migration-export-http.test.ts +2 -2
  81. package/src/__tests__/migration-import-commit-http.test.ts +2 -2
  82. package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
  83. package/src/__tests__/migration-validate-http.test.ts +2 -2
  84. package/src/__tests__/non-member-access-request.test.ts +2 -7
  85. package/src/__tests__/notification-decision-fallback.test.ts +4 -0
  86. package/src/__tests__/notification-decision-identity.test.ts +4 -0
  87. package/src/__tests__/notification-decision-strategy.test.ts +71 -0
  88. package/src/__tests__/oauth-cli.test.ts +5 -1
  89. package/src/__tests__/permission-types.test.ts +1 -0
  90. package/src/__tests__/provider-commit-message-generator.test.ts +0 -37
  91. package/src/__tests__/provider-error-scenarios.test.ts +0 -267
  92. package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
  93. package/src/__tests__/provider-streaming.benchmark.test.ts +2 -81
  94. package/src/__tests__/qdrant-manager.test.ts +28 -2
  95. package/src/__tests__/registry.test.ts +0 -6
  96. package/src/__tests__/relay-server.test.ts +1 -2
  97. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
  98. package/src/__tests__/script-proxy-injection-runtime.test.ts +1 -1
  99. package/src/__tests__/secret-onetime-send.test.ts +1 -1
  100. package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
  101. package/src/__tests__/secure-keys.test.ts +95 -272
  102. package/src/__tests__/shell-identity.test.ts +96 -6
  103. package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
  104. package/src/__tests__/skill-feature-flags.test.ts +46 -45
  105. package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
  106. package/src/__tests__/skill-load-inline-command.test.ts +8 -12
  107. package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
  108. package/src/__tests__/skill-load-tool.test.ts +0 -2
  109. package/src/__tests__/skill-memory.test.ts +17 -3
  110. package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
  111. package/src/__tests__/skills.test.ts +0 -2
  112. package/src/__tests__/slack-inbound-verification.test.ts +0 -4
  113. package/src/__tests__/stale-approval-dedup.test.ts +171 -0
  114. package/src/__tests__/stt-hints.test.ts +437 -0
  115. package/src/__tests__/suggestion-routes.test.ts +1 -32
  116. package/src/__tests__/system-prompt.test.ts +0 -1
  117. package/src/__tests__/task-memory-cleanup.test.ts +14 -0
  118. package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
  119. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
  120. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
  121. package/src/__tests__/twilio-routes-twiml.test.ts +139 -1
  122. package/src/__tests__/update-bulletin.test.ts +0 -2
  123. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
  124. package/src/__tests__/voice-quality.test.ts +58 -0
  125. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -7
  126. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
  127. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +220 -0
  128. package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
  129. package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
  130. package/src/acp/agent-process.ts +9 -1
  131. package/src/agent/loop.ts +1 -1
  132. package/src/approvals/guardian-request-resolvers.ts +164 -38
  133. package/src/calls/__tests__/tts-text-sanitizer.test.ts +254 -0
  134. package/src/calls/audio-store.test.ts +97 -0
  135. package/src/calls/audio-store.ts +205 -0
  136. package/src/calls/call-controller.ts +90 -8
  137. package/src/calls/call-domain.ts +3 -0
  138. package/src/calls/call-store.ts +10 -3
  139. package/src/calls/fish-audio-client.ts +129 -0
  140. package/src/calls/relay-server.ts +27 -0
  141. package/src/calls/stt-hints.ts +189 -0
  142. package/src/calls/tts-text-sanitizer.ts +61 -0
  143. package/src/calls/twilio-routes.ts +34 -5
  144. package/src/calls/types.ts +1 -0
  145. package/src/calls/voice-ingress-preflight.ts +0 -42
  146. package/src/calls/voice-quality.ts +38 -5
  147. package/src/calls/voice-session-bridge.ts +7 -12
  148. package/src/cli/commands/avatar.ts +2 -2
  149. package/src/cli/commands/config.ts +1 -4
  150. package/src/cli/commands/credentials.ts +128 -82
  151. package/src/cli/commands/doctor.ts +2 -2
  152. package/src/cli/commands/keys.ts +7 -7
  153. package/src/cli/commands/memory.ts +1 -1
  154. package/src/cli/commands/oauth/connections.ts +11 -29
  155. package/src/cli/commands/oauth/index.ts +7 -0
  156. package/src/cli/commands/oauth/platform.ts +525 -0
  157. package/src/cli/commands/platform.ts +3 -3
  158. package/src/cli/lib/daemon-credential-client.ts +284 -0
  159. package/src/cli.ts +1 -1
  160. package/src/config/assistant-feature-flags.ts +186 -5
  161. package/src/config/bundled-skills/AGENTS.md +34 -0
  162. package/src/config/bundled-skills/acp/SKILL.md +10 -0
  163. package/src/config/bundled-skills/app-builder/SKILL.md +0 -4
  164. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  165. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  166. package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
  167. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -0
  168. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -0
  169. package/src/config/bundled-skills/settings/SKILL.md +15 -2
  170. package/src/config/bundled-skills/settings/TOOLS.json +47 -2
  171. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +59 -0
  172. package/src/config/bundled-skills/settings/tools/avatar-update.ts +80 -0
  173. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
  174. package/src/config/bundled-skills/slack/SKILL.md +1 -1
  175. package/src/config/bundled-tool-registry.ts +5 -11
  176. package/src/config/defaults.ts +0 -2
  177. package/src/config/env-registry.ts +5 -5
  178. package/src/config/env.ts +21 -14
  179. package/src/config/feature-flag-registry.json +49 -9
  180. package/src/config/loader.ts +106 -42
  181. package/src/config/schema.ts +9 -29
  182. package/src/config/schemas/calls.ts +30 -0
  183. package/src/config/schemas/fish-audio.ts +39 -0
  184. package/src/config/schemas/inference.ts +2 -2
  185. package/src/config/schemas/journal.ts +16 -0
  186. package/src/config/schemas/memory-processing.ts +2 -2
  187. package/src/config/schemas/security.ts +0 -4
  188. package/src/config/types.ts +1 -1
  189. package/src/contacts/contact-store.ts +39 -0
  190. package/src/contacts/types.ts +2 -0
  191. package/src/credential-execution/approval-bridge.ts +1 -0
  192. package/src/credential-execution/executable-discovery.ts +28 -4
  193. package/src/credential-execution/feature-gates.ts +16 -0
  194. package/src/credential-execution/process-manager.ts +38 -0
  195. package/src/credential-execution/startup-timeout.ts +36 -0
  196. package/src/daemon/approval-generators.ts +3 -9
  197. package/src/daemon/assistant-attachments.ts +9 -0
  198. package/src/daemon/config-watcher.ts +5 -0
  199. package/src/daemon/conversation-error.ts +13 -1
  200. package/src/daemon/conversation-memory.ts +1 -2
  201. package/src/daemon/conversation-process.ts +18 -1
  202. package/src/daemon/conversation-surfaces.ts +30 -1
  203. package/src/daemon/conversation-tool-setup.ts +0 -105
  204. package/src/daemon/conversation.ts +21 -1
  205. package/src/daemon/guardian-action-generators.ts +3 -9
  206. package/src/daemon/handlers/config-vercel.ts +92 -0
  207. package/src/daemon/handlers/skills.ts +2 -15
  208. package/src/daemon/install-symlink.ts +195 -0
  209. package/src/daemon/lifecycle.ts +234 -51
  210. package/src/daemon/message-types/conversations.ts +4 -4
  211. package/src/daemon/message-types/diagnostics.ts +3 -22
  212. package/src/daemon/message-types/messages.ts +0 -2
  213. package/src/daemon/message-types/upgrades.ts +8 -0
  214. package/src/daemon/server.ts +32 -95
  215. package/src/events/domain-events.ts +2 -1
  216. package/src/inbound/platform-callback-registration.ts +3 -3
  217. package/src/instrument.ts +8 -5
  218. package/src/memory/app-store.ts +31 -0
  219. package/src/memory/conversation-title-service.ts +50 -1
  220. package/src/memory/db-init.ts +16 -0
  221. package/src/memory/indexer.ts +19 -10
  222. package/src/memory/items-extractor.ts +328 -321
  223. package/src/memory/job-handlers/conversation-starters.ts +4 -1
  224. package/src/memory/job-handlers/summarization.ts +26 -16
  225. package/src/memory/jobs-store.ts +63 -6
  226. package/src/memory/jobs-worker.ts +31 -7
  227. package/src/memory/journal-memory.ts +214 -0
  228. package/src/memory/migrations/001-job-deferrals.ts +19 -0
  229. package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
  230. package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
  231. package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
  232. package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
  233. package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
  234. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
  235. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
  236. package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
  237. package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
  238. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
  239. package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
  240. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
  241. package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
  242. package/src/memory/migrations/116-messages-fts.ts +106 -1
  243. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
  244. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
  245. package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
  246. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
  247. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
  248. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
  249. package/src/memory/migrations/141-rename-verification-table.ts +54 -0
  250. package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
  251. package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
  252. package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
  253. package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
  254. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
  255. package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
  256. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
  257. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
  258. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
  259. package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
  260. package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
  261. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
  262. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
  263. package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
  264. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
  265. package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
  266. package/src/memory/migrations/193-add-source-type-columns.ts +81 -0
  267. package/src/memory/migrations/index.ts +5 -0
  268. package/src/memory/migrations/registry.ts +98 -0
  269. package/src/memory/migrations/validate-migration-state.ts +137 -11
  270. package/src/memory/qdrant-circuit-breaker.ts +9 -0
  271. package/src/memory/qdrant-manager.ts +64 -7
  272. package/src/memory/retriever.test.ts +37 -25
  273. package/src/memory/retriever.ts +24 -49
  274. package/src/memory/schema/calls.ts +1 -0
  275. package/src/memory/schema/contacts.ts +1 -0
  276. package/src/memory/schema/memory-core.ts +2 -0
  277. package/src/memory/search/formatting.ts +7 -44
  278. package/src/memory/search/staleness.ts +4 -0
  279. package/src/memory/search/tier-classifier.ts +10 -2
  280. package/src/memory/search/types.ts +2 -5
  281. package/src/memory/task-memory-cleanup.ts +4 -3
  282. package/src/notifications/adapters/slack.ts +168 -6
  283. package/src/notifications/broadcaster.ts +1 -0
  284. package/src/notifications/copy-composer.ts +59 -2
  285. package/src/notifications/decision-engine.ts +4 -1
  286. package/src/notifications/signal.ts +2 -0
  287. package/src/notifications/types.ts +2 -0
  288. package/src/oauth/connection-resolver.ts +6 -4
  289. package/src/permissions/checker.ts +0 -38
  290. package/src/permissions/shell-identity.ts +76 -22
  291. package/src/permissions/types.ts +4 -2
  292. package/src/platform/client.ts +35 -7
  293. package/src/prompts/journal-context.ts +133 -0
  294. package/src/prompts/persona-resolver.ts +194 -0
  295. package/src/prompts/system-prompt.ts +44 -4
  296. package/src/prompts/templates/SOUL.md +10 -0
  297. package/src/prompts/templates/users/default.md +1 -0
  298. package/src/providers/provider-send-message.ts +3 -32
  299. package/src/providers/registry.ts +29 -179
  300. package/src/providers/types.ts +1 -1
  301. package/src/runtime/access-request-helper.ts +4 -0
  302. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  303. package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
  304. package/src/runtime/auth/__tests__/guard-tests.test.ts +9 -50
  305. package/src/runtime/auth/external-assistant-id.ts +13 -59
  306. package/src/runtime/auth/route-policy.ts +17 -1
  307. package/src/runtime/auth/token-service.ts +43 -138
  308. package/src/runtime/channel-readiness-service.ts +1 -16
  309. package/src/runtime/gateway-client.ts +47 -4
  310. package/src/runtime/guardian-decision-types.ts +45 -4
  311. package/src/runtime/http-server.ts +31 -3
  312. package/src/runtime/middleware/error-handler.ts +1 -9
  313. package/src/runtime/routes/access-request-decision.ts +2 -2
  314. package/src/runtime/routes/app-management-routes.ts +2 -1
  315. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +219 -30
  316. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +37 -14
  317. package/src/runtime/routes/audio-routes.ts +40 -0
  318. package/src/runtime/routes/btw-routes.ts +0 -17
  319. package/src/runtime/routes/channel-readiness-routes.ts +9 -4
  320. package/src/runtime/routes/conversation-query-routes.ts +63 -1
  321. package/src/runtime/routes/conversation-routes.ts +4 -44
  322. package/src/runtime/routes/debug-routes.ts +12 -9
  323. package/src/runtime/routes/diagnostics-routes.ts +1 -477
  324. package/src/runtime/routes/guardian-approval-interception.ts +168 -11
  325. package/src/runtime/routes/guardian-approval-prompt.ts +6 -1
  326. package/src/runtime/routes/guardian-approval-reply-helpers.ts +103 -21
  327. package/src/runtime/routes/identity-routes.ts +19 -30
  328. package/src/runtime/routes/inbound-message-handler.ts +31 -1
  329. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +64 -5
  330. package/src/runtime/routes/inbound-stages/background-dispatch.ts +52 -40
  331. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
  332. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  333. package/src/runtime/routes/integrations/twilio.ts +52 -10
  334. package/src/runtime/routes/integrations/vercel.ts +89 -0
  335. package/src/runtime/routes/log-export-routes.ts +5 -0
  336. package/src/runtime/routes/memory-item-routes.test.ts +3 -3
  337. package/src/runtime/routes/memory-item-routes.ts +46 -14
  338. package/src/runtime/routes/migration-rollback-routes.ts +209 -0
  339. package/src/runtime/routes/migration-routes.ts +17 -1
  340. package/src/runtime/routes/notification-routes.ts +58 -0
  341. package/src/runtime/routes/schedule-routes.ts +65 -0
  342. package/src/runtime/routes/secret-routes.ts +141 -10
  343. package/src/runtime/routes/settings-routes.ts +41 -1
  344. package/src/runtime/routes/tts-routes.ts +96 -0
  345. package/src/runtime/routes/upgrade-broadcast-routes.ts +26 -2
  346. package/src/runtime/routes/workspace-commit-routes.ts +62 -0
  347. package/src/runtime/routes/workspace-routes.test.ts +22 -1
  348. package/src/runtime/routes/workspace-routes.ts +1 -1
  349. package/src/runtime/routes/workspace-utils.ts +86 -2
  350. package/src/security/ces-credential-client.ts +75 -29
  351. package/src/security/ces-rpc-credential-backend.ts +86 -0
  352. package/src/security/credential-backend.ts +22 -92
  353. package/src/security/keychain-broker-client.ts +10 -2
  354. package/src/security/secure-keys.ts +113 -115
  355. package/src/skills/catalog-install.ts +6 -32
  356. package/src/skills/skill-memory.ts +1 -0
  357. package/src/subagent/manager.ts +2 -5
  358. package/src/telemetry/usage-telemetry-reporter.ts +4 -2
  359. package/src/tools/acp/spawn.ts +78 -1
  360. package/src/tools/calls/call-start.ts +1 -0
  361. package/src/tools/credentials/vault.ts +5 -3
  362. package/src/tools/executor.ts +0 -4
  363. package/src/tools/memory/definitions.ts +3 -2
  364. package/src/tools/memory/handlers.ts +10 -7
  365. package/src/tools/network/script-proxy/session-manager.ts +19 -4
  366. package/src/tools/network/web-fetch.ts +3 -1
  367. package/src/tools/skills/execute.ts +1 -1
  368. package/src/tools/terminal/safe-env.ts +1 -0
  369. package/src/tools/types.ts +0 -8
  370. package/src/util/browser.ts +15 -0
  371. package/src/util/errors.ts +0 -12
  372. package/src/util/platform.ts +4 -51
  373. package/src/workspace/git-service.ts +5 -2
  374. package/src/workspace/migrations/001-avatar-rename.ts +15 -0
  375. package/src/workspace/migrations/003-seed-device-id.ts +17 -1
  376. package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
  377. package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
  378. package/src/workspace/migrations/006-services-config.ts +49 -0
  379. package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
  380. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
  381. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
  382. package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
  383. package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
  384. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
  385. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
  386. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
  387. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
  388. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
  389. package/src/workspace/migrations/017-seed-persona-dirs.ts +96 -0
  390. package/src/workspace/migrations/018-rekey-compound-credential-keys.ts +184 -0
  391. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +103 -0
  392. package/src/workspace/migrations/migrate-to-workspace-volume.ts +27 -5
  393. package/src/workspace/migrations/registry.ts +12 -0
  394. package/src/workspace/migrations/runner.ts +106 -2
  395. package/src/workspace/migrations/types.ts +4 -0
  396. package/src/workspace/provider-commit-message-generator.ts +12 -21
  397. package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
  398. package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
  399. package/src/__tests__/diagnostics-export.test.ts +0 -288
  400. package/src/__tests__/local-gateway-health.test.ts +0 -209
  401. package/src/__tests__/provider-fail-open-selection.test.ts +0 -271
  402. package/src/__tests__/provider-failover-actual-provider.test.ts +0 -66
  403. package/src/__tests__/secret-ingress-handler.test.ts +0 -120
  404. package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
  405. package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
  406. package/src/__tests__/swarm-orchestrator.test.ts +0 -463
  407. package/src/__tests__/swarm-plan-validator.test.ts +0 -384
  408. package/src/__tests__/swarm-recursion.test.ts +0 -197
  409. package/src/__tests__/swarm-router-planner.test.ts +0 -234
  410. package/src/__tests__/swarm-tool.test.ts +0 -185
  411. package/src/__tests__/swarm-worker-backend.test.ts +0 -144
  412. package/src/__tests__/swarm-worker-runner.test.ts +0 -288
  413. package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
  414. package/src/commands/cc-command-registry.ts +0 -248
  415. package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
  416. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
  417. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
  418. package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
  419. package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
  420. package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
  421. package/src/config/schemas/swarm.ts +0 -82
  422. package/src/logfire.ts +0 -135
  423. package/src/memory/search/lexical.ts +0 -48
  424. package/src/providers/failover.ts +0 -186
  425. package/src/runtime/local-gateway-health.ts +0 -275
  426. package/src/security/secret-ingress.ts +0 -68
  427. package/src/swarm/backend-claude-code.ts +0 -225
  428. package/src/swarm/checkpoint.ts +0 -137
  429. package/src/swarm/graph-utils.ts +0 -53
  430. package/src/swarm/index.ts +0 -55
  431. package/src/swarm/limits.ts +0 -66
  432. package/src/swarm/orchestrator.ts +0 -424
  433. package/src/swarm/plan-validator.ts +0 -117
  434. package/src/swarm/router-planner.ts +0 -162
  435. package/src/swarm/router-prompts.ts +0 -39
  436. package/src/swarm/synthesizer.ts +0 -81
  437. package/src/swarm/types.ts +0 -72
  438. package/src/swarm/worker-backend.ts +0 -131
  439. package/src/swarm/worker-prompts.ts +0 -80
  440. package/src/swarm/worker-runner.ts +0 -170
  441. package/src/tools/claude-code/claude-code.ts +0 -610
  442. package/src/tools/swarm/delegate.ts +0 -205
@@ -54,6 +54,7 @@ mock.module("node:fs", () => ({
54
54
  // Import after mocking
55
55
  import {
56
56
  loadCheckpoints,
57
+ rollbackWorkspaceMigrations,
57
58
  runWorkspaceMigrations,
58
59
  } from "../workspace/migrations/runner.js";
59
60
 
@@ -68,6 +69,7 @@ function makeMigration(id: string): WorkspaceMigration {
68
69
  id,
69
70
  description: `Migration ${id}`,
70
71
  run: mock(() => {}),
72
+ down: mock(() => {}),
71
73
  };
72
74
  }
73
75
 
@@ -244,6 +246,7 @@ describe("runWorkspaceMigrations", () => {
244
246
  // Simulate async work
245
247
  await Promise.resolve();
246
248
  }),
249
+ down: mock(() => {}),
247
250
  };
248
251
 
249
252
  await runWorkspaceMigrations(WORKSPACE_DIR, [asyncMigration]);
@@ -291,3 +294,114 @@ describe("runWorkspaceMigrations", () => {
291
294
  );
292
295
  });
293
296
  });
297
+
298
+ describe("rollbackWorkspaceMigrations", () => {
299
+ beforeEach(() => {
300
+ mockCheckpointContents = null;
301
+ readTextFileSyncFn.mockClear();
302
+ ensureDirFn.mockClear();
303
+ writeFileSyncFn.mockClear();
304
+ renameSyncFn.mockClear();
305
+ logWarnFn.mockClear();
306
+ logInfoFn.mockClear();
307
+ logErrorFn.mockClear();
308
+ });
309
+
310
+ test("rolls back migrations in reverse order", async () => {
311
+ const m1 = makeMigration("001");
312
+ const m2 = makeMigration("002");
313
+ const m3 = makeMigration("003");
314
+
315
+ // All three migrations are marked as completed in checkpoints
316
+ mockCheckpointContents = JSON.stringify({
317
+ applied: {
318
+ "001": { appliedAt: "2025-01-01T00:00:00.000Z", status: "completed" },
319
+ "002": { appliedAt: "2025-01-02T00:00:00.000Z", status: "completed" },
320
+ "003": { appliedAt: "2025-01-03T00:00:00.000Z", status: "completed" },
321
+ },
322
+ });
323
+
324
+ const callOrder: string[] = [];
325
+ (m2.down as ReturnType<typeof mock>).mockImplementation(() => {
326
+ callOrder.push("002");
327
+ });
328
+ (m3.down as ReturnType<typeof mock>).mockImplementation(() => {
329
+ callOrder.push("003");
330
+ });
331
+
332
+ // Roll back to m1 — should reverse m3 then m2, but not m1
333
+ await rollbackWorkspaceMigrations(WORKSPACE_DIR, [m1, m2, m3], "001");
334
+
335
+ expect(m3.down).toHaveBeenCalledTimes(1);
336
+ expect(m2.down).toHaveBeenCalledTimes(1);
337
+ expect(m1.down).not.toHaveBeenCalled();
338
+ expect(callOrder).toEqual(["003", "002"]);
339
+ });
340
+
341
+ test("handles crash during rollback (rolling_back status)", async () => {
342
+ const m1 = makeMigration("001");
343
+
344
+ // Simulate a crash during a previous rollback — m1 is left in rolling_back state
345
+ mockCheckpointContents = JSON.stringify({
346
+ applied: {
347
+ "001": {
348
+ appliedAt: "2025-01-01T00:00:00.000Z",
349
+ status: "rolling_back",
350
+ },
351
+ },
352
+ });
353
+
354
+ // runWorkspaceMigrations should clear the rolling_back status and re-run forward
355
+ await runWorkspaceMigrations(WORKSPACE_DIR, [m1]);
356
+
357
+ // The runner treats "rolling_back" like "started" — it clears the entry and re-runs
358
+ expect(m1.run).toHaveBeenCalledTimes(1);
359
+ });
360
+
361
+ test("removes checkpoints for rolled-back migrations", async () => {
362
+ const m1 = makeMigration("001");
363
+ const m2 = makeMigration("002");
364
+ const m3 = makeMigration("003");
365
+
366
+ mockCheckpointContents = JSON.stringify({
367
+ applied: {
368
+ "001": { appliedAt: "2025-01-01T00:00:00.000Z", status: "completed" },
369
+ "002": { appliedAt: "2025-01-02T00:00:00.000Z", status: "completed" },
370
+ "003": { appliedAt: "2025-01-03T00:00:00.000Z", status: "completed" },
371
+ },
372
+ });
373
+
374
+ await rollbackWorkspaceMigrations(WORKSPACE_DIR, [m1, m2, m3], "001");
375
+
376
+ // The last checkpoint write should only contain m1 (002 and 003 were rolled back)
377
+ const lastWriteCall = writeFileSyncFn.mock.calls.at(-1) as unknown[];
378
+ const finalCheckpoint = JSON.parse(lastWriteCall[1] as string);
379
+ expect(finalCheckpoint.applied["001"]).toBeDefined();
380
+ expect(finalCheckpoint.applied["002"]).toBeUndefined();
381
+ expect(finalCheckpoint.applied["003"]).toBeUndefined();
382
+ });
383
+
384
+ test("no-op when already at target", async () => {
385
+ const m1 = makeMigration("001");
386
+ const m2 = makeMigration("002");
387
+ const m3 = makeMigration("003");
388
+
389
+ mockCheckpointContents = JSON.stringify({
390
+ applied: {
391
+ "001": { appliedAt: "2025-01-01T00:00:00.000Z", status: "completed" },
392
+ "002": { appliedAt: "2025-01-02T00:00:00.000Z", status: "completed" },
393
+ "003": { appliedAt: "2025-01-03T00:00:00.000Z", status: "completed" },
394
+ },
395
+ });
396
+
397
+ // Target is the last migration — nothing to roll back
398
+ await rollbackWorkspaceMigrations(WORKSPACE_DIR, [m1, m2, m3], "003");
399
+
400
+ expect(m1.down).not.toHaveBeenCalled();
401
+ expect(m2.down).not.toHaveBeenCalled();
402
+ expect(m3.down).not.toHaveBeenCalled();
403
+
404
+ // No checkpoint writes should have occurred (no rollback happened)
405
+ expect(writeFileSyncFn).not.toHaveBeenCalled();
406
+ });
407
+ });
@@ -52,7 +52,7 @@ export class AcpAgentProcess {
52
52
 
53
53
  this.proc = spawn(this.config.command, this.config.args, {
54
54
  cwd,
55
- stdio: ["pipe", "pipe", "inherit"],
55
+ stdio: ["pipe", "pipe", "pipe"],
56
56
  env: { ...process.env, ...this.config.env },
57
57
  });
58
58
 
@@ -68,6 +68,14 @@ export class AcpAgentProcess {
68
68
  stream,
69
69
  );
70
70
 
71
+ // Capture stderr so agent crash details appear in logs
72
+ this.proc.stderr?.on("data", (chunk: Buffer) => {
73
+ const text = chunk.toString().trim();
74
+ if (text) {
75
+ log.error({ agentId: this.agentId, stderr: text }, "ACP agent stderr");
76
+ }
77
+ });
78
+
71
79
  // Handle process exit
72
80
  this.proc.on("exit", (code) => {
73
81
  this.handleProcessExit(code);
package/src/agent/loop.ts CHANGED
@@ -23,7 +23,7 @@ export interface AgentLoopConfig {
23
23
  maxTokens: number;
24
24
  maxInputTokens?: number; // context window size for tool result truncation
25
25
  thinking?: { enabled: boolean };
26
- effort: "low" | "medium" | "high";
26
+ effort: "low" | "medium" | "high" | "max";
27
27
  toolChoice?:
28
28
  | { type: "auto" }
29
29
  | { type: "any" }
@@ -40,6 +40,22 @@ const log = getLogger("guardian-request-resolvers");
40
40
  // Helpers
41
41
  // ---------------------------------------------------------------------------
42
42
 
43
+ /**
44
+ * Determines whether a Slack delivery should use ephemeral mode.
45
+ *
46
+ * Ephemeral messages (`chat.postEphemeral`) require a real channel ID
47
+ * (starts with `C` for public/private channels, or `D` for DM conversations).
48
+ * When the chat ID is a user ID (starts with `U`), `chat.postEphemeral` fails
49
+ * with `channel_not_found`. In that case the message is already going to a DM
50
+ * opened by `chat.postMessage`, so ephemeral isn't needed.
51
+ *
52
+ * Returns `true` only when the source channel is Slack AND the chatId is a
53
+ * shared channel (starts with `C`), meaning other users could see the message.
54
+ */
55
+ function shouldUseEphemeral(sourceChannel: string, chatId: string): boolean {
56
+ return sourceChannel === "slack" && chatId.startsWith("C");
57
+ }
58
+
43
59
  // ---------------------------------------------------------------------------
44
60
  // Types
45
61
  // ---------------------------------------------------------------------------
@@ -372,13 +388,22 @@ const accessRequestResolver: GuardianRequestResolver = {
372
388
  // Deliver denial notification and lifecycle signals when channel context is available
373
389
  if (channelDeliveryContext) {
374
390
  try {
391
+ const denialPayload: Parameters<typeof deliverChannelReply>[1] = {
392
+ chatId: requesterChatId,
393
+ text: "Your access request has been denied.",
394
+ assistantId,
395
+ };
396
+ // On Slack shared channels, deliver as ephemeral so only the requester sees the denial
397
+ if (
398
+ shouldUseEphemeral(channel, requesterChatId) &&
399
+ requesterExternalUserId
400
+ ) {
401
+ denialPayload.ephemeral = true;
402
+ denialPayload.user = requesterExternalUserId;
403
+ }
375
404
  await deliverChannelReply(
376
405
  channelDeliveryContext.replyCallbackUrl,
377
- {
378
- chatId: requesterChatId,
379
- text: "Your access request has been denied by the guardian.",
380
- assistantId,
381
- },
406
+ denialPayload,
382
407
  channelDeliveryContext.bearerToken,
383
408
  );
384
409
  } catch (err) {
@@ -435,7 +460,7 @@ const accessRequestResolver: GuardianRequestResolver = {
435
460
  desktopDeliverUrl,
436
461
  {
437
462
  chatId: targetChatId,
438
- text: "Your access request has been denied by the guardian.",
463
+ text: "Your access request has been denied.",
439
464
  assistantId,
440
465
  },
441
466
  desktopBearerToken,
@@ -520,18 +545,28 @@ const accessRequestResolver: GuardianRequestResolver = {
520
545
  let codeDelivered = true;
521
546
 
522
547
  // Deliver verification code to guardian
548
+ const codeText =
549
+ `You approved access for ${requesterExternalUserId}. ` +
550
+ `Give them this verification code: \`${session.secret}\`. ` +
551
+ `The code expires in 10 minutes.`;
523
552
  try {
524
- const codeText =
525
- `You approved access for ${requesterExternalUserId}. ` +
526
- `Give them this verification code: ${session.secret}. ` +
527
- `The code expires in 10 minutes.`;
553
+ const codePayload: Parameters<typeof deliverChannelReply>[1] = {
554
+ chatId: channelDeliveryContext.guardianChatId,
555
+ text: codeText,
556
+ assistantId,
557
+ };
558
+ // On Slack shared channels, deliver the verification code as ephemeral
559
+ // so only the guardian sees the secret — not all channel members.
560
+ if (
561
+ shouldUseEphemeral(channel, channelDeliveryContext.guardianChatId) &&
562
+ ctx.actor.actorExternalUserId
563
+ ) {
564
+ codePayload.ephemeral = true;
565
+ codePayload.user = ctx.actor.actorExternalUserId;
566
+ }
528
567
  await deliverChannelReply(
529
568
  channelDeliveryContext.replyCallbackUrl,
530
- {
531
- chatId: channelDeliveryContext.guardianChatId,
532
- text: codeText,
533
- assistantId,
534
- },
569
+ codePayload,
535
570
  channelDeliveryContext.bearerToken,
536
571
  );
537
572
  } catch (err) {
@@ -542,20 +577,85 @@ const accessRequestResolver: GuardianRequestResolver = {
542
577
  codeDelivered = false;
543
578
  }
544
579
 
545
- // Notify the requester
546
- if (codeDelivered) {
580
+ // If the guardian approved in a shared channel (not a DM), also send
581
+ // them a DM with the verification code for better privacy and
582
+ // discoverability. On Slack, posting to a user ID opens a DM.
583
+ const guardianUserId = ctx.actor.actorExternalUserId;
584
+ if (
585
+ codeDelivered &&
586
+ channel === "slack" &&
587
+ guardianUserId &&
588
+ !channelDeliveryContext.guardianChatId.startsWith("D")
589
+ ) {
590
+ // Strip threadTs from the callback URL — it belongs to the shared
591
+ // channel thread and would cause thread_not_found errors in the DM.
592
+ let dmCallbackUrl = channelDeliveryContext.replyCallbackUrl;
593
+ try {
594
+ const url = new URL(channelDeliveryContext.replyCallbackUrl);
595
+ url.searchParams.delete("threadTs");
596
+ dmCallbackUrl = url.toString();
597
+ } catch {
598
+ // Malformed URL — use as-is
599
+ }
600
+
547
601
  try {
548
602
  await deliverChannelReply(
549
- channelDeliveryContext.replyCallbackUrl,
603
+ dmCallbackUrl,
550
604
  {
551
- chatId: requesterChatId,
552
- text:
553
- "Your access request has been approved! " +
554
- "Please enter the 6-digit verification code you receive from the guardian.",
605
+ chatId: guardianUserId,
606
+ text: codeText,
555
607
  assistantId,
556
608
  },
557
609
  channelDeliveryContext.bearerToken,
558
610
  );
611
+ } catch (err) {
612
+ // Best-effort: the code was already delivered in the shared channel
613
+ log.warn(
614
+ { err, guardianUserId },
615
+ "Failed to send guardian DM confirmation with verification code",
616
+ );
617
+ }
618
+ }
619
+
620
+ // Notify the requester. For Slack, route to DM via the user ID and
621
+ // strip threadTs (which belongs to the guardian's channel thread).
622
+ const requesterTargetChatId =
623
+ channel === "slack" && requesterExternalUserId
624
+ ? requesterExternalUserId
625
+ : requesterChatId;
626
+ let requesterCallbackUrl = channelDeliveryContext.replyCallbackUrl;
627
+ if (channel === "slack" && requesterExternalUserId) {
628
+ try {
629
+ const url = new URL(channelDeliveryContext.replyCallbackUrl);
630
+ url.searchParams.delete("threadTs");
631
+ requesterCallbackUrl = url.toString();
632
+ } catch {
633
+ // Malformed URL — use as-is
634
+ }
635
+ }
636
+
637
+ if (codeDelivered) {
638
+ try {
639
+ const approvalPayload: Parameters<typeof deliverChannelReply>[1] = {
640
+ chatId: requesterTargetChatId,
641
+ text:
642
+ "Your access request has been approved! " +
643
+ "Please enter the 6-digit verification code you receive from the guardian.",
644
+ assistantId,
645
+ };
646
+ // On Slack shared channels, deliver as ephemeral so only the requester sees
647
+ if (
648
+ shouldUseEphemeral(channel, requesterChatId) &&
649
+ requesterExternalUserId
650
+ ) {
651
+ approvalPayload.ephemeral = true;
652
+ approvalPayload.user = requesterExternalUserId;
653
+ }
654
+ await deliverChannelReply(
655
+ requesterCallbackUrl,
656
+ approvalPayload,
657
+ channelDeliveryContext.bearerToken,
658
+ );
559
659
  requesterNotified = true;
560
660
  } catch (err) {
561
661
  log.error(
@@ -565,15 +665,23 @@ const accessRequestResolver: GuardianRequestResolver = {
565
665
  }
566
666
  } else {
567
667
  try {
668
+ const failurePayload: Parameters<typeof deliverChannelReply>[1] = {
669
+ chatId: requesterTargetChatId,
670
+ text:
671
+ "Your access request was approved, but we were unable to " +
672
+ "deliver the verification code. Please try again later.",
673
+ assistantId,
674
+ };
675
+ if (
676
+ shouldUseEphemeral(channel, requesterChatId) &&
677
+ requesterExternalUserId
678
+ ) {
679
+ failurePayload.ephemeral = true;
680
+ failurePayload.user = requesterExternalUserId;
681
+ }
568
682
  await deliverChannelReply(
569
- channelDeliveryContext.replyCallbackUrl,
570
- {
571
- chatId: requesterChatId,
572
- text:
573
- "Your access request was approved, but we were unable to " +
574
- "deliver the verification code. Please try again later.",
575
- assistantId,
576
- },
683
+ requesterCallbackUrl,
684
+ failurePayload,
577
685
  channelDeliveryContext.bearerToken,
578
686
  );
579
687
  } catch (err) {
@@ -635,8 +743,8 @@ const accessRequestResolver: GuardianRequestResolver = {
635
743
  }
636
744
 
637
745
  const verificationReplyText = requesterNotified
638
- ? `Access approved for ${requesterLabel}. Give them this verification code: ${session.secret}. The code expires in 10 minutes.`
639
- : `Access approved for ${requesterLabel}. Give them this verification code: ${session.secret}. The code expires in 10 minutes. I could not notify them automatically, so please tell them to send the code manually.`;
746
+ ? `Access approved for ${requesterLabel}. Give them this verification code: \`${session.secret}\`. The code expires in 10 minutes.`
747
+ : `Access approved for ${requesterLabel}. Give them this verification code: \`${session.secret}\`. The code expires in 10 minutes. I could not notify them automatically, so please tell them to send the code manually.`;
640
748
 
641
749
  return {
642
750
  ok: true,
@@ -686,13 +794,22 @@ const toolGrantRequestResolver: GuardianRequestResolver = {
686
794
 
687
795
  if (channelDeliveryContext && requesterChatId) {
688
796
  try {
689
- await deliverChannelReply(
690
- channelDeliveryContext.replyCallbackUrl,
797
+ const grantDenialPayload: Parameters<typeof deliverChannelReply>[1] =
691
798
  {
692
799
  chatId: requesterChatId,
693
800
  text: `Your request to use "${request.toolName}" has been denied by the guardian.`,
694
801
  assistantId,
695
- },
802
+ };
803
+ if (
804
+ shouldUseEphemeral(request.sourceChannel ?? "", requesterChatId) &&
805
+ request.requesterExternalUserId
806
+ ) {
807
+ grantDenialPayload.ephemeral = true;
808
+ grantDenialPayload.user = request.requesterExternalUserId;
809
+ }
810
+ await deliverChannelReply(
811
+ channelDeliveryContext.replyCallbackUrl,
812
+ grantDenialPayload,
696
813
  channelDeliveryContext.bearerToken,
697
814
  );
698
815
  } catch (err) {
@@ -775,13 +892,22 @@ const toolGrantRequestResolver: GuardianRequestResolver = {
775
892
  );
776
893
  } else if (channelDeliveryContext && requesterChatId) {
777
894
  try {
778
- await deliverChannelReply(
779
- channelDeliveryContext.replyCallbackUrl,
895
+ const grantApprovalPayload: Parameters<typeof deliverChannelReply>[1] =
780
896
  {
781
897
  chatId: requesterChatId,
782
898
  text: `Your request to use "${request.toolName}" has been approved. Please retry your request.`,
783
899
  assistantId,
784
- },
900
+ };
901
+ if (
902
+ shouldUseEphemeral(request.sourceChannel ?? "", requesterChatId) &&
903
+ request.requesterExternalUserId
904
+ ) {
905
+ grantApprovalPayload.ephemeral = true;
906
+ grantApprovalPayload.user = request.requesterExternalUserId;
907
+ }
908
+ await deliverChannelReply(
909
+ channelDeliveryContext.replyCallbackUrl,
910
+ grantApprovalPayload,
785
911
  channelDeliveryContext.bearerToken,
786
912
  );
787
913
  } catch (err) {