@vellumai/assistant 0.4.49 → 0.4.50

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 (239) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/memory.md +180 -119
  4. package/package.json +2 -2
  5. package/src/__tests__/agent-loop.test.ts +3 -1
  6. package/src/__tests__/anthropic-provider.test.ts +114 -23
  7. package/src/__tests__/approval-cascade.test.ts +1 -15
  8. package/src/__tests__/approval-routes-http.test.ts +2 -0
  9. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  10. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  11. package/src/__tests__/checker.test.ts +13 -0
  12. package/src/__tests__/config-schema.test.ts +1 -68
  13. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  14. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  15. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  16. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  17. package/src/__tests__/credential-vault-unit.test.ts +4 -0
  18. package/src/__tests__/credential-vault.test.ts +13 -1
  19. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  20. package/src/__tests__/date-context.test.ts +93 -77
  21. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  22. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  23. package/src/__tests__/history-repair.test.ts +245 -0
  24. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  25. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  26. package/src/__tests__/invite-redemption-service.test.ts +65 -1
  27. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  28. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  29. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  30. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  31. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  32. package/src/__tests__/memory-regressions.test.ts +477 -2841
  33. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  34. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  35. package/src/__tests__/mime-builder.test.ts +28 -0
  36. package/src/__tests__/native-web-search.test.ts +1 -0
  37. package/src/__tests__/oauth-cli.test.ts +572 -5
  38. package/src/__tests__/oauth-store.test.ts +120 -6
  39. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  40. package/src/__tests__/registry.test.ts +0 -1
  41. package/src/__tests__/relay-server.test.ts +46 -1
  42. package/src/__tests__/schedule-tools.test.ts +32 -0
  43. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  44. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  45. package/src/__tests__/secure-keys.test.ts +7 -2
  46. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  47. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  48. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  49. package/src/__tests__/session-agent-loop.test.ts +19 -15
  50. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  51. package/src/__tests__/session-error.test.ts +124 -2
  52. package/src/__tests__/session-history-web-search.test.ts +918 -0
  53. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  54. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  55. package/src/__tests__/session-queue.test.ts +37 -27
  56. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  57. package/src/__tests__/session-slash-known.test.ts +1 -15
  58. package/src/__tests__/session-slash-queue.test.ts +1 -15
  59. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  60. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  61. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  62. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  63. package/src/__tests__/skills-install-extract.test.ts +93 -0
  64. package/src/__tests__/skillssh-registry.test.ts +451 -0
  65. package/src/__tests__/trust-store.test.ts +15 -0
  66. package/src/__tests__/voice-invite-redemption.test.ts +32 -1
  67. package/src/agent/ax-tree-compaction.test.ts +51 -0
  68. package/src/agent/loop.ts +39 -12
  69. package/src/approvals/AGENTS.md +1 -1
  70. package/src/approvals/guardian-request-resolvers.ts +14 -2
  71. package/src/bundler/compiler-tools.ts +66 -2
  72. package/src/calls/call-domain.ts +132 -0
  73. package/src/calls/call-store.ts +6 -0
  74. package/src/calls/relay-server.ts +43 -5
  75. package/src/calls/relay-setup-router.ts +17 -1
  76. package/src/calls/twilio-config.ts +1 -1
  77. package/src/calls/types.ts +3 -1
  78. package/src/cli/commands/doctor.ts +4 -3
  79. package/src/cli/commands/mcp.ts +46 -59
  80. package/src/cli/commands/memory.ts +16 -165
  81. package/src/cli/commands/oauth/apps.ts +31 -2
  82. package/src/cli/commands/oauth/connections.ts +431 -97
  83. package/src/cli/commands/oauth/providers.ts +15 -1
  84. package/src/cli/commands/sessions.ts +5 -2
  85. package/src/cli/commands/skills.ts +173 -1
  86. package/src/cli/http-client.ts +0 -20
  87. package/src/cli/main-screen.tsx +2 -2
  88. package/src/cli/program.ts +5 -6
  89. package/src/cli.ts +4 -10
  90. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  91. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  92. package/src/config/bundled-tool-registry.ts +2 -5
  93. package/src/config/schema.ts +1 -12
  94. package/src/config/schemas/memory-lifecycle.ts +0 -9
  95. package/src/config/schemas/memory-processing.ts +0 -180
  96. package/src/config/schemas/memory-retrieval.ts +32 -104
  97. package/src/config/schemas/memory.ts +0 -10
  98. package/src/config/types.ts +0 -4
  99. package/src/context/window-manager.ts +4 -1
  100. package/src/daemon/config-watcher.ts +61 -3
  101. package/src/daemon/daemon-control.ts +1 -1
  102. package/src/daemon/date-context.ts +114 -31
  103. package/src/daemon/handlers/sessions.ts +18 -13
  104. package/src/daemon/handlers/skills.ts +20 -1
  105. package/src/daemon/history-repair.ts +72 -8
  106. package/src/daemon/host-cu-proxy.ts +55 -26
  107. package/src/daemon/lifecycle.ts +31 -3
  108. package/src/daemon/mcp-reload-service.ts +2 -2
  109. package/src/daemon/message-types/computer-use.ts +1 -12
  110. package/src/daemon/message-types/memory.ts +4 -16
  111. package/src/daemon/message-types/messages.ts +1 -0
  112. package/src/daemon/message-types/sessions.ts +4 -0
  113. package/src/daemon/server.ts +12 -1
  114. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  115. package/src/daemon/session-agent-loop.ts +334 -48
  116. package/src/daemon/session-error.ts +89 -6
  117. package/src/daemon/session-history.ts +17 -7
  118. package/src/daemon/session-media-retry.ts +6 -2
  119. package/src/daemon/session-memory.ts +69 -149
  120. package/src/daemon/session-process.ts +10 -1
  121. package/src/daemon/session-runtime-assembly.ts +49 -19
  122. package/src/daemon/session-surfaces.ts +4 -1
  123. package/src/daemon/session-tool-setup.ts +7 -1
  124. package/src/daemon/session.ts +12 -2
  125. package/src/instrument.ts +61 -1
  126. package/src/memory/admin.ts +2 -191
  127. package/src/memory/canonical-guardian-store.ts +38 -2
  128. package/src/memory/conversation-crud.ts +0 -33
  129. package/src/memory/conversation-queries.ts +22 -3
  130. package/src/memory/db-init.ts +28 -0
  131. package/src/memory/embedding-backend.ts +84 -8
  132. package/src/memory/embedding-types.ts +9 -1
  133. package/src/memory/indexer.ts +7 -46
  134. package/src/memory/items-extractor.ts +274 -76
  135. package/src/memory/job-handlers/backfill.ts +2 -127
  136. package/src/memory/job-handlers/cleanup.ts +2 -16
  137. package/src/memory/job-handlers/extraction.ts +2 -138
  138. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  139. package/src/memory/job-handlers/summarization.ts +3 -148
  140. package/src/memory/job-utils.ts +21 -59
  141. package/src/memory/jobs-store.ts +1 -159
  142. package/src/memory/jobs-worker.ts +9 -52
  143. package/src/memory/migrations/104-core-indexes.ts +3 -3
  144. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  145. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  146. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  147. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  148. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  149. package/src/memory/migrations/154-drop-fts.ts +20 -0
  150. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  151. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  152. package/src/memory/migrations/index.ts +7 -0
  153. package/src/memory/qdrant-client.ts +148 -51
  154. package/src/memory/raw-query.ts +1 -1
  155. package/src/memory/retriever.test.ts +294 -273
  156. package/src/memory/retriever.ts +421 -645
  157. package/src/memory/schema/calls.ts +2 -0
  158. package/src/memory/schema/memory-core.ts +3 -48
  159. package/src/memory/schema/oauth.ts +2 -0
  160. package/src/memory/search/formatting.ts +263 -176
  161. package/src/memory/search/lexical.ts +1 -254
  162. package/src/memory/search/ranking.ts +0 -455
  163. package/src/memory/search/semantic.ts +100 -14
  164. package/src/memory/search/staleness.ts +47 -0
  165. package/src/memory/search/tier-classifier.ts +21 -0
  166. package/src/memory/search/types.ts +15 -77
  167. package/src/memory/task-memory-cleanup.ts +4 -6
  168. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  169. package/src/oauth/byo-connection.test.ts +8 -1
  170. package/src/oauth/oauth-store.ts +113 -27
  171. package/src/oauth/seed-providers.ts +6 -0
  172. package/src/oauth/token-persistence.ts +11 -3
  173. package/src/permissions/defaults.ts +1 -0
  174. package/src/permissions/trust-store.ts +23 -1
  175. package/src/playbooks/playbook-compiler.ts +1 -1
  176. package/src/prompts/system-prompt.ts +18 -2
  177. package/src/providers/anthropic/client.ts +56 -126
  178. package/src/providers/types.ts +7 -1
  179. package/src/runtime/AGENTS.md +9 -0
  180. package/src/runtime/auth/route-policy.ts +6 -3
  181. package/src/runtime/guardian-reply-router.ts +24 -22
  182. package/src/runtime/http-server.ts +2 -2
  183. package/src/runtime/invite-redemption-service.ts +19 -1
  184. package/src/runtime/invite-service.ts +25 -0
  185. package/src/runtime/pending-interactions.ts +2 -2
  186. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  187. package/src/runtime/routes/conversation-routes.ts +9 -1
  188. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  189. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  190. package/src/runtime/routes/memory-item-routes.ts +503 -0
  191. package/src/runtime/routes/session-management-routes.ts +3 -3
  192. package/src/runtime/routes/settings-routes.ts +2 -2
  193. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  194. package/src/runtime/routes/workspace-routes.ts +2 -1
  195. package/src/security/keychain-broker-client.ts +17 -4
  196. package/src/security/secure-keys.ts +25 -3
  197. package/src/security/token-manager.ts +36 -36
  198. package/src/skills/catalog-install.ts +74 -18
  199. package/src/skills/skillssh-registry.ts +503 -0
  200. package/src/tools/assets/search.ts +5 -1
  201. package/src/tools/computer-use/definitions.ts +0 -10
  202. package/src/tools/computer-use/registry.ts +1 -1
  203. package/src/tools/credentials/vault.ts +1 -3
  204. package/src/tools/memory/definitions.ts +4 -13
  205. package/src/tools/memory/handlers.test.ts +83 -103
  206. package/src/tools/memory/handlers.ts +50 -85
  207. package/src/tools/schedule/create.ts +8 -1
  208. package/src/tools/schedule/update.ts +8 -1
  209. package/src/tools/skills/load.ts +25 -2
  210. package/src/__tests__/clarification-resolver.test.ts +0 -193
  211. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  212. package/src/__tests__/conflict-policy.test.ts +0 -269
  213. package/src/__tests__/conflict-store.test.ts +0 -372
  214. package/src/__tests__/contradiction-checker.test.ts +0 -361
  215. package/src/__tests__/entity-extractor.test.ts +0 -211
  216. package/src/__tests__/entity-search.test.ts +0 -1117
  217. package/src/__tests__/profile-compiler.test.ts +0 -392
  218. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  219. package/src/__tests__/session-profile-injection.test.ts +0 -557
  220. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  221. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  222. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  223. package/src/daemon/session-conflict-gate.ts +0 -167
  224. package/src/daemon/session-dynamic-profile.ts +0 -77
  225. package/src/memory/clarification-resolver.ts +0 -417
  226. package/src/memory/conflict-intent.ts +0 -205
  227. package/src/memory/conflict-policy.ts +0 -127
  228. package/src/memory/conflict-store.ts +0 -410
  229. package/src/memory/contradiction-checker.ts +0 -508
  230. package/src/memory/entity-extractor.ts +0 -535
  231. package/src/memory/format-recall.ts +0 -47
  232. package/src/memory/fts-reconciler.ts +0 -165
  233. package/src/memory/job-handlers/conflict.ts +0 -200
  234. package/src/memory/profile-compiler.ts +0 -195
  235. package/src/memory/recall-cache.ts +0 -117
  236. package/src/memory/search/entity.ts +0 -535
  237. package/src/memory/search/query-expansion.test.ts +0 -70
  238. package/src/memory/search/query-expansion.ts +0 -118
  239. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -1,3 +1,6 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
