comisai 1.0.11 → 1.0.12

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 (247) hide show
  1. package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +1 -4
  2. package/node_modules/@comis/agent/package.json +1 -1
  3. package/node_modules/@comis/channels/package.json +1 -1
  4. package/node_modules/@comis/cli/package.json +1 -1
  5. package/node_modules/@comis/core/package.json +1 -1
  6. package/node_modules/@comis/daemon/package.json +1 -1
  7. package/node_modules/@comis/gateway/package.json +1 -1
  8. package/node_modules/@comis/infra/package.json +1 -1
  9. package/node_modules/@comis/memory/package.json +1 -1
  10. package/node_modules/@comis/scheduler/package.json +1 -1
  11. package/node_modules/@comis/shared/package.json +1 -1
  12. package/node_modules/@comis/skills/package.json +1 -1
  13. package/package.json +18 -18
  14. package/node_modules/@comis/core/dist/approval/approval-gate.test.d.ts +0 -1
  15. package/node_modules/@comis/core/dist/approval/approval-gate.test.js +0 -1003
  16. package/node_modules/@comis/core/dist/bootstrap.test.d.ts +0 -1
  17. package/node_modules/@comis/core/dist/bootstrap.test.js +0 -150
  18. package/node_modules/@comis/core/dist/config/backup.test.d.ts +0 -1
  19. package/node_modules/@comis/core/dist/config/backup.test.js +0 -160
  20. package/node_modules/@comis/core/dist/config/env-substitution.test.d.ts +0 -1
  21. package/node_modules/@comis/core/dist/config/env-substitution.test.js +0 -259
  22. package/node_modules/@comis/core/dist/config/field-metadata.test.d.ts +0 -1
  23. package/node_modules/@comis/core/dist/config/field-metadata.test.js +0 -72
  24. package/node_modules/@comis/core/dist/config/git-manager.test.d.ts +0 -1
  25. package/node_modules/@comis/core/dist/config/git-manager.test.js +0 -1042
  26. package/node_modules/@comis/core/dist/config/immutable-keys.test.d.ts +0 -1
  27. package/node_modules/@comis/core/dist/config/immutable-keys.test.js +0 -283
  28. package/node_modules/@comis/core/dist/config/include-resolver.test.d.ts +0 -1
  29. package/node_modules/@comis/core/dist/config/include-resolver.test.js +0 -292
  30. package/node_modules/@comis/core/dist/config/layered.test.d.ts +0 -1
  31. package/node_modules/@comis/core/dist/config/layered.test.js +0 -211
  32. package/node_modules/@comis/core/dist/config/loader.test.d.ts +0 -1
  33. package/node_modules/@comis/core/dist/config/loader.test.js +0 -300
  34. package/node_modules/@comis/core/dist/config/migrate.test.d.ts +0 -1
  35. package/node_modules/@comis/core/dist/config/migrate.test.js +0 -244
  36. package/node_modules/@comis/core/dist/config/partial-validator.test.d.ts +0 -1
  37. package/node_modules/@comis/core/dist/config/partial-validator.test.js +0 -98
  38. package/node_modules/@comis/core/dist/config/schema-agent-model.test.d.ts +0 -1
  39. package/node_modules/@comis/core/dist/config/schema-agent-model.test.js +0 -279
  40. package/node_modules/@comis/core/dist/config/schema-agent-session.test.d.ts +0 -1
  41. package/node_modules/@comis/core/dist/config/schema-agent-session.test.js +0 -242
  42. package/node_modules/@comis/core/dist/config/schema-agent.test.d.ts +0 -1
  43. package/node_modules/@comis/core/dist/config/schema-agent.test.js +0 -645
  44. package/node_modules/@comis/core/dist/config/schema-channel.test.d.ts +0 -1
  45. package/node_modules/@comis/core/dist/config/schema-channel.test.js +0 -341
  46. package/node_modules/@comis/core/dist/config/schema-coalescer.test.d.ts +0 -1
  47. package/node_modules/@comis/core/dist/config/schema-coalescer.test.js +0 -51
  48. package/node_modules/@comis/core/dist/config/schema-context-engine.test.d.ts +0 -1
  49. package/node_modules/@comis/core/dist/config/schema-context-engine.test.js +0 -797
  50. package/node_modules/@comis/core/dist/config/schema-context-guard.test.d.ts +0 -1
  51. package/node_modules/@comis/core/dist/config/schema-context-guard.test.js +0 -111
  52. package/node_modules/@comis/core/dist/config/schema-daemon.test.d.ts +0 -1
  53. package/node_modules/@comis/core/dist/config/schema-daemon.test.js +0 -107
  54. package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.d.ts +0 -1
  55. package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.js +0 -51
  56. package/node_modules/@comis/core/dist/config/schema-documentation.test.d.ts +0 -1
  57. package/node_modules/@comis/core/dist/config/schema-documentation.test.js +0 -63
  58. package/node_modules/@comis/core/dist/config/schema-gateway.test.d.ts +0 -1
  59. package/node_modules/@comis/core/dist/config/schema-gateway.test.js +0 -219
  60. package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.d.ts +0 -1
  61. package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.js +0 -41
  62. package/node_modules/@comis/core/dist/config/schema-integrations.test.d.ts +0 -1
  63. package/node_modules/@comis/core/dist/config/schema-integrations.test.js +0 -92
  64. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.d.ts +0 -1
  65. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.js +0 -61
  66. package/node_modules/@comis/core/dist/config/schema-misc.test.d.ts +0 -1
  67. package/node_modules/@comis/core/dist/config/schema-misc.test.js +0 -394
  68. package/node_modules/@comis/core/dist/config/schema-observability.test.d.ts +0 -1
  69. package/node_modules/@comis/core/dist/config/schema-observability.test.js +0 -76
  70. package/node_modules/@comis/core/dist/config/schema-providers.test.d.ts +0 -1
  71. package/node_modules/@comis/core/dist/config/schema-providers.test.js +0 -294
  72. package/node_modules/@comis/core/dist/config/schema-queue.test.d.ts +0 -1
  73. package/node_modules/@comis/core/dist/config/schema-queue.test.js +0 -234
  74. package/node_modules/@comis/core/dist/config/schema-response-prefix.test.d.ts +0 -1
  75. package/node_modules/@comis/core/dist/config/schema-response-prefix.test.js +0 -36
  76. package/node_modules/@comis/core/dist/config/schema-security.test.d.ts +0 -1
  77. package/node_modules/@comis/core/dist/config/schema-security.test.js +0 -54
  78. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.d.ts +0 -1
  79. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.js +0 -60
  80. package/node_modules/@comis/core/dist/config/schema-serializer.test.d.ts +0 -1
  81. package/node_modules/@comis/core/dist/config/schema-serializer.test.js +0 -73
  82. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.d.ts +0 -1
  83. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.js +0 -39
  84. package/node_modules/@comis/core/dist/context/context.test.d.ts +0 -1
  85. package/node_modules/@comis/core/dist/context/context.test.js +0 -276
  86. package/node_modules/@comis/core/dist/domain/agent-response.test.d.ts +0 -1
  87. package/node_modules/@comis/core/dist/domain/agent-response.test.js +0 -159
  88. package/node_modules/@comis/core/dist/domain/credential-mapping.test.d.ts +0 -1
  89. package/node_modules/@comis/core/dist/domain/credential-mapping.test.js +0 -135
  90. package/node_modules/@comis/core/dist/domain/delivery-origin.test.d.ts +0 -1
  91. package/node_modules/@comis/core/dist/domain/delivery-origin.test.js +0 -68
  92. package/node_modules/@comis/core/dist/domain/execution-graph.test.d.ts +0 -1
  93. package/node_modules/@comis/core/dist/domain/execution-graph.test.js +0 -441
  94. package/node_modules/@comis/core/dist/domain/memory-entry.test.d.ts +0 -1
  95. package/node_modules/@comis/core/dist/domain/memory-entry.test.js +0 -193
  96. package/node_modules/@comis/core/dist/domain/normalized-message.test.d.ts +0 -1
  97. package/node_modules/@comis/core/dist/domain/normalized-message.test.js +0 -255
  98. package/node_modules/@comis/core/dist/domain/session-key.test.d.ts +0 -1
  99. package/node_modules/@comis/core/dist/domain/session-key.test.js +0 -291
  100. package/node_modules/@comis/core/dist/domain/subagent-context-config.test.d.ts +0 -1
  101. package/node_modules/@comis/core/dist/domain/subagent-context-config.test.js +0 -131
  102. package/node_modules/@comis/core/dist/domain/subagent-context-types.test.d.ts +0 -1
  103. package/node_modules/@comis/core/dist/domain/subagent-context-types.test.js +0 -182
  104. package/node_modules/@comis/core/dist/event-bus/bus.test.d.ts +0 -1
  105. package/node_modules/@comis/core/dist/event-bus/bus.test.js +0 -152
  106. package/node_modules/@comis/core/dist/event-bus/events-agent.test.d.ts +0 -1
  107. package/node_modules/@comis/core/dist/event-bus/events-agent.test.js +0 -409
  108. package/node_modules/@comis/core/dist/event-bus/events-channel.test.d.ts +0 -1
  109. package/node_modules/@comis/core/dist/event-bus/events-channel.test.js +0 -240
  110. package/node_modules/@comis/core/dist/event-bus/events-infra.test.d.ts +0 -1
  111. package/node_modules/@comis/core/dist/event-bus/events-infra.test.js +0 -416
  112. package/node_modules/@comis/core/dist/event-bus/events-messaging.test.d.ts +0 -1
  113. package/node_modules/@comis/core/dist/event-bus/events-messaging.test.js +0 -433
  114. package/node_modules/@comis/core/dist/event-bus/events.test.d.ts +0 -1
  115. package/node_modules/@comis/core/dist/event-bus/events.test.js +0 -93
  116. package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.d.ts +0 -1
  117. package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.js +0 -29
  118. package/node_modules/@comis/core/dist/hooks/hook-runner.test.d.ts +0 -1
  119. package/node_modules/@comis/core/dist/hooks/hook-runner.test.js +0 -490
  120. package/node_modules/@comis/core/dist/hooks/hook-strategies.test.d.ts +0 -1
  121. package/node_modules/@comis/core/dist/hooks/hook-strategies.test.js +0 -209
  122. package/node_modules/@comis/core/dist/hooks/integration.test.d.ts +0 -1
  123. package/node_modules/@comis/core/dist/hooks/integration.test.js +0 -235
  124. package/node_modules/@comis/core/dist/hooks/plugin-registry.test.d.ts +0 -1
  125. package/node_modules/@comis/core/dist/hooks/plugin-registry.test.js +0 -470
  126. package/node_modules/@comis/core/dist/load-env.test.d.ts +0 -1
  127. package/node_modules/@comis/core/dist/load-env.test.js +0 -21
  128. package/node_modules/@comis/core/dist/security/action-classifier.test.d.ts +0 -1
  129. package/node_modules/@comis/core/dist/security/action-classifier.test.js +0 -298
  130. package/node_modules/@comis/core/dist/security/audit-aggregator.test.d.ts +0 -1
  131. package/node_modules/@comis/core/dist/security/audit-aggregator.test.js +0 -128
  132. package/node_modules/@comis/core/dist/security/audit.test.d.ts +0 -1
  133. package/node_modules/@comis/core/dist/security/audit.test.js +0 -154
  134. package/node_modules/@comis/core/dist/security/canary-token.test.d.ts +0 -1
  135. package/node_modules/@comis/core/dist/security/canary-token.test.js +0 -45
  136. package/node_modules/@comis/core/dist/security/config-redaction.test.d.ts +0 -1
  137. package/node_modules/@comis/core/dist/security/config-redaction.test.js +0 -107
  138. package/node_modules/@comis/core/dist/security/external-content.test.d.ts +0 -1
  139. package/node_modules/@comis/core/dist/security/external-content.test.js +0 -210
  140. package/node_modules/@comis/core/dist/security/injection-patterns.test.d.ts +0 -1
  141. package/node_modules/@comis/core/dist/security/injection-patterns.test.js +0 -213
  142. package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.d.ts +0 -1
  143. package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.js +0 -194
  144. package/node_modules/@comis/core/dist/security/input-guard.test.d.ts +0 -1
  145. package/node_modules/@comis/core/dist/security/input-guard.test.js +0 -215
  146. package/node_modules/@comis/core/dist/security/input-security-guard.test.d.ts +0 -1
  147. package/node_modules/@comis/core/dist/security/input-security-guard.test.js +0 -215
  148. package/node_modules/@comis/core/dist/security/input-validator.test.d.ts +0 -1
  149. package/node_modules/@comis/core/dist/security/input-validator.test.js +0 -133
  150. package/node_modules/@comis/core/dist/security/log-sanitizer.test.d.ts +0 -1
  151. package/node_modules/@comis/core/dist/security/log-sanitizer.test.js +0 -260
  152. package/node_modules/@comis/core/dist/security/memory-write-validator.test.d.ts +0 -1
  153. package/node_modules/@comis/core/dist/security/memory-write-validator.test.js +0 -62
  154. package/node_modules/@comis/core/dist/security/output-guard.test.d.ts +0 -1
  155. package/node_modules/@comis/core/dist/security/output-guard.test.js +0 -397
  156. package/node_modules/@comis/core/dist/security/safe-path.test.d.ts +0 -1
  157. package/node_modules/@comis/core/dist/security/safe-path.test.js +0 -95
  158. package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.d.ts +0 -1
  159. package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.js +0 -231
  160. package/node_modules/@comis/core/dist/security/secret-access.test.d.ts +0 -1
  161. package/node_modules/@comis/core/dist/security/secret-access.test.js +0 -41
  162. package/node_modules/@comis/core/dist/security/secret-crypto.test.d.ts +0 -1
  163. package/node_modules/@comis/core/dist/security/secret-crypto.test.js +0 -113
  164. package/node_modules/@comis/core/dist/security/secret-manager.test.d.ts +0 -1
  165. package/node_modules/@comis/core/dist/security/secret-manager.test.js +0 -394
  166. package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.d.ts +0 -1
  167. package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.js +0 -268
  168. package/node_modules/@comis/core/dist/security/secrets-audit.test.d.ts +0 -10
  169. package/node_modules/@comis/core/dist/security/secrets-audit.test.js +0 -295
  170. package/node_modules/@comis/core/dist/security/ssrf-guard.test.d.ts +0 -1
  171. package/node_modules/@comis/core/dist/security/ssrf-guard.test.js +0 -127
  172. package/node_modules/@comis/core/dist/security/token-generator.test.d.ts +0 -1
  173. package/node_modules/@comis/core/dist/security/token-generator.test.js +0 -35
  174. package/node_modules/@comis/core/dist/tool-metadata.test.d.ts +0 -1
  175. package/node_modules/@comis/core/dist/tool-metadata.test.js +0 -112
  176. package/node_modules/@comis/memory/dist/compaction.test.d.ts +0 -1
  177. package/node_modules/@comis/memory/dist/compaction.test.js +0 -298
  178. package/node_modules/@comis/memory/dist/context-schema.test.d.ts +0 -1
  179. package/node_modules/@comis/memory/dist/context-schema.test.js +0 -246
  180. package/node_modules/@comis/memory/dist/context-store.test.d.ts +0 -1
  181. package/node_modules/@comis/memory/dist/context-store.test.js +0 -708
  182. package/node_modules/@comis/memory/dist/credential-mapping-schema.test.d.ts +0 -7
  183. package/node_modules/@comis/memory/dist/credential-mapping-schema.test.js +0 -73
  184. package/node_modules/@comis/memory/dist/credential-mapping-store.test.d.ts +0 -8
  185. package/node_modules/@comis/memory/dist/credential-mapping-store.test.js +0 -340
  186. package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.d.ts +0 -1
  187. package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.js +0 -165
  188. package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.d.ts +0 -1
  189. package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.js +0 -263
  190. package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.d.ts +0 -1
  191. package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.js +0 -202
  192. package/node_modules/@comis/memory/dist/embedding-cache-lru.test.d.ts +0 -1
  193. package/node_modules/@comis/memory/dist/embedding-cache-lru.test.js +0 -241
  194. package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.d.ts +0 -8
  195. package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.js +0 -678
  196. package/node_modules/@comis/memory/dist/embedding-cache.test.d.ts +0 -1
  197. package/node_modules/@comis/memory/dist/embedding-cache.test.js +0 -213
  198. package/node_modules/@comis/memory/dist/embedding-fingerprint.test.d.ts +0 -1
  199. package/node_modules/@comis/memory/dist/embedding-fingerprint.test.js +0 -87
  200. package/node_modules/@comis/memory/dist/embedding-hash.test.d.ts +0 -1
  201. package/node_modules/@comis/memory/dist/embedding-hash.test.js +0 -31
  202. package/node_modules/@comis/memory/dist/embedding-integration.test.d.ts +0 -8
  203. package/node_modules/@comis/memory/dist/embedding-integration.test.js +0 -232
  204. package/node_modules/@comis/memory/dist/embedding-provider-factory.test.d.ts +0 -1
  205. package/node_modules/@comis/memory/dist/embedding-provider-factory.test.js +0 -176
  206. package/node_modules/@comis/memory/dist/embedding-provider-local.test.d.ts +0 -8
  207. package/node_modules/@comis/memory/dist/embedding-provider-local.test.js +0 -76
  208. package/node_modules/@comis/memory/dist/embedding-provider-openai.test.d.ts +0 -8
  209. package/node_modules/@comis/memory/dist/embedding-provider-openai.test.js +0 -100
  210. package/node_modules/@comis/memory/dist/embedding-queue.test.d.ts +0 -1
  211. package/node_modules/@comis/memory/dist/embedding-queue.test.js +0 -236
  212. package/node_modules/@comis/memory/dist/hybrid-search.test.d.ts +0 -1
  213. package/node_modules/@comis/memory/dist/hybrid-search.test.js +0 -476
  214. package/node_modules/@comis/memory/dist/identity-link-store.test.d.ts +0 -1
  215. package/node_modules/@comis/memory/dist/identity-link-store.test.js +0 -88
  216. package/node_modules/@comis/memory/dist/memory-api.test.d.ts +0 -1
  217. package/node_modules/@comis/memory/dist/memory-api.test.js +0 -495
  218. package/node_modules/@comis/memory/dist/memory-concurrency.test.d.ts +0 -20
  219. package/node_modules/@comis/memory/dist/memory-concurrency.test.js +0 -222
  220. package/node_modules/@comis/memory/dist/named-graph-store.test.d.ts +0 -1
  221. package/node_modules/@comis/memory/dist/named-graph-store.test.js +0 -227
  222. package/node_modules/@comis/memory/dist/observability-store.test.d.ts +0 -1
  223. package/node_modules/@comis/memory/dist/observability-store.test.js +0 -704
  224. package/node_modules/@comis/memory/dist/row-mapper.test.d.ts +0 -1
  225. package/node_modules/@comis/memory/dist/row-mapper.test.js +0 -409
  226. package/node_modules/@comis/memory/dist/schema.test.d.ts +0 -1
  227. package/node_modules/@comis/memory/dist/schema.test.js +0 -240
  228. package/node_modules/@comis/memory/dist/secret-store-schema.test.d.ts +0 -7
  229. package/node_modules/@comis/memory/dist/secret-store-schema.test.js +0 -90
  230. package/node_modules/@comis/memory/dist/session-store.test.d.ts +0 -1
  231. package/node_modules/@comis/memory/dist/session-store.test.js +0 -262
  232. package/node_modules/@comis/memory/dist/setup-secrets.test.d.ts +0 -1
  233. package/node_modules/@comis/memory/dist/setup-secrets.test.js +0 -140
  234. package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.d.ts +0 -1
  235. package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.js +0 -888
  236. package/node_modules/@comis/memory/dist/sqlite-secret-store.test.d.ts +0 -8
  237. package/node_modules/@comis/memory/dist/sqlite-secret-store.test.js +0 -245
  238. package/node_modules/@comis/shared/dist/abort.test.d.ts +0 -1
  239. package/node_modules/@comis/shared/dist/abort.test.js +0 -71
  240. package/node_modules/@comis/shared/dist/result.test.d.ts +0 -1
  241. package/node_modules/@comis/shared/dist/result.test.js +0 -178
  242. package/node_modules/@comis/shared/dist/suppress-error.test.d.ts +0 -1
  243. package/node_modules/@comis/shared/dist/suppress-error.test.js +0 -50
  244. package/node_modules/@comis/shared/dist/timeout.test.d.ts +0 -1
  245. package/node_modules/@comis/shared/dist/timeout.test.js +0 -75
  246. package/node_modules/@comis/shared/dist/ttl-cache.test.d.ts +0 -1
  247. package/node_modules/@comis/shared/dist/ttl-cache.test.js +0 -81
