@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
@@ -8,21 +8,21 @@
8
8
  * with a mocked select provider, a stubbed dense lane, an in-memory selections
9
9
  * DB, and synthetic fixtures, driving them over a MULTI-TURN sequence:
10
10
  *
11
- * orchestrate (needle ∪ dense ∪ edge → selectPool over a shared WorkingSet
12
- * → carry-forward)
11
+ * orchestrate (cache-ordered pool: core + hot stable prefix, then
12
+ * needle ∪ dense ∪ edge finder candidates → ONE selectPool call)
13
13
  * → attribute selections to lane sources (the shadow plugin's REAL
14
- * `attributeSelections`, reading `result.laneBySlug`)
14
+ * `attributeSelections`, reading `result.lanes`)
15
15
  * → write to `memory_v3_selections` (the shadow plugin's REAL
16
16
  * `writeSelections`)
17
17
  * → summarizeSelections (the offline A/B readout)
18
18
  *
19
19
  * This is exactly the side-effect contract shadow mode observes each turn: the
20
- * candidate pool is the union of the lanes — synthetic capability pages are
21
- * indexed like any other page, so they enter through the needle lane rather than
22
- * being always-added — a SINGLE select runs per turn, the working set carries
23
- * selections forward across turns, and each selection is logged tagged with its
24
- * lane source. None of this changes live injection — shadow mode is
25
- * observation-only; cutover is the `memory-v3-live` flag flip.
20
+ * candidate pool is the cache-ordered union of the lanes — synthetic capability
21
+ * pages are indexed like any other page, so they enter through the needle lane
22
+ * rather than being always-added — a SINGLE select runs per turn, the result is
23
+ * this turn's selections only, and each selection is
24
+ * logged tagged with its lane source. None of this changes live injection —
25
+ * shadow mode is observation-only; cutover is the `memory-v3-live` flag flip.
26
26
  *
27
27
  * Slugs are generic placeholders (`page-a`, `topic-x`, `page-b`, …) — this is a
28
28
  * public repo.
@@ -41,6 +41,7 @@ import type {
41
41
  Provider,
42
42
  ProviderResponse,
43
43
  } from "../../../../providers/types.js";
44
+ import { renderCard } from "../card.js";
44
45
  import type { EdgeGraph } from "../edge.js";
45
46
  import { buildEdgeGraph } from "../edge.js";
46
47
  import type { OrchestrateResult } from "../orchestrate.js";
@@ -116,12 +117,11 @@ mock.module("../../../../memory/db-connection.js", () => ({
116
117
  }));
117
118
 
118
119
  const { orchestrate } = await import("../orchestrate.js");
119
- const { WorkingSet } = await import("../working-set.js");
120
120
  const { summarizeSelections } = await import("../selection-log-store.js");
121
121
  // The REAL attribution + writer from the shadow plugin, imported AFTER the
122
122
  // db-connection mock so `writeSelections` binds to the in-memory test DB. Using
123
123
  // the production code (rather than a local copy) means this test exercises the
124
- // real `result.laneBySlug` attribution — the only thing that can emit "dense".
124
+ // real `result.lanes` attribution — the only thing that can emit "dense".
125
125
  const { attributeSelections, writeSelections } =
126
126
  await import("../shadow-plugin.js");
127
127
 
@@ -211,20 +211,39 @@ function toolUseResponse(input: Record<string, unknown>): ProviderResponse {
211
211
  };
212
212
  }
213
213
 
214
- /** Parse the numbered `<candidates>` block back into an ordered slug list. */
214
+ /**
215
+ * Parse the two-segment selector input back into the globally-numbered pool
216
+ * slug list: stable-prefix cards (`<candidate_cards>`, identified by their
217
+ * `[i] # memory/concepts/<slug>.md` header line) then finder lines
218
+ * (`<candidates>`, `[i] slug — descriptor`).
219
+ */
215
220
  function candidateSlugs(messages: Message[]): Slug[] {
221
+ const entries: Array<{ id: number; slug: string }> = [];
216
222
  for (const msg of messages) {
217
223
  for (const block of msg.content) {
218
224
  if (block.type !== "text") continue;
219
- const m = /<candidates>\n([\s\S]*?)\n<\/candidates>/.exec(block.text);
220
- if (!m) continue;
221
- return m[1]
222
- .split("\n")
223
- .map((line) => /^\[\d+\] (\S+) —/.exec(line)?.[1])
224
- .filter((s): s is string => !!s);
225
+ const cards = /<candidate_cards>\n([\s\S]*?)\n<\/candidate_cards>/.exec(
226
+ block.text,
227
+ );
228
+ if (cards) {
229
+ for (const m of cards[1].matchAll(
230
+ /^\[(\d+)\] # memory\/concepts\/(.+)\.md$/gm,
231
+ )) {
232
+ entries.push({ id: Number(m[1]), slug: m[2]! });
233
+ }
234
+ }
235
+ const finder = /<candidates>\n([\s\S]*?)\n<\/candidates>/.exec(
236
+ block.text,
237
+ );
238
+ if (finder) {
239
+ for (const line of finder[1].split("\n")) {
240
+ const m = /^\[(\d+)\] (\S+)(?: — |$)/.exec(line);
241
+ if (m) entries.push({ id: Number(m[1]), slug: m[2]! });
242
+ }
243
+ }
225
244
  }
226
245
  }
227
- return [];
246
+ return entries.sort((a, b) => a.id - b.id).map((e) => e.slug);
228
247
  }