1
4
  import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
2
5
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
6
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
@@ -11,7 +14,7 @@ import {
11
14
  deleteMcpOAuthCredentials,
12
15
  McpOAuthProvider,
13
16
  } from "../../mcp/mcp-oauth-provider.js";
14
- import { httpSend } from "../http-client.js";
17
+ import { getWorkspaceDir } from "../../util/platform.js";
15
18
  import { log } from "../logger.js";
16
19
 
17
20
  export const HEALTH_CHECK_TIMEOUT_MS = 10_000;
@@ -51,6 +54,21 @@ export async function checkServerHealth(
51
54
  }
52
55
  }
53
56
 
57
+ /**
58
+ * Write a signal file so the daemon's ConfigWatcher triggers an MCP reload.
59
+ * Used by `mcp reload`, `mcp auth`, and any operation that needs the daemon
60
+ * to reconnect MCP servers.
61
+ */
62
+ function signalMcpReload(): void {
63
+ try {
64
+ const signalsDir = join(getWorkspaceDir(), "signals");
65
+ mkdirSync(signalsDir, { recursive: true });
66
+ writeFileSync(join(signalsDir, "mcp-reload"), "");
67
+ } catch {
68
+ // Best-effort — the daemon may not be running or the directory may not exist.
69
+ }
70
+ }
71
+
54
72
  export function registerMcpCommand(program: Command): void {
55
73
  const mcp = program
56
74
  .command("mcp")
@@ -67,8 +85,8 @@ server uses one of three transport types:
67
85
  sse Remote server using Server-Sent Events
68
86
  streamable-http Remote server using Streamable HTTP transport
69
87
 
70
- After changing MCP server configuration, run 'vellum mcp reload' to apply
71
- changes without restarting the assistant.
88
+ MCP server configuration changes are detected automatically by the running
89
+ assistant. You can also run 'vellum mcp reload' to trigger a manual reload.
72
90
 
73
91
  Examples:
74
92
  $ assistant mcp list
@@ -251,61 +269,20 @@ Examples:
251
269
  .addHelpText(
252
270
  "after",
253
271
  `
254
- Sends a message to the running assistant to disconnect and reconnect all MCP
255
- servers using the current configuration from disk. Active sessions pick up
256
- new tools on their next turn automatically. The assistant must be running.
272
+ Signals the running assistant to disconnect and reconnect all MCP servers
273
+ using the current configuration from disk. Active sessions pick up new tools
274
+ on their next turn automatically. The assistant must be running.
257
275
 
258
276
  Examples:
259
277
  $ vellum mcp reload
260
278
  $ vellum mcp reload # after editing config.json to add a new server
261
279
  $ vellum mcp reload # after running "vellum mcp auth <server>"`,
262
280
  )
263
- .action(async () => {
264
- log.info("Sending reload request to assistant...");
265
- try {
266
- const res = await httpSend("/v1/mcp/reload", { method: "POST" });
267
- const response = (await res.json()) as {
268
- success: boolean;
269
- serverCount?: number;
270
- toolCount?: number;
271
- servers?: {
272
- id: string;
273
- connected: boolean;
274
- disabled?: boolean;
275
- toolCount: number;
276
- tools: string[];
277
- }[];
278
- error?: string;
279
- };
280
- if (response.success) {
281
- log.info(
282
- `MCP servers reloaded: ${response.serverCount} server(s), ${response.toolCount} tool(s)\n`,
283
- );
284
- if (response.servers && response.servers.length > 0) {
285
- for (const server of response.servers) {
286
- const status = server.disabled
287
- ? "⊘ Disabled"
288
- : server.connected
289
- ? "\u2713 Connected"
290
- : "\u2717 Not connected";
291
- log.info(` ${server.id}`);
292
- log.info(` Status: ${status}`);
293
- log.info(
294
- ` Tools: ${server.toolCount > 0 ? server.tools.join(", ") : "(none)"}`,
295
- );
296
- log.info("");
297
- }
298
- }
299
- } else {
300
- log.error(`Failed to reload: ${response.error}`);
301
- process.exitCode = 1;
302
- }
303
- } catch (err) {
304
- log.error(
305
- `Failed to send reload request: ${err instanceof Error ? err.message : err}`,
306
- );
307
- process.exitCode = 1;
308
- }
281
+ .action(() => {
282
+ signalMcpReload();
283
+ log.info(
284
+ "MCP reload signal sent. The running assistant will reconnect servers shortly.",
285
+ );
309
286
  });
310
287
 
311
288
  mcp
@@ -422,7 +399,10 @@ Examples:
422
399
 
423
400
  saveRawConfig(raw);
424
401
  log.info(`Added MCP server "${name}" (${opts.transportType})`);
425
- log.info("Run 'vellum mcp reload' to apply changes.");
402
+ log.info(
403
+ "The running assistant will pick up this change automatically. " +
404
+ "Or run 'vellum mcp reload' to apply now.",
405
+ );
426
406
  },
427
407
  );
428
408
 
@@ -444,8 +424,8 @@ OAuth flow. If the server already has valid cached tokens, the command succeeds
444
424
  immediately without opening a browser. Tokens are cached locally for future use
445
425
  by the assistant.
446
426
 
447
- After successful authentication, run 'vellum mcp reload' to apply changes
448
- without restarting the assistant.
427
+ After successful authentication, the running assistant detects the change
428
+ automatically. You can also run 'vellum mcp reload' to apply immediately.
449
429
 
450
430
  Examples:
451
431
  $ assistant mcp auth my-server
@@ -603,7 +583,11 @@ Examples:
603
583
  provider.stopCallbackServer();
604
584
 
605
585
  log.info(`Authentication successful for "${name}".`);
606
- log.info("Run 'vellum mcp reload' to apply changes.");
586
+ log.info(
587
+ "The running assistant will pick up this change automatically. " +
588
+ "Or run 'vellum mcp reload' to apply now.",
589
+ );
590
+ signalMcpReload();
607
591
  process.exit(0);
608
592
  });
