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,704 +0,0 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import Database from "better-sqlite3";
3
- import { initSchema } from "./schema.js";
4
- import { createObservabilityStore } from "./observability-store.js";
5
- describe("ObservabilityStore", () => {
6
- let db;
7
- let store;
8
- beforeEach(() => {
9
- db = new Database(":memory:");
10
- initSchema(db, 768);
11
- store = createObservabilityStore(db);
12
- });
13
- // -----------------------------------------------------------------------
14
- // Token usage CRUD
15
- // -----------------------------------------------------------------------
16
- describe("token usage", () => {
17
- const baseEntry = {
18
- timestamp: 1710000000000,
19
- traceId: "trace-1",
20
- agentId: "agent-a",
21
- channelId: "ch-1",
22
- executionId: "exec-1",
23
- sessionKey: "sess-1",
24
- provider: "anthropic",
25
- model: "claude-sonnet-4-20250514",
26
- promptTokens: 100,
27
- completionTokens: 50,
28
- totalTokens: 150,
29
- cacheReadTokens: 10,
30
- cacheWriteTokens: 5,
31
- costInput: 0.003,
32
- costOutput: 0.0015,
33
- costTotal: 0.0045,
34
- costCacheRead: 0.001,
35
- costCacheWrite: 0.002,
36
- cacheSaved: 0.005,
37
- latencyMs: 1200,
38
- };
39
- it("inserts and queries a single row with all fields round-tripping", () => {
40
- store.insertTokenUsage(baseEntry);
41
- const rows = store.queryTokenUsage();
42
- expect(rows).toHaveLength(1);
43
- const row = rows[0];
44
- expect(row.id).toBeDefined();
45
- expect(row.timestamp).toBe(baseEntry.timestamp);
46
- expect(row.traceId).toBe("trace-1");
47
- expect(row.agentId).toBe("agent-a");
48
- expect(row.channelId).toBe("ch-1");
49
- expect(row.executionId).toBe("exec-1");
50
- expect(row.sessionKey).toBe("sess-1");
51
- expect(row.provider).toBe("anthropic");
52
- expect(row.model).toBe("claude-sonnet-4-20250514");
53
- expect(row.promptTokens).toBe(100);
54
- expect(row.completionTokens).toBe(50);
55
- expect(row.totalTokens).toBe(150);
56
- expect(row.cacheReadTokens).toBe(10);
57
- expect(row.cacheWriteTokens).toBe(5);
58
- expect(row.costInput).toBeCloseTo(0.003);
59
- expect(row.costOutput).toBeCloseTo(0.0015);
60
- expect(row.costTotal).toBeCloseTo(0.0045);
61
- expect(row.costCacheRead).toBeCloseTo(0.001);
62
- expect(row.costCacheWrite).toBeCloseTo(0.002);
63
- expect(row.cacheSaved).toBeCloseTo(0.005);
64
- expect(row.latencyMs).toBe(1200);
65
- });
66
- it("round-trips cache cost fields", () => {
67
- store.insertTokenUsage({
68
- ...baseEntry,
69
- costCacheRead: 0.0012,
70
- costCacheWrite: 0.0024,
71
- cacheSaved: 0.008,
72
- });
73
- const rows = store.queryTokenUsage();
74
- expect(rows[0].costCacheRead).toBeCloseTo(0.0012);
75
- expect(rows[0].costCacheWrite).toBeCloseTo(0.0024);
76
- expect(rows[0].cacheSaved).toBeCloseTo(0.008);
77
- });
78
- it("queries with sinceMs filter", () => {
79
- store.insertTokenUsage({ ...baseEntry, timestamp: 1000 });
80
- store.insertTokenUsage({ ...baseEntry, timestamp: 2000 });
81
- store.insertTokenUsage({ ...baseEntry, timestamp: 3000 });
82
- const rows = store.queryTokenUsage({ sinceMs: 2000 });
83
- expect(rows).toHaveLength(2);
84
- expect(rows.every((r) => r.timestamp >= 2000)).toBe(true);
85
- });
86
- it("queries with agentId filter", () => {
87
- store.insertTokenUsage({ ...baseEntry, agentId: "agent-a" });
88
- store.insertTokenUsage({ ...baseEntry, agentId: "agent-b" });
89
- const rows = store.queryTokenUsage({ agentId: "agent-a" });
90
- expect(rows).toHaveLength(1);
91
- expect(rows[0].agentId).toBe("agent-a");
92
- });
93
- it("queries with provider filter", () => {
94
- store.insertTokenUsage({ ...baseEntry, provider: "anthropic" });
95
- store.insertTokenUsage({ ...baseEntry, provider: "openai" });
96
- const rows = store.queryTokenUsage({ provider: "openai" });
97
- expect(rows).toHaveLength(1);
98
- expect(rows[0].provider).toBe("openai");
99
- });
100
- it("queries with sessionKey filter", () => {
101
- store.insertTokenUsage({ ...baseEntry, sessionKey: "sess-1" });
102
- store.insertTokenUsage({ ...baseEntry, sessionKey: "sess-2" });
103
- const rows = store.queryTokenUsage({ sessionKey: "sess-2" });
104
- expect(rows).toHaveLength(1);
105
- expect(rows[0].sessionKey).toBe("sess-2");
106
- });
107
- it("respects limit parameter", () => {
108
- for (let i = 0; i < 5; i++) {
109
- store.insertTokenUsage({ ...baseEntry, timestamp: baseEntry.timestamp + i });
110
- }
111
- const rows = store.queryTokenUsage({ limit: 3 });
112
- expect(rows).toHaveLength(3);
113
- });
114
- it("orders results by timestamp DESC", () => {
115
- store.insertTokenUsage({ ...baseEntry, timestamp: 1000 });
116
- store.insertTokenUsage({ ...baseEntry, timestamp: 3000 });
117
- store.insertTokenUsage({ ...baseEntry, timestamp: 2000 });
118
- const rows = store.queryTokenUsage();
119
- expect(rows[0].timestamp).toBe(3000);
120
- expect(rows[1].timestamp).toBe(2000);
121
- expect(rows[2].timestamp).toBe(1000);
122
- });
123
- });
124
- // -----------------------------------------------------------------------
125
- // Aggregations
126
- // -----------------------------------------------------------------------
127
- describe("aggregateByProvider", () => {
128
- it("returns correct GROUP BY results for 2 providers", () => {
129
- const base = {
130
- timestamp: 1000,
131
- traceId: "t1",
132
- agentId: "a1",
133
- provider: "anthropic",
134
- model: "claude-sonnet",
135
- promptTokens: 100,
136
- completionTokens: 50,
137
- totalTokens: 150,
138
- costInput: 0.003,
139
- costOutput: 0.0015,
140
- costTotal: 0.005,
141
- costCacheRead: 0,
142
- costCacheWrite: 0,
143
- cacheSaved: 0,
144
- latencyMs: 500,
145
- };
146
- store.insertTokenUsage({ ...base, provider: "anthropic", model: "claude-sonnet", costTotal: 0.01, totalTokens: 100, cacheSaved: 0.003 });
147
- store.insertTokenUsage({ ...base, provider: "anthropic", model: "claude-sonnet", costTotal: 0.02, totalTokens: 200, cacheSaved: 0.005 });
148
- store.insertTokenUsage({ ...base, provider: "openai", model: "gpt-4o", costTotal: 0.05, totalTokens: 500, cacheSaved: 0.01 });
149
- const agg = store.aggregateByProvider();
150
- expect(agg).toHaveLength(2);
151
- const anthropic = agg.find((a) => a.provider === "anthropic");
152
- expect(anthropic.model).toBe("claude-sonnet");
153
- expect(anthropic.totalCost).toBeCloseTo(0.03);
154
- expect(anthropic.totalTokens).toBe(300);
155
- expect(anthropic.callCount).toBe(2);
156
- expect(anthropic.totalCacheSaved).toBeCloseTo(0.008);
157
- const openai = agg.find((a) => a.provider === "openai");
158
- expect(openai.model).toBe("gpt-4o");
159
- expect(openai.totalCost).toBeCloseTo(0.05);
160
- expect(openai.totalTokens).toBe(500);
161
- expect(openai.callCount).toBe(1);
162
- expect(openai.totalCacheSaved).toBeCloseTo(0.01);
163
- });
164
- it("respects sinceMs filter", () => {
165
- const base = {
166
- traceId: "t1",
167
- agentId: "a1",
168
- provider: "anthropic",
169
- model: "claude",
170
- promptTokens: 10,
171
- completionTokens: 5,
172
- totalTokens: 15,
173
- costInput: 0.001,
174
- costOutput: 0.001,
175
- costTotal: 0.002,
176
- costCacheRead: 0,
177
- costCacheWrite: 0,
178
- cacheSaved: 0,
179
- latencyMs: 100,
180
- };
181
- store.insertTokenUsage({ ...base, timestamp: 1000, costTotal: 0.01 });
182
- store.insertTokenUsage({ ...base, timestamp: 5000, costTotal: 0.02 });
183
- const agg = store.aggregateByProvider(3000);
184
- expect(agg).toHaveLength(1);
185
- expect(agg[0].totalCost).toBeCloseTo(0.02);
186
- expect(agg[0].callCount).toBe(1);
187
- });
188
- });
189
- describe("aggregateByAgent", () => {
190
- it("returns correct GROUP BY results", () => {
191
- const base = {
192
- timestamp: 1000,
193
- traceId: "t1",
194
- provider: "anthropic",
195
- model: "claude",
196
- promptTokens: 10,
197
- completionTokens: 5,
198
- totalTokens: 100,
199
- costInput: 0.001,
200
- costOutput: 0.001,
201
- costTotal: 0.01,
202
- costCacheRead: 0,
203
- costCacheWrite: 0,
204
- cacheSaved: 0,
205
- latencyMs: 100,
206
- };
207
- store.insertTokenUsage({ ...base, agentId: "agent-a", costTotal: 0.01, totalTokens: 100, cacheSaved: 0.004 });
208
- store.insertTokenUsage({ ...base, agentId: "agent-a", costTotal: 0.02, totalTokens: 200, cacheSaved: 0.006 });
209
- store.insertTokenUsage({ ...base, agentId: "agent-b", costTotal: 0.05, totalTokens: 500, cacheSaved: 0.015 });
210
- const agg = store.aggregateByAgent();
211
- expect(agg).toHaveLength(2);
212
- const agentA = agg.find((a) => a.agentId === "agent-a");
213
- expect(agentA.totalCost).toBeCloseTo(0.03);
214
- expect(agentA.totalTokens).toBe(300);
215
- expect(agentA.callCount).toBe(2);
216
- expect(agentA.totalCacheSaved).toBeCloseTo(0.01);
217
- const agentB = agg.find((a) => a.agentId === "agent-b");
218
- expect(agentB.totalCacheSaved).toBeCloseTo(0.015);
219
- });
220
- });
221
- describe("aggregateBySession", () => {
222
- it("returns correct results for a specific session", () => {
223
- const base = {
224
- timestamp: 1000,
225
- traceId: "t1",
226
- agentId: "a1",
227
- provider: "anthropic",
228
- model: "claude",
229
- promptTokens: 10,
230
- completionTokens: 5,
231
- totalTokens: 100,
232
- costInput: 0.001,
233
- costOutput: 0.001,
234
- costTotal: 0.01,
235
- costCacheRead: 0,
236
- costCacheWrite: 0,
237
- cacheSaved: 0,
238
- latencyMs: 100,
239
- };
240
- store.insertTokenUsage({ ...base, sessionKey: "sess-1", costTotal: 0.01, totalTokens: 100, cacheSaved: 0.002 });
241
- store.insertTokenUsage({ ...base, sessionKey: "sess-1", costTotal: 0.02, totalTokens: 200, cacheSaved: 0.007 });
242
- store.insertTokenUsage({ ...base, sessionKey: "sess-2", costTotal: 0.05, totalTokens: 500, cacheSaved: 0.012 });
243
- const agg = store.aggregateBySession("sess-1");
244
- expect(agg.sessionKey).toBe("sess-1");
245
- expect(agg.totalCost).toBeCloseTo(0.03);
246
- expect(agg.totalTokens).toBe(300);
247
- expect(agg.callCount).toBe(2);
248
- expect(agg.totalCacheSaved).toBeCloseTo(0.009);
249
- });
250
- it("returns zeroes for non-existent session", () => {
251
- const agg = store.aggregateBySession("nonexistent");
252
- expect(agg.sessionKey).toBe("nonexistent");
253
- expect(agg.totalCost).toBe(0);
254
- expect(agg.totalTokens).toBe(0);
255
- expect(agg.callCount).toBe(0);
256
- expect(agg.totalCacheSaved).toBe(0);
257
- });
258
- });
259
- describe("aggregateHourly", () => {
260
- it("returns correct hourly buckets", () => {
261
- const base = {
262
- traceId: "t1",
263
- agentId: "a1",
264
- provider: "anthropic",
265
- model: "claude",
266
- promptTokens: 10,
267
- completionTokens: 5,
268
- totalTokens: 100,
269
- costInput: 0.001,
270
- costOutput: 0.001,
271
- costTotal: 0.01,
272
- costCacheRead: 0,
273
- costCacheWrite: 0,
274
- cacheSaved: 0,
275
- latencyMs: 100,
276
- };
277
- const hour1 = 3600000; // 1 hour in ms
278
- const hour2 = 7200000; // 2 hours in ms
279
- // Two entries in hour 1
280
- store.insertTokenUsage({ ...base, timestamp: hour1 + 100, costTotal: 0.01, totalTokens: 100, cacheSaved: 0.003 });
281
- store.insertTokenUsage({ ...base, timestamp: hour1 + 200, costTotal: 0.02, totalTokens: 200, cacheSaved: 0.004 });
282
- // One entry in hour 2
283
- store.insertTokenUsage({ ...base, timestamp: hour2 + 100, costTotal: 0.05, totalTokens: 500, cacheSaved: 0.02 });
284
- const buckets = store.aggregateHourly();
285
- expect(buckets).toHaveLength(2);
286
- expect(buckets[0].hour).toBe(hour1);
287
- expect(buckets[0].totalCost).toBeCloseTo(0.03);
288
- expect(buckets[0].totalTokens).toBe(300);
289
- expect(buckets[0].callCount).toBe(2);
290
- expect(buckets[0].totalCacheSaved).toBeCloseTo(0.007);
291
- expect(buckets[1].hour).toBe(hour2);
292
- expect(buckets[1].totalCost).toBeCloseTo(0.05);
293
- expect(buckets[1].totalTokens).toBe(500);
294
- expect(buckets[1].callCount).toBe(1);
295
- expect(buckets[1].totalCacheSaved).toBeCloseTo(0.02);
296
- });
297
- });
298
- // -----------------------------------------------------------------------
299
- // Delivery CRUD
300
- // -----------------------------------------------------------------------
301
- describe("delivery", () => {
302
- const baseDelivery = {
303
- timestamp: 1710000000000,
304
- traceId: "trace-d1",
305
- agentId: "agent-a",
306
- channelType: "telegram",
307
- channelId: "tg-123",
308
- sessionKey: "sess-1",
309
- status: "success",
310
- latencyMs: 350,
311
- errorMessage: "",
312
- messagePreview: "Hello world",
313
- toolCalls: 2,
314
- llmCalls: 1,
315
- tokensTotal: 150,
316
- costTotal: 0.005,
317
- };
318
- it("inserts and queries a delivery row with all fields", () => {
319
- store.insertDelivery(baseDelivery);
320
- const rows = store.queryDelivery();
321
- expect(rows).toHaveLength(1);
322
- const row = rows[0];
323
- expect(row.traceId).toBe("trace-d1");
324
- expect(row.channelType).toBe("telegram");
325
- expect(row.status).toBe("success");
326
- expect(row.latencyMs).toBe(350);
327
- expect(row.toolCalls).toBe(2);
328
- expect(row.costTotal).toBeCloseTo(0.005);
329
- });
330
- it("queries with channelType filter", () => {
331
- store.insertDelivery({ ...baseDelivery, channelType: "telegram" });
332
- store.insertDelivery({ ...baseDelivery, channelType: "discord" });
333
- const rows = store.queryDelivery({ channelType: "telegram" });
334
- expect(rows).toHaveLength(1);
335
- expect(rows[0].channelType).toBe("telegram");
336
- });
337
- it("queries with status filter", () => {
338
- store.insertDelivery({ ...baseDelivery, status: "success" });
339
- store.insertDelivery({ ...baseDelivery, status: "error" });
340
- store.insertDelivery({ ...baseDelivery, status: "timeout" });
341
- const rows = store.queryDelivery({ status: "error" });
342
- expect(rows).toHaveLength(1);
343
- expect(rows[0].status).toBe("error");
344
- });
345
- });
346
- describe("deliveryStats", () => {
347
- it("returns correct counts and avg latency", () => {
348
- const base = {
349
- timestamp: 1000,
350
- traceId: "t1",
351
- agentId: "a1",
352
- channelType: "telegram",
353
- channelId: "ch-1",
354
- latencyMs: 100,
355
- };
356
- store.insertDelivery({ ...base, status: "success", latencyMs: 100 });
357
- store.insertDelivery({ ...base, status: "success", latencyMs: 200 });
358
- store.insertDelivery({ ...base, status: "error", latencyMs: 50 });
359
- store.insertDelivery({ ...base, status: "timeout", latencyMs: 5000 });
360
- store.insertDelivery({ ...base, status: "filtered", latencyMs: 10 });
361
- const stats = store.deliveryStats();
362
- expect(stats.total).toBe(5);
363
- expect(stats.success).toBe(2);
364
- expect(stats.error).toBe(1);
365
- expect(stats.timeout).toBe(1);
366
- expect(stats.filtered).toBe(1);
367
- expect(stats.avgLatencyMs).toBeCloseTo(1072); // (100+200+50+5000+10)/5
368
- });
369
- it("returns zeroes when no data exists", () => {
370
- const stats = store.deliveryStats();
371
- expect(stats.total).toBe(0);
372
- expect(stats.success).toBe(0);
373
- expect(stats.avgLatencyMs).toBe(0);
374
- });
375
- });
376
- // -----------------------------------------------------------------------
377
- // Diagnostics CRUD
378
- // -----------------------------------------------------------------------
379
- describe("diagnostics", () => {
380
- const baseDiag = {
381
- timestamp: 1710000000000,
382
- category: "llm_call",
383
- severity: "info",
384
- agentId: "agent-a",
385
- sessionKey: "sess-1",
386
- message: "LLM call completed",
387
- details: '{"model": "claude"}',
388
- traceId: "trace-d1",
389
- };
390
- it("inserts and queries a diagnostic row with all fields", () => {
391
- store.insertDiagnostic(baseDiag);
392
- const rows = store.queryDiagnostics();
393
- expect(rows).toHaveLength(1);
394
- const row = rows[0];
395
- expect(row.category).toBe("llm_call");
396
- expect(row.severity).toBe("info");
397
- expect(row.message).toBe("LLM call completed");
398
- expect(row.details).toBe('{"model": "claude"}');
399
- });
400
- it("queries with category filter", () => {
401
- store.insertDiagnostic({ ...baseDiag, category: "llm_call" });
402
- store.insertDiagnostic({ ...baseDiag, category: "error" });
403
- const rows = store.queryDiagnostics({ category: "error" });
404
- expect(rows).toHaveLength(1);
405
- expect(rows[0].category).toBe("error");
406
- });
407
- it("queries with severity filter", () => {
408
- store.insertDiagnostic({ ...baseDiag, severity: "info" });
409
- store.insertDiagnostic({ ...baseDiag, severity: "warn" });
410
- store.insertDiagnostic({ ...baseDiag, severity: "error" });
411
- const rows = store.queryDiagnostics({ severity: "warn" });
412
- expect(rows).toHaveLength(1);
413
- expect(rows[0].severity).toBe("warn");
414
- });
415
- });
416
- // -----------------------------------------------------------------------
417
- // Channel snapshots
418
- // -----------------------------------------------------------------------
419
- describe("channel snapshots", () => {
420
- it("inserts and returns latest snapshot per channel type", () => {
421
- store.insertChannelSnapshot({
422
- timestamp: 1000,
423
- channelType: "telegram",
424
- channelId: "tg-1",
425
- status: "connected",
426
- messagesSent: 10,
427
- messagesReceived: 20,
428
- uptimeMs: 60000,
429
- });
430
- store.insertChannelSnapshot({
431
- timestamp: 2000,
432
- channelType: "telegram",
433
- channelId: "tg-1",
434
- status: "connected",
435
- messagesSent: 15,
436
- messagesReceived: 25,
437
- uptimeMs: 120000,
438
- });
439
- store.insertChannelSnapshot({
440
- timestamp: 1500,
441
- channelType: "discord",
442
- channelId: "dc-1",
443
- status: "connected",
444
- messagesSent: 5,
445
- messagesReceived: 8,
446
- uptimeMs: 30000,
447
- });
448
- const snapshots = store.latestChannelSnapshots();
449
- expect(snapshots).toHaveLength(2);
450
- const tg = snapshots.find((s) => s.channelType === "telegram");
451
- expect(tg.timestamp).toBe(2000);
452
- expect(tg.messagesSent).toBe(15);
453
- const dc = snapshots.find((s) => s.channelType === "discord");
454
- expect(dc.timestamp).toBe(1500);
455
- expect(dc.messagesSent).toBe(5);
456
- });
457
- });
458
- // -----------------------------------------------------------------------
459
- // Prune
460
- // -----------------------------------------------------------------------
461
- describe("prune", () => {
462
- it("deletes old rows and preserves recent ones", () => {
463
- const now = Date.now();
464
- const oldTs = now - 2 * 86400000; // 2 days ago
465
- const recentTs = now - 100; // 100ms ago
466
- const tokenBase = {
467
- traceId: "t1",
468
- agentId: "a1",
469
- provider: "anthropic",
470
- model: "claude",
471
- promptTokens: 10,
472
- completionTokens: 5,
473
- totalTokens: 15,
474
- costInput: 0.001,
475
- costOutput: 0.001,
476
- costTotal: 0.002,
477
- costCacheRead: 0,
478
- costCacheWrite: 0,
479
- cacheSaved: 0,
480
- latencyMs: 100,
481
- };
482
- // Insert old and recent rows in all tables
483
- store.insertTokenUsage({ ...tokenBase, timestamp: oldTs });
484
- store.insertTokenUsage({ ...tokenBase, timestamp: recentTs });
485
- store.insertDelivery({
486
- timestamp: oldTs,
487
- traceId: "t1",
488
- agentId: "a1",
489
- channelType: "telegram",
490
- channelId: "ch-1",
491
- status: "success",
492
- latencyMs: 100,
493
- });
494
- store.insertDelivery({
495
- timestamp: recentTs,
496
- traceId: "t1",
497
- agentId: "a1",
498
- channelType: "telegram",
499
- channelId: "ch-1",
500
- status: "success",
501
- latencyMs: 100,
502
- });
503
- store.insertDiagnostic({ timestamp: oldTs, category: "error", severity: "warn", message: "old" });
504
- store.insertDiagnostic({ timestamp: recentTs, category: "error", severity: "warn", message: "recent" });
505
- store.insertChannelSnapshot({ timestamp: oldTs, channelType: "telegram", status: "connected" });
506
- store.insertChannelSnapshot({ timestamp: recentTs, channelType: "telegram", status: "connected" });
507
- // Prune with 1 day retention
508
- const result = store.prune(1);
509
- expect(result.tokenUsage).toBe(1);
510
- expect(result.delivery).toBe(1);
511
- expect(result.diagnostics).toBe(1);
512
- expect(result.channels).toBe(1);
513
- // Verify recent rows survive
514
- expect(store.queryTokenUsage()).toHaveLength(1);
515
- expect(store.queryDelivery()).toHaveLength(1);
516
- expect(store.queryDiagnostics()).toHaveLength(1);
517
- });
518
- });
519
- // -----------------------------------------------------------------------
520
- // Reset
521
- // -----------------------------------------------------------------------
522
- describe("resetAll", () => {
523
- it("deletes all rows from all tables and returns counts", () => {
524
- const tokenBase = {
525
- timestamp: 1000,
526
- traceId: "t1",
527
- agentId: "a1",
528
- provider: "anthropic",
529
- model: "claude",
530
- promptTokens: 10,
531
- completionTokens: 5,
532
- totalTokens: 15,
533
- costInput: 0.001,
534
- costOutput: 0.001,
535
- costTotal: 0.002,
536
- costCacheRead: 0,
537
- costCacheWrite: 0,
538
- cacheSaved: 0,
539
- latencyMs: 100,
540
- };
541
- store.insertTokenUsage(tokenBase);
542
- store.insertTokenUsage({ ...tokenBase, timestamp: 2000 });
543
- store.insertDelivery({
544
- timestamp: 1000,
545
- traceId: "t1",
546
- agentId: "a1",
547
- channelType: "telegram",
548
- channelId: "ch-1",
549
- status: "success",
550
- latencyMs: 100,
551
- });
552
- store.insertDiagnostic({ timestamp: 1000, category: "error", severity: "warn", message: "test" });
553
- store.insertChannelSnapshot({ timestamp: 1000, channelType: "telegram", status: "connected" });
554
- const result = store.resetAll();
555
- expect(result.tokenUsage).toBe(2);
556
- expect(result.delivery).toBe(1);
557
- expect(result.diagnostics).toBe(1);
558
- expect(result.channels).toBe(1);
559
- // All tables should be empty
560
- expect(store.queryTokenUsage()).toHaveLength(0);
561
- expect(store.queryDelivery()).toHaveLength(0);
562
- expect(store.queryDiagnostics()).toHaveLength(0);
563
- expect(store.latestChannelSnapshots()).toHaveLength(0);
564
- });
565
- });
566
- describe("resetTable", () => {
567
- it("deletes from specific table only", () => {
568
- const tokenBase = {
569
- timestamp: 1000,
570
- traceId: "t1",
571
- agentId: "a1",
572
- provider: "anthropic",
573
- model: "claude",
574
- promptTokens: 10,
575
- completionTokens: 5,
576
- totalTokens: 15,
577
- costInput: 0.001,
578
- costOutput: 0.001,
579
- costTotal: 0.002,
580
- costCacheRead: 0,
581
- costCacheWrite: 0,
582
- cacheSaved: 0,
583
- latencyMs: 100,
584
- };
585
- store.insertTokenUsage(tokenBase);
586
- store.insertDelivery({
587
- timestamp: 1000,
588
- traceId: "t1",
589
- agentId: "a1",
590
- channelType: "telegram",
591
- channelId: "ch-1",
592
- status: "success",
593
- latencyMs: 100,
594
- });
595
- store.insertDiagnostic({ timestamp: 1000, category: "error", severity: "warn", message: "test" });
596
- store.insertChannelSnapshot({ timestamp: 1000, channelType: "telegram", status: "connected" });
597
- const count = store.resetTable("token_usage");
598
- expect(count).toBe(1);
599
- // Only token_usage should be empty
600
- expect(store.queryTokenUsage()).toHaveLength(0);
601
- // Other tables should still have data
602
- expect(store.queryDelivery()).toHaveLength(1);
603
- expect(store.queryDiagnostics()).toHaveLength(1);
604
- expect(store.latestChannelSnapshots()).toHaveLength(1);
605
- });
606
- it("supports all table names", () => {
607
- store.insertDelivery({
608
- timestamp: 1000,
609
- traceId: "t1",
610
- agentId: "a1",
611
- channelType: "telegram",
612
- channelId: "ch-1",
613
- status: "success",
614
- latencyMs: 100,
615
- });
616
- expect(store.resetTable("delivery")).toBe(1);
617
- store.insertDiagnostic({ timestamp: 1000, category: "error", severity: "warn", message: "test" });
618
- expect(store.resetTable("diagnostics")).toBe(1);
619
- store.insertChannelSnapshot({ timestamp: 1000, channelType: "telegram", status: "connected" });
620
- expect(store.resetTable("channels")).toBe(1);
621
- });
622
- });
623
- // -----------------------------------------------------------------------
624
- // Schema idempotency
625
- // -----------------------------------------------------------------------
626
- describe("schema idempotency", () => {
627
- it("calling initSchema twice does not error", () => {
628
- // First call was in beforeEach; call again
629
- expect(() => initSchema(db, 768)).not.toThrow();
630
- // Store should still work
631
- store.insertTokenUsage({
632
- timestamp: 1000,
633
- traceId: "t1",
634
- agentId: "a1",
635
- provider: "anthropic",
636
- model: "claude",
637
- promptTokens: 10,
638
- completionTokens: 5,
639
- totalTokens: 15,
640
- costInput: 0.001,
641
- costOutput: 0.001,
642
- costTotal: 0.002,
643
- costCacheRead: 0,
644
- costCacheWrite: 0,
645
- cacheSaved: 0,
646
- latencyMs: 100,
647
- });
648
- expect(store.queryTokenUsage()).toHaveLength(1);
649
- });
650
- });
651
- // -----------------------------------------------------------------------
652
- // DDL migration (17 -> 20 columns)
653
- // -----------------------------------------------------------------------
654
- describe("DDL migration", () => {
655
- it("migrates existing 17-column schema to 20 columns", () => {
656
- const freshDb = new Database(":memory:");
657
- // Create the OLD schema (17 columns, no cache cost columns)
658
- freshDb.exec(`
659
- CREATE TABLE IF NOT EXISTS obs_token_usage (
660
- id INTEGER PRIMARY KEY AUTOINCREMENT,
661
- timestamp INTEGER NOT NULL,
662
- trace_id TEXT NOT NULL,
663
- agent_id TEXT NOT NULL,
664
- channel_id TEXT DEFAULT '',
665
- execution_id TEXT DEFAULT '',
666
- session_key TEXT DEFAULT '',
667
- provider TEXT NOT NULL,
668
- model TEXT NOT NULL,
669
- prompt_tokens INTEGER NOT NULL,
670
- completion_tokens INTEGER NOT NULL,
671
- total_tokens INTEGER NOT NULL,
672
- cache_read_tokens INTEGER DEFAULT 0,
673
- cache_write_tokens INTEGER DEFAULT 0,
674
- cost_input REAL NOT NULL,
675
- cost_output REAL NOT NULL,
676
- cost_total REAL NOT NULL,
677
- latency_ms INTEGER NOT NULL
678
- );
679
- `);
680
- // Run initSchema -- should add 3 columns via ALTER TABLE without crashing
681
- initSchema(freshDb, 768);
682
- // Verify columns exist
683
- const columns = freshDb.prepare("PRAGMA table_info(obs_token_usage)").all();
684
- const colNames = columns.map((c) => c.name);
685
- expect(colNames).toContain("cost_cache_read");
686
- expect(colNames).toContain("cost_cache_write");
687
- expect(colNames).toContain("cache_saved");
688
- // Verify can insert with new store and round-trip
689
- const migratedStore = createObservabilityStore(freshDb);
690
- migratedStore.insertTokenUsage({
691
- timestamp: 1000, traceId: "t1", agentId: "a1", provider: "anthropic",
692
- model: "claude", promptTokens: 100, completionTokens: 50, totalTokens: 150,
693
- costInput: 0.003, costOutput: 0.0015, costTotal: 0.0045,
694
- costCacheRead: 0.001, costCacheWrite: 0.002, cacheSaved: 0.005,
695
- latencyMs: 1200,
696
- });
697
- const rows = migratedStore.queryTokenUsage();
698
- expect(rows[0].costCacheRead).toBeCloseTo(0.001);
699
- expect(rows[0].costCacheWrite).toBeCloseTo(0.002);
700
- expect(rows[0].cacheSaved).toBeCloseTo(0.005);
701
- freshDb.close();
702
- });
703
- });
704
- });