@vellumai/assistant 0.4.49 → 0.4.51

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 (353) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/integrations.md +2 -2
  4. package/docs/architecture/keychain-broker.md +6 -6
  5. package/docs/architecture/memory.md +180 -119
  6. package/knip.json +32 -0
  7. package/package.json +3 -2
  8. package/src/__tests__/agent-loop.test.ts +3 -1
  9. package/src/__tests__/anthropic-provider.test.ts +114 -23
  10. package/src/__tests__/approval-cascade.test.ts +1 -15
  11. package/src/__tests__/approval-routes-http.test.ts +2 -0
  12. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  13. package/src/__tests__/btw-routes.test.ts +61 -5
  14. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  15. package/src/__tests__/checker.test.ts +13 -0
  16. package/src/__tests__/config-schema.test.ts +1 -68
  17. package/src/__tests__/config-watcher.test.ts +8 -0
  18. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  19. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  20. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  21. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  22. package/src/__tests__/credential-security-invariants.test.ts +8 -7
  23. package/src/__tests__/credential-vault-unit.test.ts +23 -18
  24. package/src/__tests__/credential-vault.test.ts +30 -18
  25. package/src/__tests__/credentials-cli.test.ts +257 -82
  26. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  27. package/src/__tests__/date-context.test.ts +93 -77
  28. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  29. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  30. package/src/__tests__/history-repair.test.ts +245 -0
  31. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  32. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  33. package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
  34. package/src/__tests__/integration-status.test.ts +31 -30
  35. package/src/__tests__/invite-redemption-service.test.ts +166 -13
  36. package/src/__tests__/invite-routes-http.test.ts +166 -5
  37. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  38. package/src/__tests__/list-messages-attachments.test.ts +193 -0
  39. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  40. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  41. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  42. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  43. package/src/__tests__/memory-regressions.test.ts +477 -2841
  44. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  45. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  46. package/src/__tests__/mime-builder.test.ts +28 -0
  47. package/src/__tests__/native-web-search.test.ts +1 -0
  48. package/src/__tests__/oauth-cli.test.ts +824 -31
  49. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  50. package/src/__tests__/oauth-store.test.ts +363 -17
  51. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  52. package/src/__tests__/registry.test.ts +0 -1
  53. package/src/__tests__/relay-server.test.ts +55 -1
  54. package/src/__tests__/schedule-tools.test.ts +32 -0
  55. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  56. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  57. package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
  58. package/src/__tests__/secure-keys.test.ts +78 -18
  59. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  60. package/src/__tests__/server-history-render.test.ts +2 -2
  61. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  62. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  63. package/src/__tests__/session-agent-loop.test.ts +19 -15
  64. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  65. package/src/__tests__/session-error.test.ts +124 -2
  66. package/src/__tests__/session-history-web-search.test.ts +918 -0
  67. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  68. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  69. package/src/__tests__/session-queue.test.ts +37 -27
  70. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  71. package/src/__tests__/session-slash-known.test.ts +1 -15
  72. package/src/__tests__/session-slash-queue.test.ts +1 -15
  73. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  74. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  75. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  76. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  77. package/src/__tests__/skills-install-extract.test.ts +93 -0
  78. package/src/__tests__/skills.test.ts +2 -2
  79. package/src/__tests__/skillssh-registry.test.ts +451 -0
  80. package/src/__tests__/slack-channel-config.test.ts +10 -8
  81. package/src/__tests__/trust-store.test.ts +15 -0
  82. package/src/__tests__/twilio-config.test.ts +11 -10
  83. package/src/__tests__/twilio-provider.test.ts +9 -4
  84. package/src/__tests__/voice-invite-redemption.test.ts +85 -5
  85. package/src/agent/ax-tree-compaction.test.ts +51 -0
  86. package/src/agent/loop.ts +39 -12
  87. package/src/approvals/AGENTS.md +1 -1
  88. package/src/approvals/guardian-request-resolvers.ts +14 -2
  89. package/src/bundler/compiler-tools.ts +66 -2
  90. package/src/calls/call-domain.ts +134 -3
  91. package/src/calls/call-store.ts +6 -0
  92. package/src/calls/relay-server.ts +44 -6
  93. package/src/calls/relay-setup-router.ts +17 -1
  94. package/src/calls/twilio-config.ts +5 -4
  95. package/src/calls/twilio-provider.ts +14 -9
  96. package/src/calls/twilio-rest.ts +10 -7
  97. package/src/calls/types.ts +3 -1
  98. package/src/cli/commands/config.ts +14 -9
  99. package/src/cli/commands/contacts.ts +3 -0
  100. package/src/cli/commands/credentials.ts +170 -174
  101. package/src/cli/commands/doctor.ts +11 -8
  102. package/src/cli/commands/keys.ts +9 -9
  103. package/src/cli/commands/mcp.ts +46 -59
  104. package/src/cli/commands/memory.ts +16 -165
  105. package/src/cli/commands/oauth/apps.ts +68 -10
  106. package/src/cli/commands/oauth/connections.ts +475 -105
  107. package/src/cli/commands/oauth/index.ts +3 -3
  108. package/src/cli/commands/oauth/providers.ts +18 -4
  109. package/src/cli/commands/sessions.ts +5 -2
  110. package/src/cli/commands/skills.ts +173 -1
  111. package/src/cli/http-client.ts +0 -20
  112. package/src/cli/main-screen.tsx +2 -2
  113. package/src/cli/program.ts +5 -6
  114. package/src/cli.ts +20 -22
  115. package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
  116. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  117. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +35 -11
  119. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  120. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  121. package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
  135. package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
  136. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
  137. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
  138. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
  139. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
  140. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
  141. package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
  142. package/src/config/bundled-skills/messaging/SKILL.md +1 -1
  143. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  144. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  145. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
  146. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
  148. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
  149. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
  150. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
  151. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
  152. package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
  153. package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
  154. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
  155. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
  156. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
  157. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
  158. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
  159. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
  160. package/src/config/bundled-tool-registry.ts +2 -5
  161. package/src/config/loader.ts +6 -42
  162. package/src/config/schema.ts +1 -12
  163. package/src/config/schemas/memory-lifecycle.ts +0 -9
  164. package/src/config/schemas/memory-processing.ts +0 -180
  165. package/src/config/schemas/memory-retrieval.ts +32 -104
  166. package/src/config/schemas/memory.ts +0 -10
  167. package/src/config/types.ts +0 -4
  168. package/src/contacts/contact-store.ts +39 -2
  169. package/src/contacts/contacts-write.ts +9 -0
  170. package/src/context/window-manager.ts +4 -1
  171. package/src/daemon/config-watcher.ts +55 -2
  172. package/src/daemon/daemon-control.ts +1 -1
  173. package/src/daemon/date-context.ts +114 -31
  174. package/src/daemon/handlers/config-ingress.ts +2 -2
  175. package/src/daemon/handlers/config-slack-channel.ts +59 -39
  176. package/src/daemon/handlers/config-telegram.ts +23 -14
  177. package/src/daemon/handlers/session-history.ts +1 -358
  178. package/src/daemon/handlers/sessions.ts +18 -13
  179. package/src/daemon/handlers/shared.ts +3 -17
  180. package/src/daemon/handlers/skills.ts +20 -1
  181. package/src/daemon/history-repair.ts +72 -8
  182. package/src/daemon/host-cu-proxy.ts +55 -26
  183. package/src/daemon/lifecycle.ts +39 -4
  184. package/src/daemon/mcp-reload-service.ts +2 -2
  185. package/src/daemon/message-types/computer-use.ts +1 -12
  186. package/src/daemon/message-types/memory.ts +4 -16
  187. package/src/daemon/message-types/messages.ts +1 -0
  188. package/src/daemon/message-types/sessions.ts +4 -42
  189. package/src/daemon/server.ts +6 -1
  190. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  191. package/src/daemon/session-agent-loop.ts +334 -48
  192. package/src/daemon/session-error.ts +89 -6
  193. package/src/daemon/session-history.ts +17 -7
  194. package/src/daemon/session-media-retry.ts +6 -2
  195. package/src/daemon/session-memory.ts +69 -149
  196. package/src/daemon/session-process.ts +10 -1
  197. package/src/daemon/session-runtime-assembly.ts +49 -19
  198. package/src/daemon/session-slash.ts +3 -5
  199. package/src/daemon/session-surfaces.ts +4 -1
  200. package/src/daemon/session-tool-setup.ts +7 -1
  201. package/src/daemon/session.ts +12 -2
  202. package/src/email/providers/index.ts +2 -2
  203. package/src/instrument.ts +61 -1
  204. package/src/media/avatar-router.ts +1 -1
  205. package/src/memory/admin.ts +2 -191
  206. package/src/memory/canonical-guardian-store.ts +38 -2
  207. package/src/memory/conversation-crud.ts +0 -33
  208. package/src/memory/conversation-queries.ts +25 -83
  209. package/src/memory/db-init.ts +32 -0
  210. package/src/memory/embedding-backend.ts +84 -8
  211. package/src/memory/embedding-types.ts +9 -1
  212. package/src/memory/indexer.ts +7 -46
  213. package/src/memory/invite-store.ts +19 -0
  214. package/src/memory/items-extractor.ts +274 -76
  215. package/src/memory/job-handlers/backfill.ts +2 -127
  216. package/src/memory/job-handlers/cleanup.ts +2 -16
  217. package/src/memory/job-handlers/extraction.ts +2 -138
  218. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  219. package/src/memory/job-handlers/summarization.ts +3 -148
  220. package/src/memory/job-utils.ts +21 -59
  221. package/src/memory/jobs-store.ts +1 -159
  222. package/src/memory/jobs-worker.ts +9 -52
  223. package/src/memory/migrations/104-core-indexes.ts +3 -3
  224. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  225. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  226. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  227. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  228. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  229. package/src/memory/migrations/154-drop-fts.ts +20 -0
  230. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  231. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  232. package/src/memory/migrations/157-invite-contact-id.ts +104 -0
  233. package/src/memory/migrations/index.ts +8 -0
  234. package/src/memory/migrations/registry.ts +6 -0
  235. package/src/memory/qdrant-client.ts +148 -51
  236. package/src/memory/raw-query.ts +1 -1
  237. package/src/memory/retriever.test.ts +294 -273
  238. package/src/memory/retriever.ts +421 -645
  239. package/src/memory/schema/calls.ts +2 -0
  240. package/src/memory/schema/contacts.ts +1 -0
  241. package/src/memory/schema/memory-core.ts +3 -48
  242. package/src/memory/schema/oauth.ts +2 -0
  243. package/src/memory/search/formatting.ts +263 -176
  244. package/src/memory/search/lexical.ts +1 -254
  245. package/src/memory/search/ranking.ts +0 -455
  246. package/src/memory/search/semantic.ts +100 -14
  247. package/src/memory/search/staleness.ts +47 -0
  248. package/src/memory/search/tier-classifier.ts +21 -0
  249. package/src/memory/search/types.ts +15 -77
  250. package/src/memory/task-memory-cleanup.ts +4 -6
  251. package/src/messaging/provider.ts +1 -1
  252. package/src/messaging/providers/gmail/adapter.ts +1 -1
  253. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  254. package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
  255. package/src/messaging/providers/whatsapp/adapter.ts +13 -9
  256. package/src/messaging/registry.ts +9 -5
  257. package/src/oauth/byo-connection.test.ts +40 -25
  258. package/src/oauth/connect-orchestrator.ts +4 -10
  259. package/src/oauth/connection-resolver.ts +20 -6
  260. package/src/oauth/manual-token-connection.ts +5 -5
  261. package/src/oauth/oauth-store.ts +183 -31
  262. package/src/oauth/platform-connection.test.ts +1 -1
  263. package/src/oauth/provider-behaviors.ts +503 -4
  264. package/src/oauth/seed-providers.ts +214 -8
  265. package/src/oauth/token-persistence.ts +31 -16
  266. package/src/permissions/defaults.ts +1 -0
  267. package/src/permissions/trust-store.ts +23 -1
  268. package/src/playbooks/playbook-compiler.ts +1 -1
  269. package/src/prompts/system-prompt.ts +18 -2
  270. package/src/providers/anthropic/client.ts +56 -126
  271. package/src/providers/types.ts +7 -1
  272. package/src/runtime/AGENTS.md +9 -0
  273. package/src/runtime/auth/route-policy.ts +6 -3
  274. package/src/runtime/channel-readiness-service.ts +48 -40
  275. package/src/runtime/guardian-reply-router.ts +24 -22
  276. package/src/runtime/http-server.ts +2 -2
  277. package/src/runtime/http-types.ts +2 -0
  278. package/src/runtime/invite-redemption-service.ts +72 -12
  279. package/src/runtime/invite-service.ts +43 -0
  280. package/src/runtime/middleware/twilio-validation.ts +1 -1
  281. package/src/runtime/pending-interactions.ts +2 -2
  282. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  283. package/src/runtime/routes/btw-routes.ts +10 -5
  284. package/src/runtime/routes/conversation-routes.ts +56 -11
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  286. package/src/runtime/routes/integrations/slack/channel.ts +2 -2
  287. package/src/runtime/routes/integrations/telegram.ts +2 -2
  288. package/src/runtime/routes/integrations/twilio.ts +17 -17
  289. package/src/runtime/routes/invite-routes.ts +29 -4
  290. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  291. package/src/runtime/routes/memory-item-routes.ts +503 -0
  292. package/src/runtime/routes/secret-routes.ts +17 -0
  293. package/src/runtime/routes/session-management-routes.ts +3 -3
  294. package/src/runtime/routes/settings-routes.ts +3 -3
  295. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  296. package/src/runtime/routes/workspace-routes.ts +9 -4
  297. package/src/runtime/routes/workspace-utils.ts +8 -2
  298. package/src/schedule/integration-status.ts +26 -19
  299. package/src/security/keychain-broker-client.ts +17 -4
  300. package/src/security/oauth2.ts +6 -7
  301. package/src/security/secure-keys.ts +44 -19
  302. package/src/security/token-manager.ts +46 -39
  303. package/src/services/vercel-deploy.ts +0 -24
  304. package/src/signals/confirm.ts +78 -0
  305. package/src/signals/mcp-reload.ts +18 -0
  306. package/src/skills/catalog-install.ts +74 -18
  307. package/src/skills/skillssh-registry.ts +503 -0
  308. package/src/tools/assets/search.ts +5 -1
  309. package/src/tools/computer-use/definitions.ts +0 -10
  310. package/src/tools/computer-use/registry.ts +1 -1
  311. package/src/tools/credentials/vault.ts +22 -7
  312. package/src/tools/memory/definitions.ts +4 -13
  313. package/src/tools/memory/handlers.test.ts +83 -103
  314. package/src/tools/memory/handlers.ts +50 -85
  315. package/src/tools/network/script-proxy/session-manager.ts +8 -8
  316. package/src/tools/schedule/create.ts +10 -3
  317. package/src/tools/schedule/update.ts +8 -1
  318. package/src/tools/skills/load.ts +25 -2
  319. package/src/watcher/provider-types.ts +1 -1
  320. package/src/watcher/providers/github.ts +1 -1
  321. package/src/watcher/providers/gmail.ts +3 -3
  322. package/src/watcher/providers/google-calendar.ts +3 -3
  323. package/src/watcher/providers/linear.ts +1 -1
  324. package/src/__tests__/clarification-resolver.test.ts +0 -193
  325. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  326. package/src/__tests__/conflict-policy.test.ts +0 -269
  327. package/src/__tests__/conflict-store.test.ts +0 -372
  328. package/src/__tests__/contradiction-checker.test.ts +0 -361
  329. package/src/__tests__/entity-extractor.test.ts +0 -211
  330. package/src/__tests__/entity-search.test.ts +0 -1117
  331. package/src/__tests__/profile-compiler.test.ts +0 -392
  332. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  333. package/src/__tests__/session-profile-injection.test.ts +0 -557
  334. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  335. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  336. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  337. package/src/daemon/session-conflict-gate.ts +0 -167
  338. package/src/daemon/session-dynamic-profile.ts +0 -77
  339. package/src/memory/clarification-resolver.ts +0 -417
  340. package/src/memory/conflict-intent.ts +0 -205
  341. package/src/memory/conflict-policy.ts +0 -127
  342. package/src/memory/conflict-store.ts +0 -410
  343. package/src/memory/contradiction-checker.ts +0 -508
  344. package/src/memory/entity-extractor.ts +0 -535
  345. package/src/memory/format-recall.ts +0 -47
  346. package/src/memory/fts-reconciler.ts +0 -165
  347. package/src/memory/job-handlers/conflict.ts +0 -200
  348. package/src/memory/profile-compiler.ts +0 -195
  349. package/src/memory/recall-cache.ts +0 -117
  350. package/src/memory/search/entity.ts +0 -535
  351. package/src/memory/search/query-expansion.test.ts +0 -70
  352. package/src/memory/search/query-expansion.ts +0 -118
  353. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -149,13 +149,12 @@ mock.module("../memory/retriever.js", () => ({
149
149
  enabled: false,
150
150
  degraded: false,
151
151
  injectedText: "",
152
- lexicalHits: 0,
152
+
153
153
  semanticHits: 0,
154
154
  recencyHits: 0,
155
155
  injectedTokens: 0,
156
156
  latencyMs: 0,
157
157
  }),
158
- injectMemoryRecallIntoUserMessage: (msg: Message) => msg,
159
158
  stripMemoryRecallMessages: (msgs: Message[]) => msgs,
160
159
  }));
