@vellumai/assistant 0.5.15 → 0.6.0

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 (503) hide show
  1. package/ARCHITECTURE.md +3 -3
  2. package/Dockerfile +0 -3
  3. package/docs/architecture/integrations.md +15 -14
  4. package/knip.json +4 -1
  5. package/openapi.yaml +670 -122
  6. package/package.json +1 -1
  7. package/src/__tests__/actor-token-service.test.ts +68 -0
  8. package/src/__tests__/agent-loop.test.ts +0 -32
  9. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  10. package/src/__tests__/anthropic-provider.test.ts +57 -3
  11. package/src/__tests__/app-compiler.test.ts +120 -0
  12. package/src/__tests__/assistant-feature-flags-integration.test.ts +5 -377
  13. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  14. package/src/__tests__/call-domain.test.ts +2 -6
  15. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  16. package/src/__tests__/call-recovery.test.ts +2 -6
  17. package/src/__tests__/call-routes-http.test.ts +2 -6
  18. package/src/__tests__/call-store.test.ts +2 -6
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  20. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  21. package/src/__tests__/ces-rpc-credential-backend.test.ts +4 -1
  22. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  23. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  24. package/src/__tests__/checker.test.ts +84 -3
  25. package/src/__tests__/clawhub.test.ts +54 -24
  26. package/src/__tests__/cli-command-risk-guard.test.ts +108 -6
  27. package/src/__tests__/cli-memory.test.ts +377 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
  29. package/src/__tests__/config-schema.test.ts +1 -3
  30. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  31. package/src/__tests__/config-watcher-feature-flags.test.ts +211 -0
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  33. package/src/__tests__/contacts-tools.test.ts +31 -0
  34. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  35. package/src/__tests__/context-token-estimator.test.ts +175 -10
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  37. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  38. package/src/__tests__/conversation-attachments.test.ts +2 -6
  39. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  40. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  41. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  42. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  43. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  44. package/src/__tests__/conversation-error.test.ts +33 -2
  45. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  46. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  47. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  48. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  49. package/src/__tests__/conversation-runtime-assembly.test.ts +7 -4
  50. package/src/__tests__/conversation-slash-commands.test.ts +2 -6
  51. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  52. package/src/__tests__/conversation-store.test.ts +2 -6
  53. package/src/__tests__/conversation-usage.test.ts +3 -6
  54. package/src/__tests__/conversation-wipe.test.ts +11 -408
  55. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  56. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  57. package/src/__tests__/credential-security-e2e.test.ts +6 -1
  58. package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
  59. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
  60. package/src/__tests__/followup-tools.test.ts +2 -6
  61. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  62. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  63. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  64. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  65. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  66. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  67. package/src/__tests__/guardian-action-store.test.ts +2 -6
  68. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  69. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  70. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  71. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  72. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  73. package/src/__tests__/guardian-routing-invariants.test.ts +343 -6
  74. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  75. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  76. package/src/__tests__/heartbeat-service.test.ts +1 -3
  77. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  78. package/src/__tests__/injection-block.test.ts +154 -0
  79. package/src/__tests__/install-meta.test.ts +506 -0
  80. package/src/__tests__/install-skill-routing.test.ts +292 -0
  81. package/src/__tests__/intent-routing.test.ts +6 -18
  82. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  83. package/src/__tests__/invite-routes-http.test.ts +2 -6
  84. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  85. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  86. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  87. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  88. package/src/__tests__/llm-usage-store.test.ts +2 -6
  89. package/src/__tests__/log-export-workspace.test.ts +4 -34
  90. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
  91. package/src/__tests__/managed-store.test.ts +40 -21
  92. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  93. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  94. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  95. package/src/__tests__/messaging-send-tool.test.ts +6 -6
  96. package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
  97. package/src/__tests__/migration-export-http.test.ts +3 -34
  98. package/src/__tests__/migration-import-commit-http.test.ts +1 -29
  99. package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
  100. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
  101. package/src/__tests__/non-member-access-request.test.ts +2 -6
  102. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  103. package/src/__tests__/oauth-apps-routes.test.ts +120 -10
  104. package/src/__tests__/oauth-cli.test.ts +364 -2
  105. package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
  106. package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
  107. package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
  108. package/src/__tests__/oauth-providers-routes.test.ts +5 -2
  109. package/src/__tests__/oauth-store.test.ts +0 -5
  110. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  111. package/src/__tests__/outlook-attachments.test.ts +301 -0
  112. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  113. package/src/__tests__/outlook-categories.test.ts +212 -0
  114. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  115. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  116. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  117. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  118. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  119. package/src/__tests__/outlook-messaging-provider.test.ts +1071 -0
  120. package/src/__tests__/outlook-trash.test.ts +77 -0
  121. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  122. package/src/__tests__/path-policy.test.ts +2 -17
  123. package/src/__tests__/permission-types.test.ts +0 -1
  124. package/src/__tests__/platform-callback-registration.test.ts +7 -11
  125. package/src/__tests__/playbook-execution.test.ts +76 -80
  126. package/src/__tests__/playbook-tools.test.ts +5 -7
  127. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  128. package/src/__tests__/provider-error-scenarios.test.ts +21 -2
  129. package/src/__tests__/qdrant-manager.test.ts +68 -21
  130. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  131. package/src/__tests__/registry.test.ts +2 -2
  132. package/src/__tests__/require-fresh-approval.test.ts +64 -3
  133. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  134. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  135. package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
  136. package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
  137. package/src/__tests__/schedule-store.test.ts +2 -6
  138. package/src/__tests__/schedule-tools.test.ts +2 -6
  139. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  140. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  141. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  142. package/src/__tests__/search-skills-unified.test.ts +421 -0
  143. package/src/__tests__/secret-allowlist.test.ts +20 -35
  144. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  145. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  146. package/src/__tests__/sequence-store.test.ts +2 -6
  147. package/src/__tests__/server-history-render.test.ts +2 -6
  148. package/src/__tests__/shell-credential-ref.test.ts +0 -5
  149. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  150. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  151. package/src/__tests__/skill-load-feature-flag.test.ts +13 -54
  152. package/src/__tests__/skill-load-inline-command.test.ts +3 -65
  153. package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
  154. package/src/__tests__/skill-load-tool.test.ts +3 -67
  155. package/src/__tests__/skill-memory.test.ts +480 -195
  156. package/src/__tests__/skills-uninstall.test.ts +2 -2
  157. package/src/__tests__/skills.test.ts +23 -50
  158. package/src/__tests__/slack-channel-config.test.ts +2 -21
  159. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  160. package/src/__tests__/starter-bundle.test.ts +2 -8
  161. package/src/__tests__/stt-hints.test.ts +7 -2
  162. package/src/__tests__/system-prompt.test.ts +25 -45
  163. package/src/__tests__/task-compiler.test.ts +2 -27
  164. package/src/__tests__/task-management-tools.test.ts +2 -27
  165. package/src/__tests__/task-memory-cleanup.test.ts +173 -250
  166. package/src/__tests__/task-runner.test.ts +2 -27
  167. package/src/__tests__/task-scheduler.test.ts +2 -27
  168. package/src/__tests__/terminal-tools.test.ts +1 -17
  169. package/src/__tests__/test-preload.ts +3 -0
  170. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
  171. package/src/__tests__/tool-approval-handler.test.ts +4 -27
  172. package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  175. package/src/__tests__/tool-executor.test.ts +0 -1
  176. package/src/__tests__/tool-grant-request-escalation.test.ts +4 -27
  177. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
  178. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  179. package/src/__tests__/trust-store.test.ts +10 -42
  180. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
  181. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +3 -27
  182. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -28
  183. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -28
  184. package/src/__tests__/trusted-contact-verification.test.ts +2 -28
  185. package/src/__tests__/turn-boundary-resolution.test.ts +2 -34
  186. package/src/__tests__/twilio-provider.test.ts +0 -16
  187. package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
  188. package/src/__tests__/twilio-routes.test.ts +0 -24
  189. package/src/__tests__/update-bulletin.test.ts +17 -89
  190. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -26
  191. package/src/__tests__/usage-routes.test.ts +2 -27
  192. package/src/__tests__/user-reference.test.ts +1 -5
  193. package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
  194. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
  195. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  196. package/src/__tests__/voice-invite-redemption.test.ts +2 -27
  197. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -30
  198. package/src/__tests__/voice-session-bridge.test.ts +2 -27
  199. package/src/__tests__/volume-security-guard.test.ts +2 -0
  200. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  201. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -29
  202. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
  203. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +4 -29
  204. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  205. package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
  206. package/src/__tests__/workspace-policy.test.ts +1 -1
  207. package/src/acp/client-handler.ts +1 -2
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +1 -15
  211. package/src/bundler/app-compiler.ts +179 -2
  212. package/src/bundler/package-resolver.ts +3 -5
  213. package/src/cli/__tests__/notifications.test.ts +1 -24
  214. package/src/cli/cli-memory.ts +179 -0
  215. package/src/cli/commands/avatar.ts +3 -3
  216. package/src/cli/commands/config.ts +26 -13
  217. package/src/cli/commands/doctor.ts +2 -2
  218. package/src/cli/commands/memory.ts +41 -55
  219. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  220. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  221. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  222. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  223. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  224. package/src/cli/commands/oauth/connect.ts +26 -6
  225. package/src/cli/commands/oauth/mode.ts +7 -0
  226. package/src/cli/commands/oauth/providers.ts +49 -42
  227. package/src/cli/commands/oauth/shared.ts +39 -3
  228. package/src/cli/commands/platform/__tests__/connect.test.ts +3 -49
  229. package/src/cli/commands/platform/__tests__/disconnect.test.ts +3 -49
  230. package/src/cli/commands/platform/__tests__/status.test.ts +5 -55
  231. package/src/cli/commands/platform/index.ts +16 -16
  232. package/src/cli/commands/skills.ts +88 -16
  233. package/src/cli/commands/trust.ts +2 -2
  234. package/src/cli/lib/daemon-credential-client.ts +2 -3
  235. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  236. package/src/config/bundled-skills/computer-use/TOOLS.json +7 -7
  237. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  238. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  239. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  240. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  241. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  242. package/src/config/bundled-skills/messaging/SKILL.md +26 -19
  243. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  244. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  245. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  246. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  247. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  248. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  249. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  250. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  251. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  252. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  253. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  254. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  255. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  256. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  257. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  258. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  259. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  260. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  261. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  262. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  263. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  264. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  265. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  266. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  267. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  268. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  269. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  270. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  271. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  272. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  273. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  274. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  275. package/src/config/bundled-tool-registry.ts +56 -4
  276. package/src/config/env-registry.ts +15 -8
  277. package/src/config/feature-flag-registry.json +29 -116
  278. package/src/config/loader.ts +4 -0
  279. package/src/config/schemas/platform.ts +8 -0
  280. package/src/config/schemas/security.ts +0 -6
  281. package/src/config/schemas/services.ts +8 -0
  282. package/src/config/schemas/timeouts.ts +1 -1
  283. package/src/config/skills.ts +18 -7
  284. package/src/context/token-estimator.ts +25 -18
  285. package/src/context/window-manager.ts +32 -9
  286. package/src/credential-execution/approval-bridge.ts +0 -1
  287. package/src/credential-execution/process-manager.ts +3 -1
  288. package/src/daemon/config-watcher.ts +51 -0
  289. package/src/daemon/context-overflow-reducer.ts +46 -2
  290. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  291. package/src/daemon/conversation-agent-loop.ts +99 -63
  292. package/src/daemon/conversation-error.ts +31 -8
  293. package/src/daemon/conversation-lifecycle.ts +33 -0
  294. package/src/daemon/conversation-media-retry.ts +85 -7
  295. package/src/daemon/conversation-notifiers.ts +4 -1
  296. package/src/daemon/conversation-process.ts +1 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  298. package/src/daemon/conversation-usage.ts +1 -0
  299. package/src/daemon/conversation.ts +41 -2
  300. package/src/daemon/daemon-control.ts +8 -2
  301. package/src/daemon/handlers/shared.ts +22 -12
  302. package/src/daemon/handlers/skills.ts +423 -201
  303. package/src/daemon/lifecycle.ts +52 -4
  304. package/src/daemon/main.ts +5 -1
  305. package/src/daemon/message-types/conversations.ts +5 -1
  306. package/src/daemon/message-types/messages.ts +3 -1
  307. package/src/daemon/message-types/skills.ts +97 -36
  308. package/src/daemon/providers-setup.ts +7 -0
  309. package/src/daemon/server.ts +35 -22
  310. package/src/daemon/tool-side-effects.ts +27 -5
  311. package/src/events/domain-events.ts +1 -2
  312. package/src/heartbeat/heartbeat-service.ts +1 -0
  313. package/src/hooks/cli.ts +2 -2
  314. package/src/hooks/runner.ts +15 -38
  315. package/src/inbound/platform-callback-registration.ts +14 -14
  316. package/src/memory/admin.ts +11 -45
  317. package/src/memory/conversation-bootstrap.ts +2 -0
  318. package/src/memory/conversation-crud.ts +242 -348
  319. package/src/memory/conversation-group-migration.ts +157 -0
  320. package/src/memory/conversation-queries.ts +4 -2
  321. package/src/memory/db-init.ts +39 -3
  322. package/src/memory/embed.ts +73 -0
  323. package/src/memory/embedding-backend.ts +8 -14
  324. package/src/memory/embedding-runtime-manager.ts +12 -114
  325. package/src/memory/fingerprint.ts +2 -2
  326. package/src/memory/graph/bootstrap.ts +512 -0
  327. package/src/memory/graph/capability-seed.ts +297 -0
  328. package/src/memory/graph/consolidation.ts +691 -0
  329. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  330. package/src/memory/graph/decay.test.ts +208 -0
  331. package/src/memory/graph/decay.ts +195 -0
  332. package/src/memory/graph/extraction-job.ts +69 -0
  333. package/src/memory/graph/extraction.test.ts +936 -0
  334. package/src/memory/graph/extraction.ts +1254 -0
  335. package/src/memory/graph/graph-search.ts +266 -0
  336. package/src/memory/graph/image-ref-utils.ts +29 -0
  337. package/src/memory/graph/injection.test.ts +513 -0
  338. package/src/memory/graph/injection.ts +439 -0
  339. package/src/memory/graph/inspect.ts +534 -0
  340. package/src/memory/graph/narrative.ts +267 -0
  341. package/src/memory/graph/pattern-scan.ts +269 -0
  342. package/src/memory/graph/retriever.ts +1008 -0
  343. package/src/memory/graph/scoring.test.ts +548 -0
  344. package/src/memory/graph/scoring.ts +232 -0
  345. package/src/memory/graph/serendipity.ts +65 -0
  346. package/src/memory/graph/store.test.ts +1050 -0
  347. package/src/memory/graph/store.ts +699 -0
  348. package/src/memory/graph/tool-handlers.ts +426 -0
  349. package/src/memory/graph/tools.ts +141 -0
  350. package/src/memory/graph/triggers.test.ts +487 -0
  351. package/src/memory/graph/triggers.ts +223 -0
  352. package/src/memory/graph/types.ts +271 -0
  353. package/src/memory/group-crud.ts +191 -0
  354. package/src/memory/indexer.ts +37 -19
  355. package/src/memory/job-handlers/cleanup.ts +0 -53
  356. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  357. package/src/memory/job-handlers/embedding.test.ts +3 -27
  358. package/src/memory/job-handlers/embedding.ts +5 -31
  359. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  360. package/src/memory/job-handlers/summarization.ts +32 -17
  361. package/src/memory/job-utils.ts +1 -1
  362. package/src/memory/jobs-store.ts +50 -70
  363. package/src/memory/jobs-worker.ts +147 -112
  364. package/src/memory/llm-usage-store.ts +35 -2
  365. package/src/memory/message-content.ts +1 -0
  366. package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
  367. package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -0
  368. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  369. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  370. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  371. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  372. package/src/memory/migrations/index.ts +6 -0
  373. package/src/memory/migrations/registry.ts +8 -0
  374. package/src/memory/qdrant-client.ts +44 -17
  375. package/src/memory/qdrant-manager.ts +26 -5
  376. package/src/memory/schema/index.ts +1 -0
  377. package/src/memory/schema/memory-graph.ts +139 -0
  378. package/src/memory/schema/oauth.ts +1 -1
  379. package/src/memory/search/semantic.ts +47 -91
  380. package/src/memory/slack-thread-store.ts +17 -0
  381. package/src/memory/task-memory-cleanup.ts +28 -50
  382. package/src/messaging/providers/outlook/adapter.ts +200 -0
  383. package/src/messaging/providers/outlook/client.ts +610 -0
  384. package/src/messaging/providers/outlook/types.ts +201 -0
  385. package/src/notifications/adapters/macos.ts +1 -0
  386. package/src/notifications/adapters/slack.ts +1 -1
  387. package/src/notifications/copy-composer.ts +9 -0
  388. package/src/notifications/signal.ts +16 -0
  389. package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
  390. package/src/oauth/connect-orchestrator.ts +10 -3
  391. package/src/oauth/oauth-store.ts +10 -11
  392. package/src/oauth/provider-serializer.ts +3 -0
  393. package/src/oauth/provider-visibility.ts +16 -0
  394. package/src/oauth/seed-providers.ts +50 -17
  395. package/src/permissions/checker.ts +62 -9
  396. package/src/permissions/defaults.ts +4 -4
  397. package/src/permissions/types.ts +2 -4
  398. package/src/permissions/workspace-policy.ts +1 -1
  399. package/src/playbooks/playbook-compiler.ts +19 -18
  400. package/src/playbooks/types.ts +4 -3
  401. package/src/prompts/system-prompt.ts +6 -93
  402. package/src/prompts/templates/UPDATES.md +6 -0
  403. package/src/providers/anthropic/client.ts +47 -19
  404. package/src/providers/gemini/client.ts +1 -1
  405. package/src/providers/openai/client.ts +1 -1
  406. package/src/providers/registry.ts +1 -1
  407. package/src/providers/retry.ts +19 -3
  408. package/src/runtime/actor-trust-resolver.ts +5 -1
  409. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -27
  410. package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
  411. package/src/runtime/auth/route-policy.ts +7 -4
  412. package/src/runtime/guardian-reply-router.ts +10 -2
  413. package/src/runtime/http-server.ts +23 -3
  414. package/src/runtime/middleware/auth.ts +20 -0
  415. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  416. package/src/runtime/routes/attachment-routes.ts +106 -16
  417. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  418. package/src/runtime/routes/btw-routes.ts +8 -0
  419. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  420. package/src/runtime/routes/conversation-query-routes.ts +2 -58
  421. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  422. package/src/runtime/routes/debug-routes.ts +1 -1
  423. package/src/runtime/routes/global-search-routes.ts +21 -19
  424. package/src/runtime/routes/group-routes.ts +207 -0
  425. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  426. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  427. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  428. package/src/runtime/routes/inbound-stages/background-dispatch.ts +43 -2
  429. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  430. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  431. package/src/runtime/routes/memory-item-routes.test.ts +2 -31
  432. package/src/runtime/routes/memory-item-routes.ts +385 -341
  433. package/src/runtime/routes/oauth-apps.ts +18 -1
  434. package/src/runtime/routes/oauth-providers.ts +13 -1
  435. package/src/runtime/routes/schedule-routes.ts +2 -0
  436. package/src/runtime/routes/settings-routes.ts +1 -0
  437. package/src/runtime/routes/skills-routes.ts +103 -37
  438. package/src/runtime/routes/usage-routes.ts +19 -2
  439. package/src/runtime/routes/work-items-routes.test.ts +2 -27
  440. package/src/runtime/routes/workspace-routes.test.ts +3 -27
  441. package/src/schedule/scheduler.ts +8 -1
  442. package/src/security/oauth2.ts +1 -1
  443. package/src/security/secret-allowlist.ts +4 -4
  444. package/src/security/secure-keys.ts +4 -8
  445. package/src/shared/provider-env-vars.ts +19 -0
  446. package/src/skills/catalog-cache.ts +5 -0
  447. package/src/skills/catalog-install.ts +15 -14
  448. package/src/skills/clawhub.ts +134 -154
  449. package/src/skills/install-meta.ts +208 -0
  450. package/src/skills/managed-store.ts +27 -16
  451. package/src/skills/skill-memory.ts +210 -96
  452. package/src/skills/skillssh-registry.ts +19 -17
  453. package/src/tasks/task-runner.ts +3 -1
  454. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  455. package/src/tools/browser/runtime-check.ts +3 -1
  456. package/src/tools/memory/register.ts +63 -46
  457. package/src/tools/permission-checker.ts +7 -19
  458. package/src/tools/shared/filesystem/image-read.ts +22 -85
  459. package/src/tools/skills/skill-script-runner.ts +1 -1
  460. package/src/tools/terminal/safe-env.ts +1 -0
  461. package/src/tools/tool-manifest.ts +3 -3
  462. package/src/util/browser.ts +25 -10
  463. package/src/util/bun-runtime.ts +172 -0
  464. package/src/util/device-id.ts +3 -65
  465. package/src/watcher/providers/outlook-calendar.ts +343 -0
  466. package/src/watcher/providers/outlook.ts +198 -0
  467. package/src/workspace/git-service.ts +27 -6
  468. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  469. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  470. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  471. package/src/workspace/migrations/registry.ts +6 -0
  472. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  473. package/src/__tests__/journal-context.test.ts +0 -268
  474. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  475. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  476. package/src/__tests__/memory-query-builder.test.ts +0 -59
  477. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  478. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  479. package/src/__tests__/memory-regressions.test.ts +0 -3696
  480. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  481. package/src/daemon/conversation-memory.ts +0 -207
  482. package/src/memory/conversation-starters-cadence.ts +0 -74
  483. package/src/memory/items-extractor.ts +0 -860
  484. package/src/memory/job-handlers/batch-extraction.ts +0 -741
  485. package/src/memory/job-handlers/extraction.ts +0 -40
  486. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -383
  487. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  488. package/src/memory/journal-memory.ts +0 -224
  489. package/src/memory/query-builder.ts +0 -47
  490. package/src/memory/query-expansion.ts +0 -83
  491. package/src/memory/retriever.test.ts +0 -1590
  492. package/src/memory/retriever.ts +0 -1323
  493. package/src/memory/search/formatting.test.ts +0 -140
  494. package/src/memory/search/formatting.ts +0 -262
  495. package/src/memory/search/mmr.ts +0 -136
  496. package/src/memory/search/ranking.ts +0 -15
  497. package/src/memory/search/staleness.ts +0 -40
  498. package/src/memory/search/tier-classifier.ts +0 -18
  499. package/src/memory/search/types.ts +0 -121
  500. package/src/prompts/journal-context.ts +0 -156
  501. package/src/tools/memory/definitions.ts +0 -69
  502. package/src/tools/memory/handlers.test.ts +0 -590
  503. package/src/tools/memory/handlers.ts +0 -434
