@iworkforces/tracelattice 2.0.7 → 2.1.1

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 (217) hide show
  1. package/README.md +88 -64
  2. package/dist/ServerConfig.d.ts +1 -1
  3. package/dist/ServerConfig.js.map +1 -1
  4. package/dist/cli.js +223 -254
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/ConfigLoader.d.ts +29 -26
  7. package/dist/config/ConfigLoader.d.ts.map +1 -1
  8. package/dist/config/ConfigLoader.js +40 -36
  9. package/dist/config/ConfigLoader.js.map +1 -1
  10. package/dist/contracts/PersistenceBackend.d.ts +7 -108
  11. package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
  12. package/dist/contracts/PersistenceBackend.js +1 -6
  13. package/dist/contracts/calibrator.d.ts +6 -6
  14. package/dist/contracts/calibrator.d.ts.map +1 -1
  15. package/dist/contracts/ids.d.ts +1 -8
  16. package/dist/contracts/ids.d.ts.map +1 -1
  17. package/dist/contracts/ids.js +2 -3
  18. package/dist/contracts/ids.js.map +1 -1
  19. package/dist/contracts/interfaces.d.ts +4 -6
  20. package/dist/contracts/interfaces.d.ts.map +1 -1
  21. package/dist/contracts/persistence-work.d.ts +2 -3
  22. package/dist/contracts/persistence-work.d.ts.map +1 -1
  23. package/dist/contracts/summary.d.ts +0 -1
  24. package/dist/contracts/summary.d.ts.map +1 -1
  25. package/dist/core/HistoryManager.d.ts +12 -16
  26. package/dist/core/HistoryManager.d.ts.map +1 -1
  27. package/dist/core/HistoryManager.js +19 -40
  28. package/dist/core/HistoryManager.js.map +1 -1
  29. package/dist/core/IHistoryManager.d.ts +22 -30
  30. package/dist/core/IHistoryManager.d.ts.map +1 -1
  31. package/dist/core/InputNormalizer.d.ts +7 -24
  32. package/dist/core/InputNormalizer.d.ts.map +1 -1
  33. package/dist/core/InputNormalizer.js +3 -9
  34. package/dist/core/InputNormalizer.js.map +1 -1
  35. package/dist/core/PersistenceBuffer.d.ts +3 -20
  36. package/dist/core/PersistenceBuffer.d.ts.map +1 -1
  37. package/dist/core/PersistenceBuffer.js +1 -4
  38. package/dist/core/PersistenceBuffer.js.map +1 -1
  39. package/dist/core/PersistenceRestore.d.ts +1 -1
  40. package/dist/core/PersistenceRestore.d.ts.map +1 -1
  41. package/dist/core/PersistenceRestore.js +4 -10
  42. package/dist/core/PersistenceRestore.js.map +1 -1
  43. package/dist/core/PersistenceWriter.d.ts.map +1 -1
  44. package/dist/core/PersistenceWriter.js +3 -12
  45. package/dist/core/PersistenceWriter.js.map +1 -1
  46. package/dist/core/SessionErrors.d.ts +0 -11
  47. package/dist/core/SessionErrors.d.ts.map +1 -1
  48. package/dist/core/SessionErrors.js +1 -14
  49. package/dist/core/SessionErrors.js.map +1 -1
  50. package/dist/core/SessionLock.d.ts +4 -5
  51. package/dist/core/SessionLock.d.ts.map +1 -1
  52. package/dist/core/SessionLock.js +5 -10
  53. package/dist/core/SessionLock.js.map +1 -1
  54. package/dist/core/SessionManager.d.ts +0 -2
  55. package/dist/core/SessionManager.d.ts.map +1 -1
  56. package/dist/core/SessionManager.js +3 -5
  57. package/dist/core/SessionManager.js.map +1 -1
  58. package/dist/core/SessionResetCoordinator.d.ts +10 -7
  59. package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
  60. package/dist/core/SessionResetCoordinator.js +10 -28
  61. package/dist/core/SessionResetCoordinator.js.map +1 -1
  62. package/dist/core/ThoughtEvaluator.d.ts +5 -5
  63. package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
  64. package/dist/core/ThoughtEvaluator.js +4 -40
  65. package/dist/core/ThoughtEvaluator.js.map +1 -1
  66. package/dist/core/ThoughtFormatter.js.map +1 -1
  67. package/dist/core/ThoughtProcessor.d.ts +10 -3
  68. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  69. package/dist/core/ThoughtProcessor.js +34 -38
  70. package/dist/core/ThoughtProcessor.js.map +1 -1
  71. package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
  72. package/dist/core/VerificationOutcomeAdmission.js +5 -7
  73. package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
  74. package/dist/core/compression/CompressionService.d.ts +2 -1
  75. package/dist/core/compression/CompressionService.d.ts.map +1 -1
  76. package/dist/core/compression/CompressionService.js.map +1 -1
  77. package/dist/core/compression/DehydrationPolicy.d.ts.map +1 -1
  78. package/dist/core/compression/DehydrationPolicy.js.map +1 -1
  79. package/dist/core/compression/InMemorySummaryStore.d.ts +2 -1
  80. package/dist/core/compression/InMemorySummaryStore.d.ts.map +1 -1
  81. package/dist/core/compression/InMemorySummaryStore.js.map +1 -1
  82. package/dist/core/evaluator/Calibrator.d.ts +2 -2
  83. package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
  84. package/dist/core/evaluator/Calibrator.js +2 -5
  85. package/dist/core/evaluator/Calibrator.js.map +1 -1
  86. package/dist/core/evaluator/SignalComputer.d.ts +2 -1
  87. package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
  88. package/dist/core/evaluator/SignalComputer.js.map +1 -1
  89. package/dist/core/evaluator/internals.d.ts +1 -5
  90. package/dist/core/evaluator/internals.d.ts.map +1 -1
  91. package/dist/core/evaluator/internals.js +1 -3
  92. package/dist/core/evaluator/internals.js.map +1 -1
  93. package/dist/core/graph/Edge.d.ts +1 -1
  94. package/dist/core/graph/EdgeEmitter.d.ts +2 -4
  95. package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
  96. package/dist/core/graph/EdgeEmitter.js +2 -4
  97. package/dist/core/graph/EdgeEmitter.js.map +1 -1
  98. package/dist/core/graph/GraphView.d.ts +13 -1
  99. package/dist/core/graph/GraphView.d.ts.map +1 -1
  100. package/dist/core/graph/GraphView.js +34 -0
  101. package/dist/core/graph/GraphView.js.map +1 -1
  102. package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
  103. package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
  104. package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
  105. package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
  106. package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
  107. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +6 -6
  108. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
  109. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +16 -2
  110. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
  111. package/dist/core/reasoning/strategies/totScoring.d.ts.map +1 -1
  112. package/dist/core/reasoning/strategies/totScoring.js.map +1 -1
  113. package/dist/core/reasoning.d.ts +1 -3
  114. package/dist/core/reasoning.d.ts.map +1 -1
  115. package/dist/core/thought.d.ts +3 -2
  116. package/dist/core/thought.d.ts.map +1 -1
  117. package/dist/errors.d.ts +4 -20
  118. package/dist/errors.d.ts.map +1 -1
  119. package/dist/errors.js +2 -28
  120. package/dist/errors.js.map +1 -1
  121. package/dist/lib.d.ts +31 -24
  122. package/dist/lib.d.ts.map +1 -1
  123. package/dist/lib.js +55 -10
  124. package/dist/lib.js.map +1 -1
  125. package/dist/logger/NullLogger.d.ts +9 -11
  126. package/dist/logger/NullLogger.d.ts.map +1 -1
  127. package/dist/logger/NullLogger.js.map +1 -1
  128. package/dist/persistence/FilePersistence.d.ts +3 -12
  129. package/dist/persistence/FilePersistence.d.ts.map +1 -1
  130. package/dist/persistence/FilePersistence.js +9 -61
  131. package/dist/persistence/FilePersistence.js.map +1 -1
  132. package/dist/persistence/FileSnapshotV2.d.ts +2 -2
  133. package/dist/persistence/FileSnapshotV2.js +2 -2
  134. package/dist/persistence/FileSnapshotV2.js.map +1 -1
  135. package/dist/persistence/FileWriter.d.ts +1 -0
  136. package/dist/persistence/FileWriter.d.ts.map +1 -1
  137. package/dist/persistence/FileWriter.js +3 -3
  138. package/dist/persistence/FileWriter.js.map +1 -1
  139. package/dist/persistence/MemoryPersistence.d.ts +5 -15
  140. package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
  141. package/dist/persistence/MemoryPersistence.js +6 -40
  142. package/dist/persistence/MemoryPersistence.js.map +1 -1
  143. package/dist/persistence/PersistenceCodec.js +1 -3
  144. package/dist/persistence/PersistenceCodec.js.map +1 -1
  145. package/dist/persistence/PersistenceErrors.d.ts +0 -6
  146. package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
  147. package/dist/persistence/PersistenceErrors.js +1 -9
  148. package/dist/persistence/PersistenceErrors.js.map +1 -1
  149. package/dist/persistence/PersistenceScope.d.ts.map +1 -1
  150. package/dist/persistence/PersistenceScope.js +2 -2
  151. package/dist/persistence/PersistenceScope.js.map +1 -1
  152. package/dist/persistence/SqlitePersistence.d.ts +3 -10
  153. package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
  154. package/dist/persistence/SqlitePersistence.js +2 -26
  155. package/dist/persistence/SqlitePersistence.js.map +1 -1
  156. package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
  157. package/dist/persistence/SqliteSchemaV2.js +3 -12
  158. package/dist/persistence/SqliteSchemaV2.js.map +1 -1
  159. package/dist/pool/ConnectionPool.d.ts +3 -12
  160. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  161. package/dist/pool/ConnectionPool.js +5 -8
  162. package/dist/pool/ConnectionPool.js.map +1 -1
  163. package/dist/pool/IConnectionPool.d.ts +3 -9
  164. package/dist/pool/IConnectionPool.d.ts.map +1 -1
  165. package/dist/registry/SkillRegistry.d.ts +1 -7
  166. package/dist/registry/SkillRegistry.d.ts.map +1 -1
  167. package/dist/registry/SkillRegistry.js +0 -15
  168. package/dist/registry/SkillRegistry.js.map +1 -1
  169. package/dist/registry/ToolRegistry.d.ts +1 -9
  170. package/dist/registry/ToolRegistry.d.ts.map +1 -1
  171. package/dist/registry/ToolRegistry.js +0 -21
  172. package/dist/registry/ToolRegistry.js.map +1 -1
  173. package/dist/schema.d.ts +2 -1
  174. package/dist/schema.d.ts.map +1 -1
  175. package/dist/schema.js +3 -3
  176. package/dist/schema.js.map +1 -1
  177. package/dist/transport/BaseTransport.d.ts +0 -9
  178. package/dist/transport/BaseTransport.d.ts.map +1 -1
  179. package/dist/transport/BaseTransport.js +0 -11
  180. package/dist/transport/BaseTransport.js.map +1 -1
  181. package/dist/transport/HttpHelpers.d.ts +4 -1
  182. package/dist/transport/HttpHelpers.d.ts.map +1 -1
  183. package/dist/transport/HttpHelpers.js +61 -11
  184. package/dist/transport/HttpHelpers.js.map +1 -1
  185. package/dist/transport/HttpRequestLifecycle.d.ts +15 -1
  186. package/dist/transport/HttpRequestLifecycle.d.ts.map +1 -1
  187. package/dist/transport/HttpRequestLifecycle.js +66 -4
  188. package/dist/transport/HttpRequestLifecycle.js.map +1 -1
  189. package/dist/transport/HttpTransport.d.ts +2 -0
  190. package/dist/transport/HttpTransport.d.ts.map +1 -1
  191. package/dist/transport/HttpTransport.js +75 -38
  192. package/dist/transport/HttpTransport.js.map +1 -1
  193. package/dist/transport/StreamableHttpTransport.d.ts +5 -29
  194. package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
  195. package/dist/transport/StreamableHttpTransport.js +74 -116
  196. package/dist/transport/StreamableHttpTransport.js.map +1 -1
  197. package/dist/watchers/SkillWatcher.d.ts.map +1 -1
  198. package/dist/watchers/SkillWatcher.js +1 -1
  199. package/dist/watchers/SkillWatcher.js.map +1 -1
  200. package/package.json +2 -2
  201. package/dist/contracts/PersistenceBackend.js.map +0 -1
  202. package/dist/persistence/FileLegacyImport.d.ts +0 -2
  203. package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
  204. package/dist/persistence/FileLegacyImport.js +0 -183
  205. package/dist/persistence/FileLegacyImport.js.map +0 -1
  206. package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
  207. package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
  208. package/dist/persistence/SessionScopedPersistence.js +0 -9
  209. package/dist/persistence/SessionScopedPersistence.js.map +0 -1
  210. package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
  211. package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
  212. package/dist/persistence/SqliteLegacyImport.js +0 -136
  213. package/dist/persistence/SqliteLegacyImport.js.map +0 -1
  214. package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
  215. package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
  216. package/dist/persistence/SqliteLegacySchema.js +0 -72
  217. package/dist/persistence/SqliteLegacySchema.js.map +0 -1
@@ -12,7 +12,8 @@
12
12
  *
13
13
  * @module core/compression/CompressionService
14
14
  */
15
- import type { ISummaryStore, Summary } from '../../contracts/summary.js';
15
+ import type { ISummaryStore } from '../../contracts/summary.js';
16
+ import type { Summary } from './Summary.js';
16
17
  import type { IEdgeStore } from '../../contracts/interfaces.js';
17
18
  import type { Logger } from '../../logger/StructuredLogger.js';
18
19
  import type { IHistoryManager } from '../IHistoryManager.js';
