@vellumai/assistant 0.5.10 → 0.5.12

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 (395) hide show
  1. package/AGENTS.md +8 -0
  2. package/ARCHITECTURE.md +43 -43
  3. package/Dockerfile +3 -0
  4. package/docs/architecture/integrations.md +37 -42
  5. package/docs/architecture/memory.md +7 -12
  6. package/docs/credential-execution-service.md +9 -9
  7. package/docs/skills.md +1 -1
  8. package/node_modules/@vellumai/ces-contracts/src/__tests__/grants.test.ts +7 -7
  9. package/node_modules/@vellumai/ces-contracts/src/handles.ts +5 -4
  10. package/node_modules/@vellumai/credential-storage/src/index.ts +3 -3
  11. package/node_modules/@vellumai/credential-storage/src/static-credentials.ts +1 -1
  12. package/openapi.yaml +7208 -0
  13. package/package.json +2 -1
  14. package/scripts/generate-openapi.ts +562 -0
  15. package/src/__tests__/acp-session.test.ts +239 -44
  16. package/src/__tests__/assistant-feature-flag-guard.test.ts +8 -8
  17. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +5 -86
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -14
  19. package/src/__tests__/browser-skill-endstate.test.ts +1 -1
  20. package/src/__tests__/btw-routes.test.ts +8 -0
  21. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +10 -10
  22. package/src/__tests__/catalog-cache.test.ts +164 -0
  23. package/src/__tests__/catalog-search.test.ts +61 -0
  24. package/src/__tests__/channel-approvals.test.ts +7 -7
  25. package/src/__tests__/channel-readiness-service.test.ts +41 -0
  26. package/src/__tests__/cli-command-risk-guard.test.ts +181 -6
  27. package/src/__tests__/config-schema.test.ts +10 -2
  28. package/src/__tests__/context-memory-e2e.test.ts +2 -6
  29. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +396 -0
  30. package/src/__tests__/conversation-error.test.ts +3 -2
  31. package/src/__tests__/conversation-skill-tools.test.ts +1 -3
  32. package/src/__tests__/conversation-title-service.test.ts +2 -15
  33. package/src/__tests__/credential-execution-feature-gates.test.ts +4 -8
  34. package/src/__tests__/credential-execution-managed-contract.test.ts +8 -8
  35. package/src/__tests__/credential-security-e2e.test.ts +4 -4
  36. package/src/__tests__/credential-security-invariants.test.ts +12 -18
  37. package/src/__tests__/credential-vault-unit.test.ts +32 -34
  38. package/src/__tests__/credential-vault.test.ts +25 -33
  39. package/src/__tests__/credentials-cli.test.ts +3 -3
  40. package/src/__tests__/daemon-credential-client.test.ts +2 -2
  41. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -1
  42. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  43. package/src/__tests__/heartbeat-service.test.ts +35 -0
  44. package/src/__tests__/host-bash-proxy.test.ts +79 -0
  45. package/src/__tests__/host-cu-proxy.test.ts +90 -0
  46. package/src/__tests__/host-file-proxy.test.ts +89 -0
  47. package/src/__tests__/host-shell-tool.test.ts +1 -1
  48. package/src/__tests__/inline-skill-load-permissions.test.ts +3 -3
  49. package/src/__tests__/integration-status.test.ts +5 -5
  50. package/src/__tests__/list-messages-attachments.test.ts +171 -0
  51. package/src/__tests__/llm-request-log-turn-query.test.ts +64 -0
  52. package/src/__tests__/log-export-workspace.test.ts +1 -1
  53. package/src/__tests__/mcp-abort-signal.test.ts +205 -0
  54. package/src/__tests__/mcp-client-auth.test.ts +1 -1
  55. package/src/__tests__/memory-lifecycle-e2e.test.ts +2 -2
  56. package/src/__tests__/memory-recall-log-store.test.ts +182 -0
  57. package/src/__tests__/memory-recall-quality.test.ts +6 -8
  58. package/src/__tests__/memory-regressions.test.ts +53 -42
  59. package/src/__tests__/memory-retrieval.benchmark.test.ts +5 -9
  60. package/src/__tests__/messaging-send-tool.test.ts +5 -5
  61. package/src/__tests__/messaging-skill-split.test.ts +2 -17
  62. package/src/__tests__/notification-telegram-adapter.test.ts +125 -0
  63. package/src/__tests__/oauth-cli.test.ts +203 -649
  64. package/src/__tests__/oauth-provider-profiles.test.ts +55 -20
  65. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  66. package/src/__tests__/onboarding-template-contract.test.ts +2 -2
  67. package/src/__tests__/platform-callback-registration.test.ts +119 -0
  68. package/src/__tests__/secret-ingress-channel.test.ts +261 -0
  69. package/src/__tests__/secret-ingress-cli.test.ts +201 -0
  70. package/src/__tests__/secret-ingress-http.test.ts +312 -0
  71. package/src/__tests__/secret-ingress.test.ts +283 -0
  72. package/src/__tests__/secret-onetime-send.test.ts +4 -4
  73. package/src/__tests__/secret-routes-managed-proxy.test.ts +78 -0
  74. package/src/__tests__/secure-keys-managed-failover.test.ts +73 -0
  75. package/src/__tests__/skill-feature-flags-integration.test.ts +4 -4
  76. package/src/__tests__/skill-feature-flags.test.ts +11 -19
  77. package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
  78. package/src/__tests__/skill-load-inline-command.test.ts +3 -3
  79. package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
  80. package/src/__tests__/skill-memory.test.ts +2 -4
  81. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -4
  82. package/src/__tests__/skill-projection.benchmark.test.ts +1 -3
  83. package/src/__tests__/skills-uninstall.test.ts +2 -2
  84. package/src/__tests__/skills.test.ts +16 -2
  85. package/src/__tests__/slack-channel-config.test.ts +1 -1
  86. package/src/__tests__/slack-messaging-token-resolution.test.ts +22 -24
  87. package/src/__tests__/slack-share-routes.test.ts +5 -5
  88. package/src/__tests__/slack-skill.test.ts +5 -69
  89. package/src/__tests__/system-prompt.test.ts +39 -0
  90. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -1
  91. package/src/__tests__/workspace-migration-018-rekey-compound-credential-keys.test.ts +181 -0
  92. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +5 -4
  93. package/src/acp/client-handler.ts +113 -31
  94. package/src/acp/session-manager.ts +29 -27
  95. package/src/approvals/guardian-request-resolvers.ts +1 -1
  96. package/src/cli/AGENTS.md +113 -0
  97. package/src/cli/commands/autonomy.ts +3 -5
  98. package/src/cli/commands/browser-relay.ts +2 -17
  99. package/src/cli/commands/contacts.ts +6 -4
  100. package/src/cli/commands/conversations.ts +13 -1
  101. package/src/cli/commands/credential-execution.ts +17 -3
  102. package/src/cli/commands/credentials.ts +2 -8
  103. package/src/cli/commands/memory.ts +2 -3
  104. package/src/cli/commands/oauth/__tests__/connect.test.ts +706 -0
  105. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +686 -0
  106. package/src/cli/commands/oauth/__tests__/mode.test.ts +625 -0
  107. package/src/cli/commands/oauth/__tests__/ping.test.ts +631 -0
  108. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +574 -0
  109. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +416 -0
  110. package/src/cli/commands/oauth/__tests__/status.test.ts +551 -0
  111. package/src/cli/commands/oauth/__tests__/token.test.ts +420 -0
  112. package/src/cli/commands/oauth/apps.ts +87 -50
  113. package/src/cli/commands/oauth/connect.ts +405 -0
  114. package/src/cli/commands/oauth/disconnect.ts +285 -0
  115. package/src/cli/commands/oauth/index.ts +62 -20
  116. package/src/cli/commands/oauth/mode.ts +251 -0
  117. package/src/cli/commands/oauth/ping.ts +196 -0
  118. package/src/cli/commands/oauth/providers.ts +589 -55
  119. package/src/cli/commands/oauth/request.ts +564 -0
  120. package/src/cli/commands/oauth/shared.ts +114 -0
  121. package/src/cli/commands/oauth/status.ts +191 -0
  122. package/src/cli/commands/oauth/token.ts +150 -0
  123. package/src/cli/commands/platform/connect.ts +104 -0
  124. package/src/cli/commands/platform/disconnect.ts +118 -0
  125. package/src/cli/commands/platform/index.ts +252 -0
  126. package/src/cli/commands/sequence.ts +5 -4
  127. package/src/cli/commands/shotgun.ts +16 -0
  128. package/src/cli/commands/skills.ts +173 -41
  129. package/src/cli/commands/usage.ts +5 -11
  130. package/src/cli/lib/daemon-credential-client.ts +22 -38
  131. package/src/cli/program.ts +1 -1
  132. package/src/cli.ts +82 -17
  133. package/src/config/assistant-feature-flags.ts +77 -18
  134. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  135. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -1
  136. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  137. package/src/config/bundled-skills/conversations/SKILL.md +20 -0
  138. package/src/config/bundled-skills/conversations/TOOLS.json +23 -0
  139. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +66 -0
  140. package/src/config/bundled-skills/gmail/SKILL.md +13 -13
  141. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +3 -3
  142. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +2 -2
  143. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +1 -1
  144. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +1 -1
  145. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +1 -1
  146. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +1 -1
  147. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +2 -2
  148. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +1 -1
  149. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +1 -1
  150. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  151. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +1 -1
  152. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +1 -1
  153. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +1 -1
  154. package/src/config/bundled-skills/google-calendar/SKILL.md +10 -4
  155. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  156. package/src/config/bundled-skills/messaging/SKILL.md +19 -42
  157. package/src/config/bundled-skills/messaging/TOOLS.json +9 -9
  158. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  159. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -2
  160. package/src/config/bundled-skills/messaging/tools/shared.ts +5 -6
  161. package/src/config/bundled-skills/notifications/SKILL.md +1 -1
  162. package/src/config/bundled-skills/schedule/SKILL.md +2 -2
  163. package/src/config/bundled-skills/settings/SKILL.md +5 -3
  164. package/src/config/bundled-skills/settings/TOOLS.json +17 -0
  165. package/src/config/bundled-skills/settings/tools/avatar-get.ts +50 -0
  166. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +7 -0
  167. package/src/config/bundled-skills/settings/tools/avatar-update.ts +6 -1
  168. package/src/config/bundled-skills/settings/tools/identity-avatar.ts +55 -0
  169. package/src/config/bundled-skills/skills-catalog/SKILL.md +3 -3
  170. package/src/config/bundled-skills/slack/SKILL.md +58 -44
  171. package/src/config/bundled-tool-registry.ts +7 -19
  172. package/src/config/env.ts +5 -1
  173. package/src/config/feature-flag-registry.json +58 -42
  174. package/src/config/loader.ts +4 -0
  175. package/src/config/schemas/platform.ts +0 -8
  176. package/src/config/schemas/security.ts +9 -1
  177. package/src/config/schemas/services.ts +1 -1
  178. package/src/config/skill-state.ts +1 -3
  179. package/src/config/skills.ts +2 -4
  180. package/src/credential-execution/client.ts +1 -1
  181. package/src/credential-execution/feature-gates.ts +9 -16
  182. package/src/credential-execution/process-manager.ts +12 -0
  183. package/src/daemon/config-watcher.ts +4 -0
  184. package/src/daemon/conversation-agent-loop-handlers.ts +10 -0
  185. package/src/daemon/conversation-agent-loop.ts +51 -2
  186. package/src/daemon/conversation-error.ts +36 -6
  187. package/src/daemon/conversation-memory.ts +0 -1
  188. package/src/daemon/conversation-messaging.ts +9 -0
  189. package/src/daemon/conversation-runtime-assembly.ts +33 -0
  190. package/src/daemon/conversation-surfaces.ts +120 -14
  191. package/src/daemon/conversation.ts +5 -0
  192. package/src/daemon/handlers/config-slack-channel.ts +43 -1
  193. package/src/daemon/handlers/conversations.ts +41 -33
  194. package/src/daemon/handlers/skills.ts +148 -3
  195. package/src/daemon/host-bash-proxy.ts +16 -0
  196. package/src/daemon/host-cu-proxy.ts +16 -0
  197. package/src/daemon/host-file-proxy.ts +16 -0
  198. package/src/daemon/lifecycle.ts +73 -3
  199. package/src/daemon/message-types/acp.ts +0 -15
  200. package/src/daemon/message-types/conversations.ts +1 -0
  201. package/src/daemon/message-types/guardian-actions.ts +2 -0
  202. package/src/daemon/message-types/host-bash.ts +6 -1
  203. package/src/daemon/message-types/host-cu.ts +6 -1
  204. package/src/daemon/message-types/host-file.ts +6 -1
  205. package/src/daemon/message-types/integrations.ts +0 -1
  206. package/src/daemon/message-types/memory.ts +0 -1
  207. package/src/daemon/message-types/messages.ts +9 -1
  208. package/src/daemon/message-types/schedules.ts +9 -0
  209. package/src/daemon/server.ts +48 -9
  210. package/src/email/feature-gate.ts +3 -3
  211. package/src/heartbeat/heartbeat-service.ts +48 -0
  212. package/src/hooks/cli.ts +74 -0
  213. package/src/inbound/platform-callback-registration.ts +68 -19
  214. package/src/mcp/client.ts +6 -1
  215. package/src/mcp/manager.ts +2 -1
  216. package/src/mcp/mcp-oauth-provider.ts +3 -3
  217. package/src/memory/app-store.ts +3 -3
  218. package/src/memory/conversation-crud.ts +213 -0
  219. package/src/memory/conversation-key-store.ts +26 -0
  220. package/src/memory/conversation-title-service.ts +7 -17
  221. package/src/memory/db-init.ts +24 -0
  222. package/src/memory/embedding-local.ts +47 -2
  223. package/src/memory/indexer.ts +13 -10
  224. package/src/memory/items-extractor.ts +12 -4
  225. package/src/memory/job-utils.ts +5 -0
  226. package/src/memory/jobs-store.ts +10 -2
  227. package/src/memory/journal-memory.ts +6 -2
  228. package/src/memory/llm-request-log-store.ts +88 -21
  229. package/src/memory/memory-recall-log-store.ts +128 -0
  230. package/src/memory/migrations/194-memory-recall-logs.ts +50 -0
  231. package/src/memory/migrations/195-oauth-providers-ping-config.ts +23 -0
  232. package/src/memory/migrations/196-messages-conversation-created-at-index.ts +9 -0
  233. package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +186 -0
  234. package/src/memory/migrations/197-oauth-providers-behavior-columns.ts +29 -0
  235. package/src/memory/migrations/198-drop-setup-skill-id-column.ts +11 -0
  236. package/src/memory/migrations/index.ts +6 -0
  237. package/src/memory/migrations/registry.ts +8 -0
  238. package/src/memory/retriever.test.ts +4 -5
  239. package/src/memory/schema/infrastructure.ts +31 -0
  240. package/src/memory/schema/oauth.ts +14 -0
  241. package/src/messaging/provider.ts +13 -12
  242. package/src/messaging/providers/gmail/adapter.ts +44 -35
  243. package/src/messaging/providers/slack/adapter.ts +63 -33
  244. package/src/messaging/providers/telegram-bot/adapter.ts +7 -9
  245. package/src/messaging/providers/whatsapp/adapter.ts +6 -8
  246. package/src/notifications/adapters/telegram.ts +78 -2
  247. package/src/oauth/__tests__/identity-verifier.test.ts +464 -0
  248. package/src/oauth/byo-connection.test.ts +22 -24
  249. package/src/oauth/connect-orchestrator.ts +79 -64
  250. package/src/oauth/connect-types.ts +7 -65
  251. package/src/oauth/connection-resolver.test.ts +13 -13
  252. package/src/oauth/connection-resolver.ts +3 -4
  253. package/src/oauth/identity-verifier.ts +177 -0
  254. package/src/oauth/manual-token-connection.ts +5 -5
  255. package/src/oauth/oauth-store.ts +251 -5
  256. package/src/oauth/platform-connection.test.ts +56 -6
  257. package/src/oauth/platform-connection.ts +8 -1
  258. package/src/oauth/seed-providers.ts +256 -34
  259. package/src/permissions/checker.ts +129 -3
  260. package/src/permissions/trust-client.ts +2 -2
  261. package/src/platform/client.ts +2 -2
  262. package/src/prompts/journal-context.ts +6 -1
  263. package/src/prompts/system-prompt.ts +43 -9
  264. package/src/prompts/templates/BOOTSTRAP.md +16 -5
  265. package/src/providers/anthropic/client.ts +139 -28
  266. package/src/runtime/auth/__tests__/middleware.test.ts +19 -0
  267. package/src/runtime/auth/route-policy.ts +0 -1
  268. package/src/runtime/btw-sidechain.ts +7 -1
  269. package/src/runtime/channel-approvals.ts +2 -2
  270. package/src/runtime/channel-readiness-service.ts +30 -7
  271. package/src/runtime/guardian-action-service.ts +7 -2
  272. package/src/runtime/http-router.ts +31 -0
  273. package/src/runtime/http-server.ts +26 -7
  274. package/src/runtime/http-types.ts +9 -0
  275. package/src/runtime/pending-interactions.ts +21 -3
  276. package/src/runtime/routes/acp-routes.ts +46 -28
  277. package/src/runtime/routes/app-management-routes.ts +123 -0
  278. package/src/runtime/routes/app-routes.ts +31 -0
  279. package/src/runtime/routes/approval-routes.ts +108 -3
  280. package/src/runtime/routes/attachment-routes.ts +45 -0
  281. package/src/runtime/routes/avatar-routes.ts +16 -0
  282. package/src/runtime/routes/brain-graph-routes.ts +18 -0
  283. package/src/runtime/routes/btw-routes.ts +20 -0
  284. package/src/runtime/routes/call-routes.ts +81 -0
  285. package/src/runtime/routes/channel-readiness-routes.ts +48 -7
  286. package/src/runtime/routes/channel-routes.ts +18 -0
  287. package/src/runtime/routes/channel-verification-routes.ts +49 -1
  288. package/src/runtime/routes/contact-routes.ts +77 -0
  289. package/src/runtime/routes/conversation-attention-routes.ts +37 -0
  290. package/src/runtime/routes/conversation-management-routes.ts +125 -0
  291. package/src/runtime/routes/conversation-query-routes.ts +78 -0
  292. package/src/runtime/routes/conversation-routes.ts +191 -39
  293. package/src/runtime/routes/conversation-starter-routes.ts +29 -0
  294. package/src/runtime/routes/debug-routes.ts +23 -0
  295. package/src/runtime/routes/diagnostics-routes.ts +30 -0
  296. package/src/runtime/routes/documents-routes.ts +42 -0
  297. package/src/runtime/routes/events-routes.ts +10 -0
  298. package/src/runtime/routes/global-search-routes.ts +35 -0
  299. package/src/runtime/routes/guardian-action-routes.ts +61 -3
  300. package/src/runtime/routes/guardian-approval-prompt.ts +77 -2
  301. package/src/runtime/routes/heartbeat-routes.ts +278 -0
  302. package/src/runtime/routes/host-bash-routes.ts +16 -1
  303. package/src/runtime/routes/host-cu-routes.ts +23 -1
  304. package/src/runtime/routes/host-file-routes.ts +18 -1
  305. package/src/runtime/routes/identity-routes.ts +35 -0
  306. package/src/runtime/routes/inbound-message-handler.ts +46 -25
  307. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -8
  308. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +30 -2
  309. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -2
  310. package/src/runtime/routes/integrations/slack/share.ts +1 -1
  311. package/src/runtime/routes/integrations/twilio.ts +32 -22
  312. package/src/runtime/routes/invite-routes.ts +83 -0
  313. package/src/runtime/routes/log-export-routes.ts +14 -0
  314. package/src/runtime/routes/memory-item-routes.ts +99 -1
  315. package/src/runtime/routes/migration-rollback-routes.ts +25 -0
  316. package/src/runtime/routes/migration-routes.ts +40 -0
  317. package/src/runtime/routes/notification-routes.ts +20 -0
  318. package/src/runtime/routes/oauth-apps.ts +13 -4
  319. package/src/runtime/routes/pairing-routes.ts +15 -0
  320. package/src/runtime/routes/recording-routes.ts +72 -0
  321. package/src/runtime/routes/schedule-routes.ts +77 -5
  322. package/src/runtime/routes/secret-routes.ts +99 -14
  323. package/src/runtime/routes/settings-routes.ts +102 -19
  324. package/src/runtime/routes/skills-routes.ts +141 -18
  325. package/src/runtime/routes/subagents-routes.ts +38 -3
  326. package/src/runtime/routes/surface-action-routes.ts +66 -24
  327. package/src/runtime/routes/surface-content-routes.ts +20 -0
  328. package/src/runtime/routes/telemetry-routes.ts +12 -0
  329. package/src/runtime/routes/trace-event-routes.ts +25 -0
  330. package/src/runtime/routes/trust-rules-routes.ts +46 -0
  331. package/src/runtime/routes/tts-routes.ts +15 -4
  332. package/src/runtime/routes/upgrade-broadcast-routes.ts +38 -0
  333. package/src/runtime/routes/usage-routes.ts +59 -0
  334. package/src/runtime/routes/watch-routes.ts +28 -0
  335. package/src/runtime/routes/work-items-routes.ts +59 -0
  336. package/src/runtime/routes/workspace-commit-routes.ts +12 -0
  337. package/src/runtime/routes/workspace-routes.ts +102 -0
  338. package/src/schedule/integration-status.ts +2 -2
  339. package/src/schedule/scheduler.ts +7 -1
  340. package/src/security/AGENTS.md +7 -0
  341. package/src/security/ces-rpc-credential-backend.ts +19 -16
  342. package/src/security/credential-backend.ts +1 -1
  343. package/src/security/encrypted-store.ts +3 -3
  344. package/src/security/oauth-completion-page.ts +153 -0
  345. package/src/security/oauth2.ts +58 -17
  346. package/src/security/secret-ingress.ts +174 -0
  347. package/src/security/secret-patterns.ts +133 -0
  348. package/src/security/secret-scanner.ts +28 -117
  349. package/src/security/secure-keys.ts +207 -7
  350. package/src/security/token-manager.ts +3 -6
  351. package/src/signals/bash.ts +6 -1
  352. package/src/signals/confirm.ts +12 -8
  353. package/src/signals/user-message.ts +18 -3
  354. package/src/skills/catalog-cache.ts +44 -0
  355. package/src/skills/catalog-search.ts +18 -0
  356. package/src/skills/skill-memory.ts +1 -2
  357. package/src/tasks/task-runner.ts +7 -1
  358. package/src/tools/credentials/broker.ts +1 -1
  359. package/src/tools/credentials/metadata-store.ts +1 -1
  360. package/src/tools/credentials/post-connect-hooks.ts +1 -1
  361. package/src/tools/credentials/vault.ts +36 -48
  362. package/src/tools/host-terminal/host-shell.ts +16 -3
  363. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  364. package/src/tools/memory/definitions.ts +1 -1
  365. package/src/tools/memory/handlers.test.ts +2 -4
  366. package/src/tools/skills/load.ts +1 -1
  367. package/src/tools/skills/sandbox-runner.ts +16 -3
  368. package/src/tools/terminal/safe-env.ts +7 -0
  369. package/src/tools/terminal/shell.ts +16 -3
  370. package/src/tools/tool-manifest.ts +1 -1
  371. package/src/util/log-redact.ts +9 -34
  372. package/src/util/logger.ts +11 -1
  373. package/src/util/sentry-log-stream.ts +51 -0
  374. package/src/watcher/providers/github.ts +2 -2
  375. package/src/watcher/providers/gmail.ts +1 -1
  376. package/src/watcher/providers/google-calendar.ts +1 -1
  377. package/src/watcher/providers/linear.ts +2 -2
  378. package/src/workspace/migrations/011-backfill-installation-id.ts +5 -3
  379. package/src/workspace/migrations/020-rename-oauth-skill-dirs.ts +119 -0
  380. package/src/workspace/migrations/registry.ts +2 -0
  381. package/docs/architecture/keychain-broker.md +0 -68
  382. package/src/cli/commands/oauth/connections.ts +0 -734
  383. package/src/cli/commands/oauth/platform.ts +0 -525
  384. package/src/cli/commands/platform.ts +0 -176
  385. package/src/config/bundled-skills/slack/TOOLS.json +0 -272
  386. package/src/config/bundled-skills/slack/tools/shared.ts +0 -34
  387. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +0 -27
  388. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +0 -38
  389. package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +0 -146
  390. package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +0 -105
  391. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +0 -26
  392. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +0 -27
  393. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +0 -25
  394. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +0 -372
  395. package/src/oauth/provider-behaviors.ts +0 -634
