@dommaker/harness 0.19.0 → 1.1.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 (398) hide show
  1. package/CHANGELOG.md +22 -9
  2. package/bin/harness.js +136 -557
  3. package/dist/cli/commands/check.d.ts.map +1 -1
  4. package/dist/cli/commands/check.js +2 -13
  5. package/dist/cli/commands/check.js.map +1 -1
  6. package/dist/cli/commands/definitions.d.ts +90 -0
  7. package/dist/cli/commands/definitions.d.ts.map +1 -0
  8. package/dist/cli/commands/definitions.js +519 -0
  9. package/dist/cli/commands/definitions.js.map +1 -0
  10. package/dist/cli/commands/knowledge.js.map +1 -1
  11. package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
  12. package/dist/cli/commands/sync-docs/agents-syncer.js +25 -4
  13. package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
  14. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts +3 -25
  15. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
  16. package/dist/cli/commands/sync-docs/capabilities-syncer.js +3 -93
  17. package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
  18. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  19. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  20. package/dist/cli/commands/sync-docs/index.js +4 -4
  21. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  22. package/dist/completion-checkers/classify.d.ts +23 -0
  23. package/dist/completion-checkers/classify.d.ts.map +1 -0
  24. package/dist/completion-checkers/classify.js +37 -0
  25. package/dist/completion-checkers/classify.js.map +1 -0
  26. package/dist/completion-checkers/contract-presence.d.ts +12 -0
  27. package/dist/completion-checkers/contract-presence.d.ts.map +1 -0
  28. package/dist/completion-checkers/contract-presence.js +36 -0
  29. package/dist/completion-checkers/contract-presence.js.map +1 -0
  30. package/dist/completion-checkers/glob-match.d.ts +13 -0
  31. package/dist/completion-checkers/glob-match.d.ts.map +1 -0
  32. package/dist/completion-checkers/glob-match.js +58 -0
  33. package/dist/completion-checkers/glob-match.js.map +1 -0
  34. package/dist/completion-checkers/index.d.ts +19 -0
  35. package/dist/completion-checkers/index.d.ts.map +1 -0
  36. package/dist/completion-checkers/index.js +47 -0
  37. package/dist/completion-checkers/index.js.map +1 -0
  38. package/dist/completion-checkers/phase-format.d.ts +15 -0
  39. package/dist/completion-checkers/phase-format.d.ts.map +1 -0
  40. package/dist/completion-checkers/phase-format.js +42 -0
  41. package/dist/completion-checkers/phase-format.js.map +1 -0
  42. package/dist/completion-checkers/tdd-chain.d.ts +16 -0
  43. package/dist/completion-checkers/tdd-chain.d.ts.map +1 -0
  44. package/dist/completion-checkers/tdd-chain.js +57 -0
  45. package/dist/completion-checkers/tdd-chain.js.map +1 -0
  46. package/dist/completion-checkers/types.d.ts +77 -0
  47. package/dist/completion-checkers/types.d.ts.map +1 -0
  48. package/dist/completion-checkers/types.js +10 -0
  49. package/dist/completion-checkers/types.js.map +1 -0
  50. package/dist/context/index.d.ts +1 -5
  51. package/dist/context/index.d.ts.map +1 -1
  52. package/dist/context/index.js +1 -5
  53. package/dist/context/index.js.map +1 -1
  54. package/dist/context/knowledge-injector.d.ts +3 -3
  55. package/dist/context/knowledge-injector.d.ts.map +1 -1
  56. package/dist/context/knowledge-injector.js +1 -1
  57. package/dist/context/session-manager.d.ts +1 -12
  58. package/dist/context/session-manager.d.ts.map +1 -1
  59. package/dist/context/session-manager.js +0 -63
  60. package/dist/context/session-manager.js.map +1 -1
  61. package/dist/context/types.d.ts +1 -39
  62. package/dist/context/types.d.ts.map +1 -1
  63. package/dist/context/types.js +2 -15
  64. package/dist/context/types.js.map +1 -1
  65. package/dist/core/constraints/agent-prompt-renderer.d.ts +1 -1
  66. package/dist/core/constraints/agent-prompt-renderer.js +1 -1
  67. package/dist/core/constraints/capabilities-parser.d.ts +17 -2
  68. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  69. package/dist/core/constraints/capabilities-parser.js +84 -2
  70. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  71. package/dist/core/constraints/checker.d.ts +3 -17
  72. package/dist/core/constraints/checker.d.ts.map +1 -1
  73. package/dist/core/constraints/checker.js +7 -47
  74. package/dist/core/constraints/checker.js.map +1 -1
  75. package/dist/core/constraints/definitions.d.ts +0 -7
  76. package/dist/core/constraints/definitions.d.ts.map +1 -1
  77. package/dist/core/constraints/definitions.js +1 -8
  78. package/dist/core/constraints/definitions.js.map +1 -1
  79. package/dist/core/constraints/doc-freshness/runner.d.ts +0 -2
  80. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  81. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  82. package/dist/core/constraints/index.d.ts +1 -1
  83. package/dist/core/constraints/index.d.ts.map +1 -1
  84. package/dist/core/constraints/index.js +2 -3
  85. package/dist/core/constraints/index.js.map +1 -1
  86. package/dist/core/constraints/interceptor.d.ts.map +1 -1
  87. package/dist/core/constraints/interceptor.js +1 -5
  88. package/dist/core/constraints/interceptor.js.map +1 -1
  89. package/dist/core/effective-constraints.d.ts.map +1 -1
  90. package/dist/core/effective-constraints.js +0 -1
  91. package/dist/core/effective-constraints.js.map +1 -1
  92. package/dist/core/project-config-loader.d.ts.map +1 -1
  93. package/dist/core/project-config-loader.js +1 -8
  94. package/dist/core/project-config-loader.js.map +1 -1
  95. package/dist/dashboard/stats.d.ts.map +1 -1
  96. package/dist/dashboard/stats.js.map +1 -1
  97. package/dist/dashboard/types.d.ts +2 -2
  98. package/dist/dashboard/types.d.ts.map +1 -1
  99. package/dist/failure/constraint-handler.d.ts.map +1 -1
  100. package/dist/failure/constraint-handler.js +0 -2
  101. package/dist/failure/constraint-handler.js.map +1 -1
  102. package/dist/gates/acceptance.d.ts +9 -1
  103. package/dist/gates/acceptance.d.ts.map +1 -1
  104. package/dist/gates/acceptance.js +21 -0
  105. package/dist/gates/acceptance.js.map +1 -1
  106. package/dist/gates/checker-gate.d.ts +23 -0
  107. package/dist/gates/checker-gate.d.ts.map +1 -0
  108. package/dist/gates/checker-gate.js +53 -0
  109. package/dist/gates/checker-gate.js.map +1 -0
  110. package/dist/gates/command.d.ts +9 -2
  111. package/dist/gates/command.d.ts.map +1 -1
  112. package/dist/gates/command.js +10 -0
  113. package/dist/gates/command.js.map +1 -1
  114. package/dist/gates/contract.d.ts +8 -2
  115. package/dist/gates/contract.d.ts.map +1 -1
  116. package/dist/gates/contract.js +9 -0
  117. package/dist/gates/contract.js.map +1 -1
  118. package/dist/gates/decision.d.ts +17 -0
  119. package/dist/gates/decision.d.ts.map +1 -0
  120. package/dist/gates/decision.js +25 -0
  121. package/dist/gates/decision.js.map +1 -0
  122. package/dist/gates/definitions.d.ts +63 -0
  123. package/dist/gates/definitions.d.ts.map +1 -0
  124. package/dist/gates/definitions.js +160 -0
  125. package/dist/gates/definitions.js.map +1 -0
  126. package/dist/gates/effective-gates.d.ts +30 -0
  127. package/dist/gates/effective-gates.d.ts.map +1 -0
  128. package/dist/gates/effective-gates.js +85 -0
  129. package/dist/gates/effective-gates.js.map +1 -0
  130. package/dist/gates/index.d.ts +25 -1
  131. package/dist/gates/index.d.ts.map +1 -1
  132. package/dist/gates/index.js +37 -1
  133. package/dist/gates/index.js.map +1 -1
  134. package/dist/gates/performance.d.ts +8 -2
  135. package/dist/gates/performance.d.ts.map +1 -1
  136. package/dist/gates/performance.js +9 -0
  137. package/dist/gates/performance.js.map +1 -1
  138. package/dist/gates/registry.d.ts +32 -0
  139. package/dist/gates/registry.d.ts.map +1 -0
  140. package/dist/gates/registry.js +90 -0
  141. package/dist/gates/registry.js.map +1 -0
  142. package/dist/gates/review.d.ts +8 -2
  143. package/dist/gates/review.d.ts.map +1 -1
  144. package/dist/gates/review.js +9 -0
  145. package/dist/gates/review.js.map +1 -1
  146. package/dist/gates/runner.d.ts +30 -0
  147. package/dist/gates/runner.d.ts.map +1 -0
  148. package/dist/gates/runner.js +38 -0
  149. package/dist/gates/runner.js.map +1 -0
  150. package/dist/gates/security.d.ts +8 -2
  151. package/dist/gates/security.d.ts.map +1 -1
  152. package/dist/gates/security.js +9 -0
  153. package/dist/gates/security.js.map +1 -1
  154. package/dist/gates/types.d.ts +41 -1
  155. package/dist/gates/types.d.ts.map +1 -1
  156. package/dist/hooks/bootstrap.d.ts.map +1 -1
  157. package/dist/hooks/bootstrap.js +0 -2
  158. package/dist/hooks/bootstrap.js.map +1 -1
  159. package/dist/hooks/config.d.ts +26 -0
  160. package/dist/hooks/config.d.ts.map +1 -0
  161. package/dist/hooks/config.js +30 -0
  162. package/dist/hooks/config.js.map +1 -0
  163. package/dist/hooks/index.d.ts +2 -1
  164. package/dist/hooks/index.d.ts.map +1 -1
  165. package/dist/hooks/index.js +4 -1
  166. package/dist/hooks/index.js.map +1 -1
  167. package/dist/hooks/registry.d.ts +18 -1
  168. package/dist/hooks/registry.d.ts.map +1 -1
  169. package/dist/hooks/registry.js +45 -0
  170. package/dist/hooks/registry.js.map +1 -1
  171. package/dist/hooks/types.d.ts +20 -0
  172. package/dist/hooks/types.d.ts.map +1 -1
  173. package/dist/index.d.ts +5 -8
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +11 -20
  176. package/dist/index.js.map +1 -1
  177. package/dist/knowledge/import.d.ts +2 -2
  178. package/dist/knowledge/import.d.ts.map +1 -1
  179. package/dist/knowledge/ingest.js.map +1 -1
  180. package/dist/knowledge/lifecycle-hooks.d.ts +2 -2
  181. package/dist/knowledge/lifecycle-hooks.d.ts.map +1 -1
  182. package/dist/knowledge/types.d.ts +5 -7
  183. package/dist/knowledge/types.d.ts.map +1 -1
  184. package/dist/knowledge/types.js +1 -1
  185. package/dist/knowledge/types.js.map +1 -1
  186. package/dist/monitoring/constraint-doctor.d.ts +4 -22
  187. package/dist/monitoring/constraint-doctor.d.ts.map +1 -1
  188. package/dist/monitoring/constraint-doctor.js +7 -94
  189. package/dist/monitoring/constraint-doctor.js.map +1 -1
  190. package/dist/presets/standard.d.ts +1 -1
  191. package/dist/presets/standard.d.ts.map +1 -1
  192. package/dist/presets/standard.js +1 -2
  193. package/dist/presets/standard.js.map +1 -1
  194. package/dist/pretool-use-hook.d.ts +16 -0
  195. package/dist/pretool-use-hook.d.ts.map +1 -0
  196. package/dist/pretool-use-hook.js +68 -0
  197. package/dist/pretool-use-hook.js.map +1 -0
  198. package/dist/spec/annotation-checker.d.ts.map +1 -1
  199. package/dist/spec/annotation-checker.js +6 -26
  200. package/dist/spec/annotation-checker.js.map +1 -1
  201. package/dist/tools/index.d.ts +0 -4
  202. package/dist/tools/index.d.ts.map +1 -1
  203. package/dist/tools/index.js +0 -4
  204. package/dist/tools/index.js.map +1 -1
  205. package/dist/types/constraint.d.ts +1 -12
  206. package/dist/types/constraint.d.ts.map +1 -1
  207. package/dist/types/constraint.js +0 -3
  208. package/dist/types/constraint.js.map +1 -1
  209. package/dist/types/project-config.d.ts +0 -2
  210. package/dist/types/project-config.d.ts.map +1 -1
  211. package/dist/utils/file-walk.d.ts +2 -2
  212. package/dist/utils/file-walk.js +2 -2
  213. package/package.json +6 -1
  214. package/src/CONTEXT.md +15 -0
  215. package/src/__tests__/checker-extra.test.ts +2 -59
  216. package/src/__tests__/constraint-doctor.test.ts +1 -140
  217. package/src/__tests__/constraint-handler.test.ts +0 -4
  218. package/src/__tests__/pretool-use-hook.test.ts +82 -0
  219. package/src/__tests__/project-config-loader-extra.test.ts +0 -20
  220. package/src/__tests__/project-config-loader.test.ts +0 -1
  221. package/src/cli/commands/CONTEXT.md +15 -7
  222. package/src/cli/commands/__tests__/check-drift.test.ts +0 -3
  223. package/src/cli/commands/__tests__/check-skip-output.test.ts +0 -5
  224. package/src/cli/commands/__tests__/check.test.ts +7 -75
  225. package/src/cli/commands/__tests__/registry.test.ts +201 -0
  226. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +55 -0
  227. package/src/cli/commands/check.ts +2 -14
  228. package/src/cli/commands/definitions.ts +593 -0
  229. package/src/cli/commands/knowledge.ts +3 -3
  230. package/src/cli/commands/sync-docs/agents-syncer.ts +26 -6
  231. package/src/cli/commands/sync-docs/capabilities-syncer.ts +4 -110
  232. package/src/cli/commands/sync-docs/index.ts +8 -5
  233. package/src/completion-checkers/CONTEXT.md +25 -0
  234. package/src/completion-checkers/__tests__/contract-presence.test.ts +44 -0
  235. package/src/completion-checkers/__tests__/phase-format.test.ts +60 -0
  236. package/src/completion-checkers/__tests__/tdd-chain.test.ts +99 -0
  237. package/src/completion-checkers/classify.ts +47 -0
  238. package/src/completion-checkers/contract-presence.ts +40 -0
  239. package/src/completion-checkers/glob-match.ts +54 -0
  240. package/src/completion-checkers/index.ts +19 -0
  241. package/src/completion-checkers/phase-format.ts +48 -0
  242. package/src/completion-checkers/tdd-chain.ts +63 -0
  243. package/src/completion-checkers/types.ts +84 -0
  244. package/src/context/CONTEXT.md +2 -7
  245. package/src/context/__tests__/session-manager.test.ts +0 -91
  246. package/src/context/index.ts +1 -5
  247. package/src/context/knowledge-injector.ts +3 -3
  248. package/src/context/session-manager.ts +0 -74
  249. package/src/context/types.ts +2 -63
  250. package/src/core/constraints/__tests__/interceptor.test.ts +0 -2
  251. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  252. package/src/core/constraints/capabilities-parser.ts +95 -2
  253. package/src/core/constraints/checker.ts +8 -53
  254. package/src/core/constraints/definitions.ts +0 -8
  255. package/src/core/constraints/doc-freshness/runner.ts +1 -2
  256. package/src/core/constraints/index.ts +1 -2
  257. package/src/core/constraints/interceptor.ts +1 -6
  258. package/src/core/effective-constraints.ts +0 -1
  259. package/src/core/project-config-loader.ts +1 -7
  260. package/src/dashboard/stats.ts +2 -2
  261. package/src/dashboard/types.ts +2 -2
  262. package/src/failure/constraint-handler.ts +0 -2
  263. package/src/gates/CONTEXT.md +16 -13
  264. package/src/gates/__tests__/checker-gate.test.ts +45 -0
  265. package/src/gates/__tests__/contract.test.ts +73 -0
  266. package/src/gates/__tests__/effective-gates.test.ts +82 -0
  267. package/src/gates/__tests__/gate-interface.test.ts +202 -0
  268. package/src/gates/__tests__/registry.test.ts +87 -0
  269. package/src/gates/__tests__/runner.test.ts +81 -0
  270. package/src/gates/acceptance.ts +24 -1
  271. package/src/gates/checker-gate.ts +54 -0
  272. package/src/gates/command.ts +13 -2
  273. package/src/gates/contract.ts +12 -2
  274. package/src/gates/decision.ts +27 -0
  275. package/src/gates/definitions.ts +207 -0
  276. package/src/gates/effective-gates.ts +106 -0
  277. package/src/gates/index.ts +38 -0
  278. package/src/gates/performance.ts +12 -2
  279. package/src/gates/registry.ts +107 -0
  280. package/src/gates/review.ts +12 -2
  281. package/src/gates/runner.ts +57 -0
  282. package/src/gates/security.ts +12 -2
  283. package/src/gates/types.ts +48 -1
  284. package/src/hooks/CONTEXT.md +12 -2
  285. package/src/hooks/__tests__/bootstrap.test.ts +0 -1
  286. package/src/hooks/__tests__/config.test.ts +19 -0
  287. package/src/hooks/__tests__/pipeline.test.ts +79 -0
  288. package/src/hooks/__tests__/registry.test.ts +67 -0
  289. package/src/hooks/bootstrap.ts +0 -2
  290. package/src/hooks/config.ts +29 -0
  291. package/src/hooks/index.ts +2 -1
  292. package/src/hooks/registry.ts +60 -1
  293. package/src/hooks/types.ts +21 -0
  294. package/src/index.ts +11 -21
  295. package/src/knowledge/import.ts +3 -3
  296. package/src/knowledge/ingest.ts +4 -4
  297. package/src/knowledge/lifecycle-hooks.ts +3 -3
  298. package/src/knowledge/types.ts +5 -8
  299. package/src/monitoring/constraint-doctor.ts +7 -106
  300. package/src/presets/__tests__/standard.test.ts +0 -2
  301. package/src/presets/standard.ts +1 -2
  302. package/src/pretool-use-hook.ts +68 -0
  303. package/src/spec/__tests__/annotation-checker.test.ts +9 -3
  304. package/src/spec/annotation-checker.ts +7 -29
  305. package/src/tools/CONTEXT.md +7 -14
  306. package/src/tools/index.ts +0 -4
  307. package/src/types/constraint.ts +1 -14
  308. package/src/types/project-config.ts +0 -3
  309. package/src/utils/file-walk.ts +2 -2
  310. package/dist/architecture/constraint-engine.d.ts +0 -67
  311. package/dist/architecture/constraint-engine.d.ts.map +0 -1
  312. package/dist/architecture/constraint-engine.js +0 -295
  313. package/dist/architecture/constraint-engine.js.map +0 -1
  314. package/dist/architecture/cross-project-checker.d.ts +0 -54
  315. package/dist/architecture/cross-project-checker.d.ts.map +0 -1
  316. package/dist/architecture/cross-project-checker.js +0 -467
  317. package/dist/architecture/cross-project-checker.js.map +0 -1
  318. package/dist/cli/commands/index.d.ts +0 -30
  319. package/dist/cli/commands/index.d.ts.map +0 -1
  320. package/dist/cli/commands/index.js +0 -91
  321. package/dist/cli/commands/index.js.map +0 -1
  322. package/dist/context/file-budget.d.ts +0 -40
  323. package/dist/context/file-budget.d.ts.map +0 -1
  324. package/dist/context/file-budget.js +0 -147
  325. package/dist/context/file-budget.js.map +0 -1
  326. package/dist/context/progressive-loader.d.ts +0 -109
  327. package/dist/context/progressive-loader.d.ts.map +0 -1
  328. package/dist/context/progressive-loader.js +0 -166
  329. package/dist/context/progressive-loader.js.map +0 -1
  330. package/dist/context/token-pipeline.d.ts +0 -55
  331. package/dist/context/token-pipeline.d.ts.map +0 -1
  332. package/dist/context/token-pipeline.js +0 -220
  333. package/dist/context/token-pipeline.js.map +0 -1
  334. package/dist/context/tool-output-budget.d.ts +0 -59
  335. package/dist/context/tool-output-budget.d.ts.map +0 -1
  336. package/dist/context/tool-output-budget.js +0 -177
  337. package/dist/context/tool-output-budget.js.map +0 -1
  338. package/dist/core/constraints/default-executors.d.ts +0 -10
  339. package/dist/core/constraints/default-executors.d.ts.map +0 -1
  340. package/dist/core/constraints/default-executors.js +0 -120
  341. package/dist/core/constraints/default-executors.js.map +0 -1
  342. package/dist/llm/adapter.d.ts +0 -36
  343. package/dist/llm/adapter.d.ts.map +0 -1
  344. package/dist/llm/adapter.js +0 -118
  345. package/dist/llm/adapter.js.map +0 -1
  346. package/dist/llm/index.d.ts +0 -3
  347. package/dist/llm/index.d.ts.map +0 -1
  348. package/dist/llm/index.js +0 -19
  349. package/dist/llm/index.js.map +0 -1
  350. package/dist/llm/types.d.ts +0 -62
  351. package/dist/llm/types.d.ts.map +0 -1
  352. package/dist/llm/types.js +0 -8
  353. package/dist/llm/types.js.map +0 -1
  354. package/dist/tools/core/index.d.ts +0 -13
  355. package/dist/tools/core/index.d.ts.map +0 -1
  356. package/dist/tools/core/index.js +0 -198
  357. package/dist/tools/core/index.js.map +0 -1
  358. package/dist/tools/loader.d.ts +0 -21
  359. package/dist/tools/loader.d.ts.map +0 -1
  360. package/dist/tools/loader.js +0 -199
  361. package/dist/tools/loader.js.map +0 -1
  362. package/dist/tools/registry.d.ts +0 -59
  363. package/dist/tools/registry.d.ts.map +0 -1
  364. package/dist/tools/registry.js +0 -115
  365. package/dist/tools/registry.js.map +0 -1
  366. package/dist/tools/types.d.ts +0 -38
  367. package/dist/tools/types.d.ts.map +0 -1
  368. package/dist/tools/types.js +0 -6
  369. package/dist/tools/types.js.map +0 -1
  370. package/src/__tests__/architecture-engine.test.ts +0 -619
  371. package/src/__tests__/context/progressive-loader.test.ts +0 -131
  372. package/src/__tests__/cross-project-checker.test.ts +0 -318
  373. package/src/architecture/CONTEXT.md +0 -22
  374. package/src/architecture/constraint-engine.ts +0 -351
  375. package/src/architecture/cross-project-checker.ts +0 -545
  376. package/src/cli/commands/index.ts +0 -30
  377. package/src/context/__tests__/file-budget.test.ts +0 -142
  378. package/src/context/__tests__/progressive-loader.test.ts +0 -264
  379. package/src/context/__tests__/token-pipeline.test.ts +0 -178
  380. package/src/context/__tests__/tool-output-budget.test.ts +0 -95
  381. package/src/context/file-budget.ts +0 -142
  382. package/src/context/progressive-loader.ts +0 -260
  383. package/src/context/token-pipeline.ts +0 -265
  384. package/src/context/tool-output-budget.ts +0 -178
  385. package/src/core/constraints/__tests__/default-executors.test.ts +0 -57
  386. package/src/core/constraints/default-executors.ts +0 -92
  387. package/src/llm/CONTEXT.md +0 -21
  388. package/src/llm/__tests__/adapter.test.ts +0 -172
  389. package/src/llm/adapter.ts +0 -149
  390. package/src/llm/index.ts +0 -2
  391. package/src/llm/types.ts +0 -81
  392. package/src/tools/__tests__/loader.test.ts +0 -252
  393. package/src/tools/__tests__/registry.test.ts +0 -157
  394. package/src/tools/core/__tests__/core.test.ts +0 -122
  395. package/src/tools/core/index.ts +0 -201
  396. package/src/tools/loader.ts +0 -216
  397. package/src/tools/registry.ts +0 -128
  398. package/src/tools/types.ts +0 -46