@@ -0,0 +1,36 @@
1
+ import type {
2
+ ToolContext,
3
+ ToolExecutionResult,
4
+ } from "../../../../tools/types.js";
5
+ import * as calendar from "../calendar-client.js";
6
+ import { getCalendarConnection, ok } from "./shared.js";
7
+
8
+ export async function run(
9
+ input: Record<string, unknown>,
10
+ _context: ToolContext,
11
+ ): Promise<ToolExecutionResult> {
12
+ const account = input.account as string | undefined;
13
+ const eventId = input.event_id as string;
14
+ const response = input.response as "accepted" | "declined" | "tentative";
15
+
16
+ const connection = await getCalendarConnection(account);
17
+
18
+ // Fetch the event to get context for the response message
19
+ const event = await calendar.getEvent(connection, eventId);
20
+
21
+ // If the user is the organizer, no RSVP is needed
22
+ if (event.responseStatus?.response === "organizer") {
23
+ return ok("You are the organizer of this event. No RSVP needed.");
24
+ }
25
+
26
+ // Send RSVP via the dedicated Microsoft Graph endpoint, notifying the organizer
27
+ await calendar.rsvpEvent(connection, eventId, response, true);
28
+
29
+ const responseLabel =
30
+ response === "accepted"
31
+ ? "Accepted"
32
+ : response === "declined"
33
+ ? "Declined"
34
+ : "Tentatively accepted";
35
+ return ok(`${responseLabel} the event "${event.subject ?? eventId}".`);
36
+ }
@@ -0,0 +1,17 @@
1
+ import type { OAuthConnection } from "../../../../oauth/connection.js";
2
+ import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
3
+ import type { ToolExecutionResult } from "../../../../tools/types.js";
4
+
5
+ export function ok(content: string): ToolExecutionResult {
6
+ return { content, isError: false };
7
+ }
8
+
9
+ export function err(message: string): ToolExecutionResult {
10
+ return { content: message, isError: true };
11
+ }
12
+
13
+ export async function getCalendarConnection(
14
+ account?: string,
15
+ ): Promise<OAuthConnection> {
16
+ return resolveOAuthConnection("outlook", { account });
17
+ }
@@ -0,0 +1,120 @@
1
+ /** Microsoft Graph date+time pair. timeZone may be omitted when dateTime carries an offset. */
2
+ export interface OutlookDateTimeZone {
3
+ dateTime: string;
4
+ timeZone?: string;
5
+ }
6
+
7
+ /** Attendee on a calendar event. */
8
+ export interface OutlookCalendarAttendee {
9
+ emailAddress: { address: string; name?: string };
10
+ type: "required" | "optional" | "resource";
11
+ status?: {
12
+ response:
13
+ | "none"
14
+ | "organizer"
15
+ | "tentativelyAccepted"
16
+ | "accepted"
17
+ | "declined"
18
+ | "notResponded";
19
+ time?: string;
20
+ };
21
+ }
22
+
23
+ /** Physical or virtual location for a calendar event. */
24
+ export interface OutlookLocation {
25
+ displayName?: string;
26
+ locationType?: string;
27
+ address?: Record<string, unknown>;
28
+ coordinates?: Record<string, unknown>;
29
+ }
30
+
31
+ /** Rich-text body of a calendar item. */
32
+ export interface OutlookItemBody {
33
+ contentType: "text" | "html";
34
+ content: string;
35
+ }
36
+
37
+ /** A single calendar event from Microsoft Graph. */
38
+ export interface OutlookCalendarEvent {
39
+ id: string;
40
+ subject?: string;
41
+ bodyPreview?: string;
42
+ body?: OutlookItemBody;
43
+ start?: OutlookDateTimeZone;
44
+ end?: OutlookDateTimeZone;
45
+ location?: OutlookLocation;
46
+ locations?: OutlookLocation[];
47
+ attendees?: OutlookCalendarAttendee[];
48
+ organizer?: { emailAddress: { address: string; name?: string } };
49
+ isAllDay?: boolean;
50
+ isCancelled?: boolean;
51
+ showAs?:
52
+ | "free"
53
+ | "tentative"
54
+ | "busy"
55
+ | "oof"
56
+ | "workingElsewhere"
57
+ | "unknown";
58
+ importance?: "low" | "normal" | "high";
59
+ sensitivity?: "normal" | "personal" | "private" | "confidential";
60
+ webLink?: string;
61
+ onlineMeetingUrl?: string;
62
+ createdDateTime?: string;
63
+ lastModifiedDateTime?: string;
64
+ seriesMasterId?: string;
65
+ type?: "singleInstance" | "occurrence" | "exception" | "seriesMaster";
66
+ categories?: string[];
67
+ responseStatus?: { response: string; time?: string };
68
+ }
69
+
70
+ /** Paginated list of calendar events. */
71
+ export interface OutlookCalendarEventListResponse {
72
+ value?: OutlookCalendarEvent[];
73
+ "@odata.nextLink"?: string;
74
+ "@odata.deltaLink"?: string;
75
+ "@odata.count"?: number;
76
+ }
77
+
78
+ /** A single schedule item (free/busy block). */
79
+ export interface OutlookScheduleItem {
80
+ status:
81
+ | "free"
82
+ | "tentative"
83
+ | "busy"
84
+ | "oof"
85
+ | "workingElsewhere"
86
+ | "unknown";
87
+ start: OutlookDateTimeZone;
88
+ end: OutlookDateTimeZone;
89
+ subject?: string;
90
+ location?: string;
91
+ }
92
+
93
+ /** Schedule information for one user. */
94
+ export interface OutlookScheduleInformation {
95
+ scheduleId: string;
96
+ availabilityView: string;
97
+ scheduleItems: OutlookScheduleItem[];
98
+ error?: Record<string, unknown>;
99
+ }
100
+
101
+ /** Response from the getSchedule endpoint. */
102
+ export interface OutlookScheduleResponse {
103
+ value?: OutlookScheduleInformation[];
104
+ }
105
+
106
+ /** A calendar in the user's mailbox. */
107
+ export interface OutlookCalendar {
108
+ id: string;
109
+ name?: string;
110
+ color?: string;
111
+ isDefaultCalendar?: boolean;
112
+ canEdit?: boolean;
113
+ owner?: { name: string; address: string };
114
+ }
115
+
116
+ /** Paginated list of calendars. */
117
+ export interface OutlookCalendarListResponse {
118
+ value?: OutlookCalendar[];
119
+ "@odata.nextLink"?: string;
120
+ }
@@ -1,10 +1,10 @@
1
- import { and, eq } from "drizzle-orm";
2
- import { v4 as uuid } from "uuid";
1
+ import { sql } from "drizzle-orm";
3
2
 
