open-multi-agent-kit 0.96.2 → 0.98.0

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 (368) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +43 -9
  3. package/dist/cli/args.d.ts +2 -3
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +13 -189
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/help.d.ts +3 -0
  8. package/dist/cli/help.d.ts.map +1 -0
  9. package/dist/cli/help.js +194 -0
  10. package/dist/cli/help.js.map +1 -0
  11. package/dist/cli/initial-message.d.ts.map +1 -1
  12. package/dist/cli/initial-message.js +2 -1
  13. package/dist/cli/initial-message.js.map +1 -1
  14. package/dist/cli/resource-paths.d.ts +4 -0
  15. package/dist/cli/resource-paths.d.ts.map +1 -0
  16. package/dist/cli/resource-paths.js +59 -0
  17. package/dist/cli/resource-paths.js.map +1 -0
  18. package/dist/commands/adaptorch-doctor-cli.d.ts +13 -0
  19. package/dist/commands/adaptorch-doctor-cli.d.ts.map +1 -0
  20. package/dist/commands/adaptorch-doctor-cli.js +115 -0
  21. package/dist/commands/adaptorch-doctor-cli.js.map +1 -0
  22. package/dist/commands/resource-doctor-cli.d.ts +4 -0
  23. package/dist/commands/resource-doctor-cli.d.ts.map +1 -1
  24. package/dist/commands/resource-doctor-cli.js +35 -5
  25. package/dist/commands/resource-doctor-cli.js.map +1 -1
  26. package/dist/core/adaptorch-bridge.d.ts +11 -13
  27. package/dist/core/adaptorch-bridge.d.ts.map +1 -1
  28. package/dist/core/adaptorch-bridge.js +11 -13
  29. package/dist/core/adaptorch-bridge.js.map +1 -1
  30. package/dist/core/agent-session-snapshot.d.ts +16 -0
  31. package/dist/core/agent-session-snapshot.d.ts.map +1 -0
  32. package/dist/core/agent-session-snapshot.js +111 -0
  33. package/dist/core/agent-session-snapshot.js.map +1 -0
  34. package/dist/core/agent-session.d.ts +14 -10
  35. package/dist/core/agent-session.d.ts.map +1 -1
  36. package/dist/core/agent-session.js +102 -217
  37. package/dist/core/agent-session.js.map +1 -1
  38. package/dist/core/agent-tool-settings.d.ts +10 -0
  39. package/dist/core/agent-tool-settings.d.ts.map +1 -1
  40. package/dist/core/agent-tool-settings.js +10 -1
  41. package/dist/core/agent-tool-settings.js.map +1 -1
  42. package/dist/core/attachment-store.d.ts +39 -0
  43. package/dist/core/attachment-store.d.ts.map +1 -0
  44. package/dist/core/attachment-store.js +81 -0
  45. package/dist/core/attachment-store.js.map +1 -0
  46. package/dist/core/command-safety.d.ts +8 -0
  47. package/dist/core/command-safety.d.ts.map +1 -1
  48. package/dist/core/command-safety.js +140 -14
  49. package/dist/core/command-safety.js.map +1 -1
  50. package/dist/core/compaction/compaction.d.ts +13 -1
  51. package/dist/core/compaction/compaction.d.ts.map +1 -1
  52. package/dist/core/compaction/compaction.js +60 -62
  53. package/dist/core/compaction/compaction.js.map +1 -1
  54. package/dist/core/compaction/index.d.ts +1 -0
  55. package/dist/core/compaction/index.d.ts.map +1 -1
  56. package/dist/core/compaction/index.js +1 -0
  57. package/dist/core/compaction/index.js.map +1 -1
  58. package/dist/core/compaction/knowledge-triage-format.d.ts +9 -0
  59. package/dist/core/compaction/knowledge-triage-format.d.ts.map +1 -0
  60. package/dist/core/compaction/knowledge-triage-format.js +71 -0
  61. package/dist/core/compaction/knowledge-triage-format.js.map +1 -0
  62. package/dist/core/compaction/knowledge-triage-types.d.ts +7 -0
  63. package/dist/core/compaction/knowledge-triage-types.d.ts.map +1 -0
  64. package/dist/core/compaction/knowledge-triage-types.js +2 -0
  65. package/dist/core/compaction/knowledge-triage-types.js.map +1 -0
  66. package/dist/core/compaction/knowledge-triage.d.ts +29 -0
  67. package/dist/core/compaction/knowledge-triage.d.ts.map +1 -0
  68. package/dist/core/compaction/knowledge-triage.js +189 -0
  69. package/dist/core/compaction/knowledge-triage.js.map +1 -0
  70. package/dist/core/compaction/transaction.d.ts.map +1 -1
  71. package/dist/core/compaction/transaction.js +1 -1
  72. package/dist/core/compaction/transaction.js.map +1 -1
  73. package/dist/core/compaction/utils.d.ts +4 -0
  74. package/dist/core/compaction/utils.d.ts.map +1 -1
  75. package/dist/core/compaction/utils.js +37 -0
  76. package/dist/core/compaction/utils.js.map +1 -1
  77. package/dist/core/completion-sound-io.d.ts +14 -0
  78. package/dist/core/completion-sound-io.d.ts.map +1 -0
  79. package/dist/core/completion-sound-io.js +64 -0
  80. package/dist/core/completion-sound-io.js.map +1 -0
  81. package/dist/core/completion-sound.d.ts +4 -10
  82. package/dist/core/completion-sound.d.ts.map +1 -1
  83. package/dist/core/completion-sound.js +28 -58
  84. package/dist/core/completion-sound.js.map +1 -1
  85. package/dist/core/context-budget-governor-v2.d.ts +1 -1
  86. package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
  87. package/dist/core/context-budget-governor-v2.js +1 -1
  88. package/dist/core/context-budget-governor-v2.js.map +1 -1
  89. package/dist/core/context-budget-relevance.d.ts +15 -2
  90. package/dist/core/context-budget-relevance.d.ts.map +1 -1
  91. package/dist/core/context-budget-relevance.js +21 -9
  92. package/dist/core/context-budget-relevance.js.map +1 -1
  93. package/dist/core/context-budget-system-prompt-items.d.ts +1 -1
  94. package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
  95. package/dist/core/context-budget-system-prompt-items.js.map +1 -1
  96. package/dist/core/context-budget-system-prompt.d.ts +1 -1
  97. package/dist/core/context-budget-system-prompt.d.ts.map +1 -1
  98. package/dist/core/context-budget-system-prompt.js.map +1 -1
  99. package/dist/core/context-budget-v2-cache-keys.d.ts +3 -0
  100. package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
  101. package/dist/core/context-budget-v2-cache-keys.js +2 -0
  102. package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
  103. package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
  104. package/dist/core/context-budget-v2-plan-cache-keys.js +3 -0
  105. package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
  106. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  107. package/dist/core/context-budget-v2-planner.js +2 -1
  108. package/dist/core/context-budget-v2-planner.js.map +1 -1
  109. package/dist/core/context-budget-v2-scoring.d.ts +17 -0
  110. package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
  111. package/dist/core/context-budget-v2-scoring.js +25 -8
  112. package/dist/core/context-budget-v2-scoring.js.map +1 -1
  113. package/dist/core/context-budget-v2-selection.d.ts +2 -2
  114. package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
  115. package/dist/core/context-budget-v2-selection.js +18 -1
  116. package/dist/core/context-budget-v2-selection.js.map +1 -1
  117. package/dist/core/context-budget-v2-types.d.ts +17 -0
  118. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  119. package/dist/core/context-budget-v2-types.js +15 -0
  120. package/dist/core/context-budget-v2-types.js.map +1 -1
  121. package/dist/core/context-file.d.ts +23 -0
  122. package/dist/core/context-file.d.ts.map +1 -0
  123. package/dist/core/context-file.js +17 -0
  124. package/dist/core/context-file.js.map +1 -0
  125. package/dist/core/extensions/builtin/command-safety-gate.d.ts +3 -1
  126. package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
  127. package/dist/core/extensions/builtin/command-safety-gate.js +7 -0
  128. package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
  129. package/dist/core/extensions/types.d.ts +12 -1
  130. package/dist/core/extensions/types.d.ts.map +1 -1
  131. package/dist/core/extensions/types.js.map +1 -1
  132. package/dist/core/keybindings.d.ts +1 -1
  133. package/dist/core/keybindings.d.ts.map +1 -1
  134. package/dist/core/keybindings.js +6 -1
  135. package/dist/core/keybindings.js.map +1 -1
  136. package/dist/core/model-prompt-policy.d.ts +1 -1
  137. package/dist/core/model-prompt-policy.d.ts.map +1 -1
  138. package/dist/core/model-prompt-policy.js.map +1 -1
  139. package/dist/core/model-registry.d.ts +8 -3
  140. package/dist/core/model-registry.d.ts.map +1 -1
  141. package/dist/core/model-registry.js +71 -1
  142. package/dist/core/model-registry.js.map +1 -1
  143. package/dist/core/package-doctor-source-scan.d.ts +9 -0
  144. package/dist/core/package-doctor-source-scan.d.ts.map +1 -1
  145. package/dist/core/package-doctor-source-scan.js +77 -4
  146. package/dist/core/package-doctor-source-scan.js.map +1 -1
  147. package/dist/core/prompt-attachment.d.ts +51 -0
  148. package/dist/core/prompt-attachment.d.ts.map +1 -0
  149. package/dist/core/prompt-attachment.js +186 -0
  150. package/dist/core/prompt-attachment.js.map +1 -0
  151. package/dist/core/prompt-settlement.d.ts +6 -3
  152. package/dist/core/prompt-settlement.d.ts.map +1 -1
  153. package/dist/core/prompt-settlement.js +10 -14
  154. package/dist/core/prompt-settlement.js.map +1 -1
  155. package/dist/core/provider-resilience.d.ts +28 -0
  156. package/dist/core/provider-resilience.d.ts.map +1 -1
  157. package/dist/core/provider-resilience.js +50 -0
  158. package/dist/core/provider-resilience.js.map +1 -1
  159. package/dist/core/provider-retry.d.ts +1 -1
  160. package/dist/core/provider-retry.d.ts.map +1 -1
  161. package/dist/core/provider-retry.js +1 -1
  162. package/dist/core/provider-retry.js.map +1 -1
  163. package/dist/core/provider-usage.d.ts.map +1 -1
  164. package/dist/core/provider-usage.js +68 -2
  165. package/dist/core/provider-usage.js.map +1 -1
  166. package/dist/core/reasoning-router-promotion.d.ts +124 -0
  167. package/dist/core/reasoning-router-promotion.d.ts.map +1 -0
  168. package/dist/core/reasoning-router-promotion.js +121 -0
  169. package/dist/core/reasoning-router-promotion.js.map +1 -0
  170. package/dist/core/reasoning-router-replay-stability.d.ts +65 -0
  171. package/dist/core/reasoning-router-replay-stability.d.ts.map +1 -0
  172. package/dist/core/reasoning-router-replay-stability.js +67 -0
  173. package/dist/core/reasoning-router-replay-stability.js.map +1 -0
  174. package/dist/core/reasoning-router-v4-weights.d.ts +6 -6
  175. package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
  176. package/dist/core/reasoning-router-v4-weights.js +3 -3
  177. package/dist/core/reasoning-router-v4-weights.js.map +1 -1
  178. package/dist/core/reasoning-router-v4.d.ts.map +1 -1
  179. package/dist/core/reasoning-router-v4.js +6 -6
  180. package/dist/core/reasoning-router-v4.js.map +1 -1
  181. package/dist/core/redaction.d.ts.map +1 -1
  182. package/dist/core/redaction.js +1 -1
  183. package/dist/core/redaction.js.map +1 -1
  184. package/dist/core/resource-admission.d.ts +2 -1
  185. package/dist/core/resource-admission.d.ts.map +1 -1
  186. package/dist/core/resource-admission.js +11 -0
  187. package/dist/core/resource-admission.js.map +1 -1
  188. package/dist/core/resource-governor-format.d.ts +1 -1
  189. package/dist/core/resource-governor-format.d.ts.map +1 -1
  190. package/dist/core/resource-governor-format.js.map +1 -1
  191. package/dist/core/resource-governor-settings.d.ts +6 -12
  192. package/dist/core/resource-governor-settings.d.ts.map +1 -1
  193. package/dist/core/resource-governor-settings.js.map +1 -1
  194. package/dist/core/resource-governor-types.d.ts +24 -0
  195. package/dist/core/resource-governor-types.d.ts.map +1 -0
  196. package/dist/core/resource-governor-types.js +15 -0
  197. package/dist/core/resource-governor-types.js.map +1 -0
  198. package/dist/core/resource-loader.d.ts +1 -7
  199. package/dist/core/resource-loader.d.ts.map +1 -1
  200. package/dist/core/resource-loader.js.map +1 -1
  201. package/dist/core/resource-observation-journal.d.ts +2 -1
  202. package/dist/core/resource-observation-journal.d.ts.map +1 -1
  203. package/dist/core/resource-observation-journal.js +4 -3
  204. package/dist/core/resource-observation-journal.js.map +1 -1
  205. package/dist/core/resource-observation-report-reader.d.ts +7 -0
  206. package/dist/core/resource-observation-report-reader.d.ts.map +1 -0
  207. package/dist/core/resource-observation-report-reader.js +157 -0
  208. package/dist/core/resource-observation-report-reader.js.map +1 -0
  209. package/dist/core/resource-observation-report.d.ts +24 -0
  210. package/dist/core/resource-observation-report.d.ts.map +1 -0
  211. package/dist/core/resource-observation-report.js +101 -0
  212. package/dist/core/resource-observation-report.js.map +1 -0
  213. package/dist/core/router-feedback-collector.d.ts +1 -1
  214. package/dist/core/router-feedback-collector.d.ts.map +1 -1
  215. package/dist/core/router-feedback-collector.js.map +1 -1
  216. package/dist/core/session-bash-service.d.ts.map +1 -1
  217. package/dist/core/session-bash-service.js +4 -3
  218. package/dist/core/session-bash-service.js.map +1 -1
  219. package/dist/core/session-failure-cause.d.ts +33 -0
  220. package/dist/core/session-failure-cause.d.ts.map +1 -0
  221. package/dist/core/session-failure-cause.js +141 -0
  222. package/dist/core/session-failure-cause.js.map +1 -0
  223. package/dist/core/session-system-prompt.d.ts +1 -1
  224. package/dist/core/session-system-prompt.d.ts.map +1 -1
  225. package/dist/core/session-system-prompt.js.map +1 -1
  226. package/dist/core/session-termination.d.ts +1 -1
  227. package/dist/core/session-termination.d.ts.map +1 -1
  228. package/dist/core/session-termination.js +11 -2
  229. package/dist/core/session-termination.js.map +1 -1
  230. package/dist/core/settings-manager.d.ts +1 -1
  231. package/dist/core/settings-manager.d.ts.map +1 -1
  232. package/dist/core/settings-manager.js.map +1 -1
  233. package/dist/core/system-prompt.d.ts +1 -1
  234. package/dist/core/system-prompt.d.ts.map +1 -1
  235. package/dist/core/system-prompt.js.map +1 -1
  236. package/dist/core/tools/bash.d.ts.map +1 -1
  237. package/dist/core/tools/bash.js +10 -14
  238. package/dist/core/tools/bash.js.map +1 -1
  239. package/dist/core/tools/grep.d.ts.map +1 -1
  240. package/dist/core/tools/grep.js +13 -48
  241. package/dist/core/tools/grep.js.map +1 -1
  242. package/dist/core/tools/read.d.ts.map +1 -1
  243. package/dist/core/tools/read.js +1 -34
  244. package/dist/core/tools/read.js.map +1 -1
  245. package/dist/core/workload-classifier.d.ts +2 -10
  246. package/dist/core/workload-classifier.d.ts.map +1 -1
  247. package/dist/core/workload-classifier.js +17 -0
  248. package/dist/core/workload-classifier.js.map +1 -1
  249. package/dist/core/workload-family-matcher.d.ts +1 -1
  250. package/dist/core/workload-family-matcher.d.ts.map +1 -1
  251. package/dist/core/workload-family-matcher.js.map +1 -1
  252. package/dist/core/workload-shard-execution-types.d.ts +40 -0
  253. package/dist/core/workload-shard-execution-types.d.ts.map +1 -0
  254. package/dist/core/workload-shard-execution-types.js +14 -0
  255. package/dist/core/workload-shard-execution-types.js.map +1 -0
  256. package/dist/core/workload-shard-executor.d.ts +3 -27
  257. package/dist/core/workload-shard-executor.d.ts.map +1 -1
  258. package/dist/core/workload-shard-executor.js.map +1 -1
  259. package/dist/core/workload-shard-runner.d.ts +1 -1
  260. package/dist/core/workload-shard-runner.d.ts.map +1 -1
  261. package/dist/core/workload-shard-runner.js.map +1 -1
  262. package/dist/core/workload-types.d.ts +24 -0
  263. package/dist/core/workload-types.d.ts.map +1 -0
  264. package/dist/core/workload-types.js +15 -0
  265. package/dist/core/workload-types.js.map +1 -0
  266. package/dist/index.d.ts +1 -1
  267. package/dist/index.d.ts.map +1 -1
  268. package/dist/index.js +1 -1
  269. package/dist/index.js.map +1 -1
  270. package/dist/main.d.ts +2 -0
  271. package/dist/main.d.ts.map +1 -1
  272. package/dist/main.js +27 -47
  273. package/dist/main.js.map +1 -1
  274. package/dist/modes/interactive/components/attachment-strip.d.ts +21 -0
  275. package/dist/modes/interactive/components/attachment-strip.d.ts.map +1 -0
  276. package/dist/modes/interactive/components/attachment-strip.js +136 -0
  277. package/dist/modes/interactive/components/attachment-strip.js.map +1 -0
  278. package/dist/modes/interactive/components/footer.d.ts +6 -0
  279. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  280. package/dist/modes/interactive/components/footer.js +26 -1
  281. package/dist/modes/interactive/components/footer.js.map +1 -1
  282. package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
  283. package/dist/modes/interactive/components/status-sidebar.js +12 -1
  284. package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
  285. package/dist/modes/interactive/interactive-mode.d.ts +23 -4
  286. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  287. package/dist/modes/interactive/interactive-mode.js +174 -53
  288. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  289. package/dist/modes/interactive/theme/omk-control-panel.json +1 -1
  290. package/dist/utils/clipboard-image.d.ts.map +1 -1
  291. package/dist/utils/clipboard-image.js +42 -33
  292. package/dist/utils/clipboard-image.js.map +1 -1
  293. package/dist/utils/clipboard.d.ts.map +1 -1
  294. package/dist/utils/clipboard.js +14 -2
  295. package/dist/utils/clipboard.js.map +1 -1
  296. package/docs/adaptorch-preview-spec.md +20 -18
  297. package/docs/adaptorch-preview.md +9 -9
  298. package/docs/compaction.md +25 -4
  299. package/docs/correctness-wall.md +10 -10
  300. package/docs/docs.json +12 -0
  301. package/docs/environment-variables.md +9 -2
  302. package/docs/extensions.md +12 -3
  303. package/docs/index.md +7 -1
  304. package/docs/metrics.md +74 -2
  305. package/docs/provider-resilience.md +11 -0
  306. package/docs/runtime-algorithms.md +359 -0
  307. package/docs/sdk.md +2 -2
  308. package/docs/settings.md +11 -10
  309. package/docs/usage.md +19 -3
  310. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  311. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  312. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  313. package/examples/extensions/gondolin/package-lock.json +2 -2
  314. package/examples/extensions/gondolin/package.json +1 -1
  315. package/examples/extensions/sandbox/package-lock.json +2 -2
  316. package/examples/extensions/sandbox/package.json +1 -1
  317. package/examples/extensions/with-deps/package-lock.json +2 -2
  318. package/examples/extensions/with-deps/package.json +1 -1
  319. package/npm-shrinkwrap.json +18 -18
  320. package/package.json +7 -7
  321. package/dist/core/context-budget-governor.d.ts +0 -67
  322. package/dist/core/context-budget-governor.d.ts.map +0 -1
  323. package/dist/core/context-budget-governor.js +0 -224
  324. package/dist/core/context-budget-governor.js.map +0 -1
  325. package/dist/core/lean-ctx.d.ts +0 -99
  326. package/dist/core/lean-ctx.d.ts.map +0 -1
  327. package/dist/core/lean-ctx.js +0 -225
  328. package/dist/core/lean-ctx.js.map +0 -1
  329. package/dist/core/read-anchors.d.ts +0 -110
  330. package/dist/core/read-anchors.d.ts.map +0 -1
  331. package/dist/core/read-anchors.js +0 -193
  332. package/dist/core/read-anchors.js.map +0 -1
  333. package/dist/core/recovery-checkpoint.d.ts +0 -196
  334. package/dist/core/recovery-checkpoint.d.ts.map +0 -1
  335. package/dist/core/recovery-checkpoint.js +0 -382
  336. package/dist/core/recovery-checkpoint.js.map +0 -1
  337. package/dist/core/sandbox-policy-v2.d.ts +0 -49
  338. package/dist/core/sandbox-policy-v2.d.ts.map +0 -1
  339. package/dist/core/sandbox-policy-v2.js +0 -368
  340. package/dist/core/sandbox-policy-v2.js.map +0 -1
  341. package/dist/core/tools/omp-pure-seams.d.ts +0 -41
  342. package/dist/core/tools/omp-pure-seams.d.ts.map +0 -1
  343. package/dist/core/tools/omp-pure-seams.js +0 -142
  344. package/dist/core/tools/omp-pure-seams.js.map +0 -1
  345. package/dist/core/tools/omp-seam-runtime.d.ts +0 -100
  346. package/dist/core/tools/omp-seam-runtime.d.ts.map +0 -1
  347. package/dist/core/tools/omp-seam-runtime.js +0 -40
  348. package/dist/core/tools/omp-seam-runtime.js.map +0 -1
  349. package/dist/guardrails/audit-logger.d.ts +0 -4
  350. package/dist/guardrails/audit-logger.d.ts.map +0 -1
  351. package/dist/guardrails/audit-logger.js +0 -28
  352. package/dist/guardrails/audit-logger.js.map +0 -1
  353. package/dist/guardrails/freedomd-adapter.d.ts +0 -16
  354. package/dist/guardrails/freedomd-adapter.d.ts.map +0 -1
  355. package/dist/guardrails/freedomd-adapter.js +0 -87
  356. package/dist/guardrails/freedomd-adapter.js.map +0 -1
  357. package/dist/orchestration/lane-grant-auditor.d.ts +0 -4
  358. package/dist/orchestration/lane-grant-auditor.d.ts.map +0 -1
  359. package/dist/orchestration/lane-grant-auditor.js +0 -87
  360. package/dist/orchestration/lane-grant-auditor.js.map +0 -1
  361. package/dist/types/guardrails.d.ts +0 -61
  362. package/dist/types/guardrails.d.ts.map +0 -1
  363. package/dist/types/guardrails.js +0 -9
  364. package/dist/types/guardrails.js.map +0 -1
  365. package/dist/types/lane-grant.d.ts +0 -58
  366. package/dist/types/lane-grant.d.ts.map +0 -1
  367. package/dist/types/lane-grant.js +0 -9
  368. package/dist/types/lane-grant.js.map +0 -1
