@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
@@ -1 +1 @@
1
- {"version":3,"file":"core/graph/EdgeEmitter.js","sources":["../../../src/core/graph/EdgeEmitter.ts"],"sourcesContent":["/**\n * EdgeEmitter — emits DAG edges for thoughts based on their metadata.\n *\n * Stateless helper extracted from HistoryManager. Holds a reference to an\n * optional `IEdgeStore` and a feature flag (`dagEdges`) gating writes.\n *\n * @module EdgeEmitter\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport { getErrorMessage } from '../../errors.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport { NullLogger } from '../../logger/NullLogger.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ResolvedThoughtReferences, ThoughtAdmissionContext } from '../IHistoryManager.js';\nimport type { Edge, EdgeKind } from './Edge.js';\nimport {\n\tgenerateEdgeId,\n\ttype BranchId,\n\ttype SessionId,\n\ttype ThoughtId,\n} from '../../contracts/ids.js';\n\n/** Minimal session view needed for edge emission. */\nexport interface EdgeEmissionSession {\n\tthought_history: ThoughtData[];\n\tbranches: Record<BranchId, ThoughtData[]>;\n}\n\n/** Configuration options for EdgeEmitter. */\nexport interface EdgeEmitterConfig {\n\tedgeStore?: IEdgeStore;\n\tdagEdges?: boolean;\n\tdefaultSessionId: SessionId;\n\tlogger?: Logger;\n}\n\n/**\n * Emits DAG edges for thought relationships when an `IEdgeStore` is configured\n * and the `dagEdges` feature flag is enabled. No-ops otherwise.\n */\nexport class EdgeEmitter {\n\tprivate readonly _edgeStore?: IEdgeStore;\n\tprivate readonly _dagEdges: boolean;\n\tprivate readonly _defaultSessionId: SessionId;\n\tprivate readonly _logger: Logger;\n\n\tconstructor(config: EdgeEmitterConfig) {\n\t\tthis._edgeStore = config.edgeStore;\n\t\tthis._dagEdges = config.dagEdges ?? true;\n\t\tthis._defaultSessionId = config.defaultSessionId;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t}\n\n\t/** Returns true when edge emission is active (store + flag both set). */\n\tpublic isEnabled(): boolean {\n\t\treturn this._edgeStore !== undefined && this._dagEdges;\n\t}\n\n\t/**\n\t * Emits DAG edges for a thought based on its metadata fields.\n\t *\n\t * Edge kinds (in priority order):\n\t * - branch: branch_from_thought + branch_id → parent.id → current.id\n\t * - merge: merge_from_thoughts → source.id → current.id (per source)\n\t * - verifies: verification_target + thought_type=verification → current.id → target.id\n\t * - critiques: verification_target + thought_type=critique → current.id → target.id\n\t * - derives_from: synthesis_sources → source.id → current.id (per source)\n\t * - revises: revises_thought → current.id → target.id\n\t * - tool_invocation: stable admission source id → current.id\n\t * - sequence: default chronological link from previous thought (if none of the above)\n\t * @returns True only when at least one edge was added to the store\n\t */\n\tpublic emitEdgesForThought(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (!this._edgeStore || !this._dagEdges) return false;\n\t\tif (!thought.id) return false;\n\n\t\tconst sessionId = thought.session_id ?? this._defaultSessionId;\n\t\tconst references = context?.resolvedReferences ?? {};\n\t\tconst hasRelationalIntent =\n\t\t\t(thought.branch_from_thought !== undefined && thought.branch_id !== undefined) ||\n\t\t\t(thought.merge_from_thoughts?.length ?? 0) > 0 ||\n\t\t\t(thought.verification_target !== undefined &&\n\t\t\t\t(thought.thought_type === 'verification' || thought.thought_type === 'critique')) ||\n\t\t\t(thought.synthesis_sources?.length ?? 0) > 0 ||\n\t\t\tthought.revises_thought !== undefined ||\n\t\t\t(thought.thought_type === 'tool_observation' &&\n\t\t\t\tcontext?.toolInvocationSourceThoughtId !== undefined);\n\t\tconst emittedRelational = [\n\t\t\tthis._emitBranchEdge(thought, references, sessionId),\n\t\t\tthis._emitMergeEdges(thought, references, sessionId),\n\t\t\tthis._emitVerificationEdge(thought, references, sessionId),\n\t\t\tthis._emitCritiqueEdge(thought, references, sessionId),\n\t\t\tthis._emitSynthesisEdges(thought, references, sessionId),\n\t\t\tthis._emitRevisionEdge(thought, references, sessionId),\n\t\t\tthis._emitToolInvocationEdge(thought, sessionId, context),\n\t\t].some((emitted) => emitted);\n\n\t\tif (emittedRelational || hasRelationalIntent) return emittedRelational;\n\t\treturn this._emitSequenceEdge(session, thought, sessionId);\n\t}\n\n\tprivate _emitBranchEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.branch_from_thought === undefined || !thought.branch_id) return false;\n\n\t\treturn this._addEdgeIfValid(references.branchFromThoughtId, thought.id, 'branch', sessionId);\n\t}\n\n\tprivate _emitMergeEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.mergeFromThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'merge', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitVerificationEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'verification')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\treferences.verificationTargetThoughtId,\n\t\t\t'verifies',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitCritiqueEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'critique')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\treferences.verificationTargetThoughtId,\n\t\t\t'critiques',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitSynthesisEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.synthesisSourceThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'derives_from', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitRevisionEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.revises_thought === undefined) return false;\n\n\t\treturn this._addEdgeIfValid(thought.id, references.revisesThoughtId, 'revises', sessionId);\n\t}\n\n\tprivate _emitToolInvocationEdge(\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (\n\t\t\tthought.thought_type !== 'tool_observation' ||\n\t\t\tcontext?.toolInvocationSourceThoughtId === undefined\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst metadata = thought.tool_name !== undefined ? { tool_name: thought.tool_name } : undefined;\n\t\treturn this._addEdgeIfValid(\n\t\t\tcontext.toolInvocationSourceThoughtId,\n\t\t\tthought.id,\n\t\t\t'tool_invocation',\n\t\t\tsessionId,\n\t\t\tmetadata\n\t\t);\n\t}\n\n\tprivate _emitSequenceEdge(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tconst history = session.thought_history;\n\t\tif (history.length < 2) return false;\n\n\t\tconst prev = history[history.length - 2];\n\t\tif (!prev?.id) return false;\n\n\t\treturn this._addEdgeIfValid(prev.id, thought.id, 'sequence', sessionId);\n\t}\n\n\t/**\n\t * Adds an edge to the edge store if both endpoints are non-empty strings.\n\t * Returns true if added, false if skipped (missing endpoint).\n\t * Failures (e.g. self-edge) are caught and logged.\n\t */\n\tprivate _addEdgeIfValid(\n\t\tfrom: ThoughtId | undefined,\n\t\tto: ThoughtId | undefined,\n\t\tkind: EdgeKind,\n\t\tsessionId: SessionId,\n\t\tmetadata?: Record<string, unknown>\n\t): boolean {\n\t\tif (!from || !to) {\n\t\t\tthis._logger.debug('Skipping edge: unresolved endpoint', {\n\t\t\t\tkind,\n\t\t\t\tfrom: from ?? null,\n\t\t\t\tto: to ?? null,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst edge: Edge = {\n\t\t\tid: generateEdgeId(),\n\t\t\tfrom: from as Edge['from'],\n\t\t\tto: to as Edge['to'],\n\t\t\tkind,\n\t\t\tsessionId: sessionId as Edge['sessionId'],\n\t\t\tcreatedAt: Date.now(),\n\t\t\t...(metadata !== undefined ? { metadata } : {}),\n\t\t};\n\t\tif (!this._edgeStore) {\n\t\t\tthis._logger.warn('EdgeStore not available; skipping edge', { kind });\n\t\t\treturn false;\n\t\t}\n\t\tconst duplicate = this._edgeStore\n\t\t\t.edgesForSession(sessionId)\n\t\t\t.some((existing) => existing.kind === kind && existing.from === from && existing.to === to);\n\t\tif (duplicate) return false;\n\t\ttry {\n\t\t\tthis._edgeStore.addEdge(edge);\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tthis._logger.info('Failed to add DAG edge', {\n\t\t\t\tkind,\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"names":["EdgeEmitter","config","NullLogger","undefined","session","thought","context","sessionId","references","hasRelationalIntent","emittedRelational","emitted","srcId","metadata","history","prev","from","to","kind","edge","generateEdgeId","Date","duplicate","existing","err","getErrorMessage"],"mappings":"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"}
1
+ {"version":3,"file":"core/graph/EdgeEmitter.js","sources":["../../../src/core/graph/EdgeEmitter.ts"],"sourcesContent":["/**\n * EdgeEmitter — emits DAG edges for thoughts based on their metadata.\n *\n * Stateless helper extracted from HistoryManager. Holds a reference to an\n * optional `IEdgeStore` and a feature flag (`dagEdges`) gating writes.\n *\n * @module EdgeEmitter\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport { getErrorMessage } from '../../errors.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport { NullLogger } from '../../logger/NullLogger.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ResolvedThoughtReferences, ThoughtAdmissionContext } from '../IHistoryManager.js';\nimport type { Edge, EdgeKind } from './Edge.js';\nimport {\n\tgenerateEdgeId,\n\ttype BranchId,\n\ttype SessionId,\n\ttype ThoughtId,\n} from '../../contracts/ids.js';\n\n/** Minimal session view needed for edge emission. */\nexport interface EdgeEmissionSession {\n\tthought_history: ThoughtData[];\n\tbranches: Record<BranchId, ThoughtData[]>;\n}\n\n/** Configuration options for EdgeEmitter. */\nexport interface EdgeEmitterConfig {\n\tedgeStore?: IEdgeStore;\n\tdagEdges: boolean;\n\tlogger?: Logger;\n}\n\n/**\n * Emits DAG edges for thought relationships when an `IEdgeStore` is configured\n * and the `dagEdges` feature flag is enabled. No-ops otherwise.\n */\nexport class EdgeEmitter {\n\tprivate readonly _edgeStore?: IEdgeStore;\n\tprivate readonly _dagEdges: boolean;\n\tprivate readonly _logger: Logger;\n\n\tconstructor(config: EdgeEmitterConfig) {\n\t\tthis._edgeStore = config.edgeStore;\n\t\tthis._dagEdges = config.dagEdges;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t}\n\n\t/** Returns true when edge emission is active (store + flag both set). */\n\tpublic isEnabled(): boolean {\n\t\treturn this._edgeStore !== undefined && this._dagEdges;\n\t}\n\n\t/**\n\t * Emits DAG edges for a thought based on its metadata fields.\n\t *\n\t * Edge kinds (in priority order):\n\t * - branch: branch_from_thought + branch_id → parent.id → current.id\n\t * - merge: merge_from_thoughts → source.id → current.id (per source)\n\t * - verifies: verification_target + thought_type=verification → current.id → target.id\n\t * - critiques: verification_target + thought_type=critique → current.id → target.id\n\t * - derives_from: synthesis_sources → source.id → current.id (per source)\n\t * - revises: revises_thought → current.id → target.id\n\t * - tool_invocation: stable admission source id → current.id\n\t * - sequence: default chronological link from previous thought (if none of the above)\n\t * @returns True only when at least one edge was added to the store\n\t */\n\tpublic emitEdgesForThought(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (!this._edgeStore || !this._dagEdges) return false;\n\t\tif (!thought.id) return false;\n\n\t\tconst sessionId = thought.session_id;\n\t\tconst references = context?.resolvedReferences ?? {};\n\t\tconst hasRelationalIntent =\n\t\t\t(thought.branch_from_thought !== undefined && thought.branch_id !== undefined) ||\n\t\t\t(thought.merge_from_thoughts?.length ?? 0) > 0 ||\n\t\t\t(thought.verification_target !== undefined &&\n\t\t\t\t(thought.thought_type === 'verification' || thought.thought_type === 'critique')) ||\n\t\t\t(thought.synthesis_sources?.length ?? 0) > 0 ||\n\t\t\tthought.revises_thought !== undefined ||\n\t\t\t(thought.thought_type === 'tool_observation' &&\n\t\t\t\tcontext?.toolInvocationSourceThoughtId !== undefined);\n\t\tconst emittedRelational = [\n\t\t\tthis._emitBranchEdge(thought, references, sessionId),\n\t\t\tthis._emitMergeEdges(thought, references, sessionId),\n\t\t\tthis._emitVerificationEdge(thought, references, sessionId),\n\t\t\tthis._emitCritiqueEdge(thought, references, sessionId),\n\t\t\tthis._emitSynthesisEdges(thought, references, sessionId),\n\t\t\tthis._emitRevisionEdge(thought, references, sessionId),\n\t\t\tthis._emitToolInvocationEdge(thought, sessionId, context),\n\t\t].some((emitted) => emitted);\n\n\t\tif (emittedRelational || hasRelationalIntent) return emittedRelational;\n\t\treturn this._emitSequenceEdge(session, thought, sessionId);\n\t}\n\n\tprivate _emitBranchEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.branch_from_thought === undefined || !thought.branch_id) return false;\n\n\t\treturn this._addEdgeIfValid(references.branchFromThoughtId, thought.id, 'branch', sessionId);\n\t}\n\n\tprivate _emitMergeEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.mergeFromThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'merge', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitVerificationEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'verification')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\treferences.verificationTargetThoughtId,\n\t\t\t'verifies',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitCritiqueEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'critique')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\treferences.verificationTargetThoughtId,\n\t\t\t'critiques',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitSynthesisEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.synthesisSourceThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'derives_from', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitRevisionEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.revises_thought === undefined) return false;\n\n\t\treturn this._addEdgeIfValid(thought.id, references.revisesThoughtId, 'revises', sessionId);\n\t}\n\n\tprivate _emitToolInvocationEdge(\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (\n\t\t\tthought.thought_type !== 'tool_observation' ||\n\t\t\tcontext?.toolInvocationSourceThoughtId === undefined\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst metadata = thought.tool_name !== undefined ? { tool_name: thought.tool_name } : undefined;\n\t\treturn this._addEdgeIfValid(\n\t\t\tcontext.toolInvocationSourceThoughtId,\n\t\t\tthought.id,\n\t\t\t'tool_invocation',\n\t\t\tsessionId,\n\t\t\tmetadata\n\t\t);\n\t}\n\n\tprivate _emitSequenceEdge(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tconst history = session.thought_history;\n\t\tif (history.length < 2) return false;\n\n\t\tconst prev = history[history.length - 2];\n\t\tif (!prev?.id) return false;\n\n\t\treturn this._addEdgeIfValid(prev.id, thought.id, 'sequence', sessionId);\n\t}\n\n\t/**\n\t * Adds an edge to the edge store if both endpoints are non-empty strings.\n\t * Returns true if added, false if skipped (missing endpoint).\n\t * Failures (e.g. self-edge) are caught and logged.\n\t */\n\tprivate _addEdgeIfValid(\n\t\tfrom: ThoughtId | undefined,\n\t\tto: ThoughtId | undefined,\n\t\tkind: EdgeKind,\n\t\tsessionId: SessionId,\n\t\tmetadata?: Record<string, unknown>\n\t): boolean {\n\t\tif (!from || !to) {\n\t\t\tthis._logger.debug('Skipping edge: unresolved endpoint', {\n\t\t\t\tkind,\n\t\t\t\tfrom: from ?? null,\n\t\t\t\tto: to ?? null,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst edge: Edge = {\n\t\t\tid: generateEdgeId(),\n\t\t\tfrom: from as Edge['from'],\n\t\t\tto: to as Edge['to'],\n\t\t\tkind,\n\t\t\tsessionId: sessionId as Edge['sessionId'],\n\t\t\tcreatedAt: Date.now(),\n\t\t\t...(metadata !== undefined ? { metadata } : {}),\n\t\t};\n\t\tif (!this._edgeStore) {\n\t\t\tthis._logger.warn('EdgeStore not available; skipping edge', { kind });\n\t\t\treturn false;\n\t\t}\n\t\tconst duplicate = this._edgeStore\n\t\t\t.edgesForSession(sessionId)\n\t\t\t.some((existing) => existing.kind === kind && existing.from === from && existing.to === to);\n\t\tif (duplicate) return false;\n\t\ttry {\n\t\t\tthis._edgeStore.addEdge(edge);\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tthis._logger.info('Failed to add DAG edge', {\n\t\t\t\tkind,\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"names":["EdgeEmitter","config","NullLogger","undefined","session","thought","context","sessionId","references","hasRelationalIntent","emittedRelational","emitted","srcId","metadata","history","prev","from","to","kind","edge","generateEdgeId","Date","duplicate","existing","err","getErrorMessage"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * GraphView — read-only graph traversal queries over an {@link IEdgeStore}.
3
3
  *
4
4
  * Provides BFS / topological / ancestor / descendant queries over the
5
- * thought DAG. All methods return arrays of thought ids (ulid strings),
5
+ * thought DAG. Queries return thought ids or graph distances,
6
6
  * never `ThoughtData` objects — the view is intentionally decoupled from
7
7
  * `HistoryManager` so it can be reused by strategies that work purely in
8
8
  * terms of graph structure.
@@ -54,6 +54,18 @@ export declare class GraphView {
54
54
  * ```
55
55
  */
56
56
  chronological(sessionId: SessionId): readonly ThoughtId[];
57
+ /**
58
+ * Return the shortest directed distance from any retained root to a thought.
59
+ *
60
+ * Nodes are derived from the current edge store, so isolated thoughts are
61
+ * invisible and pruning can expose a retained node as a new root. Every edge
62
+ * kind participates in the traversal.
63
+ *
64
+ * @param sessionId - Session to query
65
+ * @param thoughtId - Thought whose root distance to resolve
66
+ * @returns Zero for a root, or `undefined` when no root can reach the thought
67
+ */
68
+ depthFromRoots(sessionId: SessionId, thoughtId: ThoughtId): number | undefined;
57
69
  /**
58
70
  * Return all thought ids reachable from `rootThoughtId` via `'branch'`
59
71
  * edges, including the root itself.
@@ -1 +1 @@
1
- {"version":3,"file":"GraphView.d.ts","sourceRoot":"","sources":["../../../src/core/graph/GraphView.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAInE;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC;;;;;;;;;OASG;gBACS,KAAK,EAAE,UAAU;IAI7B;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAUzD;;;;;;;;;;;;;;;OAeG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAkBpF;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IA4BvD;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAI9F;;;;;;;;;;;;;;OAcG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAIhG;;;;;;;;;;OAUG;IACH,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAelD;;;OAGG;IACH,OAAO,CAAC,aAAa;IAcrB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAmBlB;;OAEG;IACH,OAAO,CAAC,aAAa;IAsBrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;;OAGG;IACH,OAAO,CAAC,WAAW;CA+BnB"}
1
+ {"version":3,"file":"GraphView.d.ts","sourceRoot":"","sources":["../../../src/core/graph/GraphView.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAInE;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC;;;;;;;;;OASG;gBACS,KAAK,EAAE,UAAU;IAI7B;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAUzD;;;;;;;;;;OAUG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS;IAuC9E;;;;;;;;;;;;;;;OAeG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAkBpF;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IA4BvD;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAI9F;;;;;;;;;;;;;;OAcG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAIhG;;;;;;;;;;OAUG;IACH,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAelD;;;OAGG;IACH,OAAO,CAAC,aAAa;IAcrB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAmBlB;;OAEG;IACH,OAAO,CAAC,aAAa;IAsBrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;;OAGG;IACH,OAAO,CAAC,WAAW;CA+BnB"}
@@ -11,6 +11,40 @@ class GraphView {
11
11
  const roots = this._findRoots(nodes, hasIncoming, edges);
12
12
  return this._bfsFromRoots(sessionId, roots);
13
13
  }
14
+ depthFromRoots(sessionId, thoughtId) {
15
+ const edges = this._store.edgesForSession(sessionId);
16
+ if (0 === edges.length) return;
17
+ const nodes = new Set();
18
+ const hasIncoming = new Set();
19
+ const outgoing = new Map();
20
+ for (const edge of edges){
21
+ nodes.add(edge.from);
22
+ nodes.add(edge.to);
23
+ hasIncoming.add(edge.to);
24
+ const children = outgoing.get(edge.from);
25
+ if (void 0 === children) outgoing.set(edge.from, [
26
+ edge.to
27
+ ]);
28
+ else children.push(edge.to);
29
+ }
30
+ if (!nodes.has(thoughtId)) return;
31
+ let frontier = [];
32
+ for (const node of nodes)if (!hasIncoming.has(node)) frontier.push(node);
33
+ const visited = new Set(frontier);
34
+ let depth = 0;
35
+ while(frontier.length > 0){
36
+ const next = [];
37
+ for (const node of frontier){
38
+ if (node === thoughtId) return depth;
39
+ for (const child of outgoing.get(node) ?? [])if (!visited.has(child)) {
40
+ visited.add(child);
41
+ next.push(child);
42
+ }
43
+ }
44
+ frontier = next;
45
+ depth++;
46
+ }
47
+ }
14
48
  branchThoughts(sessionId, rootThoughtId) {
15
49
  const visited = new Set([
16
50
  rootThoughtId
@@ -1 +1 @@
1
- {"version":3,"file":"core/graph/GraphView.js","sources":["../../../src/core/graph/GraphView.ts"],"sourcesContent":["/**\n * GraphView — read-only graph traversal queries over an {@link IEdgeStore}.\n *\n * Provides BFS / topological / ancestor / descendant queries over the\n * thought DAG. All methods return arrays of thought ids (ulid strings),\n * never `ThoughtData` objects — the view is intentionally decoupled from\n * `HistoryManager` so it can be reused by strategies that work purely in\n * terms of graph structure.\n *\n * Construction is cheap (stores a reference to the underlying store).\n * Each query reads the latest store state — no caching, no snapshots.\n *\n * @module core/graph/GraphView\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\nimport { CycleDetectedError } from '../../errors.js';\nimport type { Edge } from './Edge.js';\n\n/**\n * Read-only traversal queries over an {@link IEdgeStore}.\n *\n * @example\n * ```typescript\n * const store = new EdgeStore();\n * // ... populate store ...\n * const view = new GraphView(store);\n * const order = view.topological('s1');\n * ```\n */\nexport class GraphView {\n\tprivate readonly _store: IEdgeStore;\n\n\t/**\n\t * Create a new GraphView backed by the given edge store.\n\t *\n\t * @param store - The edge store to query (held by reference, read-only access)\n\t *\n\t * @example\n\t * ```typescript\n\t * const view = new GraphView(edgeStore);\n\t * ```\n\t */\n\tconstructor(store: IEdgeStore) {\n\t\tthis._store = store;\n\t}\n\n\t/**\n\t * Return all thought ids in the session, ordered by BFS from roots.\n\t *\n\t * Roots are nodes with no incoming edges. Within a layer, neighbours\n\t * are visited in `outgoing` order (which the underlying store keeps\n\t * sorted by `createdAt` ascending).\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in chronological BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const ids = view.chronological('s1');\n\t * ```\n\t */\n\tchronological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst { nodes, hasIncoming } = this._collectNodes(edges);\n\t\tconst roots = this._findRoots(nodes, hasIncoming, edges);\n\t\treturn this._bfsFromRoots(sessionId, roots) as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all thought ids reachable from `rootThoughtId` via `'branch'`\n\t * edges, including the root itself.\n\t *\n\t * Non-branch edges are ignored. Cycles (if any) do not cause infinite\n\t * loops because each node is visited at most once.\n\t *\n\t * @param sessionId - Session to query\n\t * @param rootThoughtId - The starting thought id (typically the branch root)\n\t * @returns Thought ids forming the branch (includes root)\n\t *\n\t * @example\n\t * ```typescript\n\t * const branchIds = view.branchThoughts('s1', 'thought-root');\n\t * ```\n\t */\n\tbranchThoughts(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst visited = new Set<string>([rootThoughtId]);\n\t\tconst order: string[] = [rootThoughtId];\n\t\tconst queue: string[] = [rootThoughtId];\n\t\twhile (queue.length > 0) {\n\t\t\tconst current = queue.shift()!;\n\t\t\tconst out = this._store.outgoing(sessionId, current as ThoughtId);\n\t\t\tfor (const edge of out) {\n\t\t\t\tif (edge.kind !== 'branch') continue;\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return a topological ordering of all thought ids in the session\n\t * using Kahn's algorithm.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in topological order\n\t * @throws {CycleDetectedError} If the graph contains a cycle\n\t *\n\t * @example\n\t * ```typescript\n\t * const order = view.topological('s1');\n\t * ```\n\t */\n\ttopological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst inDegree = this._buildInDegree(edges);\n\t\tconst queue: string[] = [];\n\t\tfor (const [node, deg] of inDegree) {\n\t\t\tif (deg === 0) queue.push(node);\n\t\t}\n\t\tconst order: string[] = [];\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\torder.push(node);\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tconst next = (inDegree.get(edge.to) ?? 0) - 1;\n\t\t\t\tinDegree.set(edge.to, next);\n\t\t\t\tif (next === 0) queue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\tif (order.length !== inDegree.size) {\n\t\t\tthrow new CycleDetectedError(\n\t\t\t\t`Cycle detected in session '${sessionId}': topological sort incomplete (${order.length}/${inDegree.size})`\n\t\t\t);\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return all ancestors of `thoughtId` via incoming-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct parents only)\n\t * @returns Ancestor thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const parents = view.ancestors('s1', 'thought-id', 1);\n\t * ```\n\t */\n\tancestors(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'incoming') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all descendants of `thoughtId` via outgoing-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct children only)\n\t * @returns Descendant thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const children = view.descendants('s1', 'thought-id');\n\t * ```\n\t */\n\tdescendants(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'outgoing') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all thought ids in the session that have no outgoing edges.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids that are graph leaves\n\t *\n\t * @example\n\t * ```typescript\n\t * const tips = view.leaves('s1');\n\t * ```\n\t */\n\tleaves(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst { nodes } = this._collectNodes(edges);\n\t\tconst result: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (this._store.outgoing(sessionId, node as ThoughtId).length === 0) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t}\n\t\treturn result as ThoughtId[];\n\t}\n\n\t/**\n\t * Collect every node id referenced by the edges and a set of nodes\n\t * that have at least one incoming edge.\n\t */\n\tprivate _collectNodes(edges: readonly Edge[]): {\n\t\tnodes: Set<string>;\n\t\thasIncoming: Set<string>;\n\t} {\n\t\tconst nodes = new Set<string>();\n\t\tconst hasIncoming = new Set<string>();\n\t\tfor (const edge of edges) {\n\t\t\tnodes.add(edge.from);\n\t\t\tnodes.add(edge.to);\n\t\t\thasIncoming.add(edge.to);\n\t\t}\n\t\treturn { nodes, hasIncoming };\n\t}\n\n\t/**\n\t * Find roots (no incoming) ordered by the earliest outgoing edge\n\t * `createdAt`. Nodes with no outgoing edges fall back to the order\n\t * they appear among edges (already sorted by `createdAt`).\n\t */\n\tprivate _findRoots(\n\t\tnodes: Set<string>,\n\t\thasIncoming: Set<string>,\n\t\tedges: readonly Edge[]\n\t): string[] {\n\t\tconst earliest = new Map<string, number>();\n\t\tfor (const edge of edges) {\n\t\t\tif (!earliest.has(edge.from)) {\n\t\t\t\tearliest.set(edge.from, edge.createdAt);\n\t\t\t}\n\t\t}\n\t\tconst roots: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (!hasIncoming.has(node)) roots.push(node);\n\t\t}\n\t\troots.sort((a, b) => (earliest.get(a) ?? Infinity) - (earliest.get(b) ?? Infinity));\n\t\treturn roots;\n\t}\n\n\t/**\n\t * BFS from a list of root ids, visiting each node at most once.\n\t */\n\tprivate _bfsFromRoots(sessionId: SessionId, roots: readonly string[]): readonly string[] {\n\t\tconst visited = new Set<string>();\n\t\tconst order: string[] = [];\n\t\tconst queue: string[] = [];\n\t\tfor (const root of roots) {\n\t\t\tif (visited.has(root)) continue;\n\t\t\tvisited.add(root);\n\t\t\torder.push(root);\n\t\t\tqueue.push(root);\n\t\t}\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order;\n\t}\n\n\t/**\n\t * Build an in-degree map covering every node referenced by the edges.\n\t */\n\tprivate _buildInDegree(edges: readonly Edge[]): Map<string, number> {\n\t\tconst inDegree = new Map<string, number>();\n\t\tfor (const edge of edges) {\n\t\t\tif (!inDegree.has(edge.from)) inDegree.set(edge.from, 0);\n\t\t\tinDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);\n\t\t}\n\t\treturn inDegree;\n\t}\n\n\t/**\n\t * Generic BFS closure in either direction. Excludes the start node\n\t * from the result and respects an optional depth cap.\n\t */\n\tprivate _bfsClosure(\n\t\tsessionId: SessionId,\n\t\tstartId: string,\n\t\tmaxDepth: number | undefined,\n\t\tdirection: 'incoming' | 'outgoing'\n\t): readonly string[] {\n\t\tconst cap = maxDepth ?? Number.POSITIVE_INFINITY;\n\t\tconst visited = new Set<string>([startId]);\n\t\tconst order: string[] = [];\n\t\tlet frontier: string[] = [startId];\n\t\tlet depth = 0;\n\t\twhile (frontier.length > 0 && depth < cap) {\n\t\t\tconst next: string[] = [];\n\t\t\tfor (const node of frontier) {\n\t\t\t\tconst edges =\n\t\t\t\t\tdirection === 'outgoing'\n\t\t\t\t\t\t? this._store.outgoing(sessionId, node as ThoughtId)\n\t\t\t\t\t\t: this._store.incoming(sessionId, node as ThoughtId);\n\t\t\t\tfor (const edge of edges) {\n\t\t\t\t\tconst neighbour = direction === 'outgoing' ? edge.to : edge.from;\n\t\t\t\t\tif (visited.has(neighbour)) continue;\n\t\t\t\t\tvisited.add(neighbour);\n\t\t\t\t\torder.push(neighbour);\n\t\t\t\t\tnext.push(neighbour);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrontier = next;\n\t\t\tdepth++;\n\t\t}\n\t\treturn order;\n\t}\n}\n"],"names":["GraphView","store","sessionId","edges","nodes","hasIncoming","roots","rootThoughtId","visited","Set","order","queue","current","out","edge","inDegree","node","deg","next","CycleDetectedError","thoughtId","maxDepth","result","earliest","Map","a","b","Infinity","root","startId","direction","cap","Number","frontier","depth","neighbour"],"mappings":"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"}
1
+ {"version":3,"file":"core/graph/GraphView.js","sources":["../../../src/core/graph/GraphView.ts"],"sourcesContent":["/**\n * GraphView — read-only graph traversal queries over an {@link IEdgeStore}.\n *\n * Provides BFS / topological / ancestor / descendant queries over the\n * thought DAG. Queries return thought ids or graph distances,\n * never `ThoughtData` objects — the view is intentionally decoupled from\n * `HistoryManager` so it can be reused by strategies that work purely in\n * terms of graph structure.\n *\n * Construction is cheap (stores a reference to the underlying store).\n * Each query reads the latest store state — no caching, no snapshots.\n *\n * @module core/graph/GraphView\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\nimport { CycleDetectedError } from '../../errors.js';\nimport type { Edge } from './Edge.js';\n\n/**\n * Read-only traversal queries over an {@link IEdgeStore}.\n *\n * @example\n * ```typescript\n * const store = new EdgeStore();\n * // ... populate store ...\n * const view = new GraphView(store);\n * const order = view.topological('s1');\n * ```\n */\nexport class GraphView {\n\tprivate readonly _store: IEdgeStore;\n\n\t/**\n\t * Create a new GraphView backed by the given edge store.\n\t *\n\t * @param store - The edge store to query (held by reference, read-only access)\n\t *\n\t * @example\n\t * ```typescript\n\t * const view = new GraphView(edgeStore);\n\t * ```\n\t */\n\tconstructor(store: IEdgeStore) {\n\t\tthis._store = store;\n\t}\n\n\t/**\n\t * Return all thought ids in the session, ordered by BFS from roots.\n\t *\n\t * Roots are nodes with no incoming edges. Within a layer, neighbours\n\t * are visited in `outgoing` order (which the underlying store keeps\n\t * sorted by `createdAt` ascending).\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in chronological BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const ids = view.chronological('s1');\n\t * ```\n\t */\n\tchronological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst { nodes, hasIncoming } = this._collectNodes(edges);\n\t\tconst roots = this._findRoots(nodes, hasIncoming, edges);\n\t\treturn this._bfsFromRoots(sessionId, roots) as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return the shortest directed distance from any retained root to a thought.\n\t *\n\t * Nodes are derived from the current edge store, so isolated thoughts are\n\t * invisible and pruning can expose a retained node as a new root. Every edge\n\t * kind participates in the traversal.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - Thought whose root distance to resolve\n\t * @returns Zero for a root, or `undefined` when no root can reach the thought\n\t */\n\tdepthFromRoots(sessionId: SessionId, thoughtId: ThoughtId): number | undefined {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) return undefined;\n\n\t\tconst nodes = new Set<ThoughtId>();\n\t\tconst hasIncoming = new Set<ThoughtId>();\n\t\tconst outgoing = new Map<ThoughtId, ThoughtId[]>();\n\t\tfor (const edge of edges) {\n\t\t\tnodes.add(edge.from);\n\t\t\tnodes.add(edge.to);\n\t\t\thasIncoming.add(edge.to);\n\t\t\tconst children = outgoing.get(edge.from);\n\t\t\tif (children === undefined) outgoing.set(edge.from, [edge.to]);\n\t\t\telse children.push(edge.to);\n\t\t}\n\t\tif (!nodes.has(thoughtId)) return undefined;\n\n\t\tlet frontier: ThoughtId[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (!hasIncoming.has(node)) frontier.push(node);\n\t\t}\n\t\tconst visited = new Set<ThoughtId>(frontier);\n\t\tlet depth = 0;\n\t\twhile (frontier.length > 0) {\n\t\t\tconst next: ThoughtId[] = [];\n\t\t\tfor (const node of frontier) {\n\t\t\t\tif (node === thoughtId) return depth;\n\t\t\t\tfor (const child of outgoing.get(node) ?? []) {\n\t\t\t\t\tif (visited.has(child)) continue;\n\t\t\t\t\tvisited.add(child);\n\t\t\t\t\tnext.push(child);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrontier = next;\n\t\t\tdepth++;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Return all thought ids reachable from `rootThoughtId` via `'branch'`\n\t * edges, including the root itself.\n\t *\n\t * Non-branch edges are ignored. Cycles (if any) do not cause infinite\n\t * loops because each node is visited at most once.\n\t *\n\t * @param sessionId - Session to query\n\t * @param rootThoughtId - The starting thought id (typically the branch root)\n\t * @returns Thought ids forming the branch (includes root)\n\t *\n\t * @example\n\t * ```typescript\n\t * const branchIds = view.branchThoughts('s1', 'thought-root');\n\t * ```\n\t */\n\tbranchThoughts(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst visited = new Set<string>([rootThoughtId]);\n\t\tconst order: string[] = [rootThoughtId];\n\t\tconst queue: string[] = [rootThoughtId];\n\t\twhile (queue.length > 0) {\n\t\t\tconst current = queue.shift()!;\n\t\t\tconst out = this._store.outgoing(sessionId, current as ThoughtId);\n\t\t\tfor (const edge of out) {\n\t\t\t\tif (edge.kind !== 'branch') continue;\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return a topological ordering of all thought ids in the session\n\t * using Kahn's algorithm.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in topological order\n\t * @throws {CycleDetectedError} If the graph contains a cycle\n\t *\n\t * @example\n\t * ```typescript\n\t * const order = view.topological('s1');\n\t * ```\n\t */\n\ttopological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst inDegree = this._buildInDegree(edges);\n\t\tconst queue: string[] = [];\n\t\tfor (const [node, deg] of inDegree) {\n\t\t\tif (deg === 0) queue.push(node);\n\t\t}\n\t\tconst order: string[] = [];\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\torder.push(node);\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tconst next = (inDegree.get(edge.to) ?? 0) - 1;\n\t\t\t\tinDegree.set(edge.to, next);\n\t\t\t\tif (next === 0) queue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\tif (order.length !== inDegree.size) {\n\t\t\tthrow new CycleDetectedError(\n\t\t\t\t`Cycle detected in session '${sessionId}': topological sort incomplete (${order.length}/${inDegree.size})`\n\t\t\t);\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return all ancestors of `thoughtId` via incoming-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct parents only)\n\t * @returns Ancestor thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const parents = view.ancestors('s1', 'thought-id', 1);\n\t * ```\n\t */\n\tancestors(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'incoming') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all descendants of `thoughtId` via outgoing-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct children only)\n\t * @returns Descendant thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const children = view.descendants('s1', 'thought-id');\n\t * ```\n\t */\n\tdescendants(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'outgoing') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all thought ids in the session that have no outgoing edges.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids that are graph leaves\n\t *\n\t * @example\n\t * ```typescript\n\t * const tips = view.leaves('s1');\n\t * ```\n\t */\n\tleaves(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst { nodes } = this._collectNodes(edges);\n\t\tconst result: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (this._store.outgoing(sessionId, node as ThoughtId).length === 0) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t}\n\t\treturn result as ThoughtId[];\n\t}\n\n\t/**\n\t * Collect every node id referenced by the edges and a set of nodes\n\t * that have at least one incoming edge.\n\t */\n\tprivate _collectNodes(edges: readonly Edge[]): {\n\t\tnodes: Set<string>;\n\t\thasIncoming: Set<string>;\n\t} {\n\t\tconst nodes = new Set<string>();\n\t\tconst hasIncoming = new Set<string>();\n\t\tfor (const edge of edges) {\n\t\t\tnodes.add(edge.from);\n\t\t\tnodes.add(edge.to);\n\t\t\thasIncoming.add(edge.to);\n\t\t}\n\t\treturn { nodes, hasIncoming };\n\t}\n\n\t/**\n\t * Find roots (no incoming) ordered by the earliest outgoing edge\n\t * `createdAt`. Nodes with no outgoing edges fall back to the order\n\t * they appear among edges (already sorted by `createdAt`).\n\t */\n\tprivate _findRoots(\n\t\tnodes: Set<string>,\n\t\thasIncoming: Set<string>,\n\t\tedges: readonly Edge[]\n\t): string[] {\n\t\tconst earliest = new Map<string, number>();\n\t\tfor (const edge of edges) {\n\t\t\tif (!earliest.has(edge.from)) {\n\t\t\t\tearliest.set(edge.from, edge.createdAt);\n\t\t\t}\n\t\t}\n\t\tconst roots: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (!hasIncoming.has(node)) roots.push(node);\n\t\t}\n\t\troots.sort((a, b) => (earliest.get(a) ?? Infinity) - (earliest.get(b) ?? Infinity));\n\t\treturn roots;\n\t}\n\n\t/**\n\t * BFS from a list of root ids, visiting each node at most once.\n\t */\n\tprivate _bfsFromRoots(sessionId: SessionId, roots: readonly string[]): readonly string[] {\n\t\tconst visited = new Set<string>();\n\t\tconst order: string[] = [];\n\t\tconst queue: string[] = [];\n\t\tfor (const root of roots) {\n\t\t\tif (visited.has(root)) continue;\n\t\t\tvisited.add(root);\n\t\t\torder.push(root);\n\t\t\tqueue.push(root);\n\t\t}\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order;\n\t}\n\n\t/**\n\t * Build an in-degree map covering every node referenced by the edges.\n\t */\n\tprivate _buildInDegree(edges: readonly Edge[]): Map<string, number> {\n\t\tconst inDegree = new Map<string, number>();\n\t\tfor (const edge of edges) {\n\t\t\tif (!inDegree.has(edge.from)) inDegree.set(edge.from, 0);\n\t\t\tinDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);\n\t\t}\n\t\treturn inDegree;\n\t}\n\n\t/**\n\t * Generic BFS closure in either direction. Excludes the start node\n\t * from the result and respects an optional depth cap.\n\t */\n\tprivate _bfsClosure(\n\t\tsessionId: SessionId,\n\t\tstartId: string,\n\t\tmaxDepth: number | undefined,\n\t\tdirection: 'incoming' | 'outgoing'\n\t): readonly string[] {\n\t\tconst cap = maxDepth ?? Number.POSITIVE_INFINITY;\n\t\tconst visited = new Set<string>([startId]);\n\t\tconst order: string[] = [];\n\t\tlet frontier: string[] = [startId];\n\t\tlet depth = 0;\n\t\twhile (frontier.length > 0 && depth < cap) {\n\t\t\tconst next: string[] = [];\n\t\t\tfor (const node of frontier) {\n\t\t\t\tconst edges =\n\t\t\t\t\tdirection === 'outgoing'\n\t\t\t\t\t\t? this._store.outgoing(sessionId, node as ThoughtId)\n\t\t\t\t\t\t: this._store.incoming(sessionId, node as ThoughtId);\n\t\t\t\tfor (const edge of edges) {\n\t\t\t\t\tconst neighbour = direction === 'outgoing' ? edge.to : edge.from;\n\t\t\t\t\tif (visited.has(neighbour)) continue;\n\t\t\t\t\tvisited.add(neighbour);\n\t\t\t\t\torder.push(neighbour);\n\t\t\t\t\tnext.push(neighbour);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrontier = next;\n\t\t\tdepth++;\n\t\t}\n\t\treturn order;\n\t}\n}\n"],"names":["GraphView","store","sessionId","edges","nodes","hasIncoming","roots","thoughtId","Set","outgoing","Map","edge","children","undefined","frontier","node","visited","depth","next","child","rootThoughtId","order","queue","current","out","inDegree","deg","CycleDetectedError","maxDepth","result","earliest","a","b","Infinity","root","startId","direction","cap","Number","neighbour"],"mappings":"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"}
@@ -26,7 +26,6 @@ export interface OutcomeRecorderConfig {
26
26
  * const recorder = new OutcomeRecorder({ enabled: true });
27
27
  * recorder.recordVerification({
28
28
  * thoughtId: 't1',
29
- * thoughtNumber: 1,
30
29
  * sessionId: 'session-a',
31
30
  * predicted: 0.8,
32
31
  * actual: 1,
@@ -1 +1 @@
1
- {"version":3,"file":"OutcomeRecorder.d.ts","sourceRoot":"","sources":["../../../src/core/reasoning/OutcomeRecorder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkE;IAC5F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IAEnC;;OAEG;IACH,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED;;;;OAIG;gBACS,MAAM,EAAE,qBAAqB;IAIzC;;;;;;OAMG;IACH,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAUjE;;;;;;OAMG;IACH,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC,GAAG,IAAI;IAc1E;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,mBAAmB,EAAE;IAKxD;;;;OAIG;IACH,cAAc,IAAI,mBAAmB,EAAE;IASvC;;;;OAIG;IACH,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAIzC,gBAAgB,IAAI,IAAI;CAGxB"}
1
+ {"version":3,"file":"OutcomeRecorder.d.ts","sourceRoot":"","sources":["../../../src/core/reasoning/OutcomeRecorder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkE;IAC5F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IAEnC;;OAEG;IACH,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED;;;;OAIG;gBACS,MAAM,EAAE,qBAAqB;IAIzC;;;;;;OAMG;IACH,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAUjE;;;;;;OAMG;IACH,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC,GAAG,IAAI;IAc1E;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,mBAAmB,EAAE;IAKxD;;;;OAIG;IACH,cAAc,IAAI,mBAAmB,EAAE;IASvC;;;;OAIG;IACH,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAIzC,gBAAgB,IAAI,IAAI;CAGxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"core/reasoning/OutcomeRecorder.js","sources":["../../../src/core/reasoning/OutcomeRecorder.ts"],"sourcesContent":["/**\n * Records verification outcomes for confidence calibration.\n *\n * No-op implementation when feature flag is disabled.\n * Stores outcomes per-session in memory for later calibration use.\n *\n * @module core/reasoning/OutcomeRecorder\n */\n\nimport type { IOutcomeRecorder, VerificationOutcome } from '../../contracts/interfaces.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\nimport { ValidationError } from '../../errors.js';\n\n/**\n * Configuration for OutcomeRecorder.\n */\nexport interface OutcomeRecorderConfig {\n\t/** Whether outcome recording is enabled. */\n\tenabled: boolean;\n}\n\n/**\n * Records verification outcomes for confidence calibration.\n *\n * When disabled (default), all methods are no-ops and return empty arrays.\n * When enabled, outcomes are stored in memory per-session.\n *\n * @example\n * ```typescript\n * const recorder = new OutcomeRecorder({ enabled: true });\n * recorder.recordVerification({\n * thoughtId: 't1',\n * thoughtNumber: 1,\n * sessionId: 'session-a',\n * predicted: 0.8,\n * actual: 1,\n * type: 'verification',\n * });\n * const outcomes = recorder.getOutcomes('session-a');\n * ```\n */\nexport class OutcomeRecorder implements IOutcomeRecorder {\n\tprivate readonly _outcomes: Map<SessionId, Map<ThoughtId, VerificationOutcome>> = new Map();\n\tprivate readonly _enabled: boolean;\n\n\t/**\n\t * Whether outcome recording is currently enabled.\n\t */\n\tpublic get enabled(): boolean {\n\t\treturn this._enabled;\n\t}\n\n\t/**\n\t * Create a new OutcomeRecorder.\n\t *\n\t * @param config - Recorder configuration\n\t */\n\tconstructor(config: OutcomeRecorderConfig) {\n\t\tthis._enabled = config.enabled;\n\t}\n\n\t/**\n\t * Assert that a target is available for one outcome label.\n\t *\n\t * @param sessionId - Canonical session namespace\n\t * @param thoughtId - Stable target identity\n\t * @throws {ValidationError} When the target was already labeled\n\t */\n\tassertCanRecord(sessionId: SessionId, thoughtId: ThoughtId): void {\n\t\tif (!this._enabled) return;\n\t\tif (this._outcomes.get(sessionId)?.has(thoughtId)) {\n\t\t\tthrow new ValidationError(\n\t\t\t\t'verification_result',\n\t\t\t\t'The verification target already has a recorded result'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Record a verification outcome.\n\t *\n\t * No-op when outcome recording is disabled.\n\t *\n\t * @param outcome - The outcome data (recordedAt is auto-set)\n\t */\n\trecordVerification(outcome: Omit<VerificationOutcome, 'recordedAt'>): void {\n\t\tif (!this._enabled) return;\n\t\tthis.assertCanRecord(outcome.sessionId, outcome.thoughtId);\n\n\t\tconst full: VerificationOutcome = {\n\t\t\t...outcome,\n\t\t\trecordedAt: Date.now(),\n\t\t};\n\n\t\tconst sessionOutcomes = this._outcomes.get(outcome.sessionId) ?? new Map();\n\t\tsessionOutcomes.set(outcome.thoughtId, full);\n\t\tthis._outcomes.set(outcome.sessionId, sessionOutcomes);\n\t}\n\n\t/**\n\t * Get all recorded outcomes for a session.\n\t *\n\t * @param sessionId - The session id to query\n\t * @returns Array of outcomes (empty when disabled or no data)\n\t */\n\tgetOutcomes(sessionId: SessionId): VerificationOutcome[] {\n\t\tif (!this._enabled) return [];\n\t\treturn [...(this._outcomes.get(sessionId)?.values() ?? [])].map((outcome) => ({ ...outcome }));\n\t}\n\n\t/**\n\t * Get outcomes across all sessions.\n\t *\n\t * @returns Flat array of all outcomes (empty when disabled)\n\t */\n\tgetAllOutcomes(): VerificationOutcome[] {\n\t\tif (!this._enabled) return [];\n\t\tconst all: VerificationOutcome[] = [];\n\t\tfor (const outcomes of this._outcomes.values()) {\n\t\t\tfor (const outcome of outcomes.values()) all.push({ ...outcome });\n\t\t}\n\t\treturn all;\n\t}\n\n\t/**\n\t * Clear outcomes for a specific session.\n\t *\n\t * @param sessionId - The session id to clear\n\t */\n\tclearOutcomes(sessionId: SessionId): void {\n\t\tthis._outcomes.delete(sessionId);\n\t}\n\n\tclearAllOutcomes(): void {\n\t\tthis._outcomes.clear();\n\t}\n}\n"],"names":["OutcomeRecorder","Map","config","sessionId","thoughtId","ValidationError","outcome","full","Date","sessionOutcomes","all","outcomes"],"mappings":";AAyCO,MAAMA;IACK,YAAiE,IAAIC,MAAM;IAC3E,SAAkB;IAKnC,IAAW,UAAmB;QAC7B,OAAO,IAAI,CAAC,QAAQ;IACrB;IAOA,YAAYC,MAA6B,CAAE;QAC1C,IAAI,CAAC,QAAQ,GAAGA,OAAO,OAAO;IAC/B;IASA,gBAAgBC,SAAoB,EAAEC,SAAoB,EAAQ;QACjE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;QACpB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAACD,YAAY,IAAIC,YACtC,MAAM,IAAIC,gBACT,uBACA;IAGH;IASA,mBAAmBC,OAAgD,EAAQ;QAC1E,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;QACpB,IAAI,CAAC,eAAe,CAACA,QAAQ,SAAS,EAAEA,QAAQ,SAAS;QAEzD,MAAMC,OAA4B;YACjC,GAAGD,OAAO;YACV,YAAYE,KAAK,GAAG;QACrB;QAEA,MAAMC,kBAAkB,IAAI,CAAC,SAAS,CAAC,GAAG,CAACH,QAAQ,SAAS,KAAK,IAAIL;QACrEQ,gBAAgB,GAAG,CAACH,QAAQ,SAAS,EAAEC;QACvC,IAAI,CAAC,SAAS,CAAC,GAAG,CAACD,QAAQ,SAAS,EAAEG;IACvC;IAQA,YAAYN,SAAoB,EAAyB;QACxD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE;QAC7B,OAAO;eAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAACA,YAAY,YAAY,EAAE;SAAE,CAAC,GAAG,CAAC,CAACG,UAAa;gBAAE,GAAGA,OAAO;YAAC;IAC5F;IAOA,iBAAwC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE;QAC7B,MAAMI,MAA6B,EAAE;QACrC,KAAK,MAAMC,YAAY,IAAI,CAAC,SAAS,CAAC,MAAM,GAC3C,KAAK,MAAML,WAAWK,SAAS,MAAM,GAAID,IAAI,IAAI,CAAC;YAAE,GAAGJ,OAAO;QAAC;QAEhE,OAAOI;IACR;IAOA,cAAcP,SAAoB,EAAQ;QACzC,IAAI,CAAC,SAAS,CAAC,MAAM,CAACA;IACvB;IAEA,mBAAyB;QACxB,IAAI,CAAC,SAAS,CAAC,KAAK;IACrB;AACD"}
1
+ {"version":3,"file":"core/reasoning/OutcomeRecorder.js","sources":["../../../src/core/reasoning/OutcomeRecorder.ts"],"sourcesContent":["/**\n * Records verification outcomes for confidence calibration.\n *\n * No-op implementation when feature flag is disabled.\n * Stores outcomes per-session in memory for later calibration use.\n *\n * @module core/reasoning/OutcomeRecorder\n */\n\nimport type { IOutcomeRecorder, VerificationOutcome } from '../../contracts/interfaces.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\nimport { ValidationError } from '../../errors.js';\n\n/**\n * Configuration for OutcomeRecorder.\n */\nexport interface OutcomeRecorderConfig {\n\t/** Whether outcome recording is enabled. */\n\tenabled: boolean;\n}\n\n/**\n * Records verification outcomes for confidence calibration.\n *\n * When disabled (default), all methods are no-ops and return empty arrays.\n * When enabled, outcomes are stored in memory per-session.\n *\n * @example\n * ```typescript\n * const recorder = new OutcomeRecorder({ enabled: true });\n * recorder.recordVerification({\n * thoughtId: 't1',\n * sessionId: 'session-a',\n * predicted: 0.8,\n * actual: 1,\n * type: 'verification',\n * });\n * const outcomes = recorder.getOutcomes('session-a');\n * ```\n */\nexport class OutcomeRecorder implements IOutcomeRecorder {\n\tprivate readonly _outcomes: Map<SessionId, Map<ThoughtId, VerificationOutcome>> = new Map();\n\tprivate readonly _enabled: boolean;\n\n\t/**\n\t * Whether outcome recording is currently enabled.\n\t */\n\tpublic get enabled(): boolean {\n\t\treturn this._enabled;\n\t}\n\n\t/**\n\t * Create a new OutcomeRecorder.\n\t *\n\t * @param config - Recorder configuration\n\t */\n\tconstructor(config: OutcomeRecorderConfig) {\n\t\tthis._enabled = config.enabled;\n\t}\n\n\t/**\n\t * Assert that a target is available for one outcome label.\n\t *\n\t * @param sessionId - Canonical session namespace\n\t * @param thoughtId - Stable target identity\n\t * @throws {ValidationError} When the target was already labeled\n\t */\n\tassertCanRecord(sessionId: SessionId, thoughtId: ThoughtId): void {\n\t\tif (!this._enabled) return;\n\t\tif (this._outcomes.get(sessionId)?.has(thoughtId)) {\n\t\t\tthrow new ValidationError(\n\t\t\t\t'verification_result',\n\t\t\t\t'The verification target already has a recorded result'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Record a verification outcome.\n\t *\n\t * No-op when outcome recording is disabled.\n\t *\n\t * @param outcome - The outcome data (recordedAt is auto-set)\n\t */\n\trecordVerification(outcome: Omit<VerificationOutcome, 'recordedAt'>): void {\n\t\tif (!this._enabled) return;\n\t\tthis.assertCanRecord(outcome.sessionId, outcome.thoughtId);\n\n\t\tconst full: VerificationOutcome = {\n\t\t\t...outcome,\n\t\t\trecordedAt: Date.now(),\n\t\t};\n\n\t\tconst sessionOutcomes = this._outcomes.get(outcome.sessionId) ?? new Map();\n\t\tsessionOutcomes.set(outcome.thoughtId, full);\n\t\tthis._outcomes.set(outcome.sessionId, sessionOutcomes);\n\t}\n\n\t/**\n\t * Get all recorded outcomes for a session.\n\t *\n\t * @param sessionId - The session id to query\n\t * @returns Array of outcomes (empty when disabled or no data)\n\t */\n\tgetOutcomes(sessionId: SessionId): VerificationOutcome[] {\n\t\tif (!this._enabled) return [];\n\t\treturn [...(this._outcomes.get(sessionId)?.values() ?? [])].map((outcome) => ({ ...outcome }));\n\t}\n\n\t/**\n\t * Get outcomes across all sessions.\n\t *\n\t * @returns Flat array of all outcomes (empty when disabled)\n\t */\n\tgetAllOutcomes(): VerificationOutcome[] {\n\t\tif (!this._enabled) return [];\n\t\tconst all: VerificationOutcome[] = [];\n\t\tfor (const outcomes of this._outcomes.values()) {\n\t\t\tfor (const outcome of outcomes.values()) all.push({ ...outcome });\n\t\t}\n\t\treturn all;\n\t}\n\n\t/**\n\t * Clear outcomes for a specific session.\n\t *\n\t * @param sessionId - The session id to clear\n\t */\n\tclearOutcomes(sessionId: SessionId): void {\n\t\tthis._outcomes.delete(sessionId);\n\t}\n\n\tclearAllOutcomes(): void {\n\t\tthis._outcomes.clear();\n\t}\n}\n"],"names":["OutcomeRecorder","Map","config","sessionId","thoughtId","ValidationError","outcome","full","Date","sessionOutcomes","all","outcomes"],"mappings":";AAwCO,MAAMA;IACK,YAAiE,IAAIC,MAAM;IAC3E,SAAkB;IAKnC,IAAW,UAAmB;QAC7B,OAAO,IAAI,CAAC,QAAQ;IACrB;IAOA,YAAYC,MAA6B,CAAE;QAC1C,IAAI,CAAC,QAAQ,GAAGA,OAAO,OAAO;IAC/B;IASA,gBAAgBC,SAAoB,EAAEC,SAAoB,EAAQ;QACjE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;QACpB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAACD,YAAY,IAAIC,YACtC,MAAM,IAAIC,gBACT,uBACA;IAGH;IASA,mBAAmBC,OAAgD,EAAQ;QAC1E,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;QACpB,IAAI,CAAC,eAAe,CAACA,QAAQ,SAAS,EAAEA,QAAQ,SAAS;QAEzD,MAAMC,OAA4B;YACjC,GAAGD,OAAO;YACV,YAAYE,KAAK,GAAG;QACrB;QAEA,MAAMC,kBAAkB,IAAI,CAAC,SAAS,CAAC,GAAG,CAACH,QAAQ,SAAS,KAAK,IAAIL;QACrEQ,gBAAgB,GAAG,CAACH,QAAQ,SAAS,EAAEC;QACvC,IAAI,CAAC,SAAS,CAAC,GAAG,CAACD,QAAQ,SAAS,EAAEG;IACvC;IAQA,YAAYN,SAAoB,EAAyB;QACxD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE;QAC7B,OAAO;eAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAACA,YAAY,YAAY,EAAE;SAAE,CAAC,GAAG,CAAC,CAACG,UAAa;gBAAE,GAAGA,OAAO;YAAC;IAC5F;IAOA,iBAAwC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE;QAC7B,MAAMI,MAA6B,EAAE;QACrC,KAAK,MAAMC,YAAY,IAAI,CAAC,SAAS,CAAC,MAAM,GAC3C,KAAK,MAAML,WAAWK,SAAS,MAAM,GAAID,IAAI,IAAI,CAAC;YAAE,GAAGJ,OAAO;QAAC;QAEhE,OAAOI;IACR;IAOA,cAAcP,SAAoB,EAAQ;QACzC,IAAI,CAAC,SAAS,CAAC,MAAM,CAACA;IACvB;IAEA,mBAAyB;QACxB,IAAI,CAAC,SAAS,CAAC,KAAK;IACrB;AACD"}
@@ -10,15 +10,15 @@
10
10
  */
11
11
  import type { IReasoningStrategy, StrategyContext, StrategyDecision } from '../../../contracts/strategy.js';
12
12
  /**
13
- * Default sequential strategy. Mirrors the legacy linear thinking flow:
13
+ * Default sequential strategy. Applies the linear thinking flow:
14
14
  *
15
15
  * - Continue while `next_thought_needed` is truthy (or unset).
16
16
  * - Terminate as soon as `next_thought_needed === false`.
17
17
  * - Branch when both `branch_from_thought` and `branch_id` are present.
18
18
  *
19
19
  * Type-agnostic: all `ThoughtType` variants (including `assumption`,
20
- * `decomposition`, `backtrack`, `tool_call`, `tool_observation`, and the
21
- * legacy six) pass through unchanged. The strategy intentionally inspects
20
+ * `decomposition`, `backtrack`, `tool_call`, and `tool_observation`) pass
21
+ * through unchanged. The strategy intentionally inspects
22
22
  * only `next_thought_needed`, `branch_from_thought`, and `branch_id` —
23
23
  * type-aware behavior lives in evaluator/scoring layers, not here.
24
24
  *
@@ -1 +1 @@
1
- {"version":3,"file":"core/reasoning/strategies/SequentialStrategy.js","sources":["../../../../src/core/reasoning/strategies/SequentialStrategy.ts"],"sourcesContent":["/**\n * Sequential reasoning strategy — the default policy that preserves existing\n * {@link ThoughtProcessor} behavior. Continues the chain unless the current\n * thought explicitly signals termination via `next_thought_needed === false`.\n *\n * Pure policy: no mutable state, no I/O, no module-level variables. All\n * methods are deterministic functions of their inputs.\n *\n * @module core/reasoning/strategies/SequentialStrategy\n */\n\nimport type {\n\tIReasoningStrategy,\n\tStrategyContext,\n\tStrategyDecision,\n} from '../../../contracts/strategy.js';\n\n/**\n * Default sequential strategy. Mirrors the legacy linear thinking flow:\n *\n * - Continue while `next_thought_needed` is truthy (or unset).\n * - Terminate as soon as `next_thought_needed === false`.\n * - Branch when both `branch_from_thought` and `branch_id` are present.\n *\n * Type-agnostic: all `ThoughtType` variants (including `assumption`,\n * `decomposition`, `backtrack`, `tool_call`, `tool_observation`, and the\n * legacy six) pass through unchanged. The strategy intentionally inspects\n * only `next_thought_needed`, `branch_from_thought`, and `branch_id` —\n * type-aware behavior lives in evaluator/scoring layers, not here.\n *\n * @example\n * ```ts\n * const strategy = new SequentialStrategy();\n * const decision = strategy.decide(ctx);\n * if (decision.action === 'terminate') stop();\n * ```\n */\nexport class SequentialStrategy implements IReasoningStrategy {\n\treadonly name = 'sequential' as const;\n\n\t/**\n\t * Compute the next action for the chain.\n\t *\n\t * @param ctx - Read-only session snapshot.\n\t * @returns `{ action: 'terminate' }` when current thought signals stop,\n\t * otherwise `{ action: 'continue' }`.\n\t */\n\tdecide(ctx: StrategyContext): StrategyDecision {\n\t\tif (ctx.currentThought.next_thought_needed === false) {\n\t\t\treturn { action: 'terminate', reason: 'next_thought_needed=false' };\n\t\t}\n\t\treturn { action: 'continue' };\n\t}\n\n\t/**\n\t * Predicate: should the chain branch right now?\n\t * True iff both `branch_from_thought` and `branch_id` are set on the\n\t * current thought.\n\t */\n\tshouldBranch(ctx: StrategyContext): boolean {\n\t\tconst t = ctx.currentThought;\n\t\treturn t.branch_from_thought !== undefined && t.branch_id !== undefined;\n\t}\n\n\t/**\n\t * Predicate: should the chain terminate right now?\n\t * True iff `next_thought_needed === false`.\n\t */\n\tshouldTerminate(ctx: StrategyContext): boolean {\n\t\treturn ctx.currentThought.next_thought_needed === false;\n\t}\n}\n"],"names":["SequentialStrategy","ctx","t","undefined"],"mappings":"AAqCO,MAAMA;IACH,OAAO,aAAsB;IAStC,OAAOC,GAAoB,EAAoB;QAC9C,IAAIA,AAA2C,UAA3CA,IAAI,cAAc,CAAC,mBAAmB,EACzC,OAAO;YAAE,QAAQ;YAAa,QAAQ;QAA4B;QAEnE,OAAO;YAAE,QAAQ;QAAW;IAC7B;IAOA,aAAaA,GAAoB,EAAW;QAC3C,MAAMC,IAAID,IAAI,cAAc;QAC5B,OAAOC,AAA0BC,WAA1BD,EAAE,mBAAmB,IAAkBA,AAAgBC,WAAhBD,EAAE,SAAS;IAC1D;IAMA,gBAAgBD,GAAoB,EAAW;QAC9C,OAAOA,AAA2C,UAA3CA,IAAI,cAAc,CAAC,mBAAmB;IAC9C;AACD"}
1
+ {"version":3,"file":"core/reasoning/strategies/SequentialStrategy.js","sources":["../../../../src/core/reasoning/strategies/SequentialStrategy.ts"],"sourcesContent":["/**\n * Sequential reasoning strategy — the default policy that preserves existing\n * {@link ThoughtProcessor} behavior. Continues the chain unless the current\n * thought explicitly signals termination via `next_thought_needed === false`.\n *\n * Pure policy: no mutable state, no I/O, no module-level variables. All\n * methods are deterministic functions of their inputs.\n *\n * @module core/reasoning/strategies/SequentialStrategy\n */\n\nimport type {\n\tIReasoningStrategy,\n\tStrategyContext,\n\tStrategyDecision,\n} from '../../../contracts/strategy.js';\n\n/**\n * Default sequential strategy. Applies the linear thinking flow:\n *\n * - Continue while `next_thought_needed` is truthy (or unset).\n * - Terminate as soon as `next_thought_needed === false`.\n * - Branch when both `branch_from_thought` and `branch_id` are present.\n *\n * Type-agnostic: all `ThoughtType` variants (including `assumption`,\n * `decomposition`, `backtrack`, `tool_call`, and `tool_observation`) pass\n * through unchanged. The strategy intentionally inspects\n * only `next_thought_needed`, `branch_from_thought`, and `branch_id` —\n * type-aware behavior lives in evaluator/scoring layers, not here.\n *\n * @example\n * ```ts\n * const strategy = new SequentialStrategy();\n * const decision = strategy.decide(ctx);\n * if (decision.action === 'terminate') stop();\n * ```\n */\nexport class SequentialStrategy implements IReasoningStrategy {\n\treadonly name = 'sequential' as const;\n\n\t/**\n\t * Compute the next action for the chain.\n\t *\n\t * @param ctx - Read-only session snapshot.\n\t * @returns `{ action: 'terminate' }` when current thought signals stop,\n\t * otherwise `{ action: 'continue' }`.\n\t */\n\tdecide(ctx: StrategyContext): StrategyDecision {\n\t\tif (ctx.currentThought.next_thought_needed === false) {\n\t\t\treturn { action: 'terminate', reason: 'next_thought_needed=false' };\n\t\t}\n\t\treturn { action: 'continue' };\n\t}\n\n\t/**\n\t * Predicate: should the chain branch right now?\n\t * True iff both `branch_from_thought` and `branch_id` are set on the\n\t * current thought.\n\t */\n\tshouldBranch(ctx: StrategyContext): boolean {\n\t\tconst t = ctx.currentThought;\n\t\treturn t.branch_from_thought !== undefined && t.branch_id !== undefined;\n\t}\n\n\t/**\n\t * Predicate: should the chain terminate right now?\n\t * True iff `next_thought_needed === false`.\n\t */\n\tshouldTerminate(ctx: StrategyContext): boolean {\n\t\treturn ctx.currentThought.next_thought_needed === false;\n\t}\n}\n"],"names":["SequentialStrategy","ctx","t","undefined"],"mappings":"AAqCO,MAAMA;IACH,OAAO,aAAsB;IAStC,OAAOC,GAAoB,EAAoB;QAC9C,IAAIA,AAA2C,UAA3CA,IAAI,cAAc,CAAC,mBAAmB,EACzC,OAAO;YAAE,QAAQ;YAAa,QAAQ;QAA4B;QAEnE,OAAO;YAAE,QAAQ;QAAW;IAC7B;IAOA,aAAaA,GAAoB,EAAW;QAC3C,MAAMC,IAAID,IAAI,cAAc;QAC5B,OAAOC,AAA0BC,WAA1BD,EAAE,mBAAmB,IAAkBA,AAAgBC,WAAhBD,EAAE,SAAS;IAC1D;IAMA,gBAAgBD,GAAoB,EAAW;QAC9C,OAAOA,AAA2C,UAA3CA,IAAI,cAAc,CAAC,mBAAmB;IAC9C;AACD"}
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Observes the frontier (graph leaves), scores each leaf via
5
5
  * {@link scoreThought}, and decides whether to continue, branch (when the
6
- * current thought falls outside the beam), or terminate (on confidence
7
- * threshold or score plateau).
6
+ * current thought falls outside the beam), or terminate (on depth cap,
7
+ * confidence threshold, or score plateau).
8
8
  *
9
9
  * Pure policy: configuration lives in a module-level {@link WeakMap}, not
10
10
  * on the instance, so `Object.getOwnPropertyNames(strategy)` only ever
@@ -46,13 +46,13 @@ export declare class TreeOfThoughtStrategy implements IReasoningStrategy {
46
46
  /**
47
47
  * Compute the next action for the chain.
48
48
  *
49
- * Order of checks: termination by confidence → termination by plateau →
50
- * branch when the current thought is outside the beam → continue.
49
+ * Order of checks: depth cap → confidence → plateau → branch when the
50
+ * current thought is outside the beam → continue. Missing graphs continue.
51
51
  */
52
52
  decide(ctx: StrategyContext): StrategyDecision;
53
- /** True when the frontier is wider than the beam (diverse exploration). */
53
+ /** True below the depth cap when the frontier is wider than the beam. */
54
54
  shouldBranch(ctx: StrategyContext): boolean;
55
- /** True when the best frontier score crosses the threshold OR scores plateau. */
55
+ /** True at the depth cap, confidence threshold, or score plateau. */
56
56
  shouldTerminate(ctx: StrategyContext): boolean;
57
57
  }
58
58
  //# sourceMappingURL=TreeOfThoughtStrategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TreeOfThoughtStrategy.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,MAAM,gCAAgC,CAAC;AAKxC;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACjC;AAgED;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,YAAW,kBAAkB;IAC/D,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAE/B,6CAA6C;gBACjC,MAAM,CAAC,EAAE,SAAS;IAI9B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,gBAAgB;IAiC9C,2EAA2E;IAC3E,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;IAO3C,iFAAiF;IACjF,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;CAY9C"}
1
+ {"version":3,"file":"TreeOfThoughtStrategy.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,MAAM,gCAAgC,CAAC;AAMxC;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACjC;AAsED;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,YAAW,kBAAkB;IAC/D,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAE/B,6CAA6C;gBACjC,MAAM,CAAC,EAAE,SAAS;IAQ9B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,gBAAgB;IAoC9C,yEAAyE;IACzE,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;IAQ3C,qEAAqE;IACrE,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;CAa9C"}
@@ -1,3 +1,4 @@
1
+ import { asThoughtId } from "../../../contracts/ids.js";
1
2
  import { scoreThought, selectBeam } from "./totScoring.js";
2
3
  import { detectPlateau } from "./plateau.js";
3
4
  const DEFAULTS = {
@@ -12,7 +13,7 @@ function configOf(s) {
12
13
  return CONFIGS.get(s) ?? DEFAULTS;
13
14
  }
14
15
  function thoughtKey(t) {
15
- return t.id ?? String(t.thought_number);
16
+ return t.id ?? asThoughtId(String(t.thought_number));
16
17
  }
17
18
  function indexHistory(history) {
18
19
  const out = new Map();
@@ -41,12 +42,19 @@ function recentScores(history, window) {
41
42
  for(let i = start; i < history.length; i++)out.push(scoreThought(history[i]));
42
43
  return out;
43
44
  }
45
+ function isAtDepthCap(ctx, depthCap) {
46
+ const depth = ctx.graph?.depthFromRoots(ctx.sessionId, thoughtKey(ctx.currentThought));
47
+ return void 0 !== depth && depth >= depthCap;
48
+ }
44
49
  class TreeOfThoughtStrategy {
45
50
  name = 'tot';
46
51
  constructor(config){
52
+ const depthCap = config?.depthCap ?? DEFAULTS.depthCap;
53
+ if (!Number.isFinite(depthCap) || !Number.isInteger(depthCap) || depthCap < 0) throw new TypeError('depthCap must be a finite nonnegative integer');
47
54
  CONFIGS.set(this, {
48
55
  ...DEFAULTS,
49
- ...config ?? {}
56
+ ...config,
57
+ depthCap
50
58
  });
51
59
  }
52
60
  decide(ctx) {
@@ -54,6 +62,10 @@ class TreeOfThoughtStrategy {
54
62
  if (!ctx.graph) return {
55
63
  action: 'continue'
56
64
  };
65
+ if (isAtDepthCap(ctx, cfg.depthCap)) return {
66
+ action: 'terminate',
67
+ reason: 'depth cap'
68
+ };
57
69
  const frontier = ctx.graph.leaves(ctx.sessionId);
58
70
  const byKey = indexHistory(ctx.history);
59
71
  const scored = scoreFrontier(frontier, byKey);
@@ -84,12 +96,14 @@ class TreeOfThoughtStrategy {
84
96
  shouldBranch(ctx) {
85
97
  const cfg = configOf(this);
86
98
  if (!ctx.graph) return false;
99
+ if (isAtDepthCap(ctx, cfg.depthCap)) return false;
87
100
  const frontier = ctx.graph.leaves(ctx.sessionId);
88
101
  return frontier.length > cfg.beamWidth;
89
102
  }
90
103
  shouldTerminate(ctx) {
91
104
  const cfg = configOf(this);
92
105
  if (!ctx.graph) return false;
106
+ if (isAtDepthCap(ctx, cfg.depthCap)) return true;
93
107
  const frontier = ctx.graph.leaves(ctx.sessionId);
94
108
  const byKey = indexHistory(ctx.history);
95
109
  const scored = scoreFrontier(frontier, byKey);
@@ -1 +1 @@
1
- {"version":3,"file":"core/reasoning/strategies/TreeOfThoughtStrategy.js","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"sourcesContent":["/**\n * Tree-of-Thought reasoning strategy — beam search over the thought DAG.\n *\n * Observes the frontier (graph leaves), scores each leaf via\n * {@link scoreThought}, and decides whether to continue, branch (when the\n * current thought falls outside the beam), or terminate (on confidence\n * threshold or score plateau).\n *\n * Pure policy: configuration lives in a module-level {@link WeakMap}, not\n * on the instance, so `Object.getOwnPropertyNames(strategy)` only ever\n * surfaces the readonly `name` discriminator. All other state is derived\n * from the {@link StrategyContext} on every call.\n *\n * @module core/reasoning/strategies/TreeOfThoughtStrategy\n */\n\nimport type {\n\tIReasoningStrategy,\n\tStrategyContext,\n\tStrategyDecision,\n} from '../../../contracts/strategy.js';\nimport type { ThoughtData } from '../../thought.js';\nimport { scoreThought, selectBeam, type ScoredCandidate } from './totScoring.js';\nimport { detectPlateau } from './plateau.js';\n\n/**\n * Configuration knobs for {@link TreeOfThoughtStrategy}. All fields are\n * optional; defaults are applied in the constructor.\n */\nexport interface TotConfig {\n\t/** Top-K candidates kept on the frontier (default `3`). */\n\treadonly beamWidth?: number;\n\t/** Maximum exploration depth before forcing termination (default `8`). */\n\treadonly depthCap?: number;\n\t/** Score at/above which the chain terminates (default `0.85`). */\n\treadonly terminationConfidence?: number;\n\t/** Window size for plateau detection (default `3`). */\n\treadonly plateauWindow?: number;\n\t/** Minimum meaningful score change for plateau detection (default `0.02`). */\n\treadonly plateauEpsilon?: number;\n}\n\n/** Defaults applied when a {@link TotConfig} field is omitted. */\nconst DEFAULTS: Required<TotConfig> = {\n\tbeamWidth: 3,\n\tdepthCap: 8,\n\tterminationConfidence: 0.85,\n\tplateauWindow: 3,\n\tplateauEpsilon: 0.02,\n};\n\n/**\n * Module-private config storage. Keyed by strategy instance so that no\n * own-properties leak onto `this` (preserving the purity contract).\n */\nconst CONFIGS: WeakMap<TreeOfThoughtStrategy, Required<TotConfig>> = new WeakMap();\n\n/** Resolve the per-instance config (constructor always populates the map). */\nfunction configOf(s: TreeOfThoughtStrategy): Required<TotConfig> {\n\treturn CONFIGS.get(s) ?? DEFAULTS;\n}\n\n/** Stable identifier for a thought: `id` if present, else its sequence number. */\nfunction thoughtKey(t: ThoughtData): string {\n\treturn t.id ?? String(t.thought_number);\n}\n\n/** Index history by stable key for O(1) leaf-id → ThoughtData lookup. */\nfunction indexHistory(history: readonly ThoughtData[]): Map<string, ThoughtData> {\n\tconst out = new Map<string, ThoughtData>();\n\tfor (const t of history) out.set(thoughtKey(t), t);\n\treturn out;\n}\n\n/** Score the frontier (graph leaves), skipping ids absent from history. */\nfunction scoreFrontier(\n\tfrontier: readonly string[],\n\tbyKey: Map<string, ThoughtData>\n): ScoredCandidate[] {\n\tconst out: ScoredCandidate[] = [];\n\tfor (const id of frontier) {\n\t\tconst t = byKey.get(id);\n\t\tif (t !== undefined) out.push({ id, score: scoreThought(t) });\n\t}\n\treturn out;\n}\n\n/** Highest score in a candidate set, or `-Infinity` when empty. */\nfunction bestScore(scored: readonly ScoredCandidate[]): number {\n\tlet best = Number.NEGATIVE_INFINITY;\n\tfor (const c of scored) {\n\t\tif (c.score > best) best = c.score;\n\t}\n\treturn best;\n}\n\n/** Recent per-thought scores, used for plateau detection. */\nfunction recentScores(history: readonly ThoughtData[], window: number): number[] {\n\tconst start = history.length > window ? history.length - window : 0;\n\tconst out: number[] = [];\n\tfor (let i = start; i < history.length; i++) out.push(scoreThought(history[i]!));\n\treturn out;\n}\n\n/**\n * Tree-of-Thought strategy: beam search over the thought DAG. Pure policy.\n *\n * @example\n * ```typescript\n * const strategy = new TreeOfThoughtStrategy({ beamWidth: 4 });\n * const decision = strategy.decide(ctx);\n * ```\n */\nexport class TreeOfThoughtStrategy implements IReasoningStrategy {\n\treadonly name = 'tot' as const;\n\n\t/** @param config - See {@link TotConfig}. */\n\tconstructor(config?: TotConfig) {\n\t\tCONFIGS.set(this, { ...DEFAULTS, ...(config ?? {}) });\n\t}\n\n\t/**\n\t * Compute the next action for the chain.\n\t *\n\t * Order of checks: termination by confidence → termination by plateau →\n\t * branch when the current thought is outside the beam → continue.\n\t */\n\tdecide(ctx: StrategyContext): StrategyDecision {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) {\n\t\t\treturn { action: 'continue' };\n\t\t}\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\tconst byKey = indexHistory(ctx.history);\n\t\tconst scored = scoreFrontier(frontier, byKey);\n\t\tif (scored.length > 0 && bestScore(scored) >= cfg.terminationConfidence) {\n\t\t\treturn { action: 'terminate', reason: 'confidence threshold' };\n\t\t}\n\n\t\tconst recent = recentScores(ctx.history, cfg.plateauWindow);\n\t\tif (detectPlateau(recent, cfg.plateauWindow, cfg.plateauEpsilon)) {\n\t\t\treturn { action: 'terminate', reason: 'plateau' };\n\t\t}\n\n\t\tif (scored.length > cfg.beamWidth) {\n\t\t\tconst beam = selectBeam(scored, cfg.beamWidth);\n\t\t\tconst currentKey = thoughtKey(ctx.currentThought);\n\t\t\tif (!beam.includes(currentKey)) {\n\t\t\t\treturn {\n\t\t\t\t\taction: 'branch',\n\t\t\t\t\tbranchId: `tot-${ctx.currentThought.thought_number}`,\n\t\t\t\t\tfromThought: ctx.currentThought.thought_number,\n\t\t\t\t\treason: 'outside beam',\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn { action: 'continue', nextHint: 'explore frontier' };\n\t}\n\n\t/** True when the frontier is wider than the beam (diverse exploration). */\n\tshouldBranch(ctx: StrategyContext): boolean {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) return false;\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\treturn frontier.length > cfg.beamWidth;\n\t}\n\n\t/** True when the best frontier score crosses the threshold OR scores plateau. */\n\tshouldTerminate(ctx: StrategyContext): boolean {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) return false;\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\tconst byKey = indexHistory(ctx.history);\n\t\tconst scored = scoreFrontier(frontier, byKey);\n\t\tif (scored.length > 0 && bestScore(scored) >= cfg.terminationConfidence) {\n\t\t\treturn true;\n\t\t}\n\t\tconst recent = recentScores(ctx.history, cfg.plateauWindow);\n\t\treturn detectPlateau(recent, cfg.plateauWindow, cfg.plateauEpsilon);\n\t}\n}\n"],"names":["DEFAULTS","CONFIGS","WeakMap","configOf","s","thoughtKey","t","String","indexHistory","history","out","Map","scoreFrontier","frontier","byKey","id","undefined","scoreThought","bestScore","scored","best","Number","c","recentScores","window","start","i","TreeOfThoughtStrategy","config","ctx","cfg","recent","detectPlateau","beam","selectBeam","currentKey"],"mappings":";;AA2CA,MAAMA,WAAgC;IACrC,WAAW;IACX,UAAU;IACV,uBAAuB;IACvB,eAAe;IACf,gBAAgB;AACjB;AAMA,MAAMC,UAA+D,IAAIC;AAGzE,SAASC,SAASC,CAAwB;IACzC,OAAOH,QAAQ,GAAG,CAACG,MAAMJ;AAC1B;AAGA,SAASK,WAAWC,CAAc;IACjC,OAAOA,EAAE,EAAE,IAAIC,OAAOD,EAAE,cAAc;AACvC;AAGA,SAASE,aAAaC,OAA+B;IACpD,MAAMC,MAAM,IAAIC;IAChB,KAAK,MAAML,KAAKG,QAASC,IAAI,GAAG,CAACL,WAAWC,IAAIA;IAChD,OAAOI;AACR;AAGA,SAASE,cACRC,QAA2B,EAC3BC,KAA+B;IAE/B,MAAMJ,MAAyB,EAAE;IACjC,KAAK,MAAMK,MAAMF,SAAU;QAC1B,MAAMP,IAAIQ,MAAM,GAAG,CAACC;QACpB,IAAIT,AAAMU,WAANV,GAAiBI,IAAI,IAAI,CAAC;YAAEK;YAAI,OAAOE,aAAaX;QAAG;IAC5D;IACA,OAAOI;AACR;AAGA,SAASQ,UAAUC,MAAkC;IACpD,IAAIC,OAAOC,MAAwB;IACnC,KAAK,MAAMC,KAAKH,OACf,IAAIG,EAAE,KAAK,GAAGF,MAAMA,OAAOE,EAAE,KAAK;IAEnC,OAAOF;AACR;AAGA,SAASG,aAAad,OAA+B,EAAEe,MAAc;IACpE,MAAMC,QAAQhB,QAAQ,MAAM,GAAGe,SAASf,QAAQ,MAAM,GAAGe,SAAS;IAClE,MAAMd,MAAgB,EAAE;IACxB,IAAK,IAAIgB,IAAID,OAAOC,IAAIjB,QAAQ,MAAM,EAAEiB,IAAKhB,IAAI,IAAI,CAACO,aAAaR,OAAO,CAACiB,EAAE;IAC7E,OAAOhB;AACR;AAWO,MAAMiB;IACH,OAAO,MAAe;IAG/B,YAAYC,MAAkB,CAAE;QAC/B3B,QAAQ,GAAG,CAAC,IAAI,EAAE;YAAE,GAAGD,QAAQ;YAAE,GAAI4B,UAAU,CAAC,CAAC;QAAE;IACpD;IAQA,OAAOC,GAAoB,EAAoB;QAC9C,MAAMC,MAAM3B,SAAS,IAAI;QACzB,IAAI,CAAC0B,IAAI,KAAK,EACb,OAAO;YAAE,QAAQ;QAAW;QAE7B,MAAMhB,WAAWgB,IAAI,KAAK,CAAC,MAAM,CAACA,IAAI,SAAS;QAC/C,MAAMf,QAAQN,aAAaqB,IAAI,OAAO;QACtC,MAAMV,SAASP,cAAcC,UAAUC;QACvC,IAAIK,OAAO,MAAM,GAAG,KAAKD,UAAUC,WAAWW,IAAI,qBAAqB,EACtE,OAAO;YAAE,QAAQ;YAAa,QAAQ;QAAuB;QAG9D,MAAMC,SAASR,aAAaM,IAAI,OAAO,EAAEC,IAAI,aAAa;QAC1D,IAAIE,cAAcD,QAAQD,IAAI,aAAa,EAAEA,IAAI,cAAc,GAC9D,OAAO;YAAE,QAAQ;YAAa,QAAQ;QAAU;QAGjD,IAAIX,OAAO,MAAM,GAAGW,IAAI,SAAS,EAAE;YAClC,MAAMG,OAAOC,WAAWf,QAAQW,IAAI,SAAS;YAC7C,MAAMK,aAAa9B,WAAWwB,IAAI,cAAc;YAChD,IAAI,CAACI,KAAK,QAAQ,CAACE,aAClB,OAAO;gBACN,QAAQ;gBACR,UAAU,CAAC,IAAI,EAAEN,IAAI,cAAc,CAAC,cAAc,EAAE;gBACpD,aAAaA,IAAI,cAAc,CAAC,cAAc;gBAC9C,QAAQ;YACT;QAEF;QAEA,OAAO;YAAE,QAAQ;YAAY,UAAU;QAAmB;IAC3D;IAGA,aAAaA,GAAoB,EAAW;QAC3C,MAAMC,MAAM3B,SAAS,IAAI;QACzB,IAAI,CAAC0B,IAAI,KAAK,EAAE,OAAO;QACvB,MAAMhB,WAAWgB,IAAI,KAAK,CAAC,MAAM,CAACA,IAAI,SAAS;QAC/C,OAAOhB,SAAS,MAAM,GAAGiB,IAAI,SAAS;IACvC;IAGA,gBAAgBD,GAAoB,EAAW;QAC9C,MAAMC,MAAM3B,SAAS,IAAI;QACzB,IAAI,CAAC0B,IAAI,KAAK,EAAE,OAAO;QACvB,MAAMhB,WAAWgB,IAAI,KAAK,CAAC,MAAM,CAACA,IAAI,SAAS;QAC/C,MAAMf,QAAQN,aAAaqB,IAAI,OAAO;QACtC,MAAMV,SAASP,cAAcC,UAAUC;QACvC,IAAIK,OAAO,MAAM,GAAG,KAAKD,UAAUC,WAAWW,IAAI,qBAAqB,EACtE,OAAO;QAER,MAAMC,SAASR,aAAaM,IAAI,OAAO,EAAEC,IAAI,aAAa;QAC1D,OAAOE,cAAcD,QAAQD,IAAI,aAAa,EAAEA,IAAI,cAAc;IACnE;AACD"}
1
+ {"version":3,"file":"core/reasoning/strategies/TreeOfThoughtStrategy.js","sources":["../../../../src/core/reasoning/strategies/TreeOfThoughtStrategy.ts"],"sourcesContent":["/**\n * Tree-of-Thought reasoning strategy — beam search over the thought DAG.\n *\n * Observes the frontier (graph leaves), scores each leaf via\n * {@link scoreThought}, and decides whether to continue, branch (when the\n * current thought falls outside the beam), or terminate (on depth cap,\n * confidence threshold, or score plateau).\n *\n * Pure policy: configuration lives in a module-level {@link WeakMap}, not\n * on the instance, so `Object.getOwnPropertyNames(strategy)` only ever\n * surfaces the readonly `name` discriminator. All other state is derived\n * from the {@link StrategyContext} on every call.\n *\n * @module core/reasoning/strategies/TreeOfThoughtStrategy\n */\n\nimport type {\n\tIReasoningStrategy,\n\tStrategyContext,\n\tStrategyDecision,\n} from '../../../contracts/strategy.js';\nimport { asThoughtId, type ThoughtId } from '../../../contracts/ids.js';\nimport type { ThoughtData } from '../../thought.js';\nimport { scoreThought, selectBeam, type ScoredCandidate } from './totScoring.js';\nimport { detectPlateau } from './plateau.js';\n\n/**\n * Configuration knobs for {@link TreeOfThoughtStrategy}. All fields are\n * optional; defaults are applied in the constructor.\n */\nexport interface TotConfig {\n\t/** Top-K candidates kept on the frontier (default `3`). */\n\treadonly beamWidth?: number;\n\t/** Maximum exploration depth before forcing termination (default `8`). */\n\treadonly depthCap?: number;\n\t/** Score at/above which the chain terminates (default `0.85`). */\n\treadonly terminationConfidence?: number;\n\t/** Window size for plateau detection (default `3`). */\n\treadonly plateauWindow?: number;\n\t/** Minimum meaningful score change for plateau detection (default `0.02`). */\n\treadonly plateauEpsilon?: number;\n}\n\n/** Defaults applied when a {@link TotConfig} field is omitted. */\nconst DEFAULTS: Required<TotConfig> = {\n\tbeamWidth: 3,\n\tdepthCap: 8,\n\tterminationConfidence: 0.85,\n\tplateauWindow: 3,\n\tplateauEpsilon: 0.02,\n};\n\n/**\n * Module-private config storage. Keyed by strategy instance so that no\n * own-properties leak onto `this` (preserving the purity contract).\n */\nconst CONFIGS: WeakMap<TreeOfThoughtStrategy, Required<TotConfig>> = new WeakMap();\n\n/** Resolve the per-instance config (constructor always populates the map). */\nfunction configOf(s: TreeOfThoughtStrategy): Required<TotConfig> {\n\treturn CONFIGS.get(s) ?? DEFAULTS;\n}\n\n/** Stable identifier for a thought: `id` if present, else its sequence number. */\nfunction thoughtKey(t: ThoughtData): ThoughtId {\n\treturn t.id ?? asThoughtId(String(t.thought_number));\n}\n\n/** Index history by stable key for O(1) leaf-id → ThoughtData lookup. */\nfunction indexHistory(history: readonly ThoughtData[]): Map<string, ThoughtData> {\n\tconst out = new Map<string, ThoughtData>();\n\tfor (const t of history) out.set(thoughtKey(t), t);\n\treturn out;\n}\n\n/** Score the frontier (graph leaves), skipping ids absent from history. */\nfunction scoreFrontier(\n\tfrontier: readonly string[],\n\tbyKey: Map<string, ThoughtData>\n): ScoredCandidate[] {\n\tconst out: ScoredCandidate[] = [];\n\tfor (const id of frontier) {\n\t\tconst t = byKey.get(id);\n\t\tif (t !== undefined) out.push({ id, score: scoreThought(t) });\n\t}\n\treturn out;\n}\n\n/** Highest score in a candidate set, or `-Infinity` when empty. */\nfunction bestScore(scored: readonly ScoredCandidate[]): number {\n\tlet best = Number.NEGATIVE_INFINITY;\n\tfor (const c of scored) {\n\t\tif (c.score > best) best = c.score;\n\t}\n\treturn best;\n}\n\n/** Recent per-thought scores, used for plateau detection. */\nfunction recentScores(history: readonly ThoughtData[], window: number): number[] {\n\tconst start = history.length > window ? history.length - window : 0;\n\tconst out: number[] = [];\n\tfor (let i = start; i < history.length; i++) out.push(scoreThought(history[i]!));\n\treturn out;\n}\n\n/** Whether the current graph-visible thought has reached the configured depth cap. */\nfunction isAtDepthCap(ctx: StrategyContext, depthCap: number): boolean {\n\tconst depth = ctx.graph?.depthFromRoots(ctx.sessionId, thoughtKey(ctx.currentThought));\n\treturn depth !== undefined && depth >= depthCap;\n}\n\n/**\n * Tree-of-Thought strategy: beam search over the thought DAG. Pure policy.\n *\n * @example\n * ```typescript\n * const strategy = new TreeOfThoughtStrategy({ beamWidth: 4 });\n * const decision = strategy.decide(ctx);\n * ```\n */\nexport class TreeOfThoughtStrategy implements IReasoningStrategy {\n\treadonly name = 'tot' as const;\n\n\t/** @param config - See {@link TotConfig}. */\n\tconstructor(config?: TotConfig) {\n\t\tconst depthCap = config?.depthCap ?? DEFAULTS.depthCap;\n\t\tif (!Number.isFinite(depthCap) || !Number.isInteger(depthCap) || depthCap < 0) {\n\t\t\tthrow new TypeError('depthCap must be a finite nonnegative integer');\n\t\t}\n\t\tCONFIGS.set(this, { ...DEFAULTS, ...config, depthCap });\n\t}\n\n\t/**\n\t * Compute the next action for the chain.\n\t *\n\t * Order of checks: depth cap → confidence → plateau → branch when the\n\t * current thought is outside the beam → continue. Missing graphs continue.\n\t */\n\tdecide(ctx: StrategyContext): StrategyDecision {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) {\n\t\t\treturn { action: 'continue' };\n\t\t}\n\t\tif (isAtDepthCap(ctx, cfg.depthCap)) {\n\t\t\treturn { action: 'terminate', reason: 'depth cap' };\n\t\t}\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\tconst byKey = indexHistory(ctx.history);\n\t\tconst scored = scoreFrontier(frontier, byKey);\n\t\tif (scored.length > 0 && bestScore(scored) >= cfg.terminationConfidence) {\n\t\t\treturn { action: 'terminate', reason: 'confidence threshold' };\n\t\t}\n\n\t\tconst recent = recentScores(ctx.history, cfg.plateauWindow);\n\t\tif (detectPlateau(recent, cfg.plateauWindow, cfg.plateauEpsilon)) {\n\t\t\treturn { action: 'terminate', reason: 'plateau' };\n\t\t}\n\n\t\tif (scored.length > cfg.beamWidth) {\n\t\t\tconst beam = selectBeam(scored, cfg.beamWidth);\n\t\t\tconst currentKey = thoughtKey(ctx.currentThought);\n\t\t\tif (!beam.includes(currentKey)) {\n\t\t\t\treturn {\n\t\t\t\t\taction: 'branch',\n\t\t\t\t\tbranchId: `tot-${ctx.currentThought.thought_number}`,\n\t\t\t\t\tfromThought: ctx.currentThought.thought_number,\n\t\t\t\t\treason: 'outside beam',\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn { action: 'continue', nextHint: 'explore frontier' };\n\t}\n\n\t/** True below the depth cap when the frontier is wider than the beam. */\n\tshouldBranch(ctx: StrategyContext): boolean {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) return false;\n\t\tif (isAtDepthCap(ctx, cfg.depthCap)) return false;\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\treturn frontier.length > cfg.beamWidth;\n\t}\n\n\t/** True at the depth cap, confidence threshold, or score plateau. */\n\tshouldTerminate(ctx: StrategyContext): boolean {\n\t\tconst cfg = configOf(this);\n\t\tif (!ctx.graph) return false;\n\t\tif (isAtDepthCap(ctx, cfg.depthCap)) return true;\n\t\tconst frontier = ctx.graph.leaves(ctx.sessionId);\n\t\tconst byKey = indexHistory(ctx.history);\n\t\tconst scored = scoreFrontier(frontier, byKey);\n\t\tif (scored.length > 0 && bestScore(scored) >= cfg.terminationConfidence) {\n\t\t\treturn true;\n\t\t}\n\t\tconst recent = recentScores(ctx.history, cfg.plateauWindow);\n\t\treturn detectPlateau(recent, cfg.plateauWindow, cfg.plateauEpsilon);\n\t}\n}\n"],"names":["DEFAULTS","CONFIGS","WeakMap","configOf","s","thoughtKey","t","asThoughtId","String","indexHistory","history","out","Map","scoreFrontier","frontier","byKey","id","undefined","scoreThought","bestScore","scored","best","Number","c","recentScores","window","start","i","isAtDepthCap","ctx","depthCap","depth","TreeOfThoughtStrategy","config","TypeError","cfg","recent","detectPlateau","beam","selectBeam","currentKey"],"mappings":";;;AA4CA,MAAMA,WAAgC;IACrC,WAAW;IACX,UAAU;IACV,uBAAuB;IACvB,eAAe;IACf,gBAAgB;AACjB;AAMA,MAAMC,UAA+D,IAAIC;AAGzE,SAASC,SAASC,CAAwB;IACzC,OAAOH,QAAQ,GAAG,CAACG,MAAMJ;AAC1B;AAGA,SAASK,WAAWC,CAAc;IACjC,OAAOA,EAAE,EAAE,IAAIC,YAAYC,OAAOF,EAAE,cAAc;AACnD;AAGA,SAASG,aAAaC,OAA+B;IACpD,MAAMC,MAAM,IAAIC;IAChB,KAAK,MAAMN,KAAKI,QAASC,IAAI,GAAG,CAACN,WAAWC,IAAIA;IAChD,OAAOK;AACR;AAGA,SAASE,cACRC,QAA2B,EAC3BC,KAA+B;IAE/B,MAAMJ,MAAyB,EAAE;IACjC,KAAK,MAAMK,MAAMF,SAAU;QAC1B,MAAMR,IAAIS,MAAM,GAAG,CAACC;QACpB,IAAIV,AAAMW,WAANX,GAAiBK,IAAI,IAAI,CAAC;YAAEK;YAAI,OAAOE,aAAaZ;QAAG;IAC5D;IACA,OAAOK;AACR;AAGA,SAASQ,UAAUC,MAAkC;IACpD,IAAIC,OAAOC,MAAwB;IACnC,KAAK,MAAMC,KAAKH,OACf,IAAIG,EAAE,KAAK,GAAGF,MAAMA,OAAOE,EAAE,KAAK;IAEnC,OAAOF;AACR;AAGA,SAASG,aAAad,OAA+B,EAAEe,MAAc;IACpE,MAAMC,QAAQhB,QAAQ,MAAM,GAAGe,SAASf,QAAQ,MAAM,GAAGe,SAAS;IAClE,MAAMd,MAAgB,EAAE;IACxB,IAAK,IAAIgB,IAAID,OAAOC,IAAIjB,QAAQ,MAAM,EAAEiB,IAAKhB,IAAI,IAAI,CAACO,aAAaR,OAAO,CAACiB,EAAE;IAC7E,OAAOhB;AACR;AAGA,SAASiB,aAAaC,GAAoB,EAAEC,QAAgB;IAC3D,MAAMC,QAAQF,IAAI,KAAK,EAAE,eAAeA,IAAI,SAAS,EAAExB,WAAWwB,IAAI,cAAc;IACpF,OAAOE,AAAUd,WAAVc,SAAuBA,SAASD;AACxC;AAWO,MAAME;IACH,OAAO,MAAe;IAG/B,YAAYC,MAAkB,CAAE;QAC/B,MAAMH,WAAWG,QAAQ,YAAYjC,SAAS,QAAQ;QACtD,IAAI,CAACsB,OAAO,QAAQ,CAACQ,aAAa,CAACR,OAAO,SAAS,CAACQ,aAAaA,WAAW,GAC3E,MAAM,IAAII,UAAU;QAErBjC,QAAQ,GAAG,CAAC,IAAI,EAAE;YAAE,GAAGD,QAAQ;YAAE,GAAGiC,MAAM;YAAEH;QAAS;IACtD;IAQA,OAAOD,GAAoB,EAAoB;QAC9C,MAAMM,MAAMhC,SAAS,IAAI;QACzB,IAAI,CAAC0B,IAAI,KAAK,EACb,OAAO;YAAE,QAAQ;QAAW;QAE7B,IAAID,aAAaC,KAAKM,IAAI,QAAQ,GACjC,OAAO;YAAE,QAAQ;YAAa,QAAQ;QAAY;QAEnD,MAAMrB,WAAWe,IAAI,KAAK,CAAC,MAAM,CAACA,IAAI,SAAS;QAC/C,MAAMd,QAAQN,aAAaoB,IAAI,OAAO;QACtC,MAAMT,SAASP,cAAcC,UAAUC;QACvC,IAAIK,OAAO,MAAM,GAAG,KAAKD,UAAUC,WAAWe,IAAI,qBAAqB,EACtE,OAAO;YAAE,QAAQ;YAAa,QAAQ;QAAuB;QAG9D,MAAMC,SAASZ,aAAaK,IAAI,OAAO,EAAEM,IAAI,aAAa;QAC1D,IAAIE,cAAcD,QAAQD,IAAI,aAAa,EAAEA,IAAI,cAAc,GAC9D,OAAO;YAAE,QAAQ;YAAa,QAAQ;QAAU;QAGjD,IAAIf,OAAO,MAAM,GAAGe,IAAI,SAAS,EAAE;YAClC,MAAMG,OAAOC,WAAWnB,QAAQe,IAAI,SAAS;YAC7C,MAAMK,aAAanC,WAAWwB,IAAI,cAAc;YAChD,IAAI,CAACS,KAAK,QAAQ,CAACE,aAClB,OAAO;gBACN,QAAQ;gBACR,UAAU,CAAC,IAAI,EAAEX,IAAI,cAAc,CAAC,cAAc,EAAE;gBACpD,aAAaA,IAAI,cAAc,CAAC,cAAc;gBAC9C,QAAQ;YACT;QAEF;QAEA,OAAO;YAAE,QAAQ;YAAY,UAAU;QAAmB;IAC3D;IAGA,aAAaA,GAAoB,EAAW;QAC3C,MAAMM,MAAMhC,SAAS,IAAI;QACzB,IAAI,CAAC0B,IAAI,KAAK,EAAE,OAAO;QACvB,IAAID,aAAaC,KAAKM,IAAI,QAAQ,GAAG,OAAO;QAC5C,MAAMrB,WAAWe,IAAI,KAAK,CAAC,MAAM,CAACA,IAAI,SAAS;QAC/C,OAAOf,SAAS,MAAM,GAAGqB,IAAI,SAAS;IACvC;IAGA,gBAAgBN,GAAoB,EAAW;QAC9C,MAAMM,MAAMhC,SAAS,IAAI;QACzB,IAAI,CAAC0B,IAAI,KAAK,EAAE,OAAO;QACvB,IAAID,aAAaC,KAAKM,IAAI,QAAQ,GAAG,OAAO;QAC5C,MAAMrB,WAAWe,IAAI,KAAK,CAAC,MAAM,CAACA,IAAI,SAAS;QAC/C,MAAMd,QAAQN,aAAaoB,IAAI,OAAO;QACtC,MAAMT,SAASP,cAAcC,UAAUC;QACvC,IAAIK,OAAO,MAAM,GAAG,KAAKD,UAAUC,WAAWe,IAAI,qBAAqB,EACtE,OAAO;QAER,MAAMC,SAASZ,aAAaK,IAAI,OAAO,EAAEM,IAAI,aAAa;QAC1D,OAAOE,cAAcD,QAAQD,IAAI,aAAa,EAAEA,IAAI,cAAc;IACnE;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"totScoring.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/totScoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,2BAA2B,CAAC;AAYtE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAuCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAQnD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CACzB,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,KAAK,EAAE,MAAM,GACX,SAAS,MAAM,EAAE,CAcnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,QAAQ,EAAE,MAAM,GACd,SAAS,MAAM,EAAE,CAqDnB"}
1
+ {"version":3,"file":"totScoring.d.ts","sourceRoot":"","sources":["../../../../src/core/reasoning/strategies/totScoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,2BAA2B,CAAC;AAYtE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAuCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAQnD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CACzB,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,KAAK,EAAE,MAAM,GACX,SAAS,MAAM,EAAE,CAcnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,QAAQ,EAAE,MAAM,GACd,SAAS,MAAM,EAAE,CAqDnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"core/reasoning/strategies/totScoring.js","sources":["../../../../src/core/reasoning/strategies/totScoring.ts"],"sourcesContent":["/**\n * Tree-of-Thought scoring helpers — pure functions for ranking and frontier\n * exploration over the thought DAG.\n *\n * This module exposes three primitives used by the ToT strategy:\n *\n * - {@link scoreThought}: combine confidence and quality into a [0, 1] score.\n * - {@link selectBeam}: pick the top-K candidates with deterministic tiebreaks.\n * - {@link breadthFirstFrontier}: BFS from roots, returning leaves of the\n * explored subgraph capped by depth.\n *\n * All functions are pure: no I/O, no mutable module state, no DI.\n *\n * @module core/reasoning/strategies/totScoring\n */\n\nimport type { ThoughtData } from '../../thought.js';\nimport type { ConfidenceSignals, ThoughtType } from '../../reasoning.js';\nimport type { GraphView } from '../../graph/GraphView.js';\nimport type { SessionId, ThoughtId } from '../../../contracts/ids.js';\nimport { assertNever } from '../../../utils.js';\n\n/**\n * Optional `confidence_signals` carried alongside a thought. The core\n * `ThoughtData` type does not declare this field, but evaluator output may\n * be attached by callers that want calibrated scoring.\n */\ntype ThoughtWithSignals = ThoughtData & {\n\treadonly confidence_signals?: ConfidenceSignals;\n};\n\n/**\n * A scored candidate suitable for {@link selectBeam}.\n */\nexport interface ScoredCandidate {\n\treadonly id: string;\n\treadonly score: number;\n}\n\n/**\n * Per-type score multiplier applied on top of the base confidence×quality score.\n *\n * Weights bias the ToT frontier towards productive thought kinds:\n * - `assumption` (0.5): low confidence until backed by verification.\n * - `decomposition` (1.2): encouraged for problem-splitting.\n * - `backtrack` (0.8): signals exploration but not preferred.\n * - `tool_call` / `tool_observation` (1.0): neutral exogenous information.\n * - All other types (regular, hypothesis, verification, critique, synthesis, meta): 1.0.\n *\n * Pure function: deterministic, no I/O.\n */\nfunction getTypeWeight(type: ThoughtType | undefined): number {\n\tif (type === undefined) return 1.0;\n\tswitch (type) {\n\t\tcase 'assumption':\n\t\t\treturn 0.5;\n\t\tcase 'decomposition':\n\t\t\treturn 1.2;\n\t\tcase 'backtrack':\n\t\t\treturn 0.8;\n\t\tcase 'tool_call':\n\t\t\treturn 1.0;\n\t\tcase 'tool_observation':\n\t\t\treturn 1.0;\n\t\tcase 'regular':\n\t\tcase 'hypothesis':\n\t\tcase 'verification':\n\t\tcase 'critique':\n\t\tcase 'synthesis':\n\t\tcase 'meta':\n\t\t\treturn 1.0;\n\t\tdefault:\n\t\t\treturn assertNever(type);\n\t}\n}\n\n/**\n * Score a thought by combining its (calibrated) confidence with its\n * self-assessed quality, then applying a per-type weight.\n *\n * Formula: `(calibrated_confidence ?? confidence ?? 0) * (quality_score ?? 0.5) * typeWeight(thought_type)`\n *\n * The `calibrated_confidence` (when present on `confidence_signals`) is\n * preferred over the raw `confidence` field. The result is clamped to the\n * inclusive range `[0, 1]`.\n *\n * @param t - The thought to score.\n * @returns A score in `[0, 1]`.\n *\n * @example\n * ```typescript\n * const s = scoreThought({ ...base, confidence: 0.8, quality_score: 0.5 });\n * // s === 0.4\n * ```\n */\nexport function scoreThought(t: ThoughtData): number {\n\tconst calibrated = (t as ThoughtWithSignals).confidence_signals?.calibrated_confidence;\n\tconst confidence = calibrated ?? t.confidence ?? 0;\n\tconst quality = t.quality_score ?? 0.5;\n\tconst raw = confidence * quality * getTypeWeight(t.thought_type);\n\tif (raw < 0) return 0;\n\tif (raw > 1) return 1;\n\treturn raw;\n}\n\n/**\n * Select the top-`width` candidates by score, descending.\n *\n * Sorting is stable and deterministic: ties on `score` are broken by\n * lexicographic comparison of `id` (ascending). When `width >= candidates.length`\n * all candidates are returned in sorted order. When `width <= 0` the result\n * is empty.\n *\n * @param candidates - Scored candidates (input is not mutated).\n * @param width - Beam width (top-K).\n * @returns Selected ids in descending score order.\n *\n * @example\n * ```typescript\n * const top = selectBeam([{ id: 'a', score: 0.1 }, { id: 'b', score: 0.9 }], 1);\n * // top === ['b']\n * ```\n */\nexport function selectBeam(\n\tcandidates: readonly ScoredCandidate[],\n\twidth: number\n): readonly string[] {\n\tif (width <= 0 || candidates.length === 0) {\n\t\treturn [];\n\t}\n\tconst sorted = [...candidates].sort((a, b) => {\n\t\tif (b.score !== a.score) return b.score - a.score;\n\t\treturn a.id < b.id ? -1 : 1;\n\t});\n\tconst k = width >= sorted.length ? sorted.length : width;\n\tconst result: string[] = [];\n\tfor (let i = 0; i < k; i++) {\n\t\tresult.push(sorted[i]!.id);\n\t}\n\treturn result;\n}\n\n/**\n * Compute the BFS frontier reachable from `roots` within `depthCap` levels.\n *\n * Traverses outgoing edges via `graph.descendants(sessionId, id, 1)`. The returned\n * set contains the *leaves* of the explored subgraph — nodes that either\n * (a) sit at the depth cap, or (b) have no outgoing edges within the\n * explored region.\n *\n * Special cases:\n * - `depthCap === 0` returns the unique roots in input order.\n * - empty `roots` returns an empty array.\n *\n * Each node is visited at most once, so cycles cannot cause infinite loops.\n *\n * @param graph - Read-only graph view.\n * @param sessionId - Session scoping the traversal.\n * @param roots - Starting thought ids.\n * @param depthCap - Maximum BFS depth (0 = roots only).\n * @returns Frontier (leaf) thought ids of the explored subgraph.\n *\n * @example\n * ```typescript\n * const frontier = breadthFirstFrontier(view, 's1', ['root'], 2);\n * ```\n */\nexport function breadthFirstFrontier(\n\tgraph: GraphView,\n\tsessionId: SessionId,\n\troots: readonly string[],\n\tdepthCap: number\n): readonly string[] {\n\tif (roots.length === 0) {\n\t\treturn [];\n\t}\n\tconst uniqueRoots: string[] = [];\n\tconst seenRoots = new Set<string>();\n\tfor (const r of roots) {\n\t\tif (!seenRoots.has(r)) {\n\t\t\tseenRoots.add(r);\n\t\t\tuniqueRoots.push(r);\n\t\t}\n\t}\n\tif (depthCap <= 0) {\n\t\treturn uniqueRoots;\n\t}\n\n\tconst visited = new Set<string>(uniqueRoots);\n\tlet frontier: string[] = [...uniqueRoots];\n\tlet depth = 0;\n\n\twhile (frontier.length > 0 && depth < depthCap) {\n\t\tconst next: string[] = [];\n\t\tfor (const node of frontier) {\n\t\t\tfor (const child of graph.descendants(sessionId, node as ThoughtId, 1)) {\n\t\t\t\tif (visited.has(child)) continue;\n\t\t\t\tvisited.add(child);\n\t\t\t\tnext.push(child);\n\t\t\t}\n\t\t}\n\t\tfrontier = next;\n\t\tdepth++;\n\t}\n\n\tconst explored = visited;\n\tconst leaves: string[] = [];\n\tconst seenLeaf = new Set<string>();\n\tconst collect = (id: string): void => {\n\t\tseenLeaf.add(id);\n\t\tleaves.push(id);\n\t};\n\n\tif (depth >= depthCap && frontier.length > 0) {\n\t\t// Hit the depth cap — current frontier is leaves regardless of children.\n\t\tfor (const id of frontier) collect(id);\n\t}\n\t// Any explored node with no outgoing edges inside the explored set is also\n\t// a leaf (covers nodes shallower than depthCap that terminated naturally).\n\tfor (const id of explored) {\n\t\tif (seenLeaf.has(id)) continue;\n\t\tconst children = graph.descendants(sessionId, id as ThoughtId, 1);\n\t\tif (children.length === 0) collect(id);\n\t}\n\treturn leaves;\n}\n"],"names":["getTypeWeight","type","undefined","assertNever","scoreThought","t","calibrated","confidence","quality","raw","selectBeam","candidates","width","sorted","a","b","k","result","i","breadthFirstFrontier","graph","sessionId","roots","depthCap","uniqueRoots","seenRoots","Set","r","visited","frontier","depth","next","node","child","explored","leaves","seenLeaf","collect","id","children"],"mappings":";AAmDA,SAASA,cAAcC,IAA6B;IACnD,IAAIA,AAASC,WAATD,MAAoB,OAAO;IAC/B,OAAQA;QACP,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;YACJ,OAAO;QACR;YACC,OAAOE,YAAYF;IACrB;AACD;AAqBO,SAASG,aAAaC,CAAc;IAC1C,MAAMC,aAAcD,EAAyB,kBAAkB,EAAE;IACjE,MAAME,aAAaD,cAAcD,EAAE,UAAU,IAAI;IACjD,MAAMG,UAAUH,EAAE,aAAa,IAAI;IACnC,MAAMI,MAAMF,aAAaC,UAAUR,cAAcK,EAAE,YAAY;IAC/D,IAAII,MAAM,GAAG,OAAO;IACpB,IAAIA,MAAM,GAAG,OAAO;IACpB,OAAOA;AACR;AAoBO,SAASC,WACfC,UAAsC,EACtCC,KAAa;IAEb,IAAIA,SAAS,KAAKD,AAAsB,MAAtBA,WAAW,MAAM,EAClC,OAAO,EAAE;IAEV,MAAME,SAAS;WAAIF;KAAW,CAAC,IAAI,CAAC,CAACG,GAAGC;QACvC,IAAIA,EAAE,KAAK,KAAKD,EAAE,KAAK,EAAE,OAAOC,EAAE,KAAK,GAAGD,EAAE,KAAK;QACjD,OAAOA,EAAE,EAAE,GAAGC,EAAE,EAAE,GAAG,KAAK;IAC3B;IACA,MAAMC,IAAIJ,SAASC,OAAO,MAAM,GAAGA,OAAO,MAAM,GAAGD;IACnD,MAAMK,SAAmB,EAAE;IAC3B,IAAK,IAAIC,IAAI,GAAGA,IAAIF,GAAGE,IACtBD,OAAO,IAAI,CAACJ,MAAM,CAACK,EAAE,CAAE,EAAE;IAE1B,OAAOD;AACR;AA2BO,SAASE,qBACfC,KAAgB,EAChBC,SAAoB,EACpBC,KAAwB,EACxBC,QAAgB;IAEhB,IAAID,AAAiB,MAAjBA,MAAM,MAAM,EACf,OAAO,EAAE;IAEV,MAAME,cAAwB,EAAE;IAChC,MAAMC,YAAY,IAAIC;IACtB,KAAK,MAAMC,KAAKL,MACf,IAAI,CAACG,UAAU,GAAG,CAACE,IAAI;QACtBF,UAAU,GAAG,CAACE;QACdH,YAAY,IAAI,CAACG;IAClB;IAED,IAAIJ,YAAY,GACf,OAAOC;IAGR,MAAMI,UAAU,IAAIF,IAAYF;IAChC,IAAIK,WAAqB;WAAIL;KAAY;IACzC,IAAIM,QAAQ;IAEZ,MAAOD,SAAS,MAAM,GAAG,KAAKC,QAAQP,SAAU;QAC/C,MAAMQ,OAAiB,EAAE;QACzB,KAAK,MAAMC,QAAQH,SAClB,KAAK,MAAMI,SAASb,MAAM,WAAW,CAACC,WAAWW,MAAmB,GACnE,KAAIJ,QAAQ,GAAG,CAACK;YAChBL,QAAQ,GAAG,CAACK;YACZF,KAAK,IAAI,CAACE;;QAGZJ,WAAWE;QACXD;IACD;IAEA,MAAMI,WAAWN;IACjB,MAAMO,SAAmB,EAAE;IAC3B,MAAMC,WAAW,IAAIV;IACrB,MAAMW,UAAU,CAACC;QAChBF,SAAS,GAAG,CAACE;QACbH,OAAO,IAAI,CAACG;IACb;IAEA,IAAIR,SAASP,YAAYM,SAAS,MAAM,GAAG,GAE1C,KAAK,MAAMS,MAAMT,SAAUQ,QAAQC;IAIpC,KAAK,MAAMA,MAAMJ,SAAU;QAC1B,IAAIE,SAAS,GAAG,CAACE,KAAK;QACtB,MAAMC,WAAWnB,MAAM,WAAW,CAACC,WAAWiB,IAAiB;QAC/D,IAAIC,AAAoB,MAApBA,SAAS,MAAM,EAAQF,QAAQC;IACpC;IACA,OAAOH;AACR"}
1
+ {"version":3,"file":"core/reasoning/strategies/totScoring.js","sources":["../../../../src/core/reasoning/strategies/totScoring.ts"],"sourcesContent":["/**\n * Tree-of-Thought scoring helpers — pure functions for ranking and frontier\n * exploration over the thought DAG.\n *\n * This module exposes three primitives used by the ToT strategy:\n *\n * - {@link scoreThought}: combine confidence and quality into a [0, 1] score.\n * - {@link selectBeam}: pick the top-K candidates with deterministic tiebreaks.\n * - {@link breadthFirstFrontier}: BFS from roots, returning leaves of the\n * explored subgraph capped by depth.\n *\n * All functions are pure: no I/O, no mutable module state, no DI.\n *\n * @module core/reasoning/strategies/totScoring\n */\n\nimport type { ThoughtData } from '../../thought.js';\nimport type { ThoughtType } from '../../../contracts/reasoning-types.js';\nimport type { ConfidenceSignals } from '../../reasoning.js';\nimport type { GraphView } from '../../graph/GraphView.js';\nimport type { SessionId, ThoughtId } from '../../../contracts/ids.js';\nimport { assertNever } from '../../../utils.js';\n\n/**\n * Optional `confidence_signals` carried alongside a thought. The core\n * `ThoughtData` type does not declare this field, but evaluator output may\n * be attached by callers that want calibrated scoring.\n */\ntype ThoughtWithSignals = ThoughtData & {\n\treadonly confidence_signals?: ConfidenceSignals;\n};\n\n/**\n * A scored candidate suitable for {@link selectBeam}.\n */\nexport interface ScoredCandidate {\n\treadonly id: string;\n\treadonly score: number;\n}\n\n/**\n * Per-type score multiplier applied on top of the base confidence×quality score.\n *\n * Weights bias the ToT frontier towards productive thought kinds:\n * - `assumption` (0.5): low confidence until backed by verification.\n * - `decomposition` (1.2): encouraged for problem-splitting.\n * - `backtrack` (0.8): signals exploration but not preferred.\n * - `tool_call` / `tool_observation` (1.0): neutral exogenous information.\n * - All other types (regular, hypothesis, verification, critique, synthesis, meta): 1.0.\n *\n * Pure function: deterministic, no I/O.\n */\nfunction getTypeWeight(type: ThoughtType | undefined): number {\n\tif (type === undefined) return 1.0;\n\tswitch (type) {\n\t\tcase 'assumption':\n\t\t\treturn 0.5;\n\t\tcase 'decomposition':\n\t\t\treturn 1.2;\n\t\tcase 'backtrack':\n\t\t\treturn 0.8;\n\t\tcase 'tool_call':\n\t\t\treturn 1.0;\n\t\tcase 'tool_observation':\n\t\t\treturn 1.0;\n\t\tcase 'regular':\n\t\tcase 'hypothesis':\n\t\tcase 'verification':\n\t\tcase 'critique':\n\t\tcase 'synthesis':\n\t\tcase 'meta':\n\t\t\treturn 1.0;\n\t\tdefault:\n\t\t\treturn assertNever(type);\n\t}\n}\n\n/**\n * Score a thought by combining its (calibrated) confidence with its\n * self-assessed quality, then applying a per-type weight.\n *\n * Formula: `(calibrated_confidence ?? confidence ?? 0) * (quality_score ?? 0.5) * typeWeight(thought_type)`\n *\n * The `calibrated_confidence` (when present on `confidence_signals`) is\n * preferred over the raw `confidence` field. The result is clamped to the\n * inclusive range `[0, 1]`.\n *\n * @param t - The thought to score.\n * @returns A score in `[0, 1]`.\n *\n * @example\n * ```typescript\n * const s = scoreThought({ ...base, confidence: 0.8, quality_score: 0.5 });\n * // s === 0.4\n * ```\n */\nexport function scoreThought(t: ThoughtData): number {\n\tconst calibrated = (t as ThoughtWithSignals).confidence_signals?.calibrated_confidence;\n\tconst confidence = calibrated ?? t.confidence ?? 0;\n\tconst quality = t.quality_score ?? 0.5;\n\tconst raw = confidence * quality * getTypeWeight(t.thought_type);\n\tif (raw < 0) return 0;\n\tif (raw > 1) return 1;\n\treturn raw;\n}\n\n/**\n * Select the top-`width` candidates by score, descending.\n *\n * Sorting is stable and deterministic: ties on `score` are broken by\n * lexicographic comparison of `id` (ascending). When `width >= candidates.length`\n * all candidates are returned in sorted order. When `width <= 0` the result\n * is empty.\n *\n * @param candidates - Scored candidates (input is not mutated).\n * @param width - Beam width (top-K).\n * @returns Selected ids in descending score order.\n *\n * @example\n * ```typescript\n * const top = selectBeam([{ id: 'a', score: 0.1 }, { id: 'b', score: 0.9 }], 1);\n * // top === ['b']\n * ```\n */\nexport function selectBeam(\n\tcandidates: readonly ScoredCandidate[],\n\twidth: number\n): readonly string[] {\n\tif (width <= 0 || candidates.length === 0) {\n\t\treturn [];\n\t}\n\tconst sorted = [...candidates].sort((a, b) => {\n\t\tif (b.score !== a.score) return b.score - a.score;\n\t\treturn a.id < b.id ? -1 : 1;\n\t});\n\tconst k = width >= sorted.length ? sorted.length : width;\n\tconst result: string[] = [];\n\tfor (let i = 0; i < k; i++) {\n\t\tresult.push(sorted[i]!.id);\n\t}\n\treturn result;\n}\n\n/**\n * Compute the BFS frontier reachable from `roots` within `depthCap` levels.\n *\n * Traverses outgoing edges via `graph.descendants(sessionId, id, 1)`. The returned\n * set contains the *leaves* of the explored subgraph — nodes that either\n * (a) sit at the depth cap, or (b) have no outgoing edges within the\n * explored region.\n *\n * Special cases:\n * - `depthCap === 0` returns the unique roots in input order.\n * - empty `roots` returns an empty array.\n *\n * Each node is visited at most once, so cycles cannot cause infinite loops.\n *\n * @param graph - Read-only graph view.\n * @param sessionId - Session scoping the traversal.\n * @param roots - Starting thought ids.\n * @param depthCap - Maximum BFS depth (0 = roots only).\n * @returns Frontier (leaf) thought ids of the explored subgraph.\n *\n * @example\n * ```typescript\n * const frontier = breadthFirstFrontier(view, 's1', ['root'], 2);\n * ```\n */\nexport function breadthFirstFrontier(\n\tgraph: GraphView,\n\tsessionId: SessionId,\n\troots: readonly string[],\n\tdepthCap: number\n): readonly string[] {\n\tif (roots.length === 0) {\n\t\treturn [];\n\t}\n\tconst uniqueRoots: string[] = [];\n\tconst seenRoots = new Set<string>();\n\tfor (const r of roots) {\n\t\tif (!seenRoots.has(r)) {\n\t\t\tseenRoots.add(r);\n\t\t\tuniqueRoots.push(r);\n\t\t}\n\t}\n\tif (depthCap <= 0) {\n\t\treturn uniqueRoots;\n\t}\n\n\tconst visited = new Set<string>(uniqueRoots);\n\tlet frontier: string[] = [...uniqueRoots];\n\tlet depth = 0;\n\n\twhile (frontier.length > 0 && depth < depthCap) {\n\t\tconst next: string[] = [];\n\t\tfor (const node of frontier) {\n\t\t\tfor (const child of graph.descendants(sessionId, node as ThoughtId, 1)) {\n\t\t\t\tif (visited.has(child)) continue;\n\t\t\t\tvisited.add(child);\n\t\t\t\tnext.push(child);\n\t\t\t}\n\t\t}\n\t\tfrontier = next;\n\t\tdepth++;\n\t}\n\n\tconst explored = visited;\n\tconst leaves: string[] = [];\n\tconst seenLeaf = new Set<string>();\n\tconst collect = (id: string): void => {\n\t\tseenLeaf.add(id);\n\t\tleaves.push(id);\n\t};\n\n\tif (depth >= depthCap && frontier.length > 0) {\n\t\t// Hit the depth cap — current frontier is leaves regardless of children.\n\t\tfor (const id of frontier) collect(id);\n\t}\n\t// Any explored node with no outgoing edges inside the explored set is also\n\t// a leaf (covers nodes shallower than depthCap that terminated naturally).\n\tfor (const id of explored) {\n\t\tif (seenLeaf.has(id)) continue;\n\t\tconst children = graph.descendants(sessionId, id as ThoughtId, 1);\n\t\tif (children.length === 0) collect(id);\n\t}\n\treturn leaves;\n}\n"],"names":["getTypeWeight","type","undefined","assertNever","scoreThought","t","calibrated","confidence","quality","raw","selectBeam","candidates","width","sorted","a","b","k","result","i","breadthFirstFrontier","graph","sessionId","roots","depthCap","uniqueRoots","seenRoots","Set","r","visited","frontier","depth","next","node","child","explored","leaves","seenLeaf","collect","id","children"],"mappings":";AAoDA,SAASA,cAAcC,IAA6B;IACnD,IAAIA,AAASC,WAATD,MAAoB,OAAO;IAC/B,OAAQA;QACP,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;YACJ,OAAO;QACR,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;YACJ,OAAO;QACR;YACC,OAAOE,YAAYF;IACrB;AACD;AAqBO,SAASG,aAAaC,CAAc;IAC1C,MAAMC,aAAcD,EAAyB,kBAAkB,EAAE;IACjE,MAAME,aAAaD,cAAcD,EAAE,UAAU,IAAI;IACjD,MAAMG,UAAUH,EAAE,aAAa,IAAI;IACnC,MAAMI,MAAMF,aAAaC,UAAUR,cAAcK,EAAE,YAAY;IAC/D,IAAII,MAAM,GAAG,OAAO;IACpB,IAAIA,MAAM,GAAG,OAAO;IACpB,OAAOA;AACR;AAoBO,SAASC,WACfC,UAAsC,EACtCC,KAAa;IAEb,IAAIA,SAAS,KAAKD,AAAsB,MAAtBA,WAAW,MAAM,EAClC,OAAO,EAAE;IAEV,MAAME,SAAS;WAAIF;KAAW,CAAC,IAAI,CAAC,CAACG,GAAGC;QACvC,IAAIA,EAAE,KAAK,KAAKD,EAAE,KAAK,EAAE,OAAOC,EAAE,KAAK,GAAGD,EAAE,KAAK;QACjD,OAAOA,EAAE,EAAE,GAAGC,EAAE,EAAE,GAAG,KAAK;IAC3B;IACA,MAAMC,IAAIJ,SAASC,OAAO,MAAM,GAAGA,OAAO,MAAM,GAAGD;IACnD,MAAMK,SAAmB,EAAE;IAC3B,IAAK,IAAIC,IAAI,GAAGA,IAAIF,GAAGE,IACtBD,OAAO,IAAI,CAACJ,MAAM,CAACK,EAAE,CAAE,EAAE;IAE1B,OAAOD;AACR;AA2BO,SAASE,qBACfC,KAAgB,EAChBC,SAAoB,EACpBC,KAAwB,EACxBC,QAAgB;IAEhB,IAAID,AAAiB,MAAjBA,MAAM,MAAM,EACf,OAAO,EAAE;IAEV,MAAME,cAAwB,EAAE;IAChC,MAAMC,YAAY,IAAIC;IACtB,KAAK,MAAMC,KAAKL,MACf,IAAI,CAACG,UAAU,GAAG,CAACE,IAAI;QACtBF,UAAU,GAAG,CAACE;QACdH,YAAY,IAAI,CAACG;IAClB;IAED,IAAIJ,YAAY,GACf,OAAOC;IAGR,MAAMI,UAAU,IAAIF,IAAYF;IAChC,IAAIK,WAAqB;WAAIL;KAAY;IACzC,IAAIM,QAAQ;IAEZ,MAAOD,SAAS,MAAM,GAAG,KAAKC,QAAQP,SAAU;QAC/C,MAAMQ,OAAiB,EAAE;QACzB,KAAK,MAAMC,QAAQH,SAClB,KAAK,MAAMI,SAASb,MAAM,WAAW,CAACC,WAAWW,MAAmB,GACnE,KAAIJ,QAAQ,GAAG,CAACK;YAChBL,QAAQ,GAAG,CAACK;YACZF,KAAK,IAAI,CAACE;;QAGZJ,WAAWE;QACXD;IACD;IAEA,MAAMI,WAAWN;IACjB,MAAMO,SAAmB,EAAE;IAC3B,MAAMC,WAAW,IAAIV;IACrB,MAAMW,UAAU,CAACC;QAChBF,SAAS,GAAG,CAACE;QACbH,OAAO,IAAI,CAACG;IACb;IAEA,IAAIR,SAASP,YAAYM,SAAS,MAAM,GAAG,GAE1C,KAAK,MAAMS,MAAMT,SAAUQ,QAAQC;IAIpC,KAAK,MAAMA,MAAMJ,SAAU;QAC1B,IAAIE,SAAS,GAAG,CAACE,KAAK;QACtB,MAAMC,WAAWnB,MAAM,WAAW,CAACC,WAAWiB,IAAiB;QAC/D,IAAIC,AAAoB,MAApBA,SAAS,MAAM,EAAQF,QAAQC;IACpC;IACA,OAAOH;AACR"}
@@ -7,9 +7,7 @@
7
7
  * @module core/reasoning
8
8
  */
9
9
  import type { CalibrationMetrics } from '../contracts/calibrator.js';
10
- import type { PatternName as ContractPatternName, ThoughtType as ContractThoughtType } from '../contracts/reasoning-types.js';
11
- export type ThoughtType = ContractThoughtType;
12
- export type PatternName = ContractPatternName;
10
+ import type { PatternName, ThoughtType } from '../contracts/reasoning-types.js';
13
11
  /**
14
12
  * A detected reasoning pattern — surfaced as metadata or a warning.
15
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"reasoning.d.ts","sourceRoot":"","sources":["../../src/core/reasoning.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reasoning.d.ts","sourceRoot":"","sources":["../../src/core/reasoning.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,7 @@ import type { StepRecommendation } from './step.js';
27
27
  * thought: 'I should read the package.json to understand dependencies',
28
28
  * thought_number: 1,
29
29
  * total_thoughts: 5,
30
+ * session_id: asSessionId('package-analysis'),
30
31
  * next_thought_needed: true,
31
32
  * current_step: {
32
33
  * step_description: 'Read package.json',
@@ -45,7 +46,7 @@ export type ThoughtData = Omit<SchemaOutput, 'id' | 'session_id' | 'continuation
45
46
  /** Unique identifier for this thought (branded ThoughtId). Auto-generated when not provided. */
46
47
  id?: ThoughtId;
47
48
  /** Session identifier (branded SessionId) for state isolation. */
48
- session_id?: SessionId;
49
+ session_id: SessionId;
49
50
  /** Continuation token (branded SuspensionToken) linking tool_observation back to suspended tool_call. */
50
51
  continuation_token?: SuspensionToken;
51
52
  /** Branch identifier (branded BranchId) for branching reasoning paths. */
@@ -69,7 +70,7 @@ export type ThoughtData = Omit<SchemaOutput, 'id' | 'session_id' | 'continuation
69
70
  * has guaranteed per-type invariants. Allows downstream methods to consume
70
71
  * narrowed thoughts without `!` non-null assertions.
71
72
  */
72
- import type { ThoughtType } from './reasoning.js';
73
+ import type { ThoughtType } from '../contracts/reasoning-types.js';
73
74
  /** A `tool_call` thought with `tool_name` guaranteed by validation. */
74
75
  export type ToolCallThought = ThoughtData & {
75
76
  readonly thought_type: 'tool_call';
@@ -1 +1 @@
1
- {"version":3,"file":"thought.d.ts","sourceRoot":"","sources":["../../src/core/thought.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAC7B,YAAY,EACV,IAAI,GACJ,YAAY,GACZ,oBAAoB,GACpB,oBAAoB,GACpB,WAAW,GACX,kBAAkB,GAClB,cAAc,GACd,gBAAgB,CAClB,GAAG;IACH,gGAAgG;IAChG,EAAE,CAAC,EAAE,SAAS,CAAC;IAEf,kEAAkE;IAClE,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB,yGAAyG;IACzG,kBAAkB,CAAC,EAAE,eAAe,CAAC;IAErC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,QAAQ,CAAC;IAErB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,QAAQ,EAAE,CAAC;IAE9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAElC,+EAA+E;IAC/E,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACtC,CAAC;AAEF;;;;GAIG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,uEAAuE;AACvE,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC3C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG;IAClD,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,eAAe,CAAC;CAC7C,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG;IAC5C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAC/C,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC3C,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG;IAC5C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG;IACvC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAC7B,WAAW,EACX,WAAW,GAAG,kBAAkB,GAAG,WAAW,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,CAC1F,CAAC;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACzB,eAAe,GACf,sBAAsB,GACtB,gBAAgB,GAChB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,WAAW,CAAC"}
1
+ {"version":3,"file":"thought.d.ts","sourceRoot":"","sources":["../../src/core/thought.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAC7B,YAAY,EACV,IAAI,GACJ,YAAY,GACZ,oBAAoB,GACpB,oBAAoB,GACpB,WAAW,GACX,kBAAkB,GAClB,cAAc,GACd,gBAAgB,CAClB,GAAG;IACH,gGAAgG;IAChG,EAAE,CAAC,EAAE,SAAS,CAAC;IAEf,kEAAkE;IAClE,UAAU,EAAE,SAAS,CAAC;IAEtB,yGAAyG;IACzG,kBAAkB,CAAC,EAAE,eAAe,CAAC;IAErC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,QAAQ,CAAC;IAErB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,QAAQ,EAAE,CAAC;IAE9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAElC,+EAA+E;IAC/E,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACtC,CAAC;AAEF;;;;GAIG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,uEAAuE;AACvE,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC3C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG;IAClD,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,eAAe,CAAC;CAC7C,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG;IAC5C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAC/C,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC3C,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG;IAC5C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC;IACnC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG;IACvC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAC7B,WAAW,EACX,WAAW,GAAG,kBAAkB,GAAG,WAAW,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,CAC1F,CAAC;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACzB,eAAe,GACf,sBAAsB,GACtB,gBAAgB,GAChB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,WAAW,CAAC"}