@vellumai/assistant 0.8.10 → 0.8.11-staging.1

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 (400) hide show
  1. package/bun.lock +62 -1
  2. package/docs/workspace-tools.md +196 -0
  3. package/examples/plugins/echo/README.md +3 -3
  4. package/knip.json +1 -0
  5. package/openapi.yaml +460 -128
  6. package/package.json +2 -1
  7. package/scripts/build-plugin-api.ts +299 -0
  8. package/src/__tests__/agent-loop-callsite-precedence.test.ts +7 -0
  9. package/src/__tests__/agent-loop-compaction-events.test.ts +197 -0
  10. package/src/__tests__/agent-loop-exit-reason.test.ts +93 -96
  11. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +2 -0
  12. package/src/__tests__/agent-loop-output-hooks.test.ts +274 -1
  13. package/src/__tests__/agent-loop-override-profile.test.ts +3 -0
  14. package/src/__tests__/agent-loop-provider-error-recording.test.ts +4 -0
  15. package/src/__tests__/agent-loop-thinking.test.ts +4 -0
  16. package/src/__tests__/agent-loop.test.ts +578 -5
  17. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -1
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  20. package/src/__tests__/btw-routes.test.ts +0 -1
  21. package/src/__tests__/build-persisted-content.test.ts +75 -1
  22. package/src/__tests__/catalog-install-normalize.test.ts +141 -0
  23. package/src/__tests__/ces-startup-timeout.test.ts +60 -0
  24. package/src/__tests__/compaction-events.test.ts +1 -0
  25. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  26. package/src/__tests__/context-overflow-reducer.test.ts +264 -124
  27. package/src/__tests__/context-window-manager-overflow-rung.test.ts +351 -0
  28. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  29. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +13 -5
  30. package/src/__tests__/conversation-agent-loop-overflow.test.ts +284 -455
  31. package/src/__tests__/conversation-agent-loop.test.ts +131 -551
  32. package/src/__tests__/conversation-app-control-instantiation.test.ts +13 -0
  33. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  34. package/src/__tests__/conversation-fork-crud.test.ts +259 -0
  35. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  36. package/src/__tests__/conversation-lifecycle.test.ts +257 -1
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +38 -377
  39. package/src/__tests__/conversation-queue.test.ts +1 -39
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +119 -8
  41. package/src/__tests__/conversation-skill-tools.test.ts +491 -5
  42. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  43. package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
  44. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  45. package/src/__tests__/conversation-store.test.ts +74 -0
  46. package/src/__tests__/conversation-surfaces-app-control.test.ts +4 -1
  47. package/src/__tests__/conversation-tool-setup-attribution.test.ts +323 -0
  48. package/src/__tests__/conversation-tool-setup-tools-disabled.test.ts +34 -0
  49. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  50. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  51. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -0
  52. package/src/__tests__/corrected-target.test.ts +93 -0
  53. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -5
  54. package/src/__tests__/credential-execution-tools.test.ts +23 -11
  55. package/src/__tests__/credential-security-invariants.test.ts +6 -1
  56. package/src/__tests__/db-schedule-syntax-migration.test.ts +80 -0
  57. package/src/__tests__/device-id.test.ts +70 -1
  58. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  59. package/src/__tests__/empty-response-hook.test.ts +242 -66
  60. package/src/__tests__/external-plugin-loader.test.ts +0 -31
  61. package/src/__tests__/get-skill-detail-audit.test.ts +43 -1
  62. package/src/__tests__/guardian-routing-invariants.test.ts +91 -0
  63. package/src/__tests__/history-repair-hook.test.ts +228 -3
  64. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +254 -9
  66. package/src/__tests__/identity-routes.test.ts +1 -0
  67. package/src/__tests__/image-recovery-hook.test.ts +387 -0
  68. package/src/__tests__/injector-chain.test.ts +5 -4
  69. package/src/__tests__/injector-v3-suppression.test.ts +373 -47
  70. package/src/__tests__/intent-routing.test.ts +7 -0
  71. package/src/__tests__/memory-retrieval-hook.test.ts +117 -15
  72. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  73. package/src/__tests__/oauth-store.test.ts +0 -85
  74. package/src/__tests__/{context-overflow-policy.test.ts → overflow-policy.test.ts} +1 -1
  75. package/src/__tests__/parallel-tool.benchmark.test.ts +4 -0
  76. package/src/__tests__/persist-unsendable-image-downscale.test.ts +29 -9
  77. package/src/__tests__/persist-unsendable-image.test.ts +4 -4
  78. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  79. package/src/__tests__/plugin-bootstrap.test.ts +82 -73
  80. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  81. package/src/__tests__/plugin-types.test.ts +0 -8
  82. package/src/__tests__/provider-catalog-visibility.test.ts +1 -9
  83. package/src/__tests__/prune-old-conversations-job.test.ts +99 -0
  84. package/src/__tests__/registry.test.ts +240 -1
  85. package/src/__tests__/require-fresh-approval.test.ts +3 -0
  86. package/src/__tests__/schedule-routes.test.ts +116 -1
  87. package/src/__tests__/schedule-store.test.ts +28 -0
  88. package/src/__tests__/schedule-tools.test.ts +94 -1
  89. package/src/__tests__/server-history-render.test.ts +39 -0
  90. package/src/__tests__/skill-projection-feature-flag.test.ts +13 -0
  91. package/src/__tests__/skill-projection.benchmark.test.ts +25 -7
  92. package/src/__tests__/skills.test.ts +202 -0
  93. package/src/__tests__/slim-skill-category.test.ts +195 -0
  94. package/src/__tests__/strip-memory-injections.test.ts +33 -39
  95. package/src/__tests__/test-support/tool-invocation-seed.ts +79 -0
  96. package/src/__tests__/title-generate-hook.test.ts +9 -7
  97. package/src/__tests__/tool-audit-listener.test.ts +264 -1
  98. package/src/__tests__/tool-error-hook.test.ts +4 -3
  99. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
  100. package/src/__tests__/tool-executor-lifecycle-events.test.ts +273 -0
  101. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
  102. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  103. package/src/__tests__/tools-get-route.test.ts +202 -0
  104. package/src/__tests__/workspace-tool-loader.test.ts +319 -0
  105. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  106. package/src/agent/loop.ts +569 -319
  107. package/src/api/events/tool-result.ts +9 -0
  108. package/src/api/events/tool-use-start.ts +7 -0
  109. package/src/api/index.ts +10 -0
  110. package/src/api/responses/conversation-message.ts +135 -27
  111. package/src/api/responses/memory-v3-selection-log.ts +4 -4
  112. package/src/approvals/guardian-request-resolvers.ts +26 -0
  113. package/src/browser-session/backends/host-bridge.ts +29 -0
  114. package/src/browser-session/index.ts +1 -0
  115. package/src/browser-session/types.ts +5 -1
  116. package/src/cli/commands/__tests__/schedules.test.ts +62 -4
  117. package/src/cli/commands/__tests__/skills.test.ts +53 -0
  118. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  119. package/src/cli/commands/inference-providers.ts +0 -8
  120. package/src/cli/commands/plugins.ts +2 -2
  121. package/src/cli/commands/schedules.ts +27 -4
  122. package/src/cli/commands/skills.ts +187 -146
  123. package/src/cli/commands/tools.ts +106 -0
  124. package/src/cli/lib/__tests__/install-from-github.test.ts +256 -328
  125. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +6 -2
  126. package/src/cli/lib/__tests__/plugin-details.test.ts +10 -16
  127. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +2 -2
  128. package/src/cli/lib/__tests__/search-plugins.test.ts +145 -240
  129. package/src/cli/lib/install-from-github.ts +187 -117
  130. package/src/cli/lib/plugin-catalog-cache.ts +9 -9
  131. package/src/cli/lib/plugin-details.ts +38 -68
  132. package/src/cli/lib/plugin-marketplace.ts +42 -14
  133. package/src/cli/lib/search-plugins.ts +29 -129
  134. package/src/cli/program.ts +2 -0
  135. package/src/config/bundled-skills/acp/SKILL.md +1 -0
  136. package/src/config/bundled-skills/app-builder/SKILL.md +1 -0
  137. package/src/config/bundled-skills/app-control/SKILL.md +1 -0
  138. package/src/config/bundled-skills/computer-use/SKILL.md +1 -0
  139. package/src/config/bundled-skills/contacts/SKILL.md +1 -0
  140. package/src/config/bundled-skills/document-editor/SKILL.md +1 -0
  141. package/src/config/bundled-skills/followups/SKILL.md +1 -0
  142. package/src/config/bundled-skills/image-studio/SKILL.md +1 -0
  143. package/src/config/bundled-skills/media-processing/SKILL.md +1 -0
  144. package/src/config/bundled-skills/messaging/SKILL.md +1 -0
  145. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -0
  146. package/src/config/bundled-skills/playbooks/SKILL.md +1 -0
  147. package/src/config/bundled-skills/schedule/SKILL.md +1 -0
  148. package/src/config/bundled-skills/schedule/TOOLS.json +11 -3
  149. package/src/config/bundled-skills/sequences/SKILL.md +1 -0
  150. package/src/config/bundled-skills/settings/SKILL.md +1 -0
  151. package/src/config/bundled-skills/skill-management/SKILL.md +101 -1
  152. package/src/config/bundled-skills/subagent/SKILL.md +1 -0
  153. package/src/config/bundled-skills/transcribe/SKILL.md +1 -0
  154. package/src/config/env-registry.ts +23 -0
  155. package/src/config/feature-flag-registry.json +17 -81
  156. package/src/config/loader.ts +5 -22
  157. package/src/config/schema.ts +2 -0
  158. package/src/config/schemas/__tests__/compaction-logs.test.ts +56 -0
  159. package/src/config/schemas/__tests__/memory-v2.test.ts +0 -1
  160. package/src/config/schemas/__tests__/memory-v3.test.ts +61 -1
  161. package/src/config/schemas/compaction-logs.ts +79 -0
  162. package/src/config/schemas/memory-v2.ts +0 -8
  163. package/src/config/schemas/memory-v3.ts +104 -33
  164. package/src/config/seed-inference-profiles.ts +1 -1
  165. package/src/config/skills.ts +117 -47
  166. package/src/context/compactor.ts +11 -0
  167. package/src/context/strip-injections.ts +38 -4
  168. package/src/credential-execution/feature-gates.ts +0 -21
  169. package/src/credential-execution/startup-timeout.ts +32 -4
  170. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +18 -0
  171. package/src/daemon/conversation-agent-loop-handlers.ts +140 -91
  172. package/src/daemon/conversation-agent-loop.ts +123 -658
  173. package/src/daemon/conversation-error.ts +6 -33
  174. package/src/daemon/conversation-lifecycle.ts +1 -1
  175. package/src/daemon/conversation-runtime-assembly.ts +183 -22
  176. package/src/daemon/conversation-skill-tools.ts +137 -8
  177. package/src/daemon/conversation-slash.ts +0 -14
  178. package/src/daemon/conversation-store.ts +2 -19
  179. package/src/daemon/conversation-tool-setup.ts +87 -1
  180. package/src/daemon/conversation.ts +119 -50
  181. package/src/daemon/external-plugins-bootstrap.ts +36 -95
  182. package/src/daemon/handlers/config-channels.ts +11 -2
  183. package/src/daemon/handlers/shared.ts +9 -1
  184. package/src/daemon/handlers/skills.ts +10 -4
  185. package/src/daemon/host-app-control-proxy.ts +72 -57
  186. package/src/daemon/host-browser-proxy.ts +117 -22
  187. package/src/daemon/lifecycle.ts +34 -5
  188. package/src/daemon/message-protocol.ts +0 -7
  189. package/src/daemon/message-types/schedules.ts +1 -0
  190. package/src/daemon/message-types/skills.ts +17 -0
  191. package/src/daemon/providers-setup.ts +3 -0
  192. package/src/daemon/server.ts +3 -3
  193. package/src/daemon/tool-setup-types.ts +9 -3
  194. package/src/daemon/trust-context.ts +23 -0
  195. package/src/daemon/workspace-tools-watcher.ts +324 -0
  196. package/src/events/tool-audit-listener.ts +78 -16
  197. package/src/events/tool-metrics-listener.ts +2 -5
  198. package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +227 -0
  199. package/src/memory/__tests__/conversation-queries.test.ts +176 -0
  200. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +20 -32
  201. package/src/memory/compaction-log-writer-clickhouse.ts +418 -0
  202. package/src/memory/conversation-crud.ts +134 -3
  203. package/src/memory/conversation-queries.ts +64 -7
  204. package/src/memory/db-init.ts +14 -0
  205. package/src/memory/embedding-backend.test.ts +130 -1
  206. package/src/memory/embedding-backend.ts +79 -106
  207. package/src/memory/embedding-gemini.ts +5 -0
  208. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +12 -0
  209. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +19 -0
  210. package/src/memory/graph/conversation-graph-memory.ts +36 -25
  211. package/src/memory/graph/tool-handlers.ts +3 -0
  212. package/src/memory/job-handlers/cleanup.ts +3 -1
  213. package/src/memory/jobs-store.ts +0 -28
  214. package/src/memory/jobs-worker.ts +10 -22
  215. package/src/memory/memory-marker.ts +29 -0
  216. package/src/memory/memory-retrospective-startup-cleanup.ts +1 -1
  217. package/src/memory/migrations/268-add-memory-v3-selections.ts +6 -0
  218. package/src/memory/migrations/270-schedule-description.ts +36 -0
  219. package/src/memory/migrations/275-tool-invocations-add-skill-id.test.ts +81 -0
  220. package/src/memory/migrations/275-tool-invocations-add-skill-id.ts +20 -0
  221. package/src/memory/migrations/276-tool-invocations-created-at-id-index.test.ts +68 -0
  222. package/src/memory/migrations/276-tool-invocations-created-at-id-index.ts +20 -0
  223. package/src/memory/migrations/277-add-memory-v3-ever-injected.ts +29 -0
  224. package/src/memory/migrations/278-tool-invocations-telemetry-columns.test.ts +96 -0
  225. package/src/memory/migrations/278-tool-invocations-telemetry-columns.ts +39 -0
  226. package/src/memory/migrations/279-create-skill-loaded-events.test.ts +84 -0
  227. package/src/memory/migrations/279-create-skill-loaded-events.ts +26 -0
  228. package/src/memory/migrations/280-conversations-surfaced-at.test.ts +88 -0
  229. package/src/memory/migrations/280-conversations-surfaced-at.ts +24 -0
  230. package/src/memory/migrations/index.ts +10 -0
  231. package/src/memory/migrations/registry.ts +8 -0
  232. package/src/memory/schema/conversations.ts +16 -0
  233. package/src/memory/schema/infrastructure.ts +26 -0
  234. package/src/memory/skill-loaded-events-store.test.ts +160 -0
  235. package/src/memory/skill-loaded-events-store.ts +95 -0
  236. package/src/memory/tool-executed-events-store.test.ts +219 -0
  237. package/src/memory/tool-executed-events-store.ts +102 -0
  238. package/src/memory/tool-usage-store.ts +15 -3
  239. package/src/memory/v2/__tests__/consolidation-job.test.ts +117 -12
  240. package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +189 -0
  241. package/src/memory/v2/__tests__/injected-block-slugs.test.ts +90 -0
  242. package/src/memory/v2/__tests__/page-store.test.ts +33 -0
  243. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +88 -15
  244. package/src/memory/v2/activation-store.ts +50 -1
  245. package/src/memory/v2/consolidation-job.ts +113 -29
  246. package/src/memory/v2/injected-block-slugs.ts +79 -0
  247. package/src/memory/v2/injection.ts +6 -1
  248. package/src/memory/v2/prompts/consolidation.ts +414 -13
  249. package/src/memory/v2/router.ts +2 -28
  250. package/src/memory/v2/static-context.ts +1 -1
  251. package/src/memory/v2/types.ts +16 -0
  252. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  253. package/src/notifications/access-request-copy.ts +298 -0
  254. package/src/notifications/adapters/slack.ts +3 -3
  255. package/src/notifications/adapters/telegram.ts +2 -1
  256. package/src/notifications/copy-composer.ts +49 -267
  257. package/src/notifications/decision-engine.ts +16 -35
  258. package/src/notifications/home-feed-side-effect.ts +1 -6
  259. package/src/oauth/oauth-store.ts +0 -9
  260. package/src/permissions/checker.test.ts +83 -1
  261. package/src/permissions/checker.ts +25 -2
  262. package/src/permissions/gateway-threshold-reader.test.ts +182 -0
  263. package/src/permissions/gateway-threshold-reader.ts +80 -0
  264. package/src/platform/client.ts +1 -3
  265. package/src/platform/feature-gate.ts +3 -12
  266. package/src/plugin-api/constants.ts +4 -2
  267. package/src/plugin-api/index.ts +63 -11
  268. package/src/plugin-api/types.ts +236 -71
  269. package/src/plugins/defaults/compaction/compact.ts +66 -2
  270. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +240 -32
  271. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  272. package/src/{daemon/context-overflow-policy.ts → plugins/defaults/compaction/overflow-policy.ts} +1 -1
  273. package/src/plugins/defaults/compaction/window-manager.ts +303 -1
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +173 -0
  275. package/src/plugins/defaults/empty-response/hooks/stop.ts +11 -115
  276. package/src/plugins/defaults/empty-response/nudge-state-store.ts +46 -0
  277. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +50 -0
  278. package/src/plugins/defaults/history-repair/hooks/stop.ts +22 -0
  279. package/src/plugins/defaults/history-repair/repair-state-store.ts +51 -0
  280. package/src/plugins/defaults/history-repair/terminal.ts +39 -2
  281. package/src/plugins/defaults/image-recovery/detect.ts +25 -0
  282. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +73 -0
  283. package/src/plugins/defaults/image-recovery/hooks/stop.ts +22 -0
  284. package/src/plugins/defaults/image-recovery/image-recovery-state-store.ts +48 -0
  285. package/src/plugins/defaults/image-recovery/package.json +14 -0
  286. package/src/{daemon/persist-unsendable-image.ts → plugins/defaults/image-recovery/recover.ts} +67 -14
  287. package/src/plugins/defaults/index.ts +71 -5
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +76 -112
  289. package/src/plugins/defaults/memory-retrieval/hooks/{user-prompt-submit-temp.ts → user-prompt-submit.ts} +83 -74
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +14 -8
  291. package/src/plugins/defaults/memory-retrieval/injectors.ts +2 -18
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1157 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +683 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +161 -140
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +160 -0
  297. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +335 -316
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +145 -53
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +38 -1
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +18 -8
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +112 -71
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +192 -51
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +4 -16
  304. package/src/plugins/defaults/memory-v3-shadow/card.test.ts +173 -0
  305. package/src/plugins/defaults/memory-v3-shadow/card.ts +116 -0
  306. package/src/plugins/defaults/memory-v3-shadow/core-set.test.ts +104 -0
  307. package/src/plugins/defaults/memory-v3-shadow/core-set.ts +59 -0
  308. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +305 -0
  309. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +278 -0
  310. package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +138 -0
  311. package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +85 -0
  312. package/src/plugins/defaults/memory-v3-shadow/injector.ts +331 -24
  313. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +119 -13
  314. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +169 -114
  315. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +47 -16
  316. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +144 -66
  317. package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +758 -0
  318. package/src/plugins/defaults/memory-v3-shadow/prune.ts +471 -0
  319. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +68 -16
  320. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +19 -12
  321. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +96 -43
  322. package/src/plugins/defaults/memory-v3-shadow/types.ts +34 -17
  323. package/src/plugins/defaults/title-generate/hooks/stop.ts +9 -11
  324. package/src/plugins/pipeline.ts +8 -5
  325. package/src/plugins/types.ts +5 -51
  326. package/src/providers/cache-control.ts +26 -0
  327. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -2
  328. package/src/providers/model-catalog.ts +13 -1
  329. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +147 -0
  330. package/src/providers/openai/chat-completions-provider.ts +46 -0
  331. package/src/providers/openai/responses-provider.ts +45 -0
  332. package/src/providers/registry.ts +0 -8
  333. package/src/runtime/__tests__/agent-wake.test.ts +0 -1
  334. package/src/runtime/agent-wake.ts +13 -0
  335. package/src/runtime/routes/__tests__/acp-routes.test.ts +151 -0
  336. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +12 -50
  337. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +322 -0
  338. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +0 -62
  339. package/src/runtime/routes/__tests__/plugins-routes.test.ts +31 -11
  340. package/src/runtime/routes/acp-routes.test.ts +106 -0
  341. package/src/runtime/routes/acp-routes.ts +248 -2
  342. package/src/runtime/routes/browser-tabs-routes.ts +1 -1
  343. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  344. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +0 -14
  345. package/src/runtime/routes/consolidation-routes.ts +6 -82
  346. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  347. package/src/runtime/routes/conversation-management-routes.ts +71 -0
  348. package/src/runtime/routes/identity-routes.ts +8 -0
  349. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  350. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -45
  351. package/src/runtime/routes/plugins-routes.ts +34 -45
  352. package/src/runtime/routes/schedule-routes.ts +43 -5
  353. package/src/runtime/routes/settings-routes.ts +140 -15
  354. package/src/runtime/routes/skills-routes.ts +18 -6
  355. package/src/runtime/services/__tests__/conversation-serializer.test.ts +140 -0
  356. package/src/runtime/services/conversation-serializer.ts +38 -1
  357. package/src/runtime/verification-outbound-actions.ts +147 -2
  358. package/src/runtime/verification-templates.ts +29 -3
  359. package/src/schedule/schedule-store.ts +19 -0
  360. package/src/skills/catalog-install.ts +77 -13
  361. package/src/tasks/task-scheduler.ts +1 -0
  362. package/src/telemetry/types.ts +66 -1
  363. package/src/telemetry/usage-telemetry-reporter.test.ts +542 -13
  364. package/src/telemetry/usage-telemetry-reporter.ts +213 -20
  365. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +49 -2
  366. package/src/tools/browser/__tests__/browser-status.test.ts +29 -5
  367. package/src/tools/browser/browser-execution.ts +27 -9
  368. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +380 -4
  369. package/src/tools/browser/cdp-client/__tests__/host-bridge-cdp-client.test.ts +107 -0
  370. package/src/tools/browser/cdp-client/__tests__/types.test.ts +6 -1
  371. package/src/tools/browser/cdp-client/factory.ts +217 -17
  372. package/src/tools/browser/cdp-client/host-bridge-cdp-client.ts +67 -0
  373. package/src/tools/browser/cdp-client/types.ts +22 -2
  374. package/src/tools/credential-execution/make-authenticated-request.ts +2 -1
  375. package/src/tools/credential-execution/manage-secure-command-tool.ts +169 -164
  376. package/src/tools/credential-execution/run-authenticated-command.ts +2 -1
  377. package/src/tools/executor.ts +39 -7
  378. package/src/tools/registry.ts +387 -5
  379. package/src/tools/schedule/create.ts +16 -0
  380. package/src/tools/schedule/list.ts +12 -4
  381. package/src/tools/schedule/update.ts +12 -0
  382. package/src/tools/skills/load.ts +11 -6
  383. package/src/tools/terminal/safe-env.ts +2 -0
  384. package/src/tools/types.ts +65 -9
  385. package/src/tools/workspace-tools/loader.ts +673 -0
  386. package/src/usage/attribution.ts +28 -0
  387. package/src/util/device-id.ts +17 -3
  388. package/src/util/platform.ts +16 -0
  389. package/tsconfig.plugin-api.json +13 -0
  390. package/src/__tests__/plugin-external-api.test.ts +0 -68
  391. package/src/__tests__/plugin-skill-contribution.test.ts +0 -355
  392. package/src/daemon/message-types/browser.ts +0 -10
  393. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  394. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +0 -36
  395. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +0 -37
  396. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +0 -106
  397. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +0 -44
  398. package/src/plugins/defaults/memory-v3-shadow/working-set.ts +0 -91
  399. package/src/plugins/external-api.ts +0 -114
  400. package/src/plugins/plugin-skill-contributions.ts +0 -292
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Tests for the gateway-backed threshold reader, focused on
3
+ * refreshAutoApproveThreshold(): the cache-bypassing re-read performed
4
+ * before a permission prompt is surfaced. The reader's caches (5s
5
+ * conversation TTL with negative caching, 30s global TTL) are never
6
+ * invalidated by threshold writes, so without the refresh a user who just
7
+ * switched to Full access could still be prompted from a stale snapshot.
8
+ */
9
+
10
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
11
+
12
+ // Silence logger output during tests.
13
+ mock.module("../util/logger.js", () => ({
14
+ getLogger: () =>
15
+ new Proxy({} as Record<string, unknown>, {
16
+ get: () => () => {},
17
+ }),
18
+ }));
19
+
20
+ // ── Controllable IPC mock ────────────────────────────────────────────────────
21
+
22
+ type IpcHandler = (params?: Record<string, unknown>) => unknown;
23
+
24
+ const ipcHandlers = new Map<string, IpcHandler>();
25
+ const ipcCallLog: Array<{ method: string; params?: Record<string, unknown> }> =
26
+ [];
27
+
28
+ mock.module("../ipc/gateway-client.js", () => ({
29
+ ipcCall: async (method: string, params?: Record<string, unknown>) => {
30
+ ipcCallLog.push({ method, params });
31
+ const handler = ipcHandlers.get(method);
32
+ return handler ? handler(params) : undefined;
33
+ },
34
+ ipcCallPersistent: async () => undefined,
35
+ resetPersistentClient: () => {},
36
+ }));
37
+
38
+ import {
39
+ _clearGlobalCacheForTesting,
40
+ _resetFailureCoalesceForTesting,
41
+ getAutoApproveThreshold,
42
+ refreshAutoApproveThreshold,
43
+ } from "./gateway-threshold-reader.js";
44
+
45
+ function countCalls(method: string): number {
46
+ return ipcCallLog.filter((c) => c.method === method).length;
47
+ }
48
+
49
+ describe("refreshAutoApproveThreshold", () => {
50
+ beforeEach(() => {
51
+ _clearGlobalCacheForTesting();
52
+ _resetFailureCoalesceForTesting();
53
+ ipcHandlers.clear();
54
+ ipcCallLog.length = 0;
55
+ });
56
+
57
+ test("bypasses a stale conversation cache and returns the fresh override", async () => {
58
+ // Seed the cache with "low" via the normal read path.
59
+ ipcHandlers.set("get_conversation_threshold", () => ({
60
+ threshold: "low",
61
+ }));
62
+ expect(await getAutoApproveThreshold("conv-1", "conversation")).toBe("low");
63
+
64
+ // The user switches the conversation to Full access — the gateway now
65
+ // returns "high", but the reader's 5s cache still holds "low".
66
+ ipcHandlers.set("get_conversation_threshold", () => ({
67
+ threshold: "high",
68
+ }));
69
+ expect(await getAutoApproveThreshold("conv-1", "conversation")).toBe("low");
70
+
71
+ // The refresh bypasses the cache and sees the new value.
72
+ expect(await refreshAutoApproveThreshold("conv-1", "conversation")).toBe(
73
+ "high",
74
+ );
75
+ });
76
+
77
+ test("primes the conversation cache so subsequent reads skip IPC", async () => {
78
+ ipcHandlers.set("get_conversation_threshold", () => ({
79
+ threshold: "high",
80
+ }));
81
+
82
+ expect(await refreshAutoApproveThreshold("conv-2", "conversation")).toBe(
83
+ "high",
84
+ );
85
+ const callsAfterRefresh = countCalls("get_conversation_threshold");
86
+
87
+ expect(await getAutoApproveThreshold("conv-2", "conversation")).toBe(
88
+ "high",
89
+ );
90
+ // Cache hit — no additional IPC round-trip.
91
+ expect(countCalls("get_conversation_threshold")).toBe(callsAfterRefresh);
92
+ });
93
+
94
+ test("returns null when the conversation override read fails", async () => {
95
+ // No handler registered → ipcCall returns undefined (transport failure).
96
+ expect(
97
+ await refreshAutoApproveThreshold("conv-3", "conversation"),
98
+ ).toBeNull();
99
+ // Must not fall through to the global read: without the override we
100
+ // cannot know whether the conversation is stricter than the global.
101
+ expect(countCalls("get_global_thresholds")).toBe(0);
102
+ });
103
+
104
+ test("falls through to a fresh global read when no override exists", async () => {
105
+ ipcHandlers.set("get_conversation_threshold", () => null);
106
+ ipcHandlers.set("get_global_thresholds", () => ({
107
+ interactive: "high",
108
+ autonomous: "low",
109
+ headless: "none",
110
+ }));
111
+
112
+ expect(await refreshAutoApproveThreshold("conv-4", "conversation")).toBe(
113
+ "high",
114
+ );
115
+ });
116
+
117
+ test("bypasses a stale global cache", async () => {
118
+ ipcHandlers.set("get_global_thresholds", () => ({
119
+ interactive: "medium",
120
+ autonomous: "low",
121
+ headless: "none",
122
+ }));
123
+ expect(await getAutoApproveThreshold(undefined, "conversation")).toBe(
124
+ "medium",
125
+ );
126
+
127
+ // The user switches the global interactive threshold to Full access —
128
+ // the reader's 30s global cache still holds "medium".
129
+ ipcHandlers.set("get_global_thresholds", () => ({
130
+ interactive: "high",
131
+ autonomous: "low",
132
+ headless: "none",
133
+ }));
134
+ expect(await getAutoApproveThreshold(undefined, "conversation")).toBe(
135
+ "medium",
136
+ );
137
+
138
+ expect(await refreshAutoApproveThreshold(undefined, "conversation")).toBe(
139
+ "high",
140
+ );
141
+
142
+ // The refresh primed the global cache with the fresh values.
143
+ expect(await getAutoApproveThreshold(undefined, "conversation")).toBe(
144
+ "high",
145
+ );
146
+ });
147
+
148
+ test("resolves the context-appropriate global field", async () => {
149
+ ipcHandlers.set("get_global_thresholds", () => ({
150
+ interactive: "high",
151
+ autonomous: "medium",
152
+ headless: "none",
153
+ }));
154
+
155
+ expect(await refreshAutoApproveThreshold("conv-5", "background")).toBe(
156
+ "medium",
157
+ );
158
+ expect(await refreshAutoApproveThreshold("conv-5", "headless")).toBe(
159
+ "none",
160
+ );
161
+ // Background/headless contexts never consult the per-conversation
162
+ // override, mirroring getAutoApproveThreshold.
163
+ expect(countCalls("get_conversation_threshold")).toBe(0);
164
+ });
165
+
166
+ test("returns null when the global read fails", async () => {
167
+ expect(
168
+ await refreshAutoApproveThreshold(undefined, "conversation"),
169
+ ).toBeNull();
170
+ });
171
+
172
+ test("returns null for an invalid global value", async () => {
173
+ ipcHandlers.set("get_global_thresholds", () => ({
174
+ interactive: "bogus",
175
+ autonomous: "low",
176
+ headless: "none",
177
+ }));
178
+ expect(
179
+ await refreshAutoApproveThreshold(undefined, "conversation"),
180
+ ).toBeNull();
181
+ });
182
+ });
@@ -288,3 +288,83 @@ async function fetchGlobalThresholds(): Promise<GlobalThresholds> {
288
288
  cachedGlobalTimestamp = Date.now();
289
289
  return result;
290
290
  }