609
593
 
@@ -621,8 +605,8 @@ any stored OAuth credentials (tokens, client info, discovery metadata) for
621
605
  sse/streamable-http servers. If no OAuth credentials exist, the cleanup is
622
606
  silently skipped.
623
607
 
624
- After removal, run 'vellum mcp reload' to apply changes without restarting
625
- the assistant.
608
+ After removal, the running assistant detects the change automatically. You
609
+ can also run 'vellum mcp reload' to apply immediately.
626
610
 
627
611
  Examples:
628
612
  $ assistant mcp remove my-server
@@ -655,6 +639,9 @@ Examples:
655
639
  delete servers[name];
656
640
  saveRawConfig(raw);
657
641
  log.info(`Removed MCP server "${name}".`);
658
- log.info("Run 'vellum mcp reload' to apply changes.");
642
+ log.info(
643
+ "The running assistant will pick up this change automatically. " +
644
+ "Or run 'vellum mcp reload' to apply now.",
645
+ );
659
646
  });
660
647
  }
@@ -1,21 +1,16 @@
1
1
  import type { Command } from "commander";
2
2
 
3
3
  import {
4
- dismissPendingConflicts,
5
4
  getMemorySystemStatus,
6
5
  queryMemory,
7
6
  requestMemoryBackfill,
8
7
  requestMemoryCleanup,
9
8
  requestMemoryRebuildIndex,
10
9
  } from "../../memory/admin.js";
