@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
@@ -1,18 +1,34 @@
1
1
  /**
2
2
  * Memory v3 — single pool selector.
3
3
  *
4
- * Runs a SINGLE forced-tool call over one unified candidate pool. Each candidate
5
- * is a page slug paired with a per-candidate `descriptor` the caller supplies —
6
- * the matched section text for a needle/dense hit, or a curated link description
7
- * for an edge page. The caller assembles the pool by unioning the section lanes;
8
- * the pool selector only decides which of those candidates the reply will draw
9
- * on.
4
+ * Runs a SINGLE forced-tool call over one unified candidate pool rendered in
5
+ * two segments that share one numbering:
10
6
  *
11
- * No cache breakpoint. The pool is recomputed from per-turn section matches and
12
- * is therefore dynamic per turn, so it carries no `cache_control` breakpoint:
13
- * caching a prefix that changes every turn would never hit. Carry-forward (the
14
- * working set unioned in by the orchestrator) is the cache mechanism here, not a
15
- * static prefix breakpoint.
7
+ * 1. STABLE PREFIX — the core+hot lane pages as FULL CARDS (head section +
8
+ * section TOC, see `card.ts`), numbered `[1]…[m]` in pool order. The
9
+ * cards are query- and conversation-state-independent, so the rendered
10
+ * segment is byte-identical across turns while the lanes are unchanged
11
+ * (lane invalidation at consolidation is the recompute cadence). It is
12
+ * emitted as its OWN content block carrying a `cache_control`
13
+ * breakpoint, so it rides the provider KV cache — block-level
14
+ * `cache_control` is preserved through `toAnthropicBlockSafe` (PR
15
+ * #33258; covered by the caller-stamped-block tests in
16
+ * `anthropic-provider.test.ts`).
17
+ * 2. DYNAMIC TAIL — the per-turn finder candidates as compact numbered
18
+ * lines (`[m+1] <slug> — <matched-section snippet>`), then the
19
+ * situational/recent/current conversation context. Re-rendered every
20
+ * turn; never cached. `disableTurnStartCache` suppresses the provider's
21
+ * auto-applied 1h turn-start breakpoint, which would otherwise land on
22
+ * this per-turn-varying block and pay cache_creation with no future hit
23
+ * (same rationale as the v2 router).
24
+ *
25
+ * Candidate composition is deliberately conversation-state-independent:
26
+ * already-injected pages are NOT filtered out of the pool — that would change
27
+ * the stable prefix per conversation state and bust the cache. Re-selecting
28
+ * an injected page is harmless (injection dedup happens downstream) and feeds
29
+ * hot-set frecency + spotlight eligibility. A page may appear BOTH as a
30
+ * stable-prefix card and as a finder line (its current matched section);
31
+ * selections are deduped by slug.
16
32
  *
17
33
  * Failure handling is recall-safe by construction:
18
34
  * - explicit `ids` → select exactly those candidates,
@@ -27,11 +43,16 @@
27
43
 
28
44
  import { z } from "zod";
29
45
 
46
+ import { cachedTextBlock } from "../../../providers/cache-control.js";
30
47
  import {
31
48
  extractToolUse,
32
49
  getConfiguredProvider,
33
50
  } from "../../../providers/provider-send-message.js";
34
- import type { Message, ToolDefinition } from "../../../providers/types.js";
51
+ import type {
52
+ ContentBlock,
53
+ Message,
54
+ ToolDefinition,
55
+ } from "../../../providers/types.js";
35
56
  import { getLogger } from "../../../util/logger.js";
36
57
  import { truncate } from "../../../util/truncate.js";
37
58
  import { retryForResult } from "./llm-retry.js";
@@ -39,22 +60,40 @@ import type { MemoryRoutingTurn, SelectedPage, Slug } from "./types.js";
39
60
 
40
61
  const log = getLogger("memory-v3-pool-select");
41
62
 
42
- /** A candidate page in the unified pool, with the descriptor that justifies it. */
63
+ /** A dynamic-tail (finder) candidate: the slug plus the descriptor that
64
+ * justifies it — a matched section for a needle/dense hit, or a curated link
65
+ * description for an edge page. Rendered as a one-line snippet. */
43
66
  export interface PoolCandidate {
44
67
  slug: Slug;
45
- /**
46
- * The text that justifies this candidate: a matched section for a
47
- * needle/dense hit, or a curated link description for an edge page. Rendered
48
- * (truncated) in the numbered candidate list the selector judges against.
49
- */
50
68
  descriptor: string;
51
69
  }
