@vellumai/assistant 0.8.8 → 0.8.9-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 (340) hide show
  1. package/bun.lock +2 -2
  2. package/examples/plugins/echo/README.md +61 -60
  3. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  4. package/examples/plugins/echo/hooks/stop.ts +16 -0
  5. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  6. package/examples/plugins/echo/package.json +1 -2
  7. package/examples/plugins/echo/src/emit.ts +19 -0
  8. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  9. package/openapi.yaml +236 -6
  10. package/package.json +2 -2
  11. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  12. package/src/__tests__/agent-loop-exit-reason.test.ts +185 -140
  13. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  14. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  15. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  16. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  17. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  18. package/src/__tests__/agent-loop.test.ts +441 -96
  19. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  20. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  21. package/src/__tests__/anthropic-provider.test.ts +1 -1
  22. package/src/__tests__/app-control-flow.test.ts +1 -1
  23. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  24. package/src/__tests__/approval-cascade.test.ts +5 -4
  25. package/src/__tests__/approval-routes-http.test.ts +4 -1
  26. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  27. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  28. package/src/__tests__/channel-approvals.test.ts +1 -1
  29. package/src/__tests__/compaction-circuit.test.ts +258 -0
  30. package/src/__tests__/compaction-direct.test.ts +132 -0
  31. package/src/__tests__/compaction-events.test.ts +5 -5
  32. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -4
  33. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  34. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +59 -103
  35. package/src/__tests__/conversation-agent-loop-overflow.test.ts +94 -189
  36. package/src/__tests__/conversation-agent-loop.test.ts +249 -490
  37. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  38. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -4
  39. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  40. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -4
  41. package/src/__tests__/conversation-process-callsite.test.ts +14 -14
  42. package/src/__tests__/conversation-provider-retry-repair.test.ts +18 -16
  43. package/src/__tests__/conversation-queue.test.ts +9 -9
  44. package/src/__tests__/conversation-runtime-assembly.test.ts +923 -231
  45. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  46. package/src/__tests__/conversation-slash-queue.test.ts +6 -4
  47. package/src/__tests__/conversation-slash-unknown.test.ts +6 -4
  48. package/src/__tests__/conversation-speed-override.test.ts +10 -9
  49. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  50. package/src/__tests__/conversation-workspace-cache-state.test.ts +23 -20
  51. package/src/__tests__/conversation-workspace-injection.test.ts +68 -6
  52. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +14 -11
  53. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  54. package/src/__tests__/credential-security-invariants.test.ts +0 -1
  55. package/src/__tests__/db-acp-history.test.ts +101 -0
  56. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  57. package/src/__tests__/empty-response-hook.test.ts +1 -1
  58. package/src/__tests__/file-write-tool.test.ts +63 -0
  59. package/src/__tests__/gateway-only-guard.test.ts +12 -2
  60. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  61. package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
  62. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  63. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  64. package/src/__tests__/heartbeat-service.test.ts +1 -0
  65. package/src/__tests__/history-repair-hook.test.ts +1 -1
  66. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  67. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  68. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  69. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  70. package/src/__tests__/injector-background-turn.test.ts +13 -23
  71. package/src/__tests__/injector-chain.test.ts +268 -44
  72. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  73. package/src/__tests__/injector-document-comments.test.ts +97 -114
  74. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  75. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  76. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  77. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  78. package/src/__tests__/memory-retrieval-hook.test.ts +73 -6
  79. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  80. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  81. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  82. package/src/__tests__/plugin-bootstrap.test.ts +12 -23
  83. package/src/__tests__/plugin-registry.test.ts +3 -49
  84. package/src/__tests__/plugin-types.test.ts +0 -70
  85. package/src/__tests__/reaction-persistence.test.ts +1 -1
  86. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  87. package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
  88. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  89. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  90. package/src/__tests__/subagent-detail.test.ts +25 -7
  91. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  92. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  93. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  94. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  95. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  96. package/src/__tests__/title-generate-hook.test.ts +1 -1
  97. package/src/__tests__/tool-error-hook.test.ts +1 -1
  98. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  99. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  100. package/src/acp/__tests__/agent-process.test.ts +161 -0
  101. package/src/acp/__tests__/client-handler.test.ts +40 -0
  102. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  103. package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
  104. package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
  105. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  106. package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
  107. package/src/acp/agent-process.ts +61 -1
  108. package/src/acp/auto-install.test.ts +196 -0
  109. package/src/acp/auto-install.ts +177 -0
  110. package/src/acp/client-handler.ts +31 -0
  111. package/src/acp/feature-gate.test.ts +48 -0
  112. package/src/acp/feature-gate.ts +34 -0
  113. package/src/acp/prepare-agent-env.ts +83 -29
  114. package/src/acp/resolve-agent.test.ts +320 -7
  115. package/src/acp/resolve-agent.ts +182 -18
  116. package/src/acp/resume-hint.ts +25 -0
  117. package/src/acp/session-manager.ts +495 -73
  118. package/src/acp/types.ts +8 -0
  119. package/src/agent/compaction-circuit.ts +60 -102
  120. package/src/agent/loop.ts +390 -240
  121. package/src/api/responses/conversation-message.ts +14 -1
  122. package/src/approvals/guardian-request-resolvers.ts +1 -1
  123. package/src/background-wake/next-wake.ts +1 -0
  124. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  125. package/src/cli/commands/plugins.ts +43 -37
  126. package/src/cli/lib/__tests__/install-from-github.test.ts +429 -111
  127. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  128. package/src/cli/lib/__tests__/plugin-details.test.ts +372 -0
  129. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +220 -0
  130. package/src/cli/lib/__tests__/search-plugins.test.ts +226 -32
  131. package/src/cli/lib/install-from-github.ts +464 -55
  132. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  133. package/src/cli/lib/plugin-details.ts +409 -0
  134. package/src/cli/lib/plugin-marketplace.ts +197 -0
  135. package/src/cli/lib/search-plugins.ts +195 -29
  136. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  137. package/src/config/acp-defaults.test.ts +10 -0
  138. package/src/config/acp-defaults.ts +6 -0
  139. package/src/config/bundled-skills/acp/SKILL.md +83 -31
  140. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  141. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  142. package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
  143. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  144. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  145. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  146. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  147. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  148. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  149. package/src/config/bundled-tool-registry.ts +2 -0
  150. package/src/config/feature-flag-registry.json +14 -5
  151. package/src/config/schemas/heartbeat.ts +9 -0
  152. package/src/context/strip-injections.ts +8 -2
  153. package/src/context/window-manager.ts +27 -13
  154. package/src/daemon/conversation-agent-loop-handlers.ts +10 -35
  155. package/src/daemon/conversation-agent-loop.ts +167 -1005
  156. package/src/daemon/conversation-lifecycle.ts +11 -255
  157. package/src/daemon/conversation-process.ts +8 -136
  158. package/src/daemon/conversation-registry.ts +159 -0
  159. package/src/daemon/conversation-runtime-assembly.ts +293 -392
  160. package/src/daemon/conversation-store.ts +9 -90
  161. package/src/daemon/conversation-surfaces.ts +24 -8
  162. package/src/daemon/conversation-workspace.ts +17 -0
  163. package/src/daemon/conversation.ts +383 -56
  164. package/src/daemon/external-plugins-bootstrap.ts +14 -19
  165. package/src/daemon/handlers/conversations.ts +3 -1
  166. package/src/daemon/handlers/skills.ts +4 -1
  167. package/src/daemon/host-proxy-preactivation.ts +1 -3
  168. package/src/daemon/lifecycle.ts +21 -0
  169. package/src/daemon/server.ts +2 -0
  170. package/src/daemon/wake-conversation-ops.ts +269 -0
  171. package/src/embedded/plugin-api.ts +2 -2
  172. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  173. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  174. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  175. package/src/heartbeat/heartbeat-service.ts +26 -0
  176. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  177. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  178. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  179. package/src/ipc/skill-routes/memory.ts +4 -2
  180. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  181. package/src/memory/conversation-crud.ts +29 -19
  182. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  183. package/src/memory/db-init.ts +2 -0
  184. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  185. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  186. package/src/memory/jobs-worker.ts +25 -1
  187. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  188. package/src/memory/migrations/index.ts +1 -0
  189. package/src/memory/schema/acp.ts +4 -0
  190. package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
  191. package/src/memory/v2/consolidation-job.ts +13 -4
  192. package/src/plugin-api/constants.ts +4 -0
  193. package/src/plugin-api/index.ts +6 -5
  194. package/src/plugin-api/types.ts +75 -0
  195. package/src/plugins/defaults/compaction/compact.ts +59 -0
  196. package/src/plugins/defaults/compaction/manager-store.ts +44 -0
  197. package/src/plugins/defaults/compaction/package.json +1 -2
  198. package/src/plugins/defaults/empty-response/package.json +0 -1
  199. package/src/plugins/defaults/history-repair/package.json +0 -1
  200. package/src/plugins/defaults/index.ts +135 -26
  201. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +103 -38
  202. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +167 -56
  203. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  204. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  205. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  206. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
  207. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +9 -6
  208. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
  209. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +8 -5
  210. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
  211. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
  212. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +10 -5
  213. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
  214. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +5 -5
  215. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +16 -17
  216. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -2
  217. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +9 -5
  218. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +5 -2
  219. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  220. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  221. package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
  222. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +15 -8
  223. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +2 -2
  224. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  225. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
  226. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/provider-blocks.ts +1 -1
  227. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +7 -3
  228. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
  229. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +5 -5
  230. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
  231. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +7 -7
  232. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +32 -94
  233. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
  234. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +1 -1
  235. package/src/plugins/defaults/title-generate/package.json +0 -1
  236. package/src/plugins/defaults/tool-error/package.json +0 -1
  237. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  238. package/src/plugins/pipeline.ts +6 -293
  239. package/src/plugins/registry.ts +9 -37
  240. package/src/plugins/types.ts +76 -381
  241. package/src/plugins/user-loader.ts +30 -127
  242. package/src/proactive-artifact/aux-message-injector.ts +1 -1
  243. package/src/proactive-artifact/job.test.ts +1 -1
  244. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  245. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +35 -3
  246. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  247. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  248. package/src/runtime/agent-wake.ts +108 -209
  249. package/src/runtime/assistant-event-hub.ts +1 -1
  250. package/src/runtime/channel-approvals.ts +1 -1
  251. package/src/runtime/interactive-ui.ts +1 -1
  252. package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
  253. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  254. package/src/runtime/routes/__tests__/plugins-routes.test.ts +398 -73
  255. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  256. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  257. package/src/runtime/routes/acp-routes.test.ts +89 -25
  258. package/src/runtime/routes/acp-routes.ts +81 -29
  259. package/src/runtime/routes/approval-routes.ts +1 -1
  260. package/src/runtime/routes/browser-routes.ts +1 -1
  261. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  262. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  263. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  264. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  265. package/src/runtime/routes/conversation-routes.ts +28 -2
  266. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  267. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  268. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  269. package/src/runtime/routes/host-cu-routes.ts +1 -1
  270. package/src/runtime/routes/identity-routes.ts +18 -3
  271. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  272. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  273. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  274. package/src/runtime/routes/memory-v3-routes.ts +16 -6
  275. package/src/runtime/routes/playground/helpers.ts +1 -1
  276. package/src/runtime/routes/plugins-routes.ts +336 -35
  277. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  278. package/src/runtime/routes/work-items-routes.ts +2 -4
  279. package/src/runtime/services/conversation-serializer.ts +1 -1
  280. package/src/signals/cancel.ts +2 -4
  281. package/src/subagent/manager.ts +21 -5
  282. package/src/tools/acp/context.ts +20 -0
  283. package/src/tools/acp/list-agents.test.ts +7 -1
  284. package/src/tools/acp/spawn.test.ts +158 -55
  285. package/src/tools/acp/spawn.ts +47 -72
  286. package/src/tools/acp/steer.test.ts +105 -8
  287. package/src/tools/acp/steer.ts +48 -17
  288. package/src/tools/apps/executors.ts +13 -8
  289. package/src/tools/filesystem/write.ts +34 -0
  290. package/src/tools/subagent/spawn.ts +2 -4
  291. package/src/tools/ui-surface/definitions.ts +25 -5
  292. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  293. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  294. package/docs/plugins.md +0 -832
  295. package/examples/plugins/echo/register.ts +0 -143
  296. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  297. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  298. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  299. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  300. package/src/__tests__/pipeline-runner.test.ts +0 -554
  301. package/src/__tests__/plugin-external-api.test.ts +0 -68
  302. package/src/daemon/wake-target-adapter.ts +0 -253
  303. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  304. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  305. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  306. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  307. package/src/plugins/defaults/compaction/register.ts +0 -35
  308. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  309. package/src/plugins/defaults/empty-response/register.ts +0 -23
  310. package/src/plugins/defaults/history-repair/register.ts +0 -24
  311. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  312. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  313. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  314. package/src/plugins/defaults/title-generate/register.ts +0 -35
  315. package/src/plugins/defaults/tool-error/register.ts +0 -23
  316. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  317. package/src/plugins/external-api.ts +0 -104
  318. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
  319. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
  320. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  321. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  322. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +0 -0
  323. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
  324. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/provider-blocks.test.ts +0 -0
  325. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
  326. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
  327. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  328. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  329. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
  330. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  331. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  332. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  333. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  334. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  335. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  336. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
  337. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
  338. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
  339. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
  340. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