291
+
292
+ /**
293
+ * Re-read the auto-approve threshold from the gateway, bypassing both
294
+ * caches, and prime them with the fresh values.
295
+ *
296
+ * Used by the permission checker immediately before surfacing an
297
+ * interactive prompt: the cached snapshot (5s conversation TTL with
298
+ * negative caching, 30s global TTL) may predate a threshold change the
299
+ * user just made — e.g. switching to Full access — because no threshold
300
+ * write path invalidates these in-process caches (the web picker writes
301
+ * through the gateway HTTP route, the desktop picker through the
302
+ * `set_conversation_threshold` IPC). Prompting from a stale threshold
303
+ * directly contradicts the user's visible setting. A prompt is already a
304
+ * rare, user-visible interruption, so the extra IPC round-trip is cheap
305
+ * relative to a wrong prompt.
306
+ *
307
+ * Returns the freshly-resolved threshold, or `null` when the gateway
308
+ * could not be reached. Callers must keep their original decision on
309
+ * `null` — fail toward prompting, never toward silent approval. The
310
+ * conversation-override read failing is also treated as `null` (rather
311
+ * than falling through to the global threshold) because without the
312
+ * override we cannot know whether the conversation is configured more
313
+ * strictly than the global default.
314
+ */
315
+ export async function refreshAutoApproveThreshold(
316
+ conversationId: string | undefined,
317
+ executionContext?: ExecutionContext,
318
+ ): Promise<Threshold | null> {
319
+ const ctx: ExecutionContext = executionContext ?? "conversation";
320
+
321
+ if (ctx === "conversation" && conversationId) {
322
+ const result = (await ipcCall("get_conversation_threshold", {
323
+ conversationId,
324
+ })) as ConversationThreshold | null | undefined;
325
+
326
+ if (result === undefined) {
327
+ noteFailure(
328
+ "conversation_threshold",
329
+ { conversationId },
330
+ "IPC call failed for conversation threshold refresh, keeping cached decision",
331
+ );
332
+ return null;
333
+ }
334
+ noteSuccess("conversation_threshold");
335
+ if (result && isValidThreshold(result.threshold)) {
336
+ conversationThresholdCache.set(conversationId, {
337
+ threshold: result.threshold,
338
+ timestamp: Date.now(),
339
+ });
340
+ return result.threshold;
341
+ }
342
+ // No override (or unexpected shape) — prime the negative cache and
343
+ // fall through to a fresh global read.
344
+ conversationThresholdCache.set(conversationId, {
345
+ threshold: null,
346
+ timestamp: Date.now(),
347
+ });
348
+ }
349
+
350
+ try {
351
+ const result = (await ipcCall(
352
+ "get_global_thresholds",
353
+ )) as GlobalThresholds | null;
354
+ if (!result) {
355
+ throw new Error("Gateway IPC returned no result for global thresholds");
356
+ }
357
+ noteSuccess("global_thresholds");
358
+ cachedGlobalThresholds = result;
359
+ cachedGlobalTimestamp = Date.now();
360
+ const value = result[mapExecutionContextToField(ctx)];
361
+ return isValidThreshold(value) ? value : null;
362
+ } catch (err) {
363
+ noteFailure(
364
+ "global_thresholds",
365
+ { error: String(err) },
366
+ "Failed to refresh global thresholds, keeping cached decision",
367
+ );
368
+ return null;
369
+ }
370
+ }
@@ -45,9 +45,7 @@ export class VellumPlatformClient {
45
45
  */
46
46
  static async create(): Promise<VellumPlatformClient | null> {
47
47
  if (!arePlatformFeaturesEnabled()) {
48
- log.debug(
49
- "platform-features-in-local-mode is disabled — returning null",
50
- );
48
+ log.debug("platform features disabled — returning null");
51
49
  return null;
52
50
  }
53
51
 
@@ -1,15 +1,6 @@
1
- import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
2
- import { getIsPlatform } from "../config/env-registry.js";
3
- import type { AssistantConfig } from "../config/schema.js";
1
+ import { getDisablePlatform, getIsPlatform } from "../config/env-registry.js";
4
2
 
5
- const FLAG_KEY = "platform-features-in-local-mode" as const;
6
-
7
- export function arePlatformFeaturesEnabled(
8
- config?: AssistantConfig,
9
- ): boolean {
3
+ export function arePlatformFeaturesEnabled(): boolean {
10
4
  if (getIsPlatform()) return true;
11
- return isAssistantFeatureFlagEnabled(
12
- FLAG_KEY,
13
- (config ?? {}) as AssistantConfig,
14
- );
5
+ return !getDisablePlatform();
15
6
  }
@@ -24,10 +24,12 @@ export const HOOKS = {
24
24
  PRE_MODEL_CALL: "pre-model-call",
25
25
  /** Fires once per tool result, after the tool returns and before the result is sent to the provider. */
26
26
  POST_TOOL_USE: "post-tool-use",
27
- /** Fires when the model yields a response with no tool calls — the run's stop boundary. Decides whether to stop or continue with a follow-up turn. */
27
+ /** Fires once per run when the loop has committed to ending — the definitive terminal hook for teardown. Cannot continue the loop; reports how the turn ended via `exitReason`. */
28
28
  STOP: "stop",
29
- /** Fires for each finalized assistant message, once per model call, before it is persisted/streamed-final. A hook may transform the message content. */
29
+ /** Fires at every model-call outcome (finalized reply or provider rejection), before the message is persisted/streamed-final. A hook may transform the content and owns the continue/retry decision. */
30
30
  POST_MODEL_CALL: "post-model-call",
31
+ /** Fires after the loop successfully compacts a conversation mid-turn. */
32
+ POST_COMPACT: "post-compact",
31
33
  } as const;
32
34
 
33
35
  /** Union of every hook name declared in {@link HOOKS}. */
@@ -11,27 +11,45 @@
11
11
  *
12
12
  * ## Surface today
13
13
  *
14
- * The public package is intentionally **declarative**: a plugin is a
15
- * directory whose `package.json` is the manifest and whose `hooks/` /
16
- * `tools/` / `skills/` / `routes/` subdirectories are the contributions.
17
- * The host introspects the directory at load time and wires it into the
18
- * runtime — plugin authors never call a runtime registration function.
14
+ * The primary authoring model is **declarative**: a plugin is a directory
15
+ * whose `package.json` is the manifest and whose `hooks/` / `tools/` /
16
+ * `skills/` / `routes/` subdirectories are the contributions. The host
17
+ * introspects the directory at load time and wires it into the runtime.
19
18
  *
20
- * What this module exposes is therefore types-only: the context shapes
19
+ * Most of what this module exposes is therefore types: the context shapes
21
20
  * the host hands to plugin hooks, and the logger shape they include.
22
21
  *
22
+ * Alongside those types, the module exposes a small set of **runtime
23
+ * handles** for plugins that need to reach the assistant's live singletons
24
+ * (subscribe to runtime events, read secrets). These resolve to the
25
+ * assistant's own instances: the host parks the loaded plugin-api namespace
26
+ * on `globalThis` at boot, and the workspace-level shim re-binds each
27
+ * runtime export from there — so a plugin's
28
+ * `import { assistantEventHub } from "@vellumai/plugin-api"` lands on the
29
+ * same singleton the assistant uses, even when the daemon is a
30
+ * `bun --compile` binary where an absolute-path import would load a
31
+ * disjoint module copy.
32
+ *
33
+ * - {@link assistantEventHub} — the assistant's pub/sub hub for runtime events
34
+ * - {@link getSecureKeyAsync} — read a secret from secure storage
35
+ *
23
36
  * - {@link PluginInitContext} — passed to `init` hook at bootstrap
24
37
  * - {@link PluginShutdownContext} — passed to `shutdown` hook at teardown
25
38
  * - {@link UserPromptSubmitContext} — passed to `user-prompt-submit` hook,
26
39
  * fired immediately before the agent loop receives a user's prompt
40
+ * - {@link PostCompactContext} — passed to `post-compact` hook, fired after
41
+ * the agent loop compacts a conversation mid-turn to re-apply injections
27
42
  * - {@link PreModelCallContext} — passed to `pre-model-call` hook, fired
28
43
  * before each provider call to edit the request / defer output streaming
29
44
  * - {@link PostToolUseContext} — passed to `post-tool-use` hook, fired once
30
45
  * per tool result before it joins the provider-bound history
31
- * - {@link StopContext} — passed to `stop` hook, fired when the model yields
32
- * a response with no tool calls
33
- * - {@link PostModelCallContext} — passed to `post-model-call` hook,
34
- * fired for each finalized assistant message to transform its content
46
+ * - {@link StopContext} — passed to `stop` hook, the definitive terminal hook
47
+ * fired exactly once when the turn ends (no continue capability)
48
+ * - {@link AgentLoopExitReason} — why a turn reached its terminal state, carried
49
+ * on {@link StopContext} and the `agent_loop_exit` event
50
+ * - {@link PostModelCallContext} — passed to `post-model-call` hook, fired at
51
+ * every model-call outcome (a finalized reply or a provider rejection) to
52
+ * transform content and decide whether to retry
35
53
  * - {@link PluginHookFn} — signature every lifecycle hook implements
36
54
  * - {@link PluginLogger} — pino-compatible logger shape on the contexts
37
55
  * - {@link ToolDefinition} — author-facing tool spec (default-export shape
@@ -42,19 +60,53 @@
42
60
 
43
61
  export type { HookName } from "./constants.js";
44
62
  export { HOOKS } from "./constants.js";
63
+ // Conversation message/content shapes. A hook receives the live message
64
+ // history (e.g. `PostToolUseContext.latestMessages: Message[]`), so plugins
65
+ // that inspect or narrow content blocks — reading a `tool_use` block's input,
66
+ // matching a `tool_result` — need to name these types.
67
+ export type {
68
+ ContentBlock,
69
+ FileContent,
70
+ ImageContent,
71
+ Message,
72
+ RedactedThinkingContent,
73
+ ServerToolUseContent,
74
+ TextContent,
75
+ ThinkingContent,
76
+ ToolResultContent,
77
+ ToolUseContent,
78
+ WebSearchToolResultContent,
79
+ } from "../providers/types.js";
45
80
  export type {
81
+ AgentLoopExitReason,
46
82
  PluginHookFn,
47
83
  PluginInitContext,
48
84
  PluginLogger,
49
85
  PluginShutdownContext,
86
+ PostCompactContext,
50
87
  PostModelCallContext,
88
+ PostModelCallDecision,
51
89
  PostToolUseContext,
52
90
  PreModelCallContext,
53
91
  StopContext,
54
- StopDecision,
55
92
  ToolContext,
56
93
  ToolDefinition,
57
94
  ToolExecutionResult,
58
95
  UserPromptSubmitContext,
59
96
  } from "./types.js";
60
97
  export { RiskLevel } from "./types.js";
98
+
99
+ // ─── Runtime handles ─────────────────────────────────────────────────────────
100
+ // Values (not just types) that plugins consume at module-load / init time.
101
+ // Workspace-local plugins resolve these via the boot-time shim, which
102
+ // re-binds each from the assistant's globalThis-parked namespace so they
103
+ // share module identity with the assistant's own singletons.
104
+ export type { AssistantEvent } from "../runtime/assistant-event.js";
105
+ export type {
106
+ AssistantEventCallback,
107
+ AssistantEventFilter,
108
+ AssistantEventHub,
109
+ AssistantEventSubscription,
110
+ } from "../runtime/assistant-event-hub.js";
111
+ export { assistantEventHub } from "../runtime/assistant-event-hub.js";
112
+ export { getSecureKeyAsync } from "../security/secure-keys.js";