52
70
 
71
+ /** A stable-prefix candidate: the slug plus its pre-rendered FULL card
72
+ * (`renderCard` output — head section + TOC). Cards must be byte-stable
73
+ * across turns for the prefix to ride the provider KV cache, which is why
74
+ * callers pre-render them at lane init rather than per turn. */
75
+ export interface StableCandidate {
76
+ slug: Slug;
77
+ card: string;
78
+ }
79
+
80
+ /**
81
+ * The selector's unified candidate pool in cache order: the stable prefix
82
+ * (core+hot cards) then the dynamic finder tail. The two segments share one
83
+ * numbering — `[1]…[m]` cards, `[m+1]…` finder lines — and MAY repeat a slug
84
+ * (a finder hit on a core/hot page keeps its matched-section line so the
85
+ * page's CURRENT relevance stays visible); selections are deduped by slug.
86
+ */
87
+ export interface SelectorPool {
88
+ stable: StableCandidate[];
89
+ finder: PoolCandidate[];
90
+ }
91
+
53
92
  /** Tool name forced via `tool_choice`. Shared constant so tests can match it. */
54
93
  const SELECT_PAGES_TOOL_NAME = "select_pages";
55
94
 
56
- /** Descriptors are truncated to keep the candidate list compact. */
57
- const DESCRIPTOR_MAX_CHARS = 400;
95
+ /** Finder-line snippets are truncated to keep the dynamic tail compact. */
96
+ const SNIPPET_MAX_CHARS = 300;
58
97
 