@@ -0,0 +1,357 @@
1
+ /**
2
+ * Tests for the `pre-model-call` and `assistant-message` plugin hooks: a plugin
3
+ * can edit the outbound request, transform the finalized assistant message
4
+ * (persisted + streamed), and defer the live stream so the transformed text is
5
+ * emitted once. All hooks here use neutral transforms (redaction / uppercasing).
6
+ */
7
+ import { beforeEach, describe, expect, test } from "bun:test";
8
+
9
+ import type { AgentEvent } from "../agent/loop.js";
10
+ import { AgentLoop } from "../agent/loop.js";
11
+ import type {
12
+ AssistantMessageContext,
13
+ PreModelCallContext,
14
+ } from "../plugin-api/types.js";
15
+ import { resetPluginRegistryAndRegisterDefaults } from "../plugins/defaults/index.js";
16
+ import { registerPlugin } from "../plugins/registry.js";
17
+ import type {
18
+ ContentBlock,
19
+ Message,
20
+ ProviderResponse,
21
+ } from "../providers/types.js";
22
+ import { createMockProvider, textResponse } from "./helpers/mock-provider.js";
23
+
24
+ const userMessage: Message = {
25
+ role: "user",
26
+ content: [{ type: "text", text: "Hello" }],
27
+ };
28
+
29
+ function collect(events: AgentEvent[]): (event: AgentEvent) => void {
30
+ return (event) => events.push(event);
31
+ }
32
+
33
+ function streamedText(events: AgentEvent[]): string {
34
+ return events
35
+ .filter(
36
+ (e): e is Extract<AgentEvent, { type: "text_delta" }> =>
37
+ e.type === "text_delta",
38
+ )
39
+ .map((e) => e.text)
40
+ .join("");
41
+ }
42
+
43
+ function textOf(content: ReadonlyArray<ContentBlock>): string {
44
+ let out = "";
45
+ for (const block of content) if (block.type === "text") out += block.text;
46
+ return out;
47
+ }
48
+
49
+ function lastAssistant(history: Message[]): Message {
50
+ for (let i = history.length - 1; i >= 0; i--) {
51
+ if (history[i].role === "assistant") return history[i];
52
+ }
53
+ throw new Error("no assistant message in history");
54
+ }
55
+
56
+ function registerOutputHookPlugin(hooks: {
57
+ preModelCall?: (ctx: PreModelCallContext) => void;
58
+ assistantMessage?: (ctx: AssistantMessageContext) => void;
59
+ }): void {
60
+ registerPlugin({
61
+ manifest: { name: "test-output-hooks", version: "0.0.0" },
62
+ hooks: {
63
+ ...(hooks.preModelCall
64
+ ? {
65
+ "pre-model-call": async (ctx: PreModelCallContext) => {
66
+ hooks.preModelCall!(ctx);
67
+ },
68
+ }
69
+ : {}),
70
+ ...(hooks.assistantMessage
71
+ ? {
72
+ "assistant-message": async (ctx: AssistantMessageContext) => {
73
+ hooks.assistantMessage!(ctx);
74
+ },
75
+ }
76
+ : {}),
77
+ },
78
+ });
79
+ }
80
+
81
+ describe("agent loop output hooks", () => {
82
+ beforeEach(() => {
83
+ resetPluginRegistryAndRegisterDefaults();
84
+ });
85
+
86
+ test("assistant-message transforms the persisted message content", async () => {
87
+ registerOutputHookPlugin({
88
+ assistantMessage: (ctx) => {
89
+ ctx.content = ctx.content.map((b) =>
90
+ b.type === "text"
91
+ ? { type: "text", text: b.text.replace("secret", "[redacted]") }
92
+ : b,
93
+ );
94
+ },
95
+ });
96
+ const { provider } = createMockProvider([textResponse("my secret value")]);
97
+ const loop = new AgentLoop({
98
+ provider: provider,
99
+ systemPrompt: "system",
100
+ conversationId: "test-conversation",
101
+ });
102
+ const events: AgentEvent[] = [];
103
+ const { history } = await loop.run({
104
+ messages: [userMessage],
105
+ onEvent: collect(events),
106
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
107
+ });
108
+ expect(textOf(lastAssistant(history).content)).toBe("my [redacted] value");
109
+ });
110
+
111
+ test("deferred output: the real stream is suppressed and the transformed text is emitted once", async () => {
112
+ registerOutputHookPlugin({
113
+ preModelCall: (ctx) => {
114
+ ctx.deferAssistantOutput = true;
115
+ },
116
+ assistantMessage: (ctx) => {
117
+ ctx.content = [{ type: "text", text: "[filtered]" }];
118
+ },
119
+ });
120
+ const { provider } = createMockProvider([textResponse("my secret value")]);
121
+ const loop = new AgentLoop({
122
+ provider: provider,
123
+ systemPrompt: "system",
124
+ conversationId: "test-conversation",
125
+ });
126
+ const events: AgentEvent[] = [];
127
+ const { history } = await loop.run({
128
+ messages: [userMessage],
129
+ onEvent: collect(events),
130
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
131
+ });
132
+ // Her real words never streamed; only the transformed text did, once.
133
+ expect(streamedText(events)).not.toContain("secret");
134
+ expect(streamedText(events)).toBe("[filtered]");
135
+ expect(textOf(lastAssistant(history).content)).toBe("[filtered]");
136
+ });
137
+
138
+ test("without defer, the real text still streams while storage is transformed", async () => {
139
+ registerOutputHookPlugin({
140
+ assistantMessage: (ctx) => {
141
+ ctx.content = [{ type: "text", text: "[stored]" }];
142
+ },
143
+ });
144
+ const { provider } = createMockProvider([textResponse("live text")]);
145
+ const loop = new AgentLoop({
146
+ provider: provider,
147
+ systemPrompt: "system",
148
+ conversationId: "test-conversation",
149
+ });
150
+ const events: AgentEvent[] = [];
151
+ const { history } = await loop.run({
152
+ messages: [userMessage],
153
+ onEvent: collect(events),
154
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
155
+ });
156
+ expect(streamedText(events)).toBe("live text"); // streamed live, untransformed
157
+ expect(textOf(lastAssistant(history).content)).toBe("[stored]"); // storage transformed
158
+ });
159
+
160
+ test("transforms text but leaves tool_use blocks intact", async () => {
161
+ const toolAndText: ProviderResponse = {
162
+ content: [
163
+ { type: "text", text: "calling" },
164
+ { type: "tool_use", id: "t1", name: "noop", input: {} },
165
+ ],
166
+ model: "mock-model",
167
+ usage: { inputTokens: 1, outputTokens: 1 },
168
+ stopReason: "tool_use",
169
+ };
170
+ registerOutputHookPlugin({
171
+ assistantMessage: (ctx) => {
172
+ ctx.content = ctx.content.map((b) =>
173
+ b.type === "text" ? { type: "text", text: b.text.toUpperCase() } : b,
174
+ );
175
+ },
176
+ });
177
+ const { provider } = createMockProvider([
178
+ toolAndText,
179
+ textResponse("done"),
180
+ ]);
181
+ const loop = new AgentLoop({
182
+ provider: provider,
183
+ systemPrompt: "system",
184
+ conversationId: "test-conversation",
185
+ tools: [
186
+ {
187
+ name: "noop",
188
+ description: "",
189
+ input_schema: { type: "object", properties: {} },
190
+ },
191
+ ],
192
+ toolExecutor: async () => ({ content: "ok", isError: false }),
193
+ });
194
+ const { history } = await loop.run({
195
+ messages: [userMessage],
196
+ onEvent: collect([]),
197
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
198
+ });
199
+ const toolTurn = history.find(
200
+ (m) =>
201
+ m.role === "assistant" && m.content.some((b) => b.type === "tool_use"),
202
+ )!;
203
+ expect(toolTurn.content.find((b) => b.type === "text")).toEqual({
204
+ type: "text",
205
+ text: "CALLING",
206
+ });
207
+ expect(toolTurn.content.find((b) => b.type === "tool_use")).toMatchObject({
208
+ type: "tool_use",
209
+ id: "t1",
210
+ name: "noop",
211
+ });
212
+ });
213
+
214
+ test("pre-model-call can edit the outbound system prompt", async () => {
215
+ registerOutputHookPlugin({
216
+ preModelCall: (ctx) => {
217
+ ctx.systemPrompt = `${ctx.systemPrompt ?? ""} [EDITED]`;
218
+ },
219
+ });
220
+ const { provider, calls } = createMockProvider([textResponse("hi")]);
221
+ const loop = new AgentLoop({
222
+ provider: provider,
223
+ systemPrompt: "base prompt",
224
+ conversationId: "test-conversation",
225
+ });
226
+ await loop.run({
227
+ messages: [userMessage],
228
+ onEvent: collect([]),
229
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
230
+ });
231
+ expect(calls[0].systemPrompt).toContain("[EDITED]");
232
+ });
233
+
234
+ test("fail-open: a hook that mutates in place AND then throws cannot corrupt the persisted content", async () => {
235
+ // The hook mutates the array it receives before throwing. If the loop
236
+ // handed the hook the real `assistantMessage.content` array, the
237
+ // mid-mutation would survive into history. The loop must clone the
238
+ // content before invoking the hook.
239
+ registerOutputHookPlugin({
240
+ assistantMessage: (ctx) => {
241
+ ctx.content.push({ type: "text", text: "[INJECTED]" });
242
+ throw new Error("boom");
243
+ },
244
+ });
245
+ const { provider } = createMockProvider([textResponse("untouched")]);
246
+ const loop = new AgentLoop({
247
+ provider: provider,
248
+ systemPrompt: "system",
249
+ conversationId: "test-conversation",
250
+ });
251
+ const { history } = await loop.run({
252
+ messages: [userMessage],
253
+ onEvent: collect([]),
254
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
255
+ });
256
+ const finalContent = lastAssistant(history).content;
257
+ expect(textOf(finalContent)).toBe("untouched");
258
+ expect(
259
+ finalContent.some((b) => b.type === "text" && b.text === "[INJECTED]"),
260
+ ).toBe(false);
261
+ });
262
+
263
+ test("max_tokens turn: the hook fires and the deferred final text is emitted", async () => {
264
+ // Without this, an output-filter plugin misses the truncated reply; with
265
+ // defer set, the live stream was suppressed and the client would see
266
+ // nothing at all.
267
+ const seen: { calls: number } = { calls: 0 };
268
+ registerOutputHookPlugin({
269
+ preModelCall: (ctx) => {
270
+ ctx.deferAssistantOutput = true;
271
+ },
272
+ assistantMessage: (ctx) => {
273
+ seen.calls += 1;
274
+ ctx.content = ctx.content.map((b) =>
275
+ b.type === "text" ? { type: "text", text: b.text.toUpperCase() } : b,
276
+ );
277
+ },
278
+ });
279
+ const truncated: ProviderResponse = {
280
+ content: [{ type: "text", text: "partial answer" }],
281
+ model: "mock-model",
282
+ usage: { inputTokens: 1, outputTokens: 1 },
283
+ stopReason: "max_tokens",
284
+ };
285
+ const { provider } = createMockProvider([truncated]);
286
+ const loop = new AgentLoop({
287
+ provider: provider,
288
+ systemPrompt: "system",
289
+ conversationId: "test-conversation",
290
+ });
291
+ const events: AgentEvent[] = [];
292
+ const { history } = await loop.run({
293
+ messages: [userMessage],
294
+ onEvent: collect(events),
295
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
296
+ });
297
+ expect(seen.calls).toBe(1);
298
+ expect(textOf(lastAssistant(history).content)).toBe("PARTIAL ANSWER");
299
+ // Real stream suppressed; transformed final text emitted once.
300
+ expect(streamedText(events)).toBe("PARTIAL ANSWER");
301
+ });
302
+
303
+ test("deferred final text passes through sensitive-output substitution", async () => {
304
+ // A tool returns a sensitive binding; the next assistant turn uses the
305
+ // placeholder (the persisted message must keep it — model never sees real
306
+ // values on reload), but the deferred final stream must show the real
307
+ // value, just like the normal live stream would.
308
+ registerOutputHookPlugin({
309
+ preModelCall: (ctx) => {
310
+ ctx.deferAssistantOutput = true;
311
+ },
312
+ });
313
+ const placeholder = "VELLUM_ASSISTANT_INVITE_CODE_TESTXXXX";
314
+ const real = "real-invite-code-xyz";
315
+ const toolThenText = [
316
+ {
317
+ content: [{ type: "tool_use", id: "t1", name: "issue", input: {} }],
318
+ model: "mock-model",
319
+ usage: { inputTokens: 1, outputTokens: 1 },
320
+ stopReason: "tool_use",
321
+ } as ProviderResponse,
322
+ textResponse(`Your code is ${placeholder}.`),
323
+ ];
324
+ const { provider } = createMockProvider(toolThenText);
325
+ const loop = new AgentLoop({
326
+ provider: provider,
327
+ systemPrompt: "system",
328
+ conversationId: "test-conversation",
329
+ tools: [
330
+ {
331
+ name: "issue",
332
+ description: "",
333
+ input_schema: { type: "object", properties: {} },
334
+ },
335
+ ],
336
+ toolExecutor: async () => ({
337
+ content: `code=${placeholder}`,
338
+ isError: false,
339
+ sensitiveBindings: [{ kind: "invite_code", placeholder, value: real }],
340
+ }),
341
+ });
342
+ const events: AgentEvent[] = [];
343
+ const { history } = await loop.run({
344
+ messages: [userMessage],
345
+ onEvent: collect(events),
346
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
347
+ });
348
+ // Persisted message keeps the placeholder — model must never see real
349
+ // values on reload.
350
+ expect(textOf(lastAssistant(history).content)).toContain(placeholder);
351
+ expect(textOf(lastAssistant(history).content)).not.toContain(real);
352
+ // Streamed final text shows the substituted real value, matching the
353
+ // behavior of the normal live stream.
354
+ expect(streamedText(events)).toContain(real);
355
+ expect(streamedText(events)).not.toContain(placeholder);
356
+ });
357
+ });
@@ -110,13 +110,19 @@ describe("AgentLoop.run — overrideProfile plumbing", () => {
110
110
  _input: Record<string, unknown>,
111
111
  ) => ({ content: "ok", isError: false });
112
112
 
113
- const loop = new AgentLoop(provider, "system", {
113
+ const loop = new AgentLoop({
114
+ provider: provider,
115
+ systemPrompt: "system",
116
+ conversationId: "test-conversation",
114
117
  config: { maxTokens: 1024 },
115
118
  tools: dummyTools,
116
119
  toolExecutor: toolExecutor,
117
120
  });
118
121
 
119
- await loop.run([userMessage], () => {}, {
122
+ await loop.run({
123
+ messages: [userMessage],
124
+ onEvent: () => {},
125
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
120
126
  callSite: "mainAgent",
121
127
  overrideProfile: "fast",
122
128
  });
@@ -130,11 +136,18 @@ describe("AgentLoop.run — overrideProfile plumbing", () => {
130
136
 
131
137
  test("omits overrideProfile from providerConfig when unset (default behavior unchanged)", async () => {
132
138
  const { provider, configs } = makeRecordingProvider([textResponse("hi")]);
133
- const loop = new AgentLoop(provider, "system", {
139
+ const loop = new AgentLoop({
140
+ provider: provider,
141
+ systemPrompt: "system",
142
+ conversationId: "test-conversation",
134
143
  config: { maxTokens: 1024 },
135
144
  });
136
145
 
137
- await loop.run([userMessage], () => {});
146
+ await loop.run({
147
+ messages: [userMessage],
148
+ onEvent: () => {},
149
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
150
+ });
138
151
 
139
152
  // Single send, no overrideProfile field at all.
140
153
  expect(configs()).toHaveLength(1);
@@ -148,11 +161,17 @@ describe("AgentLoop.run — overrideProfile plumbing", () => {
148
161
  // receives so a non-existent profile silently falls back at the
149
162
  // provider layer (covered by provider-send-message-override-profile.test.ts).
150
163
  const { provider, configs } = makeRecordingProvider([textResponse("hi")]);
151
- const loop = new AgentLoop(provider, "system", {
164
+ const loop = new AgentLoop({
165
+ provider: provider,
166
+ systemPrompt: "system",
167
+ conversationId: "test-conversation",
152
168
  config: { maxTokens: 1024 },
153
169
  });
154
170
 
155
- await loop.run([userMessage], () => {}, {
171
+ await loop.run({
172
+ messages: [userMessage],
173
+ onEvent: () => {},
174
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
156
175
  callSite: "mainAgent",
157
176
  overrideProfile: "does-not-exist",
158
177
  });
@@ -83,14 +83,19 @@ describe("AgentLoop provider_error event emission", () => {
83
83
  const { provider, calls } = makeThrowingProvider("anthropic", () => thrown);
84
84
 
85
85
  const events: AgentEvent[] = [];
86
- const loop = new AgentLoop(provider, "you are a helpful assistant");
86
+ const loop = new AgentLoop({
87
+ provider: provider,
88
+ systemPrompt: "you are a helpful assistant",
89
+ conversationId: "test-conversation",
90
+ });
87
91
 
88
- await loop.run(
89
- [{ role: "user", content: [{ type: "text", text: "hi" }] }],
90
- (e) => {
92
+ await loop.run({
93
+ messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
94
+ onEvent: (e) => {
91
95
  events.push(e);
92
96
  },
93
- );
97
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
98
+ });
94
99
 
95
100
  expect(calls).toHaveLength(1);
96
101
 
@@ -122,14 +127,19 @@ describe("AgentLoop provider_error event emission", () => {
122
127
  const { provider } = makeThrowingProvider("gemini", () => thrown);
123
128
 
124
129
  const events: AgentEvent[] = [];
125
- const loop = new AgentLoop(provider, "system");
130
+ const loop = new AgentLoop({
131
+ provider: provider,
132
+ systemPrompt: "system",
133
+ conversationId: "test-conversation",
134
+ });
126
135
 
127
- await loop.run(
128
- [{ role: "user", content: [{ type: "text", text: "hi" }] }],
129
- (e) => {
136
+ await loop.run({
137
+ messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
138
+ onEvent: (e) => {
130
139
  events.push(e);
131
140
  },
132
- );
141
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
142
+ });
133
143
 
134
144
  const providerErrorIdx = events.findIndex(
135
145
  (e) => e.type === "provider_error",
@@ -148,14 +158,19 @@ describe("AgentLoop provider_error event emission", () => {
148
158
  const { provider } = makeThrowingProvider("openai", () => thrown);
149
159
 
150
160
  const events: AgentEvent[] = [];
151
- const loop = new AgentLoop(provider, "system");
161
+ const loop = new AgentLoop({
162
+ provider: provider,
163
+ systemPrompt: "system",
164
+ conversationId: "test-conversation",
165
+ });
152
166
 
153
- await loop.run(
154
- [{ role: "user", content: [{ type: "text", text: "hi" }] }],
155
- (e) => {
167
+ await loop.run({
168
+ messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
169
+ onEvent: (e) => {
156
170
  events.push(e);
157
171
  },
158
- );
172
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
173
+ });
159
174
 
160
175
  const providerErrorEvent = events.find((e) => e.type === "provider_error");
161
176
  expect(providerErrorEvent).toBeDefined();
@@ -179,15 +194,20 @@ describe("AgentLoop provider_error event emission", () => {
179
194
  });
180
195
 
181
196
  const events: AgentEvent[] = [];
182
- const loop = new AgentLoop(provider, "system");
197
+ const loop = new AgentLoop({
198
+ provider: provider,
199
+ systemPrompt: "system",
200
+ conversationId: "test-conversation",
201
+ });
183
202
 
184
- await loop.run(
185
- [{ role: "user", content: [{ type: "text", text: "hi" }] }],
186
- (e) => {
203
+ await loop.run({
204
+ messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
205
+ onEvent: (e) => {
187
206
  events.push(e);
188
207
  },
189
- { signal: controller.signal },
190
- );
208
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
209
+ signal: controller.signal,
210
+ });
191
211
 
192
212
  const providerErrorEvent = events.find((e) => e.type === "provider_error");
193
213
  // Cancellation should never produce a recording row — there's no
@@ -37,17 +37,21 @@ function createMockProvider(): {
37
37
  describe("AgentLoop thinking and effort", () => {
38
38
  test("sends adaptive thinking when thinking is enabled", async () => {
39
39
  const { provider, lastConfig } = createMockProvider();
40
- const loop = new AgentLoop(provider, "test", {
40
+ const loop = new AgentLoop({
41
+ provider: provider,
42
+ systemPrompt: "test",
43
+ conversationId: "test-conversation",
41
44
  config: {
42
45
  maxTokens: 64000,
43
46
  thinking: { enabled: true },
44
47
  },
45
48
  });
46
49
 
47
- await loop.run(
48
- [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
49
- () => {},
50
- );
50
+ await loop.run({
51
+ messages: [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
52
+ onEvent: () => {},
53
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
54
+ });
51
55
 
52
56
  const config = lastConfig()!;
53
57
  const thinking = config.thinking as { type: string };
@@ -56,17 +60,21 @@ describe("AgentLoop thinking and effort", () => {
56
60
 
57
61
  test("sends disabled thinking when thinking is disabled", async () => {
58
62
  const { provider, lastConfig } = createMockProvider();
59
- const loop = new AgentLoop(provider, "test", {
63
+ const loop = new AgentLoop({
64
+ provider: provider,
65
+ systemPrompt: "test",
66
+ conversationId: "test-conversation",
60
67
  config: {
61
68
  maxTokens: 64000,
62
69
  thinking: { enabled: false },
63
70
  },
64
71
  });
65
72
 
66
- await loop.run(
67
- [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
68
- () => {},
69
- );
73
+ await loop.run({
74
+ messages: [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
75
+ onEvent: () => {},
76
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
77
+ });
70
78
 
71
79
  const config = lastConfig()!;
72
80
  expect(config.thinking).toEqual({ type: "disabled" });
@@ -74,17 +82,21 @@ describe("AgentLoop thinking and effort", () => {
74
82
 
75
83
  test("sends effort in provider config", async () => {
76
84
  const { provider, lastConfig } = createMockProvider();
77
- const loop = new AgentLoop(provider, "test", {
85
+ const loop = new AgentLoop({
86
+ provider: provider,
87
+ systemPrompt: "test",
88
+ conversationId: "test-conversation",
78
89
  config: {
79
90
  maxTokens: 64000,
80
91
  effort: "high",
81
92
  },
82
93
  });
83
94
 
84
- await loop.run(
85
- [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
86
- () => {},
87
- );
95
+ await loop.run({
96
+ messages: [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
97
+ onEvent: () => {},
98
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
99
+ });
88
100
 
89
101
  const config = lastConfig()!;
90
102
  expect(config.effort).toBe("high");
@@ -92,7 +104,10 @@ describe("AgentLoop thinking and effort", () => {
92
104
 
93
105
  test("sends effort with disabled thinking when thinking is disabled", async () => {
94
106
  const { provider, lastConfig } = createMockProvider();
95
- const loop = new AgentLoop(provider, "test", {
107
+ const loop = new AgentLoop({
108
+ provider: provider,
109
+ systemPrompt: "test",
110
+ conversationId: "test-conversation",
96
111
  config: {
97
112
  maxTokens: 64000,
98
113
  effort: "medium",
@@ -100,10 +115,11 @@ describe("AgentLoop thinking and effort", () => {
100
115
  },
101
116
  });
102
117
 
103
- await loop.run(
104
- [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
105
- () => {},
106
- );
118
+ await loop.run({
119
+ messages: [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
120
+ onEvent: () => {},
121
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
122
+ });
107
123
 
108
124
  const config = lastConfig()!;
109
125
  expect(config.effort).toBe("medium");