@@ -1 +1 @@
1
- {"version":3,"file":"CompressionService.d.ts","sourceRoot":"","sources":["../../../src/core/compression/CompressionService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,KAAK,EAA0B,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAKrF,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAiB7E,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,cAAc,EAAE,eAAe,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;IACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;gBAEvB,IAAI,EAAE,eAAe;IAKjC;;;;;;OAMG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,GAAG,OAAO;IAkC3F,uEAAuE;IACvE,OAAO,CAAC,oBAAoB;IAW5B,uEAAuE;IACvE,OAAO,CAAC,eAAe;IAKvB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAWvB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAYrB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAsBtB,8EAA8E;IAC9E,OAAO,CAAC,eAAe;CAMvB"}
1
+ {"version":3,"file":"CompressionService.d.ts","sourceRoot":"","sources":["../../../src/core/compression/CompressionService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,KAAK,EAA0B,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAKrF,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAiB7E,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,cAAc,EAAE,eAAe,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;IACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;gBAEvB,IAAI,EAAE,eAAe;IAKjC;;;;;;OAMG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,GAAG,OAAO;IAkC3F,uEAAuE;IACvE,OAAO,CAAC,oBAAoB;IAW5B,uEAAuE;IACvE,OAAO,CAAC,eAAe;IAKvB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAWvB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAYrB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAsBtB,8EAA8E;IAC9E,OAAO,CAAC,eAAe;CAMvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"core/compression/CompressionService.js","sources":["../../../src/core/compression/CompressionService.ts"],"sourcesContent":["/**\n * CompressionService — deterministic branch summarization.\n *\n * Compresses a terminated branch (or any subtree rooted at a thought) into a\n * single {@link Summary} record. Pure offline computation: no LLM, no I/O.\n *\n * Topic extraction is unigram frequency with stopword filtering; aggregate\n * confidence is the arithmetic mean of per-thought calibrated (or raw)\n * confidence values. The covered set is identified via\n * {@link GraphView.descendants}. Compression is **additive**: original\n * thoughts are never mutated or deleted.\n *\n * @module core/compression/CompressionService\n */\n\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport type { HistorySessionSnapshot, IHistoryManager } from '../IHistoryManager.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ConfidenceSignals } from '../reasoning.js';\nimport { GraphView } from '../graph/GraphView.js';\nimport { generateUlid } from '../ids.js';\nimport type { BranchId, SessionId, ThoughtId } from '../../contracts/ids.js';\n\n/** Stopwords excluded from topic extraction (lowercase). */\nconst STOPWORDS: ReadonlySet<string> = new Set([\n\t'the', 'this', 'that', 'then', 'than', 'with', 'from', 'have', 'will', 'been',\n\t'they', 'them', 'their', 'there', 'about', 'would', 'could', 'should', 'which',\n\t'where', 'when', 'what', 'some', 'into', 'also', 'just', 'like', 'over', 'such',\n\t'after', 'only', 'most', 'very', 'much', 'well', 'even', 'still', 'since',\n\t'being', 'doing', 'going', 'using',\n]);\n\nconst MIN_TOKEN_LENGTH = 4;\nconst TOP_TOPICS = 3;\n\n/** Local view of {@link ThoughtData} that exposes optional confidence signals. */\ntype ThoughtWithSignals = ThoughtData & { readonly confidence_signals?: ConfidenceSignals };\n\n/** Dependencies required by {@link CompressionService}. */\nexport interface CompressionDeps {\n\treadonly historyManager: IHistoryManager;\n\treadonly edgeStore: IEdgeStore;\n\treadonly summaryStore: ISummaryStore;\n\treadonly onSummaryCreated?: (summary: Summary) => void;\n\treadonly logger?: Logger;\n}\n\n/**\n * Deterministic, offline compression of branch subtrees into {@link Summary}.\n *\n * @example\n * ```typescript\n * const svc = new CompressionService({ historyManager, edgeStore, summaryStore });\n * const summary = svc.compressBranch('s1', 'alt-1', 'thought-root');\n * ```\n */\nexport class CompressionService {\n\tprivate readonly _deps: CompressionDeps;\n\tprivate readonly _graph: GraphView;\n\n\tconstructor(deps: CompressionDeps) {\n\t\tthis._deps = deps;\n\t\tthis._graph = new GraphView(deps.edgeStore);\n\t}\n\n\t/**\n\t * Compress the subtree rooted at `rootThoughtId` into a {@link Summary}.\n\t *\n\t * Idempotency: if a summary for the same `(branchId, rootThoughtId)` already\n\t * exists in the store, the existing summary is returned unchanged — same\n\t * inputs always yield the same Summary identity.\n\t */\n\tcompressBranch(sessionId: SessionId, branchId: BranchId, rootThoughtId: ThoughtId): Summary {\n\t\tconst existing = this._findExistingForRoot(sessionId, branchId, rootThoughtId);\n\t\tif (existing) return existing;\n\n\t\tconst snapshot = this._deps.historyManager.inspectSession(sessionId);\n\t\tconst candidateIds = this._collectCovered(sessionId, rootThoughtId);\n\t\tconst thoughts = this._resolveThoughts(snapshot, candidateIds);\n\t\tconst coveredIds = thoughts.flatMap((thought) =>\n\t\t\tthought.id === undefined ? [] : [thought.id]\n\t\t);\n\t\tconst summary: Summary = {\n\t\t\tid: generateUlid(),\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcoveredIds,\n\t\t\tcoveredRange: this._coveredRange(thoughts),\n\t\t\ttopics: this._extractTopics(thoughts),\n\t\t\taggregateConfidence: this._meanConfidence(thoughts),\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\n\t\tthis._deps.summaryStore.add(summary);\n\t\tthis._deps.onSummaryCreated?.(summary);\n\t\tthis._deps.logger?.debug('compression.branch.compressed', {\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcovered: coveredIds.length,\n\t\t\ttopics: summary.topics,\n\t\t});\n\t\treturn summary;\n\t}\n\n\t/** Look up an existing summary on this branch with a matching root. */\n\tprivate _findExistingForRoot(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\trootThoughtId: ThoughtId\n\t): Summary | undefined {\n\t\tfor (const s of this._deps.summaryStore.forBranch(sessionId, branchId)) {\n\t\t\tif (s.rootThoughtId === rootThoughtId) return s;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Collect the root and all of its descendants (chronological BFS). */\n\tprivate _collectCovered(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst descendants = this._graph.descendants(sessionId, rootThoughtId);\n\t\treturn [rootThoughtId, ...descendants];\n\t}\n\n\t/**\n\t * Resolve candidate ids against one stable session snapshot. Main-history\n\t * records take precedence over branch copies; branch-only records are added\n\t * in declared branch order. Graph ids absent from the snapshot are omitted.\n\t */\n\tprivate _resolveThoughts(\n\t\tsnapshot: HistorySessionSnapshot,\n\t\tcandidateIds: readonly ThoughtId[]\n\t): ThoughtData[] {\n\t\tconst byId = new Map<ThoughtId, ThoughtData>();\n\t\tfor (const thought of snapshot.history) {\n\t\t\tif (thought.id !== undefined && !byId.has(thought.id)) byId.set(thought.id, thought);\n\t\t}\n\t\tfor (const branchId of snapshot.branchIds) {\n\t\t\tfor (const thought of snapshot.branches[branchId] ?? []) {\n\t\t\t\tif (thought.id !== undefined && !byId.has(thought.id)) byId.set(thought.id, thought);\n\t\t\t}\n\t\t}\n\n\t\tconst resolved: ThoughtData[] = [];\n\t\tconst seen = new Set<ThoughtId>();\n\t\tfor (const id of candidateIds) {\n\t\t\tif (seen.has(id)) continue;\n\t\t\tconst thought = byId.get(id);\n\t\t\tif (thought === undefined) continue;\n\t\t\tseen.add(id);\n\t\t\tresolved.push(thought);\n\t\t}\n\t\treturn resolved;\n\t}\n\n\t/**\n\t * Mean of (`calibrated_confidence` ?? `confidence` ?? 0) across covered.\n\t * Returns 0 when no thoughts are covered.\n\t */\n\tprivate _meanConfidence(thoughts: readonly ThoughtData[]): number {\n\t\tif (thoughts.length === 0) return 0;\n\t\tlet sum = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tconst withSignals = t as ThoughtWithSignals;\n\t\t\tconst calibrated = withSignals.confidence_signals?.calibrated_confidence;\n\t\t\tsum += calibrated ?? t.confidence ?? 0;\n\t\t}\n\t\treturn sum / thoughts.length;\n\t}\n\n\t/**\n\t * Inclusive `[min, max]` of `thought_number` across covered thoughts.\n\t * Returns `[0, 0]` when no thoughts are covered.\n\t */\n\tprivate _coveredRange(thoughts: readonly ThoughtData[]): readonly [number, number] {\n\t\tif (thoughts.length === 0) return [0, 0];\n\t\tlet min = Number.POSITIVE_INFINITY;\n\t\tlet max = Number.NEGATIVE_INFINITY;\n\t\tfor (const t of thoughts) {\n\t\t\tconst n = t.thought_number;\n\t\t\tif (n < min) min = n;\n\t\t\tif (n > max) max = n;\n\t\t}\n\t\treturn [min, max];\n\t}\n\n\t/**\n\t * Extract top-3 unigrams by frequency from concatenated thought text.\n\t * Ties broken by first-occurrence order (stable).\n\t */\n\tprivate _extractTopics(thoughts: readonly ThoughtData[]): readonly string[] {\n\t\tif (thoughts.length === 0) return [];\n\t\tconst counts = new Map<string, number>();\n\t\tconst order = new Map<string, number>();\n\t\tlet position = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tfor (const raw of (t.thought ?? '').split(/\\s+/)) {\n\t\t\t\tconst token = this._normalizeToken(raw);\n\t\t\t\tif (token === null) continue;\n\t\t\t\tif (!counts.has(token)) order.set(token, position++);\n\t\t\t\tcounts.set(token, (counts.get(token) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\t\tif (counts.size === 0) return [];\n\t\tconst entries = Array.from(counts.entries());\n\t\tentries.sort((a, b) => {\n\t\t\tif (b[1] !== a[1]) return b[1] - a[1];\n\t\t\treturn (order.get(a[0]) ?? 0) - (order.get(b[0]) ?? 0);\n\t\t});\n\t\treturn entries.slice(0, TOP_TOPICS).map(([word]) => word);\n\t}\n\n\t/** Lowercase + strip non-alphanumerics; reject if too short or a stopword. */\n\tprivate _normalizeToken(raw: string): string | null {\n\t\tconst cleaned = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');\n\t\tif (cleaned.length < MIN_TOKEN_LENGTH) return null;\n\t\tif (STOPWORDS.has(cleaned)) return null;\n\t\treturn cleaned;\n\t}\n}\n"],"names":["STOPWORDS","Set","MIN_TOKEN_LENGTH","TOP_TOPICS","CompressionService","deps","GraphView","sessionId","branchId","rootThoughtId","existing","snapshot","candidateIds","thoughts","coveredIds","thought","undefined","summary","generateUlid","Date","s","descendants","byId","Map","resolved","seen","id","sum","t","withSignals","calibrated","min","Number","max","n","counts","order","position","raw","token","entries","Array","a","b","word","cleaned"],"mappings":"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"}
1
+ {"version":3,"file":"core/compression/CompressionService.js","sources":["../../../src/core/compression/CompressionService.ts"],"sourcesContent":["/**\n * CompressionService — deterministic branch summarization.\n *\n * Compresses a terminated branch (or any subtree rooted at a thought) into a\n * single {@link Summary} record. Pure offline computation: no LLM, no I/O.\n *\n * Topic extraction is unigram frequency with stopword filtering; aggregate\n * confidence is the arithmetic mean of per-thought calibrated (or raw)\n * confidence values. The covered set is identified via\n * {@link GraphView.descendants}. Compression is **additive**: original\n * thoughts are never mutated or deleted.\n *\n * @module core/compression/CompressionService\n */\n\nimport type { ISummaryStore } from '../../contracts/summary.js';\nimport type { Summary } from './Summary.js';\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport type { HistorySessionSnapshot, IHistoryManager } from '../IHistoryManager.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ConfidenceSignals } from '../reasoning.js';\nimport { GraphView } from '../graph/GraphView.js';\nimport { generateUlid } from '../ids.js';\nimport type { BranchId, SessionId, ThoughtId } from '../../contracts/ids.js';\n\n/** Stopwords excluded from topic extraction (lowercase). */\nconst STOPWORDS: ReadonlySet<string> = new Set([\n\t'the', 'this', 'that', 'then', 'than', 'with', 'from', 'have', 'will', 'been',\n\t'they', 'them', 'their', 'there', 'about', 'would', 'could', 'should', 'which',\n\t'where', 'when', 'what', 'some', 'into', 'also', 'just', 'like', 'over', 'such',\n\t'after', 'only', 'most', 'very', 'much', 'well', 'even', 'still', 'since',\n\t'being', 'doing', 'going', 'using',\n]);\n\nconst MIN_TOKEN_LENGTH = 4;\nconst TOP_TOPICS = 3;\n\n/** Local view of {@link ThoughtData} that exposes optional confidence signals. */\ntype ThoughtWithSignals = ThoughtData & { readonly confidence_signals?: ConfidenceSignals };\n\n/** Dependencies required by {@link CompressionService}. */\nexport interface CompressionDeps {\n\treadonly historyManager: IHistoryManager;\n\treadonly edgeStore: IEdgeStore;\n\treadonly summaryStore: ISummaryStore;\n\treadonly onSummaryCreated?: (summary: Summary) => void;\n\treadonly logger?: Logger;\n}\n\n/**\n * Deterministic, offline compression of branch subtrees into {@link Summary}.\n *\n * @example\n * ```typescript\n * const svc = new CompressionService({ historyManager, edgeStore, summaryStore });\n * const summary = svc.compressBranch('s1', 'alt-1', 'thought-root');\n * ```\n */\nexport class CompressionService {\n\tprivate readonly _deps: CompressionDeps;\n\tprivate readonly _graph: GraphView;\n\n\tconstructor(deps: CompressionDeps) {\n\t\tthis._deps = deps;\n\t\tthis._graph = new GraphView(deps.edgeStore);\n\t}\n\n\t/**\n\t * Compress the subtree rooted at `rootThoughtId` into a {@link Summary}.\n\t *\n\t * Idempotency: if a summary for the same `(branchId, rootThoughtId)` already\n\t * exists in the store, the existing summary is returned unchanged — same\n\t * inputs always yield the same Summary identity.\n\t */\n\tcompressBranch(sessionId: SessionId, branchId: BranchId, rootThoughtId: ThoughtId): Summary {\n\t\tconst existing = this._findExistingForRoot(sessionId, branchId, rootThoughtId);\n\t\tif (existing) return existing;\n\n\t\tconst snapshot = this._deps.historyManager.inspectSession(sessionId);\n\t\tconst candidateIds = this._collectCovered(sessionId, rootThoughtId);\n\t\tconst thoughts = this._resolveThoughts(snapshot, candidateIds);\n\t\tconst coveredIds = thoughts.flatMap((thought) =>\n\t\t\tthought.id === undefined ? [] : [thought.id]\n\t\t);\n\t\tconst summary: Summary = {\n\t\t\tid: generateUlid(),\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcoveredIds,\n\t\t\tcoveredRange: this._coveredRange(thoughts),\n\t\t\ttopics: this._extractTopics(thoughts),\n\t\t\taggregateConfidence: this._meanConfidence(thoughts),\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\n\t\tthis._deps.summaryStore.add(summary);\n\t\tthis._deps.onSummaryCreated?.(summary);\n\t\tthis._deps.logger?.debug('compression.branch.compressed', {\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcovered: coveredIds.length,\n\t\t\ttopics: summary.topics,\n\t\t});\n\t\treturn summary;\n\t}\n\n\t/** Look up an existing summary on this branch with a matching root. */\n\tprivate _findExistingForRoot(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\trootThoughtId: ThoughtId\n\t): Summary | undefined {\n\t\tfor (const s of this._deps.summaryStore.forBranch(sessionId, branchId)) {\n\t\t\tif (s.rootThoughtId === rootThoughtId) return s;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Collect the root and all of its descendants (chronological BFS). */\n\tprivate _collectCovered(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst descendants = this._graph.descendants(sessionId, rootThoughtId);\n\t\treturn [rootThoughtId, ...descendants];\n\t}\n\n\t/**\n\t * Resolve candidate ids against one stable session snapshot. Main-history\n\t * records take precedence over branch copies; branch-only records are added\n\t * in declared branch order. Graph ids absent from the snapshot are omitted.\n\t */\n\tprivate _resolveThoughts(\n\t\tsnapshot: HistorySessionSnapshot,\n\t\tcandidateIds: readonly ThoughtId[]\n\t): ThoughtData[] {\n\t\tconst byId = new Map<ThoughtId, ThoughtData>();\n\t\tfor (const thought of snapshot.history) {\n\t\t\tif (thought.id !== undefined && !byId.has(thought.id)) byId.set(thought.id, thought);\n\t\t}\n\t\tfor (const branchId of snapshot.branchIds) {\n\t\t\tfor (const thought of snapshot.branches[branchId] ?? []) {\n\t\t\t\tif (thought.id !== undefined && !byId.has(thought.id)) byId.set(thought.id, thought);\n\t\t\t}\n\t\t}\n\n\t\tconst resolved: ThoughtData[] = [];\n\t\tconst seen = new Set<ThoughtId>();\n\t\tfor (const id of candidateIds) {\n\t\t\tif (seen.has(id)) continue;\n\t\t\tconst thought = byId.get(id);\n\t\t\tif (thought === undefined) continue;\n\t\t\tseen.add(id);\n\t\t\tresolved.push(thought);\n\t\t}\n\t\treturn resolved;\n\t}\n\n\t/**\n\t * Mean of (`calibrated_confidence` ?? `confidence` ?? 0) across covered.\n\t * Returns 0 when no thoughts are covered.\n\t */\n\tprivate _meanConfidence(thoughts: readonly ThoughtData[]): number {\n\t\tif (thoughts.length === 0) return 0;\n\t\tlet sum = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tconst withSignals = t as ThoughtWithSignals;\n\t\t\tconst calibrated = withSignals.confidence_signals?.calibrated_confidence;\n\t\t\tsum += calibrated ?? t.confidence ?? 0;\n\t\t}\n\t\treturn sum / thoughts.length;\n\t}\n\n\t/**\n\t * Inclusive `[min, max]` of `thought_number` across covered thoughts.\n\t * Returns `[0, 0]` when no thoughts are covered.\n\t */\n\tprivate _coveredRange(thoughts: readonly ThoughtData[]): readonly [number, number] {\n\t\tif (thoughts.length === 0) return [0, 0];\n\t\tlet min = Number.POSITIVE_INFINITY;\n\t\tlet max = Number.NEGATIVE_INFINITY;\n\t\tfor (const t of thoughts) {\n\t\t\tconst n = t.thought_number;\n\t\t\tif (n < min) min = n;\n\t\t\tif (n > max) max = n;\n\t\t}\n\t\treturn [min, max];\n\t}\n\n\t/**\n\t * Extract top-3 unigrams by frequency from concatenated thought text.\n\t * Ties broken by first-occurrence order (stable).\n\t */\n\tprivate _extractTopics(thoughts: readonly ThoughtData[]): readonly string[] {\n\t\tif (thoughts.length === 0) return [];\n\t\tconst counts = new Map<string, number>();\n\t\tconst order = new Map<string, number>();\n\t\tlet position = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tfor (const raw of (t.thought ?? '').split(/\\s+/)) {\n\t\t\t\tconst token = this._normalizeToken(raw);\n\t\t\t\tif (token === null) continue;\n\t\t\t\tif (!counts.has(token)) order.set(token, position++);\n\t\t\t\tcounts.set(token, (counts.get(token) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\t\tif (counts.size === 0) return [];\n\t\tconst entries = Array.from(counts.entries());\n\t\tentries.sort((a, b) => {\n\t\t\tif (b[1] !== a[1]) return b[1] - a[1];\n\t\t\treturn (order.get(a[0]) ?? 0) - (order.get(b[0]) ?? 0);\n\t\t});\n\t\treturn entries.slice(0, TOP_TOPICS).map(([word]) => word);\n\t}\n\n\t/** Lowercase + strip non-alphanumerics; reject if too short or a stopword. */\n\tprivate _normalizeToken(raw: string): string | null {\n\t\tconst cleaned = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');\n\t\tif (cleaned.length < MIN_TOKEN_LENGTH) return null;\n\t\tif (STOPWORDS.has(cleaned)) return null;\n\t\treturn cleaned;\n\t}\n}\n"],"names":["STOPWORDS","Set","MIN_TOKEN_LENGTH","TOP_TOPICS","CompressionService","deps","GraphView","sessionId","branchId","rootThoughtId","existing","snapshot","candidateIds","thoughts","coveredIds","thought","undefined","summary","generateUlid","Date","s","descendants","byId","Map","resolved","seen","id","sum","t","withSignals","calibrated","min","Number","max","n","counts","order","position","raw","token","entries","Array","a","b","word","cleaned"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DehydrationPolicy.d.ts","sourceRoot":"","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,wBAAwB,CAAC;AAKnE,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjD;AAED,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAErD;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IACjB,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAEzD;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CACJ,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,SAAS,EAAE,SAAS,EACpB,IAAI,CAAC,EAAE,kBAAkB,GACvB,aAAa,EAAE;CAiClB"}
1
+ {"version":3,"file":"DehydrationPolicy.d.ts","sourceRoot":"","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,wBAAwB,CAAC;AAKnE,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjD;AAED,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAErD;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IACjB,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAEzD;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CACJ,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,SAAS,EAAE,SAAS,EACpB,IAAI,CAAC,EAAE,kBAAkB,GACvB,aAAa,EAAE;CAiClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"core/compression/DehydrationPolicy.js","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"sourcesContent":["/**\n * DehydrationPolicy — sliding-window history compaction.\n *\n * Replaces older thoughts (the \"cold\" prefix beyond the most recent K) with\n * lightweight {@link SummaryRef} placeholders that point to existing\n * {@link Summary} records in an {@link ISummaryStore}. Recent thoughts (the\n * \"hot\" suffix of length K) are preserved verbatim.\n *\n * Pure and **non-mutating**: the input history array is never modified, and\n * neither the summary store nor any thought record is altered. When a cold\n * thought has no matching summary, the original {@link ThoughtData} is emitted\n * unchanged. Consecutive cold thoughts listed in the same summary's stable\n * `coveredIds` are deduplicated to a single `SummaryRef`.\n *\n * @module core/compression/DehydrationPolicy\n */\n\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\n\n/** Default value for {@link DehydrationOptions.keepLastK}. */\nconst DEFAULT_KEEP_LAST_K = 50;\n\n/** Options controlling sliding-window dehydration. */\nexport interface DehydrationOptions {\n\t/**\n\t * Number of most-recent thoughts to keep verbatim (\"hot\" window).\n\t * Older thoughts (the \"cold\" prefix) are eligible for replacement by\n\t * summary references.\n\t * @default 50\n\t */\n\treadonly keepLastK?: number;\n}\n\n/**\n * Lightweight reference replacing one or more cold thoughts covered by a\n * {@link Summary}. Carries only the summary id and the inclusive\n * `thought_number` range it covers.\n */\nexport interface SummaryRef {\n\treadonly kind: 'summary';\n\treadonly summaryId: string;\n\treadonly coveredRange: readonly [number, number];\n}\n\n/** Output entry in a dehydrated history: either a verbatim thought or a ref. */\nexport type HydratedEntry = ThoughtData | SummaryRef;\n\n/**\n * Sliding-window dehydration policy.\n *\n * @example\n * ```typescript\n * const policy = new DehydrationPolicy(summaryStore);\n * const hydrated = policy.apply(history, sessionId, { keepLastK: 50 });\n * ```\n */\nexport class DehydrationPolicy {\n\tconstructor(private readonly _summaryStore: ISummaryStore) {}\n\n\t/**\n\t * Apply sliding-window dehydration to a history array.\n\t *\n\t * Returns a new array of `(ThoughtData | SummaryRef)` where:\n\t * - The last `keepLastK` thoughts are preserved verbatim.\n\t * - Older thoughts whose stable `id` appears in an existing summary's\n\t * `coveredIds` are replaced by a single {@link SummaryRef}.\n\t * - Consecutive cold thoughts covered by the same summary collapse to one\n\t * `SummaryRef`.\n\t * - Cold thoughts with no matching summary are emitted verbatim.\n\t *\n\t * Non-mutating: the input array is not modified and original thoughts are\n\t * never altered.\n\t *\n\t * @param history - Input history (chronological)\n\t * @param sessionId - Session whose summaries should be considered\n\t * @param opts - Optional dehydration options\n\t * @returns A new array of hydrated entries\n\t */\n\tapply(\n\t\thistory: readonly ThoughtData[],\n\t\tsessionId: SessionId,\n\t\topts?: DehydrationOptions\n\t): HydratedEntry[] {\n\t\tconst k = opts?.keepLastK ?? DEFAULT_KEEP_LAST_K;\n\t\tif (history.length === 0) return [];\n\t\tif (history.length <= k) return history.slice();\n\n\t\tconst splitAt = history.length - k;\n\t\tconst cold = history.slice(0, splitAt);\n\t\tconst hot = history.slice(splitAt);\n\n\t\tconst summaries = this._summaryStore.forSession(sessionId);\n\t\tconst out: HydratedEntry[] = [];\n\t\tlet lastEmittedSummaryId: string | undefined;\n\n\t\tfor (const thought of cold) {\n\t\t\tconst match =\n\t\t\t\tthought.id === undefined ? undefined : findCoveringSummary(summaries, thought.id);\n\t\t\tif (match === undefined) {\n\t\t\t\tout.push(thought);\n\t\t\t\tlastEmittedSummaryId = undefined;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (match.id === lastEmittedSummaryId) continue;\n\t\t\tout.push({\n\t\t\t\tkind: 'summary',\n\t\t\t\tsummaryId: match.id,\n\t\t\t\tcoveredRange: match.coveredRange,\n\t\t\t});\n\t\t\tlastEmittedSummaryId = match.id;\n\t\t}\n\n\t\tfor (const t of hot) out.push(t);\n\t\treturn out;\n\t}\n}\n\n/**\n * Find the first summary whose stable `coveredIds` includes the thought.\n * Returns `undefined` when none match.\n */\nfunction findCoveringSummary(\n\tsummaries: readonly Summary[],\n\tthoughtId: ThoughtId\n): Summary | undefined {\n\tfor (const s of summaries) {\n\t\tif (s.coveredIds.includes(thoughtId)) return s;\n\t}\n\treturn undefined;\n}\n"],"names":["DEFAULT_KEEP_LAST_K","DehydrationPolicy","_summaryStore","history","sessionId","opts","k","splitAt","cold","hot","summaries","out","lastEmittedSummaryId","thought","match","undefined","findCoveringSummary","t","thoughtId","s"],"mappings":"AAsBA,MAAMA,sBAAsB;AAoCrB,MAAMC;;IACZ,YAA6BC,aAA4B,CAAE;aAA9BA,aAAa,GAAbA;IAA+B;IAqB5D,MACCC,OAA+B,EAC/BC,SAAoB,EACpBC,IAAyB,EACP;QAClB,MAAMC,IAAID,MAAM,aAAaL;QAC7B,IAAIG,AAAmB,MAAnBA,QAAQ,MAAM,EAAQ,OAAO,EAAE;QACnC,IAAIA,QAAQ,MAAM,IAAIG,GAAG,OAAOH,QAAQ,KAAK;QAE7C,MAAMI,UAAUJ,QAAQ,MAAM,GAAGG;QACjC,MAAME,OAAOL,QAAQ,KAAK,CAAC,GAAGI;QAC9B,MAAME,MAAMN,QAAQ,KAAK,CAACI;QAE1B,MAAMG,YAAY,IAAI,CAAC,aAAa,CAAC,UAAU,CAACN;QAChD,MAAMO,MAAuB,EAAE;QAC/B,IAAIC;QAEJ,KAAK,MAAMC,WAAWL,KAAM;YAC3B,MAAMM,QACLD,AAAeE,WAAfF,QAAQ,EAAE,GAAiBE,SAAYC,oBAAoBN,WAAWG,QAAQ,EAAE;YACjF,IAAIC,AAAUC,WAAVD,OAAqB;gBACxBH,IAAI,IAAI,CAACE;gBACTD,uBAAuBG;gBACvB;YACD;YACA,IAAID,MAAM,EAAE,KAAKF;gBACjBD,IAAI,IAAI,CAAC;oBACR,MAAM;oBACN,WAAWG,MAAM,EAAE;oBACnB,cAAcA,MAAM,YAAY;gBACjC;gBACAF,uBAAuBE,MAAM,EAAE;;QAChC;QAEA,KAAK,MAAMG,KAAKR,IAAKE,IAAI,IAAI,CAACM;QAC9B,OAAON;IACR;AACD;AAMA,SAASK,oBACRN,SAA6B,EAC7BQ,SAAoB;IAEpB,KAAK,MAAMC,KAAKT,UACf,IAAIS,EAAE,UAAU,CAAC,QAAQ,CAACD,YAAY,OAAOC;AAG/C"}
1
+ {"version":3,"file":"core/compression/DehydrationPolicy.js","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"sourcesContent":["/**\n * DehydrationPolicy — sliding-window history compaction.\n *\n * Replaces older thoughts (the \"cold\" prefix beyond the most recent K) with\n * lightweight {@link SummaryRef} placeholders that point to existing\n * {@link Summary} records in an {@link ISummaryStore}. Recent thoughts (the\n * \"hot\" suffix of length K) are preserved verbatim.\n *\n * Pure and **non-mutating**: the input history array is never modified, and\n * neither the summary store nor any thought record is altered. When a cold\n * thought has no matching summary, the original {@link ThoughtData} is emitted\n * unchanged. Consecutive cold thoughts listed in the same summary's stable\n * `coveredIds` are deduplicated to a single `SummaryRef`.\n *\n * @module core/compression/DehydrationPolicy\n */\n\nimport type { ISummaryStore } from '../../contracts/summary.js';\nimport type { Summary } from './Summary.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\n\n/** Default value for {@link DehydrationOptions.keepLastK}. */\nconst DEFAULT_KEEP_LAST_K = 50;\n\n/** Options controlling sliding-window dehydration. */\nexport interface DehydrationOptions {\n\t/**\n\t * Number of most-recent thoughts to keep verbatim (\"hot\" window).\n\t * Older thoughts (the \"cold\" prefix) are eligible for replacement by\n\t * summary references.\n\t * @default 50\n\t */\n\treadonly keepLastK?: number;\n}\n\n/**\n * Lightweight reference replacing one or more cold thoughts covered by a\n * {@link Summary}. Carries only the summary id and the inclusive\n * `thought_number` range it covers.\n */\nexport interface SummaryRef {\n\treadonly kind: 'summary';\n\treadonly summaryId: string;\n\treadonly coveredRange: readonly [number, number];\n}\n\n/** Output entry in a dehydrated history: either a verbatim thought or a ref. */\nexport type HydratedEntry = ThoughtData | SummaryRef;\n\n/**\n * Sliding-window dehydration policy.\n *\n * @example\n * ```typescript\n * const policy = new DehydrationPolicy(summaryStore);\n * const hydrated = policy.apply(history, sessionId, { keepLastK: 50 });\n * ```\n */\nexport class DehydrationPolicy {\n\tconstructor(private readonly _summaryStore: ISummaryStore) {}\n\n\t/**\n\t * Apply sliding-window dehydration to a history array.\n\t *\n\t * Returns a new array of `(ThoughtData | SummaryRef)` where:\n\t * - The last `keepLastK` thoughts are preserved verbatim.\n\t * - Older thoughts whose stable `id` appears in an existing summary's\n\t * `coveredIds` are replaced by a single {@link SummaryRef}.\n\t * - Consecutive cold thoughts covered by the same summary collapse to one\n\t * `SummaryRef`.\n\t * - Cold thoughts with no matching summary are emitted verbatim.\n\t *\n\t * Non-mutating: the input array is not modified and original thoughts are\n\t * never altered.\n\t *\n\t * @param history - Input history (chronological)\n\t * @param sessionId - Session whose summaries should be considered\n\t * @param opts - Optional dehydration options\n\t * @returns A new array of hydrated entries\n\t */\n\tapply(\n\t\thistory: readonly ThoughtData[],\n\t\tsessionId: SessionId,\n\t\topts?: DehydrationOptions\n\t): HydratedEntry[] {\n\t\tconst k = opts?.keepLastK ?? DEFAULT_KEEP_LAST_K;\n\t\tif (history.length === 0) return [];\n\t\tif (history.length <= k) return history.slice();\n\n\t\tconst splitAt = history.length - k;\n\t\tconst cold = history.slice(0, splitAt);\n\t\tconst hot = history.slice(splitAt);\n\n\t\tconst summaries = this._summaryStore.forSession(sessionId);\n\t\tconst out: HydratedEntry[] = [];\n\t\tlet lastEmittedSummaryId: string | undefined;\n\n\t\tfor (const thought of cold) {\n\t\t\tconst match =\n\t\t\t\tthought.id === undefined ? undefined : findCoveringSummary(summaries, thought.id);\n\t\t\tif (match === undefined) {\n\t\t\t\tout.push(thought);\n\t\t\t\tlastEmittedSummaryId = undefined;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (match.id === lastEmittedSummaryId) continue;\n\t\t\tout.push({\n\t\t\t\tkind: 'summary',\n\t\t\t\tsummaryId: match.id,\n\t\t\t\tcoveredRange: match.coveredRange,\n\t\t\t});\n\t\t\tlastEmittedSummaryId = match.id;\n\t\t}\n\n\t\tfor (const t of hot) out.push(t);\n\t\treturn out;\n\t}\n}\n\n/**\n * Find the first summary whose stable `coveredIds` includes the thought.\n * Returns `undefined` when none match.\n */\nfunction findCoveringSummary(\n\tsummaries: readonly Summary[],\n\tthoughtId: ThoughtId\n): Summary | undefined {\n\tfor (const s of summaries) {\n\t\tif (s.coveredIds.includes(thoughtId)) return s;\n\t}\n\treturn undefined;\n}\n"],"names":["DEFAULT_KEEP_LAST_K","DehydrationPolicy","_summaryStore","history","sessionId","opts","k","splitAt","cold","hot","summaries","out","lastEmittedSummaryId","thought","match","undefined","findCoveringSummary","t","thoughtId","s"],"mappings":"AAuBA,MAAMA,sBAAsB;AAoCrB,MAAMC;;IACZ,YAA6BC,aAA4B,CAAE;aAA9BA,aAAa,GAAbA;IAA+B;IAqB5D,MACCC,OAA+B,EAC/BC,SAAoB,EACpBC,IAAyB,EACP;QAClB,MAAMC,IAAID,MAAM,aAAaL;QAC7B,IAAIG,AAAmB,MAAnBA,QAAQ,MAAM,EAAQ,OAAO,EAAE;QACnC,IAAIA,QAAQ,MAAM,IAAIG,GAAG,OAAOH,QAAQ,KAAK;QAE7C,MAAMI,UAAUJ,QAAQ,MAAM,GAAGG;QACjC,MAAME,OAAOL,QAAQ,KAAK,CAAC,GAAGI;QAC9B,MAAME,MAAMN,QAAQ,KAAK,CAACI;QAE1B,MAAMG,YAAY,IAAI,CAAC,aAAa,CAAC,UAAU,CAACN;QAChD,MAAMO,MAAuB,EAAE;QAC/B,IAAIC;QAEJ,KAAK,MAAMC,WAAWL,KAAM;YAC3B,MAAMM,QACLD,AAAeE,WAAfF,QAAQ,EAAE,GAAiBE,SAAYC,oBAAoBN,WAAWG,QAAQ,EAAE;YACjF,IAAIC,AAAUC,WAAVD,OAAqB;gBACxBH,IAAI,IAAI,CAACE;gBACTD,uBAAuBG;gBACvB;YACD;YACA,IAAID,MAAM,EAAE,KAAKF;gBACjBD,IAAI,IAAI,CAAC;oBACR,MAAM;oBACN,WAAWG,MAAM,EAAE;oBACnB,cAAcA,MAAM,YAAY;gBACjC;gBACAF,uBAAuBE,MAAM,EAAE;;QAChC;QAEA,KAAK,MAAMG,KAAKR,IAAKE,IAAI,IAAI,CAACM;QAC9B,OAAON;IACR;AACD;AAMA,SAASK,oBACRN,SAA6B,EAC7BQ,SAAoB;IAEpB,KAAK,MAAMC,KAAKT,UACf,IAAIS,EAAE,UAAU,CAAC,QAAQ,CAACD,YAAY,OAAOC;AAG/C"}
@@ -11,7 +11,8 @@
11
11
  *
12
12
  * @module core/compression/InMemorySummaryStore
13
13
  */
14
- import type { ISummaryStore, Summary } from '../../contracts/summary.js';
14
+ import type { ISummaryStore } from '../../contracts/summary.js';
15
+ import type { Summary } from './Summary.js';
15
16
  import { type BranchId } from '../../contracts/ids.js';
16
17
  /**
17
18
  * In-memory implementation of {@link ISummaryStore}.
@@ -1 +1 @@
1
- {"version":3,"file":"InMemorySummaryStore.d.ts","sourceRoot":"","sources":["../../../src/core/compression/InMemorySummaryStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAIN,KAAK,QAAQ,EAGb,MAAM,wBAAwB,CAAC;AAahC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsD;IAC5E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwC;IACnE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuC;IAEjE;;;;;;;;;;;;;;OAcG;IACH,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAqB3B;;;;;;;;;;OAUG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAQpC;;;;;;;;;;OAUG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE;IAIjD;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,SAAS,OAAO,EAAE;IAIpE;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAerC,QAAQ,IAAI,IAAI;IAMhB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAShC;;;OAGG;IACH,OAAO,CAAC,aAAa;CAmBrB"}
1
+ {"version":3,"file":"InMemorySummaryStore.d.ts","sourceRoot":"","sources":["../../../src/core/compression/InMemorySummaryStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAIN,KAAK,QAAQ,EAGb,MAAM,wBAAwB,CAAC;AAahC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsD;IAC5E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwC;IACnE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuC;IAEjE;;;;;;;;;;;;;;OAcG;IACH,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAqB3B;;;;;;;;;;OAUG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAQpC;;;;;;;;;;OAUG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE;IAIjD;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,SAAS,OAAO,EAAE;IAIpE;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAerC,QAAQ,IAAI,IAAI;IAMhB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAShC;;;OAGG;IACH,OAAO,CAAC,aAAa;CAmBrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"core/compression/InMemorySummaryStore.js","sources":["../../../src/core/compression/InMemorySummaryStore.ts"],"sourcesContent":["/**\n * InMemorySummaryStore — in-memory implementation of {@link ISummaryStore}.\n *\n * Stores compressed thought summaries in three indexes for O(1) point lookups\n * and O(n) bucket reads (n = result size). Per-session and per-branch isolation\n * is enforced by maintaining independent buckets keyed by session and\n * `${sessionId}:${branchId}`.\n *\n * The store is intentionally synchronous and pure in-memory — no I/O. Persistence\n * adapters may wrap this implementation if durability is required.\n *\n * @module core/compression/InMemorySummaryStore\n */\n\nimport { SequentialThinkingError } from '../../errors.js';\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport {\n\tasBranchId,\n\tasSessionId,\n\tasSummaryId,\n\ttype BranchId,\n\ttype SessionId,\n\ttype SummaryId,\n} from '../../contracts/ids.js';\n\n/**\n * Compose the composite branch key used by the per-branch index.\n *\n * The colon separator mirrors namespace conventions in the rest of the codebase\n * and is safe because session/branch ids are constrained to alphanumeric,\n * hyphen and underscore characters.\n */\nfunction branchKey(sessionId: SessionId, branchId: BranchId): BranchId {\n\treturn asBranchId(`${sessionId}:${branchId}`);\n}\n\n/**\n * In-memory implementation of {@link ISummaryStore}.\n *\n * Maintains three indexes:\n * - `_byId`: id → summary (global lookup)\n * - `_bySession`: sessionId → summaries[] (sorted by `createdAt` ascending)\n * - `_byBranch`: `${sessionId}:${branchId}` → summaries[] (sorted by `createdAt`)\n *\n * @example\n * ```typescript\n * const store = new InMemorySummaryStore();\n * store.add({\n * id: '01HX...',\n * sessionId: 's1',\n * rootThoughtId: 't5',\n * coveredIds: ['t5', 't6'],\n * coveredRange: [5, 6],\n * topics: ['cache', 'lookup'],\n * aggregateConfidence: 0.8,\n * createdAt: Date.now(),\n * });\n * const all = store.forSession('s1');\n * ```\n */\nexport class InMemorySummaryStore implements ISummaryStore {\n\tprivate readonly _byId: Map<SessionId, Map<SummaryId, Summary>> = new Map();\n\tprivate readonly _bySession: Map<SessionId, Summary[]> = new Map();\n\tprivate readonly _byBranch: Map<BranchId, Summary[]> = new Map();\n\n\t/**\n\t * Add a summary to the store.\n\t *\n\t * Inserts the summary into all three indexes, maintaining ascending\n\t * `createdAt` order in the per-session and per-branch buckets via binary\n\t * search insertion (O(log n)).\n\t *\n\t * @param summary - The summary record to add\n\t * @throws {SequentialThinkingError} When a summary with the same id already exists\n\t *\n\t * @example\n\t * ```typescript\n\t * store.add(summary);\n\t * ```\n\t */\n\tadd(summary: Summary): void {\n\t\tlet sessionIds = this._byId.get(summary.sessionId);\n\t\tif (sessionIds === undefined) {\n\t\t\tsessionIds = new Map<SummaryId, Summary>();\n\t\t\tthis._byId.set(summary.sessionId, sessionIds);\n\t\t}\n\t\tif (sessionIds.has(asSummaryId(summary.id))) {\n\t\t\tthrow new SequentialThinkingError(`Duplicate summary id: ${summary.id}`, 'DUPLICATE_SUMMARY');\n\t\t}\n\n\t\tsessionIds.set(asSummaryId(summary.id), summary);\n\t\tthis._insertSorted(this._bySession, summary.sessionId, summary);\n\t\tif (summary.branchId !== undefined) {\n\t\t\tthis._insertSorted(\n\t\t\t\tthis._byBranch,\n\t\t\t\tbranchKey(asSessionId(summary.sessionId), summary.branchId),\n\t\t\t\tsummary\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieve a summary by its unique id.\n\t *\n\t * @param id - The summary's unique identifier\n\t * @returns The summary, or `undefined` if not found\n\t *\n\t * @example\n\t * ```typescript\n\t * const s = store.get('01HX...');\n\t * ```\n\t */\n\tget(id: string): Summary | undefined {\n\t\tfor (const sessionIds of this._byId.values()) {\n\t\t\tconst summary = sessionIds.get(asSummaryId(id));\n\t\t\tif (summary !== undefined) return summary;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all summaries for a session, sorted by `createdAt` ascending.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Read-only array of summaries (empty if none)\n\t *\n\t * @example\n\t * ```typescript\n\t * for (const s of store.forSession('s1')) console.log(s.topics);\n\t * ```\n\t */\n\tforSession(sessionId: string): readonly Summary[] {\n\t\treturn this._bySession.get(asSessionId(sessionId)) ?? [];\n\t}\n\n\t/**\n\t * Get all summaries on a specific branch within a session.\n\t *\n\t * @param sessionId - Session to query\n\t * @param branchId - Branch identifier\n\t * @returns Read-only array of summaries (empty if none)\n\t *\n\t * @example\n\t * ```typescript\n\t * const branch = store.forBranch('s1', 'alt-1');\n\t * ```\n\t */\n\tforBranch(sessionId: string, branchId: BranchId): readonly Summary[] {\n\t\treturn this._byBranch.get(branchKey(asSessionId(sessionId), branchId)) ?? [];\n\t}\n\n\t/**\n\t * Remove all summaries for a session. Other sessions are unaffected.\n\t *\n\t * Removes entries from all three indexes in a single pass over the\n\t * session's summary list.\n\t *\n\t * @param sessionId - Session to clear\n\t *\n\t * @example\n\t * ```typescript\n\t * store.clearSession('s1');\n\t * ```\n\t */\n\tclearSession(sessionId: string): void {\n\t\tconst summaries = this._bySession.get(asSessionId(sessionId));\n\t\tif (!summaries) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const summary of summaries) {\n\t\t\tif (summary.branchId !== undefined) {\n\t\t\t\tthis._byBranch.delete(branchKey(asSessionId(sessionId), summary.branchId));\n\t\t\t}\n\t\t}\n\t\tthis._byId.delete(asSessionId(sessionId));\n\t\tthis._bySession.delete(asSessionId(sessionId));\n\t}\n\n\tclearAll(): void {\n\t\tthis._byId.clear();\n\t\tthis._bySession.clear();\n\t\tthis._byBranch.clear();\n\t}\n\n\t/**\n\t * Count summaries.\n\t *\n\t * @param sessionId - If provided, count for that session only;\n\t * otherwise return the total across all sessions\n\t * @returns The number of summaries\n\t *\n\t * @example\n\t * ```typescript\n\t * const total = store.size();\n\t * const perSession = store.size('s1');\n\t * ```\n\t */\n\tsize(sessionId?: string): number {\n\t\tif (sessionId !== undefined) {\n\t\t\treturn this._bySession.get(asSessionId(sessionId))?.length ?? 0;\n\t\t}\n\t\tlet total = 0;\n\t\tfor (const sessionIds of this._byId.values()) total += sessionIds.size;\n\t\treturn total;\n\t}\n\n\t/**\n\t * Insert a summary into a bucket maintaining ascending `createdAt` order\n\t * via binary search (O(log n) search, O(n) splice).\n\t */\n\tprivate _insertSorted<K>(index: Map<K, Summary[]>, key: K, summary: Summary): void {\n\t\tlet bucket = index.get(key);\n\t\tif (!bucket) {\n\t\t\tbucket = [];\n\t\t\tindex.set(key, bucket);\n\t\t}\n\n\t\tlet lo = 0;\n\t\tlet hi = bucket.length;\n\t\twhile (lo < hi) {\n\t\t\tconst mid = (lo + hi) >>> 1;\n\t\t\tif (bucket[mid]!.createdAt <= summary.createdAt) {\n\t\t\t\tlo = mid + 1;\n\t\t\t} else {\n\t\t\t\thi = mid;\n\t\t\t}\n\t\t}\n\t\tbucket.splice(lo, 0, summary);\n\t}\n}\n"],"names":["branchKey","sessionId","branchId","asBranchId","InMemorySummaryStore","Map","summary","sessionIds","undefined","asSummaryId","SequentialThinkingError","asSessionId","id","summaries","total","index","key","bucket","lo","hi","mid"],"mappings":"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"}
1
+ {"version":3,"file":"core/compression/InMemorySummaryStore.js","sources":["../../../src/core/compression/InMemorySummaryStore.ts"],"sourcesContent":["/**\n * InMemorySummaryStore — in-memory implementation of {@link ISummaryStore}.\n *\n * Stores compressed thought summaries in three indexes for O(1) point lookups\n * and O(n) bucket reads (n = result size). Per-session and per-branch isolation\n * is enforced by maintaining independent buckets keyed by session and\n * `${sessionId}:${branchId}`.\n *\n * The store is intentionally synchronous and pure in-memory — no I/O. Persistence\n * adapters may wrap this implementation if durability is required.\n *\n * @module core/compression/InMemorySummaryStore\n */\n\nimport { SequentialThinkingError } from '../../errors.js';\nimport type { ISummaryStore } from '../../contracts/summary.js';\nimport type { Summary } from './Summary.js';\nimport {\n\tasBranchId,\n\tasSessionId,\n\tasSummaryId,\n\ttype BranchId,\n\ttype SessionId,\n\ttype SummaryId,\n} from '../../contracts/ids.js';\n\n/**\n * Compose the composite branch key used by the per-branch index.\n *\n * The colon separator mirrors namespace conventions in the rest of the codebase\n * and is safe because session/branch ids are constrained to alphanumeric,\n * hyphen and underscore characters.\n */\nfunction branchKey(sessionId: SessionId, branchId: BranchId): BranchId {\n\treturn asBranchId(`${sessionId}:${branchId}`);\n}\n\n/**\n * In-memory implementation of {@link ISummaryStore}.\n *\n * Maintains three indexes:\n * - `_byId`: id → summary (global lookup)\n * - `_bySession`: sessionId → summaries[] (sorted by `createdAt` ascending)\n * - `_byBranch`: `${sessionId}:${branchId}` → summaries[] (sorted by `createdAt`)\n *\n * @example\n * ```typescript\n * const store = new InMemorySummaryStore();\n * store.add({\n * id: '01HX...',\n * sessionId: 's1',\n * rootThoughtId: 't5',\n * coveredIds: ['t5', 't6'],\n * coveredRange: [5, 6],\n * topics: ['cache', 'lookup'],\n * aggregateConfidence: 0.8,\n * createdAt: Date.now(),\n * });\n * const all = store.forSession('s1');\n * ```\n */\nexport class InMemorySummaryStore implements ISummaryStore {\n\tprivate readonly _byId: Map<SessionId, Map<SummaryId, Summary>> = new Map();\n\tprivate readonly _bySession: Map<SessionId, Summary[]> = new Map();\n\tprivate readonly _byBranch: Map<BranchId, Summary[]> = new Map();\n\n\t/**\n\t * Add a summary to the store.\n\t *\n\t * Inserts the summary into all three indexes, maintaining ascending\n\t * `createdAt` order in the per-session and per-branch buckets via binary\n\t * search insertion (O(log n)).\n\t *\n\t * @param summary - The summary record to add\n\t * @throws {SequentialThinkingError} When a summary with the same id already exists\n\t *\n\t * @example\n\t * ```typescript\n\t * store.add(summary);\n\t * ```\n\t */\n\tadd(summary: Summary): void {\n\t\tlet sessionIds = this._byId.get(summary.sessionId);\n\t\tif (sessionIds === undefined) {\n\t\t\tsessionIds = new Map<SummaryId, Summary>();\n\t\t\tthis._byId.set(summary.sessionId, sessionIds);\n\t\t}\n\t\tif (sessionIds.has(asSummaryId(summary.id))) {\n\t\t\tthrow new SequentialThinkingError(`Duplicate summary id: ${summary.id}`, 'DUPLICATE_SUMMARY');\n\t\t}\n\n\t\tsessionIds.set(asSummaryId(summary.id), summary);\n\t\tthis._insertSorted(this._bySession, summary.sessionId, summary);\n\t\tif (summary.branchId !== undefined) {\n\t\t\tthis._insertSorted(\n\t\t\t\tthis._byBranch,\n\t\t\t\tbranchKey(asSessionId(summary.sessionId), summary.branchId),\n\t\t\t\tsummary\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieve a summary by its unique id.\n\t *\n\t * @param id - The summary's unique identifier\n\t * @returns The summary, or `undefined` if not found\n\t *\n\t * @example\n\t * ```typescript\n\t * const s = store.get('01HX...');\n\t * ```\n\t */\n\tget(id: string): Summary | undefined {\n\t\tfor (const sessionIds of this._byId.values()) {\n\t\t\tconst summary = sessionIds.get(asSummaryId(id));\n\t\t\tif (summary !== undefined) return summary;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all summaries for a session, sorted by `createdAt` ascending.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Read-only array of summaries (empty if none)\n\t *\n\t * @example\n\t * ```typescript\n\t * for (const s of store.forSession('s1')) console.log(s.topics);\n\t * ```\n\t */\n\tforSession(sessionId: string): readonly Summary[] {\n\t\treturn this._bySession.get(asSessionId(sessionId)) ?? [];\n\t}\n\n\t/**\n\t * Get all summaries on a specific branch within a session.\n\t *\n\t * @param sessionId - Session to query\n\t * @param branchId - Branch identifier\n\t * @returns Read-only array of summaries (empty if none)\n\t *\n\t * @example\n\t * ```typescript\n\t * const branch = store.forBranch('s1', 'alt-1');\n\t * ```\n\t */\n\tforBranch(sessionId: string, branchId: BranchId): readonly Summary[] {\n\t\treturn this._byBranch.get(branchKey(asSessionId(sessionId), branchId)) ?? [];\n\t}\n\n\t/**\n\t * Remove all summaries for a session. Other sessions are unaffected.\n\t *\n\t * Removes entries from all three indexes in a single pass over the\n\t * session's summary list.\n\t *\n\t * @param sessionId - Session to clear\n\t *\n\t * @example\n\t * ```typescript\n\t * store.clearSession('s1');\n\t * ```\n\t */\n\tclearSession(sessionId: string): void {\n\t\tconst summaries = this._bySession.get(asSessionId(sessionId));\n\t\tif (!summaries) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const summary of summaries) {\n\t\t\tif (summary.branchId !== undefined) {\n\t\t\t\tthis._byBranch.delete(branchKey(asSessionId(sessionId), summary.branchId));\n\t\t\t}\n\t\t}\n\t\tthis._byId.delete(asSessionId(sessionId));\n\t\tthis._bySession.delete(asSessionId(sessionId));\n\t}\n\n\tclearAll(): void {\n\t\tthis._byId.clear();\n\t\tthis._bySession.clear();\n\t\tthis._byBranch.clear();\n\t}\n\n\t/**\n\t * Count summaries.\n\t *\n\t * @param sessionId - If provided, count for that session only;\n\t * otherwise return the total across all sessions\n\t * @returns The number of summaries\n\t *\n\t * @example\n\t * ```typescript\n\t * const total = store.size();\n\t * const perSession = store.size('s1');\n\t * ```\n\t */\n\tsize(sessionId?: string): number {\n\t\tif (sessionId !== undefined) {\n\t\t\treturn this._bySession.get(asSessionId(sessionId))?.length ?? 0;\n\t\t}\n\t\tlet total = 0;\n\t\tfor (const sessionIds of this._byId.values()) total += sessionIds.size;\n\t\treturn total;\n\t}\n\n\t/**\n\t * Insert a summary into a bucket maintaining ascending `createdAt` order\n\t * via binary search (O(log n) search, O(n) splice).\n\t */\n\tprivate _insertSorted<K>(index: Map<K, Summary[]>, key: K, summary: Summary): void {\n\t\tlet bucket = index.get(key);\n\t\tif (!bucket) {\n\t\t\tbucket = [];\n\t\t\tindex.set(key, bucket);\n\t\t}\n\n\t\tlet lo = 0;\n\t\tlet hi = bucket.length;\n\t\twhile (lo < hi) {\n\t\t\tconst mid = (lo + hi) >>> 1;\n\t\t\tif (bucket[mid]!.createdAt <= summary.createdAt) {\n\t\t\t\tlo = mid + 1;\n\t\t\t} else {\n\t\t\t\thi = mid;\n\t\t\t}\n\t\t}\n\t\tbucket.splice(lo, 0, summary);\n\t}\n}\n"],"names":["branchKey","sessionId","branchId","asBranchId","InMemorySummaryStore","Map","summary","sessionIds","undefined","asSummaryId","SequentialThinkingError","asSessionId","id","summaries","total","index","key","bucket","lo","hi","mid"],"mappings":"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"}
@@ -22,7 +22,7 @@
22
22
  */
23
23
  import type { CalibrationMetrics, CalibrationResult, ICalibrator } from '../../contracts/calibrator.js';
24
24
  import type { IOutcomeRecorder } from '../../contracts/interfaces.js';
25
- import type { ThoughtType } from '../reasoning.js';
25
+ import type { ThoughtType } from '../../contracts/reasoning-types.js';
26
26
  import type { SessionId } from '../../contracts/ids.js';
27
27
  /**
28
28
  * Confidence calibration service.
@@ -45,7 +45,7 @@ export declare class Calibrator implements ICalibrator {
45
45
  constructor(outcomeRecorder: IOutcomeRecorder, enabled: boolean);
46
46
  calibrate(rawConfidence: number, type: ThoughtType, sessionId: SessionId): CalibrationResult;
47
47
  metrics(sessionId?: SessionId): CalibrationMetrics;
48
- refit(sessionId?: SessionId): void;
48
+ refit(sessionId: SessionId): void;
49
49
  clearSession(sessionId: SessionId): void;
50
50
  clearAll(): void;
51
51
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Calibrator.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/Calibrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAuB,MAAM,+BAA+B,CAAC;AAC3F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AA4HxD;;;;;;;;;;;;;GAaG;AACH,qBAAa,UAAW,YAAW,WAAW;IAC7C,SAAgB,OAAO,EAAE,OAAO,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoD;gBAEtE,eAAe,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO;IAKxD,SAAS,CACf,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,SAAS,GAClB,iBAAiB;IAqBb,OAAO,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,kBAAkB;IAclD,KAAK,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI;IAUlC,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAKxC,QAAQ,IAAI,IAAI;CAIvB"}
1
+ {"version":3,"file":"Calibrator.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/Calibrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAuB,MAAM,+BAA+B,CAAC;AAC3F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAyHxD;;;;;;;;;;;;;GAaG;AACH,qBAAa,UAAW,YAAW,WAAW;IAC7C,SAAgB,OAAO,EAAE,OAAO,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;gBAElD,eAAe,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO;IAKxD,SAAS,CACf,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,SAAS,GAClB,iBAAiB;IAoBb,OAAO,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,kBAAkB;IAclD,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAKjC,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAKxC,QAAQ,IAAI,IAAI;CAIvB"}
@@ -1,7 +1,6 @@
1
1
  import { EPSILON, MIN_OUTCOMES_FOR_TEMPERATURE, applyTemperature, fitTemperature } from "./calibration-math.js";
2
2
  import { ALL_THOUGHT_TYPES } from "./internals.js";
3
3
  const ECE_BINS = 10;
4
- const GLOBAL_KEY = Symbol('global calibration temperature');
5
4
  function aggregatePerType(outcomes) {
6
5
  const sums = new Map();
7
6
  for (const o of outcomes){
@@ -96,7 +95,7 @@ class Calibrator {
96
95
  const observedMean = typeStats?.mean ?? 0.5;
97
96
  const priorWeight = 1 / (1 + n / 10);
98
97
  const shrunk = priorWeight * observedMean + (1 - priorWeight) * raw;
99
- const temperature = this._temperatures.get(sessionId) ?? this._temperatures.get(GLOBAL_KEY) ?? 1.0;
98
+ const temperature = this._temperatures.get(sessionId) ?? 1.0;
100
99
  const calibrated = outcomes.length >= MIN_OUTCOMES_FOR_TEMPERATURE ? applyTemperature(shrunk, temperature) : shrunk;
101
100
  return {
102
101
  raw,
@@ -117,9 +116,7 @@ class Calibrator {
117
116
  }
118
117
  refit(sessionId) {
119
118
  if (!this.enabled) return;
120
- const key = sessionId ?? GLOBAL_KEY;
121
- const outcomes = void 0 === sessionId ? this._recorder.getAllOutcomes() : this._recorder.getOutcomes(sessionId);
122
- this._temperatures.set(key, fitTemperature(outcomes));
119
+ this._temperatures.set(sessionId, fitTemperature(this._recorder.getOutcomes(sessionId)));
123
120
  }
124
121
  clearSession(sessionId) {
125
122
  if (!this.enabled) return;
@@ -1 +1 @@
1
- {"version":3,"file":"core/evaluator/Calibrator.js","sources":["../../../src/core/evaluator/Calibrator.ts"],"sourcesContent":["/**\n * Confidence calibration for sequential thinking reasoning.\n *\n * Provides the {@link Calibrator} class — maps raw model confidence values\n * to calibrated probabilities using per-type Beta(2, 2) priors and\n * grid-searched temperature scaling. Reports calibration quality through\n * Brier score and 10-bin Expected Calibration Error (ECE).\n *\n * Math summary:\n * - **Per-type prior**: Beta(α=2, β=2), prior mean = 0.5. As outcomes accumulate\n * for a type, the calibrated value shrinks toward the observed mean of that\n * type with weight `priorWeight = 1 / (1 + n / 10)` where `n` is the type's\n * sample count.\n * - **Temperature scaling**: Grid search T ∈ {0.5, 0.75, 1.0, 1.25, 1.5, 2.0}\n * minimizing negative log-likelihood (NLL) over recorded outcomes. Default T=1.0.\n * Requires ≥10 outcomes; below that threshold only prior shrinkage is applied.\n * - **Brier score**: `mean((predicted - actual)^2)` over recorded outcomes.\n * - **ECE (10-bin)**: bucket predictions in 0.1 increments, compute weighted\n * absolute deviation between bin mean confidence and bin accuracy.\n *\n * @module core/evaluator/Calibrator\n */\n\nimport type {\n\tCalibrationMetrics,\n\tCalibrationResult,\n\tICalibrator,\n} from '../../contracts/calibrator.js';\nimport type { IOutcomeRecorder, VerificationOutcome } from '../../contracts/interfaces.js';\nimport type { ThoughtType } from '../reasoning.js';\nimport type { SessionId } from '../../contracts/ids.js';\nimport {\n\tEPSILON,\n\tMIN_OUTCOMES_FOR_TEMPERATURE,\n\tapplyTemperature,\n\tfitTemperature,\n} from './calibration-math.js';\nimport { ALL_THOUGHT_TYPES } from './internals.js';\n\n/** Number of bins used by ECE (10-bin → 0.1 increments). */\nconst ECE_BINS = 10;\n\n/** Sentinel used in the per-session temperature map for global state. */\nconst GLOBAL_KEY: unique symbol = Symbol('global calibration temperature');\n\n/**\n * Build per-type empirical means + counts from a list of outcomes.\n *\n * @param outcomes - Outcomes to aggregate.\n * @returns Map of thought type to `{ mean, count }`. Types with no outcomes\n * are absent from the map.\n */\nfunction aggregatePerType(\n\toutcomes: readonly VerificationOutcome[]\n): Map<string, { mean: number; count: number }> {\n\tconst sums = new Map<string, { sum: number; count: number }>();\n\tfor (const o of outcomes) {\n\t\tconst prev = sums.get(o.type) ?? { sum: 0, count: 0 };\n\t\tprev.sum += o.actual;\n\t\tprev.count += 1;\n\t\tsums.set(o.type, prev);\n\t}\n\tconst result = new Map<string, { mean: number; count: number }>();\n\tfor (const [type, { sum, count }] of sums) {\n\t\tresult.set(type, { mean: sum / count, count });\n\t}\n\treturn result;\n}\n\n/**\n * Compute the Brier score over a list of outcomes.\n *\n * @param outcomes - Outcomes to score.\n * @returns Mean squared error between predicted probability and actual label,\n * or `null` if `outcomes` is empty.\n */\nfunction brierScore(outcomes: readonly VerificationOutcome[]): number | null {\n\tif (outcomes.length === 0) return null;\n\tlet sum = 0;\n\tfor (const o of outcomes) {\n\t\tconst diff = o.predicted - o.actual;\n\t\tsum += diff * diff;\n\t}\n\treturn sum / outcomes.length;\n}\n\n/**\n * Compute 10-bin Expected Calibration Error.\n *\n * Buckets predictions in 0.1-wide bins, then sums weighted absolute\n * differences between bin mean confidence and bin accuracy.\n *\n * @param outcomes - Outcomes to evaluate.\n * @returns ECE in `[0, 1]`, or `null` if `outcomes` is empty.\n */\nfunction expectedCalibrationError(outcomes: readonly VerificationOutcome[]): number | null {\n\tif (outcomes.length === 0) return null;\n\tconst binConfSum = new Array<number>(ECE_BINS).fill(0);\n\tconst binAccSum = new Array<number>(ECE_BINS).fill(0);\n\tconst binCount = new Array<number>(ECE_BINS).fill(0);\n\tfor (const o of outcomes) {\n\t\tconst p = Math.min(1 - EPSILON, Math.max(0, o.predicted));\n\t\tconst idx = Math.min(ECE_BINS - 1, Math.floor(p * ECE_BINS));\n\t\tbinConfSum[idx] = (binConfSum[idx] ?? 0) + p;\n\t\tbinAccSum[idx] = (binAccSum[idx] ?? 0) + o.actual;\n\t\tbinCount[idx] = (binCount[idx] ?? 0) + 1;\n\t}\n\tconst total = outcomes.length;\n\tlet ece = 0;\n\tfor (let i = 0; i < ECE_BINS; i++) {\n\t\tconst n = binCount[i] ?? 0;\n\t\tif (n === 0) continue;\n\t\tconst meanConf = (binConfSum[i] ?? 0) / n;\n\t\tconst meanAcc = (binAccSum[i] ?? 0) / n;\n\t\tece += (n / total) * Math.abs(meanConf - meanAcc);\n\t}\n\treturn ece;\n}\n\n/**\n * Build the per-type Brier score breakdown for {@link CalibrationMetrics}.\n *\n * @param outcomes - Outcomes to bucket by type.\n * @returns Record keyed by every {@link ThoughtType}; `null` for types with\n * no recorded outcomes.\n */\nfunction perTypeBrier(\n\toutcomes: readonly VerificationOutcome[]\n): Record<ThoughtType, number | null> {\n\tconst buckets = new Map<string, VerificationOutcome[]>();\n\tfor (const o of outcomes) {\n\t\tconst list = buckets.get(o.type) ?? [];\n\t\tlist.push(o);\n\t\tbuckets.set(o.type, list);\n\t}\n\tconst result = {} as Record<ThoughtType, number | null>;\n\tfor (const t of ALL_THOUGHT_TYPES) {\n\t\tresult[t] = brierScore(buckets.get(t) ?? []);\n\t}\n\treturn result;\n}\n\n/** Empty CalibrationMetrics returned when calibration is disabled. */\nfunction emptyMetrics(): CalibrationMetrics {\n\tconst perType = {} as Record<ThoughtType, number | null>;\n\tfor (const t of ALL_THOUGHT_TYPES) perType[t] = null;\n\treturn {\n\t\tbrierScore: null,\n\t\tece: null,\n\t\tsampleCount: 0,\n\t\tperTypeBrier: perType,\n\t};\n}\n\n/**\n * Confidence calibration service.\n *\n * Stateless w.r.t. outcome storage (delegated to {@link IOutcomeRecorder}),\n * but maintains a small per-session temperature cache that is recomputed\n * via {@link Calibrator.refit}.\n *\n * @example\n * ```typescript\n * const calibrator = new Calibrator(outcomeRecorder, true);\n * const result = calibrator.calibrate(0.9, 'hypothesis', 'session-1');\n * console.log(result.calibrated, result.temperature, result.priorWeight);\n * ```\n */\nexport class Calibrator implements ICalibrator {\n\tpublic readonly enabled: boolean;\n\tprivate readonly _recorder: IOutcomeRecorder;\n\tprivate readonly _temperatures = new Map<SessionId | typeof GLOBAL_KEY, number>();\n\n\tconstructor(outcomeRecorder: IOutcomeRecorder, enabled: boolean) {\n\t\tthis._recorder = outcomeRecorder;\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic calibrate(\n\t\trawConfidence: number,\n\t\ttype: ThoughtType,\n\t\tsessionId: SessionId\n\t): CalibrationResult {\n\t\tconst raw = Math.min(1, Math.max(0, rawConfidence));\n\t\tif (!this.enabled) {\n\t\t\treturn { raw, calibrated: raw, temperature: 1.0, priorWeight: 0 };\n\t\t}\n\t\tconst outcomes = this._recorder.getOutcomes(sessionId);\n\t\tconst perType = aggregatePerType(outcomes);\n\t\tconst typeStats = perType.get(type);\n\t\tconst n = typeStats?.count ?? 0;\n\t\tconst observedMean = typeStats?.mean ?? 0.5;\n\t\tconst priorWeight = 1 / (1 + n / 10);\n\t\tconst shrunk = priorWeight * observedMean + (1 - priorWeight) * raw;\n\t\tconst temperature =\n\t\t\tthis._temperatures.get(sessionId) ?? this._temperatures.get(GLOBAL_KEY) ?? 1.0;\n\t\tconst calibrated =\n\t\t\toutcomes.length >= MIN_OUTCOMES_FOR_TEMPERATURE\n\t\t\t\t? applyTemperature(shrunk, temperature)\n\t\t\t\t: shrunk;\n\t\treturn { raw, calibrated, temperature, priorWeight };\n\t}\n\n\tpublic metrics(sessionId?: SessionId): CalibrationMetrics {\n\t\tif (!this.enabled) return emptyMetrics();\n\t\tconst outcomes =\n\t\t\tsessionId === undefined\n\t\t\t\t? this._recorder.getAllOutcomes()\n\t\t\t\t: this._recorder.getOutcomes(sessionId);\n\t\treturn {\n\t\t\tbrierScore: brierScore(outcomes),\n\t\t\tece: expectedCalibrationError(outcomes),\n\t\t\tsampleCount: outcomes.length,\n\t\t\tperTypeBrier: perTypeBrier(outcomes),\n\t\t};\n\t}\n\n\tpublic refit(sessionId?: SessionId): void {\n\t\tif (!this.enabled) return;\n\t\tconst key = sessionId ?? GLOBAL_KEY;\n\t\tconst outcomes =\n\t\t\tsessionId === undefined\n\t\t\t\t? this._recorder.getAllOutcomes()\n\t\t\t\t: this._recorder.getOutcomes(sessionId);\n\t\tthis._temperatures.set(key, fitTemperature(outcomes));\n\t}\n\n\tpublic clearSession(sessionId: SessionId): void {\n\t\tif (!this.enabled) return;\n\t\tthis._temperatures.delete(sessionId);\n\t}\n\n\tpublic clearAll(): void {\n\t\tif (!this.enabled) return;\n\t\tthis._temperatures.clear();\n\t}\n}\n"],"names":["ECE_BINS","GLOBAL_KEY","Symbol","aggregatePerType","outcomes","sums","Map","o","prev","result","type","sum","count","brierScore","diff","expectedCalibrationError","binConfSum","Array","binAccSum","binCount","p","Math","EPSILON","idx","total","ece","i","n","meanConf","meanAcc","perTypeBrier","buckets","list","t","ALL_THOUGHT_TYPES","emptyMetrics","perType","Calibrator","outcomeRecorder","enabled","rawConfidence","sessionId","raw","typeStats","observedMean","priorWeight","shrunk","temperature","calibrated","MIN_OUTCOMES_FOR_TEMPERATURE","applyTemperature","undefined","key","fitTemperature"],"mappings":"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"}
1
+ {"version":3,"file":"core/evaluator/Calibrator.js","sources":["../../../src/core/evaluator/Calibrator.ts"],"sourcesContent":["/**\n * Confidence calibration for sequential thinking reasoning.\n *\n * Provides the {@link Calibrator} class — maps raw model confidence values\n * to calibrated probabilities using per-type Beta(2, 2) priors and\n * grid-searched temperature scaling. Reports calibration quality through\n * Brier score and 10-bin Expected Calibration Error (ECE).\n *\n * Math summary:\n * - **Per-type prior**: Beta(α=2, β=2), prior mean = 0.5. As outcomes accumulate\n * for a type, the calibrated value shrinks toward the observed mean of that\n * type with weight `priorWeight = 1 / (1 + n / 10)` where `n` is the type's\n * sample count.\n * - **Temperature scaling**: Grid search T ∈ {0.5, 0.75, 1.0, 1.25, 1.5, 2.0}\n * minimizing negative log-likelihood (NLL) over recorded outcomes. Default T=1.0.\n * Requires ≥10 outcomes; below that threshold only prior shrinkage is applied.\n * - **Brier score**: `mean((predicted - actual)^2)` over recorded outcomes.\n * - **ECE (10-bin)**: bucket predictions in 0.1 increments, compute weighted\n * absolute deviation between bin mean confidence and bin accuracy.\n *\n * @module core/evaluator/Calibrator\n */\n\nimport type {\n\tCalibrationMetrics,\n\tCalibrationResult,\n\tICalibrator,\n} from '../../contracts/calibrator.js';\nimport type { IOutcomeRecorder, VerificationOutcome } from '../../contracts/interfaces.js';\nimport type { ThoughtType } from '../../contracts/reasoning-types.js';\nimport type { SessionId } from '../../contracts/ids.js';\nimport {\n\tEPSILON,\n\tMIN_OUTCOMES_FOR_TEMPERATURE,\n\tapplyTemperature,\n\tfitTemperature,\n} from './calibration-math.js';\nimport { ALL_THOUGHT_TYPES } from './internals.js';\n\n/** Number of bins used by ECE (10-bin → 0.1 increments). */\nconst ECE_BINS = 10;\n\n/**\n * Build per-type empirical means + counts from a list of outcomes.\n *\n * @param outcomes - Outcomes to aggregate.\n * @returns Map of thought type to `{ mean, count }`. Types with no outcomes\n * are absent from the map.\n */\nfunction aggregatePerType(\n\toutcomes: readonly VerificationOutcome[]\n): Map<string, { mean: number; count: number }> {\n\tconst sums = new Map<string, { sum: number; count: number }>();\n\tfor (const o of outcomes) {\n\t\tconst prev = sums.get(o.type) ?? { sum: 0, count: 0 };\n\t\tprev.sum += o.actual;\n\t\tprev.count += 1;\n\t\tsums.set(o.type, prev);\n\t}\n\tconst result = new Map<string, { mean: number; count: number }>();\n\tfor (const [type, { sum, count }] of sums) {\n\t\tresult.set(type, { mean: sum / count, count });\n\t}\n\treturn result;\n}\n\n/**\n * Compute the Brier score over a list of outcomes.\n *\n * @param outcomes - Outcomes to score.\n * @returns Mean squared error between predicted probability and actual label,\n * or `null` if `outcomes` is empty.\n */\nfunction brierScore(outcomes: readonly VerificationOutcome[]): number | null {\n\tif (outcomes.length === 0) return null;\n\tlet sum = 0;\n\tfor (const o of outcomes) {\n\t\tconst diff = o.predicted - o.actual;\n\t\tsum += diff * diff;\n\t}\n\treturn sum / outcomes.length;\n}\n\n/**\n * Compute 10-bin Expected Calibration Error.\n *\n * Buckets predictions in 0.1-wide bins, then sums weighted absolute\n * differences between bin mean confidence and bin accuracy.\n *\n * @param outcomes - Outcomes to evaluate.\n * @returns ECE in `[0, 1]`, or `null` if `outcomes` is empty.\n */\nfunction expectedCalibrationError(outcomes: readonly VerificationOutcome[]): number | null {\n\tif (outcomes.length === 0) return null;\n\tconst binConfSum = new Array<number>(ECE_BINS).fill(0);\n\tconst binAccSum = new Array<number>(ECE_BINS).fill(0);\n\tconst binCount = new Array<number>(ECE_BINS).fill(0);\n\tfor (const o of outcomes) {\n\t\tconst p = Math.min(1 - EPSILON, Math.max(0, o.predicted));\n\t\tconst idx = Math.min(ECE_BINS - 1, Math.floor(p * ECE_BINS));\n\t\tbinConfSum[idx] = (binConfSum[idx] ?? 0) + p;\n\t\tbinAccSum[idx] = (binAccSum[idx] ?? 0) + o.actual;\n\t\tbinCount[idx] = (binCount[idx] ?? 0) + 1;\n\t}\n\tconst total = outcomes.length;\n\tlet ece = 0;\n\tfor (let i = 0; i < ECE_BINS; i++) {\n\t\tconst n = binCount[i] ?? 0;\n\t\tif (n === 0) continue;\n\t\tconst meanConf = (binConfSum[i] ?? 0) / n;\n\t\tconst meanAcc = (binAccSum[i] ?? 0) / n;\n\t\tece += (n / total) * Math.abs(meanConf - meanAcc);\n\t}\n\treturn ece;\n}\n\n/**\n * Build the per-type Brier score breakdown for {@link CalibrationMetrics}.\n *\n * @param outcomes - Outcomes to bucket by type.\n * @returns Record keyed by every {@link ThoughtType}; `null` for types with\n * no recorded outcomes.\n */\nfunction perTypeBrier(\n\toutcomes: readonly VerificationOutcome[]\n): Record<ThoughtType, number | null> {\n\tconst buckets = new Map<string, VerificationOutcome[]>();\n\tfor (const o of outcomes) {\n\t\tconst list = buckets.get(o.type) ?? [];\n\t\tlist.push(o);\n\t\tbuckets.set(o.type, list);\n\t}\n\tconst result = {} as Record<ThoughtType, number | null>;\n\tfor (const t of ALL_THOUGHT_TYPES) {\n\t\tresult[t] = brierScore(buckets.get(t) ?? []);\n\t}\n\treturn result;\n}\n\n/** Empty CalibrationMetrics returned when calibration is disabled. */\nfunction emptyMetrics(): CalibrationMetrics {\n\tconst perType = {} as Record<ThoughtType, number | null>;\n\tfor (const t of ALL_THOUGHT_TYPES) perType[t] = null;\n\treturn {\n\t\tbrierScore: null,\n\t\tece: null,\n\t\tsampleCount: 0,\n\t\tperTypeBrier: perType,\n\t};\n}\n\n/**\n * Confidence calibration service.\n *\n * Stateless w.r.t. outcome storage (delegated to {@link IOutcomeRecorder}),\n * but maintains a small per-session temperature cache that is recomputed\n * via {@link Calibrator.refit}.\n *\n * @example\n * ```typescript\n * const calibrator = new Calibrator(outcomeRecorder, true);\n * const result = calibrator.calibrate(0.9, 'hypothesis', 'session-1');\n * console.log(result.calibrated, result.temperature, result.priorWeight);\n * ```\n */\nexport class Calibrator implements ICalibrator {\n\tpublic readonly enabled: boolean;\n\tprivate readonly _recorder: IOutcomeRecorder;\n\tprivate readonly _temperatures = new Map<SessionId, number>();\n\n\tconstructor(outcomeRecorder: IOutcomeRecorder, enabled: boolean) {\n\t\tthis._recorder = outcomeRecorder;\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic calibrate(\n\t\trawConfidence: number,\n\t\ttype: ThoughtType,\n\t\tsessionId: SessionId\n\t): CalibrationResult {\n\t\tconst raw = Math.min(1, Math.max(0, rawConfidence));\n\t\tif (!this.enabled) {\n\t\t\treturn { raw, calibrated: raw, temperature: 1.0, priorWeight: 0 };\n\t\t}\n\t\tconst outcomes = this._recorder.getOutcomes(sessionId);\n\t\tconst perType = aggregatePerType(outcomes);\n\t\tconst typeStats = perType.get(type);\n\t\tconst n = typeStats?.count ?? 0;\n\t\tconst observedMean = typeStats?.mean ?? 0.5;\n\t\tconst priorWeight = 1 / (1 + n / 10);\n\t\tconst shrunk = priorWeight * observedMean + (1 - priorWeight) * raw;\n\t\tconst temperature = this._temperatures.get(sessionId) ?? 1.0;\n\t\tconst calibrated =\n\t\t\toutcomes.length >= MIN_OUTCOMES_FOR_TEMPERATURE\n\t\t\t\t? applyTemperature(shrunk, temperature)\n\t\t\t\t: shrunk;\n\t\treturn { raw, calibrated, temperature, priorWeight };\n\t}\n\n\tpublic metrics(sessionId?: SessionId): CalibrationMetrics {\n\t\tif (!this.enabled) return emptyMetrics();\n\t\tconst outcomes =\n\t\t\tsessionId === undefined\n\t\t\t\t? this._recorder.getAllOutcomes()\n\t\t\t\t: this._recorder.getOutcomes(sessionId);\n\t\treturn {\n\t\t\tbrierScore: brierScore(outcomes),\n\t\t\tece: expectedCalibrationError(outcomes),\n\t\t\tsampleCount: outcomes.length,\n\t\t\tperTypeBrier: perTypeBrier(outcomes),\n\t\t};\n\t}\n\n\tpublic refit(sessionId: SessionId): void {\n\t\tif (!this.enabled) return;\n\t\tthis._temperatures.set(sessionId, fitTemperature(this._recorder.getOutcomes(sessionId)));\n\t}\n\n\tpublic clearSession(sessionId: SessionId): void {\n\t\tif (!this.enabled) return;\n\t\tthis._temperatures.delete(sessionId);\n\t}\n\n\tpublic clearAll(): void {\n\t\tif (!this.enabled) return;\n\t\tthis._temperatures.clear();\n\t}\n}\n"],"names":["ECE_BINS","aggregatePerType","outcomes","sums","Map","o","prev","result","type","sum","count","brierScore","diff","expectedCalibrationError","binConfSum","Array","binAccSum","binCount","p","Math","EPSILON","idx","total","ece","i","n","meanConf","meanAcc","perTypeBrier","buckets","list","t","ALL_THOUGHT_TYPES","emptyMetrics","perType","Calibrator","outcomeRecorder","enabled","rawConfidence","sessionId","raw","typeStats","observedMean","priorWeight","shrunk","temperature","calibrated","MIN_OUTCOMES_FOR_TEMPERATURE","applyTemperature","undefined","fitTemperature"],"mappings":"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"}
@@ -10,7 +10,8 @@
10
10
  *
11
11
  * @module core/evaluator/SignalComputer
12
12
  */
13
- import type { ConfidenceSignals, ThoughtType } from '../reasoning.js';
13
+ import type { ThoughtType } from '../../contracts/reasoning-types.js';
14
+ import type { ConfidenceSignals } from '../reasoning.js';
14
15
  import type { ThoughtData } from '../thought.js';
15
16
  /** Result of {@link SignalComputer.computeStructuralQuality}. */
16
17
  interface StructuralQualityResult {
@@ -1 +1 @@
1
- {"version":3,"file":"SignalComputer.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/SignalComputer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAgBjD,iEAAiE;AACjE,UAAU,uBAAuB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE;QACX,cAAc,EAAE,MAAM,CAAC;QACvB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,gBAAgB,EAAE,MAAM,CAAC;QACzB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,CAAC;IACF,cAAc,EAAE;QACf,cAAc,EAAE,MAAM,CAAC;QACvB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,gBAAgB,EAAE,MAAM,CAAC;QACzB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,CAAC;CACF;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAK5B;IAEX;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAIlC;IAEX;;;;;;OAMG;IACI,wBAAwB,CAC9B,OAAO,EAAE,WAAW,EAAE,EACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,GACrC,iBAAiB;IAiCpB;;;;;;;;;;;;;;;OAeG;IACI,wBAAwB,CAC9B,OAAO,EAAE,WAAW,EAAE,EACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EACvC,gBAAgB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,EAC7C,WAAW,EAAE,MAAM,EAAE,GACnB,uBAAuB,GAAG,IAAI;IA+EjC;;;;;;OAMG;IACI,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;IAUvE;;;;;;OAMG;IACI,6BAA6B,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;CAS1E"}
1
+ {"version":3,"file":"SignalComputer.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/SignalComputer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAgBjD,iEAAiE;AACjE,UAAU,uBAAuB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE;QACX,cAAc,EAAE,MAAM,CAAC;QACvB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,gBAAgB,EAAE,MAAM,CAAC;QACzB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,CAAC;IACF,cAAc,EAAE;QACf,cAAc,EAAE,MAAM,CAAC;QACvB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,gBAAgB,EAAE,MAAM,CAAC;QACzB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,CAAC;CACF;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAK5B;IAEX;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAIlC;IAEX;;;;;;OAMG;IACI,wBAAwB,CAC9B,OAAO,EAAE,WAAW,EAAE,EACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,GACrC,iBAAiB;IAiCpB;;;;;;;;;;;;;;;OAeG;IACI,wBAAwB,CAC9B,OAAO,EAAE,WAAW,EAAE,EACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EACvC,gBAAgB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,EAC7C,WAAW,EAAE,MAAM,EAAE,GACnB,uBAAuB,GAAG,IAAI;IA+EjC;;;;;;OAMG;IACI,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;IAUvE;;;;;;OAMG;IACI,6BAA6B,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;CAS1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"core/evaluator/SignalComputer.js","sources":["../../../src/core/evaluator/SignalComputer.ts"],"sourcesContent":["/**\n * Confidence signal computation for sequential thinking.\n *\n * Provides {@link SignalComputer} — a pure stateless service that computes\n * {@link ConfidenceSignals} (including the composite `structural_quality`\n * score and its components) from thought history and branch data.\n *\n * Extracted from `ThoughtEvaluator` as part of the evaluator decomposition.\n * All methods are pure: no side effects, no I/O, no internal state.\n *\n * @module core/evaluator/SignalComputer\n */\n\nimport type { ConfidenceSignals, ThoughtType } from '../reasoning.js';\nimport type { ThoughtData } from '../thought.js';\nimport { ALL_THOUGHT_TYPES, _computeChainDepth, _countByType } from './internals.js';\n\n/** Floor value applied to each quality component to prevent geometric mean collapse. */\nconst FLOOR = 0.01;\n\n/**\n * Round a numeric value to a fixed number of decimal places to mitigate\n * IEEE 754 floating-point accumulation errors (e.g. 0.9 + 0.8 averaging to\n * 0.8500000000000001 instead of 0.85).\n */\nfunction roundToPrecision(value: number, decimals: number = 10): number {\n\tconst factor = Math.pow(10, decimals);\n\treturn Math.round(value * factor) / factor;\n}\n\n/** Result of {@link SignalComputer.computeStructuralQuality}. */\ninterface StructuralQualityResult {\n\tscore: number;\n\tcomponents: {\n\t\ttype_diversity: number;\n\t\tverification_coverage: number;\n\t\tdepth_efficiency: number;\n\t\tconfidence_stability: number | null;\n\t};\n\traw_components: {\n\t\ttype_diversity: number;\n\t\tverification_coverage: number;\n\t\tdepth_efficiency: number;\n\t\tconfidence_stability: number | null;\n\t};\n}\n\n/**\n * Stateless service that computes {@link ConfidenceSignals} from thought history.\n *\n * @remarks\n * Pure computation — no side effects, no I/O, no internal state.\n * Safe to register as singleton or transient in DI.\n */\nexport class SignalComputer {\n\t/**\n\t * Structural quality weight configuration.\n\t *\n\t * Weights reflect the relative importance of each quality dimension:\n\t * - type_diversity (0.3): Shannon entropy of thought types — rewards reasoning that uses\n\t * multiple cognitive modes (hypothesis, verification, critique, synthesis) rather than\n\t * monotonic sequences. Based on information theory: higher entropy = more information.\n\t *\n\t * - verification_coverage (0.3): Ratio of verified to total hypotheses — rewards scientific\n\t * rigor. Hypotheses without verification are speculation; verification grounds reasoning.\n\t * Equal weight with diversity because unverified reasoning is a common failure mode.\n\t *\n\t * - depth_efficiency (0.2): Ratio of structural depth to total thoughts — rewards efficient\n\t * reasoning. Deep chains (many revisions/branches) are good; but only if proportionally\n\t * dense. Padding with low-value thoughts penalizes this metric.\n\t *\n\t * - confidence_stability (0.2): Low variance in self-assessed confidence — rewards calibrated\n\t * reasoning. Wildly fluctuating confidence suggests uncertainty about the approach.\n\t * Lower weight because confidence values are LLM self-reports (inherently noisy).\n\t *\n\t * Design rationale:\n\t * - Diversity + Verification (0.6) > Depth + Stability (0.4): Structural properties of the\n\t * reasoning DAG are more important than behavioral signals.\n\t * - All weights are positive (no dimension is penalizing).\n\t * - Weights sum to 1.0 for normalized scoring.\n\t * - When confidence_stability is unavailable (n<2), remaining weights redistribute\n\t * proportionally: td→0.375, vc→0.375, de→0.25 (preserving relative ratios).\n\t */\n\tprivate static readonly QUALITY_WEIGHTS = {\n\t\ttypeDiversity: 0.3,\n\t\tverificationCoverage: 0.3,\n\t\tdepthEfficiency: 0.2,\n\t\tconfidenceStability: 0.2,\n\t} as const;\n\n\t/**\n\t * Redistributed weights when confidence_stability is excluded (n<2).\n\t * Preserves relative ratios of remaining components (sum = 1.0).\n\t */\n\tprivate static readonly QUALITY_WEIGHTS_NO_CS = {\n\t\ttypeDiversity: 0.375,\n\t\tverificationCoverage: 0.375,\n\t\tdepthEfficiency: 0.25,\n\t} as const;\n\n\t/**\n\t * Compute confidence signals from history context.\n\t *\n\t * @param history - All thoughts in the current session\n\t * @param branches - Map of branch IDs to their thought arrays\n\t * @returns Computed confidence signals reflecting reasoning quality\n\t */\n\tpublic computeConfidenceSignals(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): ConfidenceSignals {\n\t\tconst typeDistribution = _countByType(history);\n\t\tconst allConfidences = history\n\t\t\t.map((t) => t.confidence)\n\t\t\t.filter((c): c is number => c !== undefined);\n\n\t\t// Compute structural quality components\n\t\tconst structuralResult = this.computeStructuralQuality(\n\t\t\thistory,\n\t\t\tbranches,\n\t\t\ttypeDistribution,\n\t\t\tallConfidences\n\t\t);\n\n\t\treturn {\n\t\t\treasoning_depth: history.length,\n\t\t\trevision_count: history.filter((t) => t.is_revision).length,\n\t\t\tbranch_count: Object.keys(branches).length,\n\t\t\tthought_type_distribution: typeDistribution,\n\t\t\thas_hypothesis: history.some((t) => t.thought_type === 'hypothesis'),\n\t\t\thas_verification: history.some((t) => t.thought_type === 'verification'),\n\t\t\taverage_confidence:\n\t\t\t\tallConfidences.length > 0\n\t\t\t\t\t? roundToPrecision(allConfidences.reduce((a, b) => a + b, 0) / allConfidences.length)\n\t\t\t\t\t: null,\n\t\t\t...(structuralResult !== null && {\n\t\t\t\tstructural_quality: structuralResult.score,\n\t\t\t\tquality_components: structuralResult.components,\n\t\t\t\tquality_components_raw: structuralResult.raw_components,\n\t\t\t}),\n\t\t};\n\t}\n\n\t/**\n\t * Compute the composite structural quality score and its components.\n\t *\n\t * Algorithm (all components floored at {@link FLOOR} = 0.01):\n\t * - `type_diversity` = Shannon entropy of thought_type distribution / log2(6)\n\t * - `verification_coverage` = verified_hypotheses / max(total_hypotheses, 1) (1.0 if none)\n\t * - `depth_efficiency` = max(chain_depth, branch_count + 1) / total_thoughts, clamped to 1.0\n\t * - `confidence_stability` = 1 - stddev(confidences), default 0.5 when empty, null when single value\n\t * - `structural_quality` = td^0.3 * vc^0.3 * de^0.2 * cs^0.2 (weighted geometric mean)\n\t *\n\t * Note: When confidence_stability is null (fewer than 2 confidence values), it is\n\t * excluded from the geometric mean and the remaining weights are redistributed\n\t * proportionally (td→0.375, vc→0.375, de→0.25).\n\t *\n\t * @returns Score + components, or `null` when history is empty\n\t */\n\tpublic computeStructuralQuality(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>,\n\t\ttypeDistribution: Record<ThoughtType, number>,\n\t\tconfidences: number[]\n\t): StructuralQualityResult | null {\n\t\tif (history.length === 0) return null;\n\n\t\t// 1. type_diversity: Shannon entropy / log2(6)\n\t\tconst total = history.length;\n\t\tlet entropy = 0;\n\t\tfor (const type of ALL_THOUGHT_TYPES) {\n\t\t\tconst count = typeDistribution[type];\n\t\t\tif (count > 0) {\n\t\t\t\tconst pk = count / total;\n\t\t\t\tentropy -= pk * Math.log2(pk);\n\t\t\t}\n\t\t}\n\t\tconst rawTypeDiversity = entropy / Math.log2(6);\n\t\tconst typeDiversity = Math.max(rawTypeDiversity, FLOOR);\n\n\t\t// 2. verification_coverage: verified / total hypotheses (1.0 if none)\n\t\tconst hypotheses = history.filter((t) => t.thought_type === 'hypothesis');\n\t\tconst hypothesisIds = new Set(hypotheses.map((t) => t.hypothesis_id).filter(Boolean));\n\t\tconst verifiedIds = new Set(\n\t\t\thistory\n\t\t\t\t.filter((t) => t.thought_type === 'verification' && t.hypothesis_id)\n\t\t\t\t.map((t) => t.hypothesis_id)\n\t\t);\n\t\tconst rawVerificationCoverage =\n\t\t\thypothesisIds.size === 0\n\t\t\t\t? 1.0\n\t\t\t\t: [...hypothesisIds].filter((id) => verifiedIds.has(id)).length / hypothesisIds.size;\n\t\tconst verificationCoverage = Math.max(rawVerificationCoverage, FLOOR);\n\n\t\t// 3. depth_efficiency: max(chain_depth, branch_count + 1) / total_thoughts, clamped to 1.0\n\t\t// NOTE (Metis H3): Branching is desirable — treat branches as depth-equivalent.\n\t\tconst chainDepth = _computeChainDepth(history);\n\t\tconst branchCount = Object.keys(branches).length;\n\t\tconst effectiveDepth = Math.max(chainDepth, branchCount + 1);\n\t\tconst rawDepthEfficiency = Math.min(effectiveDepth / total, 1.0);\n\t\tconst depthEfficiency = Math.max(rawDepthEfficiency, FLOOR);\n\n\t\t// 4. confidence_stability: 1 - stddev(confidences), default 0.5\n\t\tconst confidenceStability = this.computeConfidenceStability(confidences);\n\t\tconst rawConfidenceStability = this.computeRawConfidenceStability(confidences);\n\n\t\tconst components: StructuralQualityResult['components'] = {\n\t\t\ttype_diversity: typeDiversity,\n\t\t\tverification_coverage: verificationCoverage,\n\t\t\tdepth_efficiency: depthEfficiency,\n\t\t\tconfidence_stability: confidenceStability,\n\t\t};\n\n\t\tconst rawComponents: StructuralQualityResult['raw_components'] = {\n\t\t\ttype_diversity: rawTypeDiversity,\n\t\t\tverification_coverage: rawVerificationCoverage,\n\t\t\tdepth_efficiency: rawDepthEfficiency,\n\t\t\tconfidence_stability: rawConfidenceStability,\n\t\t};\n\n\t\t// Weighted geometric mean: td^0.3 * vc^0.3 * de^0.2 * cs^0.2\n\t\t// When confidence_stability is null (n<2), exclude it from the geomean\n\t\t// and redistribute its weight proportionally to remaining components\n\t\t// (normalized td=0.375, vc=0.375, de=0.25)\n\t\tlet score: number;\n\t\tif (confidenceStability !== null) {\n\t\t\tconst w = SignalComputer.QUALITY_WEIGHTS;\n\t\t\tscore =\n\t\t\t\tMath.pow(typeDiversity, w.typeDiversity) *\n\t\t\t\tMath.pow(verificationCoverage, w.verificationCoverage) *\n\t\t\t\tMath.pow(depthEfficiency, w.depthEfficiency) *\n\t\t\t\tMath.pow(confidenceStability, w.confidenceStability);\n\t\t} else {\n\t\t\tconst w3 = SignalComputer.QUALITY_WEIGHTS_NO_CS;\n\t\t\tscore =\n\t\t\t\tMath.pow(typeDiversity, w3.typeDiversity) *\n\t\t\t\tMath.pow(verificationCoverage, w3.verificationCoverage) *\n\t\t\t\tMath.pow(depthEfficiency, w3.depthEfficiency);\n\t\t}\n\n\t\treturn { score, components, raw_components: rawComponents };\n\t}\n\n\t/**\n\t * Compute confidence stability: 1 - stddev(confidences).\n\t *\n\t * - Empty input → 0.5 (neutral default)\n\t * - Single value → null (insufficient data, excluded from structural quality)\n\t * - Otherwise → max(1 - stddev, FLOOR)\n\t */\n\tpublic computeConfidenceStability(confidences: number[]): number | null {\n\t\tif (confidences.length === 0) return 0.5;\n\t\tif (confidences.length === 1) return null;\n\n\t\tconst mean = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n\t\tconst variance = confidences.reduce((sum, c) => sum + (c - mean) ** 2, 0) / confidences.length;\n\t\tconst stddev = Math.sqrt(variance);\n\t\treturn Math.max(1 - stddev, FLOOR);\n\t}\n\n\t/**\n\t * Compute raw (unfloored) confidence stability: 1 - stddev(confidences).\n\t *\n\t * - Empty input → 0.5 (neutral default)\n\t * - Single value → null (insufficient data)\n\t * - Otherwise → 1 - stddev (may be below FLOOR)\n\t */\n\tpublic computeRawConfidenceStability(confidences: number[]): number | null {\n\t\tif (confidences.length === 0) return 0.5;\n\t\tif (confidences.length === 1) return null;\n\n\t\tconst mean = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n\t\tconst variance = confidences.reduce((sum, c) => sum + (c - mean) ** 2, 0) / confidences.length;\n\t\tconst stddev = Math.sqrt(variance);\n\t\treturn 1 - stddev;\n\t}\n}\n"],"names":["FLOOR","roundToPrecision","value","decimals","factor","Math","SignalComputer","history","branches","typeDistribution","_countByType","allConfidences","t","c","undefined","structuralResult","Object","a","b","confidences","total","entropy","type","ALL_THOUGHT_TYPES","count","pk","rawTypeDiversity","typeDiversity","hypotheses","hypothesisIds","Set","Boolean","verifiedIds","rawVerificationCoverage","id","verificationCoverage","chainDepth","_computeChainDepth","branchCount","effectiveDepth","rawDepthEfficiency","depthEfficiency","confidenceStability","rawConfidenceStability","components","rawComponents","score","w","w3","mean","variance","sum","stddev"],"mappings":"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"}
1
+ {"version":3,"file":"core/evaluator/SignalComputer.js","sources":["../../../src/core/evaluator/SignalComputer.ts"],"sourcesContent":["/**\n * Confidence signal computation for sequential thinking.\n *\n * Provides {@link SignalComputer} — a pure stateless service that computes\n * {@link ConfidenceSignals} (including the composite `structural_quality`\n * score and its components) from thought history and branch data.\n *\n * Extracted from `ThoughtEvaluator` as part of the evaluator decomposition.\n * All methods are pure: no side effects, no I/O, no internal state.\n *\n * @module core/evaluator/SignalComputer\n */\n\nimport type { ThoughtType } from '../../contracts/reasoning-types.js';\nimport type { ConfidenceSignals } from '../reasoning.js';\nimport type { ThoughtData } from '../thought.js';\nimport { ALL_THOUGHT_TYPES, _computeChainDepth, _countByType } from './internals.js';\n\n/** Floor value applied to each quality component to prevent geometric mean collapse. */\nconst FLOOR = 0.01;\n\n/**\n * Round a numeric value to a fixed number of decimal places to mitigate\n * IEEE 754 floating-point accumulation errors (e.g. 0.9 + 0.8 averaging to\n * 0.8500000000000001 instead of 0.85).\n */\nfunction roundToPrecision(value: number, decimals: number = 10): number {\n\tconst factor = Math.pow(10, decimals);\n\treturn Math.round(value * factor) / factor;\n}\n\n/** Result of {@link SignalComputer.computeStructuralQuality}. */\ninterface StructuralQualityResult {\n\tscore: number;\n\tcomponents: {\n\t\ttype_diversity: number;\n\t\tverification_coverage: number;\n\t\tdepth_efficiency: number;\n\t\tconfidence_stability: number | null;\n\t};\n\traw_components: {\n\t\ttype_diversity: number;\n\t\tverification_coverage: number;\n\t\tdepth_efficiency: number;\n\t\tconfidence_stability: number | null;\n\t};\n}\n\n/**\n * Stateless service that computes {@link ConfidenceSignals} from thought history.\n *\n * @remarks\n * Pure computation — no side effects, no I/O, no internal state.\n * Safe to register as singleton or transient in DI.\n */\nexport class SignalComputer {\n\t/**\n\t * Structural quality weight configuration.\n\t *\n\t * Weights reflect the relative importance of each quality dimension:\n\t * - type_diversity (0.3): Shannon entropy of thought types — rewards reasoning that uses\n\t * multiple cognitive modes (hypothesis, verification, critique, synthesis) rather than\n\t * monotonic sequences. Based on information theory: higher entropy = more information.\n\t *\n\t * - verification_coverage (0.3): Ratio of verified to total hypotheses — rewards scientific\n\t * rigor. Hypotheses without verification are speculation; verification grounds reasoning.\n\t * Equal weight with diversity because unverified reasoning is a common failure mode.\n\t *\n\t * - depth_efficiency (0.2): Ratio of structural depth to total thoughts — rewards efficient\n\t * reasoning. Deep chains (many revisions/branches) are good; but only if proportionally\n\t * dense. Padding with low-value thoughts penalizes this metric.\n\t *\n\t * - confidence_stability (0.2): Low variance in self-assessed confidence — rewards calibrated\n\t * reasoning. Wildly fluctuating confidence suggests uncertainty about the approach.\n\t * Lower weight because confidence values are LLM self-reports (inherently noisy).\n\t *\n\t * Design rationale:\n\t * - Diversity + Verification (0.6) > Depth + Stability (0.4): Structural properties of the\n\t * reasoning DAG are more important than behavioral signals.\n\t * - All weights are positive (no dimension is penalizing).\n\t * - Weights sum to 1.0 for normalized scoring.\n\t * - When confidence_stability is unavailable (n<2), remaining weights redistribute\n\t * proportionally: td→0.375, vc→0.375, de→0.25 (preserving relative ratios).\n\t */\n\tprivate static readonly QUALITY_WEIGHTS = {\n\t\ttypeDiversity: 0.3,\n\t\tverificationCoverage: 0.3,\n\t\tdepthEfficiency: 0.2,\n\t\tconfidenceStability: 0.2,\n\t} as const;\n\n\t/**\n\t * Redistributed weights when confidence_stability is excluded (n<2).\n\t * Preserves relative ratios of remaining components (sum = 1.0).\n\t */\n\tprivate static readonly QUALITY_WEIGHTS_NO_CS = {\n\t\ttypeDiversity: 0.375,\n\t\tverificationCoverage: 0.375,\n\t\tdepthEfficiency: 0.25,\n\t} as const;\n\n\t/**\n\t * Compute confidence signals from history context.\n\t *\n\t * @param history - All thoughts in the current session\n\t * @param branches - Map of branch IDs to their thought arrays\n\t * @returns Computed confidence signals reflecting reasoning quality\n\t */\n\tpublic computeConfidenceSignals(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>\n\t): ConfidenceSignals {\n\t\tconst typeDistribution = _countByType(history);\n\t\tconst allConfidences = history\n\t\t\t.map((t) => t.confidence)\n\t\t\t.filter((c): c is number => c !== undefined);\n\n\t\t// Compute structural quality components\n\t\tconst structuralResult = this.computeStructuralQuality(\n\t\t\thistory,\n\t\t\tbranches,\n\t\t\ttypeDistribution,\n\t\t\tallConfidences\n\t\t);\n\n\t\treturn {\n\t\t\treasoning_depth: history.length,\n\t\t\trevision_count: history.filter((t) => t.is_revision).length,\n\t\t\tbranch_count: Object.keys(branches).length,\n\t\t\tthought_type_distribution: typeDistribution,\n\t\t\thas_hypothesis: history.some((t) => t.thought_type === 'hypothesis'),\n\t\t\thas_verification: history.some((t) => t.thought_type === 'verification'),\n\t\t\taverage_confidence:\n\t\t\t\tallConfidences.length > 0\n\t\t\t\t\t? roundToPrecision(allConfidences.reduce((a, b) => a + b, 0) / allConfidences.length)\n\t\t\t\t\t: null,\n\t\t\t...(structuralResult !== null && {\n\t\t\t\tstructural_quality: structuralResult.score,\n\t\t\t\tquality_components: structuralResult.components,\n\t\t\t\tquality_components_raw: structuralResult.raw_components,\n\t\t\t}),\n\t\t};\n\t}\n\n\t/**\n\t * Compute the composite structural quality score and its components.\n\t *\n\t * Algorithm (all components floored at {@link FLOOR} = 0.01):\n\t * - `type_diversity` = Shannon entropy of thought_type distribution / log2(6)\n\t * - `verification_coverage` = verified_hypotheses / max(total_hypotheses, 1) (1.0 if none)\n\t * - `depth_efficiency` = max(chain_depth, branch_count + 1) / total_thoughts, clamped to 1.0\n\t * - `confidence_stability` = 1 - stddev(confidences), default 0.5 when empty, null when single value\n\t * - `structural_quality` = td^0.3 * vc^0.3 * de^0.2 * cs^0.2 (weighted geometric mean)\n\t *\n\t * Note: When confidence_stability is null (fewer than 2 confidence values), it is\n\t * excluded from the geometric mean and the remaining weights are redistributed\n\t * proportionally (td→0.375, vc→0.375, de→0.25).\n\t *\n\t * @returns Score + components, or `null` when history is empty\n\t */\n\tpublic computeStructuralQuality(\n\t\thistory: ThoughtData[],\n\t\tbranches: Record<string, ThoughtData[]>,\n\t\ttypeDistribution: Record<ThoughtType, number>,\n\t\tconfidences: number[]\n\t): StructuralQualityResult | null {\n\t\tif (history.length === 0) return null;\n\n\t\t// 1. type_diversity: Shannon entropy / log2(6)\n\t\tconst total = history.length;\n\t\tlet entropy = 0;\n\t\tfor (const type of ALL_THOUGHT_TYPES) {\n\t\t\tconst count = typeDistribution[type];\n\t\t\tif (count > 0) {\n\t\t\t\tconst pk = count / total;\n\t\t\t\tentropy -= pk * Math.log2(pk);\n\t\t\t}\n\t\t}\n\t\tconst rawTypeDiversity = entropy / Math.log2(6);\n\t\tconst typeDiversity = Math.max(rawTypeDiversity, FLOOR);\n\n\t\t// 2. verification_coverage: verified / total hypotheses (1.0 if none)\n\t\tconst hypotheses = history.filter((t) => t.thought_type === 'hypothesis');\n\t\tconst hypothesisIds = new Set(hypotheses.map((t) => t.hypothesis_id).filter(Boolean));\n\t\tconst verifiedIds = new Set(\n\t\t\thistory\n\t\t\t\t.filter((t) => t.thought_type === 'verification' && t.hypothesis_id)\n\t\t\t\t.map((t) => t.hypothesis_id)\n\t\t);\n\t\tconst rawVerificationCoverage =\n\t\t\thypothesisIds.size === 0\n\t\t\t\t? 1.0\n\t\t\t\t: [...hypothesisIds].filter((id) => verifiedIds.has(id)).length / hypothesisIds.size;\n\t\tconst verificationCoverage = Math.max(rawVerificationCoverage, FLOOR);\n\n\t\t// 3. depth_efficiency: max(chain_depth, branch_count + 1) / total_thoughts, clamped to 1.0\n\t\t// NOTE (Metis H3): Branching is desirable — treat branches as depth-equivalent.\n\t\tconst chainDepth = _computeChainDepth(history);\n\t\tconst branchCount = Object.keys(branches).length;\n\t\tconst effectiveDepth = Math.max(chainDepth, branchCount + 1);\n\t\tconst rawDepthEfficiency = Math.min(effectiveDepth / total, 1.0);\n\t\tconst depthEfficiency = Math.max(rawDepthEfficiency, FLOOR);\n\n\t\t// 4. confidence_stability: 1 - stddev(confidences), default 0.5\n\t\tconst confidenceStability = this.computeConfidenceStability(confidences);\n\t\tconst rawConfidenceStability = this.computeRawConfidenceStability(confidences);\n\n\t\tconst components: StructuralQualityResult['components'] = {\n\t\t\ttype_diversity: typeDiversity,\n\t\t\tverification_coverage: verificationCoverage,\n\t\t\tdepth_efficiency: depthEfficiency,\n\t\t\tconfidence_stability: confidenceStability,\n\t\t};\n\n\t\tconst rawComponents: StructuralQualityResult['raw_components'] = {\n\t\t\ttype_diversity: rawTypeDiversity,\n\t\t\tverification_coverage: rawVerificationCoverage,\n\t\t\tdepth_efficiency: rawDepthEfficiency,\n\t\t\tconfidence_stability: rawConfidenceStability,\n\t\t};\n\n\t\t// Weighted geometric mean: td^0.3 * vc^0.3 * de^0.2 * cs^0.2\n\t\t// When confidence_stability is null (n<2), exclude it from the geomean\n\t\t// and redistribute its weight proportionally to remaining components\n\t\t// (normalized td=0.375, vc=0.375, de=0.25)\n\t\tlet score: number;\n\t\tif (confidenceStability !== null) {\n\t\t\tconst w = SignalComputer.QUALITY_WEIGHTS;\n\t\t\tscore =\n\t\t\t\tMath.pow(typeDiversity, w.typeDiversity) *\n\t\t\t\tMath.pow(verificationCoverage, w.verificationCoverage) *\n\t\t\t\tMath.pow(depthEfficiency, w.depthEfficiency) *\n\t\t\t\tMath.pow(confidenceStability, w.confidenceStability);\n\t\t} else {\n\t\t\tconst w3 = SignalComputer.QUALITY_WEIGHTS_NO_CS;\n\t\t\tscore =\n\t\t\t\tMath.pow(typeDiversity, w3.typeDiversity) *\n\t\t\t\tMath.pow(verificationCoverage, w3.verificationCoverage) *\n\t\t\t\tMath.pow(depthEfficiency, w3.depthEfficiency);\n\t\t}\n\n\t\treturn { score, components, raw_components: rawComponents };\n\t}\n\n\t/**\n\t * Compute confidence stability: 1 - stddev(confidences).\n\t *\n\t * - Empty input → 0.5 (neutral default)\n\t * - Single value → null (insufficient data, excluded from structural quality)\n\t * - Otherwise → max(1 - stddev, FLOOR)\n\t */\n\tpublic computeConfidenceStability(confidences: number[]): number | null {\n\t\tif (confidences.length === 0) return 0.5;\n\t\tif (confidences.length === 1) return null;\n\n\t\tconst mean = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n\t\tconst variance = confidences.reduce((sum, c) => sum + (c - mean) ** 2, 0) / confidences.length;\n\t\tconst stddev = Math.sqrt(variance);\n\t\treturn Math.max(1 - stddev, FLOOR);\n\t}\n\n\t/**\n\t * Compute raw (unfloored) confidence stability: 1 - stddev(confidences).\n\t *\n\t * - Empty input → 0.5 (neutral default)\n\t * - Single value → null (insufficient data)\n\t * - Otherwise → 1 - stddev (may be below FLOOR)\n\t */\n\tpublic computeRawConfidenceStability(confidences: number[]): number | null {\n\t\tif (confidences.length === 0) return 0.5;\n\t\tif (confidences.length === 1) return null;\n\n\t\tconst mean = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n\t\tconst variance = confidences.reduce((sum, c) => sum + (c - mean) ** 2, 0) / confidences.length;\n\t\tconst stddev = Math.sqrt(variance);\n\t\treturn 1 - stddev;\n\t}\n}\n"],"names":["FLOOR","roundToPrecision","value","decimals","factor","Math","SignalComputer","history","branches","typeDistribution","_countByType","allConfidences","t","c","undefined","structuralResult","Object","a","b","confidences","total","entropy","type","ALL_THOUGHT_TYPES","count","pk","rawTypeDiversity","typeDiversity","hypotheses","hypothesisIds","Set","Boolean","verifiedIds","rawVerificationCoverage","id","verificationCoverage","chainDepth","_computeChainDepth","branchCount","effectiveDepth","rawDepthEfficiency","depthEfficiency","confidenceStability","rawConfidenceStability","components","rawComponents","score","w","w3","mean","variance","sum","stddev"],"mappings":"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"}
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @module core/evaluator/internals
9
9
  */
10
- import type { ThoughtType } from '../reasoning.js';
10
+ import type { ThoughtType } from '../../contracts/reasoning-types.js';
11
11
  import type { ThoughtData } from '../thought.js';
12
12
  /** All valid thought types for distribution counting. */
13
13
  export declare const ALL_THOUGHT_TYPES: ThoughtType[];
@@ -20,8 +20,6 @@ export declare const ALL_THOUGHT_TYPES: ThoughtType[];
20
20
  * @returns Record mapping each ThoughtType to its occurrence count
21
21
  */
22
22
  export declare function _countByType(history: ThoughtData[]): Record<ThoughtType, number>;
23
- /** Alias of {@link _countByType} without the underscore prefix. */
24
- export declare const countByType: typeof _countByType;
25
23
  /**
26
24
  * Compute the longest contiguous chain depth (sequence of thoughts without branching).
27
25
  *
@@ -31,6 +29,4 @@ export declare const countByType: typeof _countByType;
31
29
  * @returns Length of the longest non-branching chain (0 for empty history)
32
30
  */
33
31
  export declare function _computeChainDepth(history: ThoughtData[]): number;
34
- /** Alias of {@link _computeChainDepth} without the underscore prefix. */
35
- export declare const computeChainDepth: typeof _computeChainDepth;
36
32
  //# sourceMappingURL=internals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"internals.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/internals.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,EAAE,WAAW,EAY1C,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAchF;AAED,mEAAmE;AACnE,eAAO,MAAM,WAAW,qBAAe,CAAC;AAExC;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAgBjE;AAED,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,2BAAqB,CAAC"}
1
+ {"version":3,"file":"internals.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/internals.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,EAAE,WAAW,EAY1C,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAchF;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAgBjE"}
@@ -22,7 +22,6 @@ function _countByType(history) {
22
22
  }
23
23
  return counts;
24
24
  }
25
- const countByType = _countByType;
26
25
  function _computeChainDepth(history) {
27
26
  if (0 === history.length) return 0;
28
27
  let maxDepth = 1;
@@ -37,7 +36,6 @@ function _computeChainDepth(history) {
37
36
  }
38
37
  return maxDepth;
39
38
  }
40
- const computeChainDepth = _computeChainDepth;
41
- export { ALL_THOUGHT_TYPES, _computeChainDepth, _countByType, computeChainDepth, countByType };
39
+ export { ALL_THOUGHT_TYPES, _computeChainDepth, _countByType };
42
40
 
43
41
  //# sourceMappingURL=internals.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"core/evaluator/internals.js","sources":["../../../src/core/evaluator/internals.ts"],"sourcesContent":["/**\n * Shared internal helpers for evaluator submodules.\n *\n * Pure utility functions used by SignalComputer (and future evaluator\n * components such as StatsComputer / PatternDetector). All helpers are\n * stateless and have no side effects.\n *\n * @module core/evaluator/internals\n */\n\nimport type { ThoughtType } from '../reasoning.js';\nimport type { ThoughtData } from '../thought.js';\n\n/** All valid thought types for distribution counting. */\nexport const ALL_THOUGHT_TYPES: ThoughtType[] = [\n\t'regular',\n\t'hypothesis',\n\t'verification',\n\t'critique',\n\t'synthesis',\n\t'meta',\n\t'tool_call',\n\t'tool_observation',\n\t'assumption',\n\t'decomposition',\n\t'backtrack',\n];\n\n/**\n * Count thoughts in `history` grouped by {@link ThoughtType}.\n *\n * Thoughts without an explicit `thought_type` are counted as `'regular'`.\n *\n * @param history - Thoughts to count\n * @returns Record mapping each ThoughtType to its occurrence count\n */\nexport function _countByType(history: ThoughtData[]): Record<ThoughtType, number> {\n\tconst counts = Object.fromEntries(ALL_THOUGHT_TYPES.map((t) => [t, 0])) as Record<\n\t\tThoughtType,\n\t\tnumber\n\t>;\n\n\tfor (const thought of history) {\n\t\tconst type = thought.thought_type ?? 'regular';\n\t\tif (type in counts) {\n\t\t\tcounts[type]++;\n\t\t}\n\t}\n\n\treturn counts;\n}\n\n/** Alias of {@link _countByType} without the underscore prefix. */\nexport const countByType = _countByType;\n\n/**\n * Compute the longest contiguous chain depth (sequence of thoughts without branching).\n *\n * A new chain starts whenever a thought has `branch_from_thought` set.\n *\n * @param history - Thoughts in chronological order\n * @returns Length of the longest non-branching chain (0 for empty history)\n */\nexport function _computeChainDepth(history: ThoughtData[]): number {\n\tif (history.length === 0) return 0;\n\tlet maxDepth = 1;\n\tlet currentDepth = 1;\n\n\tfor (let i = 1; i < history.length; i++) {\n\t\tconst thought = history[i]!;\n\t\tif (!thought.branch_from_thought) {\n\t\t\tcurrentDepth++;\n\t\t\tmaxDepth = Math.max(maxDepth, currentDepth);\n\t\t} else {\n\t\t\tcurrentDepth = 1;\n\t\t}\n\t}\n\n\treturn maxDepth;\n}\n\n/** Alias of {@link _computeChainDepth} without the underscore prefix. */\nexport const computeChainDepth = _computeChainDepth;\n"],"names":["ALL_THOUGHT_TYPES","_countByType","history","counts","Object","t","thought","type","countByType","_computeChainDepth","maxDepth","currentDepth","i","Math","computeChainDepth"],"mappings":"AAcO,MAAMA,oBAAmC;IAC/C;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACA;AAUM,SAASC,aAAaC,OAAsB;IAClD,MAAMC,SAASC,OAAO,WAAW,CAACJ,kBAAkB,GAAG,CAAC,CAACK,IAAM;YAACA;YAAG;SAAE;IAKrE,KAAK,MAAMC,WAAWJ,QAAS;QAC9B,MAAMK,OAAOD,QAAQ,YAAY,IAAI;QACrC,IAAIC,QAAQJ,QACXA,MAAM,CAACI,KAAK;IAEd;IAEA,OAAOJ;AACR;AAGO,MAAMK,cAAcP;AAUpB,SAASQ,mBAAmBP,OAAsB;IACxD,IAAIA,AAAmB,MAAnBA,QAAQ,MAAM,EAAQ,OAAO;IACjC,IAAIQ,WAAW;IACf,IAAIC,eAAe;IAEnB,IAAK,IAAIC,IAAI,GAAGA,IAAIV,QAAQ,MAAM,EAAEU,IAAK;QACxC,MAAMN,UAAUJ,OAAO,CAACU,EAAE;QAC1B,IAAKN,QAAQ,mBAAmB,EAI/BK,eAAe;aAJkB;YACjCA;YACAD,WAAWG,KAAK,GAAG,CAACH,UAAUC;QAC/B;IAGD;IAEA,OAAOD;AACR;AAGO,MAAMI,oBAAoBL"}
1
+ {"version":3,"file":"core/evaluator/internals.js","sources":["../../../src/core/evaluator/internals.ts"],"sourcesContent":["/**\n * Shared internal helpers for evaluator submodules.\n *\n * Pure utility functions used by SignalComputer (and future evaluator\n * components such as StatsComputer / PatternDetector). All helpers are\n * stateless and have no side effects.\n *\n * @module core/evaluator/internals\n */\n\nimport type { ThoughtType } from '../../contracts/reasoning-types.js';\nimport type { ThoughtData } from '../thought.js';\n\n/** All valid thought types for distribution counting. */\nexport const ALL_THOUGHT_TYPES: ThoughtType[] = [\n\t'regular',\n\t'hypothesis',\n\t'verification',\n\t'critique',\n\t'synthesis',\n\t'meta',\n\t'tool_call',\n\t'tool_observation',\n\t'assumption',\n\t'decomposition',\n\t'backtrack',\n];\n\n/**\n * Count thoughts in `history` grouped by {@link ThoughtType}.\n *\n * Thoughts without an explicit `thought_type` are counted as `'regular'`.\n *\n * @param history - Thoughts to count\n * @returns Record mapping each ThoughtType to its occurrence count\n */\nexport function _countByType(history: ThoughtData[]): Record<ThoughtType, number> {\n\tconst counts = Object.fromEntries(ALL_THOUGHT_TYPES.map((t) => [t, 0])) as Record<\n\t\tThoughtType,\n\t\tnumber\n\t>;\n\n\tfor (const thought of history) {\n\t\tconst type = thought.thought_type ?? 'regular';\n\t\tif (type in counts) {\n\t\t\tcounts[type]++;\n\t\t}\n\t}\n\n\treturn counts;\n}\n\n/**\n * Compute the longest contiguous chain depth (sequence of thoughts without branching).\n *\n * A new chain starts whenever a thought has `branch_from_thought` set.\n *\n * @param history - Thoughts in chronological order\n * @returns Length of the longest non-branching chain (0 for empty history)\n */\nexport function _computeChainDepth(history: ThoughtData[]): number {\n\tif (history.length === 0) return 0;\n\tlet maxDepth = 1;\n\tlet currentDepth = 1;\n\n\tfor (let i = 1; i < history.length; i++) {\n\t\tconst thought = history[i]!;\n\t\tif (!thought.branch_from_thought) {\n\t\t\tcurrentDepth++;\n\t\t\tmaxDepth = Math.max(maxDepth, currentDepth);\n\t\t} else {\n\t\t\tcurrentDepth = 1;\n\t\t}\n\t}\n\n\treturn maxDepth;\n}\n"],"names":["ALL_THOUGHT_TYPES","_countByType","history","counts","Object","t","thought","type","_computeChainDepth","maxDepth","currentDepth","i","Math"],"mappings":"AAcO,MAAMA,oBAAmC;IAC/C;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACA;AAUM,SAASC,aAAaC,OAAsB;IAClD,MAAMC,SAASC,OAAO,WAAW,CAACJ,kBAAkB,GAAG,CAAC,CAACK,IAAM;YAACA;YAAG;SAAE;IAKrE,KAAK,MAAMC,WAAWJ,QAAS;QAC9B,MAAMK,OAAOD,QAAQ,YAAY,IAAI;QACrC,IAAIC,QAAQJ,QACXA,MAAM,CAACI,KAAK;IAEd;IAEA,OAAOJ;AACR;AAUO,SAASK,mBAAmBN,OAAsB;IACxD,IAAIA,AAAmB,MAAnBA,QAAQ,MAAM,EAAQ,OAAO;IACjC,IAAIO,WAAW;IACf,IAAIC,eAAe;IAEnB,IAAK,IAAIC,IAAI,GAAGA,IAAIT,QAAQ,MAAM,EAAES,IAAK;QACxC,MAAML,UAAUJ,OAAO,CAACS,EAAE;QAC1B,IAAKL,QAAQ,mBAAmB,EAI/BI,eAAe;aAJkB;YACjCA;YACAD,WAAWG,KAAK,GAAG,CAACH,UAAUC;QAC/B;IAGD;IAEA,OAAOD;AACR"}
@@ -34,7 +34,7 @@ export type EdgeKind = 'sequence' | 'branch' | 'merge' | 'verifies' | 'critiques
34
34
  * from: parentThought.id,
35
35
  * to: childThought.id,
36
36
  * kind: 'sequence',
37
- * sessionId: '__global__',
37
+ * sessionId: asSessionId('analysis-session'),
38
38
  * createdAt: Date.now(),
39
39
  * };
40
40
  * ```
@@ -10,7 +10,7 @@ import type { IEdgeStore } from '../../contracts/interfaces.js';
10
10
  import type { Logger } from '../../logger/StructuredLogger.js';
11
11
  import type { ThoughtData } from '../thought.js';
12
12
  import type { ThoughtAdmissionContext } from '../IHistoryManager.js';
13
- import { type BranchId, type SessionId } from '../../contracts/ids.js';
13
+ import { type BranchId } from '../../contracts/ids.js';
14
14
  /** Minimal session view needed for edge emission. */
15
15
  export interface EdgeEmissionSession {
16
16
  thought_history: ThoughtData[];
@@ -19,8 +19,7 @@ export interface EdgeEmissionSession {
19
19
  /** Configuration options for EdgeEmitter. */
20
20
  export interface EdgeEmitterConfig {
21
21
  edgeStore?: IEdgeStore;
22
- dagEdges?: boolean;
23
- defaultSessionId: SessionId;
22
+ dagEdges: boolean;
24
23
  logger?: Logger;
25
24
  }
26
25
  /**
@@ -30,7 +29,6 @@ export interface EdgeEmitterConfig {
30
29
  export declare class EdgeEmitter {
31
30
  private readonly _edgeStore?;
32
31
  private readonly _dagEdges;
33
- private readonly _defaultSessionId;
34
32
  private readonly _logger;
35
33
  constructor(config: EdgeEmitterConfig);
36
34
  /** Returns true when edge emission is active (store + flag both set). */
@@ -1 +1 @@
1
- {"version":3,"file":"EdgeEmitter.d.ts","sourceRoot":"","sources":["../../../src/core/graph/EdgeEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAA6B,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhG,OAAO,EAEN,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,MAAM,wBAAwB,CAAC;AAEhC,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IACnC,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;CAC1C;AAED,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IACjC,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,iBAAiB;IAOrC,yEAAyE;IAClE,SAAS,IAAI,OAAO;IAI3B;;;;;;;;;;;;;OAaG;IACI,mBAAmB,CACzB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,uBAAuB,GAC/B,OAAO;IA6BV,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,CAAC,iBAAiB;IAczB;;;;OAIG;IACH,OAAO,CAAC,eAAe;CA2CvB"}
1
+ {"version":3,"file":"EdgeEmitter.d.ts","sourceRoot":"","sources":["../../../src/core/graph/EdgeEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAA6B,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhG,OAAO,EAEN,KAAK,QAAQ,EAGb,MAAM,wBAAwB,CAAC;AAEhC,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IACnC,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;CAC1C;AAED,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IACjC,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,iBAAiB;IAMrC,yEAAyE;IAClE,SAAS,IAAI,OAAO;IAI3B;;;;;;;;;;;;;OAaG;IACI,mBAAmB,CACzB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,uBAAuB,GAC/B,OAAO;IA6BV,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,CAAC,iBAAiB;IAczB;;;;OAIG;IACH,OAAO,CAAC,eAAe;CA2CvB"}
@@ -4,12 +4,10 @@ import { generateEdgeId } from "../../contracts/ids.js";
4
4
  class EdgeEmitter {
5
5
  _edgeStore;
6
6
  _dagEdges;
7
- _defaultSessionId;
8
7
  _logger;
9
8
  constructor(config){
10
9
  this._edgeStore = config.edgeStore;
11
- this._dagEdges = config.dagEdges ?? true;
12
- this._defaultSessionId = config.defaultSessionId;
10
+ this._dagEdges = config.dagEdges;
13
11
  this._logger = config.logger ?? new NullLogger();
14
12
  }
15
13
  isEnabled() {
@@ -18,7 +16,7 @@ class EdgeEmitter {
18
16
  emitEdgesForThought(session, thought, context) {
19
17
  if (!this._edgeStore || !this._dagEdges) return false;
20
18
  if (!thought.id) return false;
21
- const sessionId = thought.session_id ?? this._defaultSessionId;
19
+ const sessionId = thought.session_id;
22
20
  const references = context?.resolvedReferences ?? {};
23
21
  const hasRelationalIntent = void 0 !== thought.branch_from_thought && void 0 !== thought.branch_id || (thought.merge_from_thoughts?.length ?? 0) > 0 || void 0 !== thought.verification_target && ('verification' === thought.thought_type || 'critique' === thought.thought_type) || (thought.synthesis_sources?.length ?? 0) > 0 || void 0 !== thought.revises_thought || 'tool_observation' === thought.thought_type && context?.toolInvocationSourceThoughtId !== void 0;
24
22
  const emittedRelational = [