161
160
 
@@ -181,14 +180,15 @@ mock.module("../daemon/session-memory.js", () => ({
181
180
  enabled: false,
182
181
  degraded: false,
183
182
  injectedText: "",
184
- lexicalHits: 0,
183
+
185
184
  semanticHits: 0,
186
185
  recencyHits: 0,
187
186
  injectedTokens: 0,
188
187
  latencyMs: 0,
188
+ tier1Count: 0,
189
+ tier2Count: 0,
190
+ hybridSearchMs: 0,
189
191
  },
190
- dynamicProfile: { text: "" },
191
- recallInjectionStrategy: "prepend_user_block" as const,
192
192
  }),
193
193
  }));
194
194
 
@@ -197,11 +197,6 @@ mock.module("../daemon/session-runtime-assembly.js", () => ({
197
197
  stripInjectedContext: (msgs: Message[]) => msgs,
198
198
  }));
199
199
 
200
- mock.module("../daemon/session-dynamic-profile.js", () => ({
201
- stripDynamicProfileMessages: (msgs: Message[]) => msgs,
202
- injectDynamicProfileIntoUserMessage: (msg: Message) => msg,
203
- }));
204
-
205
200
  mock.module("../daemon/date-context.js", () => ({
206
201
  buildTemporalContext: () => null,
207
202
  }));