@@ -1,224 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { createFallbackTokenCounter } from "./context-budget-token-counter.js";
3
- export const CONTEXT_BUDGET_POLICY_VERSION = "context-budget-v1";
4
- export function planContextBudget(input) {
5
- const tokenCounter = input.tokenCounter ?? createFallbackTokenCounter();
6
- const modelId = input.modelId ?? "unknown";
7
- const diagnostics = [];
8
- const maxTokens = normalizeBudgetTokens("maxTokens", input.maxTokens, diagnostics);
9
- const responseReserveTokens = normalizeBudgetTokens("responseReserveTokens", input.responseReserveTokens ?? 0, diagnostics);
10
- const availableTokens = Math.max(0, maxTokens - responseReserveTokens);
11
- const plannedItems = input.items.map((item) => planItem(item, tokenCounter, modelId, diagnostics));
12
- const includedIds = new Set();
13
- let usedTokens = 0;
14
- for (const item of plannedItems) {
15
- if (item.priority !== "hard") {
16
- continue;
17
- }
18
- includedIds.add(item.id);
19
- usedTokens += item.estimatedTokens;
20
- }
21
- if (usedTokens > availableTokens) {
22
- diagnostics.push({
23
- reason: "hard_pin_over_capacity",
24
- detail: `hard-pinned context uses ${usedTokens} tokens against ${availableTokens} available tokens`,
25
- });
26
- }
27
- const selectedRedundancyKeys = new Set();
28
- const remainingOptionalItems = plannedItems.filter((item) => item.priority !== "hard");
29
- while (remainingOptionalItems.length > 0) {
30
- const rankedItems = remainingOptionalItems
31
- .map((item) => applyRedundancyPenalty(item, selectedRedundancyKeys))
32
- .sort(comparePlannedItemsForSelection);
33
- const selected = rankedItems.find((item) => usedTokens + item.estimatedTokens <= availableTokens);
34
- if (!selected) {
35
- break;
36
- }
37
- includedIds.add(selected.id);
38
- usedTokens += selected.estimatedTokens;
39
- if (selected.redundancyKey) {
40
- selectedRedundancyKeys.add(selected.redundancyKey);
41
- }
42
- const selectedIndex = remainingOptionalItems.findIndex((item) => item.id === selected.id);
43
- remainingOptionalItems.splice(selectedIndex, 1);
44
- }
45
- const includedItems = plannedItems.filter((item) => includedIds.has(item.id));
46
- const omittedItems = plannedItems.filter((item) => !includedIds.has(item.id));
47
- for (const item of omittedItems) {
48
- diagnostics.push({ reason: "item_omitted", itemId: item.id, detail: `${item.kind} omitted from context budget` });
49
- }
50
- const omittedTokens = omittedItems.reduce((sum, item) => sum + item.estimatedTokens, 0);
51
- const omittedHighPriority = omittedItems.some((item) => item.priority === "high");
52
- const emergency = usedTokens > availableTokens || diagnostics.some((diagnostic) => diagnostic.reason === "invalid_budget");
53
- const policyVersion = input.policyVersion ?? CONTEXT_BUDGET_POLICY_VERSION;
54
- const planWithoutHash = {
55
- policyVersion,
56
- maxTokens,
57
- responseReserveTokens,
58
- availableTokens,
59
- usedTokens,
60
- omittedTokens,
61
- emergency,
62
- omittedHighPriority,
63
- included: includedItems.map((item) => [item.id, item.estimatedTokens, item.score]),
64
- omitted: omittedItems.map((item) => [item.id, item.estimatedTokens, item.score]),
65
- };
66
- const planHash = createHash("sha256").update(JSON.stringify(planWithoutHash), "utf8").digest("hex");
67
- const observability = buildObservability({
68
- availableTokens,
69
- diagnostics,
70
- includedItems,
71
- omittedItems,
72
- omittedTokens,
73
- planHash,
74
- usedTokens,
75
- });
76
- return {
77
- policyVersion,
78
- maxTokens,
79
- responseReserveTokens,
80
- availableTokens,
81
- usedTokens,
82
- omittedTokens,
83
- emergency,
84
- omittedHighPriority,
85
- includedItems,
86
- omittedItems,
87
- diagnostics,
88
- planHash,
89
- observability,
90
- };
91
- }
92
- export function scoreContextBudgetItem(item, estimatedTokens) {
93
- const priorityScore = priorityWeight(item.priority);
94
- const relevance = clampScore(item.relevance) * 20;
95
- const recency = clampScore(item.recency) * 10;
96
- const evidence = clampScore(item.evidenceValue) * 15;
97
- // G1: costPenalty 비례화 — sqrt 기반으로 대항목에 더 큰 불이익 부여.
98
- // log2(t)*2는 1000토큰에서 ~19.9점으로 relevance(20점)와 동급 → 대항목 생존.
99
- // sqrt(t)*0.5는 1000토큰 15.8점, 5000토큰 35.4점, 10000토큰 50점 → 비례적 증가.
100
- const costPenalty = Math.sqrt(normalizeTokenCount(estimatedTokens)) * 0.5;
101
- return priorityScore + relevance + recency + evidence - costPenalty;
102
- }
103
- function planItem(item, tokenCounter, modelId, diagnostics) {
104
- const rawEstimate = item.tokenEstimate ?? tokenCounter.countText(item.text, modelId).tokens;
105
- const estimatedTokens = normalizeItemTokenEstimate(item.id, rawEstimate, diagnostics);
106
- return {
107
- ...item,
108
- estimatedTokens,
109
- score: item.priority === "hard" ? Number.POSITIVE_INFINITY : scoreContextBudgetItem(item, estimatedTokens),
110
- };
111
- }
112
- const REDUNDANCY_PENALTY_FLOOR = 10;
113
- const REDUNDANCY_PENALTY_SCALE = 0.8;
114
- /**
115
- * W4: Adaptive redundancy penalty — proportional to token count.
116
- * Large duplicates waste more budget so deserve higher penalty.
117
- * Formula: max(floor, sqrt(tokens) * scale)
118
- * - 200 tokens → 11.3 (near floor — minimal waste)
119
- * - 1000 tokens → 25.3 (moderate waste)
120
- * - 5000 tokens → 56.6 (heavy waste — strongly penalized)
121
- * Floor ensures small duplicates are still penalized meaningfully.
122
- * Scale (0.8) tuned to score medium=50 so large duplicates go negative.
123
- */
124
- function redundancyPenalty(estimatedTokens) {
125
- return Math.max(REDUNDANCY_PENALTY_FLOOR, Math.sqrt(estimatedTokens) * REDUNDANCY_PENALTY_SCALE);
126
- }
127
- function applyRedundancyPenalty(item, selectedRedundancyKeys) {
128
- if (!item.redundancyKey || !selectedRedundancyKeys.has(item.redundancyKey)) {
129
- return item;
130
- }
131
- return { ...item, score: item.score - redundancyPenalty(item.estimatedTokens) };
132
- }
133
- function comparePlannedItemsForSelection(a, b) {
134
- // G2: 우선순위 티어 내부에서 밀도(score/tokens) 기반 정렬.
135
- // 단위 토큰당 가치가 높은 항목을 우선 선택 → 예산 활용률 극대화.
136
- const aTier = priorityTier(a.priority);
137
- const bTier = priorityTier(b.priority);
138
- if (aTier !== bTier) {
139
- return aTier - bTier;
140
- }
141
- const aDensity = a.score > 0 ? a.score / Math.max(a.estimatedTokens, 1) : 0;
142
- const bDensity = b.score > 0 ? b.score / Math.max(b.estimatedTokens, 1) : 0;
143
- if (aDensity !== bDensity) {
144
- return bDensity - aDensity;
145
- }
146
- if (a.estimatedTokens !== b.estimatedTokens) {
147
- return a.estimatedTokens - b.estimatedTokens;
148
- }
149
- return a.id.localeCompare(b.id);
150
- }
151
- function priorityTier(priority) {
152
- switch (priority) {
153
- case "hard":
154
- return 0;
155
- case "high":
156
- return 1;
157
- case "medium":
158
- return 2;
159
- case "low":
160
- return 3;
161
- }
162
- }
163
- function priorityWeight(priority) {
164
- switch (priority) {
165
- case "hard":
166
- return 1_000_000;
167
- case "high":
168
- return 100;
169
- case "medium":
170
- return 50;
171
- case "low":
172
- return 10;
173
- }
174
- }
175
- function clampScore(value) {
176
- if (value === undefined || !Number.isFinite(value)) {
177
- return 0;
178
- }
179
- return Math.max(0, Math.min(1, value));
180
- }
181
- function normalizeBudgetTokens(field, value, diagnostics) {
182
- if (!Number.isFinite(value) || value < 0) {
183
- diagnostics.push({
184
- reason: "invalid_budget",
185
- detail: `${field} must be a non-negative finite number, got ${value}`,
186
- });
187
- return 0;
188
- }
189
- return Math.floor(value);
190
- }
191
- function normalizeItemTokenEstimate(itemId, value, diagnostics) {
192
- if (!Number.isFinite(value) || value < 0) {
193
- diagnostics.push({
194
- reason: "invalid_budget",
195
- itemId,
196
- detail: `tokenEstimate must be a non-negative finite number, got ${value}`,
197
- });
198
- return 0;
199
- }
200
- return Math.ceil(value);
201
- }
202
- function normalizeTokenCount(value) {
203
- if (!Number.isFinite(value) || value < 0) {
204
- return 0;
205
- }
206
- return value;
207
- }
208
- function buildObservability(input) {
209
- return {
210
- counts: {
211
- selected: input.includedItems.length,
212
- omitted: input.omittedItems.length,
213
- },
214
- diagnosticReasons: [...new Set(input.diagnostics.map((diagnostic) => diagnostic.reason))].sort(),
215
- tokens: {
216
- available: input.availableTokens,
217
- used: input.usedTokens,
218
- omitted: input.omittedTokens,
219
- tokenSavings: input.omittedTokens,
220
- },
221
- planHash: input.planHash,
222
- };
223
- }
224
- //# sourceMappingURL=context-budget-governor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-budget-governor.js","sourceRoot":"","sources":["../../src/core/context-budget-governor.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { createFallbackTokenCounter, type TokenCounterAdapter } from \"./context-budget-token-counter.ts\";\n\nexport type ContextBudgetItemKind =\n\t| \"system\"\n\t| \"context-pointer\"\n\t| \"context-full\"\n\t| \"skill-header\"\n\t| \"skill\"\n\t| \"mcp\"\n\t| \"history\"\n\t| \"tool-result\"\n\t| \"subagent-evidence\"\n\t| \"budget-note\";\n\nexport type ContextBudgetPriority = \"hard\" | \"high\" | \"medium\" | \"low\";\nexport type ContextBudgetDiagnosticReason = \"hard_pin_over_capacity\" | \"item_omitted\" | \"invalid_budget\";\n\nexport interface ContextBudgetItem {\n\treadonly id: string;\n\treadonly kind: ContextBudgetItemKind;\n\treadonly text: string;\n\treadonly priority: ContextBudgetPriority;\n\treadonly tokenEstimate?: number;\n\treadonly relevance?: number;\n\treadonly recency?: number;\n\treadonly evidenceValue?: number;\n\treadonly redundancyKey?: string;\n}\n\nexport interface ContextBudgetGovernorInput {\n\treadonly maxTokens: number;\n\treadonly responseReserveTokens?: number;\n\treadonly modelId?: string;\n\treadonly policyVersion?: string;\n\treadonly items: readonly ContextBudgetItem[];\n\treadonly tokenCounter?: TokenCounterAdapter;\n}\n\nexport interface ContextBudgetPlannedItem extends ContextBudgetItem {\n\treadonly estimatedTokens: number;\n\treadonly score: number;\n}\n\nexport interface ContextBudgetDiagnostic {\n\treadonly reason: ContextBudgetDiagnosticReason;\n\treadonly itemId?: string;\n\treadonly detail: string;\n}\n\nexport interface ContextBudgetObservabilityCounts {\n\treadonly selected: number;\n\treadonly omitted: number;\n}\n\nexport interface ContextBudgetObservabilityTokens {\n\treadonly available: number;\n\treadonly used: number;\n\treadonly omitted: number;\n\treadonly tokenSavings: number;\n}\n\nexport interface ContextBudgetObservability {\n\treadonly counts: ContextBudgetObservabilityCounts;\n\treadonly diagnosticReasons: readonly ContextBudgetDiagnosticReason[];\n\treadonly tokens: ContextBudgetObservabilityTokens;\n\treadonly planHash: string;\n}\n\nexport interface ContextBudgetPlan {\n\treadonly policyVersion: string;\n\treadonly maxTokens: number;\n\treadonly responseReserveTokens: number;\n\treadonly availableTokens: number;\n\treadonly usedTokens: number;\n\treadonly omittedTokens: number;\n\treadonly emergency: boolean;\n\treadonly omittedHighPriority: boolean;\n\treadonly includedItems: readonly ContextBudgetPlannedItem[];\n\treadonly omittedItems: readonly ContextBudgetPlannedItem[];\n\treadonly diagnostics: readonly ContextBudgetDiagnostic[];\n\treadonly planHash: string;\n\treadonly observability: ContextBudgetObservability;\n}\n\nexport const CONTEXT_BUDGET_POLICY_VERSION = \"context-budget-v1\";\n\nexport function planContextBudget(input: ContextBudgetGovernorInput): ContextBudgetPlan {\n\tconst tokenCounter = input.tokenCounter ?? createFallbackTokenCounter();\n\tconst modelId = input.modelId ?? \"unknown\";\n\tconst diagnostics: ContextBudgetDiagnostic[] = [];\n\tconst maxTokens = normalizeBudgetTokens(\"maxTokens\", input.maxTokens, diagnostics);\n\tconst responseReserveTokens = normalizeBudgetTokens(\n\t\t\"responseReserveTokens\",\n\t\tinput.responseReserveTokens ?? 0,\n\t\tdiagnostics,\n\t);\n\tconst availableTokens = Math.max(0, maxTokens - responseReserveTokens);\n\tconst plannedItems = input.items.map((item) => planItem(item, tokenCounter, modelId, diagnostics));\n\tconst includedIds = new Set<string>();\n\tlet usedTokens = 0;\n\n\tfor (const item of plannedItems) {\n\t\tif (item.priority !== \"hard\") {\n\t\t\tcontinue;\n\t\t}\n\t\tincludedIds.add(item.id);\n\t\tusedTokens += item.estimatedTokens;\n\t}\n\n\tif (usedTokens > availableTokens) {\n\t\tdiagnostics.push({\n\t\t\treason: \"hard_pin_over_capacity\",\n\t\t\tdetail: `hard-pinned context uses ${usedTokens} tokens against ${availableTokens} available tokens`,\n\t\t});\n\t}\n\n\tconst selectedRedundancyKeys = new Set<string>();\n\tconst remainingOptionalItems = plannedItems.filter((item) => item.priority !== \"hard\");\n\n\twhile (remainingOptionalItems.length > 0) {\n\t\tconst rankedItems = remainingOptionalItems\n\t\t\t.map((item) => applyRedundancyPenalty(item, selectedRedundancyKeys))\n\t\t\t.sort(comparePlannedItemsForSelection);\n\t\tconst selected = rankedItems.find((item) => usedTokens + item.estimatedTokens <= availableTokens);\n\t\tif (!selected) {\n\t\t\tbreak;\n\t\t}\n\n\t\tincludedIds.add(selected.id);\n\t\tusedTokens += selected.estimatedTokens;\n\t\tif (selected.redundancyKey) {\n\t\t\tselectedRedundancyKeys.add(selected.redundancyKey);\n\t\t}\n\n\t\tconst selectedIndex = remainingOptionalItems.findIndex((item) => item.id === selected.id);\n\t\tremainingOptionalItems.splice(selectedIndex, 1);\n\t}\n\n\tconst includedItems = plannedItems.filter((item) => includedIds.has(item.id));\n\tconst omittedItems = plannedItems.filter((item) => !includedIds.has(item.id));\n\tfor (const item of omittedItems) {\n\t\tdiagnostics.push({ reason: \"item_omitted\", itemId: item.id, detail: `${item.kind} omitted from context budget` });\n\t}\n\tconst omittedTokens = omittedItems.reduce((sum, item) => sum + item.estimatedTokens, 0);\n\tconst omittedHighPriority = omittedItems.some((item) => item.priority === \"high\");\n\tconst emergency =\n\t\tusedTokens > availableTokens || diagnostics.some((diagnostic) => diagnostic.reason === \"invalid_budget\");\n\tconst policyVersion = input.policyVersion ?? CONTEXT_BUDGET_POLICY_VERSION;\n\n\tconst planWithoutHash = {\n\t\tpolicyVersion,\n\t\tmaxTokens,\n\t\tresponseReserveTokens,\n\t\tavailableTokens,\n\t\tusedTokens,\n\t\tomittedTokens,\n\t\temergency,\n\t\tomittedHighPriority,\n\t\tincluded: includedItems.map((item) => [item.id, item.estimatedTokens, item.score]),\n\t\tomitted: omittedItems.map((item) => [item.id, item.estimatedTokens, item.score]),\n\t};\n\tconst planHash = createHash(\"sha256\").update(JSON.stringify(planWithoutHash), \"utf8\").digest(\"hex\");\n\tconst observability = buildObservability({\n\t\tavailableTokens,\n\t\tdiagnostics,\n\t\tincludedItems,\n\t\tomittedItems,\n\t\tomittedTokens,\n\t\tplanHash,\n\t\tusedTokens,\n\t});\n\n\treturn {\n\t\tpolicyVersion,\n\t\tmaxTokens,\n\t\tresponseReserveTokens,\n\t\tavailableTokens,\n\t\tusedTokens,\n\t\tomittedTokens,\n\t\temergency,\n\t\tomittedHighPriority,\n\t\tincludedItems,\n\t\tomittedItems,\n\t\tdiagnostics,\n\t\tplanHash,\n\t\tobservability,\n\t};\n}\n\nexport function scoreContextBudgetItem(item: ContextBudgetItem, estimatedTokens: number): number {\n\tconst priorityScore = priorityWeight(item.priority);\n\tconst relevance = clampScore(item.relevance) * 20;\n\tconst recency = clampScore(item.recency) * 10;\n\tconst evidence = clampScore(item.evidenceValue) * 15;\n\t// G1: costPenalty 비례화 — sqrt 기반으로 대항목에 더 큰 불이익 부여.\n\t// log2(t)*2는 1000토큰에서 ~19.9점으로 relevance(20점)와 동급 → 대항목 생존.\n\t// sqrt(t)*0.5는 1000토큰 15.8점, 5000토큰 35.4점, 10000토큰 50점 → 비례적 증가.\n\tconst costPenalty = Math.sqrt(normalizeTokenCount(estimatedTokens)) * 0.5;\n\treturn priorityScore + relevance + recency + evidence - costPenalty;\n}\n\nfunction planItem(\n\titem: ContextBudgetItem,\n\ttokenCounter: TokenCounterAdapter,\n\tmodelId: string,\n\tdiagnostics: ContextBudgetDiagnostic[],\n): ContextBudgetPlannedItem {\n\tconst rawEstimate = item.tokenEstimate ?? tokenCounter.countText(item.text, modelId).tokens;\n\tconst estimatedTokens = normalizeItemTokenEstimate(item.id, rawEstimate, diagnostics);\n\treturn {\n\t\t...item,\n\t\testimatedTokens,\n\t\tscore: item.priority === \"hard\" ? Number.POSITIVE_INFINITY : scoreContextBudgetItem(item, estimatedTokens),\n\t};\n}\n\nconst REDUNDANCY_PENALTY_FLOOR = 10;\nconst REDUNDANCY_PENALTY_SCALE = 0.8;\n\n/**\n * W4: Adaptive redundancy penalty — proportional to token count.\n * Large duplicates waste more budget so deserve higher penalty.\n * Formula: max(floor, sqrt(tokens) * scale)\n * - 200 tokens → 11.3 (near floor — minimal waste)\n * - 1000 tokens → 25.3 (moderate waste)\n * - 5000 tokens → 56.6 (heavy waste — strongly penalized)\n * Floor ensures small duplicates are still penalized meaningfully.\n * Scale (0.8) tuned to score medium=50 so large duplicates go negative.\n */\nfunction redundancyPenalty(estimatedTokens: number): number {\n\treturn Math.max(REDUNDANCY_PENALTY_FLOOR, Math.sqrt(estimatedTokens) * REDUNDANCY_PENALTY_SCALE);\n}\n\nfunction applyRedundancyPenalty(\n\titem: ContextBudgetPlannedItem,\n\tselectedRedundancyKeys: Set<string>,\n): ContextBudgetPlannedItem {\n\tif (!item.redundancyKey || !selectedRedundancyKeys.has(item.redundancyKey)) {\n\t\treturn item;\n\t}\n\treturn { ...item, score: item.score - redundancyPenalty(item.estimatedTokens) };\n}\n\nfunction comparePlannedItemsForSelection(a: ContextBudgetPlannedItem, b: ContextBudgetPlannedItem): number {\n\t// G2: 우선순위 티어 내부에서 밀도(score/tokens) 기반 정렬.\n\t// 단위 토큰당 가치가 높은 항목을 우선 선택 → 예산 활용률 극대화.\n\tconst aTier = priorityTier(a.priority);\n\tconst bTier = priorityTier(b.priority);\n\tif (aTier !== bTier) {\n\t\treturn aTier - bTier;\n\t}\n\tconst aDensity = a.score > 0 ? a.score / Math.max(a.estimatedTokens, 1) : 0;\n\tconst bDensity = b.score > 0 ? b.score / Math.max(b.estimatedTokens, 1) : 0;\n\tif (aDensity !== bDensity) {\n\t\treturn bDensity - aDensity;\n\t}\n\tif (a.estimatedTokens !== b.estimatedTokens) {\n\t\treturn a.estimatedTokens - b.estimatedTokens;\n\t}\n\treturn a.id.localeCompare(b.id);\n}\n\nfunction priorityTier(priority: ContextBudgetPriority): number {\n\tswitch (priority) {\n\t\tcase \"hard\":\n\t\t\treturn 0;\n\t\tcase \"high\":\n\t\t\treturn 1;\n\t\tcase \"medium\":\n\t\t\treturn 2;\n\t\tcase \"low\":\n\t\t\treturn 3;\n\t}\n}\n\nfunction priorityWeight(priority: ContextBudgetPriority): number {\n\tswitch (priority) {\n\t\tcase \"hard\":\n\t\t\treturn 1_000_000;\n\t\tcase \"high\":\n\t\t\treturn 100;\n\t\tcase \"medium\":\n\t\t\treturn 50;\n\t\tcase \"low\":\n\t\t\treturn 10;\n\t}\n}\n\nfunction clampScore(value: number | undefined): number {\n\tif (value === undefined || !Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\treturn Math.max(0, Math.min(1, value));\n}\n\nfunction normalizeBudgetTokens(\n\tfield: \"maxTokens\" | \"responseReserveTokens\",\n\tvalue: number,\n\tdiagnostics: ContextBudgetDiagnostic[],\n): number {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tdiagnostics.push({\n\t\t\treason: \"invalid_budget\",\n\t\t\tdetail: `${field} must be a non-negative finite number, got ${value}`,\n\t\t});\n\t\treturn 0;\n\t}\n\treturn Math.floor(value);\n}\n\nfunction normalizeItemTokenEstimate(itemId: string, value: number, diagnostics: ContextBudgetDiagnostic[]): number {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tdiagnostics.push({\n\t\t\treason: \"invalid_budget\",\n\t\t\titemId,\n\t\t\tdetail: `tokenEstimate must be a non-negative finite number, got ${value}`,\n\t\t});\n\t\treturn 0;\n\t}\n\treturn Math.ceil(value);\n}\n\nfunction normalizeTokenCount(value: number): number {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\treturn 0;\n\t}\n\treturn value;\n}\n\nfunction buildObservability(input: {\n\treadonly availableTokens: number;\n\treadonly diagnostics: readonly ContextBudgetDiagnostic[];\n\treadonly includedItems: readonly ContextBudgetPlannedItem[];\n\treadonly omittedItems: readonly ContextBudgetPlannedItem[];\n\treadonly omittedTokens: number;\n\treadonly planHash: string;\n\treadonly usedTokens: number;\n}): ContextBudgetObservability {\n\treturn {\n\t\tcounts: {\n\t\t\tselected: input.includedItems.length,\n\t\t\tomitted: input.omittedItems.length,\n\t\t},\n\t\tdiagnosticReasons: [...new Set(input.diagnostics.map((diagnostic) => diagnostic.reason))].sort(),\n\t\ttokens: {\n\t\t\tavailable: input.availableTokens,\n\t\t\tused: input.usedTokens,\n\t\t\tomitted: input.omittedTokens,\n\t\t\ttokenSavings: input.omittedTokens,\n\t\t},\n\t\tplanHash: input.planHash,\n\t};\n}\n"]}
@@ -1,99 +0,0 @@
1
- import { EventEmitter } from "events";
2
- declare const DEFAULT_CONFIG: {
3
- recencyWindow: number;
4
- relevanceThreshold: number;
5
- keyTurnReserve: number;
6
- summaryEvery: number;
7
- maxContextTokens: number;
8
- compressionTarget: number;
9
- tfidfWeight: number;
10
- semanticWeight: number;
11
- recencyWeight: number;
12
- keywordBoost: number;
13
- lruWeight: number;
14
- frequencyWeight: number;
15
- recencyDecayWeight: number;
16
- protectedKeywords: string[];
17
- hardTokenLimit: number;
18
- softTokenLimit: number;
19
- warningThreshold: number;
20
- criticalThreshold: number;
21
- gracefulDegradation: boolean;
22
- opportunisticExpansion: boolean;
23
- autoCompress: boolean;
24
- compressOnEveryPrompt: boolean;
25
- minTokensToCompress: number;
26
- maxTurnsBeforeCompress: number;
27
- };
28
- export interface TurnEntry {
29
- index: number;
30
- role: "user" | "assistant" | "system" | "tool";
31
- content: string;
32
- timestamp: number;
33
- metadata?: Record<string, any>;
34
- tokenCount?: number;
35
- isKeyTurn?: boolean;
36
- relevanceScore?: number;
37
- accessCount?: number;
38
- lastAccessed?: number;
39
- }
40
- export interface CompressedContext {
41
- turns: TurnEntry[];
42
- summary: string;
43
- originalTokens: number;
44
- compressedTokens: number;
45
- compressionRatio: number;
46
- techniqueUsed: string;
47
- keyTurnsPreserved: number;
48
- evictedCount: number;
49
- metadata?: Record<string, any>;
50
- }
51
- export interface BudgetStatus {
52
- usedTokens: number;
53
- totalTokens: number;
54
- ratio: number;
55
- level: "green" | "yellow" | "orange" | "red" | "exceeded";
56
- remaining: number;
57
- canAddAgents: boolean;
58
- }
59
- export declare class ContextCompressor extends EventEmitter {
60
- private config;
61
- private charsPerToken;
62
- constructor(config?: Partial<typeof DEFAULT_CONFIG>);
63
- compress(context: TurnEntry[], currentTurn?: TurnEntry): CompressedContext;
64
- private estimateTokens;
65
- private extractKeyTurns;
66
- private applyRecencyWindow;
67
- private filterByRelevance;
68
- private calculateRelevance;
69
- private tfidfSimilarity;
70
- private hierarchicalSummarize;
71
- private assembleCompressed;
72
- }
73
- export declare class TokenBudgetEnforcer extends EventEmitter {
74
- private config;
75
- constructor(config?: Partial<typeof DEFAULT_CONFIG>);
76
- check(usedTokens: number): BudgetStatus;
77
- autoCompressIfNeeded(context: TurnEntry[]): {
78
- compressed: TurnEntry[];
79
- status: BudgetStatus;
80
- };
81
- }
82
- export declare class LeanCTXEngine extends EventEmitter {
83
- private compressor;
84
- private budgetEnforcer;
85
- private history;
86
- constructor(config?: Partial<typeof DEFAULT_CONFIG>);
87
- processPrompt(prompt: string, role?: "user" | "assistant" | "system"): CompressedContext;
88
- preToolCall(_toolName: string, _toolArgs: Record<string, any>, context: TurnEntry[]): {
89
- compressed: TurnEntry[];
90
- status: BudgetStatus;
91
- };
92
- getStats(): {
93
- historyLength: number;
94
- lastCompression: number;
95
- };
96
- clearHistory(): void;
97
- }
98
- export default LeanCTXEngine;
99
- //# sourceMappingURL=lean-ctx.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lean-ctx.d.ts","sourceRoot":"","sources":["../../src/core/lean-ctx.ts"],"names":[],"mappings":"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","sourcesContent":["// OMK v6.2 — Lean CTX Engine (TypeScript)\n// =========================================\n// packages/coding-agent/src/core/lean-ctx.ts\n//\n// 매 프롬프트 입력 시 자동으로 context 분석/압축을 수행하는 엔진.\n// 순수 로컬 모드 — API 호출 0회.\n\nimport { EventEmitter } from \"events\";\n\n// ── 상수 및 설정 ────────────────────────────────────────────────────────\n\nconst DEFAULT_CONFIG = {\n\trecencyWindow: 4,\n\trelevanceThreshold: 0.3,\n\tkeyTurnReserve: 2,\n\tsummaryEvery: 3,\n\tmaxContextTokens: 2000,\n\tcompressionTarget: 0.6,\n\n\ttfidfWeight: 0.5,\n\tsemanticWeight: 0.3,\n\trecencyWeight: 0.2,\n\tkeywordBoost: 1.5,\n\n\tlruWeight: 0.4,\n\tfrequencyWeight: 0.3,\n\trecencyDecayWeight: 0.3,\n\tprotectedKeywords: [\"refusal\", \"error\", \"strategy_change\", \"phase_transition\"],\n\n\thardTokenLimit: 15000,\n\tsoftTokenLimit: 12000,\n\twarningThreshold: 0.8,\n\tcriticalThreshold: 0.95,\n\tgracefulDegradation: true,\n\topportunisticExpansion: true,\n\n\tautoCompress: true,\n\tcompressOnEveryPrompt: true,\n\tminTokensToCompress: 500,\n\tmaxTurnsBeforeCompress: 8,\n};\n\n// ── 데이터 모델 ─────────────────────────────────────────────────────────\n\nexport interface TurnEntry {\n\tindex: number;\n\trole: \"user\" | \"assistant\" | \"system\" | \"tool\";\n\tcontent: string;\n\ttimestamp: number;\n\tmetadata?: Record<string, any>;\n\ttokenCount?: number;\n\tisKeyTurn?: boolean;\n\trelevanceScore?: number;\n\taccessCount?: number;\n\tlastAccessed?: number;\n}\n\nexport interface CompressedContext {\n\tturns: TurnEntry[];\n\tsummary: string;\n\toriginalTokens: number;\n\tcompressedTokens: number;\n\tcompressionRatio: number;\n\ttechniqueUsed: string;\n\tkeyTurnsPreserved: number;\n\tevictedCount: number;\n\tmetadata?: Record<string, any>;\n}\n\nexport interface BudgetStatus {\n\tusedTokens: number;\n\ttotalTokens: number;\n\tratio: number;\n\tlevel: \"green\" | \"yellow\" | \"orange\" | \"red\" | \"exceeded\";\n\tremaining: number;\n\tcanAddAgents: boolean;\n}\n\n// ── ContextCompressor ───────────────────────────────────────────────────\n\nexport class ContextCompressor extends EventEmitter {\n\tprivate config: typeof DEFAULT_CONFIG;\n\tprivate charsPerToken = 4;\n\n\tconstructor(config?: Partial<typeof DEFAULT_CONFIG>) {\n\t\tsuper();\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tcompress(context: TurnEntry[], currentTurn?: TurnEntry): CompressedContext {\n\t\tconst originalTokens = this.estimateTokens(context);\n\n\t\tif (originalTokens < this.config.minTokensToCompress) {\n\t\t\treturn {\n\t\t\t\tturns: context,\n\t\t\t\tsummary: \"\",\n\t\t\t\toriginalTokens,\n\t\t\t\tcompressedTokens: originalTokens,\n\t\t\t\tcompressionRatio: 1.0,\n\t\t\t\ttechniqueUsed: \"none\",\n\t\t\t\tkeyTurnsPreserved: 0,\n\t\t\t\tevictedCount: 0,\n\t\t\t};\n\t\t}\n\n\t\tconst keyTurns = this.extractKeyTurns(context);\n\t\tconst recent = this.applyRecencyWindow(context);\n\t\tconst relevant = this.filterByRelevance(context, currentTurn, keyTurns);\n\t\tconst summary = this.hierarchicalSummarize(context, recent, keyTurns, relevant);\n\t\tconst compressed = this.assembleCompressed(keyTurns, relevant, recent, summary);\n\n\t\tconst compressedTokens = this.estimateTokens(compressed);\n\t\tconst ratio = originalTokens > 0 ? compressedTokens / originalTokens : 1.0;\n\n\t\treturn {\n\t\t\tturns: compressed,\n\t\t\tsummary,\n\t\t\toriginalTokens,\n\t\t\tcompressedTokens,\n\t\t\tcompressionRatio: ratio,\n\t\t\ttechniqueUsed: \"hierarchical+selective\",\n\t\t\tkeyTurnsPreserved: keyTurns.length,\n\t\t\tevictedCount: context.length - compressed.length,\n\t\t};\n\t}\n\n\tprivate estimateTokens(turns: TurnEntry[]): number {\n\t\treturn turns.reduce((sum, t) => sum + Math.ceil(t.content.length / this.charsPerToken), 0);\n\t}\n\n\tprivate extractKeyTurns(context: TurnEntry[]): TurnEntry[] {\n\t\tconst keyTurns: TurnEntry[] = [];\n\t\tconst protectedKeywords = this.config.protectedKeywords;\n\n\t\tfor (const turn of context) {\n\t\t\tconst contentLower = turn.content.toLowerCase();\n\t\t\tlet isKey = protectedKeywords.some((kw) => contentLower.includes(kw.toLowerCase()));\n\n\t\t\tif (turn.metadata?.isKeyTurn || turn.metadata?.phaseTransition) {\n\t\t\t\tisKey = true;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tturn.role === \"assistant\" &&\n\t\t\t\t[\"refuse\", \"cannot\", \"unable\", \"sorry\", \"거부\", \"죄송\"].some((w) => contentLower.includes(w))\n\t\t\t) {\n\t\t\t\tisKey = true;\n\t\t\t}\n\n\t\t\tif (isKey) {\n\t\t\t\tturn.isKeyTurn = true;\n\t\t\t\tkeyTurns.push(turn);\n\t\t\t}\n\t\t}\n\n\t\treturn keyTurns;\n\t}\n\n\tprivate applyRecencyWindow(context: TurnEntry[]): TurnEntry[] {\n\t\tconst windowSize = this.config.recencyWindow;\n\t\tif (context.length <= windowSize) return [...context];\n\t\treturn context.slice(-windowSize);\n\t}\n\n\tprivate filterByRelevance(context: TurnEntry[], currentTurn?: TurnEntry, keyTurns?: TurnEntry[]): TurnEntry[] {\n\t\tif (!currentTurn) return [...context];\n\n\t\tconst threshold = this.config.relevanceThreshold;\n\t\tconst keyIndices = new Set(keyTurns?.map((t) => t.index) ?? []);\n\n\t\treturn context.filter((turn) => {\n\t\t\tif (keyIndices.has(turn.index)) return true;\n\t\t\tconst score = this.calculateRelevance(turn, currentTurn);\n\t\t\treturn score >= threshold;\n\t\t});\n\t}\n\n\tprivate calculateRelevance(turn: TurnEntry, currentTurn: TurnEntry): number {\n\t\tconst tfidfScore = this.tfidfSimilarity(turn.content, currentTurn.content);\n\t\tconst recencyScore = Math.exp(-(Date.now() - turn.timestamp) / 3600000);\n\t\treturn tfidfScore * this.config.tfidfWeight + recencyScore * this.config.recencyWeight;\n\t}\n\n\tprivate tfidfSimilarity(text1: string, text2: string): number {\n\t\tconst words1 = text1.toLowerCase().split(/\\s+/);\n\t\tconst words2 = text2.toLowerCase().split(/\\s+/);\n\t\tconst set1 = new Set(words1);\n\t\tconst set2 = new Set(words2);\n\t\tconst intersection = new Set([...set1].filter((x) => set2.has(x)));\n\t\treturn intersection.size / Math.sqrt(set1.size * set2.size);\n\t}\n\n\tprivate hierarchicalSummarize(\n\t\t_context: TurnEntry[],\n\t\trecent: TurnEntry[],\n\t\tkeyTurns: TurnEntry[],\n\t\trelevant: TurnEntry[],\n\t): string {\n\t\tconst allImportant = [...new Set([...keyTurns, ...relevant, ...recent])].sort((a, b) => a.index - b.index);\n\t\tconst chunks: string[] = [];\n\n\t\tfor (let i = 0; i < allImportant.length; i += this.config.summaryEvery) {\n\t\t\tconst chunk = allImportant.slice(i, i + this.config.summaryEvery);\n\t\t\tconst summary = chunk.map((t) => `[${t.role}]: ${t.content.substring(0, 100)}`).join(\" | \");\n\t\t\tchunks.push(summary);\n\t\t}\n\n\t\treturn chunks.join(\"\\n\");\n\t}\n\n\tprivate assembleCompressed(\n\t\tkeyTurns: TurnEntry[],\n\t\trelevant: TurnEntry[],\n\t\trecent: TurnEntry[],\n\t\t_summary: string,\n\t): TurnEntry[] {\n\t\tconst important = new Map<number, TurnEntry>();\n\n\t\tfor (const turn of keyTurns) important.set(turn.index, turn);\n\t\tfor (const turn of relevant) important.set(turn.index, turn);\n\t\tfor (const turn of recent) important.set(turn.index, turn);\n\n\t\treturn Array.from(important.values()).sort((a, b) => a.index - b.index);\n\t}\n}\n\n// ── TokenBudgetEnforcer ─────────────────────────────────────────────────\n\nexport class TokenBudgetEnforcer extends EventEmitter {\n\tprivate config: typeof DEFAULT_CONFIG;\n\n\tconstructor(config?: Partial<typeof DEFAULT_CONFIG>) {\n\t\tsuper();\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tcheck(usedTokens: number): BudgetStatus {\n\t\tconst total = this.config.hardTokenLimit;\n\t\tconst ratio = usedTokens / total;\n\t\tconst remaining = total - usedTokens;\n\n\t\tlet level: BudgetStatus[\"level\"] = \"green\";\n\t\tif (ratio >= 1.0) level = \"exceeded\";\n\t\telse if (ratio >= this.config.criticalThreshold) level = \"red\";\n\t\telse if (ratio >= this.config.warningThreshold) level = \"orange\";\n\t\telse if (ratio >= 0.6) level = \"yellow\";\n\n\t\treturn {\n\t\t\tusedTokens,\n\t\t\ttotalTokens: total,\n\t\t\tratio,\n\t\t\tlevel,\n\t\t\tremaining,\n\t\t\tcanAddAgents: level === \"green\" || level === \"yellow\",\n\t\t};\n\t}\n\n\tautoCompressIfNeeded(context: TurnEntry[]): { compressed: TurnEntry[]; status: BudgetStatus } {\n\t\tconst tokens = context.reduce((sum, t) => sum + Math.ceil(t.content.length / 4), 0);\n\t\tconst status = this.check(tokens);\n\n\t\tif (status.level === \"red\" || status.level === \"exceeded\") {\n\t\t\tconst compressor = new ContextCompressor(this.config);\n\t\t\tconst result = compressor.compress(context);\n\t\t\treturn { compressed: result.turns, status: this.check(result.compressedTokens) };\n\t\t}\n\n\t\treturn { compressed: context, status };\n\t}\n}\n\n// ── LeanCTXEngine (통합 엔진) ───────────────────────────────────────────\n\nexport class LeanCTXEngine extends EventEmitter {\n\tprivate compressor: ContextCompressor;\n\tprivate budgetEnforcer: TokenBudgetEnforcer;\n\tprivate history: TurnEntry[] = [];\n\n\tconstructor(config?: Partial<typeof DEFAULT_CONFIG>) {\n\t\tsuper();\n\t\tthis.compressor = new ContextCompressor(config);\n\t\tthis.budgetEnforcer = new TokenBudgetEnforcer(config);\n\t}\n\n\tprocessPrompt(prompt: string, role: \"user\" | \"assistant\" | \"system\" = \"user\"): CompressedContext {\n\t\tconst currentTurn: TurnEntry = {\n\t\t\tindex: this.history.length,\n\t\t\trole,\n\t\t\tcontent: prompt,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tconst result = this.compressor.compress(this.history, currentTurn);\n\t\tthis.budgetEnforcer.autoCompressIfNeeded(result.turns);\n\n\t\tthis.history.push(currentTurn);\n\t\tif (this.history.length > 100) this.history = this.history.slice(-50);\n\n\t\treturn result;\n\t}\n\n\tpreToolCall(\n\t\t_toolName: string,\n\t\t_toolArgs: Record<string, any>,\n\t\tcontext: TurnEntry[],\n\t): { compressed: TurnEntry[]; status: BudgetStatus } {\n\t\treturn this.budgetEnforcer.autoCompressIfNeeded(context);\n\t}\n\n\tgetStats(): { historyLength: number; lastCompression: number } {\n\t\treturn { historyLength: this.history.length, lastCompression: Date.now() };\n\t}\n\n\tclearHistory(): void {\n\t\tthis.history = [];\n\t}\n}\n\nexport default LeanCTXEngine;\n"]}
@@ -1,225 +0,0 @@
1
- // OMK v6.2 — Lean CTX Engine (TypeScript)
2
- // =========================================
3
- // packages/coding-agent/src/core/lean-ctx.ts
4
- //
5
- // 매 프롬프트 입력 시 자동으로 context 분석/압축을 수행하는 엔진.
6
- // 순수 로컬 모드 — API 호출 0회.
7
- import { EventEmitter } from "events";
8
- // ── 상수 및 설정 ────────────────────────────────────────────────────────
9
- const DEFAULT_CONFIG = {
10
- recencyWindow: 4,
11
- relevanceThreshold: 0.3,
12
- keyTurnReserve: 2,
13
- summaryEvery: 3,
14
- maxContextTokens: 2000,
15
- compressionTarget: 0.6,
16
- tfidfWeight: 0.5,
17
- semanticWeight: 0.3,
18
- recencyWeight: 0.2,
19
- keywordBoost: 1.5,
20
- lruWeight: 0.4,
21
- frequencyWeight: 0.3,
22
- recencyDecayWeight: 0.3,
23
- protectedKeywords: ["refusal", "error", "strategy_change", "phase_transition"],
24
- hardTokenLimit: 15000,
25
- softTokenLimit: 12000,
26
- warningThreshold: 0.8,
27
- criticalThreshold: 0.95,
28
- gracefulDegradation: true,
29
- opportunisticExpansion: true,
30
- autoCompress: true,
31
- compressOnEveryPrompt: true,
32
- minTokensToCompress: 500,
33
- maxTurnsBeforeCompress: 8,
34
- };
35
- // ── ContextCompressor ───────────────────────────────────────────────────
36
- export class ContextCompressor extends EventEmitter {
37
- config;
38
- charsPerToken = 4;
39
- constructor(config) {
40
- super();
41
- this.config = { ...DEFAULT_CONFIG, ...config };
42
- }
43
- compress(context, currentTurn) {
44
- const originalTokens = this.estimateTokens(context);
45
- if (originalTokens < this.config.minTokensToCompress) {
46
- return {
47
- turns: context,
48
- summary: "",
49
- originalTokens,
50
- compressedTokens: originalTokens,
51
- compressionRatio: 1.0,
52
- techniqueUsed: "none",
53
- keyTurnsPreserved: 0,
54
- evictedCount: 0,
55
- };
56
- }
57
- const keyTurns = this.extractKeyTurns(context);
58
- const recent = this.applyRecencyWindow(context);
59
- const relevant = this.filterByRelevance(context, currentTurn, keyTurns);
60
- const summary = this.hierarchicalSummarize(context, recent, keyTurns, relevant);
61
- const compressed = this.assembleCompressed(keyTurns, relevant, recent, summary);
62
- const compressedTokens = this.estimateTokens(compressed);
63
- const ratio = originalTokens > 0 ? compressedTokens / originalTokens : 1.0;
64
- return {
65
- turns: compressed,
66
- summary,
67
- originalTokens,
68
- compressedTokens,
69
- compressionRatio: ratio,
70
- techniqueUsed: "hierarchical+selective",
71
- keyTurnsPreserved: keyTurns.length,
72
- evictedCount: context.length - compressed.length,
73
- };
74
- }
75
- estimateTokens(turns) {
76
- return turns.reduce((sum, t) => sum + Math.ceil(t.content.length / this.charsPerToken), 0);
77
- }
78
- extractKeyTurns(context) {
79
- const keyTurns = [];
80
- const protectedKeywords = this.config.protectedKeywords;
81
- for (const turn of context) {
82
- const contentLower = turn.content.toLowerCase();
83
- let isKey = protectedKeywords.some((kw) => contentLower.includes(kw.toLowerCase()));
84
- if (turn.metadata?.isKeyTurn || turn.metadata?.phaseTransition) {
85
- isKey = true;
86
- }
87
- if (turn.role === "assistant" &&
88
- ["refuse", "cannot", "unable", "sorry", "거부", "죄송"].some((w) => contentLower.includes(w))) {
89
- isKey = true;
90
- }
91
- if (isKey) {
92
- turn.isKeyTurn = true;
93
- keyTurns.push(turn);
94
- }
95
- }
96
- return keyTurns;
97
- }
98
- applyRecencyWindow(context) {
99
- const windowSize = this.config.recencyWindow;
100
- if (context.length <= windowSize)
101
- return [...context];
102
- return context.slice(-windowSize);
103
- }
104
- filterByRelevance(context, currentTurn, keyTurns) {
105
- if (!currentTurn)
106
- return [...context];
107
- const threshold = this.config.relevanceThreshold;
108
- const keyIndices = new Set(keyTurns?.map((t) => t.index) ?? []);
109
- return context.filter((turn) => {
110
- if (keyIndices.has(turn.index))
111
- return true;
112
- const score = this.calculateRelevance(turn, currentTurn);
113
- return score >= threshold;
114
- });
115
- }
116
- calculateRelevance(turn, currentTurn) {
117
- const tfidfScore = this.tfidfSimilarity(turn.content, currentTurn.content);
118
- const recencyScore = Math.exp(-(Date.now() - turn.timestamp) / 3600000);
119
- return tfidfScore * this.config.tfidfWeight + recencyScore * this.config.recencyWeight;
120
- }
121
- tfidfSimilarity(text1, text2) {
122
- const words1 = text1.toLowerCase().split(/\s+/);
123
- const words2 = text2.toLowerCase().split(/\s+/);
124
- const set1 = new Set(words1);
125
- const set2 = new Set(words2);
126
- const intersection = new Set([...set1].filter((x) => set2.has(x)));
127
- return intersection.size / Math.sqrt(set1.size * set2.size);
128
- }
129
- hierarchicalSummarize(_context, recent, keyTurns, relevant) {
130
- const allImportant = [...new Set([...keyTurns, ...relevant, ...recent])].sort((a, b) => a.index - b.index);
131
- const chunks = [];
132
- for (let i = 0; i < allImportant.length; i += this.config.summaryEvery) {
133
- const chunk = allImportant.slice(i, i + this.config.summaryEvery);
134
- const summary = chunk.map((t) => `[${t.role}]: ${t.content.substring(0, 100)}`).join(" | ");
135
- chunks.push(summary);
136
- }
137
- return chunks.join("\n");
138
- }
139
- assembleCompressed(keyTurns, relevant, recent, _summary) {
140
- const important = new Map();
141
- for (const turn of keyTurns)
142
- important.set(turn.index, turn);
143
- for (const turn of relevant)
144
- important.set(turn.index, turn);
145
- for (const turn of recent)
146
- important.set(turn.index, turn);
147
- return Array.from(important.values()).sort((a, b) => a.index - b.index);
148
- }
149
- }
150
- // ── TokenBudgetEnforcer ─────────────────────────────────────────────────
151
- export class TokenBudgetEnforcer extends EventEmitter {
152
- config;
153
- constructor(config) {
154
- super();
155
- this.config = { ...DEFAULT_CONFIG, ...config };
156
- }
157
- check(usedTokens) {
158
- const total = this.config.hardTokenLimit;
159
- const ratio = usedTokens / total;
160
- const remaining = total - usedTokens;
161
- let level = "green";
162
- if (ratio >= 1.0)
163
- level = "exceeded";
164
- else if (ratio >= this.config.criticalThreshold)
165
- level = "red";
166
- else if (ratio >= this.config.warningThreshold)
167
- level = "orange";
168
- else if (ratio >= 0.6)
169
- level = "yellow";
170
- return {
171
- usedTokens,
172
- totalTokens: total,
173
- ratio,
174
- level,
175
- remaining,
176
- canAddAgents: level === "green" || level === "yellow",
177
- };
178
- }
179
- autoCompressIfNeeded(context) {
180
- const tokens = context.reduce((sum, t) => sum + Math.ceil(t.content.length / 4), 0);
181
- const status = this.check(tokens);
182
- if (status.level === "red" || status.level === "exceeded") {
183
- const compressor = new ContextCompressor(this.config);
184
- const result = compressor.compress(context);
185
- return { compressed: result.turns, status: this.check(result.compressedTokens) };
186
- }
187
- return { compressed: context, status };
188
- }
189
- }
190
- // ── LeanCTXEngine (통합 엔진) ───────────────────────────────────────────
191
- export class LeanCTXEngine extends EventEmitter {
192
- compressor;
193
- budgetEnforcer;
194
- history = [];
195
- constructor(config) {
196
- super();
197
- this.compressor = new ContextCompressor(config);
198
- this.budgetEnforcer = new TokenBudgetEnforcer(config);
199
- }
200
- processPrompt(prompt, role = "user") {
201
- const currentTurn = {
202
- index: this.history.length,
203
- role,
204
- content: prompt,
205
- timestamp: Date.now(),
206
- };
207
- const result = this.compressor.compress(this.history, currentTurn);
208
- this.budgetEnforcer.autoCompressIfNeeded(result.turns);
209
- this.history.push(currentTurn);
210
- if (this.history.length > 100)
211
- this.history = this.history.slice(-50);
212
- return result;
213
- }
214
- preToolCall(_toolName, _toolArgs, context) {
215
- return this.budgetEnforcer.autoCompressIfNeeded(context);
216
- }
217
- getStats() {
218
- return { historyLength: this.history.length, lastCompression: Date.now() };
219
- }
220
- clearHistory() {
221
- this.history = [];
222
- }
223
- }
224
- export default LeanCTXEngine;
225
- //# sourceMappingURL=lean-ctx.js.map