59
98
  const SelectPagesSchema = z.object({
60
99
  // Optional: an omitted `ids` field is the recall-safe "keep everything"
@@ -66,8 +105,8 @@ const SelectPagesSchema = z.object({
66
105
  const SELECT_PAGES_TOOL: ToolDefinition = {
67
106
  name: SELECT_PAGES_TOOL_NAME,
68
107
  description:
69
- "Select the candidate pages whose content the reply would directly draw " +
70
- "on. Lean inclusive — when in doubt, keep a candidate; for a list or " +
108
+ "Select the candidate pages whose content the reply would draw on. Lean " +
109
+ "inclusive — when in doubt, keep a candidate; for a list or " +
71
110
  '"all of X" request keep every candidate that belongs. Pass `pinned_ids` ' +
72
111
  "for pages the conversation is centrally about. Omit `ids` only as a " +
73
112
  "recall-safe fallback when you cannot judge the pool (keeps every " +
@@ -88,34 +127,63 @@ const SELECT_PAGES_TOOL: ToolDefinition = {
88
127
  },
89
128
  };
90
129
 
91
- const SYSTEM_PROMPT = `You are given a pool of candidate memory pages, each surfaced because some part of it matched the conversation. Select every page whose specific content the reply to THIS message would directly draw on.
130
+ const SYSTEM_PROMPT = `You are given the candidate memory pages for an assistant's next reply, in two segments that share one numbering: full page cards first (the curated core and recently-recurring pages, shown every turn), then this turn's search hits as one-line snippets.
131
+
132
+ Select EVERY candidate whose content the upcoming reply would draw on. That includes facts the reply needs, but equally register, established framing, calibration rules, and relationship/person/project texture — pages that shape HOW to reply, not only what to say. There is no limit on how many you may select; recall matters more than precision, so when a candidate could plausibly inform the reply, keep it. For a list or an "all of X" request, keep EVERY candidate that belongs to X rather than guessing a representative subset.
92
133
 
93
- Lean inclusive: recall matters more than precision here, so when a candidate could plausibly inform the reply, keep it. For a list or an "all of X" request, keep EVERY candidate that belongs to X rather than guessing a representative subset.
134
+ Pages you select persist in the conversation automatically, and re-selecting a page that is already in context is harmless (duplicates are removed downstream) — so never withhold a candidate because it might have been selected before. Judge each candidate only by whether the upcoming reply would draw on it.
94
135
 
95
136
  A page can be relevant because of the current situation — the date or the live scratchpad — not only the message: keep a page the situation makes pertinent (e.g. a person whose anniversary is today).
96
137
 
97
138
  If the conversation is centrally ABOUT a page (rather than only peripherally relevant to it), mark that page as pinned. Call \`select_pages\` with the chosen IDs. Omit \`ids\` only as a recall-safe fallback when you cannot judge the pool (keeps every candidate); return \`[]\` when candidates are present but none are relevant.`;
98
139
 
99
- /** Collapse a descriptor to one line and cap its length for the candidate list. */
100
- function renderDescriptor(descriptor: string): string {
101
- return truncate(descriptor.replace(/\s+/g, " ").trim(), DESCRIPTOR_MAX_CHARS);
140
+ /** Collapse a descriptor to one line and cap its length for a finder line. */
141
+ function renderSnippet(descriptor: string): string {
142
+ return truncate(descriptor.replace(/\s+/g, " ").trim(), SNIPPET_MAX_CHARS);
143
+ }
144
+
145
+ /**
146
+ * Render the stable prefix: each core/hot card prefixed with its pool number.
147
+ * Pure concatenation of pre-rendered cards — byte-identical across turns for
148
+ * identical `stable` input, which is the cache contract.
149
+ */
150
+ function renderCardSegment(stable: StableCandidate[]): string {
151
+ const cards = stable.map((c, i) => `[${i + 1}] ${c.card}`);
152
+ return `<candidate_cards>\n${cards.join("\n\n")}\n</candidate_cards>`;
102
153
  }
103
154
 
104
155
  /**
105
- * Render the numbered candidate list: one `[i] slug — descriptor` line per
106
- * candidate, descriptors collapsed to one line and length-capped. The pool is
107
- * dynamic per turn, so this block is NOT cached (see the module doc).
156
+ * Render the finder tail: one `[m+i] slug — snippet` line per candidate,
157
+ * numbered continuing after the `offset` stable-prefix cards. A candidate
158
+ * with an empty descriptor renders without the dash.
108
159
  */
109
- function renderCandidateList(pool: PoolCandidate[]): string {
110
- const lines = pool.map(
111
- (c, i) => `[${i + 1}] ${c.slug} — ${renderDescriptor(c.descriptor)}`,
112
- );
160
+ function renderFinderSegment(finder: PoolCandidate[], offset: number): string {
161
+ const lines = finder.map((c, i) => {
162
+ const snippet = renderSnippet(c.descriptor);
163
+ const id = offset + i + 1;
164
+ return snippet.length > 0
165
+ ? `[${id}] ${c.slug} — ${snippet}`
166
+ : `[${id}] ${c.slug}`;
167
+ });
113
168
  return `<candidates>\n${lines.join("\n")}\n</candidates>`;
114
169
  }
115
170
 
171
+ /** Dedupe selections by slug, preserving first-seen order and ORing pinned
172
+ * flags (a page can be selected as both a card and a finder line). */
173
+ function dedupeBySlug(
174
+ entries: Array<{ slug: Slug; pinned: boolean }>,
175
+ ): SelectedPage[] {
176
+ const bySlug = new Map<Slug, boolean>();
177
+ for (const entry of entries) {
178
+ bySlug.set(entry.slug, (bySlug.get(entry.slug) ?? false) || entry.pinned);
179
+ }
180
+ return [...bySlug].map(([slug, pinned]) => ({ slug, pinned }));
181
+ }
182
+
116
183
  /**
117
184
  * Run the single forced-tool selector over the unified candidate pool. Returns
118
- * the pages to inject.
185
+ * the pages to inject, deduped by slug (a page that appeared as both a card
186
+ * and a finder line yields one entry, pinned flags ORed).
119
187
  *
120
188
  * An omitted `ids` keeps ALL candidates (the recall-safe "all of these are
121
189
  * relevant" signal); an explicit `[]` keeps none; an infrastructure failure
@@ -123,41 +191,48 @@ function renderCandidateList(pool: PoolCandidate[]): string {
123
191
  * recall lanes the orchestrator unions in.
124
192
  */
125
193
  export async function selectPool(
126
- pool: PoolCandidate[],
194
+ pool: SelectorPool,
127
195
  turn: MemoryRoutingTurn,
128
196
  ): Promise<SelectedPage[]> {
129
- if (pool.length === 0) return [];
197
+ // The concatenated numbering: ids 1…m are the stable-prefix cards, ids
198
+ // m+1… are the finder lines.
199
+ const ordered: Slug[] = [
200
+ ...pool.stable.map((c) => c.slug),
201
+ ...pool.finder.map((c) => c.slug),
202
+ ];
203
+ if (ordered.length === 0) return [];
130
204
 
131
205
  const keepAll = (): SelectedPage[] =>
132
- pool.map((c) => ({ slug: c.slug, pinned: false }));
206
+ dedupeBySlug(ordered.map((slug) => ({ slug, pinned: false })));
133
207
 
134
208
  const provider = await getConfiguredProvider("memoryV3SelectL2");
135
209
  if (!provider) {
136
210
  log.warn(
137
- { candidateCount: pool.length },
211
+ { candidateCount: ordered.length },
138
212
  "pool selector provider unavailable; degrading to deterministic lanes",
139
213
  );
140
214
  return [];
141
215
  }
142
216
 
143
- // The pool is dynamic per turn, so there is no static cache breakpoint here;
144
- // carry-forward is the cache mechanism. The candidate list and the per-turn
145
- // context go in a single plain text block.
146
- const userMsg: Message = {
147
- role: "user",
148
- content: [
149
- {
150
- type: "text",
151
- text:
152
- `${renderCandidateList(pool)}\n` +
153
- (turn.situationalContext
154
- ? `<situation>${turn.situationalContext}</situation>\n`
155
- : "") +
156
- `<recent_context>${turn.recentContext}</recent_context>\n` +
157
- `<current_message>${turn.currentMessage}</current_message>`,
158
- },
159
- ],
160
- };
217
+ // Two content blocks: the stable prefix (cards) carries the cache
218
+ // breakpoint; the dynamic tail (finder lines + per-turn context) does not.
219
+ // See the module doc for the cache contract.
220
+ const content: ContentBlock[] = [];
221
+ if (pool.stable.length > 0) {
222
+ content.push(cachedTextBlock(renderCardSegment(pool.stable)));
223
+ }
224
+ const tailParts: string[] = [];
225
+ if (pool.finder.length > 0) {
226
+ tailParts.push(renderFinderSegment(pool.finder, pool.stable.length));
227
+ }
228
+ if (turn.situationalContext) {
229
+ tailParts.push(`<situation>${turn.situationalContext}</situation>`);
230
+ }
231
+ tailParts.push(`<recent_context>${turn.recentContext}</recent_context>`);
232
+ tailParts.push(`<current_message>${turn.currentMessage}</current_message>`);
233
+ content.push({ type: "text", text: tailParts.join("\n") });
234
+
235
+ const userMsg: Message = { role: "user", content };
161
236
 
162
237
  // One forced-tool call, retried a few times so a transient malformed response
163
238
  // (no usable tool_use, or tool input that fails the schema) re-prompts before
@@ -170,6 +245,11 @@ export async function selectPool(
170
245
  config: {
171
246
  callSite: "memoryV3SelectL2" as const,
172
247
  tool_choice: { type: "tool" as const, name: SELECT_PAGES_TOOL_NAME },
248
+ // The last block of this one-shot message varies every turn; the
249
+ // provider's auto-applied turn-start breakpoint would land on it and
250
+ // pay cache_creation with no future hit. The stable-prefix block
251
+ // above carries its own breakpoint instead.
252
+ disableTurnStartCache: true,
173
253
  },
174
254
  });
175
255
  const toolBlock = extractToolUse(response);
@@ -180,7 +260,7 @@ export async function selectPool(
180
260
 
181
261
  if (parsed === null) {
182
262
  log.warn(
183
- { candidateCount: pool.length },
263
+ { candidateCount: ordered.length },
184
264
  "pool selector could not obtain a selection after retries; degrading to deterministic lanes",
185
265
  );
186
266
  return [];
@@ -191,14 +271,12 @@ export async function selectPool(
191
271
 
192
272
  const pinned = new Set(parsed.pinned_ids ?? []);
193
273
 
194
- // Map 1-based IDs back to candidate slugs, dropping out-of-range IDs without
195
- // throwing. De-duplicate while preserving model-returned order.
196
- const seen = new Set<number>();
197
- const selected: SelectedPage[] = [];
274
+ // Map 1-based IDs over the concatenated numbering, dropping out-of-range
275
+ // IDs without throwing, then dedupe by slug (pinned flags ORed).
276
+ const selected: Array<{ slug: Slug; pinned: boolean }> = [];
198
277
  for (const id of parsed.ids) {
199
- if (id < 1 || id > pool.length || seen.has(id)) continue;
200
- seen.add(id);
201
- selected.push({ slug: pool[id - 1]!.slug, pinned: pinned.has(id) });
278
+ if (id < 1 || id > ordered.length) continue;
279
+ selected.push({ slug: ordered[id - 1]!, pinned: pinned.has(id) });
202
280
  }
203
- return selected;
281
+ return dedupeBySlug(selected);
204
282
  }