@clinebot/core 0.0.27 → 0.0.29

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 (339) hide show
  1. package/README.md +7 -0
  2. package/dist/ClineCore.d.ts +28 -2
  3. package/dist/ClineCore.d.ts.map +1 -1
  4. package/dist/account/cline-account-service.d.ts +1 -1
  5. package/dist/account/cline-account-service.d.ts.map +1 -1
  6. package/dist/account/index.d.ts +1 -1
  7. package/dist/account/index.d.ts.map +1 -1
  8. package/dist/account/types.d.ts +5 -0
  9. package/dist/account/types.d.ts.map +1 -1
  10. package/dist/auth/bounded-ttl-cache.d.ts +14 -0
  11. package/dist/auth/bounded-ttl-cache.d.ts.map +1 -0
  12. package/dist/auth/cline.d.ts +27 -2
  13. package/dist/auth/cline.d.ts.map +1 -1
  14. package/dist/auth/oca.d.ts.map +1 -1
  15. package/dist/chat/chat-schema.d.ts +8 -8
  16. package/dist/extensions/config/agent-config-loader.d.ts.map +1 -0
  17. package/dist/{agents → extensions/config}/agent-config-parser.d.ts +2 -2
  18. package/dist/extensions/config/agent-config-parser.d.ts.map +1 -0
  19. package/dist/{agents → extensions/config}/hooks-config-loader.d.ts +1 -1
  20. package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -0
  21. package/dist/{agents → extensions/config}/index.d.ts +2 -4
  22. package/dist/extensions/config/index.d.ts.map +1 -0
  23. package/dist/{runtime/commands.d.ts → extensions/config/runtime-commands.d.ts} +2 -3
  24. package/dist/extensions/config/runtime-commands.d.ts.map +1 -0
  25. package/dist/extensions/config/unified-config-file-watcher.d.ts.map +1 -0
  26. package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -0
  27. package/dist/extensions/context/agentic-compaction.d.ts +13 -0
  28. package/dist/extensions/context/agentic-compaction.d.ts.map +1 -0
  29. package/dist/extensions/context/basic-compaction.d.ts +9 -0
  30. package/dist/extensions/context/basic-compaction.d.ts.map +1 -0
  31. package/dist/extensions/context/compaction-shared.d.ts +60 -0
  32. package/dist/extensions/context/compaction-shared.d.ts.map +1 -0
  33. package/dist/extensions/context/compaction.d.ts +20 -0
  34. package/dist/extensions/context/compaction.d.ts.map +1 -0
  35. package/dist/extensions/index.d.ts +5 -0
  36. package/dist/extensions/index.d.ts.map +1 -0
  37. package/dist/extensions/mcp/client.d.ts +3 -0
  38. package/dist/extensions/mcp/client.d.ts.map +1 -0
  39. package/dist/extensions/mcp/config-loader.d.ts.map +1 -0
  40. package/dist/extensions/mcp/index.d.ts +9 -0
  41. package/dist/extensions/mcp/index.d.ts.map +1 -0
  42. package/dist/{mcp → extensions/mcp}/manager.d.ts +1 -2
  43. package/dist/extensions/mcp/manager.d.ts.map +1 -0
  44. package/dist/extensions/mcp/name-transform.d.ts +3 -0
  45. package/dist/extensions/mcp/name-transform.d.ts.map +1 -0
  46. package/dist/extensions/mcp/policies.d.ts +15 -0
  47. package/dist/extensions/mcp/policies.d.ts.map +1 -0
  48. package/dist/extensions/mcp/tools.d.ts +4 -0
  49. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  50. package/dist/{mcp → extensions/mcp}/types.d.ts +29 -1
  51. package/dist/extensions/mcp/types.d.ts.map +1 -0
  52. package/dist/{agents → extensions/plugin}/plugin-config-loader.d.ts +1 -1
  53. package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -0
  54. package/dist/{agents → extensions/plugin}/plugin-loader.d.ts +1 -1
  55. package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -0
  56. package/dist/extensions/plugin/plugin-module-import.d.ts +5 -0
  57. package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -0
  58. package/dist/{agents → extensions/plugin}/plugin-sandbox.d.ts +1 -1
  59. package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -0
  60. package/dist/extensions/plugin-sandbox-bootstrap.js +485 -0
  61. package/dist/hooks/index.d.ts +4 -0
  62. package/dist/hooks/index.d.ts.map +1 -0
  63. package/dist/hooks/persistent.d.ts +64 -0
  64. package/dist/hooks/persistent.d.ts.map +1 -0
  65. package/dist/hooks/subprocess-runner.d.ts +22 -0
  66. package/dist/hooks/subprocess-runner.d.ts.map +1 -0
  67. package/dist/hooks/subprocess.d.ts +189 -0
  68. package/dist/hooks/subprocess.d.ts.map +1 -0
  69. package/dist/index.d.ts +22 -25
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +560 -447
  72. package/dist/prompt/default-system.d.ts +2 -0
  73. package/dist/prompt/default-system.d.ts.map +1 -0
  74. package/dist/providers/local-provider-service.d.ts +1 -1
  75. package/dist/providers/local-provider-service.d.ts.map +1 -1
  76. package/dist/runtime/checkpoint-hooks.d.ts +21 -0
  77. package/dist/runtime/checkpoint-hooks.d.ts.map +1 -0
  78. package/dist/runtime/hook-file-hooks.d.ts +1 -1
  79. package/dist/runtime/hook-file-hooks.d.ts.map +1 -1
  80. package/dist/runtime/rules.d.ts +1 -1
  81. package/dist/runtime/rules.d.ts.map +1 -1
  82. package/dist/runtime/runtime-builder.d.ts +1 -1
  83. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  84. package/dist/runtime/session-runtime.d.ts +25 -5
  85. package/dist/runtime/session-runtime.d.ts.map +1 -1
  86. package/dist/runtime/subprocess-sandbox.d.ts.map +1 -0
  87. package/dist/runtime/team-runtime-registry.d.ts +1 -1
  88. package/dist/runtime/team-runtime-registry.d.ts.map +1 -1
  89. package/dist/runtime/tool-approval.d.ts +1 -1
  90. package/dist/session/default-session-manager.d.ts +4 -3
  91. package/dist/session/default-session-manager.d.ts.map +1 -1
  92. package/dist/session/file-session-service.d.ts +1 -1
  93. package/dist/session/file-session-service.d.ts.map +1 -1
  94. package/dist/session/{unified-session-persistence-service.d.ts → persistence-service.d.ts} +11 -42
  95. package/dist/session/persistence-service.d.ts.map +1 -0
  96. package/dist/session/rpc-session-service.d.ts +1 -1
  97. package/dist/session/rpc-session-service.d.ts.map +1 -1
  98. package/dist/session/session-agent-events.d.ts +1 -1
  99. package/dist/session/session-artifacts.d.ts.map +1 -1
  100. package/dist/session/session-config-builder.d.ts.map +1 -1
  101. package/dist/session/session-graph.d.ts +1 -1
  102. package/dist/session/session-graph.d.ts.map +1 -1
  103. package/dist/session/session-host.d.ts.map +1 -1
  104. package/dist/session/session-manager.d.ts +6 -5
  105. package/dist/session/session-manager.d.ts.map +1 -1
  106. package/dist/session/session-manifest.d.ts +1 -1
  107. package/dist/session/session-service.d.ts +3 -2
  108. package/dist/session/session-service.d.ts.map +1 -1
  109. package/dist/session/session-team-coordination.d.ts +2 -1
  110. package/dist/session/session-team-coordination.d.ts.map +1 -1
  111. package/dist/session/utils/helpers.d.ts +51 -3
  112. package/dist/session/utils/helpers.d.ts.map +1 -1
  113. package/dist/session/utils/types.d.ts +41 -7
  114. package/dist/session/utils/types.d.ts.map +1 -1
  115. package/dist/session/workspace-manager.d.ts +1 -2
  116. package/dist/session/workspace-manager.d.ts.map +1 -1
  117. package/dist/session/workspace-manifest.d.ts +1 -22
  118. package/dist/session/workspace-manifest.d.ts.map +1 -1
  119. package/dist/storage/file-team-store.d.ts +2 -1
  120. package/dist/storage/file-team-store.d.ts.map +1 -1
  121. package/dist/storage/sqlite-team-store.d.ts +4 -1
  122. package/dist/storage/sqlite-team-store.d.ts.map +1 -1
  123. package/dist/storage/team-store.d.ts.map +1 -1
  124. package/dist/team/delegated-agent.d.ts +44 -0
  125. package/dist/team/delegated-agent.d.ts.map +1 -0
  126. package/dist/team/index.d.ts +1 -0
  127. package/dist/team/index.d.ts.map +1 -1
  128. package/dist/team/multi-agent.d.ts +229 -0
  129. package/dist/team/multi-agent.d.ts.map +1 -0
  130. package/dist/team/projections.d.ts +2 -2
  131. package/dist/team/projections.d.ts.map +1 -1
  132. package/dist/team/runtime.d.ts +5 -0
  133. package/dist/team/runtime.d.ts.map +1 -0
  134. package/dist/team/spawn-agent-tool.d.ts +85 -0
  135. package/dist/team/spawn-agent-tool.d.ts.map +1 -0
  136. package/dist/team/subagent-prompts.d.ts +4 -0
  137. package/dist/team/subagent-prompts.d.ts.map +1 -0
  138. package/dist/team/team-tools.d.ts +35 -0
  139. package/dist/team/team-tools.d.ts.map +1 -0
  140. package/dist/telemetry/OpenTelemetryProvider.d.ts +11 -1
  141. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
  142. package/dist/telemetry/{LoggerTelemetryAdapter.d.ts → TelemetryLoggerSink.d.ts} +10 -4
  143. package/dist/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
  144. package/dist/telemetry/TelemetryService.d.ts.map +1 -1
  145. package/dist/telemetry/index.js +15 -28
  146. package/dist/tools/definitions.d.ts +4 -3
  147. package/dist/tools/definitions.d.ts.map +1 -1
  148. package/dist/tools/index.d.ts +5 -5
  149. package/dist/tools/index.d.ts.map +1 -1
  150. package/dist/tools/model-tool-routing.d.ts.map +1 -1
  151. package/dist/tools/presets.d.ts +26 -0
  152. package/dist/tools/presets.d.ts.map +1 -1
  153. package/dist/tools/schemas.d.ts +8 -0
  154. package/dist/tools/schemas.d.ts.map +1 -1
  155. package/dist/tools/types.d.ts +23 -2
  156. package/dist/tools/types.d.ts.map +1 -1
  157. package/dist/types/config.d.ts +47 -3
  158. package/dist/types/config.d.ts.map +1 -1
  159. package/dist/types/events.d.ts +1 -1
  160. package/dist/types/provider-settings.d.ts +1 -1
  161. package/dist/types/provider-settings.d.ts.map +1 -1
  162. package/dist/types/storage.d.ts +2 -1
  163. package/dist/types/storage.d.ts.map +1 -1
  164. package/dist/types.d.ts +7 -16
  165. package/dist/types.d.ts.map +1 -1
  166. package/package.json +16 -13
  167. package/src/ClineCore.test.ts +150 -0
  168. package/src/ClineCore.ts +114 -8
  169. package/src/account/cline-account-service.test.ts +84 -0
  170. package/src/account/cline-account-service.ts +2 -2
  171. package/src/account/index.ts +1 -0
  172. package/src/account/types.ts +6 -0
  173. package/src/auth/bounded-ttl-cache.test.ts +38 -0
  174. package/src/auth/bounded-ttl-cache.ts +53 -0
  175. package/src/auth/cline.test.ts +173 -36
  176. package/src/auth/cline.ts +395 -93
  177. package/src/auth/oca.test.ts +125 -0
  178. package/src/auth/oca.ts +17 -4
  179. package/src/{agents → extensions/config}/agent-config-loader.test.ts +1 -1
  180. package/src/{agents → extensions/config}/agent-config-parser.ts +2 -2
  181. package/src/{agents → extensions/config}/hooks-config-loader.ts +1 -1
  182. package/src/{agents → extensions/config}/index.ts +7 -11
  183. package/src/{runtime/commands.test.ts → extensions/config/runtime-commands.test.ts} +20 -3
  184. package/src/{runtime/commands.ts → extensions/config/runtime-commands.ts} +1 -8
  185. package/src/{agents → extensions/config}/unified-config-file-watcher.ts +15 -2
  186. package/src/{agents → extensions/config}/user-instruction-config-loader.test.ts +90 -2
  187. package/src/{agents → extensions/config}/user-instruction-config-loader.ts +126 -12
  188. package/src/extensions/context/agentic-compaction.ts +119 -0
  189. package/src/extensions/context/basic-compaction.ts +275 -0
  190. package/src/extensions/context/compaction-shared.ts +458 -0
  191. package/src/extensions/context/compaction.test.ts +477 -0
  192. package/src/extensions/context/compaction.ts +203 -0
  193. package/src/extensions/index.ts +12 -0
  194. package/src/extensions/mcp/client.ts +420 -0
  195. package/src/{mcp → extensions/mcp}/index.ts +16 -0
  196. package/src/{mcp → extensions/mcp}/manager.test.ts +1 -2
  197. package/src/{mcp → extensions/mcp}/manager.ts +3 -5
  198. package/src/extensions/mcp/name-transform.ts +33 -0
  199. package/src/extensions/mcp/policies.ts +47 -0
  200. package/src/extensions/mcp/tools.ts +47 -0
  201. package/src/{mcp → extensions/mcp}/types.ts +35 -7
  202. package/src/{agents → extensions/plugin}/plugin-config-loader.test.ts +18 -13
  203. package/src/{agents → extensions/plugin}/plugin-config-loader.ts +1 -1
  204. package/src/{agents → extensions/plugin}/plugin-loader.test.ts +41 -4
  205. package/src/extensions/plugin/plugin-loader.ts +106 -0
  206. package/src/extensions/plugin/plugin-module-import.ts +278 -0
  207. package/src/{agents → extensions/plugin}/plugin-sandbox-bootstrap.ts +30 -92
  208. package/src/{agents → extensions/plugin}/plugin-sandbox.test.ts +60 -3
  209. package/src/{agents → extensions/plugin}/plugin-sandbox.ts +146 -56
  210. package/src/hooks/index.ts +25 -0
  211. package/src/hooks/persistent.ts +661 -0
  212. package/src/hooks/subprocess-runner.ts +196 -0
  213. package/src/hooks/subprocess.ts +669 -0
  214. package/src/index.ts +200 -118
  215. package/src/prompt/default-system.ts +21 -0
  216. package/src/providers/local-provider-registry.ts +1 -1
  217. package/src/providers/local-provider-service.test.ts +23 -2
  218. package/src/providers/local-provider-service.ts +2 -2
  219. package/src/runtime/checkpoint-hooks.test.ts +167 -0
  220. package/src/runtime/checkpoint-hooks.ts +186 -0
  221. package/src/runtime/hook-file-hooks.test.ts +40 -1
  222. package/src/runtime/hook-file-hooks.ts +35 -16
  223. package/src/runtime/index.ts +4 -19
  224. package/src/runtime/rules.ts +4 -1
  225. package/src/runtime/runtime-builder.team-persistence.test.ts +3 -6
  226. package/src/runtime/runtime-builder.test.ts +266 -160
  227. package/src/runtime/runtime-builder.ts +120 -47
  228. package/src/runtime/runtime-parity.test.ts +22 -22
  229. package/src/runtime/session-runtime.ts +36 -6
  230. package/src/runtime/{sandbox/subprocess-sandbox.ts → subprocess-sandbox.ts} +24 -3
  231. package/src/runtime/team-runtime-registry.ts +1 -4
  232. package/src/runtime/tool-approval.ts +1 -1
  233. package/src/session/default-session-manager.e2e.test.ts +2 -2
  234. package/src/session/default-session-manager.test.ts +553 -9
  235. package/src/session/default-session-manager.ts +140 -46
  236. package/src/session/file-session-service.ts +3 -3
  237. package/src/session/index.ts +6 -6
  238. package/src/session/persistence-service.test.ts +212 -0
  239. package/src/session/{unified-session-persistence-service.ts → persistence-service.ts} +106 -172
  240. package/src/session/rpc-session-service.ts +3 -3
  241. package/src/session/runtime-oauth-token-manager.ts +1 -1
  242. package/src/session/session-agent-events.ts +1 -1
  243. package/src/session/session-artifacts.ts +32 -4
  244. package/src/session/session-config-builder.ts +22 -9
  245. package/src/session/session-graph.ts +1 -1
  246. package/src/session/session-host.ts +19 -11
  247. package/src/session/session-manager.ts +11 -6
  248. package/src/session/session-service.team-persistence.test.ts +1 -1
  249. package/src/session/session-service.ts +6 -9
  250. package/src/session/session-team-coordination.ts +7 -3
  251. package/src/session/session-telemetry.ts +1 -1
  252. package/src/session/utils/helpers.test.ts +160 -0
  253. package/src/session/utils/helpers.ts +289 -42
  254. package/src/session/utils/types.ts +47 -7
  255. package/src/session/workspace-manager.ts +5 -3
  256. package/src/session/workspace-manifest.ts +3 -49
  257. package/src/storage/file-team-store.ts +2 -5
  258. package/src/storage/provider-settings-legacy-migration.ts +2 -2
  259. package/src/storage/provider-settings-manager.test.ts +1 -1
  260. package/src/storage/sqlite-team-store.ts +212 -125
  261. package/src/storage/team-store.ts +1 -5
  262. package/src/team/delegated-agent.ts +131 -0
  263. package/src/team/index.ts +1 -0
  264. package/src/team/multi-agent.lifecycle.test.ts +201 -0
  265. package/src/team/multi-agent.ts +1666 -0
  266. package/src/team/projections.ts +2 -4
  267. package/src/team/runtime.ts +54 -0
  268. package/src/team/spawn-agent-tool.test.ts +387 -0
  269. package/src/team/spawn-agent-tool.ts +207 -0
  270. package/src/team/subagent-prompts.ts +41 -0
  271. package/src/team/team-tools.test.ts +802 -0
  272. package/src/team/team-tools.ts +792 -0
  273. package/src/telemetry/OpenTelemetryProvider.test.ts +25 -3
  274. package/src/telemetry/OpenTelemetryProvider.ts +108 -18
  275. package/src/telemetry/TelemetryLoggerSink.test.ts +42 -0
  276. package/src/telemetry/{LoggerTelemetryAdapter.ts → TelemetryLoggerSink.ts} +21 -14
  277. package/src/telemetry/TelemetryService.test.ts +7 -7
  278. package/src/telemetry/TelemetryService.ts +2 -4
  279. package/src/tools/definitions.test.ts +76 -0
  280. package/src/tools/definitions.ts +41 -2
  281. package/src/tools/executors/apply-patch.ts +1 -1
  282. package/src/tools/executors/editor.ts +1 -1
  283. package/src/tools/executors/file-read.ts +1 -1
  284. package/src/tools/executors/search.ts +1 -1
  285. package/src/tools/executors/web-fetch.ts +1 -1
  286. package/src/tools/index.ts +6 -1
  287. package/src/tools/model-tool-routing.ts +2 -0
  288. package/src/tools/presets.test.ts +8 -0
  289. package/src/tools/presets.ts +40 -2
  290. package/src/tools/schemas.ts +19 -0
  291. package/src/tools/types.ts +31 -2
  292. package/src/types/config.ts +61 -7
  293. package/src/types/events.ts +1 -1
  294. package/src/types/index.ts +0 -1
  295. package/src/types/provider-settings.ts +1 -1
  296. package/src/types/storage.ts +2 -5
  297. package/src/types.ts +32 -44
  298. package/dist/agents/agent-config-loader.d.ts.map +0 -1
  299. package/dist/agents/agent-config-parser.d.ts.map +0 -1
  300. package/dist/agents/hooks-config-loader.d.ts.map +0 -1
  301. package/dist/agents/index.d.ts.map +0 -1
  302. package/dist/agents/plugin-config-loader.d.ts.map +0 -1
  303. package/dist/agents/plugin-loader.d.ts.map +0 -1
  304. package/dist/agents/plugin-sandbox-bootstrap.js +0 -446
  305. package/dist/agents/plugin-sandbox.d.ts.map +0 -1
  306. package/dist/agents/unified-config-file-watcher.d.ts.map +0 -1
  307. package/dist/agents/user-instruction-config-loader.d.ts.map +0 -1
  308. package/dist/mcp/config-loader.d.ts.map +0 -1
  309. package/dist/mcp/index.d.ts +0 -5
  310. package/dist/mcp/index.d.ts.map +0 -1
  311. package/dist/mcp/manager.d.ts.map +0 -1
  312. package/dist/mcp/types.d.ts.map +0 -1
  313. package/dist/runtime/commands.d.ts.map +0 -1
  314. package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +0 -1
  315. package/dist/runtime/skills.d.ts +0 -14
  316. package/dist/runtime/skills.d.ts.map +0 -1
  317. package/dist/runtime/workflows.d.ts +0 -14
  318. package/dist/runtime/workflows.d.ts.map +0 -1
  319. package/dist/session/unified-session-persistence-service.d.ts.map +0 -1
  320. package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +0 -1
  321. package/dist/types/workspace.d.ts +0 -8
  322. package/dist/types/workspace.d.ts.map +0 -1
  323. package/src/agents/plugin-loader.ts +0 -175
  324. package/src/runtime/skills.ts +0 -44
  325. package/src/runtime/workflows.test.ts +0 -119
  326. package/src/runtime/workflows.ts +0 -45
  327. package/src/session/unified-session-persistence-service.test.ts +0 -85
  328. package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
  329. package/src/types/workspace.ts +0 -7
  330. /package/dist/{agents → extensions/config}/agent-config-loader.d.ts +0 -0
  331. /package/dist/{agents → extensions/config}/unified-config-file-watcher.d.ts +0 -0
  332. /package/dist/{agents → extensions/config}/user-instruction-config-loader.d.ts +0 -0
  333. /package/dist/{mcp → extensions/mcp}/config-loader.d.ts +0 -0
  334. /package/dist/runtime/{sandbox/subprocess-sandbox.d.ts → subprocess-sandbox.d.ts} +0 -0
  335. /package/src/{agents → extensions/config}/agent-config-loader.ts +0 -0
  336. /package/src/{agents → extensions/config}/hooks-config-loader.test.ts +0 -0
  337. /package/src/{agents → extensions/config}/unified-config-file-watcher.test.ts +0 -0
  338. /package/src/{mcp → extensions/mcp}/config-loader.test.ts +0 -0
  339. /package/src/{mcp → extensions/mcp}/config-loader.ts +0 -0
