@agentlensai/server 0.2.0 → 0.5.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 (222) hide show
  1. package/dist/db/embedding-store.d.ts +74 -0
  2. package/dist/db/embedding-store.d.ts.map +1 -0
  3. package/dist/db/embedding-store.js +177 -0
  4. package/dist/db/embedding-store.js.map +1 -0
  5. package/dist/db/lesson-store.d.ts +57 -0
  6. package/dist/db/lesson-store.d.ts.map +1 -0
  7. package/dist/db/lesson-store.js +217 -0
  8. package/dist/db/lesson-store.js.map +1 -0
  9. package/dist/db/migrate.d.ts.map +1 -1
  10. package/dist/db/migrate.js +250 -4
  11. package/dist/db/migrate.js.map +1 -1
  12. package/dist/db/schema.sqlite.d.ts +881 -55
  13. package/dist/db/schema.sqlite.d.ts.map +1 -1
  14. package/dist/db/schema.sqlite.js +82 -4
  15. package/dist/db/schema.sqlite.js.map +1 -1
  16. package/dist/db/session-summary-store.d.ts +45 -0
  17. package/dist/db/session-summary-store.d.ts.map +1 -0
  18. package/dist/db/session-summary-store.js +112 -0
  19. package/dist/db/session-summary-store.js.map +1 -0
  20. package/dist/db/sqlite-store.d.ts +25 -13
  21. package/dist/db/sqlite-store.d.ts.map +1 -1
  22. package/dist/db/sqlite-store.js +224 -47
  23. package/dist/db/sqlite-store.js.map +1 -1
  24. package/dist/db/tenant-scoped-store.d.ts +61 -0
  25. package/dist/db/tenant-scoped-store.d.ts.map +1 -0
  26. package/dist/db/tenant-scoped-store.js +94 -0
  27. package/dist/db/tenant-scoped-store.js.map +1 -0
  28. package/dist/index.d.ts +25 -4
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +99 -5
  31. package/dist/index.js.map +1 -1
  32. package/dist/lib/alert-engine.d.ts +72 -0
  33. package/dist/lib/alert-engine.d.ts.map +1 -0
  34. package/dist/lib/alert-engine.js +318 -0
  35. package/dist/lib/alert-engine.js.map +1 -0
  36. package/dist/lib/analysis/cost-analysis.d.ts +20 -0
  37. package/dist/lib/analysis/cost-analysis.d.ts.map +1 -0
  38. package/dist/lib/analysis/cost-analysis.js +158 -0
  39. package/dist/lib/analysis/cost-analysis.js.map +1 -0
  40. package/dist/lib/analysis/error-patterns.d.ts +26 -0
  41. package/dist/lib/analysis/error-patterns.d.ts.map +1 -0
  42. package/dist/lib/analysis/error-patterns.js +155 -0
  43. package/dist/lib/analysis/error-patterns.js.map +1 -0
  44. package/dist/lib/analysis/index.d.ts +23 -0
  45. package/dist/lib/analysis/index.d.ts.map +1 -0
  46. package/dist/lib/analysis/index.js +144 -0
  47. package/dist/lib/analysis/index.js.map +1 -0
  48. package/dist/lib/analysis/performance-trends.d.ts +19 -0
  49. package/dist/lib/analysis/performance-trends.d.ts.map +1 -0
  50. package/dist/lib/analysis/performance-trends.js +118 -0
  51. package/dist/lib/analysis/performance-trends.js.map +1 -0
  52. package/dist/lib/analysis/tool-sequences.d.ts +19 -0
  53. package/dist/lib/analysis/tool-sequences.d.ts.map +1 -0
  54. package/dist/lib/analysis/tool-sequences.js +145 -0
  55. package/dist/lib/analysis/tool-sequences.js.map +1 -0
  56. package/dist/lib/context/index.d.ts +5 -0
  57. package/dist/lib/context/index.d.ts.map +1 -0
  58. package/dist/lib/context/index.js +5 -0
  59. package/dist/lib/context/index.js.map +1 -0
  60. package/dist/lib/context/retrieval.d.ts +56 -0
  61. package/dist/lib/context/retrieval.d.ts.map +1 -0
  62. package/dist/lib/context/retrieval.js +229 -0
  63. package/dist/lib/context/retrieval.js.map +1 -0
  64. package/dist/lib/embeddings/index.d.ts +31 -0
  65. package/dist/lib/embeddings/index.d.ts.map +1 -0
  66. package/dist/lib/embeddings/index.js +31 -0
  67. package/dist/lib/embeddings/index.js.map +1 -0
  68. package/dist/lib/embeddings/local.d.ts +15 -0
  69. package/dist/lib/embeddings/local.d.ts.map +1 -0
  70. package/dist/lib/embeddings/local.js +65 -0
  71. package/dist/lib/embeddings/local.js.map +1 -0
  72. package/dist/lib/embeddings/math.d.ts +13 -0
  73. package/dist/lib/embeddings/math.d.ts.map +1 -0
  74. package/dist/lib/embeddings/math.js +35 -0
  75. package/dist/lib/embeddings/math.js.map +1 -0
  76. package/dist/lib/embeddings/openai.d.ts +15 -0
  77. package/dist/lib/embeddings/openai.d.ts.map +1 -0
  78. package/dist/lib/embeddings/openai.js +58 -0
  79. package/dist/lib/embeddings/openai.js.map +1 -0
  80. package/dist/lib/embeddings/summarizer.d.ts +26 -0
  81. package/dist/lib/embeddings/summarizer.d.ts.map +1 -0
  82. package/dist/lib/embeddings/summarizer.js +181 -0
  83. package/dist/lib/embeddings/summarizer.js.map +1 -0
  84. package/dist/lib/embeddings/types.d.ts +17 -0
  85. package/dist/lib/embeddings/types.d.ts.map +1 -0
  86. package/dist/lib/embeddings/types.js +5 -0
  87. package/dist/lib/embeddings/types.js.map +1 -0
  88. package/dist/lib/embeddings/worker.d.ts +56 -0
  89. package/dist/lib/embeddings/worker.d.ts.map +1 -0
  90. package/dist/lib/embeddings/worker.js +109 -0
  91. package/dist/lib/embeddings/worker.js.map +1 -0
  92. package/dist/lib/event-bus.d.ts +48 -0
  93. package/dist/lib/event-bus.d.ts.map +1 -0
  94. package/dist/lib/event-bus.js +34 -0
  95. package/dist/lib/event-bus.js.map +1 -0
  96. package/dist/lib/retention.d.ts +1 -1
  97. package/dist/lib/retention.d.ts.map +1 -1
  98. package/dist/lib/sse.d.ts +22 -0
  99. package/dist/lib/sse.d.ts.map +1 -0
  100. package/dist/lib/sse.js +121 -0
  101. package/dist/lib/sse.js.map +1 -0
  102. package/dist/middleware/auth.d.ts +1 -0
  103. package/dist/middleware/auth.d.ts.map +1 -1
  104. package/dist/middleware/auth.js +2 -1
  105. package/dist/middleware/auth.js.map +1 -1
  106. package/dist/routes/agents.d.ts +1 -1
  107. package/dist/routes/agents.d.ts.map +1 -1
  108. package/dist/routes/agents.js +6 -3
  109. package/dist/routes/agents.js.map +1 -1
  110. package/dist/routes/alerts.d.ts +17 -0
  111. package/dist/routes/alerts.d.ts.map +1 -0
  112. package/dist/routes/alerts.js +141 -0
  113. package/dist/routes/alerts.js.map +1 -0
  114. package/dist/routes/analytics.d.ts +16 -0
  115. package/dist/routes/analytics.d.ts.map +1 -0
  116. package/dist/routes/analytics.js +307 -0
  117. package/dist/routes/analytics.js.map +1 -0
  118. package/dist/routes/api-keys.d.ts.map +1 -1
  119. package/dist/routes/api-keys.js +30 -5
  120. package/dist/routes/api-keys.js.map +1 -1
  121. package/dist/routes/config.d.ts +5 -0
  122. package/dist/routes/config.d.ts.map +1 -1
  123. package/dist/routes/config.js +27 -7
  124. package/dist/routes/config.js.map +1 -1
  125. package/dist/routes/context.d.ts +23 -0
  126. package/dist/routes/context.d.ts.map +1 -0
  127. package/dist/routes/context.js +52 -0
  128. package/dist/routes/context.js.map +1 -0
  129. package/dist/routes/events.d.ts +7 -2
  130. package/dist/routes/events.d.ts.map +1 -1
  131. package/dist/routes/events.js +76 -8
  132. package/dist/routes/events.js.map +1 -1
  133. package/dist/routes/ingest.d.ts +36 -0
  134. package/dist/routes/ingest.d.ts.map +1 -0
  135. package/dist/routes/ingest.js +280 -0
  136. package/dist/routes/ingest.js.map +1 -0
  137. package/dist/routes/lessons.d.ts +19 -0
  138. package/dist/routes/lessons.d.ts.map +1 -0
  139. package/dist/routes/lessons.js +164 -0
  140. package/dist/routes/lessons.js.map +1 -0
  141. package/dist/routes/recall.d.ts +20 -0
  142. package/dist/routes/recall.d.ts.map +1 -0
  143. package/dist/routes/recall.js +71 -0
  144. package/dist/routes/recall.js.map +1 -0
  145. package/dist/routes/reflect.d.ts +15 -0
  146. package/dist/routes/reflect.d.ts.map +1 -0
  147. package/dist/routes/reflect.js +55 -0
  148. package/dist/routes/reflect.js.map +1 -0
  149. package/dist/routes/sessions.d.ts +1 -1
  150. package/dist/routes/sessions.d.ts.map +1 -1
  151. package/dist/routes/sessions.js +9 -7
  152. package/dist/routes/sessions.js.map +1 -1
  153. package/dist/routes/stats.d.ts +1 -1
  154. package/dist/routes/stats.d.ts.map +1 -1
  155. package/dist/routes/stats.js +3 -1
  156. package/dist/routes/stats.js.map +1 -1
  157. package/dist/routes/stream.d.ts +23 -0
  158. package/dist/routes/stream.d.ts.map +1 -0
  159. package/dist/routes/stream.js +94 -0
  160. package/dist/routes/stream.js.map +1 -0
  161. package/dist/routes/tenant-helper.d.ts +20 -0
  162. package/dist/routes/tenant-helper.d.ts.map +1 -0
  163. package/dist/routes/tenant-helper.js +23 -0
  164. package/dist/routes/tenant-helper.js.map +1 -0
  165. package/package.json +11 -11
  166. package/LICENSE +0 -21
  167. package/dist/__tests__/agents-stats.test.d.ts +0 -5
  168. package/dist/__tests__/agents-stats.test.d.ts.map +0 -1
  169. package/dist/__tests__/agents-stats.test.js +0 -134
  170. package/dist/__tests__/agents-stats.test.js.map +0 -1
  171. package/dist/__tests__/api-keys.test.d.ts +0 -5
  172. package/dist/__tests__/api-keys.test.d.ts.map +0 -1
  173. package/dist/__tests__/api-keys.test.js +0 -118
  174. package/dist/__tests__/api-keys.test.js.map +0 -1
  175. package/dist/__tests__/auth-no-db.test.d.ts +0 -2
  176. package/dist/__tests__/auth-no-db.test.d.ts.map +0 -1
  177. package/dist/__tests__/auth-no-db.test.js +0 -43
  178. package/dist/__tests__/auth-no-db.test.js.map +0 -1
  179. package/dist/__tests__/auth.test.d.ts +0 -5
  180. package/dist/__tests__/auth.test.d.ts.map +0 -1
  181. package/dist/__tests__/auth.test.js +0 -86
  182. package/dist/__tests__/auth.test.js.map +0 -1
  183. package/dist/__tests__/config.test.d.ts +0 -2
  184. package/dist/__tests__/config.test.d.ts.map +0 -1
  185. package/dist/__tests__/config.test.js +0 -37
  186. package/dist/__tests__/config.test.js.map +0 -1
  187. package/dist/__tests__/events-ingest.test.d.ts +0 -5
  188. package/dist/__tests__/events-ingest.test.d.ts.map +0 -1
  189. package/dist/__tests__/events-ingest.test.js +0 -248
  190. package/dist/__tests__/events-ingest.test.js.map +0 -1
  191. package/dist/__tests__/events-query.test.d.ts +0 -5
  192. package/dist/__tests__/events-query.test.d.ts.map +0 -1
  193. package/dist/__tests__/events-query.test.js +0 -205
  194. package/dist/__tests__/events-query.test.js.map +0 -1
  195. package/dist/__tests__/health.test.d.ts +0 -5
  196. package/dist/__tests__/health.test.d.ts.map +0 -1
  197. package/dist/__tests__/health.test.js +0 -40
  198. package/dist/__tests__/health.test.js.map +0 -1
  199. package/dist/__tests__/sessions.test.d.ts +0 -5
  200. package/dist/__tests__/sessions.test.d.ts.map +0 -1
  201. package/dist/__tests__/sessions.test.js +0 -176
  202. package/dist/__tests__/sessions.test.js.map +0 -1
  203. package/dist/__tests__/test-helpers.d.ts +0 -24
  204. package/dist/__tests__/test-helpers.d.ts.map +0 -1
  205. package/dist/__tests__/test-helpers.js +0 -45
  206. package/dist/__tests__/test-helpers.js.map +0 -1
  207. package/dist/db/__tests__/init.test.d.ts +0 -2
  208. package/dist/db/__tests__/init.test.d.ts.map +0 -1
  209. package/dist/db/__tests__/init.test.js +0 -73
  210. package/dist/db/__tests__/init.test.js.map +0 -1
  211. package/dist/db/__tests__/sqlite-store-read.test.d.ts +0 -2
  212. package/dist/db/__tests__/sqlite-store-read.test.d.ts.map +0 -1
  213. package/dist/db/__tests__/sqlite-store-read.test.js +0 -749
  214. package/dist/db/__tests__/sqlite-store-read.test.js.map +0 -1
  215. package/dist/db/__tests__/sqlite-store-write.test.d.ts +0 -2
  216. package/dist/db/__tests__/sqlite-store-write.test.d.ts.map +0 -1
  217. package/dist/db/__tests__/sqlite-store-write.test.js +0 -418
  218. package/dist/db/__tests__/sqlite-store-write.test.js.map +0 -1
  219. package/dist/lib/__tests__/retention.test.d.ts +0 -2
  220. package/dist/lib/__tests__/retention.test.d.ts.map +0 -1
  221. package/dist/lib/__tests__/retention.test.js +0 -238
  222. package/dist/lib/__tests__/retention.test.js.map +0 -1
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Embedding Store — storage and retrieval of vector embeddings (Story 2.2)
3
+ *
4
+ * Handles CRUD operations for embeddings including:
5
+ * - Content-hash deduplication
6
+ * - In-JS cosine similarity search (SQLite doesn't support vector ops)
7
+ * - Tenant isolation
8
+ */
9
+ import type { SqliteDb } from './index.js';
10
+ /** Options for similarity search */
11
+ export interface SimilaritySearchOptions {
12
+ /** Filter by source type ('event', 'session', 'lesson') */
13
+ sourceType?: string;
14
+ /** Filter by creation time — from (ISO 8601) */
15
+ from?: string;
16
+ /** Filter by creation time — to (ISO 8601) */
17
+ to?: string;
18
+ /** Maximum number of results (default: 10) */
19
+ limit?: number;
20
+ /** Minimum similarity score to include (default: 0.0) */
21
+ minScore?: number;
22
+ }
23
+ /** A single similarity search result */
24
+ export interface SimilarityResult {
25
+ id: string;
26
+ sourceType: string;
27
+ sourceId: string;
28
+ score: number;
29
+ text: string;
30
+ embeddingModel: string;
31
+ createdAt: string;
32
+ }
33
+ /** Stored embedding record (without the raw vector) */
34
+ export interface StoredEmbedding {
35
+ id: string;
36
+ tenantId: string;
37
+ sourceType: string;
38
+ sourceId: string;
39
+ contentHash: string;
40
+ textContent: string;
41
+ embedding: Float32Array;
42
+ embeddingModel: string;
43
+ dimensions: number;
44
+ createdAt: string;
45
+ }
46
+ export declare class EmbeddingStore {
47
+ private readonly db;
48
+ constructor(db: SqliteDb);
49
+ /**
50
+ * Store an embedding with source-level deduplication.
51
+ * If an embedding with the same (tenant, source_type, source_id) already exists,
52
+ * it's updated rather than duplicated. Different sources with the same content
53
+ * are stored as separate rows to preserve source metadata.
54
+ */
55
+ store(tenantId: string, sourceType: string, sourceId: string, textContent: string, embedding: Float32Array, model: string, dimensions: number): string;
56
+ /**
57
+ * Get embeddings for a specific source.
58
+ */
59
+ getBySource(tenantId: string, sourceType: string, sourceId: string): StoredEmbedding | null;
60
+ /**
61
+ * Similarity search: load candidate embeddings filtered by tenant/sourceType/time,
62
+ * compute cosine similarity in JS, sort by score, filter by minScore, return top N.
63
+ */
64
+ similaritySearch(tenantId: string, queryVector: Float32Array, opts?: SimilaritySearchOptions): SimilarityResult[];
65
+ /**
66
+ * Delete embedding(s) for a specific source.
67
+ */
68
+ delete(tenantId: string, sourceType: string, sourceId: string): number;
69
+ /**
70
+ * Count embeddings for a tenant.
71
+ */
72
+ count(tenantId: string): number;
73
+ }
74
+ //# sourceMappingURL=embedding-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-store.d.ts","sourceRoot":"","sources":["../../src/db/embedding-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAyB3C,oCAAoC;AACpC,MAAM,WAAW,uBAAuB;IACtC,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,YAAY,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEzC;;;;;OAKG;IACH,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,YAAY,EACvB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,MAAM;IAqDT;;OAEG;IACH,WAAW,CACT,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,eAAe,GAAG,IAAI;IA6BzB;;;OAGG;IACH,gBAAgB,CACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,YAAY,EACzB,IAAI,GAAE,uBAA4B,GACjC,gBAAgB,EAAE;IAoDrB;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAetE;;OAEG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAShC"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Embedding Store — storage and retrieval of vector embeddings (Story 2.2)
3
+ *
4
+ * Handles CRUD operations for embeddings including:
5
+ * - Content-hash deduplication
6
+ * - In-JS cosine similarity search (SQLite doesn't support vector ops)
7
+ * - Tenant isolation
8
+ */
9
+ import { createHash, randomUUID } from 'node:crypto';
10
+ import { eq, and, sql } from 'drizzle-orm';
11
+ import { embeddings } from './schema.sqlite.js';
12
+ import { cosineSimilarity } from '../lib/embeddings/math.js';
13
+ /** Maximum candidates loaded into memory for similarity search */
14
+ const MAX_CANDIDATES = 10_000;
15
+ /** Compute SHA-256 content hash of text */
16
+ function contentHash(text) {
17
+ return createHash('sha256').update(text).digest('hex');
18
+ }
19
+ /** Serialize Float32Array to Buffer for SQLite BLOB storage */
20
+ function serializeEmbedding(embedding) {
21
+ // Slice to copy — avoids view mutation if source buffer is reused
22
+ return Buffer.from(embedding.buffer.slice(embedding.byteOffset, embedding.byteOffset + embedding.byteLength));
23
+ }
24
+ /** Deserialize Buffer from SQLite BLOB to Float32Array */
25
+ function deserializeEmbedding(blob) {
26
+ // Copy to fresh aligned buffer — Buffer from SQLite may have non-4-byte-aligned offset
27
+ const copy = new Uint8Array(blob).buffer;
28
+ return new Float32Array(copy);
29
+ }
30
+ export class EmbeddingStore {
31
+ db;
32
+ constructor(db) {
33
+ this.db = db;
34
+ }
35
+ /**
36
+ * Store an embedding with source-level deduplication.
37
+ * If an embedding with the same (tenant, source_type, source_id) already exists,
38
+ * it's updated rather than duplicated. Different sources with the same content
39
+ * are stored as separate rows to preserve source metadata.
40
+ */
41
+ store(tenantId, sourceType, sourceId, textContent, embedding, model, dimensions) {
42
+ const hash = contentHash(textContent);
43
+ const now = new Date().toISOString();
44
+ // Check for existing embedding from the same source
45
+ const existing = this.db
46
+ .select({ id: embeddings.id })
47
+ .from(embeddings)
48
+ .where(and(eq(embeddings.tenantId, tenantId), eq(embeddings.sourceType, sourceType), eq(embeddings.sourceId, sourceId)))
49
+ .get();
50
+ if (existing) {
51
+ // Update existing — content may have changed
52
+ this.db
53
+ .update(embeddings)
54
+ .set({
55
+ contentHash: hash,
56
+ textContent,
57
+ embedding: serializeEmbedding(embedding),
58
+ embeddingModel: model,
59
+ dimensions,
60
+ })
61
+ .where(eq(embeddings.id, existing.id))
62
+ .run();
63
+ return existing.id;
64
+ }
65
+ const id = randomUUID();
66
+ this.db
67
+ .insert(embeddings)
68
+ .values({
69
+ id,
70
+ tenantId,
71
+ sourceType,
72
+ sourceId,
73
+ contentHash: hash,
74
+ textContent,
75
+ embedding: serializeEmbedding(embedding),
76
+ embeddingModel: model,
77
+ dimensions,
78
+ createdAt: now,
79
+ })
80
+ .run();
81
+ return id;
82
+ }
83
+ /**
84
+ * Get embeddings for a specific source.
85
+ */
86
+ getBySource(tenantId, sourceType, sourceId) {
87
+ const row = this.db
88
+ .select()
89
+ .from(embeddings)
90
+ .where(and(eq(embeddings.tenantId, tenantId), eq(embeddings.sourceType, sourceType), eq(embeddings.sourceId, sourceId)))
91
+ .get();
92
+ if (!row)
93
+ return null;
94
+ return {
95
+ id: row.id,
96
+ tenantId: row.tenantId,
97
+ sourceType: row.sourceType,
98
+ sourceId: row.sourceId,
99
+ contentHash: row.contentHash,
100
+ textContent: row.textContent,
101
+ embedding: deserializeEmbedding(row.embedding),
102
+ embeddingModel: row.embeddingModel,
103
+ dimensions: row.dimensions,
104
+ createdAt: row.createdAt,
105
+ };
106
+ }
107
+ /**
108
+ * Similarity search: load candidate embeddings filtered by tenant/sourceType/time,
109
+ * compute cosine similarity in JS, sort by score, filter by minScore, return top N.
110
+ */
111
+ similaritySearch(tenantId, queryVector, opts = {}) {
112
+ const { sourceType, from, to, limit = 10, minScore = 0.0 } = opts;
113
+ // Build all conditions upfront
114
+ const conditions = [eq(embeddings.tenantId, tenantId)];
115
+ if (sourceType) {
116
+ conditions.push(eq(embeddings.sourceType, sourceType));
117
+ }
118
+ if (from) {
119
+ conditions.push(sql `${embeddings.createdAt} >= ${from}`);
120
+ }
121
+ if (to) {
122
+ conditions.push(sql `${embeddings.createdAt} <= ${to}`);
123
+ }
124
+ const rows = this.db
125
+ .select()
126
+ .from(embeddings)
127
+ .where(and(...conditions))
128
+ .limit(MAX_CANDIDATES)
129
+ .all();
130
+ if (rows.length >= MAX_CANDIDATES) {
131
+ console.warn(`[EmbeddingStore] similaritySearch hit MAX_CANDIDATES limit (${MAX_CANDIDATES}) ` +
132
+ `for tenant=${tenantId}. Results may be incomplete.`);
133
+ }
134
+ // Compute cosine similarity for each candidate
135
+ const results = [];
136
+ for (const row of rows) {
137
+ const embVector = deserializeEmbedding(row.embedding);
138
+ const score = cosineSimilarity(queryVector, embVector);
139
+ if (score >= minScore) {
140
+ results.push({
141
+ id: row.id,
142
+ sourceType: row.sourceType,
143
+ sourceId: row.sourceId,
144
+ score,
145
+ text: row.textContent,
146
+ embeddingModel: row.embeddingModel,
147
+ createdAt: row.createdAt,
148
+ });
149
+ }
150
+ }
151
+ // Sort by score descending and take top N
152
+ results.sort((a, b) => b.score - a.score);
153
+ return results.slice(0, limit);
154
+ }
155
+ /**
156
+ * Delete embedding(s) for a specific source.
157
+ */
158
+ delete(tenantId, sourceType, sourceId) {
159
+ const result = this.db
160
+ .delete(embeddings)
161
+ .where(and(eq(embeddings.tenantId, tenantId), eq(embeddings.sourceType, sourceType), eq(embeddings.sourceId, sourceId)))
162
+ .run();
163
+ return result.changes;
164
+ }
165
+ /**
166
+ * Count embeddings for a tenant.
167
+ */
168
+ count(tenantId) {
169
+ const result = this.db
170
+ .select({ count: sql `COUNT(*)` })
171
+ .from(embeddings)
172
+ .where(eq(embeddings.tenantId, tenantId))
173
+ .get();
174
+ return result?.count ?? 0;
175
+ }
176
+ }
177
+ //# sourceMappingURL=embedding-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-store.js","sourceRoot":"","sources":["../../src/db/embedding-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,kEAAkE;AAClE,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,2CAA2C;AAC3C,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,+DAA+D;AAC/D,SAAS,kBAAkB,CAAC,SAAuB;IACjD,kEAAkE;IAClE,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;AAChH,CAAC;AAED,0DAA0D;AAC1D,SAAS,oBAAoB,CAAC,IAAY;IACxC,uFAAuF;IACvF,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAyCD,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,EAAY;QAAZ,OAAE,GAAF,EAAE,CAAU;IAAG,CAAC;IAE7C;;;;;OAKG;IACH,KAAK,CACH,QAAgB,EAChB,UAAkB,EAClB,QAAgB,EAChB,WAAmB,EACnB,SAAuB,EACvB,KAAa,EACb,UAAkB;QAElB,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,oDAAoD;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;aACrB,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC;aAC7B,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACjC,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,EACrC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAClC,CACF;aACA,GAAG,EAAE,CAAC;QAET,IAAI,QAAQ,EAAE,CAAC;YACb,6CAA6C;YAC7C,IAAI,CAAC,EAAE;iBACJ,MAAM,CAAC,UAAU,CAAC;iBAClB,GAAG,CAAC;gBACH,WAAW,EAAE,IAAI;gBACjB,WAAW;gBACX,SAAS,EAAE,kBAAkB,CAAC,SAAS,CAAC;gBACxC,cAAc,EAAE,KAAK;gBACrB,UAAU;aACX,CAAC;iBACD,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;iBACrC,GAAG,EAAE,CAAC;YACT,OAAO,QAAQ,CAAC,EAAE,CAAC;QACrB,CAAC;QAED,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;QACxB,IAAI,CAAC,EAAE;aACJ,MAAM,CAAC,UAAU,CAAC;aAClB,MAAM,CAAC;YACN,EAAE;YACF,QAAQ;YACR,UAAU;YACV,QAAQ;YACR,WAAW,EAAE,IAAI;YACjB,WAAW;YACX,SAAS,EAAE,kBAAkB,CAAC,SAAS,CAAC;YACxC,cAAc,EAAE,KAAK;YACrB,UAAU;YACV,SAAS,EAAE,GAAG;SACf,CAAC;aACD,GAAG,EAAE,CAAC;QAET,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;OAEG;IACH,WAAW,CACT,QAAgB,EAChB,UAAkB,EAClB,QAAgB;QAEhB,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,MAAM,EAAE;aACR,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACjC,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,EACrC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAClC,CACF;aACA,GAAG,EAAE,CAAC;QAET,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,SAAS,EAAE,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC;YAC9C,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,SAAS,EAAE,GAAG,CAAC,SAAS;SACzB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,gBAAgB,CACd,QAAgB,EAChB,WAAyB,EACzB,OAAgC,EAAE;QAElC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;QAElE,+BAA+B;QAC/B,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QACvD,IAAI,UAAU,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,IAAI,EAAE,CAAC;YACT,UAAU,CAAC,IAAI,CAAC,GAAG,CAAA,GAAG,UAAU,CAAC,SAAS,OAAO,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,EAAE,EAAE,CAAC;YACP,UAAU,CAAC,IAAI,CAAC,GAAG,CAAA,GAAG,UAAU,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,MAAM,EAAE;aACR,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;aACzB,KAAK,CAAC,cAAc,CAAC;aACrB,GAAG,EAAE,CAAC;QAET,IAAI,IAAI,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CACV,+DAA+D,cAAc,IAAI;gBACjF,cAAc,QAAQ,8BAA8B,CACrD,CAAC;QACJ,CAAC;QAED,+CAA+C;QAC/C,MAAM,OAAO,GAAuB,EAAE,CAAC;QACvC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACtD,MAAM,KAAK,GAAG,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YACvD,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;gBACtB,OAAO,CAAC,IAAI,CAAC;oBACX,EAAE,EAAE,GAAG,CAAC,EAAE;oBACV,UAAU,EAAE,GAAG,CAAC,UAAU;oBAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,KAAK;oBACL,IAAI,EAAE,GAAG,CAAC,WAAW;oBACrB,cAAc,EAAE,GAAG,CAAC,cAAc;oBAClC,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAgB,EAAE,UAAkB,EAAE,QAAgB;QAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;aACnB,MAAM,CAAC,UAAU,CAAC;aAClB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACjC,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,EACrC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAClC,CACF;aACA,GAAG,EAAE,CAAC;QAET,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAgB;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;aACnB,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,UAAU,EAAE,CAAC;aACxC,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;aACxC,GAAG,EAAE,CAAC;QAET,OAAO,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Lesson Store (Story 3.1)
3
+ *
4
+ * CRUD operations for the lessons table with tenant isolation.
5
+ */
6
+ import type { SqliteDb } from './index.js';
7
+ import type { Lesson, LessonQuery, LessonImportance } from '@agentlensai/core';
8
+ /** Input for creating a new lesson */
9
+ export interface CreateLessonInput {
10
+ title: string;
11
+ content: string;
12
+ category?: string;
13
+ importance?: LessonImportance;
14
+ agentId?: string;
15
+ context?: Record<string, unknown>;
16
+ sourceSessionId?: string;
17
+ sourceEventId?: string;
18
+ }
19
+ /** Input for updating an existing lesson */
20
+ export interface UpdateLessonInput {
21
+ title?: string;
22
+ content?: string;
23
+ category?: string;
24
+ importance?: LessonImportance;
25
+ agentId?: string;
26
+ context?: Record<string, unknown>;
27
+ }
28
+ export declare class LessonStore {
29
+ private readonly db;
30
+ constructor(db: SqliteDb);
31
+ /**
32
+ * Create a new lesson.
33
+ */
34
+ create(tenantId: string, input: CreateLessonInput): Lesson;
35
+ /**
36
+ * Get a lesson by ID. Increments access_count and updates last_accessed_at.
37
+ * Wrapped in a transaction for atomicity.
38
+ */
39
+ get(tenantId: string, id: string): Lesson | null;
40
+ /**
41
+ * List lessons with optional filters.
42
+ */
43
+ list(tenantId: string, query?: LessonQuery): Lesson[];
44
+ /**
45
+ * Update a lesson (partial update).
46
+ */
47
+ update(tenantId: string, id: string, updates: UpdateLessonInput): Lesson;
48
+ /**
49
+ * Soft-delete (archive) a lesson.
50
+ */
51
+ archive(tenantId: string, id: string): void;
52
+ /**
53
+ * Count lessons matching filters.
54
+ */
55
+ count(tenantId: string, query?: LessonQuery): number;
56
+ }
57
+ //# sourceMappingURL=lesson-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lesson-store.d.ts","sourceRoot":"","sources":["../../src/db/lesson-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG/E,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AA+BD,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEzC;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM;IA2B1D;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA4BhD;;OAEG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE;IAyCrD;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,MAAM;IAsCxE;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAmB3C;;OAEG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM;CAkCrD"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Lesson Store (Story 3.1)
3
+ *
4
+ * CRUD operations for the lessons table with tenant isolation.
5
+ */
6
+ import { randomUUID } from 'node:crypto';
7
+ import { eq, and, or, sql, isNull } from 'drizzle-orm';
8
+ import { lessons } from './schema.sqlite.js';
9
+ import { NotFoundError } from './errors.js';
10
+ /** Valid importance values for runtime validation */
11
+ const VALID_IMPORTANCE = new Set(['low', 'normal', 'high', 'critical']);
12
+ /** Escape LIKE wildcard characters to prevent injection */
13
+ function escapeLike(s) {
14
+ return s.replace(/[%_]/g, '\\$&');
15
+ }
16
+ /** Parse a DB row into a Lesson */
17
+ function rowToLesson(row) {
18
+ return {
19
+ id: row.id,
20
+ tenantId: row.tenantId,
21
+ agentId: row.agentId ?? undefined,
22
+ category: row.category,
23
+ title: row.title,
24
+ content: row.content,
25
+ context: JSON.parse(row.context),
26
+ importance: VALID_IMPORTANCE.has(row.importance) ? row.importance : 'normal',
27
+ sourceSessionId: row.sourceSessionId ?? undefined,
28
+ sourceEventId: row.sourceEventId ?? undefined,
29
+ accessCount: row.accessCount,
30
+ lastAccessedAt: row.lastAccessedAt ?? undefined,
31
+ createdAt: row.createdAt,
32
+ updatedAt: row.updatedAt,
33
+ archivedAt: row.archivedAt ?? undefined,
34
+ };
35
+ }
36
+ export class LessonStore {
37
+ db;
38
+ constructor(db) {
39
+ this.db = db;
40
+ }
41
+ /**
42
+ * Create a new lesson.
43
+ */
44
+ create(tenantId, input) {
45
+ const now = new Date().toISOString();
46
+ const id = randomUUID();
47
+ const row = {
48
+ id,
49
+ tenantId,
50
+ agentId: input.agentId ?? null,
51
+ category: input.category ?? 'general',
52
+ title: input.title,
53
+ content: input.content,
54
+ context: JSON.stringify(input.context ?? {}),
55
+ importance: input.importance ?? 'normal',
56
+ sourceSessionId: input.sourceSessionId ?? null,
57
+ sourceEventId: input.sourceEventId ?? null,
58
+ accessCount: 0,
59
+ lastAccessedAt: null,
60
+ createdAt: now,
61
+ updatedAt: now,
62
+ archivedAt: null,
63
+ };
64
+ this.db.insert(lessons).values(row).run();
65
+ return rowToLesson(row);
66
+ }
67
+ /**
68
+ * Get a lesson by ID. Increments access_count and updates last_accessed_at.
69
+ * Wrapped in a transaction for atomicity.
70
+ */
71
+ get(tenantId, id) {
72
+ return this.db.transaction((tx) => {
73
+ const row = tx
74
+ .select()
75
+ .from(lessons)
76
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
77
+ .get();
78
+ if (!row)
79
+ return null;
80
+ // Atomic increment — uses SQL expression to avoid read-then-write race
81
+ const now = new Date().toISOString();
82
+ tx.update(lessons)
83
+ .set({
84
+ accessCount: sql `${lessons.accessCount} + 1`,
85
+ lastAccessedAt: now,
86
+ })
87
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
88
+ .run();
89
+ return rowToLesson({
90
+ ...row,
91
+ accessCount: row.accessCount + 1,
92
+ lastAccessedAt: now,
93
+ });
94
+ });
95
+ }
96
+ /**
97
+ * List lessons with optional filters.
98
+ */
99
+ list(tenantId, query) {
100
+ const conditions = [eq(lessons.tenantId, tenantId)];
101
+ if (!query?.includeArchived) {
102
+ conditions.push(isNull(lessons.archivedAt));
103
+ }
104
+ if (query?.agentId) {
105
+ conditions.push(eq(lessons.agentId, query.agentId));
106
+ }
107
+ if (query?.category) {
108
+ conditions.push(eq(lessons.category, query.category));
109
+ }
110
+ if (query?.importance) {
111
+ conditions.push(eq(lessons.importance, query.importance));
112
+ }
113
+ if (query?.search) {
114
+ const pattern = `%${escapeLike(query.search)}%`;
115
+ conditions.push(or(sql `${lessons.title} LIKE ${pattern} ESCAPE '\\'`, sql `${lessons.content} LIKE ${pattern} ESCAPE '\\'`));
116
+ }
117
+ const limit = query?.limit ?? 50;
118
+ const offset = query?.offset ?? 0;
119
+ const rows = this.db
120
+ .select()
121
+ .from(lessons)
122
+ .where(and(...conditions))
123
+ .limit(limit)
124
+ .offset(offset)
125
+ .orderBy(sql `${lessons.createdAt} DESC`)
126
+ .all();
127
+ return rows.map(rowToLesson);
128
+ }
129
+ /**
130
+ * Update a lesson (partial update).
131
+ */
132
+ update(tenantId, id, updates) {
133
+ // Check existence
134
+ const existing = this.db
135
+ .select()
136
+ .from(lessons)
137
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
138
+ .get();
139
+ if (!existing) {
140
+ throw new NotFoundError(`Lesson ${id} not found`);
141
+ }
142
+ const now = new Date().toISOString();
143
+ const setValues = { updatedAt: now };
144
+ if (updates.title !== undefined)
145
+ setValues['title'] = updates.title;
146
+ if (updates.content !== undefined)
147
+ setValues['content'] = updates.content;
148
+ if (updates.category !== undefined)
149
+ setValues['category'] = updates.category;
150
+ if (updates.importance !== undefined)
151
+ setValues['importance'] = updates.importance;
152
+ if (updates.agentId !== undefined)
153
+ setValues['agentId'] = updates.agentId;
154
+ if (updates.context !== undefined)
155
+ setValues['context'] = JSON.stringify(updates.context);
156
+ this.db
157
+ .update(lessons)
158
+ .set(setValues)
159
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
160
+ .run();
161
+ // Fetch updated row
162
+ const updated = this.db
163
+ .select()
164
+ .from(lessons)
165
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
166
+ .get();
167
+ return rowToLesson(updated);
168
+ }
169
+ /**
170
+ * Soft-delete (archive) a lesson.
171
+ */
172
+ archive(tenantId, id) {
173
+ const existing = this.db
174
+ .select()
175
+ .from(lessons)
176
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
177
+ .get();
178
+ if (!existing) {
179
+ throw new NotFoundError(`Lesson ${id} not found`);
180
+ }
181
+ const now = new Date().toISOString();
182
+ this.db
183
+ .update(lessons)
184
+ .set({ archivedAt: now, updatedAt: now })
185
+ .where(and(eq(lessons.id, id), eq(lessons.tenantId, tenantId)))
186
+ .run();
187
+ }
188
+ /**
189
+ * Count lessons matching filters.
190
+ */
191
+ count(tenantId, query) {
192
+ const conditions = [eq(lessons.tenantId, tenantId)];
193
+ if (!query?.includeArchived) {
194
+ conditions.push(isNull(lessons.archivedAt));
195
+ }
196
+ if (query?.agentId) {
197
+ conditions.push(eq(lessons.agentId, query.agentId));
198
+ }
199
+ if (query?.category) {
200
+ conditions.push(eq(lessons.category, query.category));
201
+ }
202
+ if (query?.importance) {
203
+ conditions.push(eq(lessons.importance, query.importance));
204
+ }
205
+ if (query?.search) {
206
+ const pattern = `%${escapeLike(query.search)}%`;
207
+ conditions.push(or(sql `${lessons.title} LIKE ${pattern} ESCAPE '\\'`, sql `${lessons.content} LIKE ${pattern} ESCAPE '\\'`));
208
+ }
209
+ const result = this.db
210
+ .select({ count: sql `count(*)` })
211
+ .from(lessons)
212
+ .where(and(...conditions))
213
+ .get();
214
+ return result?.count ?? 0;
215
+ }
216
+ }
217
+ //# sourceMappingURL=lesson-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lesson-store.js","sourceRoot":"","sources":["../../src/db/lesson-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAwB5C,qDAAqD;AACrD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAEhF,2DAA2D;AAC3D,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,mCAAmC;AACnC,SAAS,WAAW,CAAC,GAAgC;IACnD,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;QACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAA4B;QAC3D,UAAU,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAA8B,CAAC,CAAC,CAAC,QAAQ;QAChG,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,SAAS;QACjD,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;QAC7C,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,SAAS;QAC/C,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,WAAW;IACO;IAA7B,YAA6B,EAAY;QAAZ,OAAE,GAAF,EAAE,CAAU;IAAG,CAAC;IAE7C;;OAEG;IACH,MAAM,CAAC,QAAgB,EAAE,KAAwB;QAC/C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;QAExB,MAAM,GAAG,GAAG;YACV,EAAE;YACF,QAAQ;YACR,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,IAAI;YAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS;YACrC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;YAC5C,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,QAAQ;YACxC,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,IAAI;YAC9C,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,IAAI;YAC1C,WAAW,EAAE,CAAC;YACd,cAAc,EAAE,IAAI;YACpB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,UAAU,EAAE,IAAI;SACjB,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAE1C,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,QAAgB,EAAE,EAAU;QAC9B,OAAO,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE;YAChC,MAAM,GAAG,GAAG,EAAE;iBACX,MAAM,EAAE;iBACR,IAAI,CAAC,OAAO,CAAC;iBACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;iBAC9D,GAAG,EAAE,CAAC;YAET,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YAEtB,uEAAuE;YACvE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;iBACf,GAAG,CAAC;gBACH,WAAW,EAAE,GAAG,CAAA,GAAG,OAAO,CAAC,WAAW,MAAM;gBAC5C,cAAc,EAAE,GAAG;aACpB,CAAC;iBACD,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;iBAC9D,GAAG,EAAE,CAAC;YAET,OAAO,WAAW,CAAC;gBACjB,GAAG,GAAG;gBACN,WAAW,EAAE,GAAG,CAAC,WAAW,GAAG,CAAC;gBAChC,cAAc,EAAE,GAAG;aACpB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,QAAgB,EAAE,KAAmB;QACxC,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,CAAC;YAC5B,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,KAAK,EAAE,QAAQ,EAAE,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACtB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;YAChD,UAAU,CAAC,IAAI,CACb,EAAE,CACA,GAAG,CAAA,GAAG,OAAO,CAAC,KAAK,SAAS,OAAO,cAAc,EACjD,GAAG,CAAA,GAAG,OAAO,CAAC,OAAO,SAAS,OAAO,cAAc,CACnD,CACH,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC;QAElC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;aACzB,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,MAAM,CAAC;aACd,OAAO,CAAC,GAAG,CAAA,GAAG,OAAO,CAAC,SAAS,OAAO,CAAC;aACvC,GAAG,EAAE,CAAC;QAET,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAgB,EAAE,EAAU,EAAE,OAA0B;QAC7D,kBAAkB;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;aACrB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,SAAS,GAA4B,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QAE9D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;QACpE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1E,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;YAAE,SAAS,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC7E,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;YAAE,SAAS,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;QACnF,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1E,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE1F,IAAI,CAAC,EAAE;aACJ,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,SAAS,CAAC;aACd,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,oBAAoB;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE;aACpB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,OAAO,WAAW,CAAC,OAAQ,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,QAAgB,EAAE,EAAU;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;aACrB,MAAM,EAAE;aACR,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;QAET,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,EAAE;aACJ,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;aACxC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;aAC9D,GAAG,EAAE,CAAC;IACX,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAgB,EAAE,KAAmB;QACzC,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,CAAC;YAC5B,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,KAAK,EAAE,QAAQ,EAAE,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACtB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;YAChD,UAAU,CAAC,IAAI,CACb,EAAE,CACA,GAAG,CAAA,GAAG,OAAO,CAAC,KAAK,SAAS,OAAO,cAAc,EACjD,GAAG,CAAA,GAAG,OAAO,CAAC,OAAO,SAAS,OAAO,cAAc,CACnD,CACH,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;aACnB,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,UAAU,EAAE,CAAC;aACxC,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;aACzB,GAAG,EAAE,CAAC;QAET,OAAO,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAoGhD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB,CAoBA"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAwXhD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB,CAoBA"}