@@ -276,6 +271,7 @@ mock.module("../daemon/session-error.js", () => ({
276
271
  code: "SESSION_PROCESSING_FAILED",
277
272
  userMessage: "Something went wrong processing your message.",
278
273
  retryable: false,
274
+ errorCategory: "processing_failed",
279
275
  }),
280
276
  isUserCancellation: (err: unknown, ctx: { aborted?: boolean }) => {
281
277
  if (!ctx.aborted) return false;
@@ -376,9 +372,6 @@ function makeCtx(
376
372
  contextCompactedMessageCount: 0,
377
373
  contextCompactedAt: null,
378
374
 
379
- conflictGate: {
380
- evaluate: async () => null,
381
- } as unknown as AgentLoopSessionContext["conflictGate"],
382
375
  memoryPolicy: { scopeId: "default", includeDefaultFallback: true },
383
376
 
384
377
  currentActiveSurfaceId: undefined,
@@ -1300,6 +1293,7 @@ describe("session-agent-loop", () => {
1300
1293
  turnIndex: 0,
1301
1294
  toolCount: 1,
1302
1295
  hasToolUse: true,
1296
+ history: messages,
1303
1297
  });
1304
1298
  if (decision === "yield") {
1305
1299
  return [
@@ -1363,7 +1357,12 @@ describe("session-agent-loop", () => {
1363
1357
  providerDurationMs: 100,
1364
1358
  });
1365
1359
  if (onCheckpoint) {
1366
- onCheckpoint({ turnIndex: 0, toolCount: 1, hasToolUse: true });
1360
+ onCheckpoint({
1361
+ turnIndex: 0,
1362
+ toolCount: 1,
1363
+ hasToolUse: true,
1364
+ history: messages,
1365
+ });
1367
1366
  }
1368
1367
  return [
1369
1368
  ...messages,
@@ -1425,7 +1424,12 @@ describe("session-agent-loop", () => {
1425
1424
  providerDurationMs: 100,
1426
1425
  });
1427
1426
  if (onCheckpoint) {
1428
- onCheckpoint({ turnIndex: 0, toolCount: 1, hasToolUse: true });
1427
+ onCheckpoint({
1428
+ turnIndex: 0,
1429
+ toolCount: 1,
1430
+ hasToolUse: true,
1431
+ history: messages,
1432
+ });
1429
1433
  }
1430
1434
  return [
1431
1435
  ...messages,
@@ -83,7 +83,6 @@ mock.module("../config/loader.js", () => ({
83
83
  timeouts: { permissionTimeoutSec: 1 },
84
84
  apiKeys: {},
85
85
  skills: { entries: {}, allowBundled: true },
86
- memory: { retrieval: { injectionStrategy: "inline" } },
87
86
  permissions: { mode: "workspace" },
88
87
  }),
89
88
  loadRawConfig: () => ({}),
@@ -122,18 +121,6 @@ mock.module("../security/secret-allowlist.js", () => ({
122
121
  resetAllowlist: () => {},
123
122
  }));
124
123
 
125
- mock.module("../memory/admin.js", () => ({
126
- getMemoryConflictAndCleanupStats: () => ({
127
- conflicts: { pending: 0, resolved: 0, oldestPendingAgeMs: null },
128
- cleanup: {
129
- resolvedBacklog: 0,
130
- supersededBacklog: 0,
131
- resolvedCompleted24h: 0,
132
- supersededCompleted24h: 0,
133
- },
134
- }),
135
- }));
136
-
137
124
  mock.module("../memory/conversation-crud.js", () => ({
138
125
  getConversationThreadType: () => "default",
139
126
  setConversationOriginChannelIfUnset: () => {},
@@ -174,13 +161,12 @@ mock.module("../memory/retriever.js", () => ({
174
161
  enabled: false,
175
162
  degraded: false,
176
163
  injectedText: "",
177
- lexicalHits: 0,
164
+
178
165
  semanticHits: 0,
179
166
  recencyHits: 0,
180
167
  injectedTokens: 0,
181
168
  latencyMs: 0,
182
169
  }),
183
- injectMemoryRecallIntoUserMessage: (msg: Message) => msg,
184
170
  stripMemoryRecallMessages: (msgs: Message[]) => msgs,
185
171
  }));
186
172
 
@@ -77,6 +77,7 @@ describe("classifySessionError", () => {
77
77
  const result = classifySessionError(new Error(msg), baseCtx);
78
78
  expect(result.code).toBe("PROVIDER_NETWORK");
79
79
  expect(result.retryable).toBe(true);
80
+ expect(result.errorCategory).toBe("provider_network");
80
81
  });
81
82
  }
82
83
  });
@@ -95,6 +96,8 @@ describe("classifySessionError", () => {
95
96
  const result = classifySessionError(new Error(msg), baseCtx);
96
97
  expect(result.code).toBe("PROVIDER_RATE_LIMIT");
97
98
  expect(result.retryable).toBe(true);
99
+ expect(result.userMessage).toContain("busy");
100
+ expect(result.errorCategory).toBe("rate_limit");
98
101
  });
99
102
  }
100
103
  });
@@ -127,6 +130,7 @@ describe("classifySessionError", () => {
127
130
  expect(result.code).toBe("PROVIDER_API");
128
131
  expect(result.userMessage).toContain("timed out");
129
132
  expect(result.retryable).toBe(true);
133
+ expect(result.errorCategory).toBe("provider_timeout");
130
134
  });
131
135
  }
132
136
 
@@ -166,6 +170,8 @@ describe("classifySessionError", () => {
166
170
  const result = classifySessionError(new Error(msg), baseCtx);
167
171
  expect(result.code).toBe("CONTEXT_TOO_LARGE");
168
172
  expect(result.retryable).toBe(false);
173
+ expect(result.userMessage).toContain("too long");
174
+ expect(result.errorCategory).toBe("context_too_large");
169
175
  });
170
176
  }
171
177
  });