@@ -0,0 +1,477 @@
1
+ import type * as LlmsProviders from "@clinebot/llms";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { createContextCompactionPrepareTurn } from "./compaction";
4
+
5
+ type FakeChunk = Record<string, unknown>;
6
+
7
+ const createHandlerMock = vi.fn();
8
+
9
+ vi.mock("@clinebot/llms", () => ({
10
+ createHandler: (config: unknown) => createHandlerMock(config),
11
+ }));
12
+
13
+ async function* streamChunks(chunks: FakeChunk[]): AsyncGenerator<FakeChunk> {
14
+ for (const chunk of chunks) {
15
+ yield chunk;
16
+ }
17
+ }
18
+
19
+ describe("createContextCompactionPrepareTurn", () => {
20
+ beforeEach(() => {
21
+ vi.clearAllMocks();
22
+ });
23
+
24
+ it("summarizes older messages and keeps recent messages", async () => {
25
+ const emitStatusNotice = vi.fn();
26
+ createHandlerMock.mockReturnValue({
27
+ createMessage: vi.fn(() =>
28
+ streamChunks([
29
+ {
30
+ type: "text",
31
+ id: "summary-1",
32
+ text: "## Goal\nShip the feature\n\n## Next\n- Finish it",
33
+ },
34
+ { type: "done", id: "summary-1", success: true },
35
+ ]),
36
+ ),
37
+ });
38
+
39
+ const prepareTurn = createContextCompactionPrepareTurn({
40
+ providerId: "anthropic",
41
+ modelId: "mock-model",
42
+ providerConfig: {
43
+ providerId: "anthropic",
44
+ modelId: "mock-model",
45
+ } as LlmsProviders.ProviderConfig,
46
+ compaction: {
47
+ enabled: true,
48
+ strategy: "agentic",
49
+ preserveRecentTokens: 1,
50
+ reserveTokens: 5,
51
+ },
52
+ logger: undefined,
53
+ });
54
+
55
+ const result = await prepareTurn?.({
56
+ agentId: "agent-1",
57
+ conversationId: "conv-1",
58
+ parentAgentId: null,
59
+ iteration: 1,
60
+ abortSignal: new AbortController().signal,
61
+ emitStatusNotice,
62
+ systemPrompt: "You are helpful.",
63
+ tools: [],
64
+ messages: [
65
+ { role: "user", content: "Old turn to compact" },
66
+ { role: "assistant", content: "Old answer" },
67
+ { role: "user", content: "Implement the change" },
68
+ {
69
+ role: "assistant",
70
+ content: [
71
+ {
72
+ type: "tool_use",
73
+ id: "tool-1",
74
+ name: "read_files",
75
+ input: { file_paths: ["/tmp/example.ts"] },
76
+ },
77
+ ],
78
+ },
79
+ {
80
+ role: "user",
81
+ content: [
82
+ {
83
+ type: "tool_result",
84
+ tool_use_id: "tool-1",
85
+ content: "file contents",
86
+ },
87
+ ],
88
+ },
89
+ { role: "assistant", content: "Recent assistant state" },
90
+ ],
91
+ apiMessages: [
92
+ { role: "user", content: "Old turn to compact" },
93
+ { role: "assistant", content: "Old answer" },
94
+ { role: "user", content: "Implement the change" },
95
+ {
96
+ role: "assistant",
97
+ content: [
98
+ {
99
+ type: "tool_use",
100
+ id: "tool-1",
101
+ name: "read_files",
102
+ input: { file_paths: ["/tmp/example.ts"] },
103
+ },
104
+ ],
105
+ },
106
+ {
107
+ role: "user",
108
+ content: [
109
+ {
110
+ type: "tool_result",
111
+ tool_use_id: "tool-1",
112
+ content: "file contents",
113
+ },
114
+ ],
115
+ },
116
+ { role: "assistant", content: "Recent assistant state" },
117
+ ],
118
+ model: {
119
+ id: "mock-model",
120
+ provider: "anthropic",
121
+ info: { id: "mock-model", contextWindow: 10 },
122
+ },
123
+ });
124
+
125
+ expect(createHandlerMock).toHaveBeenCalledTimes(1);
126
+ expect(emitStatusNotice).toHaveBeenCalledWith(
127
+ "auto-compacting",
128
+ expect.objectContaining({
129
+ kind: "auto_compaction",
130
+ reason: "auto_compaction",
131
+ iteration: 1,
132
+ }),
133
+ );
134
+ expect(result?.messages).toHaveLength(5);
135
+ expect(result?.messages[0]).toMatchObject({
136
+ role: "user",
137
+ metadata: expect.objectContaining({
138
+ kind: "compaction_summary",
139
+ details: {
140
+ readFiles: [],
141
+ modifiedFiles: [],
142
+ },
143
+ }),
144
+ });
145
+ expect(typeof result?.messages[0]?.content).toBe("string");
146
+ const summaryContent = result?.messages[0]?.content as string;
147
+ expect(summaryContent).toContain("Context summary:");
148
+ expect(summaryContent).toContain("## Files");
149
+ expect(result?.messages[1]).toEqual({
150
+ role: "user",
151
+ content: "Implement the change",
152
+ });
153
+ expect(result?.messages[4]).toEqual({
154
+ role: "assistant",
155
+ content: "Recent assistant state",
156
+ });
157
+ });
158
+
159
+ it("uses the configured summarizer model for compaction", async () => {
160
+ createHandlerMock.mockReturnValue({
161
+ createMessage: vi.fn(() =>
162
+ streamChunks([
163
+ { type: "text", id: "summary-3", text: "## Goal\nSummarized" },
164
+ { type: "done", id: "summary-3", success: true },
165
+ ]),
166
+ ),
167
+ });
168
+
169
+ const prepareTurn = createContextCompactionPrepareTurn({
170
+ providerId: "anthropic",
171
+ modelId: "primary-model",
172
+ providerConfig: {
173
+ providerId: "anthropic",
174
+ modelId: "primary-model",
175
+ } as LlmsProviders.ProviderConfig,
176
+ compaction: {
177
+ enabled: true,
178
+ strategy: "agentic",
179
+ preserveRecentTokens: 1,
180
+ reserveTokens: 5,
181
+ summarizer: {
182
+ providerId: "openai",
183
+ modelId: "gpt-summary",
184
+ maxOutputTokens: 512,
185
+ },
186
+ },
187
+ logger: undefined,
188
+ });
189
+
190
+ await prepareTurn?.({
191
+ agentId: "agent-1",
192
+ conversationId: "conv-1",
193
+ parentAgentId: null,
194
+ iteration: 1,
195
+ abortSignal: new AbortController().signal,
196
+ systemPrompt: "You are helpful.",
197
+ tools: [],
198
+ messages: [
199
+ { role: "user", content: "Old turn" },
200
+ { role: "assistant", content: "Old answer" },
201
+ { role: "user", content: "Latest turn" },
202
+ { role: "assistant", content: "Latest answer" },
203
+ ],
204
+ apiMessages: [
205
+ { role: "user", content: "Old turn" },
206
+ { role: "assistant", content: "Old answer" },
207
+ { role: "user", content: "Latest turn" },
208
+ { role: "assistant", content: "Latest answer" },
209
+ ],
210
+ model: {
211
+ id: "primary-model",
212
+ provider: "anthropic",
213
+ info: { id: "primary-model", contextWindow: 10 },
214
+ },
215
+ });
216
+
217
+ expect(createHandlerMock).toHaveBeenCalledWith(
218
+ expect.objectContaining({
219
+ providerId: "openai",
220
+ modelId: "gpt-summary",
221
+ maxOutputTokens: 512,
222
+ thinking: false,
223
+ }),
224
+ );
225
+ });
226
+
227
+ it("uses basic compaction without calling the summarizer", async () => {
228
+ const emitStatusNotice = vi.fn();
229
+ const prepareTurn = createContextCompactionPrepareTurn({
230
+ providerId: "anthropic",
231
+ modelId: "mock-model",
232
+ providerConfig: {
233
+ providerId: "anthropic",
234
+ modelId: "mock-model",
235
+ } as LlmsProviders.ProviderConfig,
236
+ compaction: {
237
+ enabled: true,
238
+ strategy: "basic",
239
+ reserveTokens: 5,
240
+ },
241
+ logger: undefined,
242
+ });
243
+
244
+ const result = await prepareTurn?.({
245
+ agentId: "agent-1",
246
+ conversationId: "conv-1",
247
+ parentAgentId: null,
248
+ iteration: 1,
249
+ abortSignal: new AbortController().signal,
250
+ emitStatusNotice,
251
+ systemPrompt: "You are helpful.",
252
+ tools: [],
253
+ messages: [
254
+ { role: "user", content: "Initial request that should survive" },
255
+ {
256
+ role: "assistant",
257
+ content: [
258
+ { type: "thinking", thinking: "internal reasoning" },
259
+ { type: "text", text: "Older assistant explanation" },
260
+ {
261
+ type: "tool_use",
262
+ id: "tool-1",
263
+ name: "read_files",
264
+ input: { file_paths: ["/tmp/example.ts"] },
265
+ },
266
+ ],
267
+ },
268
+ {
269
+ role: "user",
270
+ content: [
271
+ {
272
+ type: "tool_result",
273
+ tool_use_id: "tool-1",
274
+ content: "tool output that should be removed",
275
+ },
276
+ ],
277
+ },
278
+ {
279
+ role: "user",
280
+ content: [
281
+ { type: "text", text: "Most recent user turn" },
282
+ {
283
+ type: "image",
284
+ data: "abc",
285
+ mediaType: "image/png",
286
+ },
287
+ ],
288
+ },
289
+ {
290
+ role: "assistant",
291
+ content: [
292
+ { type: "text", text: "Most recent assistant reply" },
293
+ {
294
+ type: "file",
295
+ path: "/tmp/out.ts",
296
+ content: "export const value = 1;",
297
+ },
298
+ ],
299
+ },
300
+ ],
301
+ apiMessages: [
302
+ { role: "user", content: "Initial request that should survive" },
303
+ {
304
+ role: "assistant",
305
+ content: [
306
+ { type: "thinking", thinking: "internal reasoning" },
307
+ { type: "text", text: "Older assistant explanation" },
308
+ {
309
+ type: "tool_use",
310
+ id: "tool-1",
311
+ name: "read_files",
312
+ input: { file_paths: ["/tmp/example.ts"] },
313
+ },
314
+ ],
315
+ },
316
+ {
317
+ role: "user",
318
+ content: [
319
+ {
320
+ type: "tool_result",
321
+ tool_use_id: "tool-1",
322
+ content: "tool output that should be removed",
323
+ },
324
+ ],
325
+ },
326
+ {
327
+ role: "user",
328
+ content: [
329
+ { type: "text", text: "Most recent user turn" },
330
+ {
331
+ type: "image",
332
+ data: "abc",
333
+ mediaType: "image/png",
334
+ },
335
+ ],
336
+ },
337
+ {
338
+ role: "assistant",
339
+ content: [
340
+ { type: "text", text: "Most recent assistant reply" },
341
+ {
342
+ type: "file",
343
+ path: "/tmp/out.ts",
344
+ content: "export const value = 1;",
345
+ },
346
+ ],
347
+ },
348
+ ],
349
+ model: {
350
+ id: "mock-model",
351
+ provider: "anthropic",
352
+ info: { id: "mock-model", contextWindow: 10 },
353
+ },
354
+ });
355
+
356
+ expect(createHandlerMock).not.toHaveBeenCalled();
357
+ expect(emitStatusNotice).toHaveBeenCalledWith(
358
+ "auto-compacting",
359
+ expect.objectContaining({
360
+ kind: "auto_compaction",
361
+ reason: "auto_compaction",
362
+ }),
363
+ );
364
+ expect(result?.messages).toBeDefined();
365
+ expect(result?.messages.length).toBeGreaterThan(0);
366
+ expect(
367
+ result?.messages.every((message) => typeof message.content === "string"),
368
+ ).toBe(true);
369
+ expect(
370
+ result?.messages.some((message) =>
371
+ typeof message.content === "string"
372
+ ? message.content.includes("tool output that should be removed")
373
+ : false,
374
+ ),
375
+ ).toBe(false);
376
+ });
377
+
378
+ it("defaults to threshold ratio when reserveTokens is not configured", async () => {
379
+ const prepareTurn = createContextCompactionPrepareTurn({
380
+ providerId: "anthropic",
381
+ modelId: "mock-model",
382
+ providerConfig: {
383
+ providerId: "anthropic",
384
+ modelId: "mock-model",
385
+ } as LlmsProviders.ProviderConfig,
386
+ compaction: { enabled: true },
387
+ logger: undefined,
388
+ });
389
+
390
+ const result = await prepareTurn?.({
391
+ agentId: "agent-1",
392
+ conversationId: "conv-1",
393
+ parentAgentId: null,
394
+ iteration: 1,
395
+ abortSignal: new AbortController().signal,
396
+ systemPrompt: "You are helpful.",
397
+ tools: [],
398
+ messages: [
399
+ { role: "user", content: "Short request" },
400
+ { role: "assistant", content: "Short reply" },
401
+ ],
402
+ apiMessages: [
403
+ { role: "user", content: "Short request" },
404
+ { role: "assistant", content: "Short reply" },
405
+ ],
406
+ model: {
407
+ id: "mock-model",
408
+ provider: "anthropic",
409
+ info: { id: "mock-model", contextWindow: 100 },
410
+ },
411
+ });
412
+
413
+ expect(createHandlerMock).not.toHaveBeenCalled();
414
+ expect(result).toBeUndefined();
415
+ });
416
+
417
+ it("does not compact when only pre-truncation messages exceed the threshold", async () => {
418
+ const prepareTurn = createContextCompactionPrepareTurn({
419
+ providerId: "anthropic",
420
+ modelId: "mock-model",
421
+ providerConfig: {
422
+ providerId: "anthropic",
423
+ modelId: "mock-model",
424
+ } as LlmsProviders.ProviderConfig,
425
+ compaction: {
426
+ enabled: true,
427
+ thresholdRatio: 0.8,
428
+ },
429
+ logger: undefined,
430
+ });
431
+ expect(prepareTurn).toBeDefined();
432
+
433
+ const result = await prepareTurn?.({
434
+ agentId: "agent-1",
435
+ conversationId: "conv-1",
436
+ parentAgentId: null,
437
+ iteration: 1,
438
+ abortSignal: new AbortController().signal,
439
+ systemPrompt: "You are helpful.",
440
+ tools: [],
441
+ messages: [
442
+ { role: "user", content: "Initial request" },
443
+ {
444
+ role: "user",
445
+ content: [
446
+ {
447
+ type: "tool_result",
448
+ tool_use_id: "tool-1",
449
+ content: "x".repeat(1000),
450
+ },
451
+ ],
452
+ },
453
+ ],
454
+ apiMessages: [
455
+ { role: "user", content: "Initial request" },
456
+ {
457
+ role: "user",
458
+ content: [
459
+ {
460
+ type: "tool_result",
461
+ tool_use_id: "tool-1",
462
+ content: "x".repeat(100),
463
+ },
464
+ ],
465
+ },
466
+ ],
467
+ model: {
468
+ id: "mock-model",
469
+ provider: "anthropic",
470
+ info: { id: "mock-model", contextWindow: 100 },
471
+ },
472
+ });
473
+
474
+ expect(createHandlerMock).not.toHaveBeenCalled();
475
+ expect(result).toBeUndefined();
476
+ });
477
+ });
@@ -0,0 +1,203 @@
1
+ import type * as LlmsProviders from "@clinebot/llms";
2
+ import type {
3
+ CoreCompactionConfig,
4
+ CoreCompactionContext,
5
+ CoreCompactionResult,
6
+ CoreCompactionStrategy,
7
+ CoreSessionConfig,
8
+ } from "../../types/config";
9
+ import { runAgenticCompaction } from "./agentic-compaction";
10
+ import { runBasicCompaction } from "./basic-compaction";
11
+ import {
12
+ createTokenEstimator,
13
+ DEFAULT_CONTEXT_WINDOW_TOKENS,
14
+ DEFAULT_PRESERVE_RECENT_TOKENS,
15
+ DEFAULT_THRESHOLD_RATIO,
16
+ } from "./compaction-shared";
17
+
18
+ export interface ContextPipelinePrepareTurnInput {
19
+ agentId: string;
20
+ conversationId: string;
21
+ parentAgentId: string | null;
22
+ iteration: number;
23
+ messages: CoreCompactionContext["messages"];
24
+ apiMessages: CoreCompactionContext["messages"];
25
+ abortSignal: AbortSignal;
26
+ systemPrompt: string;
27
+ tools: unknown[];
28
+ model: CoreCompactionContext["model"];
29
+ emitStatusNotice?: (
30
+ message: string,
31
+ metadata?: Record<string, unknown>,
32
+ ) => void;
33
+ }
34
+
35
+ export interface ContextPipelinePrepareTurnResult {
36
+ messages: CoreCompactionContext["messages"];
37
+ systemPrompt?: string;
38
+ }
39
+
40
+ type EstimateMessageTokens = ReturnType<typeof createTokenEstimator>;
41
+
42
+ type BuiltinCompactionStrategyOptions = {
43
+ context: CoreCompactionContext;
44
+ providerConfig: LlmsProviders.ProviderConfig;
45
+ compaction: CoreCompactionConfig | undefined;
46
+ estimateMessageTokens: EstimateMessageTokens;
47
+ logger: Pick<CoreSessionConfig, "logger">["logger"];
48
+ };
49
+
50
+ type BuiltinCompactionStrategyRunner = (
51
+ options: BuiltinCompactionStrategyOptions,
52
+ ) =>
53
+ | Promise<CoreCompactionResult | undefined>
54
+ | CoreCompactionResult
55
+ | undefined;
56
+
57
+ const BUILTIN_COMPACTION_STRATEGIES = {
58
+ basic: ({ context, estimateMessageTokens, logger }) =>
59
+ runBasicCompaction({
60
+ context,
61
+ estimateMessageTokens,
62
+ logger,
63
+ }),
64
+ agentic: ({
65
+ context,
66
+ providerConfig,
67
+ compaction,
68
+ estimateMessageTokens,
69
+ logger,
70
+ }) =>
71
+ runAgenticCompaction({
72
+ context,
73
+ providerConfig,
74
+ summarizer: compaction?.summarizer,
75
+ preserveRecentTokens:
76
+ compaction?.preserveRecentTokens ?? DEFAULT_PRESERVE_RECENT_TOKENS,
77
+ estimateMessageTokens,
78
+ logger,
79
+ }),
80
+ } satisfies Record<CoreCompactionStrategy, BuiltinCompactionStrategyRunner>;
81
+
82
+ function resolveTriggerState(input: {
83
+ inputTokens: number;
84
+ contextWindowTokens: number;
85
+ config: CoreCompactionConfig;
86
+ }): { shouldCompact: boolean; triggerTokens: number; thresholdRatio: number } {
87
+ if (typeof input.config.reserveTokens === "number") {
88
+ const reserveTokens = Math.max(0, input.config.reserveTokens);
89
+ const triggerTokens = Math.max(
90
+ 0,
91
+ input.contextWindowTokens - reserveTokens,
92
+ );
93
+ return {
94
+ shouldCompact: input.inputTokens > triggerTokens,
95
+ triggerTokens,
96
+ thresholdRatio:
97
+ input.contextWindowTokens > 0
98
+ ? triggerTokens / input.contextWindowTokens
99
+ : 0,
100
+ };
101
+ }
102
+
103
+ const thresholdRatio = input.config.thresholdRatio ?? DEFAULT_THRESHOLD_RATIO;
104
+ const triggerTokens = input.contextWindowTokens * thresholdRatio;
105
+ return {
106
+ shouldCompact: input.inputTokens > triggerTokens,
107
+ triggerTokens,
108
+ thresholdRatio,
109
+ };
110
+ }
111
+
112
+ export function createContextCompactionPrepareTurn(
113
+ config: Pick<
114
+ CoreSessionConfig,
115
+ "providerConfig" | "providerId" | "modelId" | "compaction" | "logger"
116
+ >,
117
+ ):
118
+ | ((
119
+ context: ContextPipelinePrepareTurnInput,
120
+ ) => Promise<ContextPipelinePrepareTurnResult | undefined>)
121
+ | undefined {
122
+ const userCompaction = config.compaction;
123
+ if (userCompaction?.enabled !== true) {
124
+ return undefined;
125
+ }
126
+
127
+ const providerConfig =
128
+ config.providerConfig ??
129
+ ({
130
+ providerId: config.providerId,
131
+ modelId: config.modelId,
132
+ } as LlmsProviders.ProviderConfig);
133
+ const estimateMessageTokens = createTokenEstimator();
134
+ const strategy = userCompaction?.strategy ?? "basic";
135
+ const runBuiltinStrategy = BUILTIN_COMPACTION_STRATEGIES[strategy];
136
+
137
+ return async (context) => {
138
+ const inputTokens = context.apiMessages.reduce(
139
+ (total: number, message) => total + estimateMessageTokens(message),
140
+ 0,
141
+ );
142
+ const contextWindowTokens =
143
+ userCompaction?.contextWindowTokens ??
144
+ context.model.info?.contextWindow ??
145
+ DEFAULT_CONTEXT_WINDOW_TOKENS;
146
+ if (
147
+ typeof contextWindowTokens !== "number" ||
148
+ !Number.isFinite(contextWindowTokens) ||
149
+ contextWindowTokens <= 0
150
+ ) {
151
+ return undefined;
152
+ }
153
+
154
+ const triggerState = resolveTriggerState({
155
+ inputTokens,
156
+ contextWindowTokens,
157
+ config: {
158
+ reserveTokens: userCompaction?.reserveTokens,
159
+ thresholdRatio: userCompaction?.thresholdRatio,
160
+ },
161
+ });
162
+ if (!triggerState.shouldCompact) {
163
+ return undefined;
164
+ }
165
+
166
+ const compactionContext = {
167
+ agentId: context.agentId,
168
+ conversationId: context.conversationId,
169
+ parentAgentId: context.parentAgentId,
170
+ iteration: context.iteration,
171
+ messages: context.messages,
172
+ model: context.model,
173
+ contextWindowTokens,
174
+ triggerTokens: triggerState.triggerTokens,
175
+ thresholdRatio: triggerState.thresholdRatio,
176
+ utilizationRatio:
177
+ contextWindowTokens > 0 ? inputTokens / contextWindowTokens : 0,
178
+ };
179
+
180
+ context.emitStatusNotice?.("auto-compacting", {
181
+ kind: "auto_compaction",
182
+ reason: "auto_compaction",
183
+ iteration: context.iteration,
184
+ triggerTokens: triggerState.triggerTokens,
185
+ contextWindowTokens,
186
+ });
187
+
188
+ if (userCompaction?.compact) {
189
+ return await userCompaction.compact(compactionContext);
190
+ }
191
+
192
+ return await runBuiltinStrategy({
193
+ context: compactionContext,
194
+ providerConfig: {
195
+ ...providerConfig,
196
+ abortSignal: context.abortSignal,
197
+ },
198
+ compaction: userCompaction,
199
+ estimateMessageTokens,
200
+ logger: config.logger,
201
+ });
202
+ };
203
+ }
@@ -0,0 +1,12 @@
1
+ export type { ResolveAgentPluginPathsOptions } from "./plugin/plugin-config-loader";
2
+ export {
3
+ discoverPluginModulePaths,
4
+ resolveAgentPluginPaths,
5
+ resolveAndLoadAgentPlugins,
6
+ resolvePluginConfigSearchPaths,
7
+ } from "./plugin/plugin-config-loader";
8
+ export type { LoadAgentPluginFromPathOptions } from "./plugin/plugin-loader";
9
+ export {
10
+ loadAgentPluginFromPath,
11
+ loadAgentPluginsFromPaths,
12
+ } from "./plugin/plugin-loader";