@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
@@ -1,211 +0,0 @@
1
- import { inArray } from "drizzle-orm";
2
-
3
- import { getDb, initializeDb } from "../../../../memory/db.js";
4
- import type {
5
- EntityRelationType,
6
- EntityType,
7
- } from "../../../../memory/entity-extractor.js";
8
- import { memoryEntities } from "../../../../memory/schema.js";
9
- import {
10
- collectTypedNeighbors,
11
- findMatchedEntities,
12
- findNeighborEntities,
13
- getEntityLinkedItemCandidates,
14
- } from "../../../../memory/search/entity.js";
15
- import type { TraversalStep } from "../../../../memory/search/types.js";
16
- import type {
17
- ToolContext,
18
- ToolExecutionResult,
19
- } from "../../../../tools/types.js";
20
-
21
- interface GraphQueryInput {
22
- query_type: "neighbors" | "typed_traversal" | "intersection";
23
- seeds: string[];
24
- steps?: Array<{
25
- relation_types?: string[];
26
- entity_types?: string[];
27
- }>;
28
- max_results?: number;
29
- include_items?: boolean;
30
- }
31
-
32
- interface EntityResult {
33
- id: string;
34
- name: string;
35
- type: string;
36
- aliases: string[];
37
- items?: Array<{ subject: string; statement: string }>;
38
- }
39
-
40
- export async function run(
41
- input: Record<string, unknown>,
42
- _context: ToolContext,
43
- ): Promise<ToolExecutionResult> {
44
- const params = input as unknown as GraphQueryInput;
45
-
46
- initializeDb();
47
-
48
- const maxResults = params.max_results ?? 20;
49
- const includeItems = params.include_items ?? true;
50
-
51
- // Resolve seed entity names to IDs
52
- const seedEntityIds: string[] = [];
53
- const resolvedSeeds: Array<{ name: string; id: string }> = [];
54
- for (const seedName of params.seeds) {
55
- const matched = findMatchedEntities(seedName, 5);
56
- if (matched.length > 0) {
57
- seedEntityIds.push(matched[0].id);
58
- resolvedSeeds.push({ name: seedName, id: matched[0].id });
59
- }
60
- }
61
-
62
- if (seedEntityIds.length === 0) {
63
- return {
64
- content: JSON.stringify({
65
- error: "No matching entities found for the provided seed names",
66
- seeds: params.seeds,
67
- }),
68
- isError: true,
69
- };
70
- }
71
-
72
- // For intersection queries, all seeds must resolve — dropping any seed silently
73
- // changes semantics from "reachable from ALL seeds" to "reachable from resolved seeds"
74
- if (
75
- params.query_type === "intersection" &&
76
- seedEntityIds.length < params.seeds.length
77
- ) {
78
- const unresolvedSeeds = params.seeds.filter(
79
- (name) => !resolvedSeeds.some((s) => s.name === name),
80
- );
81
- return {
82
- content: JSON.stringify({
83
- error:
84
- "Some seed entities could not be resolved. Intersection requires all seeds to match.",
85
- unresolved_seeds: unresolvedSeeds,
86
- resolved_seeds: resolvedSeeds,
87
- }),
88
- isError: true,
89
- };
90
- }
91
-
92
- let resultEntityIds: string[];
93
-
94
- switch (params.query_type) {
95
- case "neighbors": {
96
- const steps = params.steps?.[0];
97
- const result = findNeighborEntities(seedEntityIds, {
98
- maxEdges: 40,
99
- maxNeighborEntities: maxResults,
100
- maxDepth: 1,
101
- relationTypes: steps?.relation_types as
102
- | EntityRelationType[]
103
- | undefined,
104
- entityTypes: steps?.entity_types as EntityType[] | undefined,
105
- });
106
- resultEntityIds = result.neighborEntityIds;
107
- break;
108
- }
109
-
110
- case "typed_traversal": {
111
- const traversalSteps: TraversalStep[] = (params.steps ?? []).map((s) => ({
112
- relationTypes: s.relation_types as EntityRelationType[] | undefined,
113
- entityTypes: s.entity_types as EntityType[] | undefined,
114
- }));
115
- resultEntityIds = collectTypedNeighbors(seedEntityIds, traversalSteps, {
116
- maxResultsPerStep: maxResults,
117
- maxEdgesPerStep: 40,
118
- });
119
- break;
120
- }
121
-
122
- case "intersection": {
123
- // Run typed traversal from each seed independently, then intersect
124
- const traversalSteps: TraversalStep[] = (params.steps ?? []).map((s) => ({
125
- relationTypes: s.relation_types as EntityRelationType[] | undefined,
126
- entityTypes: s.entity_types as EntityType[] | undefined,
127
- }));
128
-
129
- const resultSets: Set<string>[] = [];
130
- for (const seedId of seedEntityIds) {
131
- const result = collectTypedNeighbors([seedId], traversalSteps, {
132
- maxResultsPerStep: maxResults,
133
- maxEdgesPerStep: 40,
134
- });
135
- resultSets.push(new Set(result));
136
- }
137
-
138
- if (resultSets.length === 0) {
139
- resultEntityIds = [];
140
- } else {
141
- // Intersect all sets
142
- const intersection = [...resultSets[0]].filter((id) =>
143
- resultSets.every((set) => set.has(id)),
144
- );
145
- resultEntityIds = intersection;
146
- }
147
- break;
148
- }
149
-
150
- default:
151
- return {
152
- content: JSON.stringify({
153
- error: `Unknown query_type: ${params.query_type}`,
154
- }),
155
- isError: true,
156
- };
157
- }
158
-
159
- // Look up entity details
160
- const db = getDb();
161
- const entities: EntityResult[] = [];
162
-
163
- if (resultEntityIds.length > 0) {
164
- const entityRows = db
165
- .select()
166
- .from(memoryEntities)
167
- .where(inArray(memoryEntities.id, resultEntityIds.slice(0, maxResults)))
168
- .all();
169
-
170
- for (const row of entityRows) {
171
- const entity: EntityResult = {
172
- id: row.id,
173
- name: row.name,
174
- type: row.type,
175
- aliases: row.aliases ? (JSON.parse(row.aliases) as string[]) : [],
176
- };
177
-
178
- if (includeItems) {
179
- const candidates = getEntityLinkedItemCandidates([row.id], {
180
- source: "entity_direct",
181
- scopeIds: _context.memoryScopeId
182
- ? [_context.memoryScopeId]
183
- : undefined,
184
- });
185
- entity.items = candidates.slice(0, 5).map((c) => {
186
- const parts = c.text.split(": ");
187
- return {
188
- subject: parts[0] ?? "",
189
- statement: parts.slice(1).join(": ") || c.text,
190
- };
191
- });
192
- }
193
-
194
- entities.push(entity);
195
- }
196
- }
197
-
198
- return {
199
- content: JSON.stringify(
200
- {
201
- query_type: params.query_type,
202
- resolved_seeds: resolvedSeeds,
203
- result_count: entities.length,
204
- entities,
205
- },
206
- null,
207
- 2,
208
- ),
209
- isError: false,
210
- };
211
- }
@@ -1,167 +0,0 @@
1
- /**
2
- * Conflict-gate logic extracted from Session.
3
- *
4
- * Handles pending memory conflicts internally: dismisses non-user-evidenced
5
- * and non-actionable conflicts, and attempts resolution when the user's reply
6
- * looks like an explicit clarification with topical relevance. Never produces
7
- * user-facing clarification text.
8
- */
9
-
10
- import { resolveConflictClarification } from "../memory/clarification-resolver.js";
11
- import {
12
- areStatementsCoherent,
13
- computeConflictRelevance,
14
- looksLikeClarificationReply,
15
- shouldAttemptConflictResolution,
16
- } from "../memory/conflict-intent.js";
17
- import {
18
- isConflictKindPairEligible,
19
- isConflictUserEvidenced,
20
- isStatementConflictEligible,
21
- } from "../memory/conflict-policy.js";
22
- import type { PendingConflictDetail } from "../memory/conflict-store.js";
23
- import {
24
- applyConflictResolution,
25
- listPendingConflictDetails,
26
- resolveConflict,
27
- } from "../memory/conflict-store.js";
28
-
29
- export class ConflictGate {
30
- async evaluate(
31
- userMessage: string,
32
- conflictConfig: {
33
- enabled: boolean;
34
- gateMode: string;
35
- relevanceThreshold: number;
36
- resolverLlmTimeoutMs: number;
37
- conflictableKinds: readonly string[];
38
- },
39
- scopeId = "default",
40
- ): Promise<void> {
41
- if (!conflictConfig.enabled || conflictConfig.gateMode !== "soft") return;
42
-
43
- const pendingBeforeResolve = listPendingConflictDetails(scopeId, 50);
44
-
45
- // Dismiss non-actionable conflicts (kind/statement policy, incoherent pair,
46
- // or assistant-inferred-only provenance with no user evidence)
47
- const dismissedIds = new Set<string>();
48
- for (const conflict of pendingBeforeResolve) {
49
- const dismissReason = this.getDismissReason(
50
- conflict,
51
- conflictConfig.conflictableKinds,
52
- );
53
- if (dismissReason) {
54
- resolveConflict(conflict.id, {
55
- status: "dismissed",
56
- resolutionNote: dismissReason,
57
- });
58
- dismissedIds.add(conflict.id);
59
- }
60
- }
61
-
62
- const actionablePending = pendingBeforeResolve.filter(
63
- (c) => !dismissedIds.has(c.id),
64
- );
65
-
66
- // Attempt resolution only for explicit clarification-like replies with
67
- // topical relevance to the conflict statements
68
- const clarificationReply = looksLikeClarificationReply(userMessage);
69
- const candidatesBeforeResolve = actionablePending.filter((conflict) => {
70
- const relevance = computeConflictRelevance(userMessage, conflict);
71
- return shouldAttemptConflictResolution({
72
- clarificationReply,
73
- relevance,
74
- });
75
- });
76
- await this.resolvePendingConflicts(
77
- userMessage,
78
- conflictConfig.resolverLlmTimeoutMs,
79
- candidatesBeforeResolve,
80
- );
81
- }
82
-
83
- private async resolvePendingConflicts(
84
- userMessage: string,
85
- resolverTimeoutMs: number,
86
- pendingConflicts: PendingConflictDetail[],
87
- ): Promise<void> {
88
- for (const conflict of pendingConflicts) {
89
- const resolution = await resolveConflictClarification(
90
- {
91
- existingStatement: conflict.existingStatement,
92
- candidateStatement: conflict.candidateStatement,
93
- userMessage,
94
- },
95
- { timeoutMs: resolverTimeoutMs },
96
- );
97
- if (resolution.resolution === "still_unclear") continue;
98
-
99
- applyConflictResolution({
100
- conflictId: conflict.id,
101
- resolution: resolution.resolution,
102
- mergedStatement:
103
- resolution.resolution === "merge"
104
- ? resolution.resolvedStatement
105
- : null,
106
- resolutionNote: resolution.explanation,
107
- });
108
- }
109
- }
110
-
111
- /**
112
- * Returns a dismissal reason if the conflict should be dismissed, or null if actionable.
113
- */
114
- private getDismissReason(
115
- conflict: PendingConflictDetail,
116
- conflictableKinds: readonly string[],
117
- ): string | null {
118
- if (
119
- !isConflictKindPairEligible(
120
- conflict.existingKind,
121
- conflict.candidateKind,
122
- { conflictableKinds },
123
- )
124
- ) {
125
- return "Dismissed by conflict policy (kind not eligible).";
126
- }
127
- if (
128
- !isStatementConflictEligible(
129
- conflict.existingKind,
130
- conflict.existingStatement,
131
- { conflictableKinds },
132
- )
133
- ) {
134
- return "Dismissed by conflict policy (transient/non-durable).";
135
- }
136
- if (
137
- !isStatementConflictEligible(
138
- conflict.candidateKind,
139
- conflict.candidateStatement,
140
- { conflictableKinds },
141
- )
142
- ) {
143
- return "Dismissed by conflict policy (transient/non-durable).";
144
- }
145
- // Dismiss incoherent conflicts where the two statements have zero topical overlap
146
- if (
147
- !areStatementsCoherent(
148
- conflict.existingStatement,
149
- conflict.candidateStatement,
150
- )
151
- ) {
152
- return "Dismissed by conflict policy (incoherent — zero statement overlap).";
153
- }
154
- // Dismiss conflicts where neither side has user-evidenced provenance
155
- if (
156
- !isConflictUserEvidenced(
157
- conflict.existingVerificationState,
158
- conflict.candidateVerificationState,
159
- )
160
- ) {
161
- return "Dismissed by conflict policy (no user-evidenced provenance).";
162
- }
163
- return null;
164
- }
165
- }
166
-
167
- export { computeConflictRelevance, looksLikeClarificationReply };
@@ -1,77 +0,0 @@
1
- /**
2
- * Dynamic-profile injection and stripping helpers extracted from Session.
3
- *
4
- * These are pure functions with no state — they wrap profile text into user
5
- * messages at runtime and strip it back out before persistence.
6
- */
7
-
8
- import type { Message } from "../providers/types.js";
9
-
10
- export function injectDynamicProfileIntoUserMessage(
11
- message: Message,
12
- profileText: string,
13
- ): Message {
14
- const trimmedProfile = profileText.trim();
15
- if (trimmedProfile.length === 0) return message;
16
- const block = [
17
- "<dynamic-profile-context>",
18
- trimmedProfile,
19
- "</dynamic-profile-context>",
20
- ].join("\n");
21
- return {
22
- ...message,
23
- content: [...message.content, { type: "text", text: `\n\n${block}` }],
24
- };
25
- }
26
-
27
- export function stripDynamicProfileMessages(
28
- messages: Message[],
29
- profileText: string,
30
- ): Message[] {
31
- const trimmedProfile = profileText.trim();
32
- if (trimmedProfile.length === 0) return messages;
33
- const injectedBlock = `\n\n<dynamic-profile-context>\n${trimmedProfile}\n</dynamic-profile-context>`;
34
- // Find the last user message that actually contains the injected profile block.
35
- // We can't just target the last user message by role — tool_result messages also
36
- // have role 'user', so after tool use the last user message won't be the one
37
- // we injected the profile into.
38
- let lastUserIdx = -1;
39
- for (let i = messages.length - 1; i >= 0; i--) {
40
- if (
41
- messages[i].role === "user" &&
42
- messages[i].content.some(
43
- (b) => b.type === "text" && b.text.includes(injectedBlock),
44
- )
45
- ) {
46
- lastUserIdx = i;
47
- break;
48
- }
49
- }
50
- if (lastUserIdx === -1) return messages;
51
- const message = messages[lastUserIdx];
52
- let changed = false;
53
- const nextContent = message.content
54
- .map((block) => {
55
- if (block.type !== "text") return block;
56
- const nextText = block.text.split(injectedBlock).join("");
57
- if (nextText === block.text) return block;
58
- changed = true;
59
- const stripped = nextText.replace(/\n{3,}/g, "\n\n").trimEnd();
60
- return stripped.length > 0 ? { ...block, text: stripped } : null;
61
- })
62
- .filter((block): block is NonNullable<typeof block> => block != null);
63
- if (!changed) return messages;
64
- // If stripping removed all content blocks, drop the message entirely
65
- // to avoid sending an empty content array to the provider.
66
- if (nextContent.length === 0) {
67
- return [
68
- ...messages.slice(0, lastUserIdx),
69
- ...messages.slice(lastUserIdx + 1),
70
- ];
71
- }
72
- return [
73
- ...messages.slice(0, lastUserIdx),
74
- { ...message, content: nextContent },
75
- ...messages.slice(lastUserIdx + 1),
76
- ];
77
- }