comisai 1.0.11 → 1.0.13

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 (255) hide show
  1. package/node_modules/@comis/agent/dist/model/operation-model-defaults.js +1 -0
  2. package/node_modules/@comis/agent/dist/session/comis-session-manager.js +9 -9
  3. package/node_modules/@comis/agent/package.json +1 -1
  4. package/node_modules/@comis/channels/package.json +1 -1
  5. package/node_modules/@comis/cli/package.json +1 -1
  6. package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +2 -0
  7. package/node_modules/@comis/core/package.json +1 -1
  8. package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +12 -1
  9. package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +1 -0
  10. package/node_modules/@comis/daemon/dist/wiring/setup-schedulers.js +1 -0
  11. package/node_modules/@comis/daemon/package.json +1 -1
  12. package/node_modules/@comis/gateway/package.json +1 -1
  13. package/node_modules/@comis/infra/package.json +1 -1
  14. package/node_modules/@comis/memory/package.json +1 -1
  15. package/node_modules/@comis/scheduler/dist/cron/cron-types.d.ts +6 -0
  16. package/node_modules/@comis/scheduler/dist/cron/cron-types.js +2 -0
  17. package/node_modules/@comis/scheduler/package.json +1 -1
  18. package/node_modules/@comis/shared/package.json +1 -1
  19. package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +1 -1
  20. package/node_modules/@comis/skills/package.json +1 -1
  21. package/package.json +18 -18
  22. package/node_modules/@comis/core/dist/approval/approval-gate.test.d.ts +0 -1
  23. package/node_modules/@comis/core/dist/approval/approval-gate.test.js +0 -1003
  24. package/node_modules/@comis/core/dist/bootstrap.test.d.ts +0 -1
  25. package/node_modules/@comis/core/dist/bootstrap.test.js +0 -150
  26. package/node_modules/@comis/core/dist/config/backup.test.d.ts +0 -1
  27. package/node_modules/@comis/core/dist/config/backup.test.js +0 -160
  28. package/node_modules/@comis/core/dist/config/env-substitution.test.d.ts +0 -1
  29. package/node_modules/@comis/core/dist/config/env-substitution.test.js +0 -259
  30. package/node_modules/@comis/core/dist/config/field-metadata.test.d.ts +0 -1
  31. package/node_modules/@comis/core/dist/config/field-metadata.test.js +0 -72
  32. package/node_modules/@comis/core/dist/config/git-manager.test.d.ts +0 -1
  33. package/node_modules/@comis/core/dist/config/git-manager.test.js +0 -1042
  34. package/node_modules/@comis/core/dist/config/immutable-keys.test.d.ts +0 -1
  35. package/node_modules/@comis/core/dist/config/immutable-keys.test.js +0 -283
  36. package/node_modules/@comis/core/dist/config/include-resolver.test.d.ts +0 -1
  37. package/node_modules/@comis/core/dist/config/include-resolver.test.js +0 -292
  38. package/node_modules/@comis/core/dist/config/layered.test.d.ts +0 -1
  39. package/node_modules/@comis/core/dist/config/layered.test.js +0 -211
  40. package/node_modules/@comis/core/dist/config/loader.test.d.ts +0 -1
  41. package/node_modules/@comis/core/dist/config/loader.test.js +0 -300
  42. package/node_modules/@comis/core/dist/config/migrate.test.d.ts +0 -1
  43. package/node_modules/@comis/core/dist/config/migrate.test.js +0 -244
  44. package/node_modules/@comis/core/dist/config/partial-validator.test.d.ts +0 -1
  45. package/node_modules/@comis/core/dist/config/partial-validator.test.js +0 -98
  46. package/node_modules/@comis/core/dist/config/schema-agent-model.test.d.ts +0 -1
  47. package/node_modules/@comis/core/dist/config/schema-agent-model.test.js +0 -279
  48. package/node_modules/@comis/core/dist/config/schema-agent-session.test.d.ts +0 -1
  49. package/node_modules/@comis/core/dist/config/schema-agent-session.test.js +0 -242
  50. package/node_modules/@comis/core/dist/config/schema-agent.test.d.ts +0 -1
  51. package/node_modules/@comis/core/dist/config/schema-agent.test.js +0 -645
  52. package/node_modules/@comis/core/dist/config/schema-channel.test.d.ts +0 -1
  53. package/node_modules/@comis/core/dist/config/schema-channel.test.js +0 -341
  54. package/node_modules/@comis/core/dist/config/schema-coalescer.test.d.ts +0 -1
  55. package/node_modules/@comis/core/dist/config/schema-coalescer.test.js +0 -51
  56. package/node_modules/@comis/core/dist/config/schema-context-engine.test.d.ts +0 -1
  57. package/node_modules/@comis/core/dist/config/schema-context-engine.test.js +0 -797
  58. package/node_modules/@comis/core/dist/config/schema-context-guard.test.d.ts +0 -1
  59. package/node_modules/@comis/core/dist/config/schema-context-guard.test.js +0 -111
  60. package/node_modules/@comis/core/dist/config/schema-daemon.test.d.ts +0 -1
  61. package/node_modules/@comis/core/dist/config/schema-daemon.test.js +0 -107
  62. package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.d.ts +0 -1
  63. package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.js +0 -51
  64. package/node_modules/@comis/core/dist/config/schema-documentation.test.d.ts +0 -1
  65. package/node_modules/@comis/core/dist/config/schema-documentation.test.js +0 -63
  66. package/node_modules/@comis/core/dist/config/schema-gateway.test.d.ts +0 -1
  67. package/node_modules/@comis/core/dist/config/schema-gateway.test.js +0 -219
  68. package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.d.ts +0 -1
  69. package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.js +0 -41
  70. package/node_modules/@comis/core/dist/config/schema-integrations.test.d.ts +0 -1
  71. package/node_modules/@comis/core/dist/config/schema-integrations.test.js +0 -92
  72. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.d.ts +0 -1
  73. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.js +0 -61
  74. package/node_modules/@comis/core/dist/config/schema-misc.test.d.ts +0 -1
  75. package/node_modules/@comis/core/dist/config/schema-misc.test.js +0 -394
  76. package/node_modules/@comis/core/dist/config/schema-observability.test.d.ts +0 -1
  77. package/node_modules/@comis/core/dist/config/schema-observability.test.js +0 -76
  78. package/node_modules/@comis/core/dist/config/schema-providers.test.d.ts +0 -1
  79. package/node_modules/@comis/core/dist/config/schema-providers.test.js +0 -294
  80. package/node_modules/@comis/core/dist/config/schema-queue.test.d.ts +0 -1
  81. package/node_modules/@comis/core/dist/config/schema-queue.test.js +0 -234
  82. package/node_modules/@comis/core/dist/config/schema-response-prefix.test.d.ts +0 -1
  83. package/node_modules/@comis/core/dist/config/schema-response-prefix.test.js +0 -36
  84. package/node_modules/@comis/core/dist/config/schema-security.test.d.ts +0 -1
  85. package/node_modules/@comis/core/dist/config/schema-security.test.js +0 -54
  86. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.d.ts +0 -1
  87. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.js +0 -60
  88. package/node_modules/@comis/core/dist/config/schema-serializer.test.d.ts +0 -1
  89. package/node_modules/@comis/core/dist/config/schema-serializer.test.js +0 -73
  90. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.d.ts +0 -1
  91. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.js +0 -39
  92. package/node_modules/@comis/core/dist/context/context.test.d.ts +0 -1
  93. package/node_modules/@comis/core/dist/context/context.test.js +0 -276
  94. package/node_modules/@comis/core/dist/domain/agent-response.test.d.ts +0 -1
  95. package/node_modules/@comis/core/dist/domain/agent-response.test.js +0 -159
  96. package/node_modules/@comis/core/dist/domain/credential-mapping.test.d.ts +0 -1
  97. package/node_modules/@comis/core/dist/domain/credential-mapping.test.js +0 -135
  98. package/node_modules/@comis/core/dist/domain/delivery-origin.test.d.ts +0 -1
  99. package/node_modules/@comis/core/dist/domain/delivery-origin.test.js +0 -68
  100. package/node_modules/@comis/core/dist/domain/execution-graph.test.d.ts +0 -1
  101. package/node_modules/@comis/core/dist/domain/execution-graph.test.js +0 -441
  102. package/node_modules/@comis/core/dist/domain/memory-entry.test.d.ts +0 -1
  103. package/node_modules/@comis/core/dist/domain/memory-entry.test.js +0 -193
  104. package/node_modules/@comis/core/dist/domain/normalized-message.test.d.ts +0 -1
  105. package/node_modules/@comis/core/dist/domain/normalized-message.test.js +0 -255
  106. package/node_modules/@comis/core/dist/domain/session-key.test.d.ts +0 -1
  107. package/node_modules/@comis/core/dist/domain/session-key.test.js +0 -291
  108. package/node_modules/@comis/core/dist/domain/subagent-context-config.test.d.ts +0 -1
  109. package/node_modules/@comis/core/dist/domain/subagent-context-config.test.js +0 -131
  110. package/node_modules/@comis/core/dist/domain/subagent-context-types.test.d.ts +0 -1
  111. package/node_modules/@comis/core/dist/domain/subagent-context-types.test.js +0 -182
  112. package/node_modules/@comis/core/dist/event-bus/bus.test.d.ts +0 -1
  113. package/node_modules/@comis/core/dist/event-bus/bus.test.js +0 -152
  114. package/node_modules/@comis/core/dist/event-bus/events-agent.test.d.ts +0 -1
  115. package/node_modules/@comis/core/dist/event-bus/events-agent.test.js +0 -409
  116. package/node_modules/@comis/core/dist/event-bus/events-channel.test.d.ts +0 -1
  117. package/node_modules/@comis/core/dist/event-bus/events-channel.test.js +0 -240
  118. package/node_modules/@comis/core/dist/event-bus/events-infra.test.d.ts +0 -1
  119. package/node_modules/@comis/core/dist/event-bus/events-infra.test.js +0 -416
  120. package/node_modules/@comis/core/dist/event-bus/events-messaging.test.d.ts +0 -1
  121. package/node_modules/@comis/core/dist/event-bus/events-messaging.test.js +0 -433
  122. package/node_modules/@comis/core/dist/event-bus/events.test.d.ts +0 -1
  123. package/node_modules/@comis/core/dist/event-bus/events.test.js +0 -93
  124. package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.d.ts +0 -1
  125. package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.js +0 -29
  126. package/node_modules/@comis/core/dist/hooks/hook-runner.test.d.ts +0 -1
  127. package/node_modules/@comis/core/dist/hooks/hook-runner.test.js +0 -490
  128. package/node_modules/@comis/core/dist/hooks/hook-strategies.test.d.ts +0 -1
  129. package/node_modules/@comis/core/dist/hooks/hook-strategies.test.js +0 -209
  130. package/node_modules/@comis/core/dist/hooks/integration.test.d.ts +0 -1
  131. package/node_modules/@comis/core/dist/hooks/integration.test.js +0 -235
  132. package/node_modules/@comis/core/dist/hooks/plugin-registry.test.d.ts +0 -1
  133. package/node_modules/@comis/core/dist/hooks/plugin-registry.test.js +0 -470
  134. package/node_modules/@comis/core/dist/load-env.test.d.ts +0 -1
  135. package/node_modules/@comis/core/dist/load-env.test.js +0 -21
  136. package/node_modules/@comis/core/dist/security/action-classifier.test.d.ts +0 -1
  137. package/node_modules/@comis/core/dist/security/action-classifier.test.js +0 -298
  138. package/node_modules/@comis/core/dist/security/audit-aggregator.test.d.ts +0 -1
  139. package/node_modules/@comis/core/dist/security/audit-aggregator.test.js +0 -128
  140. package/node_modules/@comis/core/dist/security/audit.test.d.ts +0 -1
  141. package/node_modules/@comis/core/dist/security/audit.test.js +0 -154
  142. package/node_modules/@comis/core/dist/security/canary-token.test.d.ts +0 -1
  143. package/node_modules/@comis/core/dist/security/canary-token.test.js +0 -45
  144. package/node_modules/@comis/core/dist/security/config-redaction.test.d.ts +0 -1
  145. package/node_modules/@comis/core/dist/security/config-redaction.test.js +0 -107
  146. package/node_modules/@comis/core/dist/security/external-content.test.d.ts +0 -1
  147. package/node_modules/@comis/core/dist/security/external-content.test.js +0 -210
  148. package/node_modules/@comis/core/dist/security/injection-patterns.test.d.ts +0 -1
  149. package/node_modules/@comis/core/dist/security/injection-patterns.test.js +0 -213
  150. package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.d.ts +0 -1
  151. package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.js +0 -194
  152. package/node_modules/@comis/core/dist/security/input-guard.test.d.ts +0 -1
  153. package/node_modules/@comis/core/dist/security/input-guard.test.js +0 -215
  154. package/node_modules/@comis/core/dist/security/input-security-guard.test.d.ts +0 -1
  155. package/node_modules/@comis/core/dist/security/input-security-guard.test.js +0 -215
  156. package/node_modules/@comis/core/dist/security/input-validator.test.d.ts +0 -1
  157. package/node_modules/@comis/core/dist/security/input-validator.test.js +0 -133
  158. package/node_modules/@comis/core/dist/security/log-sanitizer.test.d.ts +0 -1
  159. package/node_modules/@comis/core/dist/security/log-sanitizer.test.js +0 -260
  160. package/node_modules/@comis/core/dist/security/memory-write-validator.test.d.ts +0 -1
  161. package/node_modules/@comis/core/dist/security/memory-write-validator.test.js +0 -62
  162. package/node_modules/@comis/core/dist/security/output-guard.test.d.ts +0 -1
  163. package/node_modules/@comis/core/dist/security/output-guard.test.js +0 -397
  164. package/node_modules/@comis/core/dist/security/safe-path.test.d.ts +0 -1
  165. package/node_modules/@comis/core/dist/security/safe-path.test.js +0 -95
  166. package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.d.ts +0 -1
  167. package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.js +0 -231
  168. package/node_modules/@comis/core/dist/security/secret-access.test.d.ts +0 -1
  169. package/node_modules/@comis/core/dist/security/secret-access.test.js +0 -41
  170. package/node_modules/@comis/core/dist/security/secret-crypto.test.d.ts +0 -1
  171. package/node_modules/@comis/core/dist/security/secret-crypto.test.js +0 -113
  172. package/node_modules/@comis/core/dist/security/secret-manager.test.d.ts +0 -1
  173. package/node_modules/@comis/core/dist/security/secret-manager.test.js +0 -394
  174. package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.d.ts +0 -1
  175. package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.js +0 -268
  176. package/node_modules/@comis/core/dist/security/secrets-audit.test.d.ts +0 -10
  177. package/node_modules/@comis/core/dist/security/secrets-audit.test.js +0 -295
  178. package/node_modules/@comis/core/dist/security/ssrf-guard.test.d.ts +0 -1
  179. package/node_modules/@comis/core/dist/security/ssrf-guard.test.js +0 -127
  180. package/node_modules/@comis/core/dist/security/token-generator.test.d.ts +0 -1
  181. package/node_modules/@comis/core/dist/security/token-generator.test.js +0 -35
  182. package/node_modules/@comis/core/dist/tool-metadata.test.d.ts +0 -1
  183. package/node_modules/@comis/core/dist/tool-metadata.test.js +0 -112
  184. package/node_modules/@comis/memory/dist/compaction.test.d.ts +0 -1
  185. package/node_modules/@comis/memory/dist/compaction.test.js +0 -298
  186. package/node_modules/@comis/memory/dist/context-schema.test.d.ts +0 -1
  187. package/node_modules/@comis/memory/dist/context-schema.test.js +0 -246
  188. package/node_modules/@comis/memory/dist/context-store.test.d.ts +0 -1
  189. package/node_modules/@comis/memory/dist/context-store.test.js +0 -708
  190. package/node_modules/@comis/memory/dist/credential-mapping-schema.test.d.ts +0 -7
  191. package/node_modules/@comis/memory/dist/credential-mapping-schema.test.js +0 -73
  192. package/node_modules/@comis/memory/dist/credential-mapping-store.test.d.ts +0 -8
  193. package/node_modules/@comis/memory/dist/credential-mapping-store.test.js +0 -340
  194. package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.d.ts +0 -1
  195. package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.js +0 -165
  196. package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.d.ts +0 -1
  197. package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.js +0 -263
  198. package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.d.ts +0 -1
  199. package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.js +0 -202
  200. package/node_modules/@comis/memory/dist/embedding-cache-lru.test.d.ts +0 -1
  201. package/node_modules/@comis/memory/dist/embedding-cache-lru.test.js +0 -241
  202. package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.d.ts +0 -8
  203. package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.js +0 -678
  204. package/node_modules/@comis/memory/dist/embedding-cache.test.d.ts +0 -1
  205. package/node_modules/@comis/memory/dist/embedding-cache.test.js +0 -213
  206. package/node_modules/@comis/memory/dist/embedding-fingerprint.test.d.ts +0 -1
  207. package/node_modules/@comis/memory/dist/embedding-fingerprint.test.js +0 -87
  208. package/node_modules/@comis/memory/dist/embedding-hash.test.d.ts +0 -1
  209. package/node_modules/@comis/memory/dist/embedding-hash.test.js +0 -31
  210. package/node_modules/@comis/memory/dist/embedding-integration.test.d.ts +0 -8
  211. package/node_modules/@comis/memory/dist/embedding-integration.test.js +0 -232
  212. package/node_modules/@comis/memory/dist/embedding-provider-factory.test.d.ts +0 -1
  213. package/node_modules/@comis/memory/dist/embedding-provider-factory.test.js +0 -176
  214. package/node_modules/@comis/memory/dist/embedding-provider-local.test.d.ts +0 -8
  215. package/node_modules/@comis/memory/dist/embedding-provider-local.test.js +0 -76
  216. package/node_modules/@comis/memory/dist/embedding-provider-openai.test.d.ts +0 -8
  217. package/node_modules/@comis/memory/dist/embedding-provider-openai.test.js +0 -100
  218. package/node_modules/@comis/memory/dist/embedding-queue.test.d.ts +0 -1
  219. package/node_modules/@comis/memory/dist/embedding-queue.test.js +0 -236
  220. package/node_modules/@comis/memory/dist/hybrid-search.test.d.ts +0 -1
  221. package/node_modules/@comis/memory/dist/hybrid-search.test.js +0 -476
  222. package/node_modules/@comis/memory/dist/identity-link-store.test.d.ts +0 -1
  223. package/node_modules/@comis/memory/dist/identity-link-store.test.js +0 -88
  224. package/node_modules/@comis/memory/dist/memory-api.test.d.ts +0 -1
  225. package/node_modules/@comis/memory/dist/memory-api.test.js +0 -495
  226. package/node_modules/@comis/memory/dist/memory-concurrency.test.d.ts +0 -20
  227. package/node_modules/@comis/memory/dist/memory-concurrency.test.js +0 -222
  228. package/node_modules/@comis/memory/dist/named-graph-store.test.d.ts +0 -1
  229. package/node_modules/@comis/memory/dist/named-graph-store.test.js +0 -227
  230. package/node_modules/@comis/memory/dist/observability-store.test.d.ts +0 -1
  231. package/node_modules/@comis/memory/dist/observability-store.test.js +0 -704
  232. package/node_modules/@comis/memory/dist/row-mapper.test.d.ts +0 -1
  233. package/node_modules/@comis/memory/dist/row-mapper.test.js +0 -409
  234. package/node_modules/@comis/memory/dist/schema.test.d.ts +0 -1
  235. package/node_modules/@comis/memory/dist/schema.test.js +0 -240
  236. package/node_modules/@comis/memory/dist/secret-store-schema.test.d.ts +0 -7
  237. package/node_modules/@comis/memory/dist/secret-store-schema.test.js +0 -90
  238. package/node_modules/@comis/memory/dist/session-store.test.d.ts +0 -1
  239. package/node_modules/@comis/memory/dist/session-store.test.js +0 -262
  240. package/node_modules/@comis/memory/dist/setup-secrets.test.d.ts +0 -1
  241. package/node_modules/@comis/memory/dist/setup-secrets.test.js +0 -140
  242. package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.d.ts +0 -1
  243. package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.js +0 -888
  244. package/node_modules/@comis/memory/dist/sqlite-secret-store.test.d.ts +0 -8
  245. package/node_modules/@comis/memory/dist/sqlite-secret-store.test.js +0 -245
  246. package/node_modules/@comis/shared/dist/abort.test.d.ts +0 -1
  247. package/node_modules/@comis/shared/dist/abort.test.js +0 -71
  248. package/node_modules/@comis/shared/dist/result.test.d.ts +0 -1
  249. package/node_modules/@comis/shared/dist/result.test.js +0 -178
  250. package/node_modules/@comis/shared/dist/suppress-error.test.d.ts +0 -1
  251. package/node_modules/@comis/shared/dist/suppress-error.test.js +0 -50
  252. package/node_modules/@comis/shared/dist/timeout.test.d.ts +0 -1
  253. package/node_modules/@comis/shared/dist/timeout.test.js +0 -75
  254. package/node_modules/@comis/shared/dist/ttl-cache.test.d.ts +0 -1
  255. 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
- });