@vellumai/assistant 0.4.49 → 0.4.51

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 (353) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/integrations.md +2 -2
  4. package/docs/architecture/keychain-broker.md +6 -6
  5. package/docs/architecture/memory.md +180 -119
  6. package/knip.json +32 -0
  7. package/package.json +3 -2
  8. package/src/__tests__/agent-loop.test.ts +3 -1
  9. package/src/__tests__/anthropic-provider.test.ts +114 -23
  10. package/src/__tests__/approval-cascade.test.ts +1 -15
  11. package/src/__tests__/approval-routes-http.test.ts +2 -0
  12. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  13. package/src/__tests__/btw-routes.test.ts +61 -5
  14. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  15. package/src/__tests__/checker.test.ts +13 -0
  16. package/src/__tests__/config-schema.test.ts +1 -68
  17. package/src/__tests__/config-watcher.test.ts +8 -0
  18. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  19. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  20. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  21. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  22. package/src/__tests__/credential-security-invariants.test.ts +8 -7
  23. package/src/__tests__/credential-vault-unit.test.ts +23 -18
  24. package/src/__tests__/credential-vault.test.ts +30 -18
  25. package/src/__tests__/credentials-cli.test.ts +257 -82
  26. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  27. package/src/__tests__/date-context.test.ts +93 -77
  28. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  29. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  30. package/src/__tests__/history-repair.test.ts +245 -0
  31. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  32. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  33. package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
  34. package/src/__tests__/integration-status.test.ts +31 -30
  35. package/src/__tests__/invite-redemption-service.test.ts +166 -13
  36. package/src/__tests__/invite-routes-http.test.ts +166 -5
  37. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  38. package/src/__tests__/list-messages-attachments.test.ts +193 -0
  39. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  40. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  41. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  42. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  43. package/src/__tests__/memory-regressions.test.ts +477 -2841
  44. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  45. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  46. package/src/__tests__/mime-builder.test.ts +28 -0
  47. package/src/__tests__/native-web-search.test.ts +1 -0
  48. package/src/__tests__/oauth-cli.test.ts +824 -31
  49. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  50. package/src/__tests__/oauth-store.test.ts +363 -17
  51. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  52. package/src/__tests__/registry.test.ts +0 -1
  53. package/src/__tests__/relay-server.test.ts +55 -1
  54. package/src/__tests__/schedule-tools.test.ts +32 -0
  55. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  56. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  57. package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
  58. package/src/__tests__/secure-keys.test.ts +78 -18
  59. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  60. package/src/__tests__/server-history-render.test.ts +2 -2
  61. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  62. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  63. package/src/__tests__/session-agent-loop.test.ts +19 -15
  64. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  65. package/src/__tests__/session-error.test.ts +124 -2
  66. package/src/__tests__/session-history-web-search.test.ts +918 -0
  67. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  68. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  69. package/src/__tests__/session-queue.test.ts +37 -27
  70. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  71. package/src/__tests__/session-slash-known.test.ts +1 -15
  72. package/src/__tests__/session-slash-queue.test.ts +1 -15
  73. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  74. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  75. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  76. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  77. package/src/__tests__/skills-install-extract.test.ts +93 -0
  78. package/src/__tests__/skills.test.ts +2 -2
  79. package/src/__tests__/skillssh-registry.test.ts +451 -0
  80. package/src/__tests__/slack-channel-config.test.ts +10 -8
  81. package/src/__tests__/trust-store.test.ts +15 -0
  82. package/src/__tests__/twilio-config.test.ts +11 -10
  83. package/src/__tests__/twilio-provider.test.ts +9 -4
  84. package/src/__tests__/voice-invite-redemption.test.ts +85 -5
  85. package/src/agent/ax-tree-compaction.test.ts +51 -0
  86. package/src/agent/loop.ts +39 -12
  87. package/src/approvals/AGENTS.md +1 -1
  88. package/src/approvals/guardian-request-resolvers.ts +14 -2
  89. package/src/bundler/compiler-tools.ts +66 -2
  90. package/src/calls/call-domain.ts +134 -3
  91. package/src/calls/call-store.ts +6 -0
  92. package/src/calls/relay-server.ts +44 -6
  93. package/src/calls/relay-setup-router.ts +17 -1
  94. package/src/calls/twilio-config.ts +5 -4
  95. package/src/calls/twilio-provider.ts +14 -9
  96. package/src/calls/twilio-rest.ts +10 -7
  97. package/src/calls/types.ts +3 -1
  98. package/src/cli/commands/config.ts +14 -9
  99. package/src/cli/commands/contacts.ts +3 -0
  100. package/src/cli/commands/credentials.ts +170 -174
  101. package/src/cli/commands/doctor.ts +11 -8
  102. package/src/cli/commands/keys.ts +9 -9
  103. package/src/cli/commands/mcp.ts +46 -59
  104. package/src/cli/commands/memory.ts +16 -165
  105. package/src/cli/commands/oauth/apps.ts +68 -10
  106. package/src/cli/commands/oauth/connections.ts +475 -105
  107. package/src/cli/commands/oauth/index.ts +3 -3
  108. package/src/cli/commands/oauth/providers.ts +18 -4
  109. package/src/cli/commands/sessions.ts +5 -2
  110. package/src/cli/commands/skills.ts +173 -1
  111. package/src/cli/http-client.ts +0 -20
  112. package/src/cli/main-screen.tsx +2 -2
  113. package/src/cli/program.ts +5 -6
  114. package/src/cli.ts +20 -22
  115. package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
  116. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  117. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +35 -11
  119. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  120. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  121. package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
  135. package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
  136. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
  137. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
  138. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
  139. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
  140. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
  141. package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
  142. package/src/config/bundled-skills/messaging/SKILL.md +1 -1
  143. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  144. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  145. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
  146. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
  148. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
  149. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
  150. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
  151. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
  152. package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
  153. package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
  154. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
  155. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
  156. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
  157. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
  158. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
  159. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
  160. package/src/config/bundled-tool-registry.ts +2 -5
  161. package/src/config/loader.ts +6 -42
  162. package/src/config/schema.ts +1 -12
  163. package/src/config/schemas/memory-lifecycle.ts +0 -9
  164. package/src/config/schemas/memory-processing.ts +0 -180
  165. package/src/config/schemas/memory-retrieval.ts +32 -104
  166. package/src/config/schemas/memory.ts +0 -10
  167. package/src/config/types.ts +0 -4
  168. package/src/contacts/contact-store.ts +39 -2
  169. package/src/contacts/contacts-write.ts +9 -0
  170. package/src/context/window-manager.ts +4 -1
  171. package/src/daemon/config-watcher.ts +55 -2
  172. package/src/daemon/daemon-control.ts +1 -1
  173. package/src/daemon/date-context.ts +114 -31
  174. package/src/daemon/handlers/config-ingress.ts +2 -2
  175. package/src/daemon/handlers/config-slack-channel.ts +59 -39
  176. package/src/daemon/handlers/config-telegram.ts +23 -14
  177. package/src/daemon/handlers/session-history.ts +1 -358
  178. package/src/daemon/handlers/sessions.ts +18 -13
  179. package/src/daemon/handlers/shared.ts +3 -17
  180. package/src/daemon/handlers/skills.ts +20 -1
  181. package/src/daemon/history-repair.ts +72 -8
  182. package/src/daemon/host-cu-proxy.ts +55 -26
  183. package/src/daemon/lifecycle.ts +39 -4
  184. package/src/daemon/mcp-reload-service.ts +2 -2
  185. package/src/daemon/message-types/computer-use.ts +1 -12
  186. package/src/daemon/message-types/memory.ts +4 -16
  187. package/src/daemon/message-types/messages.ts +1 -0
  188. package/src/daemon/message-types/sessions.ts +4 -42
  189. package/src/daemon/server.ts +6 -1
  190. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  191. package/src/daemon/session-agent-loop.ts +334 -48
  192. package/src/daemon/session-error.ts +89 -6
  193. package/src/daemon/session-history.ts +17 -7
  194. package/src/daemon/session-media-retry.ts +6 -2
  195. package/src/daemon/session-memory.ts +69 -149
  196. package/src/daemon/session-process.ts +10 -1
  197. package/src/daemon/session-runtime-assembly.ts +49 -19
  198. package/src/daemon/session-slash.ts +3 -5
  199. package/src/daemon/session-surfaces.ts +4 -1
  200. package/src/daemon/session-tool-setup.ts +7 -1
  201. package/src/daemon/session.ts +12 -2
  202. package/src/email/providers/index.ts +2 -2
  203. package/src/instrument.ts +61 -1
  204. package/src/media/avatar-router.ts +1 -1
  205. package/src/memory/admin.ts +2 -191
  206. package/src/memory/canonical-guardian-store.ts +38 -2
  207. package/src/memory/conversation-crud.ts +0 -33
  208. package/src/memory/conversation-queries.ts +25 -83
  209. package/src/memory/db-init.ts +32 -0
  210. package/src/memory/embedding-backend.ts +84 -8
  211. package/src/memory/embedding-types.ts +9 -1
  212. package/src/memory/indexer.ts +7 -46
  213. package/src/memory/invite-store.ts +19 -0
  214. package/src/memory/items-extractor.ts +274 -76
  215. package/src/memory/job-handlers/backfill.ts +2 -127
  216. package/src/memory/job-handlers/cleanup.ts +2 -16
  217. package/src/memory/job-handlers/extraction.ts +2 -138
  218. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  219. package/src/memory/job-handlers/summarization.ts +3 -148
  220. package/src/memory/job-utils.ts +21 -59
  221. package/src/memory/jobs-store.ts +1 -159
  222. package/src/memory/jobs-worker.ts +9 -52
  223. package/src/memory/migrations/104-core-indexes.ts +3 -3
  224. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  225. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  226. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  227. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  228. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  229. package/src/memory/migrations/154-drop-fts.ts +20 -0
  230. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  231. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  232. package/src/memory/migrations/157-invite-contact-id.ts +104 -0
  233. package/src/memory/migrations/index.ts +8 -0
  234. package/src/memory/migrations/registry.ts +6 -0
  235. package/src/memory/qdrant-client.ts +148 -51
  236. package/src/memory/raw-query.ts +1 -1
  237. package/src/memory/retriever.test.ts +294 -273
  238. package/src/memory/retriever.ts +421 -645
  239. package/src/memory/schema/calls.ts +2 -0
  240. package/src/memory/schema/contacts.ts +1 -0
  241. package/src/memory/schema/memory-core.ts +3 -48
  242. package/src/memory/schema/oauth.ts +2 -0
  243. package/src/memory/search/formatting.ts +263 -176
  244. package/src/memory/search/lexical.ts +1 -254
  245. package/src/memory/search/ranking.ts +0 -455
  246. package/src/memory/search/semantic.ts +100 -14
  247. package/src/memory/search/staleness.ts +47 -0
  248. package/src/memory/search/tier-classifier.ts +21 -0
  249. package/src/memory/search/types.ts +15 -77
  250. package/src/memory/task-memory-cleanup.ts +4 -6
  251. package/src/messaging/provider.ts +1 -1
  252. package/src/messaging/providers/gmail/adapter.ts +1 -1
  253. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  254. package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
  255. package/src/messaging/providers/whatsapp/adapter.ts +13 -9
  256. package/src/messaging/registry.ts +9 -5
  257. package/src/oauth/byo-connection.test.ts +40 -25
  258. package/src/oauth/connect-orchestrator.ts +4 -10
  259. package/src/oauth/connection-resolver.ts +20 -6
  260. package/src/oauth/manual-token-connection.ts +5 -5
  261. package/src/oauth/oauth-store.ts +183 -31
  262. package/src/oauth/platform-connection.test.ts +1 -1
  263. package/src/oauth/provider-behaviors.ts +503 -4
  264. package/src/oauth/seed-providers.ts +214 -8
  265. package/src/oauth/token-persistence.ts +31 -16
  266. package/src/permissions/defaults.ts +1 -0
  267. package/src/permissions/trust-store.ts +23 -1
  268. package/src/playbooks/playbook-compiler.ts +1 -1
  269. package/src/prompts/system-prompt.ts +18 -2
  270. package/src/providers/anthropic/client.ts +56 -126
  271. package/src/providers/types.ts +7 -1
  272. package/src/runtime/AGENTS.md +9 -0
  273. package/src/runtime/auth/route-policy.ts +6 -3
  274. package/src/runtime/channel-readiness-service.ts +48 -40
  275. package/src/runtime/guardian-reply-router.ts +24 -22
  276. package/src/runtime/http-server.ts +2 -2
  277. package/src/runtime/http-types.ts +2 -0
  278. package/src/runtime/invite-redemption-service.ts +72 -12
  279. package/src/runtime/invite-service.ts +43 -0
  280. package/src/runtime/middleware/twilio-validation.ts +1 -1
  281. package/src/runtime/pending-interactions.ts +2 -2
  282. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  283. package/src/runtime/routes/btw-routes.ts +10 -5
  284. package/src/runtime/routes/conversation-routes.ts +56 -11
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  286. package/src/runtime/routes/integrations/slack/channel.ts +2 -2
  287. package/src/runtime/routes/integrations/telegram.ts +2 -2
  288. package/src/runtime/routes/integrations/twilio.ts +17 -17
  289. package/src/runtime/routes/invite-routes.ts +29 -4
  290. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  291. package/src/runtime/routes/memory-item-routes.ts +503 -0
  292. package/src/runtime/routes/secret-routes.ts +17 -0
  293. package/src/runtime/routes/session-management-routes.ts +3 -3
  294. package/src/runtime/routes/settings-routes.ts +3 -3
  295. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  296. package/src/runtime/routes/workspace-routes.ts +9 -4
  297. package/src/runtime/routes/workspace-utils.ts +8 -2
  298. package/src/schedule/integration-status.ts +26 -19
  299. package/src/security/keychain-broker-client.ts +17 -4
  300. package/src/security/oauth2.ts +6 -7
  301. package/src/security/secure-keys.ts +44 -19
  302. package/src/security/token-manager.ts +46 -39
  303. package/src/services/vercel-deploy.ts +0 -24
  304. package/src/signals/confirm.ts +78 -0
  305. package/src/signals/mcp-reload.ts +18 -0
  306. package/src/skills/catalog-install.ts +74 -18
  307. package/src/skills/skillssh-registry.ts +503 -0
  308. package/src/tools/assets/search.ts +5 -1
  309. package/src/tools/computer-use/definitions.ts +0 -10
  310. package/src/tools/computer-use/registry.ts +1 -1
  311. package/src/tools/credentials/vault.ts +22 -7
  312. package/src/tools/memory/definitions.ts +4 -13
  313. package/src/tools/memory/handlers.test.ts +83 -103
  314. package/src/tools/memory/handlers.ts +50 -85
  315. package/src/tools/network/script-proxy/session-manager.ts +8 -8
  316. package/src/tools/schedule/create.ts +10 -3
  317. package/src/tools/schedule/update.ts +8 -1
  318. package/src/tools/skills/load.ts +25 -2
  319. package/src/watcher/provider-types.ts +1 -1
  320. package/src/watcher/providers/github.ts +1 -1
  321. package/src/watcher/providers/gmail.ts +3 -3
  322. package/src/watcher/providers/google-calendar.ts +3 -3
  323. package/src/watcher/providers/linear.ts +1 -1
  324. package/src/__tests__/clarification-resolver.test.ts +0 -193
  325. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  326. package/src/__tests__/conflict-policy.test.ts +0 -269
  327. package/src/__tests__/conflict-store.test.ts +0 -372
  328. package/src/__tests__/contradiction-checker.test.ts +0 -361
  329. package/src/__tests__/entity-extractor.test.ts +0 -211
  330. package/src/__tests__/entity-search.test.ts +0 -1117
  331. package/src/__tests__/profile-compiler.test.ts +0 -392
  332. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  333. package/src/__tests__/session-profile-injection.test.ts +0 -557
  334. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  335. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  336. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  337. package/src/daemon/session-conflict-gate.ts +0 -167
  338. package/src/daemon/session-dynamic-profile.ts +0 -77
  339. package/src/memory/clarification-resolver.ts +0 -417
  340. package/src/memory/conflict-intent.ts +0 -205
  341. package/src/memory/conflict-policy.ts +0 -127
  342. package/src/memory/conflict-store.ts +0 -410
  343. package/src/memory/contradiction-checker.ts +0 -508
  344. package/src/memory/entity-extractor.ts +0 -535
  345. package/src/memory/format-recall.ts +0 -47
  346. package/src/memory/fts-reconciler.ts +0 -165
  347. package/src/memory/job-handlers/conflict.ts +0 -200
  348. package/src/memory/profile-compiler.ts +0 -195
  349. package/src/memory/recall-cache.ts +0 -117
  350. package/src/memory/search/entity.ts +0 -535
  351. package/src/memory/search/query-expansion.test.ts +0 -70
  352. package/src/memory/search/query-expansion.ts +0 -118
  353. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -9,7 +9,7 @@ import {
9
9
  import { credentialKey } from "../../security/credential-key.js";
10
10
  import {
11
11
  deleteSecureKeyAsync,
12
- getSecureKey,
12
+ getSecureKeyAsync,
13
13
  setSecureKeyAsync,
14
14
  } from "../../security/secure-keys.js";
15
15
  import {
@@ -28,21 +28,6 @@ import { shouldOutputJson, writeOutput } from "../output.js";
28
28
  // Shared helpers
29
29
  // ---------------------------------------------------------------------------
30
30
 
31
- /**
32
- * Parse a `service:field` name string. Returns the parsed pair or undefined
33
- * if the format is invalid (no colon or empty segments).
34
- */
35
- function parseCredentialName(
36
- name: string,
37
- ): { service: string; field: string } | undefined {
38
- const colonIndex = name.indexOf(":");
39
- if (colonIndex <= 0 || colonIndex >= name.length - 1) return undefined;
40
- return {
41
- service: name.slice(0, colonIndex),
42
- field: name.slice(colonIndex + 1),
43
- };
44
- }
45
-
46
31
  /**
47
32
  * Scrub a secret value for display. Shows `****` + last 4 characters for
48
33
  * secrets longer than 4 chars, `****` for secrets 4 chars or fewer, and
@@ -177,15 +162,15 @@ export function registerCredentialsCommand(program: Command): void {
177
162
  credential.addHelpText(
178
163
  "after",
179
164
  `
180
- Credentials are identified by name in service:field format, matching the
165
+ Credentials are identified by --service and --field flags, matching the
181
166
  storage convention used internally (credential/{service}/{field}):
182
167
 
183
- twilio:account_sid Twilio account SID
184
- twilio:auth_token Twilio auth token
185
- telegram:bot_token Telegram bot token
186
- slack_channel:bot_token Slack channel bot token
187
- github:token GitHub personal access token
188
- agentmail:api_key AgentMail API key
168
+ --service twilio --field account_sid Twilio account SID
169
+ --service twilio --field auth_token Twilio auth token
170
+ --service telegram --field bot_token Telegram bot token
171
+ --service slack_channel --field bot_token Slack channel bot token
172
+ --service github --field token GitHub personal access token
173
+ --service agentmail --field api_key AgentMail API key
189
174
 
190
175
  Secrets are stored in AES-256-GCM encrypted storage. Metadata (policy,
191
176
  timestamps, labels) is tracked separately and never contains secret values.
@@ -193,9 +178,9 @@ timestamps, labels) is tracked separately and never contains secret values.
193
178
  Examples:
194
179
  $ assistant credentials list
195
180
  $ assistant credentials list --search twilio
196
- $ assistant credentials set twilio:account_sid AC1234567890
197
- $ assistant credentials inspect twilio:account_sid
198
- $ assistant credentials delete twilio:auth_token`,
181
+ $ assistant credentials set --service twilio --field account_sid AC1234567890
182
+ $ assistant credentials inspect --service twilio --field account_sid
183
+ $ assistant credentials delete --service twilio --field auth_token`,
199
184
  );
200
185
 
201
186
  // -------------------------------------------------------------------------
@@ -228,7 +213,7 @@ Examples:
228
213
  $ assistant credentials list --search bot_token
229
214
  $ assistant credentials list --json`,
230
215
  )
231
- .action((opts: { search?: string }, cmd: Command) => {
216
+ .action(async (opts: { search?: string }, cmd: Command) => {
232
217
  try {
233
218
  let allMetadata = listCredentialMetadata();
234
219
 
@@ -262,11 +247,15 @@ Examples:
262
247
  }
263
248
  }
264
249
 
265
- const credentials = allMetadata.map((m) => {
266
- const secret = getSecureKey(credentialKey(m.service, m.field));
267
- const connection = connectionsByProvider.get(m.service);
268
- return buildCredentialOutput(m, secret, connection);
269
- });
250
+ const credentials = await Promise.all(
251
+ allMetadata.map(async (m) => {
252
+ const secret = await getSecureKeyAsync(
253
+ credentialKey(m.service, m.field),
254
+ );
255
+ const connection = connectionsByProvider.get(m.service);
256
+ return buildCredentialOutput(m, secret, connection);
257
+ }),
258
+ );
270
259
 
271
260
  writeOutput(cmd, { ok: true, credentials });
272
261
 
@@ -293,8 +282,13 @@ Examples:
293
282
  // -------------------------------------------------------------------------
294
283
 
295
284
  credential
296
- .command("set <name> <value>")
285
+ .command("set <value>")
297
286
  .description("Store a secret and create or update its metadata")
287
+ .requiredOption(
288
+ "--service <service>",
289
+ "Service namespace (e.g. integration:google)",
290
+ )
291
+ .requiredOption("--field <field>", "Field name (e.g. client_secret)")
298
292
  .option("--label <label>", 'Human-friendly label (e.g. "prod", "work")')
299
293
  .option("--description <description>", "What this credential is used for")
300
294
  .option(
@@ -305,22 +299,22 @@ Examples:
305
299
  "after",
306
300
  `
307
301
  Arguments:
308
- name Credential name in service:field format (e.g. twilio:account_sid)
309
302
  value The secret value to store
310
303
 
311
304
  If the credential already exists, the secret is overwritten and metadata is
312
305
  updated with any provided flags. Omitted flags leave existing metadata intact.
313
306
 
314
307
  Examples:
315
- $ assistant credentials set twilio:account_sid AC1234567890
316
- $ assistant credentials set fal:api_key key_live_abc --label "fal-prod" --description "Image generation"
317
- $ assistant credentials set github:token ghp_abc --allowed-tools "bash,host_bash"`,
308
+ $ assistant credentials set --service twilio --field account_sid AC1234567890
309
+ $ assistant credentials set --service fal --field api_key key_live_abc --label "fal-prod" --description "Image generation"
310
+ $ assistant credentials set --service github --field token ghp_abc --allowed-tools "bash,host_bash"`,
318
311
  )
319
312
  .action(
320
313
  async (
321
- name: string,
322
314
  value: string,
323
315
  opts: {
316
+ service: string;
317
+ field: string;
324
318
  label?: string;
325
319
  description?: string;
326
320
  allowedTools?: string;
@@ -328,17 +322,7 @@ Examples:
328
322
  cmd: Command,
329
323
  ) => {
330
324
  try {
331
- const parsed = parseCredentialName(name);
332
- if (!parsed) {
333
- writeOutput(cmd, {
334
- ok: false,
335
- error: `Invalid credential name "${name}". Expected service:field format (e.g. twilio:account_sid)`,
336
- });
337
- process.exitCode = 1;
338
- return;
339
- }
340
-
341
- const { service, field } = parsed;
325
+ const { service, field } = opts;
342
326
  const storageKey = credentialKey(service, field);
343
327
 
344
328
  assertMetadataWritable();
@@ -347,7 +331,7 @@ Examples:
347
331
  if (!stored) {
348
332
  writeOutput(cmd, {
349
333
  ok: false,
350
- error: `Failed to store secret for ${name}`,
334
+ error: `Failed to store secret for ${service}:${field}`,
351
335
  });
352
336
  process.exitCode = 1;
353
337
  return;
@@ -388,34 +372,23 @@ Examples:
388
372
  // -------------------------------------------------------------------------
389
373
 
390
374
  credential
391
- .command("delete <name>")
375
+ .command("delete")
392
376
  .description("Remove a secret and its metadata from the vault")
377
+ .requiredOption("--service <service>", "Service namespace")
378
+ .requiredOption("--field <field>", "Field name")
393
379
  .addHelpText(
394
380
  "after",
395
381
  `
396
- Arguments:
397
- name Credential name in service:field format (e.g. twilio:account_sid)
398
-
399
382
  Deletes both the encrypted secret and all associated metadata (policy,
400
383
  timestamps, injection templates). This action cannot be undone.
401
384
 
402
385
  Examples:
403
- $ assistant credentials delete twilio:auth_token
404
- $ assistant credentials delete github:token`,
386
+ $ assistant credentials delete --service twilio --field auth_token
387
+ $ assistant credentials delete --service github --field token`,
405
388
  )
406
- .action(async (name: string, _opts: unknown, cmd: Command) => {
389
+ .action(async (opts: { service: string; field: string }, cmd: Command) => {
407
390
  try {
408
- const parsed = parseCredentialName(name);
409
- if (!parsed) {
410
- writeOutput(cmd, {
411
- ok: false,
412
- error: `Invalid credential name "${name}". Expected service:field format (e.g. twilio:account_sid)`,
413
- });
414
- process.exitCode = 1;
415
- return;
416
- }
417
-
418
- const { service, field } = parsed;
391
+ const { service, field } = opts;
419
392
  const storageKey = credentialKey(service, field);
420
393
 
421
394
  assertMetadataWritable();
@@ -477,13 +450,15 @@ Examples:
477
450
  // -------------------------------------------------------------------------
478
451
 
479
452
  credential
480
- .command("inspect <name>")
453
+ .command("inspect [id]")
481
454
  .description("Show metadata and a masked preview of a stored credential")
455
+ .option("--service <service>", "Service namespace")
456
+ .option("--field <field>", "Field name")
482
457
  .addHelpText(
483
458
  "after",
484
459
  `
485
460
  Arguments:
486
- name Credential name in service:field format, or a credential UUID
461
+ id (optional) Credential UUID for lookup by ID
487
462
 
488
463
  Shows everything known about a credential without revealing the secret value.
489
464
  The secret is masked to show only the last 4 characters (e.g. ****c123).
@@ -491,160 +466,181 @@ The secret is masked to show only the last 4 characters (e.g. ****c123).
491
466
  Displayed fields include: label, creation/update timestamps, allowed tools,
492
467
  allowed domains, OAuth2 scopes, account info, and injection template count.
493
468
 
469
+ Use --service and --field to look up by service/field, or pass a UUID as a
470
+ positional argument. One of the two forms is required.
471
+
494
472
  Examples:
495
- $ assistant credentials inspect twilio:account_sid
473
+ $ assistant credentials inspect --service twilio --field account_sid
496
474
  $ assistant credentials inspect 7a3b1c2d-4e5f-6789-abcd-ef0123456789
497
- $ assistant credentials inspect --json slack_channel:bot_token`,
475
+ $ assistant credentials inspect --json --service slack_channel --field bot_token`,
498
476
  )
499
- .action((name: string, _opts: unknown, cmd: Command) => {
500
- try {
501
- let metadata: CredentialMetadata | undefined;
502
- let storageKey: string;
503
-
504
- if (name.includes(":")) {
505
- const parsed = parseCredentialName(name);
506
- if (!parsed) {
477
+ .action(
478
+ async (
479
+ id: string | undefined,
480
+ opts: { service?: string; field?: string },
481
+ cmd: Command,
482
+ ) => {
483
+ try {
484
+ let metadata: CredentialMetadata | undefined;
485
+ let storageKey: string;
486
+ let service: string | undefined;
487
+ let field: string | undefined;
488
+
489
+ if (opts.service && opts.field) {
490
+ service = opts.service;
491
+ field = opts.field;
492
+ metadata = getCredentialMetadata(service, field);
493
+ storageKey = credentialKey(service, field);
494
+ } else if (id) {
495
+ metadata = getCredentialMetadataById(id);
496
+ if (metadata) {
497
+ storageKey = credentialKey(metadata.service, metadata.field);
498
+ service = metadata.service;
499
+ field = metadata.field;
500
+ } else {
501
+ // No metadata found by UUID, and we can't determine the storage key
502
+ writeOutput(cmd, { ok: false, error: "Credential not found" });
503
+ process.exitCode = 1;
504
+ return;
505
+ }
506
+ } else {
507
507
  writeOutput(cmd, {
508
508
  ok: false,
509
- error: `Invalid credential name "${name}". Expected service:field format (e.g. twilio:account_sid)`,
509
+ error:
510
+ "Either --service and --field flags or a credential UUID is required",
510
511
  });
511
512
  process.exitCode = 1;
512
513
  return;
513
514
  }
514
- metadata = getCredentialMetadata(parsed.service, parsed.field);
515
- storageKey = credentialKey(parsed.service, parsed.field);
516
- } else {
517
- metadata = getCredentialMetadataById(name);
518
- if (metadata) {
519
- storageKey = credentialKey(metadata.service, metadata.field);
520
- } else {
521
- // No metadata found by UUID, and we can't determine the storage key
515
+
516
+ const secret = await getSecureKeyAsync(storageKey);
517
+
518
+ if (!metadata && (secret == null || secret.length === 0)) {
522
519
  writeOutput(cmd, { ok: false, error: "Credential not found" });
523
520
  process.exitCode = 1;
524
521
  return;
525
522
  }
526
- }
527
523
 
528
- const secret = getSecureKey(storageKey);
524
+ // If we have a secret but no metadata, we still need metadata for the output.
525
+ // This can happen if someone stored a key directly without going through the
526
+ // credential set command. Build a minimal output in that case.
527
+ if (!metadata) {
528
+ writeOutput(cmd, {
529
+ ok: true,
530
+ service: service,
531
+ field: field,
532
+ credentialId: null,
533
+ scrubbedValue: scrubSecret(secret),
534
+ hasSecret: secret != null && secret.length > 0,
535
+ alias: null,
536
+ usageDescription: null,
537
+ allowedTools: [],
538
+ allowedDomains: [],
539
+ createdAt: null,
540
+ updatedAt: null,
541
+ injectionTemplateCount: 0,
542
+ });
529
543
 
530
- if (!metadata && (secret == null || secret.length === 0)) {
531
- writeOutput(cmd, { ok: false, error: "Credential not found" });
532
- process.exitCode = 1;
533
- return;
534
- }
544
+ if (!shouldOutputJson(cmd)) {
545
+ log.info(` ${service}:${field}`);
546
+ log.info(` Value: ${scrubSecret(secret)}`);
547
+ log.info(" (no metadata record)");
548
+ }
549
+ return;
550
+ }
535
551
 
536
- // If we have a secret but no metadata, we still need metadata for the output.
537
- // This can happen if someone stored a key directly without going through the
538
- // credential set command. Build a minimal output in that case.
539
- if (!metadata) {
540
- // We only get here for the service:field path where we have storageKey
541
- // but no metadata record. Output what we can.
542
- const parsed = parseCredentialName(name)!;
543
- writeOutput(cmd, {
544
- ok: true,
545
- service: parsed.service,
546
- field: parsed.field,
547
- credentialId: null,
548
- scrubbedValue: scrubSecret(secret),
549
- hasSecret: secret != null && secret.length > 0,
550
- alias: null,
551
- usageDescription: null,
552
- allowedTools: [],
553
- allowedDomains: [],
554
- createdAt: null,
555
- updatedAt: null,
556
- injectionTemplateCount: 0,
557
- });
552
+ const connection = safeGetConnectionByProvider(metadata.service);
553
+ const output = buildCredentialOutput(metadata, secret, connection);
554
+ writeOutput(cmd, output);
558
555
 
559
556
  if (!shouldOutputJson(cmd)) {
560
- log.info(` ${parsed.service}:${parsed.field}`);
561
- log.info(` Value: ${scrubSecret(secret)}`);
562
- log.info(" (no metadata record)");
557
+ printCredentialHuman(output);
563
558
  }
564
- return;
565
- }
566
-
567
- const connection = safeGetConnectionByProvider(metadata.service);
568
- const output = buildCredentialOutput(metadata, secret, connection);
569
- writeOutput(cmd, output);
570
-
571
- if (!shouldOutputJson(cmd)) {
572
- printCredentialHuman(output);
559
+ } catch (err) {
560
+ const message = err instanceof Error ? err.message : String(err);
561
+ writeOutput(cmd, { ok: false, error: message });
562
+ process.exitCode = 1;
573
563
  }
574
- } catch (err) {
575
- const message = err instanceof Error ? err.message : String(err);
576
- writeOutput(cmd, { ok: false, error: message });
577
- process.exitCode = 1;
578
- }
579
- });
564
+ },
565
+ );
580
566
 
581
567
  // -------------------------------------------------------------------------
582
568
  // reveal
583
569
  // -------------------------------------------------------------------------
584
570
 
585
571
  credential
586
- .command("reveal <name>")
572
+ .command("reveal [id]")
587
573
  .description("Print the plaintext value of a credential")
574
+ .option("--service <service>", "Service namespace")
575
+ .option("--field <field>", "Field name")
588
576
  .addHelpText(
589
577
  "after",
590
578
  `
591
579
  Arguments:
592
- name Credential name in service:field format, or a credential UUID
580
+ id (optional) Credential UUID for lookup by ID
593
581
 
594
582
  Prints the raw secret value to stdout for piping into other tools. In JSON
595
583
  mode the value is returned as {"ok": true, "value": "..."}. In human mode
596
584
  only the bare secret is printed (no labels or decoration) so it can be
597
- captured with shell substitution, e.g. $(assistant credentials reveal twilio:auth_token).
585
+ captured with shell substitution.
586
+
587
+ Use --service and --field to look up by service/field, or pass a UUID as a
588
+ positional argument. One of the two forms is required.
598
589
 
599
590
  Examples:
600
- $ assistant credentials reveal twilio:auth_token
591
+ $ assistant credentials reveal --service twilio --field auth_token
601
592
  $ assistant credentials reveal 7a3b1c2d-4e5f-6789-abcd-ef0123456789
602
- $ assistant credentials reveal --json twilio:account_sid
603
- $ export TWILIO_TOKEN=$(assistant credentials reveal twilio:auth_token)`,
593
+ $ assistant credentials reveal --json --service twilio --field account_sid
594
+ $ export TWILIO_TOKEN=$(assistant credentials reveal --service twilio --field auth_token)`,
604
595
  )
605
- .action((name: string, _opts: unknown, cmd: Command) => {
606
- try {
607
- let storageKey: string;
608
-
609
- if (name.includes(":")) {
610
- const parsed = parseCredentialName(name);
611
- if (!parsed) {
596
+ .action(
597
+ async (
598
+ id: string | undefined,
599
+ opts: { service?: string; field?: string },
600
+ cmd: Command,
601
+ ) => {
602
+ try {
603
+ let storageKey: string;
604
+
605
+ if (opts.service && opts.field) {
606
+ storageKey = credentialKey(opts.service, opts.field);
607
+ } else if (id) {
608
+ const metadata = getCredentialMetadataById(id);
609
+ if (metadata) {
610
+ storageKey = credentialKey(metadata.service, metadata.field);
611
+ } else {
612
+ writeOutput(cmd, { ok: false, error: "Credential not found" });
613
+ process.exitCode = 1;
614
+ return;
615
+ }
616
+ } else {
612
617
  writeOutput(cmd, {
613
618
  ok: false,
614
- error: `Invalid credential name "${name}". Expected service:field format (e.g. twilio:account_sid)`,
619
+ error:
620
+ "Either --service and --field flags or a credential UUID is required",
615
621
  });
616
622
  process.exitCode = 1;
617
623
  return;
618
624
  }
619
- storageKey = credentialKey(parsed.service, parsed.field);
620
- } else {
621
- const metadata = getCredentialMetadataById(name);
622
- if (metadata) {
623
- storageKey = credentialKey(metadata.service, metadata.field);
624
- } else {
625
+
626
+ const secret = await getSecureKeyAsync(storageKey);
627
+
628
+ if (secret == null || secret.length === 0) {
625
629
  writeOutput(cmd, { ok: false, error: "Credential not found" });
626
630
  process.exitCode = 1;
627
631
  return;
628
632
  }
629
- }
630
633
 
631
- const secret = getSecureKey(storageKey);
632
-
633
- if (secret == null || secret.length === 0) {
634
- writeOutput(cmd, { ok: false, error: "Credential not found" });
634
+ if (shouldOutputJson(cmd)) {
635
+ writeOutput(cmd, { ok: true, value: secret });
636
+ } else {
637
+ process.stdout.write(secret + "\n");
638
+ }
639
+ } catch (err) {
640
+ const message = err instanceof Error ? err.message : String(err);
641
+ writeOutput(cmd, { ok: false, error: message });
635
642
  process.exitCode = 1;
636
- return;
637
- }
638
-
639
- if (shouldOutputJson(cmd)) {
640
- writeOutput(cmd, { ok: true, value: secret });
641
- } else {
642
- process.stdout.write(secret + "\n");
643
643
  }
644
- } catch (err) {
645
- const message = err instanceof Error ? err.message : String(err);
646
- writeOutput(cmd, { ok: false, error: message });
647
- process.exitCode = 1;
648
- }
649
- });
644
+ },
645
+ );
650
646
  }
@@ -3,8 +3,11 @@ import { existsSync, readFileSync, statSync } from "node:fs";
3
3
 
4
4
  import type { Command } from "commander";
5
5
 
6
+ import { getRuntimeHttpPort } from "../../config/env.js";
6
7
  import { loadRawConfig } from "../../config/loader.js";
7
8
  import { shouldAutoStartDaemon } from "../../daemon/connection-policy.js";
9
+ import { isHttpHealthy } from "../../daemon/daemon-control.js";
10
+ import { getSecureKey } from "../../security/secure-keys.js";
8
11
  import {
9
12
  getDbPath,
10
13
  getLogPath,
@@ -13,7 +16,6 @@ import {
13
16
  getWorkspaceHooksDir,
14
17
  getWorkspaceSkillsDir,
15
18
  } from "../../util/platform.js";
16
- import { getHttpBaseUrl, httpHealthCheck } from "../http-client.js";
17
19
  import { log } from "../logger.js";
18
20
 
19
21
  export function registerDoctorCommand(program: Command): void {
@@ -57,7 +59,7 @@ Examples:
57
59
  log.info("Vellum Doctor\n");
58
60
 
59
61
  // 0. Connection policy info
60
- const httpUrl = getHttpBaseUrl();
62
+ const httpUrl = `http://127.0.0.1:${getRuntimeHttpPort()}`;
61
63
  const autostart = shouldAutoStartDaemon();
62
64
  log.info(` HTTP: ${httpUrl}`);
63
65
  log.info(` Autostart: ${autostart ? "enabled" : "disabled"}\n`);
@@ -82,28 +84,29 @@ Examples:
82
84
  fireworks: "FIREWORKS_API_KEY",
83
85
  openrouter: "OPENROUTER_API_KEY",
84
86
  };
85
- const configKey = (raw.apiKeys as Record<string, string> | undefined)?.[
86
- provider
87
- ];
87
+ const configKey = getSecureKey(provider);
88
88
  const envVar = providerEnvVar[provider];
89
89
  const envKey = envVar ? process.env[envVar] : undefined;
90
+ const plaintextKey = (
91
+ raw.apiKeys as Record<string, string> | undefined
92
+ )?.[provider];
90
93
 
91
94
  if (provider === "ollama") {
92
95
  pass("Provider configured (Ollama; API key optional)");
93
- } else if (envKey || configKey) {
96
+ } else if (envKey || configKey || plaintextKey) {
94
97
  pass("API key configured");
95
98
  } else {
96
99
  fail(
97
100
  "API key configured",
98
101
  envVar
99
- ? `set ${envVar} or run: assistant config set apiKeys.${provider} <key>`
102
+ ? `set ${envVar} or run: assistant keys set ${provider} <key>`
100
103
  : `set API key for provider "${provider}"`,
101
104
  );
102
105
  }
103
106
 
104
107
  // 3. Daemon reachable (HTTP health check)
105
108
  try {
106
- const healthy = await httpHealthCheck(2000);
109
+ const healthy = await isHttpHealthy();
107
110
  if (healthy) {
108
111
  pass("Assistant reachable");
109
112
  } else {
@@ -2,9 +2,9 @@ import type { Command } from "commander";
2
2
 
3
3
  import { API_KEY_PROVIDERS } from "../../config/loader.js";
4
4
  import {
5
- deleteSecureKey,
6
- getSecureKey,
7
- setSecureKey,
5
+ deleteSecureKeyAsync,
6
+ getSecureKeyAsync,
7
+ setSecureKeyAsync,
8
8
  } from "../../security/secure-keys.js";
9
9
  import { log } from "../logger.js";
10
10
 
@@ -40,10 +40,10 @@ omitted from the output.
40
40
  Examples:
41
41
  $ assistant keys list`,
42
42
  )
43
- .action(() => {
43
+ .action(async () => {
44
44
  const stored: string[] = [];
45
45
  for (const provider of API_KEY_PROVIDERS) {
46
- const value = getSecureKey(provider);
46
+ const value = await getSecureKeyAsync(provider);
47
47
  if (value) stored.push(provider);
48
48
  }
49
49
  if (stored.length === 0) {
@@ -74,8 +74,8 @@ Examples:
74
74
  $ assistant keys set openai sk-proj-xyz789
75
75
  $ assistant keys set fireworks fw-abc123`,
76
76
  )
77
- .action((provider: string, key: string) => {
78
- if (setSecureKey(provider, key)) {
77
+ .action(async (provider: string, key: string) => {
78
+ if (await setSecureKeyAsync(provider, key)) {
79
79
  log.info(`Stored API key for "${provider}"`);
80
80
  } else {
81
81
  log.error(`Failed to store API key for "${provider}"`);
@@ -99,8 +99,8 @@ Examples:
99
99
  $ assistant keys delete openai
100
100
  $ assistant keys delete anthropic`,
101
101
  )
102
- .action((provider: string) => {
103
- const result = deleteSecureKey(provider);
102
+ .action(async (provider: string) => {
103
+ const result = await deleteSecureKeyAsync(provider);
104
104
  if (result === "deleted") {
105
105
  log.info(`Deleted API key for "${provider}"`);
106
106
  } else if (result === "error") {