@xagent-ai/cli 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  3. package/.github/workflows/ci.yml +72 -0
  4. package/.github/workflows/release.yml +109 -0
  5. package/.gitmodules +3 -3
  6. package/README.md +326 -280
  7. package/README_CN.md +325 -279
  8. package/dist/ai-client/factory.d.ts +52 -0
  9. package/dist/ai-client/factory.d.ts.map +1 -0
  10. package/dist/ai-client/factory.js +132 -0
  11. package/dist/ai-client/factory.js.map +1 -0
  12. package/dist/ai-client/index.d.ts +20 -0
  13. package/dist/ai-client/index.d.ts.map +1 -0
  14. package/dist/ai-client/index.js +49 -0
  15. package/dist/ai-client/index.js.map +1 -0
  16. package/dist/ai-client/providers/anthropic.d.ts +57 -0
  17. package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
  18. package/dist/ai-client/providers/anthropic.js +400 -0
  19. package/dist/ai-client/providers/anthropic.js.map +1 -0
  20. package/dist/ai-client/providers/openai.d.ts +57 -0
  21. package/dist/ai-client/providers/openai.d.ts.map +1 -0
  22. package/dist/ai-client/providers/openai.js +286 -0
  23. package/dist/ai-client/providers/openai.js.map +1 -0
  24. package/dist/ai-client/providers/remote.d.ts +111 -0
  25. package/dist/ai-client/providers/remote.d.ts.map +1 -0
  26. package/dist/ai-client/providers/remote.js +351 -0
  27. package/dist/ai-client/providers/remote.js.map +1 -0
  28. package/dist/ai-client/registry.d.ts +51 -0
  29. package/dist/ai-client/registry.d.ts.map +1 -0
  30. package/dist/ai-client/registry.js +81 -0
  31. package/dist/ai-client/registry.js.map +1 -0
  32. package/dist/ai-client/types.d.ts +260 -0
  33. package/dist/ai-client/types.d.ts.map +1 -0
  34. package/dist/ai-client/types.js +73 -0
  35. package/dist/ai-client/types.js.map +1 -0
  36. package/dist/ai-client-factory.d.ts +62 -0
  37. package/dist/ai-client-factory.d.ts.map +1 -0
  38. package/dist/ai-client-factory.js +157 -0
  39. package/dist/ai-client-factory.js.map +1 -0
  40. package/dist/auth.d.ts +23 -1
  41. package/dist/auth.d.ts.map +1 -1
  42. package/dist/auth.js +160 -168
  43. package/dist/auth.js.map +1 -1
  44. package/dist/cancellation.d.ts +5 -4
  45. package/dist/cancellation.d.ts.map +1 -1
  46. package/dist/cancellation.js +55 -32
  47. package/dist/cancellation.js.map +1 -1
  48. package/dist/checkpoint.d.ts +1 -1
  49. package/dist/checkpoint.d.ts.map +1 -1
  50. package/dist/checkpoint.js +2 -2
  51. package/dist/checkpoint.js.map +1 -1
  52. package/dist/cli.js +626 -13
  53. package/dist/cli.js.map +1 -1
  54. package/dist/config.d.ts +10 -4
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +62 -25
  57. package/dist/config.js.map +1 -1
  58. package/dist/context-compressor.d.ts +81 -16
  59. package/dist/context-compressor.d.ts.map +1 -1
  60. package/dist/context-compressor.js +712 -153
  61. package/dist/context-compressor.js.map +1 -1
  62. package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
  63. package/dist/gui-subagent/action-parser/actionParser.js +4 -2
  64. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  65. package/dist/gui-subagent/agent/gui-agent.d.ts +29 -2
  66. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  67. package/dist/gui-subagent/agent/gui-agent.js +87 -45
  68. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  69. package/dist/gui-subagent/index.d.ts +16 -1
  70. package/dist/gui-subagent/index.d.ts.map +1 -1
  71. package/dist/gui-subagent/index.js +4 -0
  72. package/dist/gui-subagent/index.js.map +1 -1
  73. package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
  74. package/dist/gui-subagent/operator/base-operator.js +0 -1
  75. package/dist/gui-subagent/operator/base-operator.js.map +1 -1
  76. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  77. package/dist/gui-subagent/operator/computer-operator.js +29 -8
  78. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  79. package/dist/gui-subagent/types/actions.d.ts +1 -1
  80. package/dist/gui-subagent/types/actions.d.ts.map +1 -1
  81. package/dist/gui-subagent/types/actions.js +0 -1
  82. package/dist/gui-subagent/types/actions.js.map +1 -1
  83. package/dist/gui-subagent/types/operator.d.ts +1 -1
  84. package/dist/gui-subagent/types/operator.d.ts.map +1 -1
  85. package/dist/index.d.ts +1 -2
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +1 -2
  88. package/dist/index.js.map +1 -1
  89. package/dist/input-processor.d.ts.map +1 -1
  90. package/dist/input-processor.js +6 -3
  91. package/dist/input-processor.js.map +1 -1
  92. package/dist/mcp.d.ts +5 -0
  93. package/dist/mcp.d.ts.map +1 -1
  94. package/dist/mcp.js +81 -35
  95. package/dist/mcp.js.map +1 -1
  96. package/dist/ripgrep.d.ts +29 -0
  97. package/dist/ripgrep.d.ts.map +1 -0
  98. package/dist/ripgrep.js +292 -0
  99. package/dist/ripgrep.js.map +1 -0
  100. package/dist/session.d.ts +23 -7
  101. package/dist/session.d.ts.map +1 -1
  102. package/dist/session.js +624 -243
  103. package/dist/session.js.map +1 -1
  104. package/dist/shell.d.ts +33 -0
  105. package/dist/shell.d.ts.map +1 -0
  106. package/dist/shell.js +125 -0
  107. package/dist/shell.js.map +1 -0
  108. package/dist/skill-installer.d.ts +38 -0
  109. package/dist/skill-installer.d.ts.map +1 -0
  110. package/dist/skill-installer.js +447 -0
  111. package/dist/skill-installer.js.map +1 -0
  112. package/dist/skill-invoker.d.ts +7 -1
  113. package/dist/skill-invoker.d.ts.map +1 -1
  114. package/dist/skill-invoker.js +34 -13
  115. package/dist/skill-invoker.js.map +1 -1
  116. package/dist/skill-loader.d.ts +8 -3
  117. package/dist/skill-loader.d.ts.map +1 -1
  118. package/dist/skill-loader.js +46 -44
  119. package/dist/skill-loader.js.map +1 -1
  120. package/dist/skill-manager.d.ts +85 -0
  121. package/dist/skill-manager.d.ts.map +1 -0
  122. package/dist/skill-manager.js +340 -0
  123. package/dist/skill-manager.js.map +1 -0
  124. package/dist/slash-commands.d.ts +38 -1
  125. package/dist/slash-commands.d.ts.map +1 -1
  126. package/dist/slash-commands.js +912 -296
  127. package/dist/slash-commands.js.map +1 -1
  128. package/dist/smart-approval.d.ts.map +1 -1
  129. package/dist/smart-approval.js +67 -55
  130. package/dist/smart-approval.js.map +1 -1
  131. package/dist/system-prompt-generator.d.ts +6 -0
  132. package/dist/system-prompt-generator.d.ts.map +1 -1
  133. package/dist/system-prompt-generator.js +84 -34
  134. package/dist/system-prompt-generator.js.map +1 -1
  135. package/dist/terminal.d.ts +28 -0
  136. package/dist/terminal.d.ts.map +1 -0
  137. package/dist/terminal.js +82 -0
  138. package/dist/terminal.js.map +1 -0
  139. package/dist/tools.d.ts +23 -7
  140. package/dist/tools.d.ts.map +1 -1
  141. package/dist/tools.js +797 -437
  142. package/dist/tools.js.map +1 -1
  143. package/dist/truncate.d.ts +55 -0
  144. package/dist/truncate.d.ts.map +1 -0
  145. package/dist/truncate.js +130 -0
  146. package/dist/truncate.js.map +1 -0
  147. package/dist/types.d.ts +27 -9
  148. package/dist/types.d.ts.map +1 -1
  149. package/dist/update.d.ts.map +1 -1
  150. package/dist/update.js +17 -28
  151. package/dist/update.js.map +1 -1
  152. package/dist/workflow.d.ts +5 -1
  153. package/dist/workflow.d.ts.map +1 -1
  154. package/dist/workflow.js +60 -47
  155. package/dist/workflow.js.map +1 -1
  156. package/docs/architecture/mcp-integration-guide.md +304 -194
  157. package/docs/architecture/overview.md +169 -169
  158. package/docs/architecture/tool-system-design.md +134 -134
  159. package/docs/cli/commands.md +349 -238
  160. package/docs/smart-mode.md +281 -281
  161. package/docs/third-party-models.md +439 -439
  162. package/find-skills/SKILL.md +133 -0
  163. package/package.json +89 -90
  164. package/scripts/install-ripgrep.js +241 -0
  165. package/src/ai-client/factory.ts +151 -0
  166. package/src/ai-client/index.ts +61 -0
  167. package/src/ai-client/providers/anthropic.ts +466 -0
  168. package/src/ai-client/providers/openai.ts +342 -0
  169. package/src/ai-client/providers/remote.ts +436 -0
  170. package/src/ai-client/registry.ts +97 -0
  171. package/src/ai-client/types.ts +345 -0
  172. package/src/ai-client-factory.ts +204 -0
  173. package/src/auth.ts +663 -614
  174. package/src/cancellation.ts +205 -176
  175. package/src/checkpoint.ts +219 -219
  176. package/src/cli.ts +1406 -743
  177. package/src/config.ts +341 -297
  178. package/src/context-compressor.ts +982 -290
  179. package/src/conversation.ts +288 -288
  180. package/src/gui-subagent/action-parser/actionParser.ts +318 -315
  181. package/src/gui-subagent/action-parser/constants.ts +14 -14
  182. package/src/gui-subagent/action-parser/index.ts +8 -8
  183. package/src/gui-subagent/action-parser/types.ts +31 -31
  184. package/src/gui-subagent/agent/gui-agent.ts +1151 -1089
  185. package/src/gui-subagent/agent/index.ts +5 -5
  186. package/src/gui-subagent/index.ts +177 -163
  187. package/src/gui-subagent/operator/base-operator.ts +244 -245
  188. package/src/gui-subagent/operator/computer-operator.ts +540 -520
  189. package/src/gui-subagent/operator/index.ts +6 -6
  190. package/src/gui-subagent/types/actions.ts +260 -262
  191. package/src/gui-subagent/types/index.ts +6 -6
  192. package/src/gui-subagent/types/operator.ts +106 -106
  193. package/src/gui-subagent/utils.ts +51 -51
  194. package/src/index.ts +17 -18
  195. package/src/input-processor.ts +6 -3
  196. package/src/logger.ts +438 -438
  197. package/src/mcp.ts +730 -682
  198. package/src/memory.ts +344 -344
  199. package/src/ripgrep.ts +368 -0
  200. package/src/session-manager.ts +308 -308
  201. package/src/session.ts +948 -386
  202. package/src/shell.ts +133 -0
  203. package/src/skill-installer.ts +518 -0
  204. package/src/skill-invoker.ts +960 -935
  205. package/src/skill-loader.ts +501 -496
  206. package/src/skill-manager.ts +384 -0
  207. package/src/slash-commands.ts +2181 -1389
  208. package/src/smart-approval.ts +117 -73
  209. package/src/system-prompt-generator.ts +89 -34
  210. package/src/terminal.ts +96 -0
  211. package/src/theme.ts +738 -738
  212. package/src/tools.ts +1336 -773
  213. package/src/truncate.ts +173 -0
  214. package/src/types.ts +219 -198
  215. package/src/update.ts +22 -32
  216. package/src/workflow.ts +523 -508
  217. package/tsconfig.json +22 -22
  218. package/vitest.config.ts +19 -19
  219. package/dist/ai-client.d.ts +0 -86
  220. package/dist/ai-client.d.ts.map +0 -1
  221. package/dist/ai-client.js +0 -1372
  222. package/dist/ai-client.js.map +0 -1
  223. package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
  224. package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
  225. package/dist/gui-subagent/operator/browser-operator.js +0 -306
  226. package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
  227. package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
  228. package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
  229. package/dist/gui-subagent/operator/desktop-operator.js +0 -527
  230. package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
  231. package/dist/hook.d.ts +0 -73
  232. package/dist/hook.d.ts.map +0 -1
  233. package/dist/hook.js +0 -156
  234. package/dist/hook.js.map +0 -1
  235. package/dist/input-history.d.ts +0 -24
  236. package/dist/input-history.d.ts.map +0 -1
  237. package/dist/input-history.js +0 -94
  238. package/dist/input-history.js.map +0 -1
  239. package/dist/keyboard-manager.d.ts +0 -151
  240. package/dist/keyboard-manager.d.ts.map +0 -1
  241. package/dist/keyboard-manager.js +0 -396
  242. package/dist/keyboard-manager.js.map +0 -1
  243. package/dist/print-system-prompt.d.ts +0 -2
  244. package/dist/print-system-prompt.d.ts.map +0 -1
  245. package/dist/print-system-prompt.js +0 -40
  246. package/dist/print-system-prompt.js.map +0 -1
  247. package/dist/remote-ai-client.d.ts +0 -104
  248. package/dist/remote-ai-client.d.ts.map +0 -1
  249. package/dist/remote-ai-client.js +0 -552
  250. package/dist/remote-ai-client.js.map +0 -1
  251. package/dist/sdk-output-adapter.d.ts +0 -232
  252. package/dist/sdk-output-adapter.d.ts.map +0 -1
  253. package/dist/sdk-output-adapter.js +0 -636
  254. package/dist/sdk-output-adapter.js.map +0 -1
  255. package/dist/sdk-session-v2.d.ts +0 -13
  256. package/dist/sdk-session-v2.d.ts.map +0 -1
  257. package/dist/sdk-session-v2.js +0 -46
  258. package/dist/sdk-session-v2.js.map +0 -1
  259. package/dist/sdk-session.d.ts +0 -13
  260. package/dist/sdk-session.d.ts.map +0 -1
  261. package/dist/sdk-session.js +0 -48
  262. package/dist/sdk-session.js.map +0 -1
  263. package/dist/test-boundary-conditions.d.ts.map +0 -1
  264. package/dist/test-boundary-conditions.js.map +0 -1
  265. package/dist/test-cancellation-fix.d.ts.map +0 -1
  266. package/dist/test-cancellation-fix.js.map +0 -1
  267. package/dist/test-input-history.d.ts.map +0 -1
  268. package/dist/test-input-history.js.map +0 -1
  269. package/dist/test-interaction-flow.d.ts.map +0 -1
  270. package/dist/test-interaction-flow.js.map +0 -1
  271. package/dist/test-quick.d.ts.map +0 -1
  272. package/dist/test-quick.js.map +0 -1
  273. package/dist/test-user-interaction.d.ts.map +0 -1
  274. package/dist/test-user-interaction.js.map +0 -1
  275. package/dist/tools/edit-diff.d.ts +0 -32
  276. package/dist/tools/edit-diff.d.ts.map +0 -1
  277. package/dist/tools/edit-diff.js +0 -185
  278. package/dist/tools/edit-diff.js.map +0 -1
  279. package/dist/tools/edit.d.ts +0 -11
  280. package/dist/tools/edit.d.ts.map +0 -1
  281. package/dist/tools/edit.js +0 -129
  282. package/dist/tools/edit.js.map +0 -1
  283. package/dist/unified-session.d.ts +0 -42
  284. package/dist/unified-session.d.ts.map +0 -1
  285. package/dist/unified-session.js +0 -271
  286. package/dist/unified-session.js.map +0 -1
  287. package/skills/.claude-plugin/marketplace.json +0 -45
  288. package/skills/README.md +0 -94
  289. package/skills/THIRD_PARTY_NOTICES.md +0 -405
  290. package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
  291. package/skills/skills/algorithmic-art/SKILL.md +0 -405
  292. package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
  293. package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
  294. package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
  295. package/skills/skills/brand-guidelines/SKILL.md +0 -73
  296. package/skills/skills/canvas-design/LICENSE.txt +0 -202
  297. package/skills/skills/canvas-design/SKILL.md +0 -130
  298. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  299. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  300. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  301. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  302. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  303. package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  304. package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  305. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  306. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  307. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  308. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  309. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  310. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  311. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  312. package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  313. package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  314. package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  315. package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  316. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  317. package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  318. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  319. package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  320. package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  321. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  322. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  323. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  324. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  325. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  326. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  327. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  328. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  329. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  330. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  331. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  332. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  333. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  334. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  335. package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  336. package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  337. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  338. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  339. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  340. package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  341. package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  342. package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  343. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  344. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  345. package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  346. package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  347. package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  348. package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  349. package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  350. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  351. package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  352. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  353. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  354. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  355. package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  356. package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  357. package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  358. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  359. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  360. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  361. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  362. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  363. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  364. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  365. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  366. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  367. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  368. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  369. package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  370. package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  371. package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  372. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  373. package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  374. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  375. package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  376. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  377. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  378. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  379. package/skills/skills/doc-coauthoring/SKILL.md +0 -375
  380. package/skills/skills/docx/LICENSE.txt +0 -30
  381. package/skills/skills/docx/SKILL.md +0 -197
  382. package/skills/skills/docx/docx-js.md +0 -350
  383. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  384. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  385. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  386. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  387. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  388. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  389. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  390. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  391. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  392. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  393. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  394. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  395. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  396. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  397. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  398. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  399. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  400. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  401. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  402. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  403. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  404. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  405. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  406. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  407. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  408. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  409. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  410. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  411. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  412. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  413. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  414. package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  415. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  416. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  417. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  418. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  419. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  420. package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  421. package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  422. package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
  423. package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
  424. package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
  425. package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  426. package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
  427. package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  428. package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  429. package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  430. package/skills/skills/docx/ooxml.md +0 -610
  431. package/skills/skills/docx/scripts/__init__.py +0 -1
  432. package/skills/skills/docx/scripts/document.py +0 -1276
  433. package/skills/skills/docx/scripts/templates/comments.xml +0 -3
  434. package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  435. package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  436. package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
  437. package/skills/skills/docx/scripts/templates/people.xml +0 -3
  438. package/skills/skills/docx/scripts/utilities.py +0 -374
  439. package/skills/skills/frontend-design/LICENSE.txt +0 -177
  440. package/skills/skills/frontend-design/SKILL.md +0 -42
  441. package/skills/skills/internal-comms/LICENSE.txt +0 -202
  442. package/skills/skills/internal-comms/SKILL.md +0 -32
  443. package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
  444. package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
  445. package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
  446. package/skills/skills/internal-comms/examples/general-comms.md +0 -16
  447. package/skills/skills/mcp-builder/LICENSE.txt +0 -202
  448. package/skills/skills/mcp-builder/SKILL.md +0 -236
  449. package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
  450. package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  451. package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  452. package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  453. package/skills/skills/mcp-builder/scripts/connections.py +0 -151
  454. package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
  455. package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  456. package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
  457. package/skills/skills/pdf/LICENSE.txt +0 -30
  458. package/skills/skills/pdf/SKILL.md +0 -294
  459. package/skills/skills/pdf/forms.md +0 -205
  460. package/skills/skills/pdf/reference.md +0 -612
  461. package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  462. package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  463. package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
  464. package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  465. package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
  466. package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
  467. package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  468. package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  469. package/skills/skills/pptx/LICENSE.txt +0 -30
  470. package/skills/skills/pptx/SKILL.md +0 -484
  471. package/skills/skills/pptx/html2pptx.md +0 -625
  472. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  473. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  474. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  475. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  476. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  477. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  478. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  479. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  480. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  481. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  482. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  483. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  484. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  485. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  486. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  487. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  488. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  489. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  490. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  491. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  492. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  493. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  494. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  495. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  496. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  497. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  498. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  499. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  500. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  501. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  502. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  503. package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  504. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  505. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  506. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  507. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  508. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  509. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  510. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  511. package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
  512. package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
  513. package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
  514. package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  515. package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  516. package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  517. package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  518. package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  519. package/skills/skills/pptx/ooxml.md +0 -427
  520. package/skills/skills/pptx/scripts/html2pptx.js +0 -979
  521. package/skills/skills/pptx/scripts/inventory.py +0 -1020
  522. package/skills/skills/pptx/scripts/rearrange.py +0 -231
  523. package/skills/skills/pptx/scripts/replace.py +0 -385
  524. package/skills/skills/pptx/scripts/thumbnail.py +0 -450
  525. package/skills/skills/skill-creator/LICENSE.txt +0 -202
  526. package/skills/skills/skill-creator/SKILL.md +0 -356
  527. package/skills/skills/skill-creator/references/output-patterns.md +0 -82
  528. package/skills/skills/skill-creator/references/workflows.md +0 -28
  529. package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
  530. package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
  531. package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
  532. package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
  533. package/skills/skills/slack-gif-creator/SKILL.md +0 -254
  534. package/skills/skills/slack-gif-creator/core/easing.py +0 -234
  535. package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
  536. package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
  537. package/skills/skills/slack-gif-creator/core/validators.py +0 -136
  538. package/skills/skills/slack-gif-creator/requirements.txt +0 -4
  539. package/skills/skills/theme-factory/LICENSE.txt +0 -202
  540. package/skills/skills/theme-factory/SKILL.md +0 -59
  541. package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
  542. package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
  543. package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
  544. package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
  545. package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
  546. package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
  547. package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
  548. package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
  549. package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
  550. package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
  551. package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
  552. package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
  553. package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
  554. package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
  555. package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
  556. package/skills/skills/webapp-testing/LICENSE.txt +0 -202
  557. package/skills/skills/webapp-testing/SKILL.md +0 -96
  558. package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
  559. package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
  560. package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
  561. package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
  562. package/skills/skills/xlsx/LICENSE.txt +0 -30
  563. package/skills/skills/xlsx/SKILL.md +0 -289
  564. package/skills/skills/xlsx/recalc.py +0 -178
  565. package/skills/spec/agent-skills-spec.md +0 -3
  566. package/skills/template/SKILL.md +0 -6
  567. package/src/ai-client.ts +0 -1560
  568. package/src/remote-ai-client.ts +0 -664
