@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,387 @@
1
+ /**
2
+ * Tests for the default `image-recovery` plugin's hooks.
3
+ *
4
+ * `post-model-call` (error-recovery):
5
+ * - On a provider rejection carrying an image-too-large error, the hook
6
+ * downscales the oversized image blocks in the working history (a text note
7
+ * when resize is a no-op on this host), persists the same downgrade durably,
8
+ * marks the per-conversation bound, and asks the loop to continue.
9
+ * - Bounded to one pass per turn via that bound: a second consecutive image
10
+ * rejection is left to surface (the bound is cleared by the `stop` hook, not
11
+ * here).
12
+ * - Ignores non-image errors, tool-bearing turns, and finalized (non-error)
13
+ * replies — none of which it ever touches the bound for.
14
+ *
15
+ * `stop` (terminal cleanup):
16
+ * - Clears the recovery bound unconditionally on the definitive terminal stop,
17
+ * so the next turn always recovers afresh no matter how the turn ended.
18
+ *
19
+ * Uses the real SQLite DB wired up via `test-preload.ts` (per-file temp
20
+ * workspace) so the durable-persist leg exercises the same path production does.
21
+ */
22
+
23
+ import { beforeEach, describe, expect, test } from "bun:test";
24
+
25
+ import {
26
+ addMessage,
27
+ createConversation,
28
+ getMessages,
29
+ } from "../memory/conversation-crud.js";
30
+ import { getDb } from "../memory/db-connection.js";
31
+ import { initializeDb } from "../memory/db-init.js";
32
+ import { HOOKS } from "../plugin-api/constants.js";
33
+ import type {
34
+ PluginLogger,
35
+ PostModelCallContext,
36
+ StopContext,
37
+ } from "../plugin-api/types.js";
38
+ import postModelCall from "../plugins/defaults/image-recovery/hooks/post-model-call.js";
39
+ import stop from "../plugins/defaults/image-recovery/hooks/stop.js";
40
+ import {
41
+ clearImageRecoveryAttempted,
42
+ isImageRecoveryAttempted,
43
+ markImageRecoveryAttempted,
44
+ resetImageRecoveryStoreForTests,
45
+ } from "../plugins/defaults/image-recovery/image-recovery-state-store.js";
46
+ import { defaultImageRecoveryPlugin } from "../plugins/defaults/index.js";
47
+ import { runHook } from "../plugins/pipeline.js";
48
+ import {
49
+ registerPlugin,
50
+ resetPluginRegistryForTests,
51
+ } from "../plugins/registry.js";
52
+ import type { ContentBlock, Message } from "../providers/types.js";
53
+
54
+ initializeDb();
55
+
56
+ /** Provider rejection text matched by `isImageDimensionsTooLargeError`. */
57
+ const IMAGE_ERROR_MESSAGE =
58
+ "At least one of the image dimensions exceed max allowed size: 8000 pixels";
59
+
60
+ const PROVIDER_MAX_IMAGE_DIMENSION = 8000;
61
+
62
+ const noopLogger: PluginLogger = {
63
+ info: () => {},
64
+ warn: () => {},
65
+ error: () => {},
66
+ debug: () => {},
67
+ };
68
+
69
+ function resetTables(): void {
70
+ const db = getDb();
71
+ db.run("DELETE FROM message_attachments");
72
+ db.run("DELETE FROM attachments");
73
+ db.run("DELETE FROM memory_segments");
74
+ db.run("DELETE FROM memory_embeddings");
75
+ db.run("DELETE FROM messages");
76
+ db.run("DELETE FROM conversations");
77
+ }
78
+
79
+ /**
80
+ * Build a minimal PNG whose IHDR declares the given dimensions. Only the 8-byte
81
+ * signature and width/height fields (read by `parseImageDimensions`) need to be
82
+ * correct — enough for the recovery path to classify the image as over the
83
+ * provider pixel cap. Depending on whether this host can re-encode the image,
84
+ * recovery either downscales it or replaces it with the unsendable note; the
85
+ * tests assert the rejected payload is gone rather than which of those landed.
86
+ */
87
+ function makePngBase64(width: number, height: number): string {
88
+ return Buffer.from(
89
+ Uint8Array.from([
90
+ 0x89,
91
+ 0x50,
92
+ 0x4e,
93
+ 0x47,
94
+ 0x0d,
95
+ 0x0a,
96
+ 0x1a,
97
+ 0x0a, // PNG signature
98
+ 0x00,
99
+ 0x00,
100
+ 0x00,
101
+ 0x0d, // IHDR length (13)
102
+ 0x49,
103
+ 0x48,
104
+ 0x44,
105
+ 0x52, // "IHDR"
106
+ (width >>> 24) & 0xff,
107
+ (width >>> 16) & 0xff,
108
+ (width >>> 8) & 0xff,
109
+ width & 0xff,
110
+ (height >>> 24) & 0xff,
111
+ (height >>> 16) & 0xff,
112
+ (height >>> 8) & 0xff,
113
+ height & 0xff,
114
+ 0x08,
115
+ 0x06,
116
+ 0x00,
117
+ 0x00,
118
+ 0x00, // bit depth / color type / etc.
119
+ ]),
120
+ ).toString("base64");
121
+ }
122
+
123
+ function imageBlock(data: string): ContentBlock {
124
+ return {
125
+ type: "image",
126
+ source: { type: "base64", media_type: "image/png", data },
127
+ };
128
+ }
129
+
130
+ /** A base64 PNG whose declared dimensions exceed the provider pixel cap. */
131
+ const OVERSIZED_IMAGE_DATA = makePngBase64(
132
+ PROVIDER_MAX_IMAGE_DIMENSION + 1000,
133
+ 6000,
134
+ );
135
+
136
+ /** A user turn carrying an image past the provider pixel cap. */
137
+ function oversizedImageHistory(): Message[] {
138
+ return [
139
+ {
140
+ role: "user",
141
+ content: [
142
+ { type: "text", text: "look at this" },
143
+ imageBlock(OVERSIZED_IMAGE_DATA),
144
+ ],
145
+ },
146
+ ];
147
+ }
148
+
149
+ function makeStopCtx(overrides: Partial<StopContext> = {}): StopContext {
150
+ return {
151
+ conversationId: "conv-stop",
152
+ messages: [],
153
+ exitReason: "no_tool_calls",
154
+ logger: noopLogger,
155
+ ...overrides,
156
+ };
157
+ }
158
+
159
+ function makePostModelCallCtx(
160
+ overrides: Partial<PostModelCallContext> = {},
161
+ ): PostModelCallContext {
162
+ return {
163
+ conversationId: "conv-pmc",
164
+ callSite: "mainAgent",
165
+ content: [],
166
+ messages: [],
167
+ stopReason: null,
168
+ decision: "stop",
169
+ logger: noopLogger,
170
+ ...overrides,
171
+ };
172
+ }
173
+
174
+ describe("image-recovery post-model-call hook — direct", () => {
175
+ beforeEach(() => {
176
+ resetImageRecoveryStoreForTests();
177
+ resetTables();
178
+ });
179
+
180
+ test("recoverable image error → recovers oversized image and continues", async () => {
181
+ // GIVEN a provider rejection carrying an image-too-large error over a
182
+ // history with an oversized image block.
183
+ const messages = oversizedImageHistory();
184
+ const ctx = makePostModelCallCtx({
185
+ messages,
186
+ error: new Error(IMAGE_ERROR_MESSAGE),
187
+ });
188
+
189
+ // WHEN the hook runs.
190
+ await postModelCall(ctx);
191
+
192
+ // THEN it asks the loop to retry, marks the bound, and the oversized image
193
+ // is recovered — downscaled to a smaller image or collapsed to the
194
+ // unsendable note, depending on whether this host can resize — so the
195
+ // rejected payload is gone from the working history either way.
196
+ expect(ctx.decision).toBe("continue");
197
+ expect(isImageRecoveryAttempted(ctx.conversationId)).toBe(true);
198
+ expect(JSON.stringify(ctx.messages)).not.toContain(OVERSIZED_IMAGE_DATA);
199
+ // The accompanying text block is preserved — only the image is rewritten.
200
+ expect(ctx.messages[0].content).toContainEqual({
201
+ type: "text",
202
+ text: "look at this",
203
+ });
204
+ });
205
+
206
+ test("durably persists the downgrade so the image cannot resurface", async () => {
207
+ // GIVEN a conversation whose stored history holds an oversized image.
208
+ const conv = createConversation();
209
+ await addMessage(
210
+ conv.id,
211
+ "user",
212
+ JSON.stringify([
213
+ { type: "text", text: "look at this" },
214
+ imageBlock(OVERSIZED_IMAGE_DATA),
215
+ ]),
216
+ { skipIndexing: true },
217
+ );
218
+ const ctx = makePostModelCallCtx({
219
+ conversationId: conv.id,
220
+ messages: oversizedImageHistory(),
221
+ error: new Error(IMAGE_ERROR_MESSAGE),
222
+ });
223
+
224
+ // WHEN the hook recovers the rejection.
225
+ await postModelCall(ctx);
226
+
227
+ // THEN the stored row no longer holds the oversized payload — it was
228
+ // rewritten (downscaled or replaced with the unsendable note) so a later
229
+ // turn cannot rehydrate the rejected upload from the DB.
230
+ expect(getMessages(conv.id)[0].content).not.toContain(OVERSIZED_IMAGE_DATA);
231
+ });
232
+
233
+ test("second consecutive image rejection is left to surface", async () => {
234
+ // GIVEN a turn whose first image rejection already triggered a recovery.
235
+ const conversationId = "conv-bounded";
236
+ markImageRecoveryAttempted(conversationId);
237
+ const messages = oversizedImageHistory();
238
+ const ctx = makePostModelCallCtx({
239
+ conversationId,
240
+ messages,
241
+ error: new Error(IMAGE_ERROR_MESSAGE),
242
+ });
243
+
244
+ // WHEN a second image rejection reaches the hook.
245
+ await postModelCall(ctx);
246
+
247
+ // THEN it does not recover again — the error surfaces.
248
+ expect(ctx.decision).toBe("stop");
249
+ expect(ctx.messages).toEqual(messages);
250
+
251
+ // AND the bound stays marked — the hook never clears it; the `stop` hook
252
+ // clears it at the turn boundary.
253
+ expect(isImageRecoveryAttempted(conversationId)).toBe(true);
254
+ });
255
+
256
+ test("a mid-turn tool-bearing turn is a no-op", async () => {
257
+ // GIVEN this turn already recovered an image rejection (bound marked), then
258
+ // the model returns a tool-bearing turn that the loop continues mid-run.
259
+ const conversationId = "conv-tool-turn";
260
+ markImageRecoveryAttempted(conversationId);
261
+ const ctx = makePostModelCallCtx({
262
+ conversationId,
263
+ content: [{ type: "tool_use", id: "tu_1", name: "do", input: {} }],
264
+ });
265
+
266
+ // WHEN the hook runs on that tool-bearing turn.
267
+ await postModelCall(ctx);
268
+
269
+ // THEN it leaves the bound alone — there is no provider rejection to act on.
270
+ expect(isImageRecoveryAttempted(conversationId)).toBe(true);
271
+ });
272
+
273
+ test("a non-image error while continuing is a no-op", async () => {
274
+ // GIVEN this turn already recovered an image rejection (bound marked), then
275
+ // an earlier hook (e.g. history-repair on an ordering rejection) recovered a
276
+ // different error and set the decision to continue.
277
+ const conversationId = "conv-cross-hook";
278
+ markImageRecoveryAttempted(conversationId);
279
+ const ctx = makePostModelCallCtx({
280
+ conversationId,
281
+ decision: "continue",
282
+ error: new Error("messages: roles must alternate"),
283
+ });
284
+
285
+ // WHEN the image-recovery hook runs after that earlier hook.
286
+ await postModelCall(ctx);
287
+
288
+ // THEN it leaves the in-flight continue and the bound alone — it only acts
289
+ // on an image-too-large rejection.
290
+ expect(ctx.decision).toBe("continue");
291
+ expect(isImageRecoveryAttempted(conversationId)).toBe(true);
292
+ });
293
+
294
+ test("non-image error is left untouched", async () => {
295
+ // GIVEN a provider rejection that is not an image-size violation.
296
+ const messages = oversizedImageHistory();
297
+ const ctx = makePostModelCallCtx({
298
+ messages,
299
+ error: new Error("rate limit exceeded"),
300
+ });
301
+
302
+ // WHEN the hook runs.
303
+ await postModelCall(ctx);
304
+
305
+ // THEN it defers — the decision and history are unchanged.
306
+ expect(ctx.decision).toBe("stop");
307
+ expect(ctx.messages).toEqual(messages);
308
+ });
309
+
310
+ test("finalized (non-error) reply is ignored", async () => {
311
+ // GIVEN a finalized reply — the model returned content, no error.
312
+ const messages = oversizedImageHistory();
313
+ const ctx = makePostModelCallCtx({
314
+ messages,
315
+ content: [{ type: "text", text: "done" }],
316
+ stopReason: "end_turn",
317
+ });
318
+
319
+ // WHEN the hook runs.
320
+ await postModelCall(ctx);
321
+
322
+ // THEN the model response is left untouched — recovery only applies to
323
+ // image rejections.
324
+ expect(ctx.decision).toBe("stop");
325
+ expect(ctx.messages).toEqual(messages);
326
+ });
327
+ });
328
+
329
+ // ─── stop hook (terminal cleanup) ────────────────────────────────────────────
330
+
331
+ describe("image-recovery stop hook — direct", () => {
332
+ beforeEach(() => {
333
+ resetImageRecoveryStoreForTests();
334
+ });
335
+
336
+ test("a terminal stop clears the recovery bound", async () => {
337
+ // GIVEN a turn marked a recovery-retry.
338
+ const conversationId = "conv-backstop";
339
+ markImageRecoveryAttempted(conversationId);
340
+
341
+ // WHEN the terminal stop hook runs.
342
+ await stop(makeStopCtx({ conversationId }));
343
+
344
+ // THEN the bound is cleared so the next turn recovers afresh.
345
+ expect(isImageRecoveryAttempted(conversationId)).toBe(false);
346
+ });
347
+
348
+ test("clears the bound regardless of how the turn ended", async () => {
349
+ // GIVEN a turn marked a recovery-retry that ends on an abort rather than a
350
+ // finalized reply.
351
+ const conversationId = "conv-abort";
352
+ markImageRecoveryAttempted(conversationId);
353
+
354
+ // WHEN the terminal stop hook runs for that exit.
355
+ await stop(makeStopCtx({ conversationId, exitReason: "aborted_pre_call" }));
356
+
357
+ // THEN the bound is still cleared — `stop` is the definitive terminal, so
358
+ // the next turn always recovers afresh.
359
+ expect(isImageRecoveryAttempted(conversationId)).toBe(false);
360
+ });
361
+ });
362
+
363
+ describe("image-recovery post-model-call hook — via runHook", () => {
364
+ beforeEach(() => {
365
+ resetPluginRegistryForTests();
366
+ resetImageRecoveryStoreForTests();
367
+ resetTables();
368
+ clearImageRecoveryAttempted("conv-pmc");
369
+ });
370
+
371
+ test("registering the default plugin recovers an image rejection", async () => {
372
+ // GIVEN the default image-recovery plugin is registered.
373
+ registerPlugin(defaultImageRecoveryPlugin);
374
+ const messages = oversizedImageHistory();
375
+
376
+ // WHEN the post-model-call chain runs on an image-too-large rejection.
377
+ const result = await runHook<PostModelCallContext>(
378
+ HOOKS.POST_MODEL_CALL,
379
+ makePostModelCallCtx({ messages, error: new Error(IMAGE_ERROR_MESSAGE) }),
380
+ );
381
+
382
+ // THEN the working history is recovered (the rejected payload is gone) and
383
+ // the loop is asked to retry.
384
+ expect(result.decision).toBe("continue");
385
+ expect(JSON.stringify(result.messages)).not.toContain(OVERSIZED_IMAGE_DATA);
386
+ });
387
+ });
@@ -342,16 +342,17 @@ describe("injector chain", () => {
342
342
  expect(byName.get("thread-focus")).toBe(DEFAULT_INJECTOR_ORDER.threadFocus);
343
343
  });
344
344
 
345
- test("the injector chain sorts the defaults plus memory-v3 by ascending order", () => {
346
- // The assembled chain merges the defaults with the memory-v3 injector and
347
- // sorts by `order`, so memory-v3 (order 1000) sits last.
345
+ test("the injector chain sorts the defaults plus the memory-v3 injectors by ascending order", () => {
346
+ // The assembled chain merges the defaults with the two memory-v3
347
+ // injectors and sorts by `order`, so the cards injector (order 1000) and
348
+ // the spotlight injector (order 1001) sit last, in that order.
348
349
  const chain = getInjectorChain();
349
350
  const orders = chain.map((i) => i.order);
350
351
  expect(orders).toEqual([...orders].sort((a, b) => a - b));
351
- expect(chain[chain.length - 1]?.name).toBe("memory-v3-shadow");
352
352
  expect(chain.map((i) => i.name)).toEqual([
353
353
  ...defaultInjectors.map((i) => i.name),
354
354
  "memory-v3-shadow",
355
+ "memory-v3-spotlight",
355
356
  ]);
356
357
  });
357
358