@caupulican/pi-adaptative 0.80.86 → 0.80.89

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 (353) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/dist/core/agent-session.d.ts +412 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +2053 -41
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/autonomy/approval-gate.d.ts +4 -0
  7. package/dist/core/autonomy/approval-gate.d.ts.map +1 -0
  8. package/dist/core/autonomy/approval-gate.js +27 -0
  9. package/dist/core/autonomy/approval-gate.js.map +1 -0
  10. package/dist/core/autonomy/bounded-completion.d.ts +27 -0
  11. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -0
  12. package/dist/core/autonomy/bounded-completion.js +44 -0
  13. package/dist/core/autonomy/bounded-completion.js.map +1 -0
  14. package/dist/core/autonomy/contracts.d.ts +129 -0
  15. package/dist/core/autonomy/contracts.d.ts.map +1 -0
  16. package/dist/core/autonomy/contracts.js +2 -0
  17. package/dist/core/autonomy/contracts.js.map +1 -0
  18. package/dist/core/autonomy/gates.d.ts +15 -0
  19. package/dist/core/autonomy/gates.d.ts.map +1 -0
  20. package/dist/core/autonomy/gates.js +205 -0
  21. package/dist/core/autonomy/gates.js.map +1 -0
  22. package/dist/core/autonomy/lane-tracker.d.ts +48 -0
  23. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -0
  24. package/dist/core/autonomy/lane-tracker.js +125 -0
  25. package/dist/core/autonomy/lane-tracker.js.map +1 -0
  26. package/dist/core/autonomy/path-scope.d.ts +9 -0
  27. package/dist/core/autonomy/path-scope.d.ts.map +1 -0
  28. package/dist/core/autonomy/path-scope.js +122 -0
  29. package/dist/core/autonomy/path-scope.js.map +1 -0
  30. package/dist/core/autonomy/risk-assessment.d.ts +3 -0
  31. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -0
  32. package/dist/core/autonomy/risk-assessment.js +122 -0
  33. package/dist/core/autonomy/risk-assessment.js.map +1 -0
  34. package/dist/core/autonomy/session-lane-record.d.ts +10 -0
  35. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -0
  36. package/dist/core/autonomy/session-lane-record.js +36 -0
  37. package/dist/core/autonomy/session-lane-record.js.map +1 -0
  38. package/dist/core/autonomy/status.d.ts +40 -0
  39. package/dist/core/autonomy/status.d.ts.map +1 -0
  40. package/dist/core/autonomy/status.js +107 -0
  41. package/dist/core/autonomy/status.js.map +1 -0
  42. package/dist/core/autonomy/subagent-prompt.d.ts +21 -0
  43. package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -0
  44. package/dist/core/autonomy/subagent-prompt.js +28 -0
  45. package/dist/core/autonomy/subagent-prompt.js.map +1 -0
  46. package/dist/core/autonomy/telemetry-events.d.ts +18 -0
  47. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -0
  48. package/dist/core/autonomy/telemetry-events.js +60 -0
  49. package/dist/core/autonomy/telemetry-events.js.map +1 -0
  50. package/dist/core/context/artifact-retrieval.d.ts +49 -0
  51. package/dist/core/context/artifact-retrieval.d.ts.map +1 -0
  52. package/dist/core/context/artifact-retrieval.js +49 -0
  53. package/dist/core/context/artifact-retrieval.js.map +1 -0
  54. package/dist/core/context/brain-curator.d.ts +88 -0
  55. package/dist/core/context/brain-curator.d.ts.map +1 -0
  56. package/dist/core/context/brain-curator.js +192 -0
  57. package/dist/core/context/brain-curator.js.map +1 -0
  58. package/dist/core/context/context-artifacts.d.ts +94 -0
  59. package/dist/core/context/context-artifacts.d.ts.map +1 -0
  60. package/dist/core/context/context-artifacts.js +307 -0
  61. package/dist/core/context/context-artifacts.js.map +1 -0
  62. package/dist/core/context/context-audit.d.ts +66 -0
  63. package/dist/core/context/context-audit.d.ts.map +1 -0
  64. package/dist/core/context/context-audit.js +173 -0
  65. package/dist/core/context/context-audit.js.map +1 -0
  66. package/dist/core/context/context-composition.d.ts +122 -0
  67. package/dist/core/context/context-composition.d.ts.map +1 -0
  68. package/dist/core/context/context-composition.js +163 -0
  69. package/dist/core/context/context-composition.js.map +1 -0
  70. package/dist/core/context/context-item.d.ts +117 -0
  71. package/dist/core/context/context-item.d.ts.map +1 -0
  72. package/dist/core/context/context-item.js +36 -0
  73. package/dist/core/context/context-item.js.map +1 -0
  74. package/dist/core/context/context-prompt-enforcement.d.ts +86 -0
  75. package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -0
  76. package/dist/core/context/context-prompt-enforcement.js +168 -0
  77. package/dist/core/context/context-prompt-enforcement.js.map +1 -0
  78. package/dist/core/context/context-prompt-policy.d.ts +90 -0
  79. package/dist/core/context/context-prompt-policy.d.ts.map +1 -0
  80. package/dist/core/context/context-prompt-policy.js +73 -0
  81. package/dist/core/context/context-prompt-policy.js.map +1 -0
  82. package/dist/core/context/context-retention.d.ts +36 -0
  83. package/dist/core/context/context-retention.d.ts.map +1 -0
  84. package/dist/core/context/context-retention.js +108 -0
  85. package/dist/core/context/context-retention.js.map +1 -0
  86. package/dist/core/context/context-store.d.ts +37 -0
  87. package/dist/core/context/context-store.d.ts.map +1 -0
  88. package/dist/core/context/context-store.js +45 -0
  89. package/dist/core/context/context-store.js.map +1 -0
  90. package/dist/core/context/memory-diagnostics.d.ts +50 -0
  91. package/dist/core/context/memory-diagnostics.d.ts.map +1 -0
  92. package/dist/core/context/memory-diagnostics.js +43 -0
  93. package/dist/core/context/memory-diagnostics.js.map +1 -0
  94. package/dist/core/context/memory-index-store.d.ts +28 -0
  95. package/dist/core/context/memory-index-store.d.ts.map +1 -0
  96. package/dist/core/context/memory-index-store.js +38 -0
  97. package/dist/core/context/memory-index-store.js.map +1 -0
  98. package/dist/core/context/memory-prompt-block.d.ts +34 -0
  99. package/dist/core/context/memory-prompt-block.d.ts.map +1 -0
  100. package/dist/core/context/memory-prompt-block.js +58 -0
  101. package/dist/core/context/memory-prompt-block.js.map +1 -0
  102. package/dist/core/context/memory-provider-contract.d.ts +114 -0
  103. package/dist/core/context/memory-provider-contract.d.ts.map +1 -0
  104. package/dist/core/context/memory-provider-contract.js +121 -0
  105. package/dist/core/context/memory-provider-contract.js.map +1 -0
  106. package/dist/core/context/memory-retrieval.d.ts +27 -0
  107. package/dist/core/context/memory-retrieval.d.ts.map +1 -0
  108. package/dist/core/context/memory-retrieval.js +91 -0
  109. package/dist/core/context/memory-retrieval.js.map +1 -0
  110. package/dist/core/context/okf-memory-provider.d.ts +26 -0
  111. package/dist/core/context/okf-memory-provider.d.ts.map +1 -0
  112. package/dist/core/context/okf-memory-provider.js +154 -0
  113. package/dist/core/context/okf-memory-provider.js.map +1 -0
  114. package/dist/core/context/okf-memory.d.ts +42 -0
  115. package/dist/core/context/okf-memory.d.ts.map +1 -0
  116. package/dist/core/context/okf-memory.js +175 -0
  117. package/dist/core/context/okf-memory.js.map +1 -0
  118. package/dist/core/context/policy-engine.d.ts +66 -0
  119. package/dist/core/context/policy-engine.d.ts.map +1 -0
  120. package/dist/core/context/policy-engine.js +171 -0
  121. package/dist/core/context/policy-engine.js.map +1 -0
  122. package/dist/core/context/policy-types.d.ts +102 -0
  123. package/dist/core/context/policy-types.d.ts.map +1 -0
  124. package/dist/core/context/policy-types.js +7 -0
  125. package/dist/core/context/policy-types.js.map +1 -0
  126. package/dist/core/context/sqlite-runtime-index.d.ts +19 -0
  127. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -0
  128. package/dist/core/context/sqlite-runtime-index.js +344 -0
  129. package/dist/core/context/sqlite-runtime-index.js.map +1 -0
  130. package/dist/core/context/storage-authority.d.ts +20 -0
  131. package/dist/core/context/storage-authority.d.ts.map +1 -0
  132. package/dist/core/context/storage-authority.js +51 -0
  133. package/dist/core/context/storage-authority.js.map +1 -0
  134. package/dist/core/context/tool-output-packer.d.ts +75 -0
  135. package/dist/core/context/tool-output-packer.d.ts.map +1 -0
  136. package/dist/core/context/tool-output-packer.js +77 -0
  137. package/dist/core/context/tool-output-packer.js.map +1 -0
  138. package/dist/core/context-gc.d.ts +13 -0
  139. package/dist/core/context-gc.d.ts.map +1 -1
  140. package/dist/core/context-gc.js +6 -0
  141. package/dist/core/context-gc.js.map +1 -1
  142. package/dist/core/cost/session-usage.d.ts +20 -0
  143. package/dist/core/cost/session-usage.d.ts.map +1 -0
  144. package/dist/core/cost/session-usage.js +164 -0
  145. package/dist/core/cost/session-usage.js.map +1 -0
  146. package/dist/core/delegation/session-worker-result.d.ts +10 -0
  147. package/dist/core/delegation/session-worker-result.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-result.js +36 -0
  149. package/dist/core/delegation/session-worker-result.js.map +1 -0
  150. package/dist/core/delegation/worker-result.d.ts +9 -0
  151. package/dist/core/delegation/worker-result.d.ts.map +1 -0
  152. package/dist/core/delegation/worker-result.js +152 -0
  153. package/dist/core/delegation/worker-result.js.map +1 -0
  154. package/dist/core/delegation/worker-runner.d.ts +58 -0
  155. package/dist/core/delegation/worker-runner.d.ts.map +1 -0
  156. package/dist/core/delegation/worker-runner.js +188 -0
  157. package/dist/core/delegation/worker-runner.js.map +1 -0
  158. package/dist/core/extensions/builtin.d.ts +5 -1
  159. package/dist/core/extensions/builtin.d.ts.map +1 -1
  160. package/dist/core/extensions/builtin.js +23 -1
  161. package/dist/core/extensions/builtin.js.map +1 -1
  162. package/dist/core/footer-data-provider.d.ts +5 -1
  163. package/dist/core/footer-data-provider.d.ts.map +1 -1
  164. package/dist/core/footer-data-provider.js +13 -0
  165. package/dist/core/footer-data-provider.js.map +1 -1
  166. package/dist/core/goals/goal-continuation-controller.d.ts +22 -0
  167. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -0
  168. package/dist/core/goals/goal-continuation-controller.js +88 -0
  169. package/dist/core/goals/goal-continuation-controller.js.map +1 -0
  170. package/dist/core/goals/goal-continuation-defaults.d.ts +10 -0
  171. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -0
  172. package/dist/core/goals/goal-continuation-defaults.js +10 -0
  173. package/dist/core/goals/goal-continuation-defaults.js.map +1 -0
  174. package/dist/core/goals/goal-continuation-prompt.d.ts +18 -0
  175. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -0
  176. package/dist/core/goals/goal-continuation-prompt.js +141 -0
  177. package/dist/core/goals/goal-continuation-prompt.js.map +1 -0
  178. package/dist/core/goals/goal-runtime-snapshot.d.ts +19 -0
  179. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -0
  180. package/dist/core/goals/goal-runtime-snapshot.js +23 -0
  181. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -0
  182. package/dist/core/goals/goal-state.d.ts +87 -0
  183. package/dist/core/goals/goal-state.d.ts.map +1 -0
  184. package/dist/core/goals/goal-state.js +259 -0
  185. package/dist/core/goals/goal-state.js.map +1 -0
  186. package/dist/core/goals/goal-tool-core.d.ts +66 -0
  187. package/dist/core/goals/goal-tool-core.d.ts.map +1 -0
  188. package/dist/core/goals/goal-tool-core.js +146 -0
  189. package/dist/core/goals/goal-tool-core.js.map +1 -0
  190. package/dist/core/goals/session-goal-state.d.ts +10 -0
  191. package/dist/core/goals/session-goal-state.d.ts.map +1 -0
  192. package/dist/core/goals/session-goal-state.js +35 -0
  193. package/dist/core/goals/session-goal-state.js.map +1 -0
  194. package/dist/core/learning/learning-audit.d.ts +45 -0
  195. package/dist/core/learning/learning-audit.d.ts.map +1 -0
  196. package/dist/core/learning/learning-audit.js +139 -0
  197. package/dist/core/learning/learning-audit.js.map +1 -0
  198. package/dist/core/learning/learning-gate.d.ts +29 -0
  199. package/dist/core/learning/learning-gate.d.ts.map +1 -0
  200. package/dist/core/learning/learning-gate.js +150 -0
  201. package/dist/core/learning/learning-gate.js.map +1 -0
  202. package/dist/core/learning/session-learning-decision.d.ts +10 -0
  203. package/dist/core/learning/session-learning-decision.d.ts.map +1 -0
  204. package/dist/core/learning/session-learning-decision.js +36 -0
  205. package/dist/core/learning/session-learning-decision.js.map +1 -0
  206. package/dist/core/model-capability.d.ts +41 -0
  207. package/dist/core/model-capability.d.ts.map +1 -0
  208. package/dist/core/model-capability.js +101 -0
  209. package/dist/core/model-capability.js.map +1 -0
  210. package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
  211. package/dist/core/model-router/config-diagnostics.js +1 -0
  212. package/dist/core/model-router/config-diagnostics.js.map +1 -1
  213. package/dist/core/model-router/intent-classifier.d.ts +2 -0
  214. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  215. package/dist/core/model-router/intent-classifier.js +154 -9
  216. package/dist/core/model-router/intent-classifier.js.map +1 -1
  217. package/dist/core/model-router/route-judge.d.ts +54 -0
  218. package/dist/core/model-router/route-judge.d.ts.map +1 -0
  219. package/dist/core/model-router/route-judge.js +128 -0
  220. package/dist/core/model-router/route-judge.js.map +1 -0
  221. package/dist/core/model-router/status.d.ts +4 -1
  222. package/dist/core/model-router/status.d.ts.map +1 -1
  223. package/dist/core/model-router/status.js +30 -6
  224. package/dist/core/model-router/status.js.map +1 -1
  225. package/dist/core/model-router/tool-escalation.d.ts +4 -6
  226. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  227. package/dist/core/model-router/tool-escalation.js +1 -1
  228. package/dist/core/model-router/tool-escalation.js.map +1 -1
  229. package/dist/core/models/fitness-store.d.ts +40 -0
  230. package/dist/core/models/fitness-store.d.ts.map +1 -0
  231. package/dist/core/models/fitness-store.js +61 -0
  232. package/dist/core/models/fitness-store.js.map +1 -0
  233. package/dist/core/profile-registry.d.ts.map +1 -1
  234. package/dist/core/profile-registry.js +1 -1
  235. package/dist/core/profile-registry.js.map +1 -1
  236. package/dist/core/prompt-templates.d.ts +2 -0
  237. package/dist/core/prompt-templates.d.ts.map +1 -1
  238. package/dist/core/prompt-templates.js +12 -4
  239. package/dist/core/prompt-templates.js.map +1 -1
  240. package/dist/core/research/automata-provider.d.ts +5 -0
  241. package/dist/core/research/automata-provider.d.ts.map +1 -0
  242. package/dist/core/research/automata-provider.js +15 -0
  243. package/dist/core/research/automata-provider.js.map +1 -0
  244. package/dist/core/research/evidence-bundle.d.ts +10 -0
  245. package/dist/core/research/evidence-bundle.d.ts.map +1 -0
  246. package/dist/core/research/evidence-bundle.js +116 -0
  247. package/dist/core/research/evidence-bundle.js.map +1 -0
  248. package/dist/core/research/model-fitness.d.ts +82 -0
  249. package/dist/core/research/model-fitness.d.ts.map +1 -0
  250. package/dist/core/research/model-fitness.js +308 -0
  251. package/dist/core/research/model-fitness.js.map +1 -0
  252. package/dist/core/research/research-gate.d.ts +11 -0
  253. package/dist/core/research/research-gate.d.ts.map +1 -0
  254. package/dist/core/research/research-gate.js +82 -0
  255. package/dist/core/research/research-gate.js.map +1 -0
  256. package/dist/core/research/research-runner.d.ts +59 -0
  257. package/dist/core/research/research-runner.d.ts.map +1 -0
  258. package/dist/core/research/research-runner.js +155 -0
  259. package/dist/core/research/research-runner.js.map +1 -0
  260. package/dist/core/research/session-evidence-bundle.d.ts +11 -0
  261. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -0
  262. package/dist/core/research/session-evidence-bundle.js +55 -0
  263. package/dist/core/research/session-evidence-bundle.js.map +1 -0
  264. package/dist/core/resource-loader.d.ts.map +1 -1
  265. package/dist/core/resource-loader.js +4 -0
  266. package/dist/core/resource-loader.js.map +1 -1
  267. package/dist/core/settings-manager.d.ts +160 -4
  268. package/dist/core/settings-manager.d.ts.map +1 -1
  269. package/dist/core/settings-manager.js +304 -9
  270. package/dist/core/settings-manager.js.map +1 -1
  271. package/dist/core/skills.d.ts +4 -0
  272. package/dist/core/skills.d.ts.map +1 -1
  273. package/dist/core/skills.js +18 -6
  274. package/dist/core/skills.js.map +1 -1
  275. package/dist/core/slash-commands.d.ts.map +1 -1
  276. package/dist/core/slash-commands.js +10 -1
  277. package/dist/core/slash-commands.js.map +1 -1
  278. package/dist/core/toolkit/script-registry.d.ts +34 -0
  279. package/dist/core/toolkit/script-registry.d.ts.map +1 -0
  280. package/dist/core/toolkit/script-registry.js +71 -0
  281. package/dist/core/toolkit/script-registry.js.map +1 -0
  282. package/dist/core/toolkit/script-runner.d.ts +28 -0
  283. package/dist/core/toolkit/script-runner.d.ts.map +1 -0
  284. package/dist/core/toolkit/script-runner.js +48 -0
  285. package/dist/core/toolkit/script-runner.js.map +1 -0
  286. package/dist/core/tools/artifact-retrieve.d.ts +23 -0
  287. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -0
  288. package/dist/core/tools/artifact-retrieve.js +110 -0
  289. package/dist/core/tools/artifact-retrieve.js.map +1 -0
  290. package/dist/core/tools/delegate.d.ts +32 -0
  291. package/dist/core/tools/delegate.d.ts.map +1 -0
  292. package/dist/core/tools/delegate.js +60 -0
  293. package/dist/core/tools/delegate.js.map +1 -0
  294. package/dist/core/tools/fff-search-backend.d.ts +103 -0
  295. package/dist/core/tools/fff-search-backend.d.ts.map +1 -0
  296. package/dist/core/tools/fff-search-backend.js +151 -0
  297. package/dist/core/tools/fff-search-backend.js.map +1 -0
  298. package/dist/core/tools/find.d.ts +21 -1
  299. package/dist/core/tools/find.d.ts.map +1 -1
  300. package/dist/core/tools/find.js +183 -10
  301. package/dist/core/tools/find.js.map +1 -1
  302. package/dist/core/tools/goal.d.ts +35 -0
  303. package/dist/core/tools/goal.d.ts.map +1 -0
  304. package/dist/core/tools/goal.js +122 -0
  305. package/dist/core/tools/goal.js.map +1 -0
  306. package/dist/core/tools/grep.d.ts +21 -1
  307. package/dist/core/tools/grep.d.ts.map +1 -1
  308. package/dist/core/tools/grep.js +272 -27
  309. package/dist/core/tools/grep.js.map +1 -1
  310. package/dist/core/tools/index.d.ts +4 -1
  311. package/dist/core/tools/index.d.ts.map +1 -1
  312. package/dist/core/tools/index.js +9 -0
  313. package/dist/core/tools/index.js.map +1 -1
  314. package/dist/core/tools/model-fitness.d.ts +30 -0
  315. package/dist/core/tools/model-fitness.d.ts.map +1 -0
  316. package/dist/core/tools/model-fitness.js +38 -0
  317. package/dist/core/tools/model-fitness.js.map +1 -0
  318. package/dist/core/tools/run-toolkit-script.d.ts +24 -0
  319. package/dist/core/tools/run-toolkit-script.d.ts.map +1 -0
  320. package/dist/core/tools/run-toolkit-script.js +103 -0
  321. package/dist/core/tools/run-toolkit-script.js.map +1 -0
  322. package/dist/core/tools/search-router.d.ts +75 -0
  323. package/dist/core/tools/search-router.d.ts.map +1 -0
  324. package/dist/core/tools/search-router.js +85 -0
  325. package/dist/core/tools/search-router.js.map +1 -0
  326. package/dist/modes/interactive/components/fitness-role-selector.d.ts +13 -0
  327. package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -0
  328. package/dist/modes/interactive/components/fitness-role-selector.js +65 -0
  329. package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -0
  330. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/footer.js +18 -16
  332. package/dist/modes/interactive/components/footer.js.map +1 -1
  333. package/dist/modes/interactive/components/settings-selector.d.ts +16 -1
  334. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/settings-selector.js +555 -11
  336. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  337. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  338. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  339. package/dist/modes/interactive/interactive-mode.js +308 -39
  340. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  341. package/dist/utils/tools-manager.d.ts +2 -0
  342. package/dist/utils/tools-manager.d.ts.map +1 -1
  343. package/dist/utils/tools-manager.js +154 -2
  344. package/dist/utils/tools-manager.js.map +1 -1
  345. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  346. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  347. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  348. package/examples/extensions/sandbox/package-lock.json +2 -2
  349. package/examples/extensions/sandbox/package.json +1 -1
  350. package/examples/extensions/with-deps/package-lock.json +2 -2
  351. package/examples/extensions/with-deps/package.json +1 -1
  352. package/npm-shrinkwrap.json +368 -12
  353. package/package.json +5 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-audit.js","sourceRoot":"","sources":["../../../src/core/context/context-audit.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Live observe-only bridge from AgentMessage[] to the ContextItem/policy-engine layer\n * (Phase 1 audit pass). This module only ever reads messages and the artifact store; it\n * never mutates messages, the transcript, or artifact references. It is the first thing to\n * consume the context-item.ts/context-retention.ts/policy-engine.ts contracts against live\n * session state, but it does not yet change what the model sees -- see\n * docs/context-management-rework/implementation-phases.md for where this sits.\n *\n * Scope for this pass: only `toolResult` messages become `ContextItem`s (kind\n * \"tool_output\"). Other roles (user/assistant) are skipped; representing them is later\n * work once their ContextItemKind mapping (user_instruction/approval/etc.) is designed.\n *\n * Retrieval-path semantics (deliberately narrower than context-retention.ts's item-level\n * `hasReferencedEvidence`): a transcript ref is attached to every item as provenance\n * evidence (which live message this item came from), but it never counts toward\n * `HardConstraintFlags.hasAvailableRetrievalPath` on its own -- there is no live mechanism\n * today for the model to fetch an older message back into context by session-entry id, so\n * claiming that would overclaim retrievability (the same fail-closed principle\n * `artifact_retrieve` follows). Only a resolved artifact ref (the store still has the\n * payload) counts as an available retrieval path.\n */\n\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { ToolResultMessage } from \"@caupulican/pi-ai\";\nimport type { ArtifactStore } from \"./context-artifacts.ts\";\nimport {\n\ttype ContextEvidenceRef,\n\ttype ContextItem,\n\testimateByteLength,\n\testimateTokensFromText,\n} from \"./context-item.ts\";\nimport { evaluateRetentionEligibility, type RetentionEligibility } from \"./context-retention.ts\";\nimport { evaluateHardConstraints } from \"./policy-engine.ts\";\nimport type { HardConstraintFlags, PolicyFeatures, PolicyHardConstraintCode } from \"./policy-types.ts\";\n\nexport interface ContextAuditOptions {\n\t/** Current turn index (AgentSession's own per-run counter); used as `createdAtTurn`. */\n\tturnIndex: number;\n\t/** Session-scoped artifact store, if one has been constructed. Read-only here. */\n\tartifactStore?: ArtifactStore;\n\t/** Resolve the persisted session-entry id for a toolResult message's toolCallId, if known. */\n\tsessionEntryIdForToolCallId?: (toolCallId: string) => string | undefined;\n}\n\nexport interface ContextAuditItemReport {\n\titem: ContextItem;\n\t/** The source toolResult message's own id and position, always available (unlike refs). */\n\ttoolCallId: string;\n\tmessageIndex: number;\n\t/** Coarse, store-free eligibility from context-retention.ts (treats any ref as retrievable). */\n\tretention: RetentionEligibility;\n\t/** Store-aware hard-constraint codes for keep_raw; always empty (no evaluated action restricts it), included for reportability. */\n\tkeepRawHardConstraints: PolicyHardConstraintCode[];\n\t/** Store-aware hard-constraint codes for pack_to_artifact; empty means no hard rejection. */\n\tpackToArtifactHardConstraints: PolicyHardConstraintCode[];\n\t/** Store-aware hard-constraint codes for drop_from_prompt; empty means no hard rejection. */\n\tdropFromPromptHardConstraints: PolicyHardConstraintCode[];\n\t/** Store-aware hard-constraint codes for summarize; empty means no hard rejection. */\n\tsummarizeHardConstraints: PolicyHardConstraintCode[];\n}\n\nexport interface ContextAuditReport {\n\tturnIndex: number;\n\titems: ContextAuditItemReport[];\n}\n\nfunction extractToolResultArtifactId(message: ToolResultMessage): string | undefined {\n\tconst details = message.details;\n\tif (typeof details !== \"object\" || details === null) return undefined;\n\tconst artifactId = (details as { artifactId?: unknown }).artifactId;\n\treturn typeof artifactId === \"string\" ? artifactId : undefined;\n}\n\nfunction toolResultText(message: ToolResultMessage): string {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\") parts.push(part.text);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\ninterface BuiltToolOutputItem {\n\titem: ContextItem;\n\t/** True only if an artifact ref was found AND resolved against a live store. */\n\thasResolvedArtifact: boolean;\n}\n\nfunction buildToolOutputItem(\n\tmessage: ToolResultMessage,\n\tmessageIndex: number,\n\toptions: ContextAuditOptions,\n): BuiltToolOutputItem {\n\tconst text = toolResultText(message);\n\tconst artifactId = extractToolResultArtifactId(message);\n\tconst sessionEntryId = options.sessionEntryIdForToolCallId?.(message.toolCallId);\n\n\tlet primaryRef: ContextEvidenceRef | undefined;\n\tlet hasResolvedArtifact = false;\n\t// createdAtTurn defaults to the current audit turn (an approximation -- see below) and\n\t// is overridden with the real capture turn when an artifact ref resolves.\n\tlet createdAtTurn = options.turnIndex;\n\tif (artifactId && options.artifactStore) {\n\t\t// Metadata-only: never loads the artifact's payload just to check resolvability and\n\t\t// grab ref fields (a per-turn audit pass over every artifact-backed result would\n\t\t// otherwise re-read every payload off disk each turn for no reason).\n\t\tconst ref = options.artifactStore.readRef(artifactId);\n\t\tif (ref) {\n\t\t\tprimaryRef = { type: \"artifact\", ref };\n\t\t\thasResolvedArtifact = true;\n\t\t\tcreatedAtTurn = ref.createdAtTurn;\n\t\t}\n\t}\n\n\tconst evidenceRefs: ContextEvidenceRef[] = [];\n\tif (sessionEntryId) {\n\t\tconst transcriptRef: ContextEvidenceRef = {\n\t\t\ttype: \"transcript\",\n\t\t\tref: { sessionEntryId, messageIndex },\n\t\t};\n\t\tif (!primaryRef) primaryRef = transcriptRef;\n\t\telse evidenceRefs.push(transcriptRef);\n\t}\n\n\tconst item: ContextItem = {\n\t\tid: `tool-output:${message.toolCallId}`,\n\t\tkind: \"tool_output\",\n\t\tretentionClass: \"ephemeral\",\n\t\tsource: \"tool\",\n\t\t// Transcript-only items (no artifact ref) have no real creation-turn source threaded\n\t\t// in yet, so this falls back to the current audit turn as an approximation --\n\t\t// deliberately not left silently wrong: no evaluator reads createdAtTurn today, but\n\t\t// any future staleness/break-even math must use the real per-item value above, not\n\t\t// this fallback, once one exists for non-artifact items too.\n\t\tcreatedAtTurn,\n\t\tsummary: `${message.toolName} tool result`,\n\t\tprimaryRef,\n\t\tevidenceRefs: evidenceRefs.length > 0 ? evidenceRefs : undefined,\n\t\ttokenEstimate: estimateTokensFromText(text),\n\t\tbyteEstimate: estimateByteLength(text),\n\t};\n\n\treturn { item, hasResolvedArtifact };\n}\n\n/**\n * Economic/probability fields are zeroed: `evaluateHardConstraints` does not read them for\n * pack_to_artifact/drop_from_prompt (only the break-even scoring math this audit\n * deliberately does not invoke would need real numbers here).\n */\nfunction buildPolicyFeatures(item: ContextItem, built: BuiltToolOutputItem, turnIndex: number): PolicyFeatures {\n\treturn {\n\t\tturnIndex,\n\t\texpectedRemainingTurns: 0,\n\t\tinputTokens: 0,\n\t\toutputTokens: 0,\n\t\tcacheReadTokens: 0,\n\t\tcacheWriteTokens: 0,\n\t\tartifactBytes: built.hasResolvedArtifact ? item.byteEstimate : 0,\n\t\tcharEstimate: item.byteEstimate,\n\t\tcalibratedTokenEstimate: item.tokenEstimate,\n\t\tpromptSection: \"volatile_tail\",\n\t\tretentionClass: item.retentionClass,\n\t\tisReproducible: true,\n\t\tisDecisionBearing: false,\n\t\tisPinned: false,\n\t\tisOpenRequirement: false,\n\t\tisLatestFailure: false,\n\t\tisCurrentDiff: false,\n\t\tprobabilityNeededAgain: 0,\n\t\tprobabilityErrorIfDropped: 0,\n\t\tretrievalCostTokens: 0,\n\t\tpackCostTokens: 0,\n\t\tretryCostTokens: 0,\n\t\tfailureCostTokens: 0,\n\t\tvalidationCostTokens: 0,\n\t};\n}\n\nfunction buildHardConstraintFlags(built: BuiltToolOutputItem, artifactStoreAvailable: boolean): HardConstraintFlags {\n\treturn {\n\t\tisApprovalOrDenial: false,\n\t\tisSafetyConstraint: false,\n\t\tisActiveBlocker: false,\n\t\tisCurrentValidationResult: false,\n\t\tisPathOrToolScope: false,\n\t\t// Only a resolved artifact counts; a transcript ref is provenance, not a live\n\t\t// retrieval mechanism -- see the module doc comment.\n\t\thasAvailableRetrievalPath: built.hasResolvedArtifact,\n\t\tartifactStoreAvailable,\n\t\thasEvidenceRefForSummary: built.item.primaryRef !== undefined || (built.item.evidenceRefs?.length ?? 0) > 0,\n\t\tpathOrToolBoundariesEnforced: true,\n\t\tvalidationAvailableAndStrong: false,\n\t\tpriorAttemptFailedForReasoningOrArchitecture: false,\n\t\tisHighImpactOrBroadMultiFileEdit: false,\n\t};\n}\n\n/** Build the ContextItem for a single toolResult message, for direct unit testing. */\nexport function buildToolResultContextItem(\n\tmessage: ToolResultMessage,\n\tmessageIndex: number,\n\toptions: ContextAuditOptions,\n): ContextItem {\n\treturn buildToolOutputItem(message, messageIndex, options).item;\n}\n\n/**\n * Read-only audit pass: converts live toolResult messages into ContextItems and runs the\n * existing pure retention/hard-constraint evaluators over them. Never mutates `messages`,\n * the transcript, or artifact references -- deterministic given the same messages,\n * `turnIndex`, and artifact-store state (not a cross-turn stability guarantee: turnIndex\n * and artifact-backed createdAtTurn values are expected to change turn over turn).\n */\nexport function runContextAudit(messages: AgentMessage[], options: ContextAuditOptions): ContextAuditReport {\n\tconst items: ContextAuditItemReport[] = [];\n\tmessages.forEach((message, messageIndex) => {\n\t\tif (message.role !== \"toolResult\") return;\n\t\tconst built = buildToolOutputItem(message, messageIndex, options);\n\t\tconst features = buildPolicyFeatures(built.item, built, options.turnIndex);\n\t\tconst flags = buildHardConstraintFlags(built, options.artifactStore !== undefined);\n\t\titems.push({\n\t\t\titem: built.item,\n\t\t\ttoolCallId: message.toolCallId,\n\t\t\tmessageIndex,\n\t\t\tretention: evaluateRetentionEligibility(built.item),\n\t\t\tkeepRawHardConstraints: evaluateHardConstraints(\"keep_raw\", features, flags),\n\t\t\tpackToArtifactHardConstraints: evaluateHardConstraints(\"pack_to_artifact\", features, flags),\n\t\t\tdropFromPromptHardConstraints: evaluateHardConstraints(\"drop_from_prompt\", features, flags),\n\t\t\tsummarizeHardConstraints: evaluateHardConstraints(\"summarize\", features, flags),\n\t\t});\n\t});\n\treturn { turnIndex: options.turnIndex, items };\n}\n"]}