4
3
  import { getDb } from "../../../../memory/db.js";
5
- import { computeMemoryFingerprint } from "../../../../memory/fingerprint.js";
4
+ import { createNode, updateNode } from "../../../../memory/graph/store.js";
5
+ import type { NewNode } from "../../../../memory/graph/types.js";
6
6
  import { enqueueMemoryJob } from "../../../../memory/jobs-store.js";
7
- import { memoryItems } from "../../../../memory/schema.js";
7
+ import { memoryGraphNodes } from "../../../../memory/schema.js";
8
8
  import type {
9
9
  Playbook,
10
10
  PlaybookAutonomyLevel,
@@ -13,7 +13,6 @@ import type {
13
13
  ToolContext,
14
14
  ToolExecutionResult,
15
15
  } from "../../../../tools/types.js";
16
- import { truncate } from "../../../../util/truncate.js";
17
16
 
18
17
  const VALID_AUTONOMY_LEVELS = new Set<string>(["auto", "draft", "notify"]);
19
18
 
@@ -56,27 +55,23 @@ export async function executePlaybookCreate(
56
55
  priority,
57
56
  };
58
57
  const statement = JSON.stringify(playbook);
59
- const subject = truncate(`Playbook: ${trigger}`, 80, "");
58
+ const sanitizedTrigger = trigger.replace(/[\r\n]+/g, " ");
59
+ const subject = `Playbook: ${sanitizedTrigger}`.slice(0, 80);
60
+ const content = `${subject}\n${statement}`;
60
61
  const scopeId = context.memoryScopeId ?? "default";
61
62
 
62
- const fingerprint = computeMemoryFingerprint(
63
- scopeId,
64
- "playbook",
65
- subject,
66
- statement,
67
- );
68
-
69
63
  try {
70
64
  const db = getDb();
71
65
 
66
+ // Check for duplicate by matching content in playbook-prefixed graph nodes
72
67
  const existing = db
73
- .select()
74
- .from(memoryItems)
68
+ .select({ id: memoryGraphNodes.id })
69
+ .from(memoryGraphNodes)
75
70
  .where(
76
- and(
77
- eq(memoryItems.fingerprint, fingerprint),
78
- eq(memoryItems.scopeId, scopeId),
79
- ),
71
+ sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'
72
+ AND ${memoryGraphNodes.content} = ${content}
73
+ AND ${memoryGraphNodes.scopeId} = ${scopeId}
74
+ AND ${memoryGraphNodes.fidelity} != 'gone'`,
80
75
  )
81
76
  .get();
82
77
 
@@ -87,29 +82,41 @@ export async function executePlaybookCreate(
87
82
  };
88
83
  }
89
84
 
90
- const id = uuid();
91
85
  const now = Date.now();
86
+ const newNode: NewNode = {
87
+ content,
88
+ type: "semantic",
89
+ created: now,
90
+ lastAccessed: now,
91
+ lastConsolidated: now,
92
+ eventDate: null,
93
+ emotionalCharge: {
94
+ valence: 0,
95
+ intensity: 0.1,
96
+ decayCurve: "linear",
97
+ decayRate: 0.05,
98
+ originalIntensity: 0.1,
99
+ },
100
+ fidelity: "vivid",
101
+ confidence: 0.95,
102
+ significance: 0.8,
103
+ stability: 14,
104
+ reinforcementCount: 0,
105
+ lastReinforced: now,
106
+ sourceConversations: [],
107
+ sourceType: "direct",
108
+ narrativeRole: null,
109
+ partOfStory: null,
110
+ imageRefs: null,
111
+ scopeId,
112
+ };
92
113
 
93
- db.insert(memoryItems)
94
- .values({
95
- id,
96
- kind: "playbook",
97
- subject,
98
- statement,
99
- status: "active",
100
- confidence: 0.95,
101
- importance: 0.8,
102
- fingerprint,
103
- sourceType: "tool",
104
- verificationState: "user_confirmed",
105
- scopeId,
106
- firstSeenAt: now,
107
- lastSeenAt: now,
108
- lastUsedAt: null,
109
- })
110
- .run();
114
+ const node = createNode(newNode);
115
+ updateNode(node.id, {
116
+ sourceConversations: [`playbook:${node.id}`],
117
+ });
111
118
 
112
- enqueueMemoryJob("embed_item", { itemId: id });
119
+ enqueueMemoryJob("embed_graph_node", { nodeId: node.id });
113
120
 
114
121
  const autonomyLabel =
115
122
  autonomyLevel === "auto"
@@ -121,7 +128,7 @@ export async function executePlaybookCreate(
121
128
  return {
122
129
  content: [
123
130
  "Playbook created successfully.",
124
- ` ID: ${id}`,
131
+ ` ID: ${node.id}`,
125
132
  ` Trigger: ${trigger}`,
126
133
  ` Channel: ${channel}`,
127
134
  ` Category: ${category}`,
@@ -1,7 +1,4 @@
1
- import { and, eq } from "drizzle-orm";
2
-
3
- import { getDb } from "../../../../memory/db.js";
4
- import { memoryItems } from "../../../../memory/schema.js";
1
+ import { getNode, updateNode } from "../../../../memory/graph/store.js";
5
2
  import { parsePlaybookStatement } from "../../../../playbooks/types.js";
6
3
  import type {
7
4
  ToolContext,
@@ -23,38 +20,28 @@ export async function executePlaybookDelete(
23
20
  const scopeId = context.memoryScopeId ?? "default";
24
21
 
25
22
  try {
26
- const db = getDb();
27
-
28
- const existing = db
29
- .select()
30
- .from(memoryItems)
31
- .where(
32
- and(
33
- eq(memoryItems.id, playbookId),
34
- eq(memoryItems.kind, "playbook"),
35
- eq(memoryItems.scopeId, scopeId),
36
- ),
37
- )
38
- .get();
39
-
40
- if (!existing) {
23
+ const existing = getNode(playbookId);
24
+ if (
25
+ !existing ||
26
+ existing.scopeId !== scopeId ||
27
+ !existing.sourceConversations.some((s) => s.startsWith("playbook:")) ||
28
+ existing.fidelity === "gone"
29
+ ) {
41
30
  return {
42
31
  content: `Error: Playbook with ID "${playbookId}" not found`,
43
32
  isError: true,
44
33
  };
45
34
  }
46
35
 
47
- const playbook = parsePlaybookStatement(existing.statement);
48
- const triggerLabel = playbook?.trigger ?? existing.subject;
36
+ // Extract trigger label from content
37
+ const newlineIdx = existing.content.indexOf("\n");
38
+ const statement =
39
+ newlineIdx !== -1 ? existing.content.slice(newlineIdx + 1) : "";
40
+ const playbook = parsePlaybookStatement(statement);
41
+ const triggerLabel = playbook?.trigger ?? existing.content.split("\n")[0];
49
42
 
50
- // Soft-delete by marking as superseded rather than hard-deleting,
51
- // consistent with how other memory items are retired.
52
- // Setting invalidAt so the cleanup job can eventually hard-delete it.
53
- const now = Date.now();
54
- db.update(memoryItems)
55
- .set({ status: "superseded", invalidAt: now })
56
- .where(eq(memoryItems.id, existing.id))
57
- .run();
43
+ // Soft-delete by setting fidelity to "gone"
44
+ updateNode(existing.id, { fidelity: "gone" });
58
45
 
59
46
  return {
60
47
  content: `Playbook deleted (ID: ${existing.id}, trigger: "${triggerLabel}").`,
@@ -1,7 +1,7 @@
1
- import { and, desc, eq, isNull } from "drizzle-orm";
1
+ import { and, eq, sql } from "drizzle-orm";
2
2
 
3
3
  import { getDb } from "../../../../memory/db.js";
4
- import { memoryItems } from "../../../../memory/schema.js";
4
+ import { memoryGraphNodes } from "../../../../memory/schema.js";
5
5
  import { parsePlaybookStatement } from "../../../../playbooks/types.js";
6
6
  import type {
7
7
  ToolContext,
@@ -23,22 +23,20 @@ export async function executePlaybookList(
23
23
 
24
24
  const rows = db
25
25
  .select({
26
- id: memoryItems.id,
27
- subject: memoryItems.subject,
28
- statement: memoryItems.statement,
29
- importance: memoryItems.importance,
30
- lastSeenAt: memoryItems.lastSeenAt,
26
+ id: memoryGraphNodes.id,
27
+ content: memoryGraphNodes.content,
28
+ significance: memoryGraphNodes.significance,
29
+ lastAccessed: memoryGraphNodes.lastAccessed,
31
30
  })
32
- .from(memoryItems)
31
+ .from(memoryGraphNodes)
33
32
  .where(
34
33
  and(
35
- eq(memoryItems.kind, "playbook"),
36
- eq(memoryItems.status, "active"),
37
- eq(memoryItems.scopeId, scopeId),
38
- isNull(memoryItems.invalidAt),
34
+ eq(memoryGraphNodes.scopeId, scopeId),
35
+ sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'`,
36
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
39
37
  ),
40
38
  )
41
- .orderBy(desc(memoryItems.importance))
39
+ .orderBy(sql`${memoryGraphNodes.significance} DESC`)
42
40
  .all();
43
41
 
44
42
  if (rows.length === 0) {
@@ -47,12 +45,14 @@ export async function executePlaybookList(
47
45
 
48
46
  const entries: Array<{
49
47
  id: string;
50
- subject: string;
51
- statement: string;
52
48
  playbook: NonNullable<ReturnType<typeof parsePlaybookStatement>>;
53
49
  }> = [];
54
50
  for (const row of rows) {
55
- const playbook = parsePlaybookStatement(row.statement);
51
+ // Content format: "Playbook: <trigger>\n<json statement>"
52
+ const newlineIdx = row.content.indexOf("\n");
53
+ if (newlineIdx === -1) continue;
54
+ const statement = row.content.slice(newlineIdx + 1);
55
+ const playbook = parsePlaybookStatement(statement);
56
56
  if (!playbook) continue;
57
57
 
58
58
  // Apply filters
@@ -66,8 +66,6 @@ export async function executePlaybookList(
66
66
 
67
67
  entries.push({
68
68
  id: row.id,
69
- subject: row.subject,
70
- statement: row.statement,
71
69
  playbook,
72
70
  });
73
71
  }
@@ -1,9 +1,9 @@
1
- import { and, eq } from "drizzle-orm";
1
+ import { and, eq, sql } from "drizzle-orm";
2
2
 
3
3
  import { getDb } from "../../../../memory/db.js";
4
- import { computeMemoryFingerprint } from "../../../../memory/fingerprint.js";
4
+ import { getNode, updateNode } from "../../../../memory/graph/store.js";
5
5
  import { enqueueMemoryJob } from "../../../../memory/jobs-store.js";
6
- import { memoryItems } from "../../../../memory/schema.js";
6
+ import { memoryGraphNodes } from "../../../../memory/schema.js";
7
7
  import type {
8
8
  Playbook,
9
9
  PlaybookAutonomyLevel,
@@ -13,7 +13,6 @@ import type {
13
13
  ToolContext,
14
14
  ToolExecutionResult,
15
15
  } from "../../../../tools/types.js";
16
- import { truncate } from "../../../../util/truncate.js";
17
16
 
18
17
  const VALID_AUTONOMY_LEVELS = new Set<string>(["auto", "draft", "notify"]);
19
18
 
@@ -32,28 +31,29 @@ export async function executePlaybookUpdate(
32
31
  const scopeId = context.memoryScopeId ?? "default";
33
32
 
34
33
  try {
35
- const db = getDb();
36
-
37
- const existing = db
38
- .select()
39
- .from(memoryItems)
40
- .where(
41
- and(
42
- eq(memoryItems.id, playbookId),
43
- eq(memoryItems.kind, "playbook"),
44
- eq(memoryItems.scopeId, scopeId),
45
- ),
46
- )
47
- .get();
48
-
49
- if (!existing) {
34
+ const existing = getNode(playbookId);
35
+ if (
36
+ !existing ||
37
+ existing.scopeId !== scopeId ||
38
+ !existing.sourceConversations.some((s) => s.startsWith("playbook:")) ||
39
+ existing.fidelity === "gone"
40
+ ) {
50
41
  return {
51
42
  content: `Error: Playbook with ID "${playbookId}" not found`,
52
43
  isError: true,
53
44
  };
54
45
  }
55
46
 
56
- const currentPlaybook = parsePlaybookStatement(existing.statement);
47
+ // Extract the JSON statement from the content (after the first newline)
48
+ const newlineIdx = existing.content.indexOf("\n");
49
+ if (newlineIdx === -1) {
50
+ return {
51
+ content: `Error: Playbook data is corrupted for ID "${playbookId}"`,
52
+ isError: true,
53
+ };
54
+ }
55
+ const currentStatement = existing.content.slice(newlineIdx + 1);
56
+ const currentPlaybook = parsePlaybookStatement(currentStatement);
57
57
  if (!currentPlaybook) {
58
58
  return {
59
59
  content: `Error: Playbook data is corrupted for ID "${playbookId}"`,
@@ -91,47 +91,39 @@ export async function executePlaybookUpdate(
91
91
  };
92
92
 
93
93
  const statement = JSON.stringify(updated);
94
- const subject = truncate(`Playbook: ${updated.trigger}`, 80, "");
95
- const now = Date.now();
96
-
97
- const fingerprint = computeMemoryFingerprint(
98
- scopeId,
99
- "playbook",
100
- subject,
101
- statement,
102
- );
94
+ const sanitizedTrigger = updated.trigger.replace(/[\r\n]+/g, " ");
95
+ const subject = `Playbook: ${sanitizedTrigger}`.slice(0, 80);
96
+ const content = `${subject}\n${statement}`;
103
97
 
104
- // Check if another playbook already has this fingerprint
98
+ // Check for duplicate content among other playbook nodes
99
+ const db = getDb();
105
100
  const collision = db
106
- .select({ id: memoryItems.id })
107
- .from(memoryItems)
101
+ .select({ id: memoryGraphNodes.id })
102
+ .from(memoryGraphNodes)
108
103
  .where(
109
104
  and(
110
- eq(memoryItems.fingerprint, fingerprint),
111
- eq(memoryItems.scopeId, scopeId),
105
+ eq(memoryGraphNodes.scopeId, scopeId),
106
+ sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'`,
107
+ eq(memoryGraphNodes.content, content),
108
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
109
+ sql`${memoryGraphNodes.id} != ${existing.id}`,
112
110
  ),
113
111
  )
114
112
  .get();
115
- if (collision && collision.id !== existing.id) {
113
+
114
+ if (collision) {
116
115
  return {
117
116
  content: `Error: Another playbook with this exact configuration already exists (ID: ${collision.id}).`,
118
117
  isError: true,
119
118
  };
120
119
  }
121
120
 
122
- db.update(memoryItems)
123
- .set({
124
- subject,
125
- statement,
126
- fingerprint,
127
- lastSeenAt: now,
128
- sourceType: "tool",
129
- verificationState: "user_confirmed",
130
- })
131
- .where(eq(memoryItems.id, existing.id))
132
- .run();
121
+ updateNode(existing.id, {
122
+ content,
123
+ lastAccessed: Date.now(),
124
+ });
133
125
 
134
- enqueueMemoryJob("embed_item", { itemId: existing.id });
126
+ enqueueMemoryJob("embed_graph_node", { nodeId: existing.id });
135
127
 
136
128
  const autonomyLabel =
137
129
  updated.autonomyLevel === "auto"
@@ -108,7 +108,7 @@
108
108
  "required": ["image_path"]
109
109
  },
110
110
  "executor": "tools/avatar-update.ts",
111
- "execution_target": "sandbox"
111
+ "execution_target": "host"
112
112
  },
113
113
  {
114
114
  "name": "remove_avatar",
@@ -125,7 +125,7 @@
125
125
  }
126
126
  },
127
127
  "executor": "tools/avatar-remove.ts",
128
- "execution_target": "sandbox"
128
+ "execution_target": "host"
129
129
  },
130
130
  {
131
131
  "name": "get_avatar",
@@ -142,7 +142,7 @@
142
142
  }
143
143
  },
144
144
  "executor": "tools/avatar-get.ts",
145
- "execution_target": "sandbox"
145
+ "execution_target": "host"
146
146
  }
147
147
  ]
148
148
  }
@@ -68,13 +68,7 @@ When you need to send a DM or look up a Slack user by name, check contacts first
68
68
 
69
69
  1. **Before calling `users.list`**: Use `contact_search` with `query: "<name>"` and `channel_type: "slack"`. If a matching contact has `externalUserId` (Slack user ID) and `externalChatId` (DM channel ID), skip the API lookups and use those IDs directly with `chat.postMessage`.
70
70
 
71
- 2. **After resolving via API**: When you had to call `users.list` or `conversations.open` to resolve a user, save the mapping with `contact_upsert` so future lookups are instant:
72
- ```
73
- contact_upsert {
74
- display_name: "<display name>"
75
- channels: [{ type: "slack", address: "<slack handle>", external_user_id: "<U...>", external_chat_id: "<D...>" }]
76
- }
77
- ```
71
+ 2. **After resolving via API**: When you had to call `users.list` or `conversations.open` to resolve a user, save the contact with `contact_upsert` so you can find them by name next time. External Slack IDs (user ID, DM channel ID) are cached automatically by the messaging layer and should not be passed through `contact_upsert`.
78
72
 
79
73
  ## Privacy Rules
80
74