@@ -1,112 +1,535 @@
1
- import { AIClient } from './ai-client.js';
1
+ import { getCancellationManager } from './cancellation.js';
2
+ import { createAIClient } from './ai-client-factory.js';
3
+ /**
4
+ * Model context window sizes (in tokens)
5
+ * Add models here as needed
6
+ */
7
+ const MODEL_CONTEXT_WINDOWS = {
8
+ // OpenAI
9
+ 'gpt-4': 8192,
10
+ 'gpt-4-32k': 32768,
11
+ 'gpt-4-turbo': 128000,
12
+ 'gpt-4o': 128000,
13
+ 'gpt-4o-mini': 128000,
14
+ 'gpt-5': 200000,
15
+ // Anthropic Claude
16
+ 'claude-sonnet-4-20250514': 200000,
17
+ 'claude-sonnet-4': 200000,
18
+ 'claude-opus-4': 200000,
19
+ 'claude-3-5-sonnet': 200000,
20
+ 'claude-3-opus': 200000,
21
+ // Google
22
+ 'gemini-pro': 32768,
23
+ 'gemini-ultra': 1000000,
24
+ // DeepSeek
25
+ 'deepseek-chat': 128000,
26
+ 'deepseek-coder': 128000,
27
+ 'deepseek-reasoner': 128000,
28
+ // Qwen (Tongyi Qianwen)
29
+ 'qwen-max': 32768,
30
+ 'qwen-plus': 64000,
31
+ 'qwen-turbo': 8000,
32
+ 'qwen-long': 100000,
33
+ 'qwen-vl-max': 128000,
34
+ 'Qwen3-Coder': 32768,
35
+ // Zhipu AI (GLM)
36
+ 'glm-4': 128000,
37
+ 'glm-4-plus': 128000,
38
+ 'glm-4-air': 128000,
39
+ 'glm-4.7': 128000,
40
+ // MiniMax
41
+ 'MiniMax-M2': 1000000,
42
+ 'MiniMax-M2.1': 1000000,
43
+ // Moonshot (Kimi)
44
+ 'moonshot-v1-8k': 8192,
45
+ 'moonshot-v1-32k': 32768,
46
+ 'moonshot-v1-128k': 131072,
47
+ // Doubao
48
+ 'doubao-seed-1-8-251228': 256000,
49
+ 'doubao-1-5-ui-tars-250428': 256000,
50
+ // Default fallback
51
+ 'default': 200000
52
+ };
53
+ // Compression ratio constants - easier to tune and maintain
54
+ const COMPRESSION_RATIO = {
55
+ RESERVE_RATIO: 0.50, // Reserve 50% of context window for system prompt and recent messages
56
+ SUMMARY_THRESHOLD_RATIO: 0.15, // Use 15% of available space for summary
57
+ MAX_TOKENS_RATIO: 0.8, // Use 80% of reserved tokens for compression
58
+ SUMMARY_MAX_TOKENS_RATIO: 0.5, // Use 50% of reserved tokens for summary
59
+ MIN_SUMMARY_TOKENS: 800 // Minimum tokens for summary
60
+ };
61
+ /**
62
+ * Get the context window for a model
63
+ */
64
+ export function getModelContextWindow(modelName) {
65
+ if (!modelName)
66
+ return MODEL_CONTEXT_WINDOWS['default'];
67
+ // Try exact match first
68
+ if (MODEL_CONTEXT_WINDOWS[modelName]) {
69
+ return MODEL_CONTEXT_WINDOWS[modelName];
70
+ }
71
+ // Try case-insensitive match
72
+ const lowerName = modelName.toLowerCase();
73
+ for (const [key, value] of Object.entries(MODEL_CONTEXT_WINDOWS)) {
74
+ if (key.toLowerCase() === lowerName) {
75
+ return value;
76
+ }
77
+ }
78
+ // Try partial match (e.g., "claude" matches "claude-sonnet-4")
79
+ for (const [key, value] of Object.entries(MODEL_CONTEXT_WINDOWS)) {
80
+ if (lowerName.includes(key.toLowerCase()) || key.toLowerCase().includes(lowerName)) {
81
+ return value;
82
+ }
83
+ }
84
+ return MODEL_CONTEXT_WINDOWS['default'];
85
+ }
86
+ const SUMMARIZATION_PROMPT = `The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.
87
+
88
+ Use this EXACT format:
89
+
90
+ ## Goal
91
+ [What is the user trying to accomplish? Can be multiple items if the session covers different tasks.]
92
+
93
+ ## Constraints & Preferences
94
+ - [Any constraints, preferences, or requirements mentioned by user]
95
+ - [Or "(none)" if none were mentioned]
96
+
97
+ ## Progress
98
+ ### Done
99
+ - [x] [Completed tasks/changes]
100
+
101
+ ### In Progress
102
+ - [ ] [Current work]
103
+
104
+ ### Blocked
105
+ - [Issues preventing progress, if any]
106
+
107
+ ## Key Decisions
108
+ - **[Decision]**: [Brief rationale]
109
+
110
+ ## Next Steps
111
+ 1. [Ordered list of what should happen next]
112
+
113
+ ## Critical Context
114
+
115
+ ### Key Files & Code
116
+ - [File path]: [Brief description of key content/structure]
117
+ - [File path]: [Brief description of key content/structure]
118
+
119
+ ### Execution Results
120
+ - **Files**: [What files were read, written, or edited and key findings]
121
+ - **Commands**: [Key commands run and their outputs]
122
+ - **Search/Analysis**: [Key findings from code search or analysis]
123
+
124
+ ### Project Context
125
+ - [Architecture patterns identified]
126
+ - [Important configurations]
127
+ - [Dependencies or libraries relevant to the task]
128
+
129
+ Keep each section concise. Preserve exact file paths, function names, and error messages.`;
130
+ const UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.
131
+
132
+ Update the existing structured summary with new information. RULES:
133
+ - PRESERVE all existing information from the previous summary
134
+ - ADD new progress, decisions, and context from the new messages
135
+ - UPDATE the Progress section: move items from "In Progress" to "Done" when completed
136
+ - UPDATE "Next Steps" based on what was accomplished
137
+ - PRESERVE exact file paths, function names, and error messages
138
+ - If something is no longer relevant, you may remove it
139
+
140
+ Use this EXACT format:
141
+
142
+ ## Goal
143
+ [Preserve existing goals, add new ones if the task expanded]
144
+
145
+ ## Constraints & Preferences
146
+ - [Preserve existing, add new ones discovered]
147
+
148
+ ## Progress
149
+ ### Done
150
+ - [x] [Include previously done items AND newly completed items]
151
+
152
+ ### In Progress
153
+ - [ ] [Current work - update based on progress]
154
+
155
+ ### Blocked
156
+ - [Current blockers - remove if resolved]
157
+
158
+ ## Key Decisions
159
+ - **[Decision]**: [Brief rationale] (preserve all previous, add new)
160
+
161
+ ## Next Steps
162
+ 1. [Update based on current state]
163
+
164
+ ## Critical Context
165
+
166
+ ### Key Files & Code
167
+ - [Preserve existing file info, add new files read]
168
+ - [Include brief descriptions of key code structures]
169
+
170
+ ### Execution Results
171
+ - **Files**: [Preserve file list, add new files read/written/edited]
172
+ - **Commands**: [Preserve outputs, add new command results]
173
+ - **Search/Analysis**: [Preserve findings, add new search results]
174
+
175
+ ### Project Context
176
+ - [Preserve architecture info, add new patterns discovered]
177
+ - [Preserve configs, add new relevant dependencies]
178
+
179
+ Keep each section concise. Preserve exact file paths, function names, and error messages.`;
180
+ const TURN_PREFIX_SUMMARIZATION_PROMPT = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained.
181
+
182
+ Summarize the prefix to provide context for the retained suffix:
183
+
184
+ ## Original Request
185
+ [What did the user ask for in this turn?]
186
+
187
+ ## Early Progress
188
+ - [Key decisions and work done in the prefix]
189
+
190
+ ## Critical Context
191
+
192
+ ### Key Files & Code
193
+ - [File path]: [Brief description of key content/structure]
194
+
195
+ ### Execution Results
196
+ - **Files**: [What files were read, written, or edited in this prefix]
197
+ - **Commands**: [Key commands run and outputs]
198
+
199
+ ### Context for Suffix
200
+ - [Information needed to understand the retained recent work]
201
+
202
+ Be concise. Focus on what's needed to understand the kept suffix.`;
2
203
  export class ContextCompressor {
3
204
  aiClient = null;
4
205
  defaultConfig = {
5
- enabled: true,
6
- maxMessages: 50,
7
- maxContextSize: 150000,
8
- preserveRecentMessages: 0,
9
- enableSummary: true
206
+ enabled: true
10
207
  };
11
208
  constructor(authConfig) {
12
209
  if (authConfig) {
13
- this.aiClient = new AIClient(authConfig);
210
+ this.aiClient = createAIClient(authConfig);
14
211
  }
15
212
  }
16
213
  setAIClient(aiClient) {
17
214
  this.aiClient = aiClient;
18
215
  }
19
216
  /**
20
- * Check if compression is needed
217
+ * Check if compression is needed based on token budget and model context window
218
+ * @param messages - Conversation messages
219
+ * @param config - Compression config
220
+ * @param modelName - Optional model name to determine context window
21
221
  */
22
- needsCompression(messages, config) {
222
+ needsCompression(messages, config, modelName) {
23
223
  const cfg = { ...this.defaultConfig, ...config };
24
- const userMessageCount = messages.filter(m => m.role === 'user').length;
25
- const contextSize = this.calculateContextSize(messages);
26
- if (userMessageCount > cfg.maxMessages) {
224
+ const tokenCount = this.estimateContextTokens(messages);
225
+ const messageCount = messages.length;
226
+ // Get model context window
227
+ const contextWindow = getModelContextWindow(modelName);
228
+ // Calculate threshold using compression ratio constants
229
+ const reserveTokens = Math.floor(contextWindow * COMPRESSION_RATIO.RESERVE_RATIO);
230
+ const threshold = contextWindow - reserveTokens;
231
+ if (tokenCount > threshold) {
27
232
  return {
28
233
  needsCompression: true,
29
- reason: `User message count (${userMessageCount}) exceeds maximum (${cfg.maxMessages})`
234
+ reason: `Token count (${tokenCount}) exceeds ${modelName ? `${modelName}` : ''} context budget (${threshold}, contextWindow: ${contextWindow})`,
235
+ tokenCount
30
236
  };
31
237
  }
32
- if (contextSize > cfg.maxContextSize) {
33
- return {
34
- needsCompression: true,
35
- reason: `Context size (${contextSize} chars) exceeds maximum (${cfg.maxContextSize} chars)`
36
- };
238
+ return { needsCompression: false, reason: '', tokenCount };
239
+ }
240
+ /**
241
+ * Estimate token count for a single message using message-type-aware heuristic
242
+ */
243
+ estimateMessageTokens(message) {
244
+ let chars = 0;
245
+ switch (message.role) {
246
+ case 'user':
247
+ case 'system':
248
+ case 'tool': {
249
+ chars = message.content.length;
250
+ break;
251
+ }
252
+ case 'assistant': {
253
+ if (message.reasoning_content) {
254
+ chars += message.reasoning_content.length;
255
+ }
256
+ const toolCalls = message.tool_calls;
257
+ if (toolCalls && toolCalls.length > 0) {
258
+ for (const toolCall of toolCalls) {
259
+ chars += JSON.stringify(toolCall).length;
260
+ }
261
+ }
262
+ chars += message.content.length;
263
+ break;
264
+ }
37
265
  }
38
- return { needsCompression: false, reason: '' };
266
+ return Math.ceil(chars / 4);
39
267
  }
40
268
  /**
41
- * Calculate context size(字符数)
269
+ * Estimate total token count for a conversation
42
270
  */
43
- calculateContextSize(messages) {
44
- return messages.reduce((total, msg) => {
45
- return total + msg.content.length + (msg.role.length + 10);
46
- }, 0);
271
+ estimateContextTokens(messages) {
272
+ let total = 0;
273
+ for (const msg of messages) {
274
+ total += this.estimateMessageTokens(msg);
275
+ }
276
+ return total;
47
277
  }
48
278
  /**
49
- * Compress conversation history
279
+ * Find valid cut points: indices of messages that can be cut at
280
+ * Never cut at tool results (they must follow their tool call)
50
281
  */
51
- async compressContext(messages, systemPrompt, config) {
52
- const cfg = { ...this.defaultConfig, ...config };
53
- const originalMessageCount = messages.length;
54
- const originalSize = this.calculateContextSize(messages);
55
- // Separate system messages、用户消息和助手消息
56
- const systemMessages = messages.filter(m => m.role === 'system');
57
- const nonSystemMessages = messages.filter(m => m.role !== 'system');
58
- // 如果消息数量和大小都在限制内,不需要压缩
59
- const { needsCompression } = this.needsCompression(nonSystemMessages, config);
60
- if (!needsCompression) {
61
- return {
62
- compressedMessages: messages,
63
- wasCompressed: false,
64
- originalMessageCount,
65
- compressedMessageCount: messages.length,
66
- originalSize,
67
- compressedSize: originalSize,
68
- compressionMethod: 'none'
69
- };
282
+ findValidCutPoints(messages, startIndex, endIndex) {
283
+ const cutPoints = [];
284
+ for (let i = startIndex; i < endIndex; i++) {
285
+ const msg = messages[i];
286
+ switch (msg.role) {
287
+ case 'user':
288
+ case 'assistant':
289
+ case 'system':
290
+ cutPoints.push(i);
291
+ break;
292
+ case 'tool':
293
+ // Tool results cannot be cut at (they must follow their tool call)
294
+ break;
295
+ }
296
+ }
297
+ return cutPoints;
298
+ }
299
+ /**
300
+ * Find the user message that starts the turn containing the given index
301
+ */
302
+ findTurnStartIndex(messages, entryIndex, startIndex) {
303
+ for (let i = entryIndex; i >= startIndex; i--) {
304
+ const role = messages[i].role;
305
+ if (role === 'user') {
306
+ return i;
307
+ }
308
+ }
309
+ return -1;
310
+ }
311
+ /**
312
+ * Find the cut point that keeps approximately keepRecentTokens
313
+ * Walks backwards from newest, accumulating estimated message sizes
314
+ */
315
+ findCutPoint(messages, startIndex, endIndex, keepRecentTokens) {
316
+ const cutPoints = this.findValidCutPoints(messages, startIndex, endIndex);
317
+ if (cutPoints.length === 0) {
318
+ return { firstKeptEntryIndex: startIndex, turnStartIndex: -1, isSplitTurn: false };
319
+ }
320
+ // Walk backwards from newest, accumulating estimated message sizes
321
+ let accumulatedTokens = 0;
322
+ let cutIndex = cutPoints[cutPoints.length - 1]; // Start with the last cut point
323
+ for (let i = endIndex - 1; i >= startIndex; i--) {
324
+ const messageTokens = this.estimateMessageTokens(messages[i]);
325
+ accumulatedTokens += messageTokens;
326
+ if (accumulatedTokens >= keepRecentTokens) {
327
+ // Find the closest valid cut point at or after this entry
328
+ // Search from the END of cutPoints array (closest to i)
329
+ for (let c = cutPoints.length - 1; c >= 0; c--) {
330
+ if (cutPoints[c] >= i) {
331
+ cutIndex = cutPoints[c];
332
+ }
333
+ else {
334
+ // Since cutPoints is sorted ascending, no need to continue
335
+ break;
336
+ }
337
+ }
338
+ break;
339
+ }
70
340
  }
71
- // Use AI to generate summary压缩全部历史对话
72
- const compressedMessages = await this.summarizeAllMessages(nonSystemMessages, systemPrompt, cfg);
73
- // 注意:不再保留原始的 systemMessages,因为 generateResponse 会自动添加系统提示
74
- // 压缩后的消息只includes摘要(role: assistant),避免重复的 system 消息导致 API 报错
75
- const finalMessages = [...compressedMessages];
341
+ // Determine if this is a split turn
342
+ const isUserMessage = messages[cutIndex].role === 'user';
343
+ const turnStartIndex = isUserMessage ? -1 : this.findTurnStartIndex(messages, cutIndex, startIndex);
76
344
  return {
77
- compressedMessages: finalMessages,
78
- wasCompressed: true,
79
- originalMessageCount,
80
- compressedMessageCount: finalMessages.length,
81
- originalSize,
82
- compressedSize: this.calculateContextSize(finalMessages),
83
- compressionMethod: 'summary'
345
+ firstKeptEntryIndex: cutIndex,
346
+ turnStartIndex,
347
+ isSplitTurn: !isUserMessage && turnStartIndex !== -1
84
348
  };
85
349
  }
86
350
  /**
87
- * Use AI to generate summary来压缩全部对话历史
351
+ * Extract file operations from messages by analyzing tool calls
88
352
  */
89
- async summarizeAllMessages(messages, systemPrompt, config) {
90
- // 生成完整对话的摘要
91
- const summary = await this.generateSummary(messages, systemPrompt);
92
- // 构建压缩后的对话:只有摘要作为 system 消息
93
- const compressed = [];
94
- // 添加摘要作为 assistant 消息,避免与系统提示重复导致 API 报错
95
- compressed.push({
96
- role: 'assistant',
97
- content: `[Conversation Summary - ${messages.length} messages compressed]\n\n${summary}`,
98
- timestamp: Date.now()
99
- });
100
- return compressed;
353
+ extractFileOperations(messages) {
354
+ const fileOps = {
355
+ read: new Set(),
356
+ modified: new Set()
357
+ };
358
+ let totalToolCalls = 0;
359
+ let matchedToolCalls = 0;
360
+ // Normalize tool name (handle both API format and internal format)
361
+ const isReadTool = (name) => name === 'read_file' || name === 'Read';
362
+ const isWriteTool = (name) => name === 'write_file' || name === 'Write';
363
+ const isEditTool = (name) => name === 'Edit';
364
+ const isDeleteTool = (name) => name === 'DeleteFile';
365
+ const getFilePath = (args) => {
366
+ return args.filePath || args.absolute_path || args.path || '';
367
+ };
368
+ for (const msg of messages) {
369
+ // Case 1: assistant with tool_calls field
370
+ if (msg.role === 'assistant' && msg.tool_calls) {
371
+ for (const toolCall of msg.tool_calls) {
372
+ totalToolCalls++;
373
+ const toolName = toolCall.function?.name || '';
374
+ let args = {};
375
+ try {
376
+ args = JSON.parse(toolCall.function?.arguments || '{}');
377
+ }
378
+ catch {
379
+ continue;
380
+ }
381
+ const filePath = getFilePath(args);
382
+ if (!filePath)
383
+ continue;
384
+ if (isReadTool(toolName)) {
385
+ fileOps.read.add(filePath);
386
+ matchedToolCalls++;
387
+ }
388
+ else if (isWriteTool(toolName) || isEditTool(toolName) || isDeleteTool(toolName)) {
389
+ fileOps.modified.add(filePath);
390
+ matchedToolCalls++;
391
+ }
392
+ }
393
+ }
394
+ // Case 2: tool role with JSON content (like {"name":"Read","parameters":...})
395
+ if (msg.role === 'tool' && typeof msg.content === 'string') {
396
+ try {
397
+ const content = JSON.parse(msg.content);
398
+ totalToolCalls++;
399
+ const toolName = content.name || '';
400
+ const args = content.parameters || {};
401
+ const filePath = getFilePath(args);
402
+ if (!filePath)
403
+ continue;
404
+ if (isReadTool(toolName)) {
405
+ fileOps.read.add(filePath);
406
+ matchedToolCalls++;
407
+ }
408
+ else if (isWriteTool(toolName) || isEditTool(toolName) || isDeleteTool(toolName)) {
409
+ fileOps.modified.add(filePath);
410
+ matchedToolCalls++;
411
+ }
412
+ }
413
+ catch {
414
+ // Not JSON, skip
415
+ }
416
+ }
417
+ }
418
+ return fileOps;
419
+ }
420
+ /**
421
+ * Merge file operations from previous compaction
422
+ */
423
+ mergeFileOps(ops1, ops2) {
424
+ return {
425
+ read: new Set([...ops1.read, ...ops2.read]),
426
+ modified: new Set([...ops1.modified, ...ops2.modified])
427
+ };
428
+ }
429
+ /**
430
+ * Format file operations for inclusion in summary
431
+ */
432
+ formatFileOperations(fileOps) {
433
+ const readFiles = Array.from(fileOps.read);
434
+ const modifiedFiles = Array.from(fileOps.modified);
435
+ if (readFiles.length === 0 && modifiedFiles.length === 0) {
436
+ return '';
437
+ }
438
+ let formatted = '\n\n## File Operations\n\n';
439
+ if (readFiles.length > 0) {
440
+ formatted += '### Files read_file\n';
441
+ for (const file of readFiles) {
442
+ formatted += `- ${file}\n`;
443
+ }
444
+ }
445
+ if (modifiedFiles.length > 0) {
446
+ formatted += '\n### Files Modified\n';
447
+ for (const file of modifiedFiles) {
448
+ formatted += `- ${file}\n`;
449
+ }
450
+ }
451
+ return formatted;
452
+ }
453
+ /**
454
+ * Prepare compaction - calculate cut point and extract messages to summarize
455
+ */
456
+ prepareCompaction(messages, keepRecentTokens) {
457
+ if (messages.length === 0) {
458
+ return undefined;
459
+ }
460
+ // Check if last message already contains a compression summary
461
+ const lastMsg = messages[messages.length - 1];
462
+ const isAlreadyCompressed = lastMsg.role === 'user' &&
463
+ lastMsg.content.includes('[Previous conversation summarized');
464
+ if (isAlreadyCompressed) {
465
+ return undefined;
466
+ }
467
+ const startIndex = 0;
468
+ const endIndex = messages.length;
469
+ // Find cut point
470
+ const cutPoint = this.findCutPoint(messages, startIndex, endIndex, keepRecentTokens);
471
+ // Extract messages to summarize
472
+ const historyEnd = cutPoint.firstKeptEntryIndex;
473
+ const messagesToSummarize = [];
474
+ for (let i = startIndex; i < historyEnd; i++) {
475
+ messagesToSummarize.push(messages[i]);
476
+ }
477
+ // Extract turn prefix messages if splitting (disabled for simplicity)
478
+ const turnPrefixMessages = [];
479
+ if (cutPoint.isSplitTurn) {
480
+ for (let i = cutPoint.turnStartIndex; i < cutPoint.firstKeptEntryIndex; i++) {
481
+ turnPrefixMessages.push(messages[i]);
482
+ }
483
+ }
484
+ // Get previous summary if exists (look for embedded summary in user messages)
485
+ let previousSummary;
486
+ for (let i = messages.length - 1; i >= 0; i--) {
487
+ const msg = messages[i];
488
+ if (msg.role === 'user' && msg.content.includes('[Previous conversation summarized')) {
489
+ // Extract the summary part from the content
490
+ const match = msg.content.match(/\[Previous conversation summarized.*?\]\n(.+?)(?=\n\n---\n\n|\n\n\[)/s);
491
+ if (match) {
492
+ previousSummary = match[1];
493
+ }
494
+ else {
495
+ previousSummary = msg.content;
496
+ }
497
+ break;
498
+ }
499
+ }
500
+ // Extract file operations
501
+ const fileOps = this.extractFileOperations(messagesToSummarize);
502
+ // Also extract from turn prefix
503
+ if (cutPoint.isSplitTurn) {
504
+ const prefixOps = this.extractFileOperations(turnPrefixMessages);
505
+ return {
506
+ firstKeptEntryIndex: cutPoint.firstKeptEntryIndex,
507
+ messagesToSummarize,
508
+ turnPrefixMessages,
509
+ isSplitTurn: cutPoint.isSplitTurn,
510
+ tokensBefore: this.estimateContextTokens(messagesToSummarize),
511
+ previousSummary,
512
+ fileOps: this.mergeFileOps(fileOps, prefixOps)
513
+ };
514
+ }
515
+ return {
516
+ firstKeptEntryIndex: cutPoint.firstKeptEntryIndex,
517
+ messagesToSummarize,
518
+ turnPrefixMessages,
519
+ isSplitTurn: cutPoint.isSplitTurn,
520
+ tokensBefore: this.estimateContextTokens(messagesToSummarize),
521
+ previousSummary,
522
+ fileOps
523
+ };
101
524
  }
102
525
  /**
103
- * Generate conversation summary
526
+ * Generate summary using AI
104
527
  */
105
- async generateSummary(messages, systemPrompt) {
528
+ async generateSummary(messages, systemPrompt, reserveTokens, previousSummary, customInstructions) {
106
529
  if (!this.aiClient) {
107
530
  throw new Error('AI client not initialized for summarization');
108
531
  }
109
- // Extract all conversation content
532
+ // Serialize conversation
110
533
  const conversationText = messages
111
534
  .map((m, idx) => {
112
535
  const role = m.role === 'user' ? 'User' :
@@ -115,83 +538,35 @@ export class ContextCompressor {
115
538
  return `[${idx + 1}] ${role}:\n${m.content}`;
116
539
  })
117
540
  .join('\n\n' + '='.repeat(50) + '\n\n');
118
- const summaryPrompt = `You are an expert at summarizing conversations. Please create a comprehensive summary of the following conversation.
119
-
120
- ## Instructions
121
- 1. Analyze ALL messages in the conversation
122
- 2. Create a detailed summary that captures:
123
- - Complete context and background
124
- - All topics discussed
125
- - All decisions made
126
- - All files created, modified, or analyzed
127
- - All code changes and implementations
128
- - All problems solved
129
- - Current state and progress
130
- - Any pending or ongoing tasks
131
- 3. Be extremely thorough - this summary will replace the entire conversation history
132
- 4. Include specific details like file paths, code snippets, command outputs, etc.
133
-
134
- ## Conversation to summarize
135
- ${conversationText}
136
-
137
- ## Output Format
138
- Provide a detailed, comprehensive summary in the following format:
139
-
140
- ### Conversation Summary
141
-
142
- #### Overview
143
- [Brief description of what this conversation was about]
144
-
145
- #### Background & Context
146
- [Complete background information]
147
-
148
- #### Topics Discussed
149
- - [Topic 1: detailed description]
150
- - [Topic 2: detailed description]
151
- - [All topics with full details]
152
-
153
- #### Key Decisions
154
- - [Decision 1: details and rationale]
155
- - [All decisions made during the conversation]
156
-
157
- #### File Operations
158
- - Created: [file paths]
159
- - Modified: [file paths]
160
- - Analyzed: [file paths]
161
- - Deleted: [file paths]
162
-
163
- #### Code Changes
164
- - [Specific code changes with details]
165
- - [All implementations]
166
-
167
- #### Problems & Solutions
168
- - Problem: [description]
169
- Solution: [how it was solved]
170
- - [All problems and solutions]
171
-
172
- #### Current State
173
- [What is the current status of the project/work]
174
-
175
- #### Pending Tasks
176
- - [Any ongoing or pending work]
177
-
178
- #### Important Details
179
- [Any other crucial information]
180
-
181
- Please provide the comprehensive summary possible. Do not omit any important information.`;
541
+ // Select prompt based on whether we have previous summary
542
+ let basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;
543
+ if (customInstructions) {
544
+ basePrompt = `${basePrompt}\n\nAdditional focus: ${customInstructions}`;
545
+ }
546
+ // Build prompt
547
+ let promptText = `<conversation>\n${conversationText}\n</conversation>\n\n`;
548
+ if (previousSummary) {
549
+ promptText += `<previous-summary>\n${previousSummary}\n</previous-summary>\n\n`;
550
+ }
551
+ promptText += basePrompt;
552
+ const maxTokens = Math.floor(reserveTokens * COMPRESSION_RATIO.MAX_TOKENS_RATIO);
553
+ const summaryMessage = {
554
+ role: 'user',
555
+ content: promptText
556
+ };
557
+ const aiPromise = this.aiClient.compress([summaryMessage], {
558
+ maxTokens,
559
+ temperature: 0.3
560
+ });
182
561
  try {
183
- const summaryMessage = {
184
- role: 'user',
185
- content: summaryPrompt
186
- };
187
- const response = await this.aiClient.chatCompletion([summaryMessage], {
188
- maxTokens: 8192,
189
- temperature: 0.3
190
- });
562
+ const response = await getCancellationManager().withCancellation(aiPromise, 'context-compression-summary');
191
563
  const summary = response.choices[0]?.message?.content || '';
192
564
  return typeof summary === 'string' ? summary : JSON.stringify(summary);
193
565
  }
194
566
  catch (error) {
567
+ if (error.message === 'Operation cancelled by user') {
568
+ throw error;
569
+ }
195
570
  console.error('Failed to generate summary:', error);
196
571
  const userCount = messages.filter(m => m.role === 'user').length;
197
572
  const toolCount = messages.filter(m => m.role === 'tool').length;
@@ -199,7 +574,197 @@ Please provide the comprehensive summary possible. Do not omit any important inf
199
574
  }
200
575
  }
201
576
  /**
202
- * Create compressed message copy(用于保存)
577
+ * Generate turn prefix summary when splitting a turn
578
+ */
579
+ async generateTurnPrefixSummary(messages, reserveTokens) {
580
+ if (!this.aiClient) {
581
+ throw new Error('AI client not initialized for summarization');
582
+ }
583
+ const conversationText = messages
584
+ .map((m, idx) => {
585
+ const role = m.role === 'user' ? 'User' :
586
+ m.role === 'assistant' ? 'Assistant' :
587
+ m.role === 'tool' ? 'Tool' : m.role;
588
+ return `[${idx + 1}] ${role}:\n${m.content}`;
589
+ })
590
+ .join('\n\n' + '='.repeat(50) + '\n\n');
591
+ const promptText = `<conversation>\n${conversationText}\n</conversation>\n\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`;
592
+ const maxTokens = Math.floor(reserveTokens * COMPRESSION_RATIO.SUMMARY_MAX_TOKENS_RATIO);
593
+ const summaryMessage = {
594
+ role: 'user',
595
+ content: promptText
596
+ };
597
+ const aiPromise = this.aiClient.compress([summaryMessage], {
598
+ maxTokens,
599
+ temperature: 0.3
600
+ });
601
+ try {
602
+ const response = await getCancellationManager().withCancellation(aiPromise, 'context-compression-turn-prefix');
603
+ const content = response.choices[0]?.message?.content || '';
604
+ return typeof content === 'string' ? content : JSON.stringify(content);
605
+ }
606
+ catch (error) {
607
+ if (error.message === 'Operation cancelled by user') {
608
+ throw error;
609
+ }
610
+ console.error('Failed to generate turn prefix summary:', error);
611
+ return '[Turn prefix summary unavailable]';
612
+ }
613
+ }
614
+ /**
615
+ * Main compression function with incremental compaction support
616
+ */
617
+ async compressContext(messages, systemPrompt, config, previousSummary, modelName) {
618
+ const cfg = { ...this.defaultConfig, ...config };
619
+ const originalMessageCount = messages.length;
620
+ const originalSize = messages.reduce((total, msg) => total + msg.content.length, 0);
621
+ const originalTokens = this.estimateContextTokens(messages);
622
+ const contextWindow = getModelContextWindow(modelName);
623
+ // Check if compression is needed
624
+ const { needsCompression } = this.needsCompression(messages, config, modelName);
625
+ if (!needsCompression) {
626
+ return {
627
+ compressedMessages: messages,
628
+ wasCompressed: false,
629
+ originalMessageCount,
630
+ compressedMessageCount: messages.length,
631
+ originalSize,
632
+ compressedSize: originalSize,
633
+ compressionMethod: 'none'
634
+ };
635
+ }
636
+ // Prepare compaction
637
+ // Reserve 50% of context window for new conversation, 15% for summary
638
+ const reserveTokens = Math.floor(contextWindow * COMPRESSION_RATIO.RESERVE_RATIO);
639
+ const summaryReserveTokens = Math.max(COMPRESSION_RATIO.MIN_SUMMARY_TOKENS, Math.floor((contextWindow - reserveTokens) * COMPRESSION_RATIO.SUMMARY_THRESHOLD_RATIO));
640
+ const keepRecentTokens = contextWindow - reserveTokens - summaryReserveTokens;
641
+ const preparation = this.prepareCompaction(messages, Math.max(0, keepRecentTokens));
642
+ if (!preparation) {
643
+ // Already compressed or no valid cut point
644
+ return {
645
+ compressedMessages: messages,
646
+ wasCompressed: false,
647
+ originalMessageCount,
648
+ compressedMessageCount: messages.length,
649
+ originalSize,
650
+ compressedSize: originalSize,
651
+ compressionMethod: 'none'
652
+ };
653
+ }
654
+ const { firstKeptEntryIndex, messagesToSummarize, turnPrefixMessages, isSplitTurn, tokensBefore, fileOps } = preparation;
655
+ // Generate summary
656
+ let summary;
657
+ if (isSplitTurn && turnPrefixMessages.length > 0) {
658
+ // Generate both summaries in parallel
659
+ const [historyResult, turnPrefixResult] = await Promise.all([
660
+ messagesToSummarize.length > 0
661
+ ? this.generateSummary(messagesToSummarize, systemPrompt, summaryReserveTokens, previousSummary)
662
+ : Promise.resolve('No prior history.'),
663
+ this.generateTurnPrefixSummary(turnPrefixMessages, summaryReserveTokens)
664
+ ]);
665
+ summary = `${historyResult}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefixResult}`;
666
+ }
667
+ else {
668
+ summary = await this.generateSummary(messagesToSummarize, systemPrompt, summaryReserveTokens, previousSummary);
669
+ }
670
+ // Add file operations to summary
671
+ summary += this.formatFileOperations(fileOps);
672
+ // Build compressed messages: summary + kept messages
673
+ // Summary is inserted as prefix in first user message to maintain valid message order
674
+ const compressedMessages = [];
675
+ if (messagesToSummarize.length > 0) {
676
+ // Find first user message in kept messages
677
+ let firstKeptUserMsg = null;
678
+ let firstKeptUserIndex = -1;
679
+ for (let i = firstKeptEntryIndex; i < messages.length; i++) {
680
+ if (messages[i].role === 'user') {
681
+ firstKeptUserMsg = messages[i];
682
+ firstKeptUserIndex = i;
683
+ break;
684
+ }
685
+ }
686
+ if (firstKeptUserMsg) {
687
+ // Prepend summary to first user message content
688
+ const summaryPrefix = `[Previous conversation summarized (${messagesToSummarize.length} messages):]\n${summary}\n\n---\n\n`;
689
+ compressedMessages.push({
690
+ role: 'user',
691
+ content: summaryPrefix + firstKeptUserMsg.content,
692
+ timestamp: firstKeptUserMsg.timestamp,
693
+ images: firstKeptUserMsg.images
694
+ });
695
+ // Add remaining kept messages (skip the modified first user message)
696
+ for (let i = firstKeptUserIndex + 1; i < messages.length; i++) {
697
+ const msg = messages[i];
698
+ compressedMessages.push({
699
+ role: msg.role,
700
+ content: msg.content,
701
+ timestamp: msg.timestamp,
702
+ images: msg.images,
703
+ reasoning_content: msg.reasoning_content,
704
+ tool_calls: msg.tool_calls,
705
+ tool_call_id: msg.tool_call_id
706
+ });
707
+ }
708
+ }
709
+ else {
710
+ // No user message in kept messages (rare case)
711
+ // Insert summary as a user message, then add all kept messages
712
+ // This ensures valid message order: user → assistant → tool → tool...
713
+ compressedMessages.push({
714
+ role: 'user',
715
+ content: `[Conversation Summary - ${messagesToSummarize.length} messages compressed]\n\n${summary}`,
716
+ timestamp: Date.now()
717
+ });
718
+ // Add all kept messages (they may start with assistant or tool)
719
+ for (let i = firstKeptEntryIndex; i < messages.length; i++) {
720
+ const msg = messages[i];
721
+ compressedMessages.push({
722
+ role: msg.role,
723
+ content: msg.content,
724
+ timestamp: msg.timestamp,
725
+ images: msg.images,
726
+ reasoning_content: msg.reasoning_content,
727
+ tool_calls: msg.tool_calls,
728
+ tool_call_id: msg.tool_call_id
729
+ });
730
+ }
731
+ }
732
+ }
733
+ else {
734
+ // No messages to summarize, just keep all messages
735
+ for (let i = firstKeptEntryIndex; i < messages.length; i++) {
736
+ const msg = messages[i];
737
+ compressedMessages.push({
738
+ role: msg.role,
739
+ content: msg.content,
740
+ timestamp: msg.timestamp,
741
+ images: msg.images,
742
+ reasoning_content: msg.reasoning_content,
743
+ tool_calls: msg.tool_calls,
744
+ tool_call_id: msg.tool_call_id
745
+ });
746
+ }
747
+ }
748
+ const compressedSize = compressedMessages.reduce((total, msg) => total + msg.content.length, 0);
749
+ const compressedTokens = this.estimateContextTokens(compressedMessages);
750
+ const reductionPercent = Math.round((1 - compressedSize / originalSize) * 100);
751
+ return {
752
+ compressedMessages,
753
+ wasCompressed: true,
754
+ originalMessageCount,
755
+ compressedMessageCount: compressedMessages.length,
756
+ originalSize,
757
+ compressedSize,
758
+ compressionMethod: 'summary',
759
+ tokensBefore,
760
+ details: {
761
+ readFiles: Array.from(fileOps.read),
762
+ modifiedFiles: Array.from(fileOps.modified)
763
+ }
764
+ };
765
+ }
766
+ /**
767
+ * Create compressed message copy for saving
203
768
  */
204
769
  createCompressedSnapshot(messages, compressionResult) {
205
770
  return {
@@ -209,17 +774,11 @@ Please provide the comprehensive summary possible. Do not omit any important inf
209
774
  originalSize: compressionResult.originalSize,
210
775
  compressedSize: compressionResult.compressedSize,
211
776
  compressionMethod: compressionResult.compressionMethod,
777
+ tokensBefore: compressionResult.tokensBefore,
778
+ details: compressionResult.details,
212
779
  messages: compressionResult.compressedMessages
213
780
  };
214
781
  }
215
- /**
216
- * Estimate token count (rough estimate)
217
- */
218
- estimateTokens(text) {
219
- const chineseChars = (text.match(/[\u4e00-\u9fa5]/g) || []).length;
220
- const otherChars = text.length - chineseChars;
221
- return Math.ceil(chineseChars / 2 + otherChars / 4);
222
- }
223
782
  }
224
783
  let compressorInstance = null;
225
784
  export function getContextCompressor(authConfig) {