vesper-memory 0.5.3 → 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 (80) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +16 -12
  3. package/config/sqlite-schema.sql +31 -0
  4. package/dist/cli.js +6 -49
  5. package/dist/cli.js.map +1 -1
  6. package/dist/consolidation/pipeline.d.ts +25 -6
  7. package/dist/consolidation/pipeline.d.ts.map +1 -1
  8. package/dist/consolidation/pipeline.js +310 -67
  9. package/dist/consolidation/pipeline.js.map +1 -1
  10. package/dist/memory-layers/semantic-memory.d.ts +8 -3
  11. package/dist/memory-layers/semantic-memory.d.ts.map +1 -1
  12. package/dist/memory-layers/semantic-memory.js +110 -50
  13. package/dist/memory-layers/semantic-memory.js.map +1 -1
  14. package/dist/memory-layers/skill-library.d.ts +9 -9
  15. package/dist/memory-layers/skill-library.d.ts.map +1 -1
  16. package/dist/memory-layers/skill-library.js +85 -56
  17. package/dist/memory-layers/skill-library.js.map +1 -1
  18. package/dist/memory-layers/working-memory.d.ts +2 -2
  19. package/dist/memory-layers/working-memory.d.ts.map +1 -1
  20. package/dist/memory-layers/working-memory.js +57 -47
  21. package/dist/memory-layers/working-memory.js.map +1 -1
  22. package/dist/retrieval/hybrid-search.d.ts.map +1 -1
  23. package/dist/retrieval/hybrid-search.js +10 -5
  24. package/dist/retrieval/hybrid-search.js.map +1 -1
  25. package/dist/retrieval/index-outbox.d.ts +50 -0
  26. package/dist/retrieval/index-outbox.d.ts.map +1 -0
  27. package/dist/retrieval/index-outbox.js +225 -0
  28. package/dist/retrieval/index-outbox.js.map +1 -0
  29. package/dist/retrieval/memory-retriever.d.ts +123 -0
  30. package/dist/retrieval/memory-retriever.d.ts.map +1 -0
  31. package/dist/retrieval/memory-retriever.js +723 -0
  32. package/dist/retrieval/memory-retriever.js.map +1 -0
  33. package/dist/router/smart-router.js +18 -18
  34. package/dist/server-wrapper.js +0 -0
  35. package/dist/server.d.ts +9 -1
  36. package/dist/server.d.ts.map +1 -1
  37. package/dist/server.js +859 -355
  38. package/dist/server.js.map +1 -1
  39. package/dist/utils/claude-mcp-config.d.ts +3 -0
  40. package/dist/utils/claude-mcp-config.d.ts.map +1 -0
  41. package/dist/utils/claude-mcp-config.js +42 -0
  42. package/dist/utils/claude-mcp-config.js.map +1 -0
  43. package/dist/utils/monitoring.d.ts +1 -0
  44. package/dist/utils/monitoring.d.ts.map +1 -1
  45. package/dist/utils/monitoring.js +1 -0
  46. package/dist/utils/monitoring.js.map +1 -1
  47. package/dist/utils/paths.d.ts +13 -1
  48. package/dist/utils/paths.d.ts.map +1 -1
  49. package/dist/utils/paths.js +24 -0
  50. package/dist/utils/paths.js.map +1 -1
  51. package/dist/utils/validation.d.ts +14 -2
  52. package/dist/utils/validation.d.ts.map +1 -1
  53. package/dist/utils/validation.js +64 -48
  54. package/dist/utils/validation.js.map +1 -1
  55. package/docker-compose.yml +3 -3
  56. package/package.json +7 -4
  57. package/scripts/README.md +1 -1
  58. package/scripts/health-check.sh +8 -4
  59. package/scripts/init-qdrant.ts +42 -60
  60. package/scripts/test-mcp-server.sh +2 -2
  61. package/dist/config/rate-limits.d.ts +0 -76
  62. package/dist/config/rate-limits.d.ts.map +0 -1
  63. package/dist/config/rate-limits.js +0 -161
  64. package/dist/config/rate-limits.js.map +0 -1
  65. package/dist/middleware/auth.d.ts +0 -287
  66. package/dist/middleware/auth.d.ts.map +0 -1
  67. package/dist/middleware/auth.js +0 -610
  68. package/dist/middleware/auth.js.map +0 -1
  69. package/dist/monitoring/health.d.ts +0 -241
  70. package/dist/monitoring/health.d.ts.map +0 -1
  71. package/dist/monitoring/health.js +0 -649
  72. package/dist/monitoring/health.js.map +0 -1
  73. package/dist/monitoring/metrics.d.ts +0 -153
  74. package/dist/monitoring/metrics.d.ts.map +0 -1
  75. package/dist/monitoring/metrics.js +0 -349
  76. package/dist/monitoring/metrics.js.map +0 -1
  77. package/dist/security/rate-limit-middleware.d.ts +0 -119
  78. package/dist/security/rate-limit-middleware.d.ts.map +0 -1
  79. package/dist/security/rate-limit-middleware.js +0 -193
  80. package/dist/security/rate-limit-middleware.js.map +0 -1