@@ -205,6 +211,71 @@ describe("classifySessionError", () => {
205
211
  });
206
212
  });
207
213
 
214
+ describe("ordering errors (tool_use/tool_result mismatches)", () => {
215
+ const cases = [
216
+ "tool_result block not immediately after tool_use block",
217
+ "tool_use block must have a matching tool_result",
218
+ "tool_use_id abc123 without corresponding tool_result",
219
+ "tool_result references tool_use_id not found in conversation",
220
+ "messages have invalid order",
221
+ ];
222
+
223
+ for (const msg of cases) {
224
+ it(`classifies "${msg}" as PROVIDER_ORDERING`, () => {
225
+ const result = classifySessionError(new Error(msg), baseCtx);
226
+ expect(result.code).toBe("PROVIDER_ORDERING");
227
+ expect(result.retryable).toBe(true);
228
+ expect(result.userMessage).toBe(
229
+ "An internal error occurred. Retrying...",
230
+ );
231
+ expect(result.errorCategory).toBe("tool_ordering");
232
+ });
233
+ }
234
+
235
+ it("classifies ProviderError 400 with ordering message as PROVIDER_ORDERING", () => {
236
+ const err = new ProviderError(
237
+ "Anthropic API error (400): tool_use_id abc without tool_result",
238
+ "anthropic",
239
+ 400,
240
+ );
241
+ const result = classifySessionError(err, baseCtx);
242
+ expect(result.code).toBe("PROVIDER_ORDERING");
243
+ expect(result.retryable).toBe(true);
244
+ expect(result.errorCategory).toBe("tool_ordering");
245
+ });
246
+ });
247
+
248
+ describe("web search ordering errors", () => {
249
+ const cases = [
250
+ "web_search tool_use block without result",
251
+ "web_search tool_result missing from conversation",
252
+ ];
253
+
254
+ for (const msg of cases) {
255
+ it(`classifies "${msg}" as PROVIDER_WEB_SEARCH`, () => {
256
+ const result = classifySessionError(new Error(msg), baseCtx);
257
+ expect(result.code).toBe("PROVIDER_WEB_SEARCH");
258
+ expect(result.retryable).toBe(true);
259
+ expect(result.userMessage).toBe(
260
+ "An internal error occurred with web search. Retrying...",
261
+ );
262
+ expect(result.errorCategory).toBe("web_search_ordering");
263
+ });
264
+ }
265
+
266
+ it("classifies ProviderError 400 with web_search ordering message as PROVIDER_WEB_SEARCH", () => {
267
+ const err = new ProviderError(
268
+ "Anthropic API error (400): web_search tool_use without result block",
269
+ "anthropic",
270
+ 400,
271
+ );
272
+ const result = classifySessionError(err, baseCtx);
273
+ expect(result.code).toBe("PROVIDER_WEB_SEARCH");
274
+ expect(result.retryable).toBe(true);
275
+ expect(result.errorCategory).toBe("web_search_ordering");
276
+ });
277
+ });
278
+
208
279
  describe("abort/cancel errors (non-user-initiated)", () => {
209
280
  it('classifies "aborted" as SESSION_ABORTED', () => {
210
281
  const result = classifySessionError(
@@ -232,6 +303,7 @@ describe("classifySessionError", () => {
232
303
  expect(result.code).toBe("REGENERATE_FAILED");
233
304
  expect(result.retryable).toBe(true);
234
305
  expect(result.userMessage).toContain("regenerate");
306
+ expect(result.errorCategory).toContain("regenerate:");
235
307
  });
236
308
 
237
309
  it("returns REGENERATE_FAILED for generic errors", () => {
@@ -251,6 +323,7 @@ describe("classifySessionError", () => {
251
323
  expect(result.code).toBe("SESSION_PROCESSING_FAILED");
252
324
  expect(result.retryable).toBe(false);
253
325
  expect(result.userMessage).toContain("something completely unexpected");
326
+ expect(result.errorCategory).toBe("processing_failed");
254
327
  });
255
328
 
256
329
  it("includes debugDetails with stack trace", () => {
@@ -291,6 +364,7 @@ describe("classifySessionError", () => {
291
364
  const result = classifySessionError(err, baseCtx);
292
365
  expect(result.code).toBe("PROVIDER_RATE_LIMIT");
293
366
  expect(result.retryable).toBe(true);
367
+ expect(result.errorCategory).toBe("rate_limit");
294
368
  });
295
369
 
296
370
  it("classifies ProviderError with 500 as PROVIDER_API (retryable)", () => {
@@ -344,19 +418,39 @@ describe("classifySessionError", () => {
344
418
  });
345
419
  });
346
420
 
421
+ describe("errorCategory is always present", () => {
422
+ it("includes errorCategory on all classified errors", () => {
423
+ const cases: Array<{ error: unknown; ctx: ErrorContext }> = [
424
+ { error: new Error("ECONNREFUSED"), ctx: baseCtx },
425
+ { error: new Error("rate limit"), ctx: baseCtx },
426
+ { error: new Error("prompt is too long"), ctx: baseCtx },
427
+ { error: new Error("unknown"), ctx: baseCtx },
428
+ {
429
+ error: new ProviderError("error", "anthropic", 500),
430
+ ctx: baseCtx,
431
+ },
432
+ ];
433
+ for (const { error, ctx } of cases) {
434
+ const result = classifySessionError(error, ctx);
435
+ expect(result.errorCategory).toBeDefined();
436
+ expect(result.errorCategory.length).toBeGreaterThan(0);
437
+ }
438
+ });
439
+ });
440
+
347
441
  describe("debug detail truncation", () => {
348
442
  it("truncates debugDetails longer than 4000 chars", () => {
349
443
  const longMsg = "x".repeat(5000);
350
444
  const result = classifySessionError(new Error(longMsg), baseCtx);
351
445
  expect(result.debugDetails!.length).toBeLessThanOrEqual(4020); // 4000 + truncation marker
352
- expect(result.debugDetails!).toContain("(truncated)");
446
+ expect(result.debugDetails!).toContain("(truncated)");
353
447
  });
354
448
 
355
449
  it("preserves debugDetails under 4000 chars", () => {
356
450
  const shortMsg = "short error message";
357
451
  const result = classifySessionError(new Error(shortMsg), baseCtx);
358
452
  expect(result.debugDetails).toBeDefined();
359
- expect(result.debugDetails!).not.toContain("(truncated)");
453
+ expect(result.debugDetails!).not.toContain("(truncated)");
360
454
  });
361
455
  });
362
456
 
@@ -391,6 +485,7 @@ describe("buildSessionErrorMessage", () => {
391
485
  userMessage: "Network error",
392
486
  retryable: true,
393
487
  debugDetails: "ECONNREFUSED",
488
+ errorCategory: "provider_network",
394
489
  });
395
490
 
396
491
  expect(msg.type).toBe("session_error");
@@ -399,6 +494,7 @@ describe("buildSessionErrorMessage", () => {
399
494
  expect(msg.userMessage).toBe("Network error");
400
495
  expect(msg.retryable).toBe(true);
401
496
  expect(msg.debugDetails).toBe("ECONNREFUSED");
497
+ expect(msg.errorCategory).toBe("provider_network");
402
498
  });
403
499
 
404
500
  it("omits debugDetails when not provided", () => {
@@ -406,9 +502,35 @@ describe("buildSessionErrorMessage", () => {
406
502
  code: "UNKNOWN",
407
503
  userMessage: "Something went wrong",
408
504
  retryable: false,
505
+ errorCategory: "processing_failed",
409
506
  });
410
507
 
411
508
  expect(msg.type).toBe("session_error");
412
509
  expect(msg.debugDetails).toBeUndefined();
510
+ expect(msg.errorCategory).toBe("processing_failed");
511
+ });
512
+
513
+ it("includes errorCategory for ordering errors", () => {
514
+ const msg = buildSessionErrorMessage("session-789", {
515
+ code: "PROVIDER_ORDERING",
516
+ userMessage: "An internal error occurred. Retrying...",
517
+ retryable: true,
518
+ errorCategory: "tool_ordering",
519
+ });
520
+
521
+ expect(msg.errorCategory).toBe("tool_ordering");
522
+ expect(msg.code).toBe("PROVIDER_ORDERING");
523
+ });
524
+
525
+ it("includes errorCategory for web search errors", () => {
526
+ const msg = buildSessionErrorMessage("session-abc", {
527
+ code: "PROVIDER_WEB_SEARCH",
528
+ userMessage: "An internal error occurred with web search. Retrying...",
529
+ retryable: true,
530
+ errorCategory: "web_search_ordering",
531
+ });
532
+
533
+ expect(msg.errorCategory).toBe("web_search_ordering");
534
+ expect(msg.code).toBe("PROVIDER_WEB_SEARCH");
413
535
  });
414
536
  });