@@ -1,298 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { createCompactionService } from "./compaction.js";
3
- import { createSessionStore } from "./session-store.js";
4
- import { SqliteMemoryAdapter } from "./sqlite-memory-adapter.js";
5
- // ── Helpers ────────────────────────────────────────────────────────────
6
- const testConfig = {
7
- dbPath: ":memory:",
8
- walMode: false,
9
- embeddingModel: "test-model",
10
- embeddingDimensions: 4,
11
- compaction: { enabled: false, threshold: 1000, targetSize: 500 },
12
- retention: { maxAgeDays: 0, maxEntries: 0 },
13
- };
14
- const testKey = {
15
- tenantId: "default",
16
- userId: "user-1",
17
- channelId: "telegram",
18
- };
19
- const testKey2 = {
20
- tenantId: "default",
21
- userId: "user-2",
22
- channelId: "discord",
23
- };
24
- /** Simple summarizer that just concatenates messages and returns fixed facts. */
25
- const mockSummarizer = async (messages) => ({
26
- summary: `Summary of ${messages.length} messages`,
27
- facts: ["fact-1", "fact-2"],
28
- });
29
- /** Summarizer that returns no facts. */
30
- const noFactsSummarizer = async (messages) => ({
31
- summary: `Summary of ${messages.length} messages`,
32
- facts: [],
33
- });
34
- /** Summarizer that tracks how many times it was called. */
35
- function trackingSummarizer() {
36
- const fn = async (messages) => {
37
- fn.callCount++;
38
- return {
39
- summary: `Summary of ${messages.length} messages`,
40
- facts: ["tracked-fact"],
41
- };
42
- };
43
- fn.callCount = 0;
44
- return fn;
45
- }
46
- // ── Test Suite ─────────────────────────────────────────────────────────
47
- describe("createCompactionService", () => {
48
- let db;
49
- let adapter;
50
- let sessionStore;
51
- let compactionService;
52
- beforeEach(() => {
53
- // Use the adapter's internal DB for everything (single :memory: connection)
54
- adapter = new SqliteMemoryAdapter(testConfig);
55
- db = adapter.getDb();
56
- sessionStore = createSessionStore(db);
57
- compactionService = createCompactionService(db, sessionStore, adapter, mockSummarizer);
58
- });
59
- afterEach(() => {
60
- adapter.close();
61
- });
62
- // ── Stale session detection ──────────────────────────────────────
63
- it("compacts sessions idle for longer than minIdleMs", async () => {
64
- // Save a session and manually set its updatedAt to the past
65
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
66
- // Set updatedAt to 5 hours ago
67
- const fiveHoursAgo = Date.now() - 5 * 60 * 60 * 1000;
68
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(fiveHoursAgo, "default:user-1:telegram");
69
- const result = await compactionService.compact({ minIdleMs: 4 * 60 * 60 * 1000 });
70
- expect(result.sessionsCompacted).toBe(1);
71
- expect(result.compactedKeys).toContain("default:user-1:telegram");
72
- });
73
- it("does NOT compact active sessions (within idle threshold)", async () => {
74
- // Save a session that was recently updated (within minIdleMs)
75
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
76
- const result = await compactionService.compact({ minIdleMs: 4 * 60 * 60 * 1000 });
77
- expect(result.sessionsCompacted).toBe(0);
78
- expect(result.compactedKeys).toHaveLength(0);
79
- });
80
- it("skips sessions with no messages", async () => {
81
- sessionStore.save(testKey, []);
82
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
83
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
84
- const result = await compactionService.compact({ minIdleMs: 1000 });
85
- expect(result.sessionsCompacted).toBe(0);
86
- });
87
- // ── Episodic memory creation ─────────────────────────────────────
88
- it("creates episodic memory from stale session summary", async () => {
89
- sessionStore.save(testKey, [
90
- { role: "user", content: "hello" },
91
- { role: "assistant", content: "hi" },
92
- ]);
93
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
94
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
95
- const result = await compactionService.compact({ minIdleMs: 1000 });
96
- expect(result.episodicCreated).toBe(1);
97
- // Verify the episodic memory is in the database
98
- const episodic = db
99
- .prepare("SELECT * FROM memories WHERE memory_type = 'episodic'")
100
- .all();
101
- expect(episodic).toHaveLength(1);
102
- expect(episodic[0].content).toBe("Summary of 2 messages");
103
- expect(episodic[0].source_who).toBe("compaction");
104
- });
105
- // ── Semantic fact extraction ─────────────────────────────────────
106
- it("creates semantic memories from extracted facts", async () => {
107
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
108
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
109
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
110
- const result = await compactionService.compact({ minIdleMs: 1000 });
111
- expect(result.factsExtracted).toBe(2);
112
- const facts = db
113
- .prepare("SELECT content FROM memories WHERE memory_type = 'semantic' AND tags LIKE '%fact%'")
114
- .all();
115
- expect(facts).toHaveLength(2);
116
- expect(facts.map((f) => f.content)).toContain("fact-1");
117
- expect(facts.map((f) => f.content)).toContain("fact-2");
118
- });
119
- it("handles summarizer returning no facts", async () => {
120
- const service = createCompactionService(db, sessionStore, adapter, noFactsSummarizer);
121
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
122
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
123
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
124
- const result = await service.compact({ minIdleMs: 1000 });
125
- expect(result.episodicCreated).toBe(1);
126
- expect(result.factsExtracted).toBe(0);
127
- });
128
- // ── Archive creation ─────────────────────────────────────────────
129
- it("archives original messages before deletion", async () => {
130
- const messages = [
131
- { role: "user", content: "hello" },
132
- { role: "assistant", content: "hi there" },
133
- ];
134
- sessionStore.save(testKey, messages);
135
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
136
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
137
- await compactionService.compact({ minIdleMs: 1000 });
138
- const archives = db.prepare("SELECT * FROM archives").all();
139
- expect(archives).toHaveLength(1);
140
- expect(archives[0].session_key).toBe("default:user-1:telegram");
141
- expect(JSON.parse(archives[0].messages)).toEqual(messages);
142
- expect(archives[0].expires_at).toBeGreaterThan(archives[0].archived_at);
143
- });
144
- it("archives respect configurable retention period", async () => {
145
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
146
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
147
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
148
- const customRetention = 3 * 24 * 60 * 60 * 1000; // 3 days
149
- await compactionService.compact({
150
- minIdleMs: 1000,
151
- archiveRetentionMs: customRetention,
152
- });
153
- const archive = db.prepare("SELECT * FROM archives").get();
154
- const actualRetention = archive.expires_at - archive.archived_at;
155
- expect(actualRetention).toBe(customRetention);
156
- });
157
- // ── Session deletion ─────────────────────────────────────────────
158
- it("deletes the session after compaction", async () => {
159
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
160
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
161
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
162
- await compactionService.compact({ minIdleMs: 1000 });
163
- const session = sessionStore.load(testKey);
164
- expect(session).toBeUndefined();
165
- });
166
- // ── Multiple sessions ────────────────────────────────────────────
167
- it("compacts multiple stale sessions in one run", async () => {
168
- sessionStore.save(testKey, [{ role: "user", content: "hello from user 1" }]);
169
- sessionStore.save(testKey2, [{ role: "user", content: "hello from user 2" }]);
170
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
171
- db.prepare("UPDATE sessions SET updated_at = ?").run(longAgo);
172
- const result = await compactionService.compact({ minIdleMs: 1000 });
173
- expect(result.sessionsCompacted).toBe(2);
174
- expect(result.episodicCreated).toBe(2);
175
- expect(result.factsExtracted).toBe(4); // 2 facts per session
176
- });
177
- it("only compacts stale sessions, leaves active ones alone", async () => {
178
- sessionStore.save(testKey, [{ role: "user", content: "stale" }]);
179
- sessionStore.save(testKey2, [{ role: "user", content: "active" }]);
180
- // Only make testKey stale
181
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
182
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
183
- const result = await compactionService.compact({ minIdleMs: 1000 });
184
- expect(result.sessionsCompacted).toBe(1);
185
- expect(result.compactedKeys).toContain("default:user-1:telegram");
186
- // Active session should still exist
187
- const activeSession = sessionStore.load(testKey2);
188
- expect(activeSession).toBeDefined();
189
- });
190
- // ── Pluggable summarizer ─────────────────────────────────────────
191
- it("calls the pluggable summarizer with session messages", async () => {
192
- const tracker = trackingSummarizer();
193
- const service = createCompactionService(db, sessionStore, adapter, tracker);
194
- const messages = [
195
- { role: "user", content: "hello" },
196
- { role: "assistant", content: "hi" },
197
- { role: "user", content: "bye" },
198
- ];
199
- sessionStore.save(testKey, messages);
200
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
201
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
202
- await service.compact({ minIdleMs: 1000 });
203
- expect(tracker.callCount).toBe(1);
204
- });
205
- // ── Tenant scoping ──────────────────────────────────────────────
206
- it("respects tenantId option for scoped compaction", async () => {
207
- const key1 = { tenantId: "tenant-a", userId: "u1", channelId: "ch1" };
208
- const key2 = { tenantId: "tenant-b", userId: "u2", channelId: "ch2" };
209
- sessionStore.save(key1, [{ role: "user", content: "hello" }]);
210
- sessionStore.save(key2, [{ role: "user", content: "world" }]);
211
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
212
- db.prepare("UPDATE sessions SET updated_at = ?").run(longAgo);
213
- const result = await compactionService.compact({
214
- minIdleMs: 1000,
215
- tenantId: "tenant-a",
216
- });
217
- expect(result.sessionsCompacted).toBe(1);
218
- expect(result.compactedKeys[0]).toContain("tenant-a");
219
- // tenant-b session should still exist
220
- const tenantBSession = sessionStore.load(key2);
221
- expect(tenantBSession).toBeDefined();
222
- });
223
- // ── purgeArchives ────────────────────────────────────────────────
224
- it("purgeArchives removes expired archives", async () => {
225
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
226
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
227
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
228
- // Compact with very short retention so archive expires immediately
229
- await compactionService.compact({
230
- minIdleMs: 1000,
231
- archiveRetentionMs: 1, // 1ms retention
232
- });
233
- // Verify archive exists
234
- const beforePurge = db.prepare("SELECT COUNT(*) as cnt FROM archives").get();
235
- expect(beforePurge.cnt).toBe(1);
236
- // Wait a tick to ensure expiry
237
- await new Promise((r) => setTimeout(r, 10));
238
- const purged = compactionService.purgeArchives();
239
- expect(purged).toBe(1);
240
- const afterPurge = db.prepare("SELECT COUNT(*) as cnt FROM archives").get();
241
- expect(afterPurge.cnt).toBe(0);
242
- });
243
- it("purgeArchives does not remove non-expired archives", async () => {
244
- sessionStore.save(testKey, [{ role: "user", content: "hello" }]);
245
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
246
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
247
- // Compact with long retention
248
- await compactionService.compact({
249
- minIdleMs: 1000,
250
- archiveRetentionMs: 7 * 24 * 60 * 60 * 1000, // 7 days
251
- });
252
- const purged = compactionService.purgeArchives();
253
- expect(purged).toBe(0);
254
- const archiveCount = db.prepare("SELECT COUNT(*) as cnt FROM archives").get();
255
- expect(archiveCount.cnt).toBe(1);
256
- });
257
- it("purgeArchives returns 0 when no archives exist", () => {
258
- const purged = compactionService.purgeArchives();
259
- expect(purged).toBe(0);
260
- });
261
- // ── Empty session edge case ────────────────────────────────────
262
- it("handles compaction with empty sessions (0 messages) without calling summarizer", async () => {
263
- // Create a tracking summarizer that should never be called
264
- const tracker = trackingSummarizer();
265
- const service = createCompactionService(db, sessionStore, adapter, tracker);
266
- // Save a session with 0 messages and make it stale
267
- sessionStore.save(testKey, []);
268
- const longAgo = Date.now() - 10 * 60 * 60 * 1000;
269
- db.prepare("UPDATE sessions SET updated_at = ? WHERE session_key = ?").run(longAgo, "default:user-1:telegram");
270
- const result = await service.compact({ minIdleMs: 1000 });
271
- // Verify compaction completed successfully (no crash)
272
- expect(result.sessionsCompacted).toBe(0);
273
- expect(result.episodicCreated).toBe(0);
274
- expect(result.factsExtracted).toBe(0);
275
- expect(result.compactedKeys).toHaveLength(0);
276
- // Summarizer should never have been called for an empty session
277
- expect(tracker.callCount).toBe(0);
278
- // No episodic or semantic memories should have been created
279
- const episodic = db
280
- .prepare("SELECT * FROM memories WHERE memory_type = 'episodic'")
281
- .all();
282
- expect(episodic).toHaveLength(0);
283
- const semantic = db
284
- .prepare("SELECT * FROM memories WHERE memory_type = 'semantic' AND tags LIKE '%fact%'")
285
- .all();
286
- expect(semantic).toHaveLength(0);
287
- });
288
- // ── Return value ─────────────────────────────────────────────────
289
- it("returns empty result when no sessions are stale", async () => {
290
- const result = await compactionService.compact({ minIdleMs: 1000 });
291
- expect(result).toEqual({
292
- sessionsCompacted: 0,
293
- episodicCreated: 0,
294
- factsExtracted: 0,
295
- compactedKeys: [],
296
- });
297
- });
298
- });
@@ -1,246 +0,0 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import Database from "better-sqlite3";
3
- import { initContextSchema } from "./context-schema.js";
4
- /** Open an in-memory database with foreign keys enabled and schema initialized. */
5
- function createTestDb() {
6
- const db = new Database(":memory:");
7
- db.pragma("foreign_keys = ON");
8
- initContextSchema(db);
9
- return db;
10
- }
11
- /** Insert a minimal conversation row and return its id. */
12
- function insertConversation(db, id = "conv-1") {
13
- db.prepare(`INSERT INTO ctx_conversations (conversation_id, tenant_id, agent_id, session_key)
14
- VALUES (?, 'tenant-1', 'agent-1', ?)`).run(id, `session-${id}`);
15
- return id;
16
- }
17
- /** Insert a minimal message row and return its message_id. */
18
- function insertMessage(db, conversationId, seq, role = "user", content = "hello") {
19
- const info = db
20
- .prepare(`INSERT INTO ctx_messages (conversation_id, seq, role, content, content_hash, token_count)
21
- VALUES (?, ?, ?, ?, 'hash-' || ?, 1)`)
22
- .run(conversationId, seq, role, content, seq);
23
- return Number(info.lastInsertRowid);
24
- }
25
- /** Insert a minimal summary row and return its summary_id. */
26
- function insertSummary(db, summaryId, conversationId, kind = "leaf") {
27
- db.prepare(`INSERT INTO ctx_summaries (summary_id, conversation_id, kind, content, token_count)
28
- VALUES (?, ?, ?, 'summary content', 10)`).run(summaryId, conversationId, kind);
29
- return summaryId;
30
- }
31
- describe("initContextSchema", () => {
32
- let db;
33
- beforeEach(() => {
34
- db = createTestDb();
35
- });
36
- // --- Group 1: table creation ---
37
- describe("table creation", () => {
38
- it("creates all 9 regular ctx_ tables", () => {
39
- // FTS5 creates shadow tables (e.g. ctx_messages_fts_content, _data, etc.)
40
- // Filter them out by excluding names containing '_fts_' and the FTS5 virtual tables themselves.
41
- const tables = db
42
- .prepare(`SELECT name FROM sqlite_master
43
- WHERE type='table' AND name LIKE 'ctx_%'
44
- AND name NOT LIKE '%_fts%'
45
- ORDER BY name`)
46
- .all();
47
- const names = tables.map((r) => r.name);
48
- expect(names).toEqual([
49
- "ctx_context_items",
50
- "ctx_conversations",
51
- "ctx_expansion_grants",
52
- "ctx_large_files",
53
- "ctx_message_parts",
54
- "ctx_messages",
55
- "ctx_summaries",
56
- "ctx_summary_messages",
57
- "ctx_summary_parents",
58
- ]);
59
- });
60
- it("creates 2 FTS5 virtual tables", () => {
61
- const fts = db
62
- .prepare(`SELECT name FROM sqlite_master
63
- WHERE sql LIKE '%fts5%' AND name LIKE 'ctx_%'
64
- ORDER BY name`)
65
- .all();
66
- const names = fts.map((r) => r.name);
67
- expect(names).toEqual(["ctx_messages_fts", "ctx_summaries_fts"]);
68
- });
69
- it("creates all expected indexes", () => {
70
- const indexes = db
71
- .prepare(`SELECT name FROM sqlite_master
72
- WHERE type='index' AND name LIKE 'ctx_%'
73
- ORDER BY name`)
74
- .all();
75
- const names = indexes.map((r) => r.name);
76
- expect(names).toContain("ctx_messages_conv_seq");
77
- expect(names).toContain("ctx_messages_hash");
78
- expect(names).toContain("ctx_summaries_conv");
79
- expect(names).toContain("ctx_summaries_depth");
80
- expect(names).toContain("ctx_large_files_conv");
81
- expect(names).toContain("ctx_large_files_hash");
82
- expect(names).toContain("ctx_grants_session");
83
- expect(names).toContain("ctx_grants_expires");
84
- });
85
- });
86
- // --- Group 2: idempotency ---
87
- describe("idempotency", () => {
88
- it("calling initContextSchema twice produces no errors", () => {
89
- // db already had initContextSchema called in createTestDb
90
- expect(() => initContextSchema(db)).not.toThrow();
91
- // Verify tables still exist and are usable
92
- const convId = insertConversation(db);
93
- insertMessage(db, convId, 1);
94
- const count = db
95
- .prepare("SELECT COUNT(*) as c FROM ctx_messages")
96
- .get();
97
- expect(count.c).toBe(1);
98
- });
99
- });
100
- // --- Group 3: constraints ---
101
- describe("constraints", () => {
102
- it("ctx_messages role CHECK constraint rejects invalid roles", () => {
103
- const convId = insertConversation(db);
104
- expect(() => {
105
- db.prepare(`INSERT INTO ctx_messages (conversation_id, seq, role, content, content_hash, token_count)
106
- VALUES (?, 1, 'invalid', 'test', 'hash', 1)`).run(convId);
107
- }).toThrow();
108
- });
109
- it("ctx_messages role CHECK allows valid roles", () => {
110
- const convId = insertConversation(db);
111
- for (const [i, role] of ["system", "user", "assistant", "tool"].entries()) {
112
- expect(() => {
113
- db.prepare(`INSERT INTO ctx_messages (conversation_id, seq, role, content, content_hash, token_count)
114
- VALUES (?, ?, ?, 'content', 'hash-' || ?, 1)`).run(convId, i + 1, role, i);
115
- }).not.toThrow();
116
- }
117
- });
118
- it("ctx_messages UNIQUE(conversation_id, seq) prevents duplicates", () => {
119
- const convId = insertConversation(db);
120
- insertMessage(db, convId, 1);
121
- expect(() => insertMessage(db, convId, 1)).toThrow();
122
- });
123
- it("ctx_summaries kind CHECK constraint rejects invalid kinds", () => {
124
- const convId = insertConversation(db);
125
- expect(() => {
126
- db.prepare(`INSERT INTO ctx_summaries (summary_id, conversation_id, kind, content, token_count)
127
- VALUES ('s1', ?, 'invalid', 'content', 10)`).run(convId);
128
- }).toThrow();
129
- });
130
- it("ctx_context_items CHECK enforces item_type exclusivity", () => {
131
- const convId = insertConversation(db);
132
- const msgId = insertMessage(db, convId, 1);
133
- const sumId = insertSummary(db, "sum-1", convId);
134
- // item_type='message' with summary_id set -- should fail
135
- expect(() => {
136
- db.prepare(`INSERT INTO ctx_context_items (conversation_id, ordinal, item_type, message_id, summary_id)
137
- VALUES (?, 1, 'message', ?, ?)`).run(convId, msgId, sumId);
138
- }).toThrow();
139
- // item_type='summary' with message_id set -- should fail
140
- expect(() => {
141
- db.prepare(`INSERT INTO ctx_context_items (conversation_id, ordinal, item_type, message_id, summary_id)
142
- VALUES (?, 2, 'summary', ?, ?)`).run(convId, msgId, sumId);
143
- }).toThrow();
144
- // Valid: message item with only message_id
145
- expect(() => {
146
- db.prepare(`INSERT INTO ctx_context_items (conversation_id, ordinal, item_type, message_id, summary_id)
147
- VALUES (?, 1, 'message', ?, NULL)`).run(convId, msgId);
148
- }).not.toThrow();
149
- // Valid: summary item with only summary_id
150
- expect(() => {
151
- db.prepare(`INSERT INTO ctx_context_items (conversation_id, ordinal, item_type, message_id, summary_id)
152
- VALUES (?, 2, 'summary', NULL, ?)`).run(convId, sumId);
153
- }).not.toThrow();
154
- });
155
- it("ctx_messages AUTOINCREMENT prevents rowid reuse", () => {
156
- const convId = insertConversation(db);
157
- insertMessage(db, convId, 1); // message_id = 1
158
- insertMessage(db, convId, 2); // message_id = 2
159
- const thirdId = insertMessage(db, convId, 3); // message_id = 3
160
- expect(thirdId).toBe(3);
161
- // Delete the last message
162
- db.prepare("DELETE FROM ctx_messages WHERE message_id = ?").run(thirdId);
163
- // Insert a new message -- must get id=4, not 3 (AUTOINCREMENT)
164
- const fourthId = insertMessage(db, convId, 3, "user", "new content");
165
- expect(fourthId).toBe(4);
166
- });
167
- });
168
- // --- Group 4: foreign keys and cascades ---
169
- describe("foreign keys and cascades", () => {
170
- it("deleting a conversation cascades to messages", () => {
171
- const convId = insertConversation(db);
172
- insertMessage(db, convId, 1);
173
- insertMessage(db, convId, 2);
174
- db.prepare("DELETE FROM ctx_conversations WHERE conversation_id = ?").run(convId);
175
- const count = db
176
- .prepare("SELECT COUNT(*) as c FROM ctx_messages")
177
- .get();
178
- expect(count.c).toBe(0);
179
- });
180
- it("deleting a conversation cascades to summaries and context_items", () => {
181
- const convId = insertConversation(db);
182
- const msgId = insertMessage(db, convId, 1);
183
- insertSummary(db, "sum-1", convId);
184
- db.prepare(`INSERT INTO ctx_context_items (conversation_id, ordinal, item_type, message_id, summary_id)
185
- VALUES (?, 1, 'message', ?, NULL)`).run(convId, msgId);
186
- db.prepare("DELETE FROM ctx_conversations WHERE conversation_id = ?").run(convId);
187
- const sumCount = db
188
- .prepare("SELECT COUNT(*) as c FROM ctx_summaries")
189
- .get();
190
- const itemCount = db
191
- .prepare("SELECT COUNT(*) as c FROM ctx_context_items")
192
- .get();
193
- expect(sumCount.c).toBe(0);
194
- expect(itemCount.c).toBe(0);
195
- });
196
- it("cannot delete a message referenced by ctx_summary_messages (RESTRICT)", () => {
197
- const convId = insertConversation(db);
198
- const msgId = insertMessage(db, convId, 1);
199
- insertSummary(db, "sum-1", convId);
200
- db.prepare(`INSERT INTO ctx_summary_messages (summary_id, message_id, ordinal)
201
- VALUES ('sum-1', ?, 0)`).run(msgId);
202
- expect(() => {
203
- db.prepare("DELETE FROM ctx_messages WHERE message_id = ?").run(msgId);
204
- }).toThrow();
205
- });
206
- it("cannot delete a parent summary referenced by ctx_summary_parents (RESTRICT)", () => {
207
- const convId = insertConversation(db);
208
- const parentId = insertSummary(db, "sum-parent", convId, "leaf");
209
- const childId = insertSummary(db, "sum-child", convId, "condensed");
210
- db.prepare(`INSERT INTO ctx_summary_parents (summary_id, parent_summary_id, ordinal)
211
- VALUES (?, ?, 0)`).run(childId, parentId);
212
- expect(() => {
213
- db.prepare("DELETE FROM ctx_summaries WHERE summary_id = ?").run(parentId);
214
- }).toThrow();
215
- });
216
- });
217
- // --- Group 5: FTS5 standalone tables ---
218
- describe("FTS5 standalone tables", () => {
219
- it("can insert and query ctx_messages_fts", () => {
220
- db.prepare("INSERT INTO ctx_messages_fts(rowid, content) VALUES (1, 'the quick brown fox')").run();
221
- const results = db
222
- .prepare("SELECT rowid, content FROM ctx_messages_fts WHERE ctx_messages_fts MATCH 'brown'")
223
- .all();
224
- expect(results).toHaveLength(1);
225
- expect(results[0].rowid).toBe(1);
226
- expect(results[0].content).toBe("the quick brown fox");
227
- });
228
- it("can insert and query ctx_summaries_fts", () => {
229
- db.prepare("INSERT INTO ctx_summaries_fts(summary_id, content) VALUES ('sum-1', 'summary of important events')").run();
230
- const results = db
231
- .prepare("SELECT summary_id, content FROM ctx_summaries_fts WHERE content MATCH 'important'")
232
- .all();
233
- expect(results).toHaveLength(1);
234
- expect(results[0].summary_id).toBe("sum-1");
235
- expect(results[0].content).toBe("summary of important events");
236
- });
237
- it("FTS5 uses porter tokenizer", () => {
238
- // "running" should stem to "run" via porter tokenizer
239
- db.prepare("INSERT INTO ctx_messages_fts(rowid, content) VALUES (1, 'running quickly')").run();
240
- const results = db
241
- .prepare("SELECT rowid FROM ctx_messages_fts WHERE ctx_messages_fts MATCH 'run'")
242
- .all();
243
- expect(results).toHaveLength(1);
244
- });
245
- });
246
- });