@@ -0,0 +1,225 @@
1
+ export function initializeIndexOutboxSchema(db) {
2
+ db.exec(`
3
+ CREATE TABLE IF NOT EXISTS index_outbox (
4
+ memory_id TEXT PRIMARY KEY,
5
+ operation TEXT NOT NULL CHECK (operation IN ('upsert', 'delete')),
6
+ namespace TEXT NOT NULL,
7
+ content TEXT,
8
+ memory_type TEXT,
9
+ metadata TEXT,
10
+ agent_id TEXT,
11
+ task_id TEXT,
12
+ created_at INTEGER NOT NULL,
13
+ qdrant_pending INTEGER NOT NULL DEFAULT 1,
14
+ redis_pending INTEGER NOT NULL DEFAULT 1,
15
+ attempts INTEGER NOT NULL DEFAULT 0,
16
+ last_error TEXT,
17
+ revision INTEGER NOT NULL DEFAULT 1,
18
+ updated_at INTEGER NOT NULL
19
+ );
20
+
21
+ CREATE INDEX IF NOT EXISTS idx_index_outbox_pending
22
+ ON index_outbox(qdrant_pending, redis_pending, updated_at);
23
+ `);
24
+ const columns = db.prepare("PRAGMA table_info(index_outbox)").all();
25
+ if (!columns.some((column) => column.name === "revision")) {
26
+ db.exec("ALTER TABLE index_outbox ADD COLUMN revision INTEGER NOT NULL DEFAULT 1");
27
+ }
28
+ }
29
+ /**
30
+ * Keeps Redis and Qdrant as rebuildable projections of canonical SQLite rows.
31
+ * Enqueue methods are synchronous so callers can include them in a SQLite
32
+ * transaction. Draining is best-effort and may be retried safely.
33
+ */
34
+ export class IndexOutboxProcessor {
35
+ db;
36
+ dependencies;
37
+ activeDrain;
38
+ desiredQdrantProjection;
39
+ desiredRedisProjection;
40
+ constructor(db, dependencies) {
41
+ this.db = db;
42
+ this.dependencies = dependencies;
43
+ this.desiredQdrantProjection =
44
+ dependencies.projectionConfig?.qdrant ??
45
+ Boolean(dependencies.embeddingClient && dependencies.hybridSearch);
46
+ this.desiredRedisProjection =
47
+ dependencies.projectionConfig?.redis ?? Boolean(dependencies.workingMemory);
48
+ }
49
+ enqueue(mutation) {
50
+ const now = Date.now();
51
+ const qdrantPending = this.desiredQdrantProjection ? 1 : 0;
52
+ const redisPending = this.desiredRedisProjection ? 1 : 0;
53
+ if (qdrantPending === 0 && redisPending === 0) {
54
+ // SQLite + FTS are already canonical and synchronous. Do not report an
55
+ // intentionally unconfigured projection as a permanent failed write.
56
+ this.db.prepare("DELETE FROM index_outbox WHERE memory_id = ?").run(mutation.memoryId);
57
+ return;
58
+ }
59
+ this.db
60
+ .prepare(`
61
+ INSERT INTO index_outbox (
62
+ memory_id, operation, namespace, content, memory_type, metadata,
63
+ agent_id, task_id, created_at, qdrant_pending, redis_pending,
64
+ attempts, last_error, revision, updated_at
65
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, NULL, 1, ?)
66
+ ON CONFLICT(memory_id) DO UPDATE SET
67
+ operation = excluded.operation,
68
+ namespace = excluded.namespace,
69
+ content = excluded.content,
70
+ memory_type = excluded.memory_type,
71
+ metadata = excluded.metadata,
72
+ agent_id = excluded.agent_id,
73
+ task_id = excluded.task_id,
74
+ created_at = excluded.created_at,
75
+ qdrant_pending = excluded.qdrant_pending,
76
+ redis_pending = excluded.redis_pending,
77
+ attempts = 0,
78
+ last_error = NULL,
79
+ revision = index_outbox.revision + 1,
80
+ updated_at = excluded.updated_at
81
+ `)
82
+ .run(mutation.memoryId, mutation.operation, mutation.namespace, mutation.content ?? null, mutation.memoryType ?? null, JSON.stringify(mutation.metadata ?? {}), mutation.agentId ?? null, mutation.taskId ?? null, mutation.createdAt, qdrantPending, redisPending, now);
83
+ }
84
+ getState(memoryId) {
85
+ const pending = this.db.prepare("SELECT 1 FROM index_outbox WHERE memory_id = ?").get(memoryId);
86
+ return pending ? "pending" : "indexed";
87
+ }
88
+ getPendingCount() {
89
+ const row = this.db.prepare("SELECT COUNT(*) AS count FROM index_outbox").get();
90
+ return row.count;
91
+ }
92
+ drain(limit = 100) {
93
+ if (this.activeDrain)
94
+ return this.activeDrain;
95
+ const operation = this.performDrain(limit).finally(() => {
96
+ if (this.activeDrain === operation)
97
+ this.activeDrain = undefined;
98
+ });
99
+ this.activeDrain = operation;
100
+ return operation;
101
+ }
102
+ async performDrain(limit) {
103
+ const rows = this.db
104
+ .prepare(`
105
+ SELECT * FROM index_outbox
106
+ WHERE qdrant_pending = 1 OR redis_pending = 1
107
+ ORDER BY updated_at ASC
108
+ LIMIT ?
109
+ `)
110
+ .all(limit);
111
+ const stats = {
112
+ examined: rows.length,
113
+ completed: 0,
114
+ pending: 0,
115
+ errors: [],
116
+ };
117
+ for (const row of rows) {
118
+ const errors = [];
119
+ let qdrantPending = row.qdrant_pending === 1;
120
+ let redisPending = row.redis_pending === 1;
121
+ const hybridSearch = this.dependencies.hybridSearch;
122
+ const qdrantReady = hybridSearch && (row.operation === "delete" || this.dependencies.embeddingClient);
123
+ if (qdrantPending && qdrantReady) {
124
+ try {
125
+ if (row.operation === "delete") {
126
+ await hybridSearch.deleteMemory(row.memory_id);
127
+ }
128
+ else if (row.content && row.memory_type) {
129
+ const vector = await this.dependencies.embeddingClient.embed(row.content);
130
+ const metadata = parseMetadata(row.metadata);
131
+ await hybridSearch.upsertMemory(row.memory_id, vector, {
132
+ ...metadata,
133
+ content: row.content,
134
+ memory_type: row.memory_type,
135
+ created_at: row.created_at,
136
+ namespace: row.namespace,
137
+ agent_id: row.agent_id ?? undefined,
138
+ task_id: row.task_id ?? undefined,
139
+ });
140
+ }
141
+ qdrantPending = false;
142
+ }
143
+ catch (error) {
144
+ errors.push(`qdrant: ${errorMessage(error)}`);
145
+ }
146
+ }
147
+ if (redisPending && this.dependencies.workingMemory) {
148
+ try {
149
+ if (row.operation === "delete") {
150
+ await this.dependencies.workingMemory.delete(row.memory_id, row.namespace);
151
+ }
152
+ else if (row.content && row.memory_type) {
153
+ const metadata = parseMetadata(row.metadata);
154
+ await this.dependencies.workingMemory.store({
155
+ conversationId: row.memory_id,
156
+ timestamp: new Date(row.created_at),
157
+ fullText: row.content,
158
+ keyEntities: stringArray(metadata.key_entities),
159
+ topics: stringArray(metadata.topics ?? metadata.tags),
160
+ userIntent: typeof metadata.user_intent === "string" ? metadata.user_intent : row.memory_type,
161
+ }, row.namespace);
162
+ }
163
+ redisPending = false;
164
+ }
165
+ catch (error) {
166
+ errors.push(`redis: ${errorMessage(error)}`);
167
+ }
168
+ }
169
+ if (!qdrantPending && !redisPending) {
170
+ const deleted = this.db
171
+ .prepare("DELETE FROM index_outbox WHERE memory_id = ? AND revision = ?")
172
+ .run(row.memory_id, row.revision);
173
+ if (deleted.changes > 0)
174
+ stats.completed++;
175
+ else
176
+ stats.pending++;
177
+ }
178
+ else {
179
+ const unavailable = [];
180
+ if (qdrantPending &&
181
+ (!this.dependencies.hybridSearch ||
182
+ (row.operation !== "delete" && !this.dependencies.embeddingClient))) {
183
+ unavailable.push("qdrant dependencies unavailable");
184
+ }
185
+ if (redisPending && !this.dependencies.workingMemory) {
186
+ unavailable.push("redis unavailable");
187
+ }
188
+ const messages = [...errors, ...unavailable];
189
+ const updated = this.db
190
+ .prepare(`
191
+ UPDATE index_outbox
192
+ SET qdrant_pending = ?, redis_pending = ?, attempts = attempts + ?,
193
+ last_error = ?, updated_at = ?
194
+ WHERE memory_id = ? AND revision = ?
195
+ `)
196
+ .run(qdrantPending ? 1 : 0, redisPending ? 1 : 0, errors.length > 0 ? 1 : 0, messages.join("; ") || null, Date.now(), row.memory_id, row.revision);
197
+ stats.pending++;
198
+ if (updated.changes > 0) {
199
+ stats.errors.push(...errors.map((message) => `${row.memory_id}: ${message}`));
200
+ }
201
+ }
202
+ }
203
+ return stats;
204
+ }
205
+ }
206
+ function parseMetadata(value) {
207
+ if (!value)
208
+ return {};
209
+ try {
210
+ const parsed = JSON.parse(value);
211
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
212
+ }
213
+ catch {
214
+ return {};
215
+ }
216
+ }
217
+ function stringArray(value) {
218
+ return Array.isArray(value)
219
+ ? value.filter((item) => typeof item === "string")
220
+ : [];
221
+ }
222
+ function errorMessage(error) {
223
+ return error instanceof Error ? error.message : String(error);
224
+ }
225
+ //# sourceMappingURL=index-outbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-outbox.js","sourceRoot":"","sources":["../../src/retrieval/index-outbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Canonical memory retrieval.
3
+ *
4
+ * SQLite owns memory contents and authorization-relevant attributes. FTS5 and
5
+ * Qdrant are derived indexes: they may nominate ids, but their payloads are
6
+ * never returned or trusted for filtering.
7
+ */
8
+ import Database from "better-sqlite3";
9
+ import type { EmbeddingClient } from "../embeddings/client.js";
10
+ import type { HybridSearchEngine } from "./hybrid-search.js";
11
+ export type RetrievalStrategy = "auto" | "hybrid" | "full_text" | "semantic";
12
+ export type EffectiveRetrievalStrategy = Exclude<RetrievalStrategy, "auto">;
13
+ export type RetrievalSource = "lexical" | "dense" | "fast_path";
14
+ export interface RetrieveMemoriesInput {
15
+ query: string;
16
+ namespace?: string;
17
+ memoryTypes?: string[];
18
+ maxResults?: number;
19
+ strategy?: RetrievalStrategy;
20
+ agentId?: string;
21
+ taskId?: string;
22
+ excludeAgent?: string;
23
+ includeSuperseded?: boolean;
24
+ includeArchived?: boolean;
25
+ /** Unix epoch milliseconds at which the memory must have been valid. */
26
+ asOf?: number;
27
+ /** Include a content-free account of the retrieval stages. */
28
+ explain?: boolean;
29
+ }
30
+ export interface MemoryRetrievalResult {
31
+ id: string;
32
+ content: string;
33
+ memoryType: string;
34
+ createdAt: string | number;
35
+ updatedAt: string | number;
36
+ metadata: Record<string, unknown>;
37
+ namespace: string;
38
+ agentId?: string;
39
+ agentRole?: string;
40
+ taskId?: string;
41
+ similarityScore?: number;
42
+ denseScore?: number;
43
+ /** Positive SQLite BM25 relevance (-1 * SQLite's lower-is-better value). */
44
+ lexicalScore?: number;
45
+ /** Reciprocal-rank-fusion score; present only for hybrid retrieval. */
46
+ fusedScore?: number;
47
+ rank: number;
48
+ sources: RetrievalSource[];
49
+ }
50
+ export interface RetrievalTraceStage {
51
+ stage: "lexical" | "dense" | "fusion" | "hydration" | "filtering";
52
+ candidateCount: number;
53
+ status: "ok" | "skipped" | "unavailable";
54
+ fallback?: "unfiltered_legacy_vectors";
55
+ }
56
+ export interface RetrievalTrace {
57
+ requestedStrategy: RetrievalStrategy;
58
+ effectiveStrategy: EffectiveRetrievalStrategy;
59
+ candidateLimit: number;
60
+ stages: RetrievalTraceStage[];
61
+ returnedCount: number;
62
+ }
63
+ export interface MemoryRetrievalResponse {
64
+ strategy: EffectiveRetrievalStrategy;
65
+ results: MemoryRetrievalResult[];
66
+ trace?: RetrievalTrace;
67
+ }
68
+ export interface RetrieveByIdsInput {
69
+ namespace?: string;
70
+ memoryTypes?: string[];
71
+ maxResults?: number;
72
+ agentId?: string;
73
+ taskId?: string;
74
+ excludeAgent?: string;
75
+ includeSuperseded?: boolean;
76
+ includeArchived?: boolean;
77
+ asOf?: number;
78
+ /** Optional scores from the candidate source, keyed by canonical memory id. */
79
+ similarityScores?: ReadonlyMap<string, number>;
80
+ source?: RetrievalSource;
81
+ }
82
+ export interface MemoryRetrieverDependencies {
83
+ db: Database.Database;
84
+ embeddingClient?: Pick<EmbeddingClient, "embed">;
85
+ hybridSearch?: Pick<HybridSearchEngine, "denseSearch">;
86
+ now?: () => number;
87
+ rrfK?: number;
88
+ candidateMultiplier?: number;
89
+ }
90
+ export declare class MemoryRetriever {
91
+ private readonly db;
92
+ private readonly embeddingClient?;
93
+ private readonly hybridSearch?;
94
+ private readonly now;
95
+ private readonly rrfK;
96
+ private readonly candidateMultiplier;
97
+ private memoryColumns;
98
+ constructor(dependencies: MemoryRetrieverDependencies);
99
+ /**
100
+ * Create the external-content FTS5 index and synchronization triggers.
101
+ * Existing rows are backfilled only when the index is first created.
102
+ */
103
+ initialize(): void;
104
+ retrieve(input: RetrieveMemoriesInput): Promise<MemoryRetrievalResponse>;
105
+ /**
106
+ * Canonically hydrate an ordered candidate list from a cache or legacy index.
107
+ * Supplied order is preserved, duplicate/missing ids are removed, all filters
108
+ * are applied to SQLite rows, and only returned rows receive access credit.
109
+ */
110
+ retrieveByIds(ids: readonly string[], input?: RetrieveByIdsInput): MemoryRetrievalResult[];
111
+ private validateInput;
112
+ private effectiveStrategy;
113
+ private lexicalSearch;
114
+ private denseSearch;
115
+ private rankCandidates;
116
+ private hydrate;
117
+ private matchesFilters;
118
+ private reinforceAccess;
119
+ private getMemoryColumns;
120
+ }
121
+ /** Convert arbitrary text into literal FTS tokens, never executable FTS syntax. */
122
+ export declare function sanitizeFtsQuery(query: string): string | null;
123
+ //# sourceMappingURL=memory-retriever.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-retriever.d.ts","sourceRoot":"","sources":["../../src/retrieval/memory-retriever.ts"],"names":[],"mappings":"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"}