229
248
 
230
249
  /**
@@ -255,7 +274,7 @@ function selectProvider(keep: Slug[], pin: Slug[] = []): Provider {
255
274
  // ---------------------------------------------------------------------------
256
275
  // Selection read-back. Attribution (`attributeSelections`) and the write
257
276
  // (`writeSelections`) are the shadow plugin's REAL functions, imported above —
258
- // so this test exercises the production `result.laneBySlug` attribution rather
277
+ // so this test exercises the production `result.lanes` attribution rather
259
278
  // than a local copy. The db-connection mock routes `writeSelections` at the
260
279
  // in-memory test DB.
261
280
  // ---------------------------------------------------------------------------
@@ -278,16 +297,23 @@ async function runTurn(
278
297
  pin: Slug[],
279
298
  deps: {
280
299
  lanes: Awaited<ReturnType<typeof buildLanes>>;
281
- workingSet: InstanceType<typeof WorkingSet>;
300
+ core?: Slug[];
301
+ hot?: Slug[];
282
302
  },
283
303
  ): Promise<OrchestrateResult> {
284
304
  providerStub = selectProvider(keep, pin);
305
+ const stableSlugs = [...(deps.core ?? []), ...(deps.hot ?? [])];
285
306
  const result = await orchestrate(makeTurn(turnNumber, query), {
286
307
  sectionIndex: deps.lanes.sectionIndex,
287
308
  needle: deps.lanes.needle,
288
309
  denseConfig: config,
289
310
  edgeGraph: deps.lanes.edgeGraph,
290
- workingSet: deps.workingSet,
311
+ coreSlugs: deps.core ?? [],
312
+ hotSlugs: deps.hot ?? [],
313
+ // Mirrors lane init: every stable-prefix slug gets a pre-rendered card.
314
+ prefixCards: new Map(
315
+ stableSlugs.map((slug) => [slug, renderCard(slug, RAW[slug] ?? "")]),
316
+ ),
291
317
  });
292
318
  writeSelections(CONV, turnNumber, attributeSelections(result));
293
319
  return result;
@@ -320,7 +346,7 @@ describe("memory-v3 shadow integration — candidate pool", () => {
320
346
  // topic-x (edge). "apple" does NOT match the capability page, so it is not
321
347
  // pooled this turn — capability pages are lane-ranked, not always-added.
322
348
  denseHits = [{ article: "page-b", section: 0 }];
323
- await runTurn(1, "apple", [], [], { lanes, workingSet: new WorkingSet() });
349
+ await runTurn(1, "apple", [], [], { lanes });
324
350
 
325
351
  expect(selectCalls).toBe(1);
326
352
  expect(new Set(lastPool)).toEqual(new Set(["page-a", "page-b", "topic-x"]));
@@ -330,7 +356,7 @@ describe("memory-v3 shadow integration — candidate pool", () => {
330
356
  const lanes = await buildLanes();
331
357
  // "durian" is the distinctive term in the capability page's content, so the
332
358
  // real needle ranks it and folds it into the pool.
333
- await runTurn(1, "durian", [], [], { lanes, workingSet: new WorkingSet() });
359
+ await runTurn(1, "durian", [], [], { lanes });
334
360
 
335
361
  expect(selectCalls).toBe(1);
336
362
  expect(lastPool).toContain(CAPABILITY_SLUG);
@@ -338,40 +364,52 @@ describe("memory-v3 shadow integration — candidate pool", () => {
338
364
  });
339
365
 
340
366
  // ---------------------------------------------------------------------------
341
- // Carry-forward across turns: a page selected on turn 1 stays in turn 2's
342
- // final injection without being re-selected (net-new shadow behavior), and is
343
- // logged as `carry-forward` on the later turn.
367
+ // Stable-prefix lanes: core and hot head the pool in cache order on EVERY
368
+ // turn regardless of the query, and their selections log with the core / hot
369
+ // source tags. Selections are current-turn only — nothing carries.
344
370
  // ---------------------------------------------------------------------------
345
371
 
346
- describe("memory-v3 shadow integration — carry-forward", () => {
347
- test("a turn-1 selection accumulates into turn 2's injection and logs as carry-forward", async () => {
372
+ describe("memory-v3 shadow integration — core + hot stable prefix", () => {
373
+ test("core and hot head the pool every turn and log lane-correct sources", async () => {
348
374
  const lanes = await buildLanes();
349
- const workingSet = new WorkingSet();
375
+ const prefix = { core: ["topic-x"], hot: ["page-b"] };
350
376
 
351
- // Turn 1 selects+pins page-a (needle-sourced).
352
- const t1 = await runTurn(1, "apple", ["page-a"], ["page-a"], {
377
+ // Turn 1: "apple" hits page-a (needle). The prefix precedes it in pool
378
+ // order even though the query never matches topic-x / page-b.
379
+ const t1 = await runTurn(1, "apple", ["topic-x", "page-a"], [], {
353
380
  lanes,
354
- workingSet,
381
+ ...prefix,
355
382
  });
356
- expect(t1.currentSelections.map((s) => s.slug)).toContain("page-a");
357
- expect(loggedSources(1)).toEqual([{ slug: "page-a", source: "needle" }]);
383
+ expect(lastPool).toEqual(["topic-x", "page-b", "page-a"]);
384
+ expect(t1.lanes.core).toEqual(["topic-x"]);
385
+ expect(t1.lanes.hot).toEqual(["page-b"]);
386
+ expect(loggedSources(1)).toEqual([
387
+ { slug: "topic-x", source: "core" },
388
+ { slug: "page-a", source: "needle" },
389
+ ]);
390
+
391
+ // Turn 2: a different query — the stable prefix is unchanged, the finder
392
+ // tail differs, and turn 1's un-re-selected page-a does NOT reappear in
393
+ // the result (no carry in orchestration).
394
+ const t2 = await runTurn(2, "durian", ["page-b"], [], { lanes, ...prefix });
395
+ expect(lastPool.slice(0, 2)).toEqual(["topic-x", "page-b"]);
396
+ expect(t2.selections.map((s) => s.slug)).toEqual(["page-b"]);
397
+ expect(loggedSources(2)).toEqual([{ slug: "page-b", source: "hot" }]);
398
+ });
358
399
 
359
- // Turn 2 selects a DIFFERENT page; page-a carries forward un-re-selected.
360
- denseHits = [{ article: "topic-x", section: 0 }];
361
- const t2 = await runTurn(2, "cherry", ["topic-x"], [], {
400
+ test("a finder hit on a core page logs core, not the finder lane", async () => {
401
+ const lanes = await buildLanes();
402
+ // "apple" hits page-a via the needle, but page-a is CORE — the pool lists
403
+ // it twice (stable-prefix card + finder snippet line, by design), the
404
+ // selection dedupes to one slug, and the row attributes to core.
405
+ const result = await runTurn(1, "apple", ["page-a"], [], {
362
406
  lanes,
363
- workingSet,
407
+ core: ["page-a"],
364
408
  });
365
- expect(t2.currentSelections.map((s) => s.slug)).not.toContain("page-a");
366
- expect(t2.finalInjection).toContain("page-a");
367
-
368
- // The carried page is logged with the carry-forward source tag.
369
- const t2Rows = loggedSources(2);
370
- expect(t2Rows).toContainEqual({ slug: "topic-x", source: "needle" });
371
- expect(t2Rows).toContainEqual({ slug: "page-a", source: "carry-forward" });
372
-
373
- // Working set accumulates both pages across the two turns.
374
- expect(workingSet.union()).toEqual(new Set(["page-a", "topic-x"]));
409
+ expect(lastPool.filter((s) => s === "page-a")).toHaveLength(2);
410
+ expect(result.selections).toEqual([{ slug: "page-a", pinned: false }]);
411
+ expect(result.lanes.finder.map((c) => c.slug)).toContain("page-a");
412
+ expect(loggedSources(1)).toEqual([{ slug: "page-a", source: "core" }]);
375
413
  });
376
414
  });
377
415
 
@@ -385,15 +423,10 @@ describe("memory-v3 shadow integration — lane-source attribution", () => {
385
423
  test("a needle-ranked capability selection is logged with the needle source", async () => {
386
424
  const lanes = await buildLanes();
387
425
  // "durian" matches the capability page's content section, so selecting it
388
- // records a `sectionBySlug` entry and the coarse mapping attributes it
426
+ // records a `matchedSections` entry and the lane mapping attributes it
389
427
  // `needle` (capabilities are indexed pages now, not sectionless add-ins).
390
- const result = await runTurn(1, "durian", [CAPABILITY_SLUG], [], {
391
- lanes,
392
- workingSet: new WorkingSet(),
393
- });
394
- expect(result.currentSelections.map((s) => s.slug)).toEqual([
395
- CAPABILITY_SLUG,
396
- ]);
428
+ const result = await runTurn(1, "durian", [CAPABILITY_SLUG], [], { lanes });
429
+ expect(result.selections.map((s) => s.slug)).toEqual([CAPABILITY_SLUG]);
397
430
  expect(loggedSources(1)).toEqual([
398
431
  { slug: CAPABILITY_SLUG, source: "needle" },
399
432
  ]);
@@ -402,43 +435,51 @@ describe("memory-v3 shadow integration — lane-source attribution", () => {
402
435
 
403
436
  // ---------------------------------------------------------------------------
404
437
  // A/B readout: summarizeSelections aggregates the logged shadow run by lane
405
- // source, and reports turn count + distinct-slug (working-set) footprint.
438
+ // source, and reports turn count + distinct-slug selection footprint.
406
439
  // ---------------------------------------------------------------------------
407
440
 
408
441
  describe("memory-v3 shadow integration — selection-log readout", () => {
409
442
  test("summarizeSelections aggregates a multi-turn run by source", async () => {
410
443
  const lanes = await buildLanes();
411
- const workingSet = new WorkingSet();
444
+ const prefix = { hot: ["topic-x"] };
412
445
 
413
- // Turn 1: needle selects page-a (matched "apple").
414
- await runTurn(1, "apple", ["page-a"], [], { lanes, workingSet });
415
- // Turn 2: needle selects page-b (matched "banana"); page-a carries forward.
446
+ // Turn 1: needle selects page-a (matched "apple"), plus the hot topic-x.
447
+ await runTurn(1, "apple", ["page-a", "topic-x"], [], { lanes, ...prefix });
448
+ // Turn 2: needle selects page-b (matched "banana").
416
449
  denseHits = [{ article: "page-b", section: 0 }];
417
- await runTurn(2, "banana", ["page-b"], [], { lanes, workingSet });
450
+ await runTurn(2, "banana", ["page-b"], [], { lanes, ...prefix });
418
451
  // Turn 3: needle selects the capability page (matched "durian" in its
419
- // content); page-a and page-b carry forward.
452
+ // content).
420
453
  denseHits = [];
421
- await runTurn(3, "durian", [CAPABILITY_SLUG], [], { lanes, workingSet });
454
+ await runTurn(3, "durian", [CAPABILITY_SLUG], [], { lanes, ...prefix });
422
455
 
423
456
  const summary = summarizeSelections(CONV);
424
457
  // needle: page-a (t1) + page-b (t2) + capability page (t3) = 3.
425
458
  expect(summary.bySource.needle).toBe(3);
426
- // No selection was attributed to the edge lane in this run.
459
+ // hot: topic-x (t1).
460
+ expect(summary.bySource.hot).toBe(1);
461
+ // No selection was attributed to the core or edge lanes in this run.
462
+ expect(summary.bySource.core).toBe(0);
427
463
  expect(summary.bySource.edge).toBe(0);
428
- // carry-forward: page-a (t2) + page-a & page-b (t3) = 3.
429
- expect(summary.bySource["carry-forward"]).toBe(3);
430
464
  // dense lane surfaced candidates but none were selected.
431
465
  expect(summary.bySource.dense).toBe(0);
432
466
  // Three turns logged selections.
433
467
  expect(summary.turns).toBe(3);
434
- // Distinct slugs across the run: page-a, page-b, the capability page.
435
- expect(summary.distinctSlugs).toBe(3);
468
+ // Distinct slugs across the run: page-a, topic-x, page-b, the capability
469
+ // page.
470
+ expect(summary.distinctSlugs).toBe(4);
436
471
  });
437
472
 
438
473
  test("summarizeSelections reports zeros for a conversation with no rows", () => {
439
474
  const summary = summarizeSelections("conv-empty");
440
475
  expect(summary).toEqual({
441
- bySource: { needle: 0, dense: 0, edge: 0, "carry-forward": 0 },
476
+ bySource: {
477
+ core: 0,
478
+ hot: 0,
479
+ needle: 0,
480
+ dense: 0,
481
+ edge: 0,
482
+ },
442
483
  turns: 0,
443
484
  distinctSlugs: 0,
444
485
  });