@@ -1,142 +0,0 @@
1
- /**
2
- * FileBudget 测试
3
- */
4
-
5
- import { FileBudget } from '../file-budget';
6
- import * as fs from 'fs';
7
-
8
- jest.mock('fs', () => ({
9
- statSync: jest.fn(),
10
- readFileSync: jest.fn(),
11
- }));
12
-
13
- const mockFs = fs as jest.Mocked<typeof fs>;
14
-
15
- describe('FileBudget', () => {
16
- beforeEach(() => {
17
- jest.clearAllMocks();
18
- });
19
-
20
- describe('checkFile', () => {
21
- it('应该允许小文件', () => {
22
- (mockFs.statSync as jest.Mock).mockReturnValue({ size: 1000 });
23
- const budget = new FileBudget();
24
- const result = budget.checkFile('/test/file.ts');
25
- expect(result.allowed).toBe(true);
26
- });
27
-
28
- it('应该拒绝超大文件', () => {
29
- (mockFs.statSync as jest.Mock).mockReturnValue({ size: 100000 });
30
- const budget = new FileBudget();
31
- const result = budget.checkFile('/test/large-file.ts');
32
- expect(result.allowed).toBe(false);
33
- expect(result.reason).toContain('超过限制');
34
- });
35
-
36
- it('应该处理文件不存在', () => {
37
- (mockFs.statSync as jest.Mock).mockImplementation(() => {
38
- throw new Error('ENOENT');
39
- });
40
- const budget = new FileBudget();
41
- const result = budget.checkFile('/test/missing.ts');
42
- expect(result.allowed).toBe(false);
43
- expect(result.reason).toContain('无法读取文件');
44
- });
45
- });
46
-
47
- describe('readWithBudget', () => {
48
- it('应该读取正常文件', () => {
49
- (mockFs.readFileSync as jest.Mock).mockReturnValue('line1\nline2\nline3');
50
- const budget = new FileBudget();
51
- const result = budget.readWithBudget('/test/file.ts');
52
- expect(result.content).toBe('line1\nline2\nline3');
53
- expect(result.truncated).toBe(false);
54
- expect(result.linesRead).toBe(3);
55
- });
56
-
57
- it('应该按行数截断', () => {
58
- const lines = Array.from({ length: 3000 }, (_, i) => `line${i}`);
59
- (mockFs.readFileSync as jest.Mock).mockReturnValue(lines.join('\n'));
60
- const budget = new FileBudget({ maxLines: 2000 });
61
- const result = budget.readWithBudget('/test/large.ts');
62
- expect(result.truncated).toBe(true);
63
- expect(result.linesRead).toBe(2000);
64
- expect(result.continuationHint).toContain('offset=2000');
65
- });
66
-
67
- it('应该按 token 数截断', () => {
68
- // 长内容超过 token 限制
69
- const longContent = 'a'.repeat(50000);
70
- (mockFs.readFileSync as jest.Mock).mockReturnValue(longContent);
71
- const budget = new FileBudget({ maxTokenEstimate: 100, maxLines: 10000, maxBytes: 100000 });
72
- const result = budget.readWithBudget('/test/long.ts');
73
- expect(result.truncated).toBe(true);
74
- });
75
-
76
- it('应该处理读取失败', () => {
77
- (mockFs.readFileSync as jest.Mock).mockImplementation(() => {
78
- throw new Error('EACCES');
79
- });
80
- const budget = new FileBudget();
81
- const result = budget.readWithBudget('/test/locked.ts');
82
- expect(result.content).toBe('');
83
- expect(result.continuationHint).toContain('无法读取文件');
84
- });
85
-
86
- it('应该支持自定义配置', () => {
87
- const lines = Array.from({ length: 100 }, (_, i) => `line${i}`);
88
- (mockFs.readFileSync as jest.Mock).mockReturnValue(lines.join('\n'));
89
- const budget = new FileBudget();
90
- const result = budget.readWithBudget('/test/file.ts', { maxLines: 50 });
91
- expect(result.truncated).toBe(true);
92
- expect(result.linesRead).toBe(50);
93
- });
94
-
95
- it('应该不生成 continuationHint 当配置关闭', () => {
96
- const lines = Array.from({ length: 3000 }, (_, i) => `line${i}`);
97
- (mockFs.readFileSync as jest.Mock).mockReturnValue(lines.join('\n'));
98
- const budget = new FileBudget({ continuationHint: false, maxLines: 2000 });
99
- const result = budget.readWithBudget('/test/large.ts');
100
- expect(result.truncated).toBe(true);
101
- expect(result.continuationHint).toBeUndefined();
102
- });
103
-
104
- it('should truncate by byte count', () => {
105
- const content = 'x'.repeat(20000);
106
- (mockFs.readFileSync as jest.Mock).mockReturnValue(content);
107
- const budget = new FileBudget({ maxBytes: 500, maxLines: 50000, maxTokenEstimate: 100000 });
108
- const result = budget.readWithBudget('/test/big-bytes.ts');
109
- expect(result.truncated).toBe(true);
110
- expect(result.content.length).toBeLessThan(20000);
111
- });
112
-
113
- it('should include continuation hint when byte truncated', () => {
114
- const content = 'y'.repeat(20000);
115
- (mockFs.readFileSync as jest.Mock).mockReturnValue(content);
116
- const budget = new FileBudget({
117
- maxBytes: 500,
118
- maxLines: 50000,
119
- maxTokenEstimate: 100000,
120
- continuationHint: true,
121
- });
122
- const result = budget.readWithBudget('/test/big-bytes-hint.ts');
123
- expect(result.truncated).toBe(true);
124
- expect(result.continuationHint).toContain('字节');
125
- });
126
- });
127
-
128
- describe('getConfig', () => {
129
- it('应该返回默认配置', () => {
130
- const budget = new FileBudget();
131
- const config = budget.getConfig();
132
- expect(config.maxLines).toBe(2000);
133
- expect(config.maxBytes).toBe(51200);
134
- });
135
-
136
- it('应该返回自定义配置', () => {
137
- const budget = new FileBudget({ maxLines: 1000 });
138
- const config = budget.getConfig();
139
- expect(config.maxLines).toBe(1000);
140
- });
141
- });
142
- });
@@ -1,264 +0,0 @@
1
- /**
2
- * ProgressiveLoader 测试
3
- */
4
-
5
- import { ProgressiveLoader, progressiveLoader } from '../progressive-loader';
6
-
7
- describe('ProgressiveLoader', () => {
8
- let loader: ProgressiveLoader;
9
-
10
- beforeEach(() => {
11
- loader = new ProgressiveLoader();
12
- });
13
-
14
- describe('loadInChunks()', () => {
15
- it('should load items in chunks', async () => {
16
- const items = Array.from({ length: 100 }, (_, i) => i);
17
- const chunks: any[] = [];
18
-
19
- await loader.loadInChunks(items, {
20
- chunkSize: 20,
21
- onChunk: (chunk) => { chunks.push(chunk); },
22
- });
23
-
24
- expect(chunks.length).toBe(5);
25
- expect(chunks[0].length).toBe(20);
26
- });
27
-
28
- it('should call progress callback', async () => {
29
- const items = Array.from({ length: 50 }, (_, i) => i);
30
- const progress: any[] = [];
31
-
32
- await loader.loadInChunks(items, {
33
- chunkSize: 10,
34
- onProgress: (loaded, total) => progress.push({ loaded, total }),
35
- });
36
-
37
- expect(progress.length).toBeGreaterThan(0);
38
- expect(progress[progress.length - 1].loaded).toBe(50);
39
- });
40
-
41
- it('should load in parallel when parallel=true', async () => {
42
- const items = Array.from({ length: 20 }, (_, i) => i);
43
- const chunks: any[] = [];
44
-
45
- await loader.loadInChunks(items, {
46
- chunkSize: 5,
47
- parallel: true,
48
- onChunk: (chunk) => { chunks.push(chunk); },
49
- });
50
-
51
- expect(chunks.length).toBe(4);
52
- });
53
-
54
- it('should handle delay', async () => {
55
- const items = Array.from({ length: 10 }, (_, i) => i);
56
-
57
- const start = Date.now();
58
- await loader.loadInChunks(items, {
59
- chunkSize: 2,
60
- delay: 10,
61
- });
62
-
63
- // Should have taken some time (at least 4 delays = 40ms)
64
- const elapsed = Date.now() - start;
65
- expect(elapsed).toBeGreaterThanOrEqual(30);
66
- });
67
-
68
- it('should handle empty items', async () => {
69
- await loader.loadInChunks([], {
70
- chunkSize: 10,
71
- });
72
- // Should complete without error
73
- });
74
-
75
- it('should handle items not divisible by chunkSize', async () => {
76
- const items = Array.from({ length: 25 }, (_, i) => i);
77
- const chunks: any[] = [];
78
-
79
- await loader.loadInChunks(items, {
80
- chunkSize: 10,
81
- onChunk: (chunk) => { chunks.push(chunk); },
82
- });
83
-
84
- expect(chunks.length).toBe(3);
85
- expect(chunks[2].length).toBe(5);
86
- });
87
- });
88
-
89
- describe('loadWithBudget()', () => {
90
- it('should load items within budget', async () => {
91
- const items = [
92
- { text: 'short' },
93
- { text: 'medium' },
94
- { text: 'long' },
95
- ];
96
-
97
- const result = await loader.loadWithBudget(items, {
98
- budget: 100,
99
- estimator: (item) => item.text.length,
100
- });
101
-
102
- expect(result.items.length).toBe(3);
103
- expect(result.tokensUsed).toBe(15);
104
- expect(result.truncated).toBe(false);
105
- });
106
-
107
- it('should truncate when budget exceeded', async () => {
108
- const items = [
109
- { text: 'a' },
110
- { text: 'b'.repeat(100) },
111
- { text: 'c'.repeat(100) },
112
- ];
113
-
114
- const result = await loader.loadWithBudget(items, {
115
- budget: 50,
116
- estimator: (item) => item.text.length,
117
- onBudgetExceeded: 'truncate',
118
- });
119
-
120
- expect(result.items.length).toBeLessThan(3);
121
- expect(result.truncated).toBe(true);
122
- });
123
-
124
- it('should throw error when onBudgetExceeded=error', async () => {
125
- const items = [
126
- { text: 'short' },
127
- { text: 'a'.repeat(200) },
128
- ];
129
-
130
- await expect(
131
- loader.loadWithBudget(items, {
132
- budget: 50,
133
- estimator: (item) => item.text.length,
134
- onBudgetExceeded: 'error',
135
- })
136
- ).rejects.toThrow('Token budget exceeded');
137
- });
138
-
139
- it('should skip items when onBudgetExceeded=skip', async () => {
140
- const items = [
141
- { text: 'short' },
142
- { text: 'verylong'.repeat(100) },
143
- { text: 'short2' },
144
- ];
145
-
146
- const result = await loader.loadWithBudget(items, {
147
- budget: 50,
148
- estimator: (item) => item.text.length,
149
- onBudgetExceeded: 'skip',
150
- });
151
-
152
- expect(result.skipped).toBeGreaterThan(0);
153
- });
154
-
155
- it('should respect minItems', async () => {
156
- const items = [
157
- { text: 'verylong'.repeat(100) },
158
- { text: 'verylong'.repeat(100) },
159
- ];
160
-
161
- const result = await loader.loadWithBudget(items, {
162
- budget: 10,
163
- estimator: (item) => item.text.length,
164
- minItems: 1,
165
- onBudgetExceeded: 'truncate',
166
- });
167
-
168
- expect(result.items.length).toBeGreaterThanOrEqual(1);
169
- });
170
-
171
- it('should handle empty items', async () => {
172
- const result = await loader.loadWithBudget([], {
173
- budget: 100,
174
- estimator: () => 0,
175
- });
176
-
177
- expect(result.items.length).toBe(0);
178
- expect(result.tokensUsed).toBe(0);
179
- });
180
- });
181
-
182
- describe('createStream()', () => {
183
- it('should create async iterator', async () => {
184
- const source = async function* () {
185
- yield 1;
186
- yield 2;
187
- yield 3;
188
- yield 4;
189
- yield 5;
190
- };
191
-
192
- const stream = loader.createStream(source(), 2);
193
- const chunks: any[] = [];
194
-
195
- for await (const chunk of stream) {
196
- chunks.push(chunk);
197
- }
198
-
199
- expect(chunks.length).toBe(3);
200
- expect(chunks[0]).toEqual([1, 2]);
201
- expect(chunks[2]).toEqual([5]);
202
- });
203
-
204
- it('should handle empty source', async () => {
205
- const source = async function* () {};
206
-
207
- const stream = loader.createStream(source(), 10);
208
- const chunks: any[] = [];
209
-
210
- for await (const chunk of stream) {
211
- chunks.push(chunk);
212
- }
213
-
214
- expect(chunks.length).toBe(0);
215
- });
216
- });
217
-
218
- describe('processBatch()', () => {
219
- it('should process items with concurrency', async () => {
220
- const items = [1, 2, 3, 4, 5];
221
- const processor = async (n: number) => n * 2;
222
-
223
- const results = await loader.processBatch(items, processor, 2);
224
-
225
- expect(results.length).toBe(5);
226
- expect(results).toContain(2);
227
- expect(results).toContain(10);
228
- });
229
-
230
- it('should handle empty items', async () => {
231
- const results = await loader.processBatch([], async (n) => n, 5);
232
- expect(results.length).toBe(0);
233
- });
234
-
235
- it('should handle async processor', async () => {
236
- const items = [1, 2, 3];
237
- const processed: number[] = [];
238
-
239
- const processor = async (n: number) => {
240
- processed.push(n);
241
- return n * 2;
242
- };
243
-
244
- await loader.processBatch(items, processor, 1);
245
-
246
- // Check that all items were processed
247
- expect(processed.sort()).toEqual([1, 2, 3]);
248
- });
249
- });
250
- });
251
-
252
- describe('progressiveLoader (default instance)', () => {
253
- it('should be usable', async () => {
254
- const items = [1, 2, 3];
255
- const chunks: any[] = [];
256
-
257
- await progressiveLoader.loadInChunks(items, {
258
- chunkSize: 1,
259
- onChunk: (chunk) => { chunks.push(chunk); return undefined; },
260
- });
261
-
262
- expect(chunks.length).toBe(3);
263
- });
264
- });
@@ -1,178 +0,0 @@
1
- /**
2
- * TokenPipeline 测试
3
- */
4
-
5
- import { TokenPipeline } from '../token-pipeline';
6
- import type { ContextSource, TokenBudgetAllocation } from '../types';
7
-
8
- const defaultBudget: TokenBudgetAllocation = {
9
- total: 8000,
10
- systemPrompt: 1000,
11
- toolDefinitions: 500,
12
- knowledge: 600,
13
- notes: 300,
14
- history: 5600,
15
- };
16
-
17
- function makeSource(overrides: Partial<ContextSource> & { priority: number }): ContextSource {
18
- return {
19
- type: 'user_message',
20
- id: `src-${Math.random().toString(36).slice(2, 8)}`,
21
- content: 'test content',
22
- ...overrides,
23
- };
24
- }
25
-
26
- describe('TokenPipeline', () => {
27
- let pipeline: TokenPipeline;
28
-
29
- beforeEach(() => {
30
- pipeline = new TokenPipeline();
31
- });
32
-
33
- describe('run', () => {
34
- it('应该执行完整流水线', () => {
35
- const input = {
36
- sources: [
37
- makeSource({ type: 'system_prompt', priority: 1, content: 'You are helpful.' }),
38
- makeSource({ type: 'user_message', priority: 6, content: 'Hello' }),
39
- ],
40
- budget: defaultBudget,
41
- };
42
-
43
- const result = pipeline.run(input);
44
- expect(result.prompt).toContain('You are helpful.');
45
- expect(result.prompt).toContain('Hello');
46
- expect(result.snapshot).toBeDefined();
47
- expect(result.snapshot.totalTokens).toBeGreaterThan(0);
48
- });
49
-
50
- it('应该把 P1 放在开头,P6 放在结尾', () => {
51
- const input = {
52
- sources: [
53
- makeSource({ type: 'user_message', priority: 6, content: 'USER_MSG' }),
54
- makeSource({ type: 'system_prompt', priority: 1, content: 'SYSTEM' }),
55
- makeSource({ type: 'knowledge', priority: 3, content: 'KNOWLEDGE' }),
56
- ],
57
- budget: defaultBudget,
58
- };
59
-
60
- const result = pipeline.run(input);
61
- const prompt = result.prompt;
62
- const sysIdx = prompt.indexOf('SYSTEM');
63
- const knowIdx = prompt.indexOf('KNOWLEDGE');
64
- const userIdx = prompt.indexOf('USER_MSG');
65
-
66
- expect(sysIdx).toBeLessThan(knowIdx);
67
- expect(knowIdx).toBeLessThan(userIdx);
68
- });
69
-
70
- it('应该生成 ContextUsageSnapshot', () => {
71
- const input = {
72
- sources: [
73
- makeSource({ type: 'system_prompt', priority: 1, content: 'system' }),
74
- makeSource({ type: 'tool_output', priority: 5, content: 'output' }),
75
- ],
76
- budget: defaultBudget,
77
- };
78
-
79
- const result = pipeline.run(input);
80
- expect(result.snapshot.breakdown.systemPrompt).toBeGreaterThan(0);
81
- expect(result.snapshot.timestamp).toBeDefined();
82
- });
83
- });
84
-
85
- describe('collect', () => {
86
- it('应该按 priority 分组', () => {
87
- const sources = [
88
- makeSource({ priority: 1, content: 'a' }),
89
- makeSource({ priority: 3, content: 'b' }),
90
- makeSource({ priority: 1, content: 'c' }),
91
- ];
92
-
93
- const groups = pipeline.collect(sources);
94
- expect(groups.length).toBe(2);
95
- expect(groups[0].priority).toBe(1);
96
- expect(groups[0].sources.length).toBe(2);
97
- expect(groups[1].priority).toBe(3);
98
- });
99
- });
100
-
101
- describe('sort', () => {
102
- it('应该按 priority 排序', () => {
103
- const groups = [
104
- { priority: 1, sources: [makeSource({ priority: 1, content: 'p1' })] },
105
- { priority: 3, sources: [makeSource({ priority: 3, content: 'p3' })] },
106
- ];
107
-
108
- const sorted = pipeline.sort(groups);
109
- expect(sorted[0].priority).toBe(1);
110
- expect(sorted[1].priority).toBe(3);
111
- });
112
- });
113
-
114
- describe('compress', () => {
115
- it('应该不压缩 P1 和 P6', () => {
116
- const sorted = [
117
- makeSource({ type: 'system_prompt', priority: 1, content: 'a'.repeat(5000) }),
118
- makeSource({ type: 'user_message', priority: 6, content: 'b'.repeat(5000) }),
119
- ];
120
-
121
- const { compressed } = pipeline.compress(sorted, defaultBudget);
122
- expect(compressed.length).toBe(2);
123
- });
124
-
125
- it('应该裁剪超出预算的 P3-P5', () => {
126
- const sorted = [
127
- makeSource({ priority: 3, content: 'x'.repeat(10000) }),
128
- makeSource({ priority: 3, content: 'y'.repeat(10000) }),
129
- ];
130
-
131
- const { compressed, dropped } = pipeline.compress(sorted, defaultBudget);
132
- // 预算不足时,部分项被截断,部分被丢弃
133
- expect(compressed.length).toBeLessThanOrEqual(2);
134
- expect(dropped.length).toBeGreaterThan(0);
135
- expect(compressed.length + dropped.filter(d => d.reason.includes('超出预算')).length).toBe(2);
136
- });
137
- });
138
-
139
- describe('applyBudget', () => {
140
- it('应该按总预算裁剪', () => {
141
- const compressed = [
142
- makeSource({ priority: 5, content: 'x'.repeat(50000) }),
143
- ];
144
-
145
- const result = pipeline.applyBudget(compressed, { ...defaultBudget, total: 100 });
146
- // 超预算的非 P1/P6 项应被丢弃
147
- expect(result.length).toBeLessThanOrEqual(1);
148
- });
149
-
150
- it('应该强制保留 P1', () => {
151
- const compressed = [
152
- makeSource({ type: 'system_prompt', priority: 1, content: 'x'.repeat(50000) }),
153
- ];
154
-
155
- const result = pipeline.applyBudget(compressed, { ...defaultBudget, total: 100 });
156
- expect(result.length).toBe(1);
157
- });
158
- });
159
-
160
- describe('assemble', () => {
161
- it('应该按优先级拼装', () => {
162
- const budgeted = [
163
- makeSource({ priority: 6, content: 'USER' }),
164
- makeSource({ priority: 1, content: 'SYS' }),
165
- makeSource({ priority: 3, content: 'KNOW' }),
166
- ];
167
-
168
- const prompt = pipeline.assemble(budgeted);
169
- expect(prompt.indexOf('SYS')).toBeLessThan(prompt.indexOf('KNOW'));
170
- expect(prompt.indexOf('KNOW')).toBeLessThan(prompt.indexOf('USER'));
171
- });
172
-
173
- it('应该处理空输入', () => {
174
- const prompt = pipeline.assemble([]);
175
- expect(prompt).toBe('');
176
- });
177
- });
178
- });
@@ -1,95 +0,0 @@
1
- /**
2
- * ToolOutputBudget 测试
3
- */
4
-
5
- import { ToolOutputBudget } from '../tool-output-budget';
6
-
7
- describe('ToolOutputBudget', () => {
8
- describe('checkOutput', () => {
9
- it('应该允许正常输出', () => {
10
- const budget = new ToolOutputBudget();
11
- const result = budget.checkOutput('short output');
12
- expect(result.allowed).toBe(true);
13
- expect(result.strategy).toBe('full');
14
- });
15
-
16
- it('应该标记超大输出为 preview', () => {
17
- const budget = new ToolOutputBudget();
18
- const largeOutput = 'x'.repeat(20000);
19
- const result = budget.checkOutput(largeOutput);
20
- expect(result.strategy).toBe('preview');
21
- expect(result.reason).toContain('超过限制');
22
- });
23
-
24
- it('应该标记超大输出为 overflow 当配置开启', () => {
25
- const budget = new ToolOutputBudget({ overflowToDisk: true });
26
- const largeOutput = 'x'.repeat(20000);
27
- const result = budget.checkOutput(largeOutput);
28
- expect(result.strategy).toBe('overflow');
29
- });
30
-
31
- it('应该标记重复输出为 dedup', () => {
32
- const budget = new ToolOutputBudget();
33
- budget.checkOutput('same content');
34
- const result = budget.checkOutput('same content');
35
- expect(result.strategy).toBe('dedup');
36
- });
37
-
38
- it('应该按 token 比例检查', () => {
39
- const budget = new ToolOutputBudget({ maxTokenRatio: 0.1 });
40
- // 约 2500 tokens (10000 chars / 4)
41
- const output = 'x'.repeat(10000);
42
- const result = budget.checkOutput(output, 10000);
43
- expect(result.strategy).toBe('preview');
44
- });
45
- });
46
-
47
- describe('applyBudget', () => {
48
- it('应该返回完整内容当策略为 full', () => {
49
- const budget = new ToolOutputBudget();
50
- const result = budget.applyBudget('hello world', 'full');
51
- expect(result.content).toBe('hello world');
52
- expect(result.keptTokens).toBe(result.originalTokens);
53
- });
54
-
55
- it('应该生成预览当策略为 preview', () => {
56
- const budget = new ToolOutputBudget({ previewLines: 3 });
57
- const lines = Array.from({ length: 100 }, (_, i) => `line ${i} with some extra content to make it longer`);
58
- const result = budget.applyBudget(lines.join('\n'), 'preview');
59
- expect(result.content).toContain('line 0');
60
- expect(result.content).toContain('省略');
61
- expect(result.keptTokens).toBeLessThan(result.originalTokens);
62
- });
63
-
64
- it('应该返回省略提示当策略为 dedup', () => {
65
- const budget = new ToolOutputBudget();
66
- const result = budget.applyBudget('duplicate content', 'dedup');
67
- expect(result.content).toContain('重复内容');
68
- });
69
-
70
- it('应该处理 overflow 策略', () => {
71
- const budget = new ToolOutputBudget({ previewLines: 2 });
72
- const content = Array.from({ length: 20 }, (_, i) => `line${i}`).join('\n');
73
- const result = budget.applyBudget(content, 'overflow');
74
- expect(result.content).toContain('输出已写入磁盘');
75
- expect(result.offloaded).toBeDefined();
76
- });
77
- });
78
-
79
- describe('clearDedupCache', () => {
80
- it('应该清除去重缓存', () => {
81
- const budget = new ToolOutputBudget();
82
- budget.checkOutput('content');
83
- budget.clearDedupCache();
84
- const result = budget.checkOutput('content');
85
- expect(result.strategy).toBe('full');
86
- });
87
- });
88
-
89
- describe('getConfig', () => {
90
- it('应该返回配置', () => {
91
- const budget = new ToolOutputBudget({ maxChars: 8000 });
92
- expect(budget.getConfig().maxChars).toBe(8000);
93
- });
94
- });
95
- });