11
- import { listPendingConflictDetails } from "../../memory/conflict-store.js";
12
10
  import { listConversations } from "../../memory/conversation-queries.js";
13
- import { rawGet } from "../../memory/db.js";
14
11
  import { initializeDb } from "../db.js";
15
12
  import { log } from "../logger.js";
16
13
 
17
- const SHORT_HASH_LENGTH = 8;
18
-
19
14
  export function registerMemoryCommand(program: Command): void {
20
15
  const memory = program
21
16
  .command("memory")
@@ -24,23 +19,20 @@ export function registerMemoryCommand(program: Command): void {
24
19
  memory.addHelpText(
25
20
  "after",
26
21
  `
27
- The memory subsystem indexes conversation segments into full-text search (FTS)
28
- and vector embeddings for semantic recall. When the assistant encounters new
29
- information that contradicts a stored fact, a conflict is created and held in
30
- "pending_clarification" status until explicitly dismissed or resolved.
22
+ The memory subsystem indexes conversation segments using hybrid search (dense
23
+ and sparse vector embeddings) for semantic recall, with tier classification
24
+ to prioritize high-value memories.
31
25
 
32
26
  Key concepts:
33
27
  segments Chunks of conversation text extracted for indexing
34
28
  items Distilled facts/statements derived from segments
35
29
  summaries Compressed representations of conversation history
36
30
  embeddings Vector representations used for semantic similarity search
37
- conflicts Pairs of contradictory statements awaiting resolution
38
31
 
39
32
  Examples:
40
33
  $ assistant memory status
41
34
  $ assistant memory query "What is the project deadline?"
42
- $ assistant memory backfill
43
- $ assistant memory dismiss-conflicts --all`,
35
+ $ assistant memory backfill`,
44
36
  );
45
37
 
46
38
  memory
@@ -59,10 +51,7 @@ Fields shown:
59
51
  items Total distilled fact items stored
60
52
  summaries Total compressed conversation summaries
61
53
  embeddings Total vector embeddings computed
62
- pending conflicts Conflicts awaiting user resolution
63
- resolved conflicts Conflicts that have been dismissed or resolved
64
- oldest pending age How long the oldest unresolved conflict has been waiting
65
- cleanup backlogs Number of resolved conflicts and superseded items pending cleanup
54
+ cleanup backlogs Number of superseded items pending cleanup
66
55
  cleanup throughput Number of cleanup operations completed in the last 24 hours
67
56
  jobs Status of background jobs (backfill, cleanup, rebuild-index)
68
57
 
@@ -84,29 +73,9 @@ Examples:
84
73
  log.info(`Items: ${status.counts.items.toLocaleString()}`);
85
74
  log.info(`Summaries: ${status.counts.summaries.toLocaleString()}`);
86
75
  log.info(`Embeddings: ${status.counts.embeddings.toLocaleString()}`);
87
- log.info(
88
- `Pending conflicts: ${status.conflicts.pending.toLocaleString()}`,
89
- );
90
- log.info(
91
- `Resolved conflicts: ${status.conflicts.resolved.toLocaleString()}`,
92
- );
93
- if (status.conflicts.oldestPendingAgeMs != null) {
94
- const oldestMinutes = Math.floor(
95
- status.conflicts.oldestPendingAgeMs / 60_000,
96
- );
97
- log.info(`Oldest pending conflict age: ${oldestMinutes} min`);
98
- } else {
99
- log.info("Oldest pending conflict age: n/a");
100
- }
101
- log.info(
102
- `Cleanup backlog (resolved conflicts): ${status.cleanup.resolvedBacklog.toLocaleString()}`,
103
- );
104
76
  log.info(
105
77
  `Cleanup backlog (superseded items): ${status.cleanup.supersededBacklog.toLocaleString()}`,
106
78
  );
107
- log.info(
108
- `Cleanup throughput 24h (resolved conflicts): ${status.cleanup.resolvedCompleted24h.toLocaleString()}`,
109
- );
110
79
  log.info(
111
80
  `Cleanup throughput 24h (superseded items): ${status.cleanup.supersededCompleted24h.toLocaleString()}`,
112
81
  );
@@ -123,8 +92,8 @@ Examples:
123
92
  .addHelpText(
124
93
  "after",
125
94
  `
126
- Queues a background job to index unprocessed conversation segments into FTS
127
- and vector embeddings. The job resumes from where the last backfill left off,
95
+ Queues a background job to index unprocessed conversation segments into
96
+ vector embeddings. The job resumes from where the last backfill left off,
128
97
  processing only new or unindexed segments.
129
98
 
130
99
  The --force flag restarts the backfill from the very beginning, reprocessing
@@ -144,7 +113,7 @@ Examples:
144
113
  memory
145
114
  .command("cleanup")
146
115
  .description(
147
- "Queue cleanup jobs for resolved conflicts and stale superseded items",
116
+ "Queue cleanup jobs for stale superseded items",
148
117
  )
149
118
  .option(
150
119
  "--retention-ms <ms>",
@@ -153,11 +122,8 @@ Examples:
153
122
  .addHelpText(
154
123
  "after",
155
124
  `
156
- Queues two background cleanup jobs:
157
- 1. Resolved conflicts cleanup removes conflict records that have been
158
- dismissed or resolved past the retention threshold.
159
- 2. Stale superseded items cleanup — removes memory items that have been
160
- superseded by newer, corrected facts past the retention threshold.
125
+ Queues a background cleanup job to remove memory items that have been
126
+ superseded by newer, corrected facts past the retention threshold.
161
127
 
162
128
  The optional --retention-ms flag sets the minimum age (in milliseconds) a
163
129
  record must have before it is eligible for cleanup. If omitted, the system
@@ -175,9 +141,6 @@ Examples:
175
141
  const jobs = requestMemoryCleanup(
176
142
  Number.isFinite(retentionMs) ? retentionMs : undefined,
177
143
  );
178
- log.info(
179
- `Queued cleanup_resolved_conflicts job: ${jobs.resolvedConflictsJobId}`,
180
- );
181
144
  log.info(
182
145
  `Queued cleanup_stale_superseded_items job: ${jobs.staleSupersededItemsJobId}`,
183
146
  );
@@ -195,8 +158,8 @@ Examples:
195
158
  Arguments:
196
159
  text The recall query string used to search memory (e.g. "What is the
197
160
  project deadline?"). Matched against indexed segments using the full
198
- recall pipeline: lexical (FTS), semantic (vector similarity), recency
199
- (time-weighted), and entity (named entity extraction).
161
+ recall pipeline: semantic (dense + sparse vector similarity) and recency
162
+ (time-weighted).
200
163
 
201
164
  Runs the complete memory recall pipeline and displays hit counts for each
202
165
  retrieval strategy, the total injected token count, query latency, and the
@@ -221,10 +184,8 @@ Examples:
221
184
  if (result.degraded) {
222
185
  log.info(`Memory degraded: ${result.reason ?? "unknown reason"}`);
223
186
  }
224
- log.info(`Lexical hits: ${result.lexicalHits}`);
225
187
  log.info(`Semantic hits: ${result.semanticHits}`);
226
188
  log.info(`Recency hits: ${result.recencyHits}`);
227
- log.info(`Entity hits: ${result.entityHits}`);
228
189
  log.info(`Injected tokens: ${result.injectedTokens}`);
229
190
  log.info(`Latency: ${result.latencyMs}ms`);
230
191
  if (result.injectedText.length > 0) {
@@ -237,13 +198,13 @@ Examples:
237
198
 
238
199
  memory
239
200
  .command("rebuild-index")
240
- .description("Queue a memory FTS+embedding index rebuild job")
201
+ .description("Queue a memory embedding index rebuild job")
241
202
  .addHelpText(
242
203
  "after",
243
204
  `
244
- Queues a background job that performs a full rebuild of both the FTS (full-text
245
- search) index and the vector embedding index. All existing index data is
246
- dropped and reconstructed from the source memory items.
205
+ Queues a background job that performs a full rebuild of the vector embedding
206
+ index. All existing index data is dropped and reconstructed from the source
207
+ memory items.
247
208
 
248
209
  This is useful after schema changes, embedding model upgrades, or if index
249
210
  corruption is suspected. The rebuild runs asynchronously; use "assistant memory
@@ -258,114 +219,4 @@ Examples:
258
219
  const jobId = requestMemoryRebuildIndex();
259
220
  log.info(`Queued rebuild-index job: ${jobId}`);
260
221
  });
261
-
262
- memory
263
- .command("dismiss-conflicts")
264
- .description("Dismiss pending memory conflicts (all or matching a pattern)")
265
- .option("-a, --all", "Dismiss all pending conflicts")
266
- .option(
267
- "-p, --pattern <regex>",
268
- "Dismiss conflicts where either statement matches this regex",
269
- )
270
- .option("-s, --scope <id>", 'Memory scope (default: "default")')
271
- .option("--dry-run", "Show what would be dismissed without making changes")
272
- .addHelpText(
273
- "after",
274
- `
275
- Two modes of operation:
276
- --all Dismiss every pending conflict in the scope
277
- --pattern <regex> Dismiss only conflicts where either the existing or
278
- candidate statement matches the given regex (case-insensitive)
279
-
280
- At least one of --all or --pattern must be provided. If both are given,
281
- --all takes priority and all pending conflicts are dismissed.
282
-
283
- The --scope flag targets a specific memory scope. Defaults to "default" if
284
- omitted. The --dry-run flag previews which conflicts would be dismissed
285
- without actually modifying any records.
286
-
287
- Examples:
288
- $ assistant memory dismiss-conflicts --all
289
- $ assistant memory dismiss-conflicts --pattern "project deadline" --dry-run
290
- $ assistant memory dismiss-conflicts --pattern "^preferred\\b" --scope work`,
291
- )
292
- .action(
293
- (opts: {
294
- all?: boolean;
295
- pattern?: string;
296
- scope?: string;
297
- dryRun?: boolean;
298
- }) => {
299
- if (!opts.all && !opts.pattern) {
300
- log.info("At least one of --all or --pattern must be provided.");
301
- log.info("Use --dry-run to preview without making changes.");
302
- return;
303
- }
304
-
305
- initializeDb();
306
-
307
- const pattern = opts.pattern
308
- ? new RegExp(opts.pattern, "i")
309
- : undefined;
310
-
311
- if (opts.dryRun) {
312
- const scopeId = opts.scope ?? "default";
313
- const totalPending =
314
- rawGet<{ c: number }>(
315
- `SELECT COUNT(*) AS c FROM memory_item_conflicts WHERE scope_id = ? AND status = 'pending_clarification'`,
316
- scopeId,
317
- )?.c ?? 0;
318
-
319
- // Show a sample of conflicts (can't paginate without dismissing)
320
- const sample = listPendingConflictDetails(scopeId, 1000);
321
- let matchCount = 0;
322
- for (const conflict of sample) {
323
- const matches =
324
- opts.all ||
325
- (pattern &&
326
- (pattern.test(conflict.existingStatement) ||
327
- pattern.test(conflict.candidateStatement)));
328
- if (!matches) continue;
329
- matchCount++;
330
- log.info(
331
- ` [${conflict.id.slice(0, SHORT_HASH_LENGTH)}] "${
332
- conflict.existingStatement
333
- }" vs "${conflict.candidateStatement}"`,
334
- );
335
- }
336
-
337
- if (opts.all) {
338
- // --all matches everything, so matchCount is just the sample size
339
- log.info(
340
- `\nDry run: ${totalPending} of ${totalPending} pending conflicts would be dismissed.`,
341
- );
342
- } else {
343
- const moreNote =
344
- totalPending > sample.length
345
- ? ` (showing first ${sample.length} of ${totalPending})`
346
- : "";
347
- log.info(
348
- `\nDry run: ${matchCount} of ${totalPending} pending conflicts would be dismissed.${moreNote}`,
349
- );
350
- }
351
- return;
352
- }
353
-
354
- const result = dismissPendingConflicts({
355
- all: opts.all,
356
- pattern,
357
- scopeId: opts.scope,
358
- });
359
- for (const detail of result.details) {
360
- log.info(
361
- ` Dismissed [${detail.id.slice(0, SHORT_HASH_LENGTH)}]: "${
362
- detail.existingStatement
363
- }" vs "${detail.candidateStatement}"`,
364
- );
365
- }
366
- log.info(
367
- `\nDismissed ${result.dismissed} conflicts. ${result.remaining} pending conflicts remain.`,
368
- );
369
- },
370
- );
371
222
  }
@@ -165,6 +165,10 @@ At least --id or --provider must be specified.`,
165
165
  "--client-secret <secret>",
166
166
  "OAuth client secret (stored in secure keychain)",
167
167
  )
168
+ .option(
169
+ "--client-secret-credential-path <path>",
170
+ "Path to an existing client secret in the credential store (mutually exclusive with --client-secret)",
171
+ )
168
172
  .addHelpText(
169
173
  "after",
170
174
  `
@@ -175,21 +179,46 @@ stored in the secure system keychain — not in the database.
175
179
  When an existing app is matched and a --client-secret is provided, the stored
176
180
  secret is updated. The app row itself is returned as-is.
177
181
 
182
+ You can supply the client secret directly via --client-secret, or reference an
183
+ existing credential in the store via --client-secret-credential-path. These two
184
+ options are mutually exclusive — providing both is an error.
185
+
178
186
  Examples:
179
187
  $ assistant oauth apps upsert --provider integration:gmail --client-id abc123
180
188
  $ assistant oauth apps upsert --provider integration:slack --client-id def456 --client-secret s3cret
189
+ $ assistant oauth apps upsert --provider integration:slack --client-id def456 --client-secret-credential-path "custom/path"
181
190
  $ assistant oauth apps upsert --provider integration:gmail --client-id abc123 --json`,
182
191
  )
183
192
  .action(
184
193
  async (
185
- opts: { provider: string; clientId: string; clientSecret?: string },
194
+ opts: {
195
+ provider: string;
196
+ clientId: string;
197
+ clientSecret?: string;
198
+ clientSecretCredentialPath?: string;
199
+ },
186
200
  cmd: Command,
187
201
  ) => {
188
202
  try {
203
+ if (opts.clientSecret && opts.clientSecretCredentialPath) {
204
+ writeOutput(cmd, {
205
+ ok: false,
206
+ error:
207
+ "Cannot provide both --client-secret and --client-secret-credential-path",
208
+ });
209
+ process.exitCode = 1;
210
+ return;
211
+ }
212
+
213
+ const clientSecretOpts = opts.clientSecret
214
+ ? { clientSecretValue: opts.clientSecret }
215
+ : opts.clientSecretCredentialPath
216
+ ? { clientSecretCredentialPath: opts.clientSecretCredentialPath }
217
+ : undefined;
189
218
  const row = await upsertApp(
190
219
  opts.provider,
191
220
  opts.clientId,
192
- opts.clientSecret,
221
+ clientSecretOpts,
193
222
  );
194
223
 
195
224
  if (!shouldOutputJson(cmd)) {