@@ -8,6 +8,8 @@
8
8
  * GET /v1/channel-verification-sessions/status — check guardian binding status
9
9
  */
10
10
 
11
+ import { z } from "zod";
12
+
11
13
  import type { ChannelId } from "../../channels/types.js";
12
14
  import {
13
15
  createInboundChallenge,
@@ -243,31 +245,77 @@ export async function handleRevokeVerificationBinding(
243
245
 
244
246
  export function channelVerificationRouteDefinitions(): RouteDefinition[] {
245
247
  return [
246
- // Channel verification (unified session API)
247
248
  {
248
249
  endpoint: "channel-verification-sessions",
249
250
  method: "POST",
251
+ summary: "Create verification session",
252
+ description:
253
+ "Create a channel verification session (inbound challenge, outbound, or trusted contact).",
254
+ tags: ["channel-verification"],
255
+ requestBody: z.object({
256
+ channel: z.string().describe("Channel ID"),
257
+ destination: z.string().describe("Outbound destination"),
258
+ rebind: z.boolean(),
259
+ conversationId: z.string(),
260
+ originConversationId: z.string(),
261
+ purpose: z.string().describe("guardian or trusted_contact"),
262
+ contactChannelId: z.string(),
263
+ }),
250
264
  handler: async ({ req, authContext }) =>
251
265
  handleCreateVerificationSession(req, authContext.assistantId),
252
266
  },
253
267
  {
254
268
  endpoint: "channel-verification-sessions/resend",
255
269
  method: "POST",
270
+ summary: "Resend verification code",
271
+ description: "Resend the outbound verification code.",
272
+ tags: ["channel-verification"],
273
+ requestBody: z.object({
274
+ channel: z.string(),
275
+ originConversationId: z.string().optional(),
276
+ }),
256
277
  handler: async ({ req }) => handleResendVerificationSession(req),
257
278
  },
258
279
  {
259
280
  endpoint: "channel-verification-sessions",
260
281
  method: "DELETE",
282
+ summary: "Cancel verification sessions",
283
+ description:
284
+ "Cancel all active inbound and outbound verification sessions.",
285
+ tags: ["channel-verification"],
286
+ requestBody: z.object({
287
+ channel: z.string(),
288
+ }),
289
+ responseBody: z.object({
290
+ success: z.boolean(),
291
+ channel: z.string(),
292
+ }),
261
293
  handler: async ({ req }) => handleCancelVerificationSession(req),
262
294
  },
263
295
  {
264
296
  endpoint: "channel-verification-sessions/revoke",
265
297
  method: "POST",
298
+ summary: "Revoke verification binding",
299
+ description: "Cancel all sessions and revoke the guardian binding.",
300
+ tags: ["channel-verification"],
301
+ requestBody: z.object({
302
+ channel: z.string(),
303
+ }),
266
304
  handler: async ({ req }) => handleRevokeVerificationBinding(req),
267
305
  },
268
306
  {
269
307
  endpoint: "channel-verification-sessions/status",
270
308
  method: "GET",
309
+ summary: "Get verification status",
310
+ description: "Check guardian binding and verification session status.",
311
+ tags: ["channel-verification"],
312
+ queryParams: [
313
+ {
314
+ name: "channel",
315
+ schema: { type: "string" },
316
+ description: "Optional channel ID filter",
317
+ },
318
+ ],
271
319
  handler: ({ url }) => handleGetVerificationStatus(url),
272
320
  },
273
321
  ];
@@ -9,6 +9,8 @@
9
9
  * PATCH /v1/contact-channels/:contactChannelId — update a contact channel's status/policy
10
10
  */
11
11
 
12
+ import { z } from "zod";
13
+
12
14
  import {
13
15
  deleteContact,
14
16
  getAssistantContactMetadata,
@@ -417,22 +419,82 @@ export function contactRouteDefinitions(): RouteDefinition[] {
417
419
  {
418
420
  endpoint: "contacts",
419
421
  method: "GET",
422
+ summary: "List contacts",
423
+ description:
424
+ "Return all contacts, optionally filtered by type or channel status.",
425
+ tags: ["contacts"],
426
+ responseBody: z.object({
427
+ ok: z.boolean(),
428
+ contacts: z
429
+ .array(z.unknown())
430
+ .describe("Contact objects with channels and metadata"),
431
+ }),
420
432
  handler: ({ url }) => handleListContacts(url),
421
433
  },
422
434
  {
423
435
  endpoint: "contacts",
424
436
  method: "POST",
437
+ summary: "Create or update a contact",
438
+ description:
439
+ "Create a new contact or update an existing one. Supports upsert by contactId or channel handle.",
440
+ tags: ["contacts"],
441
+ requestBody: z.object({
442
+ contactId: z.string().describe("Existing contact ID (for update)"),
443
+ displayName: z.string().describe("Display name"),
444
+ channels: z
445
+ .array(z.unknown())
446
+ .describe("Channel objects with channelId, handle, displayName"),
447
+ assistantMetadata: z
448
+ .object({})
449
+ .passthrough()
450
+ .describe("Assistant-side metadata"),
451
+ }),
452
+ responseBody: z.object({
453
+ ok: z.boolean(),
454
+ contact: z
455
+ .object({})
456
+ .passthrough()
457
+ .describe("Created or updated contact"),
458
+ }),
425
459
  handler: async ({ req }) => handleUpsertContact(req),
426
460
  },
427
461
  {
428
462
  endpoint: "contacts/merge",
429
463
  method: "POST",
464
+ summary: "Merge two contacts",
465
+ description: "Merge two contacts, keeping one and absorbing the other.",
466
+ tags: ["contacts"],
467
+ requestBody: z.object({
468
+ keepId: z.string().describe("ID of the contact to keep"),
469
+ mergeId: z
470
+ .string()
471
+ .describe("ID of the contact to merge into the kept one"),
472
+ }),
473
+ responseBody: z.object({
474
+ ok: z.boolean(),
475
+ contact: z.object({}).passthrough().describe("Merged contact"),
476
+ }),
430
477
  handler: async ({ req }) => handleMergeContacts(req),
431
478
  },
432
479
  {
433
480
  endpoint: "contact-channels/:contactChannelId",
434
481
  method: "PATCH",
435
482
  policyKey: "contact-channels",
483
+ summary: "Update a contact channel",
484
+ description: "Update status, policy, or reason on a contact's channel.",
485
+ tags: ["contacts"],
486
+ requestBody: z.object({
487
+ status: z.string().describe("Channel status"),
488
+ policy: z.string().describe("Channel policy"),
489
+ reason: z.string().describe("Reason for the change"),
490
+ }),
491
+ responseBody: z.object({
492
+ ok: z.boolean(),
493
+ contact: z
494
+ .object({})
495
+ .passthrough()
496
+ .describe("Updated contact (if applicable)"),
497
+ }),
436
498
  handler: async ({ req, params }) =>
437
499
  handleUpdateContactChannel(req, params.contactChannelId),
438
500
  },
@@ -450,12 +512,27 @@ export function contactCatchAllRouteDefinitions(): RouteDefinition[] {
450
512
  endpoint: "contacts/:id",
451
513
  method: "GET",
452
514
  policyKey: "contacts",
515
+ summary: "Get a contact",
516
+ description:
517
+ "Return a single contact with its channels and assistant metadata.",
518
+ tags: ["contacts"],
519
+ responseBody: z.object({
520
+ ok: z.boolean(),
521
+ contact: z.object({}).passthrough().describe("Contact details"),
522
+ assistantMetadata: z
523
+ .object({})
524
+ .passthrough()
525
+ .describe("Assistant-side metadata"),
526
+ }),
453
527
  handler: ({ params }) => handleGetContact(params.id),
454
528
  },
455
529
  {
456
530
  endpoint: "contacts/:id",
457
531
  method: "DELETE",
458
532
  policyKey: "contacts",
533
+ summary: "Delete a contact",
534
+ description: "Delete a contact by ID.",
535
+ tags: ["contacts"],
459
536
  handler: ({ params }) => handleDeleteContact(params.id),
460
537
  },
461
538
  ];
@@ -4,6 +4,8 @@
4
4
  * useful for assistant/LLM reporting and UI indicators.
5
5
  */
6
6
 
7
+ import { z } from "zod";
8
+
7
9
  import {
8
10
  type AttentionFilterState,
9
11
  listConversationAttention,
@@ -134,6 +136,41 @@ export function conversationAttentionRouteDefinitions(): RouteDefinition[] {
134
136
  {
135
137
  endpoint: "conversations/attention",
136
138
  method: "GET",
139
+ summary: "List conversation attention states",
140
+ description:
141
+ "Return attention state (seen/unseen) for conversations, with pagination.",
142
+ tags: ["conversations"],
143
+ queryParams: [
144
+ {
145
+ name: "state",
146
+ schema: { type: "string" },
147
+ description: "Filter: seen, unseen, or all (default all)",
148
+ },
149
+ {
150
+ name: "source",
151
+ schema: { type: "string" },
152
+ description: "Filter by source (default all)",
153
+ },
154
+ {
155
+ name: "channel",
156
+ schema: { type: "string" },
157
+ description: "Filter by source channel",
158
+ },
159
+ {
160
+ name: "limit",
161
+ schema: { type: "integer" },
162
+ description: "Max results (1–100, default 20)",
163
+ },
164
+ {
165
+ name: "before",
166
+ schema: { type: "number" },
167
+ description: "Cursor for pagination (timestamp)",
168
+ },
169
+ ],
170
+ responseBody: z.object({
171
+ conversations: z.array(z.unknown()).describe("Attention state objects"),
172
+ hasMore: z.boolean(),
173
+ }),
137
174
  handler: ({ url }) => handleListConversationAttention(url),
138
175
  },
139
176
  ];
@@ -14,9 +14,13 @@
14
14
  * POST /v1/conversations/reorder — reorder / pin conversations
15
15
  */
16
16
 
17
+ import { z } from "zod";
18
+
17
19
  import {
18
20
  batchSetDisplayOrders,
21
+ countConversationsByScheduleJobId,
19
22
  deleteConversation,
23
+ getConversation,
20
24
  PRIVATE_CONVERSATION_FORK_ERROR,
21
25
  wipeConversation,
22
26
  } from "../../memory/conversation-crud.js";
@@ -27,6 +31,7 @@ import {
27
31
  setConversationKeyIfAbsent,
28
32
  } from "../../memory/conversation-key-store.js";
29
33
  import { enqueueMemoryJob } from "../../memory/jobs-store.js";
34
+ import { deleteSchedule } from "../../schedule/schedule-store.js";
30
35
  import { UserError } from "../../util/errors.js";
31
36
  import { getLogger } from "../../util/logger.js";
32
37
  import { httpError } from "../http-errors.js";
@@ -73,6 +78,22 @@ export function conversationManagementRouteDefinitions(
73
78
  endpoint: "conversations",
74
79
  method: "POST",
75
80
  policyKey: "conversations",
81
+ summary: "Create a conversation",
82
+ description: "Create or get an existing conversation by key.",
83
+ tags: ["conversations"],
84
+ requestBody: z.object({
85
+ conversationKey: z
86
+ .string()
87
+ .describe("Idempotency key for the conversation"),
88
+ conversationType: z
89
+ .string()
90
+ .describe("'standard' (default) or 'private'"),
91
+ }),
92
+ responseBody: z.object({
93
+ id: z.string(),
94
+ conversationKey: z.string(),
95
+ conversationType: z.string(),
96
+ }),
76
97
  handler: async ({ req }) => {
77
98
  let body: { conversationKey?: string; conversationType?: string } = {};
78
99
  try {
@@ -111,6 +132,17 @@ export function conversationManagementRouteDefinitions(
111
132
  endpoint: "conversations/fork",
112
133
  method: "POST",
113
134
  policyKey: "conversations/fork",
135
+ summary: "Fork a conversation",
136
+ description:
137
+ "Create a copy of a conversation, optionally truncated at a specific message.",
138
+ tags: ["conversations"],
139
+ requestBody: z.object({
140
+ conversationId: z.string(),
141
+ throughMessageId: z
142
+ .string()
143
+ .describe("Truncate the fork at this message")
144
+ .optional(),
145
+ }),
114
146
  handler: async ({ req }) => {
115
147
  if (!deps.forkConversation) {
116
148
  return httpError(
@@ -172,6 +204,21 @@ export function conversationManagementRouteDefinitions(
172
204
  endpoint: "conversations/switch",
173
205
  method: "POST",
174
206
  policyKey: "conversations/switch",
207
+ summary: "Switch active conversation",
208
+ description: "Set the active conversation for the current session.",
209
+ tags: ["conversations"],
210
+ requestBody: z.object({
211
+ conversationId: z.string(),
212
+ conversationKey: z
213
+ .string()
214
+ .describe("Optional key to register for this conversation")
215
+ .optional(),
216
+ }),
217
+ responseBody: z.object({
218
+ conversationId: z.string(),
219
+ title: z.string(),
220
+ conversationType: z.string(),
221
+ }),
175
222
  handler: async ({ req }) => {
176
223
  const body = (await req.json()) as {
177
224
  conversationId?: string;
@@ -206,6 +253,12 @@ export function conversationManagementRouteDefinitions(
206
253
  endpoint: "conversations/:id/name",
207
254
  method: "PATCH",
208
255
  policyKey: "conversations/name",
256
+ summary: "Rename a conversation",
257
+ description: "Update the display name of a conversation.",
258
+ tags: ["conversations"],
259
+ requestBody: z.object({
260
+ name: z.string(),
261
+ }),
209
262
  handler: async ({ req, params }) => {
210
263
  const body = (await req.json()) as { name?: string };
211
264
  const name = body.name;
@@ -227,6 +280,10 @@ export function conversationManagementRouteDefinitions(
227
280
  endpoint: "conversations",
228
281
  method: "DELETE",
229
282
  policyKey: "conversations/clear-all",
283
+ summary: "Clear all conversations",
284
+ description:
285
+ "Permanently delete ALL conversations, messages, and memory. Requires X-Confirm-Destructive header.",
286
+ tags: ["conversations"],
230
287
  handler: ({ req }) => {
231
288
  const confirm = req.headers.get("x-confirm-destructive");
232
289
  if (confirm !== "clear-all-conversations") {
@@ -245,6 +302,16 @@ export function conversationManagementRouteDefinitions(
245
302
  endpoint: "conversations/:id/wipe",
246
303
  method: "POST",
247
304
  policyKey: "conversations/wipe",
305
+ summary: "Wipe a conversation",
306
+ description:
307
+ "Delete all messages in a conversation and revert associated memory changes.",
308
+ tags: ["conversations"],
309
+ responseBody: z.object({
310
+ wiped: z.boolean(),
311
+ unsupersededItems: z.number().int(),
312
+ deletedSummaries: z.number().int(),
313
+ cancelledJobs: z.number().int(),
314
+ }),
248
315
  handler: async ({ params }) => {
249
316
  const resolvedId = resolveConversationId(params.id);
250
317
  if (!resolvedId) {
@@ -254,6 +321,20 @@ export function conversationManagementRouteDefinitions(
254
321
  404,
255
322
  );
256
323
  }
324
+
325
+ // Cancel the associated schedule job (if any) before wiping the
326
+ // conversation — but only when this is the last conversation that
327
+ // references the schedule. Recurring schedules create a new
328
+ // conversation per run, so we must not cancel the schedule when
329
+ // earlier run conversations are cleaned up.
330
+ const conv = getConversation(resolvedId);
331
+ if (
332
+ conv?.scheduleJobId &&
333
+ countConversationsByScheduleJobId(conv.scheduleJobId) <= 1
334
+ ) {
335
+ deleteSchedule(conv.scheduleJobId);
336
+ }
337
+
257
338
  deps.destroyConversation(resolvedId);
258
339
  const result = wipeConversation(resolvedId);
259
340
  // Enqueue Qdrant vector cleanup jobs
@@ -296,6 +377,9 @@ export function conversationManagementRouteDefinitions(
296
377
  endpoint: "conversations/:id",
297
378
  method: "DELETE",
298
379
  policyKey: "conversations",
380
+ summary: "Delete a conversation",
381
+ description: "Permanently delete a single conversation and its messages.",
382
+ tags: ["conversations"],
299
383
  handler: async ({ params }) => {
300
384
  const resolvedId = resolveConversationId(params.id);
301
385
  if (!resolvedId) {
@@ -305,6 +389,20 @@ export function conversationManagementRouteDefinitions(
305
389
  404,
306
390
  );
307
391
  }
392
+
393
+ // Cancel the associated schedule job (if any) before deleting the
394
+ // conversation — but only when this is the last conversation that
395
+ // references the schedule. Recurring schedules create a new
396
+ // conversation per run, so we must not cancel the schedule when
397
+ // earlier run conversations are cleaned up.
398
+ const conv = getConversation(resolvedId);
399
+ if (
400
+ conv?.scheduleJobId &&
401
+ countConversationsByScheduleJobId(conv.scheduleJobId) <= 1
402
+ ) {
403
+ deleteSchedule(conv.scheduleJobId);
404
+ }
405
+
308
406
  // Tear down the in-memory conversation (abort + dispose) before removing
309
407
  // persistence so that a running agent loop doesn't write to a deleted
310
408
  // conversation row, tripping FK constraints.
@@ -339,6 +437,10 @@ export function conversationManagementRouteDefinitions(
339
437
  endpoint: "conversations/:id/cancel",
340
438
  method: "POST",
341
439
  policyKey: "conversations/cancel",
440
+ summary: "Cancel generation",
441
+ description:
442
+ "Abort the in-progress assistant response for a conversation.",
443
+ tags: ["conversations"],
342
444
  handler: ({ params }) => {
343
445
  const resolvedId = resolveConversationId(params.id) ?? params.id;
344
446
  deps.cancelGeneration(resolvedId);
@@ -349,6 +451,14 @@ export function conversationManagementRouteDefinitions(
349
451
  endpoint: "conversations/:id/undo",
350
452
  method: "POST",
351
453
  policyKey: "conversations/undo",
454
+ summary: "Undo last message",
455
+ description:
456
+ "Remove the most recent user+assistant message pair from the conversation.",
457
+ tags: ["conversations"],
458
+ responseBody: z.object({
459
+ removedCount: z.number().int(),
460
+ conversationId: z.string(),
461
+ }),
352
462
  handler: async ({ params }) => {
353
463
  const result = await deps.undoLastMessage(params.id);
354
464
  if (!result) {
@@ -368,6 +478,10 @@ export function conversationManagementRouteDefinitions(
368
478
  endpoint: "conversations/:id/regenerate",
369
479
  method: "POST",
370
480
  policyKey: "conversations/regenerate",
481
+ summary: "Regenerate response",
482
+ description:
483
+ "Re-run the assistant for the last user message in a conversation.",
484
+ tags: ["conversations"],
371
485
  handler: async ({ params }) => {
372
486
  try {
373
487
  const result = await deps.regenerateResponse(params.id);
@@ -397,6 +511,17 @@ export function conversationManagementRouteDefinitions(
397
511
  endpoint: "conversations/reorder",
398
512
  method: "POST",
399
513
  policyKey: "conversations/reorder",
514
+ summary: "Reorder conversations",
515
+ description:
516
+ "Batch-update display order and pin state for conversations.",
517
+ tags: ["conversations"],
518
+ requestBody: z.object({
519
+ updates: z
520
+ .array(z.unknown())
521
+ .describe(
522
+ "Array of { conversationId, displayOrder?, isPinned? } objects",
523
+ ),
524
+ }),
400
525
  handler: async ({ req }) => {
401
526
  const body = (await req.json()) as {
402
527
  updates?: Array<{
@@ -20,6 +20,8 @@
20
20
  * DELETE /v1/messages/queued/:id — delete queued message
21
21
  */
22
22
 
23
+ import { z } from "zod";
24
+
23
25
  import {
24
26
  deepMergeOverwrite,
25
27
  getConfig,
@@ -43,7 +45,9 @@ import {
43
45
  performConversationSearch,
44
46
  } from "../../daemon/handlers/conversation-history.js";
45
47
  import { deleteQueuedMessage } from "../../daemon/handlers/conversations.js";
48
+ import { getAssistantMessageIdsInTurn } from "../../memory/conversation-crud.js";
46
49
  import { getRequestLogsByMessageId } from "../../memory/llm-request-log-store.js";
50
+ import { getMemoryRecallLogByMessageIds } from "../../memory/memory-recall-log-store.js";
47
51
  import { httpError } from "../http-errors.js";
48
52
  import type { RouteDefinition } from "../http-router.js";
49
53
  import { normalizeLlmContextPayloads } from "./llm-context-normalization.js";
@@ -109,6 +113,10 @@ export function conversationQueryRouteDefinitions(
109
113
  endpoint: "model",
110
114
  method: "GET",
111
115
  policyKey: "model",
116
+ summary: "Get current model config",
117
+ description:
118
+ "Return the active LLM model ID, provider, and available models.",
119
+ tags: ["config"],
112
120
  handler: async () => {
113
121
  const info = await getModelInfo();
114
122
  return Response.json(info);
@@ -118,6 +126,13 @@ export function conversationQueryRouteDefinitions(
118
126
  endpoint: "model",
119
127
  method: "PUT",
120
128
  policyKey: "model",
129
+ summary: "Set LLM model",
130
+ description: "Change the active LLM model and optionally its provider.",
131
+ tags: ["config"],
132
+ requestBody: z.object({
133
+ modelId: z.string(),
134
+ provider: z.string().describe("Optional provider override").optional(),
135
+ }),
121
136
  handler: async ({ req }) => {
122
137
  if (!deps.getModelSetContext) {
123
138
  return httpError("INTERNAL_ERROR", "Model set not available", 500);
@@ -165,6 +180,12 @@ export function conversationQueryRouteDefinitions(
165
180
  endpoint: "model/image-gen",
166
181
  method: "PUT",
167
182
  policyKey: "model/image-gen",
183
+ summary: "Set image generation model",
184
+ description: "Change the active image generation model.",
185
+ tags: ["config"],
186
+ requestBody: z.object({
187
+ modelId: z.string(),
188
+ }),
168
189
  handler: async ({ req }) => {
169
190
  if (!deps.getModelSetContext) {
170
191
  return httpError(
@@ -200,6 +221,10 @@ export function conversationQueryRouteDefinitions(
200
221
  endpoint: "config/embeddings",
201
222
  method: "GET",
202
223
  policyKey: "config/embeddings",
224
+ summary: "Get embedding config",
225
+ description:
226
+ "Return the active embedding provider, model, and available options.",
227
+ tags: ["config"],
203
228
  handler: async () => {
204
229
  const info = await getEmbeddingConfigInfo();
205
230
  return Response.json(info);
@@ -209,6 +234,13 @@ export function conversationQueryRouteDefinitions(
209
234
  endpoint: "config/embeddings",
210
235
  method: "PUT",
211
236
  policyKey: "config/embeddings",
237
+ summary: "Set embedding config",
238
+ description: "Change the embedding provider and optionally model.",
239
+ tags: ["config"],
240
+ requestBody: z.object({
241
+ provider: z.string(),
242
+ model: z.string().optional(),
243
+ }),
212
244
  handler: async ({ req }) => {
213
245
  if (!deps.getModelSetContext) {
214
246
  return httpError(
@@ -265,6 +297,12 @@ export function conversationQueryRouteDefinitions(
265
297
  endpoint: "config/permissions/skip",
266
298
  method: "GET",
267
299
  policyKey: "config/permissions/skip",
300
+ summary: "Get permission-skip flag",
301
+ description: "Return whether dangerouslySkipPermissions is enabled.",
302
+ tags: ["config"],
303
+ responseBody: z.object({
304
+ enabled: z.boolean(),
305
+ }),
268
306
  handler: () => {
269
307
  const config = getConfig();
270
308
  return Response.json({
@@ -276,6 +314,12 @@ export function conversationQueryRouteDefinitions(
276
314
  endpoint: "config/permissions/skip",
277
315
  method: "PUT",
278
316
  policyKey: "config/permissions/skip",
317
+ summary: "Set permission-skip flag",
318
+ description: "Enable or disable dangerouslySkipPermissions.",
319
+ tags: ["config"],
320
+ requestBody: z.object({
321
+ enabled: z.boolean(),
322
+ }),
279
323
  handler: async ({ req }) => {
280
324
  const body = (await req.json()) as { enabled?: unknown };
281
325
  if (typeof body.enabled !== "boolean") {
@@ -304,6 +348,9 @@ export function conversationQueryRouteDefinitions(
304
348
  endpoint: "config",
305
349
  method: "GET",
306
350
  policyKey: "config",
351
+ summary: "Get full config",
352
+ description: "Return the raw settings.json configuration object.",
353
+ tags: ["config"],
307
354
  handler: () => {
308
355
  try {
309
356
  const raw = loadRawConfig();
@@ -324,6 +371,10 @@ export function conversationQueryRouteDefinitions(
324
371
  endpoint: "config",
325
372
  method: "PATCH",
326
373
  policyKey: "config",
374
+ summary: "Patch config",
375
+ description:
376
+ "Deep-merge a partial JSON object into the settings.json configuration.",
377
+ tags: ["config"],
327
378
  handler: async ({ req }) => {
328
379
  const body = (await req.json()) as Record<string, unknown>;
329
380
  if (
@@ -359,6 +410,14 @@ export function conversationQueryRouteDefinitions(
359
410
  endpoint: "conversations/search",
360
411
  method: "GET",
361
412
  policyKey: "conversations/search",
413
+ summary: "Search conversations",
414
+ description:
415
+ "Full-text search across conversation titles and message content.",
416
+ tags: ["conversations"],
417
+ responseBody: z.object({
418
+ query: z.string(),
419
+ results: z.array(z.unknown()),
420
+ }),
362
421
  handler: ({ url }) => {
363
422
  const q = url.searchParams.get("q");
364
423
  if (!q) {
@@ -388,6 +447,9 @@ export function conversationQueryRouteDefinitions(
388
447
  endpoint: "messages/:id/content",
389
448
  method: "GET",
390
449
  policyKey: "messages/content",
450
+ summary: "Get message content",
451
+ description: "Return the full content of a single message by ID.",
452
+ tags: ["messages"],
391
453
  handler: ({ url, params }) => {
392
454
  const conversationId = url.searchParams.get("conversationId");
393
455
  const result = getMessageContent(
@@ -406,12 +468,23 @@ export function conversationQueryRouteDefinitions(
406
468
  endpoint: "messages/:id/llm-context",
407
469
  method: "GET",
408
470
  policyKey: "messages/llm-context",
471
+ summary: "Get LLM context for a message",
472
+ description:
473
+ "Return request/response logs and memory recall data for a specific message.",
474
+ tags: ["messages"],
475
+ responseBody: z.object({
476
+ messageId: z.string(),
477
+ logs: z.array(z.unknown()),
478
+ memoryRecall: z.object({}).passthrough(),
479
+ }),
409
480
  handler: ({ params }) => {
410
481
  const messageId = params.id;
411
482
  if (!messageId) {
412
483
  return httpError("BAD_REQUEST", "message id is required", 400);
413
484
  }
414
485
  const logs = getRequestLogsByMessageId(messageId);
486
+ const turnMessageIds = getAssistantMessageIdsInTurn(messageId);
487
+ const memoryRecallLog = getMemoryRecallLogByMessageIds(turnMessageIds);
415
488
  return Response.json({
416
489
  messageId,
417
490
  logs: logs.map((log) => {
@@ -444,6 +517,7 @@ export function conversationQueryRouteDefinitions(
444
517
  ...result,
445
518
  };
446
519
  }),
520
+ memoryRecall: memoryRecallLog ?? null,
447
521
  });
448
522
  },
449
523
  },
@@ -453,6 +527,10 @@ export function conversationQueryRouteDefinitions(
453
527
  endpoint: "messages/queued/:id",
454
528
  method: "DELETE",
455
529
  policyKey: "messages/queued",
530
+ summary: "Delete a queued message",
531
+ description:
532
+ "Remove a pending message from the conversation queue before it is processed.",
533
+ tags: ["messages"],
456
534
  handler: ({ url, params }) => {
457
535
  if (!deps.findConversationForQueue) {
458
536
  return httpError(