@@ -0,0 +1,122 @@
1
+ import type { AgentMessage } from "@caupulican/pi-agent-core";
2
+ import type { CurationTelemetrySnapshot } from "./brain-curator.ts";
3
+ /**
4
+ * Context composition dashboard (user-facing): decomposes EVERYTHING that rides along on every
5
+ * request — system prompt, active tool schemas, extension contributions, injected blocks
6
+ * (memory recall pages, evidence blocks), and the session messages themselves (raw vs. GC-packed
7
+ * vs. policy-stubbed) — so a user integrating their own tools/extensions can see exactly what
8
+ * each addition costs per request and where cleaning is (or is not) working.
9
+ *
10
+ * Honesty contract: everything here is an ESTIMATE (chars/4) EXCEPT `providerReportedTokens`,
11
+ * which is what the provider actually billed. The dashboard always shows both and the delta —
12
+ * the delta is the measure of how much the estimates can be trusted, never hidden.
13
+ *
14
+ * Known exclusions (named, not hidden): extension `context` handlers may rewrite messages at
15
+ * send time in ways this view cannot see. The memory evidence block and enforcement stubbing
16
+ * are ALSO send-time-only, but those are modeled explicitly via `adjustments`.
17
+ */
18
+ export interface ToolCompositionRow {
19
+ name: string;
20
+ /** Estimated tokens for the tool's name+description+schema as sent to the provider. */
21
+ schemaTokens: number;
22
+ source: "built-in" | "extension";
23
+ }
24
+ export interface ExtensionCompositionRow {
25
+ name: string;
26
+ path: string;
27
+ toolCount: number;
28
+ commandCount: number;
29
+ /** Estimated schema tokens of this extension's ACTIVE tools (its per-request cost). */
30
+ activeToolSchemaTokens: number;
31
+ }
32
+ export interface MessageClassRow {
33
+ label: string;
34
+ count: number;
35
+ tokens: number;
36
+ }
37
+ export interface ContextCompositionReport {
38
+ /** Estimated tokens of the system prompt sent on every request. */
39
+ systemPromptTokens: number;
40
+ systemPromptChars: number;
41
+ /** Estimated tokens of ALL active tool schemas sent on every request. */
42
+ toolSchemaTokens: number;
43
+ tools: ToolCompositionRow[];
44
+ extensions: ExtensionCompositionRow[];
45
+ /** Session message classes (raw/user/assistant/stubs/recall pages), heaviest first. */
46
+ messageClasses: MessageClassRow[];
47
+ messageTokens: number;
48
+ messageCount: number;
49
+ /** Estimated total sent per request: system prompt + tool schemas + messages. */
50
+ estimatedRequestTokens: number;
51
+ /** What the provider actually reported for the current context, when known. */
52
+ providerReportedTokens: number | null;
53
+ contextWindow: number | null;
54
+ gc: {
55
+ packedCount: number;
56
+ savedTokens: number;
57
+ } | null;
58
+ enforcement: {
59
+ enforcedCount: number;
60
+ advisoryEvictions: number;
61
+ } | null;
62
+ curation: {
63
+ enabled: boolean;
64
+ telemetry: CurationTelemetrySnapshot;
65
+ lastSkipReason?: string;
66
+ } | null;
67
+ /** Background/side-channel spend that does NOT ride in this context but bills the account. */
68
+ spawned: {
69
+ cost: number;
70
+ reports: number;
71
+ } | null;
72
+ /** Send-time-only deltas folded into estimatedRequestTokens: +evidence block, -policy stubs. */
73
+ adjustments: {
74
+ memoryEvidenceTokens: number;
75
+ enforcementSavedTokens: number;
76
+ };
77
+ /** Actionable, bounded observations derived from the numbers above. */
78
+ observations: string[];
79
+ }
80
+ export interface BuildContextCompositionInput {
81
+ systemPrompt: string;
82
+ tools: Array<{
83
+ name: string;
84
+ description?: string;
85
+ parameters?: unknown;
86
+ source?: "built-in" | "extension";
87
+ }>;
88
+ extensions: Array<{
89
+ name: string;
90
+ path: string;
91
+ toolNames: string[];
92
+ commandCount: number;
93
+ }>;
94
+ messages: AgentMessage[];
95
+ providerReportedTokens: number | null;
96
+ contextWindow: number | null;
97
+ gc?: {
98
+ packedCount: number;
99
+ savedTokens: number;
100
+ };
101
+ enforcement?: {
102
+ enforcedCount: number;
103
+ advisoryEvictions: number;
104
+ };
105
+ curation?: {
106
+ enabled: boolean;
107
+ telemetry: CurationTelemetrySnapshot;
108
+ lastSkipReason?: string;
109
+ };
110
+ spawned?: {
111
+ cost: number;
112
+ reports: number;
113
+ };
114
+ adjustments?: {
115
+ memoryEvidenceTokens: number;
116
+ enforcementSavedTokens: number;
117
+ };
118
+ }
119
+ export declare function buildContextCompositionReport(input: BuildContextCompositionInput): ContextCompositionReport;
120
+ /** Bounded plain-text dashboard (interactive `/context` command and tests). */
121
+ export declare function formatContextCompositionDashboard(report: ContextCompositionReport, maxToolRows?: number): string;
122
+ //# sourceMappingURL=context-composition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-composition.d.ts","sourceRoot":"","sources":["../../../src/core/context/context-composition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAEpE;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,uFAAuF;IACvF,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;CACjC;AAED,MAAM,WAAW,uBAAuB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,sBAAsB,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACxC,mEAAmE;IACnE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,UAAU,EAAE,uBAAuB,EAAE,CAAC;IACtC,uFAAuF;IACvF,cAAc,EAAE,eAAe,EAAE,CAAC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,sBAAsB,EAAE,MAAM,CAAC;IAC/B,+EAA+E;IAC/E,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACxD,WAAW,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzE,QAAQ,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,yBAAyB,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACrG,8FAA8F;IAC9F,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,gGAAgG;IAChG,WAAW,EAAE;QAAE,oBAAoB,EAAE,MAAM,CAAC;QAAC,sBAAsB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9E,uEAAuE;IACvE,YAAY,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,4BAA4B;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC;IAC9G,UAAU,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;IACH,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,EAAE,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,WAAW,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,yBAAyB,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/F,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,WAAW,CAAC,EAAE;QAAE,oBAAoB,EAAE,MAAM,CAAC;QAAC,sBAAsB,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E;AAiCD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,4BAA4B,GAAG,wBAAwB,CAoG3G;AAED,+EAA+E;AAC/E,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,wBAAwB,EAAE,WAAW,SAAK,GAAG,MAAM,CAmE5G","sourcesContent":["import type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport { estimateTokens } from \"../compaction/compaction.ts\";\nimport type { CurationTelemetrySnapshot } from \"./brain-curator.ts\";\n\n/**\n * Context composition dashboard (user-facing): decomposes EVERYTHING that rides along on every\n * request — system prompt, active tool schemas, extension contributions, injected blocks\n * (memory recall pages, evidence blocks), and the session messages themselves (raw vs. GC-packed\n * vs. policy-stubbed) — so a user integrating their own tools/extensions can see exactly what\n * each addition costs per request and where cleaning is (or is not) working.\n *\n * Honesty contract: everything here is an ESTIMATE (chars/4) EXCEPT `providerReportedTokens`,\n * which is what the provider actually billed. The dashboard always shows both and the delta —\n * the delta is the measure of how much the estimates can be trusted, never hidden.\n *\n * Known exclusions (named, not hidden): extension `context` handlers may rewrite messages at\n * send time in ways this view cannot see. The memory evidence block and enforcement stubbing\n * are ALSO send-time-only, but those are modeled explicitly via `adjustments`.\n */\n\nexport interface ToolCompositionRow {\n\tname: string;\n\t/** Estimated tokens for the tool's name+description+schema as sent to the provider. */\n\tschemaTokens: number;\n\tsource: \"built-in\" | \"extension\";\n}\n\nexport interface ExtensionCompositionRow {\n\tname: string;\n\tpath: string;\n\ttoolCount: number;\n\tcommandCount: number;\n\t/** Estimated schema tokens of this extension's ACTIVE tools (its per-request cost). */\n\tactiveToolSchemaTokens: number;\n}\n\nexport interface MessageClassRow {\n\tlabel: string;\n\tcount: number;\n\ttokens: number;\n}\n\nexport interface ContextCompositionReport {\n\t/** Estimated tokens of the system prompt sent on every request. */\n\tsystemPromptTokens: number;\n\tsystemPromptChars: number;\n\t/** Estimated tokens of ALL active tool schemas sent on every request. */\n\ttoolSchemaTokens: number;\n\ttools: ToolCompositionRow[];\n\textensions: ExtensionCompositionRow[];\n\t/** Session message classes (raw/user/assistant/stubs/recall pages), heaviest first. */\n\tmessageClasses: MessageClassRow[];\n\tmessageTokens: number;\n\tmessageCount: number;\n\t/** Estimated total sent per request: system prompt + tool schemas + messages. */\n\testimatedRequestTokens: number;\n\t/** What the provider actually reported for the current context, when known. */\n\tproviderReportedTokens: number | null;\n\tcontextWindow: number | null;\n\tgc: { packedCount: number; savedTokens: number } | null;\n\tenforcement: { enforcedCount: number; advisoryEvictions: number } | null;\n\tcuration: { enabled: boolean; telemetry: CurationTelemetrySnapshot; lastSkipReason?: string } | null;\n\t/** Background/side-channel spend that does NOT ride in this context but bills the account. */\n\tspawned: { cost: number; reports: number } | null;\n\t/** Send-time-only deltas folded into estimatedRequestTokens: +evidence block, -policy stubs. */\n\tadjustments: { memoryEvidenceTokens: number; enforcementSavedTokens: number };\n\t/** Actionable, bounded observations derived from the numbers above. */\n\tobservations: string[];\n}\n\nexport interface BuildContextCompositionInput {\n\tsystemPrompt: string;\n\ttools: Array<{ name: string; description?: string; parameters?: unknown; source?: \"built-in\" | \"extension\" }>;\n\textensions: Array<{\n\t\tname: string;\n\t\tpath: string;\n\t\ttoolNames: string[];\n\t\tcommandCount: number;\n\t}>;\n\tmessages: AgentMessage[];\n\tproviderReportedTokens: number | null;\n\tcontextWindow: number | null;\n\tgc?: { packedCount: number; savedTokens: number };\n\tenforcement?: { enforcedCount: number; advisoryEvictions: number };\n\tcuration?: { enabled: boolean; telemetry: CurationTelemetrySnapshot; lastSkipReason?: string };\n\tspawned?: { cost: number; reports: number };\n\tadjustments?: { memoryEvidenceTokens: number; enforcementSavedTokens: number };\n}\n\nfunction estimateTextTokens(text: string): number {\n\treturn Math.ceil(text.length / 4);\n}\n\nfunction messageText(message: AgentMessage): string {\n\tconst content = (message as { content?: unknown }).content;\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => (part as { type?: string }).type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction classifyMessage(message: AgentMessage): string {\n\tconst details = (\n\t\tmessage as { details?: { contextGc?: { packed?: unknown }; promptPolicy?: { enforced?: unknown } } }\n\t).details;\n\tif (details?.contextGc?.packed === true) return \"gc-packed stub\";\n\tif (details?.promptPolicy?.enforced === true) return \"policy stub\";\n\tif (message.role === \"custom\") {\n\t\tconst customType = (message as { customType?: string }).customType ?? \"\";\n\t\tif (customType === \"memory_context\" || messageText(message).includes(\"<memory_context\")) {\n\t\t\treturn \"memory recall page\";\n\t\t}\n\t\treturn `custom (${customType || \"unknown\"})`;\n\t}\n\tif (message.role === \"toolResult\") return `toolResult (${(message as { toolName?: string }).toolName ?? \"?\"})`;\n\treturn message.role;\n}\n\nexport function buildContextCompositionReport(input: BuildContextCompositionInput): ContextCompositionReport {\n\tconst systemPromptTokens = estimateTextTokens(input.systemPrompt);\n\n\tconst tools: ToolCompositionRow[] = input.tools\n\t\t.map((tool) => ({\n\t\t\tname: tool.name,\n\t\t\tschemaTokens: estimateTextTokens(\n\t\t\t\tJSON.stringify({ name: tool.name, description: tool.description ?? \"\", parameters: tool.parameters ?? {} }),\n\t\t\t),\n\t\t\tsource: tool.source ?? (\"built-in\" as const),\n\t\t}))\n\t\t.sort((a, b) => b.schemaTokens - a.schemaTokens);\n\tconst toolSchemaTokens = tools.reduce((sum, tool) => sum + tool.schemaTokens, 0);\n\tconst toolTokensByName = new Map(tools.map((tool) => [tool.name, tool.schemaTokens]));\n\n\tconst extensions: ExtensionCompositionRow[] = input.extensions\n\t\t.map((extension) => ({\n\t\t\tname: extension.name,\n\t\t\tpath: extension.path,\n\t\t\ttoolCount: extension.toolNames.length,\n\t\t\tcommandCount: extension.commandCount,\n\t\t\tactiveToolSchemaTokens: extension.toolNames.reduce(\n\t\t\t\t(sum, toolName) => sum + (toolTokensByName.get(toolName) ?? 0),\n\t\t\t\t0,\n\t\t\t),\n\t\t}))\n\t\t.sort((a, b) => b.activeToolSchemaTokens - a.activeToolSchemaTokens);\n\n\tconst classes = new Map<string, MessageClassRow>();\n\tlet messageTokens = 0;\n\tfor (const message of input.messages) {\n\t\tconst label = classifyMessage(message);\n\t\tconst tokens = estimateTokens(message);\n\t\tmessageTokens += tokens;\n\t\tconst row = classes.get(label) ?? { label, count: 0, tokens: 0 };\n\t\trow.count++;\n\t\trow.tokens += tokens;\n\t\tclasses.set(label, row);\n\t}\n\tconst messageClasses = [...classes.values()].sort((a, b) => b.tokens - a.tokens);\n\n\tconst adjustments = input.adjustments ?? { memoryEvidenceTokens: 0, enforcementSavedTokens: 0 };\n\tconst estimatedRequestTokens = Math.max(\n\t\t0,\n\t\tsystemPromptTokens +\n\t\t\ttoolSchemaTokens +\n\t\t\tmessageTokens +\n\t\t\tadjustments.memoryEvidenceTokens -\n\t\t\tadjustments.enforcementSavedTokens,\n\t);\n\n\tconst observations: string[] = [];\n\tconst heaviestTool = tools[0];\n\tif (heaviestTool && toolSchemaTokens > 0 && heaviestTool.schemaTokens > Math.max(500, toolSchemaTokens * 0.3)) {\n\t\tobservations.push(\n\t\t\t`tool \"${heaviestTool.name}\" alone is ~${heaviestTool.schemaTokens} tokens of schema on EVERY request — trim its description/schema if you own it`,\n\t\t);\n\t}\n\tconst recall = messageClasses.find((row) => row.label === \"memory recall page\");\n\tif (recall && recall.tokens > 1500) {\n\t\tobservations.push(\n\t\t\t`${recall.count} memory recall page(s) hold ~${recall.tokens} tokens — verify context GC is packing stale ones (gc packed: ${input.gc?.packedCount ?? 0})`,\n\t\t);\n\t}\n\tif (input.contextWindow && systemPromptTokens + toolSchemaTokens > input.contextWindow * 0.35) {\n\t\tobservations.push(\n\t\t\t`fixed per-request overhead (system+tools) is ~${Math.round(((systemPromptTokens + toolSchemaTokens) / input.contextWindow) * 100)}% of the context window before any conversation`,\n\t\t);\n\t}\n\tif (input.providerReportedTokens !== null) {\n\t\tconst delta = input.providerReportedTokens - estimatedRequestTokens;\n\t\tif (Math.abs(delta) > Math.max(2000, estimatedRequestTokens * 0.25)) {\n\t\t\tobservations.push(\n\t\t\t\t`provider-reported context (${input.providerReportedTokens}) differs from the estimate by ${delta > 0 ? \"+\" : \"\"}${delta} tokens — treat estimates as directional`,\n\t\t\t);\n\t\t}\n\t}\n\tif (input.curation?.enabled && input.curation.lastSkipReason) {\n\t\tobservations.push(`curation is enabled but idle: ${input.curation.lastSkipReason}`);\n\t}\n\n\treturn {\n\t\tsystemPromptTokens,\n\t\tsystemPromptChars: input.systemPrompt.length,\n\t\ttoolSchemaTokens,\n\t\ttools,\n\t\textensions,\n\t\tmessageClasses,\n\t\tmessageTokens,\n\t\tmessageCount: input.messages.length,\n\t\testimatedRequestTokens,\n\t\tproviderReportedTokens: input.providerReportedTokens,\n\t\tcontextWindow: input.contextWindow,\n\t\tgc: input.gc ?? null,\n\t\tenforcement: input.enforcement ?? null,\n\t\tcuration: input.curation ?? null,\n\t\tspawned: input.spawned ?? null,\n\t\tadjustments,\n\t\tobservations,\n\t};\n}\n\n/** Bounded plain-text dashboard (interactive `/context` command and tests). */\nexport function formatContextCompositionDashboard(report: ContextCompositionReport, maxToolRows = 10): string {\n\tconst pct = (tokens: number) =>\n\t\treport.contextWindow ? ` (${((tokens / report.contextWindow) * 100).toFixed(1)}% of window)` : \"\";\n\tconst lines: string[] = [\n\t\t\"Context composition — what rides on EVERY request\",\n\t\t`estimated request total: ~${report.estimatedRequestTokens} tokens${pct(report.estimatedRequestTokens)}${\n\t\t\treport.providerReportedTokens !== null ? ` · provider-reported: ${report.providerReportedTokens}` : \"\"\n\t\t}`,\n\t\t\"\",\n\t\t`system prompt: ~${report.systemPromptTokens} tokens (${report.systemPromptChars} chars)`,\n\t\t`tool schemas: ~${report.toolSchemaTokens} tokens across ${report.tools.length} active tool(s)`,\n\t];\n\tfor (const tool of report.tools.slice(0, maxToolRows)) {\n\t\tlines.push(` - ${tool.name}: ~${tool.schemaTokens} tok [${tool.source}]`);\n\t}\n\tif (report.tools.length > maxToolRows) {\n\t\tconst rest = report.tools.slice(maxToolRows).reduce((sum, tool) => sum + tool.schemaTokens, 0);\n\t\tlines.push(` - (+${report.tools.length - maxToolRows} more: ~${rest} tok)`);\n\t}\n\tif (report.extensions.length > 0) {\n\t\tlines.push(\"\", \"extensions:\");\n\t\tfor (const extension of report.extensions.slice(0, 8)) {\n\t\t\tlines.push(\n\t\t\t\t` - ${extension.name}: ${extension.toolCount} tool(s), ${extension.commandCount} command(s), ~${extension.activeToolSchemaTokens} tok of active schemas`,\n\t\t\t);\n\t\t}\n\t}\n\tlines.push(\"\", `session messages: ${report.messageCount} row(s), ~${report.messageTokens} tokens`);\n\tif (report.adjustments.memoryEvidenceTokens > 0 || report.adjustments.enforcementSavedTokens > 0) {\n\t\tlines.push(\n\t\t\t`send-time adjustments: +${report.adjustments.memoryEvidenceTokens} memory evidence, -${report.adjustments.enforcementSavedTokens} policy stubs (applied when the request is built)`,\n\t\t);\n\t}\n\tfor (const row of report.messageClasses.slice(0, 10)) {\n\t\tlines.push(` - ${row.label}: ${row.count} row(s), ~${row.tokens} tok`);\n\t}\n\tif (report.gc) {\n\t\tlines.push(\n\t\t\t\"\",\n\t\t\t`context GC: ${report.gc.packedCount} row(s) packed, ~${report.gc.savedTokens} tokens saved this pass`,\n\t\t);\n\t}\n\tif (report.enforcement) {\n\t\tlines.push(\n\t\t\t`prompt policy: ${report.enforcement.enforcedCount} stub(s) this turn (${report.enforcement.advisoryEvictions} via brain advisory)`,\n\t\t);\n\t}\n\tif (report.curation) {\n\t\tconst t = report.curation.telemetry;\n\t\tlines.push(\n\t\t\t`brain curation: ${report.curation.enabled ? \"enabled\" : \"disabled\"} — ${t.jobsRun} job(s) run, ${t.parseFailures} parse failure(s), ${t.queued} queued, ~${Math.ceil(t.localChars / 4)} tokens processed locally${\n\t\t\t\treport.curation.lastSkipReason ? ` · last skip: ${report.curation.lastSkipReason}` : \"\"\n\t\t\t}`,\n\t\t);\n\t}\n\tif (report.spawned && report.spawned.reports > 0) {\n\t\tlines.push(\n\t\t\t`spawned/background spend (NOT in this context): ${report.spawned.reports} report(s), $${report.spawned.cost.toFixed(4)}`,\n\t\t);\n\t}\n\tif (report.observations.length > 0) {\n\t\tlines.push(\"\", \"observations:\");\n\t\tfor (const observation of report.observations.slice(0, 5)) {\n\t\t\tlines.push(` ! ${observation}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
@@ -0,0 +1,163 @@
1
+ import { estimateTokens } from "../compaction/compaction.js";
2
+ function estimateTextTokens(text) {
3
+ return Math.ceil(text.length / 4);
4
+ }
5
+ function messageText(message) {
6
+ const content = message.content;
7
+ if (typeof content === "string")
8
+ return content;
9
+ if (!Array.isArray(content))
10
+ return "";
11
+ return content
12
+ .filter((part) => part.type === "text")
13
+ .map((part) => part.text)
14
+ .join("\n");
15
+ }
16
+ function classifyMessage(message) {
17
+ const details = message.details;
18
+ if (details?.contextGc?.packed === true)
19
+ return "gc-packed stub";
20
+ if (details?.promptPolicy?.enforced === true)
21
+ return "policy stub";
22
+ if (message.role === "custom") {
23
+ const customType = message.customType ?? "";
24
+ if (customType === "memory_context" || messageText(message).includes("<memory_context")) {
25
+ return "memory recall page";
26
+ }
27
+ return `custom (${customType || "unknown"})`;
28
+ }
29
+ if (message.role === "toolResult")
30
+ return `toolResult (${message.toolName ?? "?"})`;
31
+ return message.role;
32
+ }
33
+ export function buildContextCompositionReport(input) {
34
+ const systemPromptTokens = estimateTextTokens(input.systemPrompt);
35
+ const tools = input.tools
36
+ .map((tool) => ({
37
+ name: tool.name,
38
+ schemaTokens: estimateTextTokens(JSON.stringify({ name: tool.name, description: tool.description ?? "", parameters: tool.parameters ?? {} })),
39
+ source: tool.source ?? "built-in",
40
+ }))
41
+ .sort((a, b) => b.schemaTokens - a.schemaTokens);
42
+ const toolSchemaTokens = tools.reduce((sum, tool) => sum + tool.schemaTokens, 0);
43
+ const toolTokensByName = new Map(tools.map((tool) => [tool.name, tool.schemaTokens]));
44
+ const extensions = input.extensions
45
+ .map((extension) => ({
46
+ name: extension.name,
47
+ path: extension.path,
48
+ toolCount: extension.toolNames.length,
49
+ commandCount: extension.commandCount,
50
+ activeToolSchemaTokens: extension.toolNames.reduce((sum, toolName) => sum + (toolTokensByName.get(toolName) ?? 0), 0),
51
+ }))
52
+ .sort((a, b) => b.activeToolSchemaTokens - a.activeToolSchemaTokens);
53
+ const classes = new Map();
54
+ let messageTokens = 0;
55
+ for (const message of input.messages) {
56
+ const label = classifyMessage(message);
57
+ const tokens = estimateTokens(message);
58
+ messageTokens += tokens;
59
+ const row = classes.get(label) ?? { label, count: 0, tokens: 0 };
60
+ row.count++;
61
+ row.tokens += tokens;
62
+ classes.set(label, row);
63
+ }
64
+ const messageClasses = [...classes.values()].sort((a, b) => b.tokens - a.tokens);
65
+ const adjustments = input.adjustments ?? { memoryEvidenceTokens: 0, enforcementSavedTokens: 0 };
66
+ const estimatedRequestTokens = Math.max(0, systemPromptTokens +
67
+ toolSchemaTokens +
68
+ messageTokens +
69
+ adjustments.memoryEvidenceTokens -
70
+ adjustments.enforcementSavedTokens);
71
+ const observations = [];
72
+ const heaviestTool = tools[0];
73
+ if (heaviestTool && toolSchemaTokens > 0 && heaviestTool.schemaTokens > Math.max(500, toolSchemaTokens * 0.3)) {
74
+ observations.push(`tool "${heaviestTool.name}" alone is ~${heaviestTool.schemaTokens} tokens of schema on EVERY request — trim its description/schema if you own it`);
75
+ }
76
+ const recall = messageClasses.find((row) => row.label === "memory recall page");
77
+ if (recall && recall.tokens > 1500) {
78
+ observations.push(`${recall.count} memory recall page(s) hold ~${recall.tokens} tokens — verify context GC is packing stale ones (gc packed: ${input.gc?.packedCount ?? 0})`);
79
+ }
80
+ if (input.contextWindow && systemPromptTokens + toolSchemaTokens > input.contextWindow * 0.35) {
81
+ observations.push(`fixed per-request overhead (system+tools) is ~${Math.round(((systemPromptTokens + toolSchemaTokens) / input.contextWindow) * 100)}% of the context window before any conversation`);
82
+ }
83
+ if (input.providerReportedTokens !== null) {
84
+ const delta = input.providerReportedTokens - estimatedRequestTokens;
85
+ if (Math.abs(delta) > Math.max(2000, estimatedRequestTokens * 0.25)) {
86
+ observations.push(`provider-reported context (${input.providerReportedTokens}) differs from the estimate by ${delta > 0 ? "+" : ""}${delta} tokens — treat estimates as directional`);
87
+ }
88
+ }
89
+ if (input.curation?.enabled && input.curation.lastSkipReason) {
90
+ observations.push(`curation is enabled but idle: ${input.curation.lastSkipReason}`);
91
+ }
92
+ return {
93
+ systemPromptTokens,
94
+ systemPromptChars: input.systemPrompt.length,
95
+ toolSchemaTokens,
96
+ tools,
97
+ extensions,
98
+ messageClasses,
99
+ messageTokens,
100
+ messageCount: input.messages.length,
101
+ estimatedRequestTokens,
102
+ providerReportedTokens: input.providerReportedTokens,
103
+ contextWindow: input.contextWindow,
104
+ gc: input.gc ?? null,
105
+ enforcement: input.enforcement ?? null,
106
+ curation: input.curation ?? null,
107
+ spawned: input.spawned ?? null,
108
+ adjustments,
109
+ observations,
110
+ };
111
+ }
112
+ /** Bounded plain-text dashboard (interactive `/context` command and tests). */
113
+ export function formatContextCompositionDashboard(report, maxToolRows = 10) {
114
+ const pct = (tokens) => report.contextWindow ? ` (${((tokens / report.contextWindow) * 100).toFixed(1)}% of window)` : "";
115
+ const lines = [
116
+ "Context composition — what rides on EVERY request",
117
+ `estimated request total: ~${report.estimatedRequestTokens} tokens${pct(report.estimatedRequestTokens)}${report.providerReportedTokens !== null ? ` · provider-reported: ${report.providerReportedTokens}` : ""}`,
118
+ "",
119
+ `system prompt: ~${report.systemPromptTokens} tokens (${report.systemPromptChars} chars)`,
120
+ `tool schemas: ~${report.toolSchemaTokens} tokens across ${report.tools.length} active tool(s)`,
121
+ ];
122
+ for (const tool of report.tools.slice(0, maxToolRows)) {
123
+ lines.push(` - ${tool.name}: ~${tool.schemaTokens} tok [${tool.source}]`);
124
+ }
125
+ if (report.tools.length > maxToolRows) {
126
+ const rest = report.tools.slice(maxToolRows).reduce((sum, tool) => sum + tool.schemaTokens, 0);
127
+ lines.push(` - (+${report.tools.length - maxToolRows} more: ~${rest} tok)`);
128
+ }
129
+ if (report.extensions.length > 0) {
130
+ lines.push("", "extensions:");
131
+ for (const extension of report.extensions.slice(0, 8)) {
132
+ lines.push(` - ${extension.name}: ${extension.toolCount} tool(s), ${extension.commandCount} command(s), ~${extension.activeToolSchemaTokens} tok of active schemas`);
133
+ }
134
+ }
135
+ lines.push("", `session messages: ${report.messageCount} row(s), ~${report.messageTokens} tokens`);
136
+ if (report.adjustments.memoryEvidenceTokens > 0 || report.adjustments.enforcementSavedTokens > 0) {
137
+ lines.push(`send-time adjustments: +${report.adjustments.memoryEvidenceTokens} memory evidence, -${report.adjustments.enforcementSavedTokens} policy stubs (applied when the request is built)`);
138
+ }
139
+ for (const row of report.messageClasses.slice(0, 10)) {
140
+ lines.push(` - ${row.label}: ${row.count} row(s), ~${row.tokens} tok`);
141
+ }
142
+ if (report.gc) {
143
+ lines.push("", `context GC: ${report.gc.packedCount} row(s) packed, ~${report.gc.savedTokens} tokens saved this pass`);
144
+ }
145
+ if (report.enforcement) {
146
+ lines.push(`prompt policy: ${report.enforcement.enforcedCount} stub(s) this turn (${report.enforcement.advisoryEvictions} via brain advisory)`);
147
+ }
148
+ if (report.curation) {
149
+ const t = report.curation.telemetry;
150
+ lines.push(`brain curation: ${report.curation.enabled ? "enabled" : "disabled"} — ${t.jobsRun} job(s) run, ${t.parseFailures} parse failure(s), ${t.queued} queued, ~${Math.ceil(t.localChars / 4)} tokens processed locally${report.curation.lastSkipReason ? ` · last skip: ${report.curation.lastSkipReason}` : ""}`);
151
+ }
152
+ if (report.spawned && report.spawned.reports > 0) {
153
+ lines.push(`spawned/background spend (NOT in this context): ${report.spawned.reports} report(s), $${report.spawned.cost.toFixed(4)}`);
154
+ }
155
+ if (report.observations.length > 0) {
156
+ lines.push("", "observations:");
157
+ for (const observation of report.observations.slice(0, 5)) {
158
+ lines.push(` ! ${observation}`);
159
+ }
160
+ }
161
+ return lines.join("\n");
162
+ }
163
+ //# sourceMappingURL=context-composition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-composition.js","sourceRoot":"","sources":["../../../src/core/context/context-composition.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport { estimateTokens } from \"../compaction/compaction.ts\";\nimport type { CurationTelemetrySnapshot } from \"./brain-curator.ts\";\n\n/**\n * Context composition dashboard (user-facing): decomposes EVERYTHING that rides along on every\n * request — system prompt, active tool schemas, extension contributions, injected blocks\n * (memory recall pages, evidence blocks), and the session messages themselves (raw vs. GC-packed\n * vs. policy-stubbed) — so a user integrating their own tools/extensions can see exactly what\n * each addition costs per request and where cleaning is (or is not) working.\n *\n * Honesty contract: everything here is an ESTIMATE (chars/4) EXCEPT `providerReportedTokens`,\n * which is what the provider actually billed. The dashboard always shows both and the delta —\n * the delta is the measure of how much the estimates can be trusted, never hidden.\n *\n * Known exclusions (named, not hidden): extension `context` handlers may rewrite messages at\n * send time in ways this view cannot see. The memory evidence block and enforcement stubbing\n * are ALSO send-time-only, but those are modeled explicitly via `adjustments`.\n */\n\nexport interface ToolCompositionRow {\n\tname: string;\n\t/** Estimated tokens for the tool's name+description+schema as sent to the provider. */\n\tschemaTokens: number;\n\tsource: \"built-in\" | \"extension\";\n}\n\nexport interface ExtensionCompositionRow {\n\tname: string;\n\tpath: string;\n\ttoolCount: number;\n\tcommandCount: number;\n\t/** Estimated schema tokens of this extension's ACTIVE tools (its per-request cost). */\n\tactiveToolSchemaTokens: number;\n}\n\nexport interface MessageClassRow {\n\tlabel: string;\n\tcount: number;\n\ttokens: number;\n}\n\nexport interface ContextCompositionReport {\n\t/** Estimated tokens of the system prompt sent on every request. */\n\tsystemPromptTokens: number;\n\tsystemPromptChars: number;\n\t/** Estimated tokens of ALL active tool schemas sent on every request. */\n\ttoolSchemaTokens: number;\n\ttools: ToolCompositionRow[];\n\textensions: ExtensionCompositionRow[];\n\t/** Session message classes (raw/user/assistant/stubs/recall pages), heaviest first. */\n\tmessageClasses: MessageClassRow[];\n\tmessageTokens: number;\n\tmessageCount: number;\n\t/** Estimated total sent per request: system prompt + tool schemas + messages. */\n\testimatedRequestTokens: number;\n\t/** What the provider actually reported for the current context, when known. */\n\tproviderReportedTokens: number | null;\n\tcontextWindow: number | null;\n\tgc: { packedCount: number; savedTokens: number } | null;\n\tenforcement: { enforcedCount: number; advisoryEvictions: number } | null;\n\tcuration: { enabled: boolean; telemetry: CurationTelemetrySnapshot; lastSkipReason?: string } | null;\n\t/** Background/side-channel spend that does NOT ride in this context but bills the account. */\n\tspawned: { cost: number; reports: number } | null;\n\t/** Send-time-only deltas folded into estimatedRequestTokens: +evidence block, -policy stubs. */\n\tadjustments: { memoryEvidenceTokens: number; enforcementSavedTokens: number };\n\t/** Actionable, bounded observations derived from the numbers above. */\n\tobservations: string[];\n}\n\nexport interface BuildContextCompositionInput {\n\tsystemPrompt: string;\n\ttools: Array<{ name: string; description?: string; parameters?: unknown; source?: \"built-in\" | \"extension\" }>;\n\textensions: Array<{\n\t\tname: string;\n\t\tpath: string;\n\t\ttoolNames: string[];\n\t\tcommandCount: number;\n\t}>;\n\tmessages: AgentMessage[];\n\tproviderReportedTokens: number | null;\n\tcontextWindow: number | null;\n\tgc?: { packedCount: number; savedTokens: number };\n\tenforcement?: { enforcedCount: number; advisoryEvictions: number };\n\tcuration?: { enabled: boolean; telemetry: CurationTelemetrySnapshot; lastSkipReason?: string };\n\tspawned?: { cost: number; reports: number };\n\tadjustments?: { memoryEvidenceTokens: number; enforcementSavedTokens: number };\n}\n\nfunction estimateTextTokens(text: string): number {\n\treturn Math.ceil(text.length / 4);\n}\n\nfunction messageText(message: AgentMessage): string {\n\tconst content = (message as { content?: unknown }).content;\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => (part as { type?: string }).type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction classifyMessage(message: AgentMessage): string {\n\tconst details = (\n\t\tmessage as { details?: { contextGc?: { packed?: unknown }; promptPolicy?: { enforced?: unknown } } }\n\t).details;\n\tif (details?.contextGc?.packed === true) return \"gc-packed stub\";\n\tif (details?.promptPolicy?.enforced === true) return \"policy stub\";\n\tif (message.role === \"custom\") {\n\t\tconst customType = (message as { customType?: string }).customType ?? \"\";\n\t\tif (customType === \"memory_context\" || messageText(message).includes(\"<memory_context\")) {\n\t\t\treturn \"memory recall page\";\n\t\t}\n\t\treturn `custom (${customType || \"unknown\"})`;\n\t}\n\tif (message.role === \"toolResult\") return `toolResult (${(message as { toolName?: string }).toolName ?? \"?\"})`;\n\treturn message.role;\n}\n\nexport function buildContextCompositionReport(input: BuildContextCompositionInput): ContextCompositionReport {\n\tconst systemPromptTokens = estimateTextTokens(input.systemPrompt);\n\n\tconst tools: ToolCompositionRow[] = input.tools\n\t\t.map((tool) => ({\n\t\t\tname: tool.name,\n\t\t\tschemaTokens: estimateTextTokens(\n\t\t\t\tJSON.stringify({ name: tool.name, description: tool.description ?? \"\", parameters: tool.parameters ?? {} }),\n\t\t\t),\n\t\t\tsource: tool.source ?? (\"built-in\" as const),\n\t\t}))\n\t\t.sort((a, b) => b.schemaTokens - a.schemaTokens);\n\tconst toolSchemaTokens = tools.reduce((sum, tool) => sum + tool.schemaTokens, 0);\n\tconst toolTokensByName = new Map(tools.map((tool) => [tool.name, tool.schemaTokens]));\n\n\tconst extensions: ExtensionCompositionRow[] = input.extensions\n\t\t.map((extension) => ({\n\t\t\tname: extension.name,\n\t\t\tpath: extension.path,\n\t\t\ttoolCount: extension.toolNames.length,\n\t\t\tcommandCount: extension.commandCount,\n\t\t\tactiveToolSchemaTokens: extension.toolNames.reduce(\n\t\t\t\t(sum, toolName) => sum + (toolTokensByName.get(toolName) ?? 0),\n\t\t\t\t0,\n\t\t\t),\n\t\t}))\n\t\t.sort((a, b) => b.activeToolSchemaTokens - a.activeToolSchemaTokens);\n\n\tconst classes = new Map<string, MessageClassRow>();\n\tlet messageTokens = 0;\n\tfor (const message of input.messages) {\n\t\tconst label = classifyMessage(message);\n\t\tconst tokens = estimateTokens(message);\n\t\tmessageTokens += tokens;\n\t\tconst row = classes.get(label) ?? { label, count: 0, tokens: 0 };\n\t\trow.count++;\n\t\trow.tokens += tokens;\n\t\tclasses.set(label, row);\n\t}\n\tconst messageClasses = [...classes.values()].sort((a, b) => b.tokens - a.tokens);\n\n\tconst adjustments = input.adjustments ?? { memoryEvidenceTokens: 0, enforcementSavedTokens: 0 };\n\tconst estimatedRequestTokens = Math.max(\n\t\t0,\n\t\tsystemPromptTokens +\n\t\t\ttoolSchemaTokens +\n\t\t\tmessageTokens +\n\t\t\tadjustments.memoryEvidenceTokens -\n\t\t\tadjustments.enforcementSavedTokens,\n\t);\n\n\tconst observations: string[] = [];\n\tconst heaviestTool = tools[0];\n\tif (heaviestTool && toolSchemaTokens > 0 && heaviestTool.schemaTokens > Math.max(500, toolSchemaTokens * 0.3)) {\n\t\tobservations.push(\n\t\t\t`tool \"${heaviestTool.name}\" alone is ~${heaviestTool.schemaTokens} tokens of schema on EVERY request — trim its description/schema if you own it`,\n\t\t);\n\t}\n\tconst recall = messageClasses.find((row) => row.label === \"memory recall page\");\n\tif (recall && recall.tokens > 1500) {\n\t\tobservations.push(\n\t\t\t`${recall.count} memory recall page(s) hold ~${recall.tokens} tokens — verify context GC is packing stale ones (gc packed: ${input.gc?.packedCount ?? 0})`,\n\t\t);\n\t}\n\tif (input.contextWindow && systemPromptTokens + toolSchemaTokens > input.contextWindow * 0.35) {\n\t\tobservations.push(\n\t\t\t`fixed per-request overhead (system+tools) is ~${Math.round(((systemPromptTokens + toolSchemaTokens) / input.contextWindow) * 100)}% of the context window before any conversation`,\n\t\t);\n\t}\n\tif (input.providerReportedTokens !== null) {\n\t\tconst delta = input.providerReportedTokens - estimatedRequestTokens;\n\t\tif (Math.abs(delta) > Math.max(2000, estimatedRequestTokens * 0.25)) {\n\t\t\tobservations.push(\n\t\t\t\t`provider-reported context (${input.providerReportedTokens}) differs from the estimate by ${delta > 0 ? \"+\" : \"\"}${delta} tokens — treat estimates as directional`,\n\t\t\t);\n\t\t}\n\t}\n\tif (input.curation?.enabled && input.curation.lastSkipReason) {\n\t\tobservations.push(`curation is enabled but idle: ${input.curation.lastSkipReason}`);\n\t}\n\n\treturn {\n\t\tsystemPromptTokens,\n\t\tsystemPromptChars: input.systemPrompt.length,\n\t\ttoolSchemaTokens,\n\t\ttools,\n\t\textensions,\n\t\tmessageClasses,\n\t\tmessageTokens,\n\t\tmessageCount: input.messages.length,\n\t\testimatedRequestTokens,\n\t\tproviderReportedTokens: input.providerReportedTokens,\n\t\tcontextWindow: input.contextWindow,\n\t\tgc: input.gc ?? null,\n\t\tenforcement: input.enforcement ?? null,\n\t\tcuration: input.curation ?? null,\n\t\tspawned: input.spawned ?? null,\n\t\tadjustments,\n\t\tobservations,\n\t};\n}\n\n/** Bounded plain-text dashboard (interactive `/context` command and tests). */\nexport function formatContextCompositionDashboard(report: ContextCompositionReport, maxToolRows = 10): string {\n\tconst pct = (tokens: number) =>\n\t\treport.contextWindow ? ` (${((tokens / report.contextWindow) * 100).toFixed(1)}% of window)` : \"\";\n\tconst lines: string[] = [\n\t\t\"Context composition — what rides on EVERY request\",\n\t\t`estimated request total: ~${report.estimatedRequestTokens} tokens${pct(report.estimatedRequestTokens)}${\n\t\t\treport.providerReportedTokens !== null ? ` · provider-reported: ${report.providerReportedTokens}` : \"\"\n\t\t}`,\n\t\t\"\",\n\t\t`system prompt: ~${report.systemPromptTokens} tokens (${report.systemPromptChars} chars)`,\n\t\t`tool schemas: ~${report.toolSchemaTokens} tokens across ${report.tools.length} active tool(s)`,\n\t];\n\tfor (const tool of report.tools.slice(0, maxToolRows)) {\n\t\tlines.push(` - ${tool.name}: ~${tool.schemaTokens} tok [${tool.source}]`);\n\t}\n\tif (report.tools.length > maxToolRows) {\n\t\tconst rest = report.tools.slice(maxToolRows).reduce((sum, tool) => sum + tool.schemaTokens, 0);\n\t\tlines.push(` - (+${report.tools.length - maxToolRows} more: ~${rest} tok)`);\n\t}\n\tif (report.extensions.length > 0) {\n\t\tlines.push(\"\", \"extensions:\");\n\t\tfor (const extension of report.extensions.slice(0, 8)) {\n\t\t\tlines.push(\n\t\t\t\t` - ${extension.name}: ${extension.toolCount} tool(s), ${extension.commandCount} command(s), ~${extension.activeToolSchemaTokens} tok of active schemas`,\n\t\t\t);\n\t\t}\n\t}\n\tlines.push(\"\", `session messages: ${report.messageCount} row(s), ~${report.messageTokens} tokens`);\n\tif (report.adjustments.memoryEvidenceTokens > 0 || report.adjustments.enforcementSavedTokens > 0) {\n\t\tlines.push(\n\t\t\t`send-time adjustments: +${report.adjustments.memoryEvidenceTokens} memory evidence, -${report.adjustments.enforcementSavedTokens} policy stubs (applied when the request is built)`,\n\t\t);\n\t}\n\tfor (const row of report.messageClasses.slice(0, 10)) {\n\t\tlines.push(` - ${row.label}: ${row.count} row(s), ~${row.tokens} tok`);\n\t}\n\tif (report.gc) {\n\t\tlines.push(\n\t\t\t\"\",\n\t\t\t`context GC: ${report.gc.packedCount} row(s) packed, ~${report.gc.savedTokens} tokens saved this pass`,\n\t\t);\n\t}\n\tif (report.enforcement) {\n\t\tlines.push(\n\t\t\t`prompt policy: ${report.enforcement.enforcedCount} stub(s) this turn (${report.enforcement.advisoryEvictions} via brain advisory)`,\n\t\t);\n\t}\n\tif (report.curation) {\n\t\tconst t = report.curation.telemetry;\n\t\tlines.push(\n\t\t\t`brain curation: ${report.curation.enabled ? \"enabled\" : \"disabled\"} — ${t.jobsRun} job(s) run, ${t.parseFailures} parse failure(s), ${t.queued} queued, ~${Math.ceil(t.localChars / 4)} tokens processed locally${\n\t\t\t\treport.curation.lastSkipReason ? ` · last skip: ${report.curation.lastSkipReason}` : \"\"\n\t\t\t}`,\n\t\t);\n\t}\n\tif (report.spawned && report.spawned.reports > 0) {\n\t\tlines.push(\n\t\t\t`spawned/background spend (NOT in this context): ${report.spawned.reports} report(s), $${report.spawned.cost.toFixed(4)}`,\n\t\t);\n\t}\n\tif (report.observations.length > 0) {\n\t\tlines.push(\"\", \"observations:\");\n\t\tfor (const observation of report.observations.slice(0, 5)) {\n\t\t\tlines.push(` ! ${observation}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Pure, provider-free context contracts.
3
+ *
4
+ * These types describe the curated working state the prompt builder will eventually
5
+ * consume, distinct from the immutable session transcript. Adding this module makes no
6
+ * behavior change: nothing here is wired into prompt construction yet.
7
+ */
8
+ export type ContextItemKind = "user_instruction" | "approval" | "denial" | "safety_constraint" | "goal_state" | "requirement" | "plan" | "blocker" | "evidence" | "invalidated_assumption" | "tool_output" | "tool_output_digest" | "file_snapshot" | "diff_summary" | "test_result" | "conversation_tail" | "retrieved_artifact" | "memory_item" | "memory_digest";
9
+ export type ContextRetentionClass = "pinned" | "active" | "decision_bearing" | "useful" | "ephemeral" | "expired";
10
+ export type ContextSource = "user" | "assistant" | "tool" | "runtime" | "session" | "memory" | "external_provider";
11
+ export interface ContextArtifactRef {
12
+ id: string;
13
+ kind: "tool_output" | "file_snapshot" | "test_output" | "diff" | "transcript_slice";
14
+ storagePath?: string;
15
+ sessionEntryId?: string;
16
+ toolName?: string;
17
+ command?: string;
18
+ path?: string;
19
+ byteLength: number;
20
+ lineCount?: number;
21
+ createdAtTurn: number;
22
+ reproducible: boolean;
23
+ }
24
+ export type MemoryScope = "session" | "project" | "user" | "global";
25
+ export interface ContextMemoryRef {
26
+ providerId: string;
27
+ itemId: string;
28
+ scope: MemoryScope;
29
+ kind: string;
30
+ uri?: string;
31
+ }
32
+ export interface ContextTranscriptRef {
33
+ sessionEntryId: string;
34
+ branchId?: string;
35
+ messageIndex?: number;
36
+ }
37
+ export type ContextEvidenceRef = {
38
+ type: "artifact";
39
+ ref: ContextArtifactRef;
40
+ } | {
41
+ type: "memory";
42
+ ref: ContextMemoryRef;
43
+ } | {
44
+ type: "transcript";
45
+ ref: ContextTranscriptRef;
46
+ } | {
47
+ type: "runtime";
48
+ id: string;
49
+ description: string;
50
+ };
51
+ export interface ContextItem {
52
+ id: string;
53
+ kind: ContextItemKind;
54
+ retentionClass: ContextRetentionClass;
55
+ source: ContextSource;
56
+ createdAtTurn: number;
57
+ lastUsedAtTurn?: number;
58
+ summary?: string;
59
+ content?: string;
60
+ primaryRef?: ContextEvidenceRef;
61
+ evidenceRefs?: ContextEvidenceRef[];
62
+ tokenEstimate: number;
63
+ byteEstimate: number;
64
+ supersededBy?: string;
65
+ invalidates?: string[];
66
+ pinReason?: string;
67
+ expiresAfterGoalId?: string;
68
+ }
69
+ export interface InvalidatedAssumptionItem {
70
+ id: string;
71
+ kind: "invalidated_assumption";
72
+ retentionClass: "decision_bearing" | "useful";
73
+ summary: string;
74
+ reason: string;
75
+ evidenceRefs: ContextEvidenceRef[];
76
+ expiresAfterGoalId?: string;
77
+ }
78
+ export type ModelRetentionAction = {
79
+ action: "keep";
80
+ itemId: string;
81
+ reason: string;
82
+ } | {
83
+ action: "summarize";
84
+ itemId: string;
85
+ summary: string;
86
+ reason: string;
87
+ evidenceRefs?: ContextEvidenceRef[];
88
+ } | {
89
+ action: "drop_from_prompt";
90
+ itemId: string;
91
+ reason: string;
92
+ } | {
93
+ action: "invalidate";
94
+ itemId: string;
95
+ summary: string;
96
+ reason: string;
97
+ evidenceRefs: ContextEvidenceRef[];
98
+ } | {
99
+ action: "pin_request";
100
+ itemId: string;
101
+ reason: string;
102
+ };
103
+ /**
104
+ * Kinds that are hard-retained regardless of retentionClass: their semantics must remain
105
+ * present in prompt context per the contracts-and-retention.md hard retention rules.
106
+ */
107
+ export declare const HARD_RETAINED_CONTEXT_KINDS: ReadonlySet<ContextItemKind>;
108
+ /** UTF-8 byte length, matching how the runtime measures raw payload size elsewhere. */
109
+ export declare function estimateByteLength(text: string): number;
110
+ export declare function estimateLineCount(text: string): number;
111
+ /**
112
+ * No-tokenizer sizing rule from policy-engine-spec.md: estimatedTokens = ceil(chars / 4).
113
+ * Calibrate against provider-reported usage post-call; never treat this as semantic criticality.
114
+ */
115
+ export declare function estimateTokensFromChars(charCount: number): number;
116
+ export declare function estimateTokensFromText(text: string): number;
117
+ //# sourceMappingURL=context-item.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-item.d.ts","sourceRoot":"","sources":["../../../src/core/context/context-item.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, provider-free context contracts.\n *\n * These types describe the curated working state the prompt builder will eventually\n * consume, distinct from the immutable session transcript. Adding this module makes no\n * behavior change: nothing here is wired into prompt construction yet.\n */\n\nexport type ContextItemKind =\n\t| \"user_instruction\"\n\t| \"approval\"\n\t| \"denial\"\n\t| \"safety_constraint\"\n\t| \"goal_state\"\n\t| \"requirement\"\n\t| \"plan\"\n\t| \"blocker\"\n\t| \"evidence\"\n\t| \"invalidated_assumption\"\n\t| \"tool_output\"\n\t| \"tool_output_digest\"\n\t| \"file_snapshot\"\n\t| \"diff_summary\"\n\t| \"test_result\"\n\t| \"conversation_tail\"\n\t| \"retrieved_artifact\"\n\t| \"memory_item\"\n\t| \"memory_digest\";\n\nexport type ContextRetentionClass = \"pinned\" | \"active\" | \"decision_bearing\" | \"useful\" | \"ephemeral\" | \"expired\";\n\nexport type ContextSource = \"user\" | \"assistant\" | \"tool\" | \"runtime\" | \"session\" | \"memory\" | \"external_provider\";\n\nexport interface ContextArtifactRef {\n\tid: string;\n\tkind: \"tool_output\" | \"file_snapshot\" | \"test_output\" | \"diff\" | \"transcript_slice\";\n\tstoragePath?: string;\n\tsessionEntryId?: string;\n\ttoolName?: string;\n\tcommand?: string;\n\tpath?: string;\n\tbyteLength: number;\n\tlineCount?: number;\n\tcreatedAtTurn: number;\n\treproducible: boolean;\n}\n\nexport type MemoryScope = \"session\" | \"project\" | \"user\" | \"global\";\n\nexport interface ContextMemoryRef {\n\tproviderId: string;\n\titemId: string;\n\tscope: MemoryScope;\n\tkind: string;\n\turi?: string;\n}\n\nexport interface ContextTranscriptRef {\n\tsessionEntryId: string;\n\tbranchId?: string;\n\tmessageIndex?: number;\n}\n\nexport type ContextEvidenceRef =\n\t| { type: \"artifact\"; ref: ContextArtifactRef }\n\t| { type: \"memory\"; ref: ContextMemoryRef }\n\t| { type: \"transcript\"; ref: ContextTranscriptRef }\n\t| { type: \"runtime\"; id: string; description: string };\n\nexport interface ContextItem {\n\tid: string;\n\tkind: ContextItemKind;\n\tretentionClass: ContextRetentionClass;\n\tsource: ContextSource;\n\tcreatedAtTurn: number;\n\tlastUsedAtTurn?: number;\n\tsummary?: string;\n\tcontent?: string;\n\tprimaryRef?: ContextEvidenceRef;\n\tevidenceRefs?: ContextEvidenceRef[];\n\ttokenEstimate: number;\n\tbyteEstimate: number;\n\tsupersededBy?: string;\n\tinvalidates?: string[];\n\tpinReason?: string;\n\texpiresAfterGoalId?: string;\n}\n\nexport interface InvalidatedAssumptionItem {\n\tid: string;\n\tkind: \"invalidated_assumption\";\n\tretentionClass: \"decision_bearing\" | \"useful\";\n\tsummary: string;\n\treason: string;\n\tevidenceRefs: ContextEvidenceRef[];\n\texpiresAfterGoalId?: string;\n}\n\nexport type ModelRetentionAction =\n\t| { action: \"keep\"; itemId: string; reason: string }\n\t| { action: \"summarize\"; itemId: string; summary: string; reason: string; evidenceRefs?: ContextEvidenceRef[] }\n\t| { action: \"drop_from_prompt\"; itemId: string; reason: string }\n\t| { action: \"invalidate\"; itemId: string; summary: string; reason: string; evidenceRefs: ContextEvidenceRef[] }\n\t| { action: \"pin_request\"; itemId: string; reason: string };\n\n/**\n * Kinds that are hard-retained regardless of retentionClass: their semantics must remain\n * present in prompt context per the contracts-and-retention.md hard retention rules.\n */\nexport const HARD_RETAINED_CONTEXT_KINDS: ReadonlySet<ContextItemKind> = new Set([\n\t\"user_instruction\",\n\t\"approval\",\n\t\"denial\",\n\t\"safety_constraint\",\n]);\n\nconst NO_TOKENIZER_CHARS_PER_TOKEN = 4;\n\n/** UTF-8 byte length, matching how the runtime measures raw payload size elsewhere. */\nexport function estimateByteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf8\");\n}\n\nexport function estimateLineCount(text: string): number {\n\treturn text.length === 0 ? 0 : text.split(\"\\n\").length;\n}\n\n/**\n * No-tokenizer sizing rule from policy-engine-spec.md: estimatedTokens = ceil(chars / 4).\n * Calibrate against provider-reported usage post-call; never treat this as semantic criticality.\n */\nexport function estimateTokensFromChars(charCount: number): number {\n\treturn Math.ceil(Math.max(0, charCount) / NO_TOKENIZER_CHARS_PER_TOKEN);\n}\n\nexport function estimateTokensFromText(text: string): number {\n\treturn estimateTokensFromChars(text.length);\n}\n"]}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Pure, provider-free context contracts.
3
+ *
4
+ * These types describe the curated working state the prompt builder will eventually
5
+ * consume, distinct from the immutable session transcript. Adding this module makes no
6
+ * behavior change: nothing here is wired into prompt construction yet.
7
+ */
8
+ /**
9
+ * Kinds that are hard-retained regardless of retentionClass: their semantics must remain
10
+ * present in prompt context per the contracts-and-retention.md hard retention rules.
11
+ */
12
+ export const HARD_RETAINED_CONTEXT_KINDS = new Set([
13
+ "user_instruction",
14
+ "approval",
15
+ "denial",
16
+ "safety_constraint",
17
+ ]);
18
+ const NO_TOKENIZER_CHARS_PER_TOKEN = 4;
19
+ /** UTF-8 byte length, matching how the runtime measures raw payload size elsewhere. */
20
+ export function estimateByteLength(text) {
21
+ return Buffer.byteLength(text, "utf8");
22
+ }
23
+ export function estimateLineCount(text) {
24
+ return text.length === 0 ? 0 : text.split("\n").length;
25
+ }
26
+ /**
27
+ * No-tokenizer sizing rule from policy-engine-spec.md: estimatedTokens = ceil(chars / 4).
28
+ * Calibrate against provider-reported usage post-call; never treat this as semantic criticality.
29
+ */
30
+ export function estimateTokensFromChars(charCount) {
31
+ return Math.ceil(Math.max(0, charCount) / NO_TOKENIZER_CHARS_PER_TOKEN);
32
+ }
33
+ export function estimateTokensFromText(text) {
34
+ return estimateTokensFromChars(text.length);
35
+ }
36
+ //# sourceMappingURL=context-item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-item.js","sourceRoot":"","sources":["../../../src/core/context/context-item.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmGH;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAiC,IAAI,GAAG,CAAC;IAChF,kBAAkB;IAClB,UAAU;IACV,QAAQ;IACR,mBAAmB;CACnB,CAAC,CAAC;AAEH,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAEvC,uFAAuF;AACvF,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAU;IACxD,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAAA,CACvC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAU;IACvD,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAAA,CACvD;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB,EAAU;IAClE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,4BAA4B,CAAC,CAAC;AAAA,CACxE;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAU;IAC5D,OAAO,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAAA,CAC5C","sourcesContent":["/**\n * Pure, provider-free context contracts.\n *\n * These types describe the curated working state the prompt builder will eventually\n * consume, distinct from the immutable session transcript. Adding this module makes no\n * behavior change: nothing here is wired into prompt construction yet.\n */\n\nexport type ContextItemKind =\n\t| \"user_instruction\"\n\t| \"approval\"\n\t| \"denial\"\n\t| \"safety_constraint\"\n\t| \"goal_state\"\n\t| \"requirement\"\n\t| \"plan\"\n\t| \"blocker\"\n\t| \"evidence\"\n\t| \"invalidated_assumption\"\n\t| \"tool_output\"\n\t| \"tool_output_digest\"\n\t| \"file_snapshot\"\n\t| \"diff_summary\"\n\t| \"test_result\"\n\t| \"conversation_tail\"\n\t| \"retrieved_artifact\"\n\t| \"memory_item\"\n\t| \"memory_digest\";\n\nexport type ContextRetentionClass = \"pinned\" | \"active\" | \"decision_bearing\" | \"useful\" | \"ephemeral\" | \"expired\";\n\nexport type ContextSource = \"user\" | \"assistant\" | \"tool\" | \"runtime\" | \"session\" | \"memory\" | \"external_provider\";\n\nexport interface ContextArtifactRef {\n\tid: string;\n\tkind: \"tool_output\" | \"file_snapshot\" | \"test_output\" | \"diff\" | \"transcript_slice\";\n\tstoragePath?: string;\n\tsessionEntryId?: string;\n\ttoolName?: string;\n\tcommand?: string;\n\tpath?: string;\n\tbyteLength: number;\n\tlineCount?: number;\n\tcreatedAtTurn: number;\n\treproducible: boolean;\n}\n\nexport type MemoryScope = \"session\" | \"project\" | \"user\" | \"global\";\n\nexport interface ContextMemoryRef {\n\tproviderId: string;\n\titemId: string;\n\tscope: MemoryScope;\n\tkind: string;\n\turi?: string;\n}\n\nexport interface ContextTranscriptRef {\n\tsessionEntryId: string;\n\tbranchId?: string;\n\tmessageIndex?: number;\n}\n\nexport type ContextEvidenceRef =\n\t| { type: \"artifact\"; ref: ContextArtifactRef }\n\t| { type: \"memory\"; ref: ContextMemoryRef }\n\t| { type: \"transcript\"; ref: ContextTranscriptRef }\n\t| { type: \"runtime\"; id: string; description: string };\n\nexport interface ContextItem {\n\tid: string;\n\tkind: ContextItemKind;\n\tretentionClass: ContextRetentionClass;\n\tsource: ContextSource;\n\tcreatedAtTurn: number;\n\tlastUsedAtTurn?: number;\n\tsummary?: string;\n\tcontent?: string;\n\tprimaryRef?: ContextEvidenceRef;\n\tevidenceRefs?: ContextEvidenceRef[];\n\ttokenEstimate: number;\n\tbyteEstimate: number;\n\tsupersededBy?: string;\n\tinvalidates?: string[];\n\tpinReason?: string;\n\texpiresAfterGoalId?: string;\n}\n\nexport interface InvalidatedAssumptionItem {\n\tid: string;\n\tkind: \"invalidated_assumption\";\n\tretentionClass: \"decision_bearing\" | \"useful\";\n\tsummary: string;\n\treason: string;\n\tevidenceRefs: ContextEvidenceRef[];\n\texpiresAfterGoalId?: string;\n}\n\nexport type ModelRetentionAction =\n\t| { action: \"keep\"; itemId: string; reason: string }\n\t| { action: \"summarize\"; itemId: string; summary: string; reason: string; evidenceRefs?: ContextEvidenceRef[] }\n\t| { action: \"drop_from_prompt\"; itemId: string; reason: string }\n\t| { action: \"invalidate\"; itemId: string; summary: string; reason: string; evidenceRefs: ContextEvidenceRef[] }\n\t| { action: \"pin_request\"; itemId: string; reason: string };\n\n/**\n * Kinds that are hard-retained regardless of retentionClass: their semantics must remain\n * present in prompt context per the contracts-and-retention.md hard retention rules.\n */\nexport const HARD_RETAINED_CONTEXT_KINDS: ReadonlySet<ContextItemKind> = new Set([\n\t\"user_instruction\",\n\t\"approval\",\n\t\"denial\",\n\t\"safety_constraint\",\n]);\n\nconst NO_TOKENIZER_CHARS_PER_TOKEN = 4;\n\n/** UTF-8 byte length, matching how the runtime measures raw payload size elsewhere. */\nexport function estimateByteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf8\");\n}\n\nexport function estimateLineCount(text: string): number {\n\treturn text.length === 0 ? 0 : text.split(\"\\n\").length;\n}\n\n/**\n * No-tokenizer sizing rule from policy-engine-spec.md: estimatedTokens = ceil(chars / 4).\n * Calibrate against provider-reported usage post-call; never treat this as semantic criticality.\n */\nexport function estimateTokensFromChars(charCount: number): number {\n\treturn Math.ceil(Math.max(0, charCount) / NO_TOKENIZER_CHARS_PER_TOKEN);\n}\n\nexport function estimateTokensFromText(text: string): number {\n\treturn estimateTokensFromChars(text.length);\n}\n"]}