@xagent-ai/cli 1.2.2 → 1.3.1
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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/release.yml +76 -0
- package/.github/workflows/ci.yml +75 -0
- package/.github/workflows/release.yml +103 -0
- package/.gitmodules +3 -3
- package/README.md +326 -280
- package/README_CN.md +325 -279
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +7 -3
- package/dist/agents.js.map +1 -1
- package/dist/ai-client/factory.d.ts +40 -0
- package/dist/ai-client/factory.d.ts.map +1 -0
- package/dist/ai-client/factory.js +100 -0
- package/dist/ai-client/factory.js.map +1 -0
- package/dist/ai-client/index.d.ts +20 -0
- package/dist/ai-client/index.d.ts.map +1 -0
- package/dist/ai-client/index.js +49 -0
- package/dist/ai-client/index.js.map +1 -0
- package/dist/ai-client/providers/anthropic.d.ts +57 -0
- package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
- package/dist/ai-client/providers/anthropic.js +406 -0
- package/dist/ai-client/providers/anthropic.js.map +1 -0
- package/dist/ai-client/providers/openai.d.ts +57 -0
- package/dist/ai-client/providers/openai.d.ts.map +1 -0
- package/dist/ai-client/providers/openai.js +290 -0
- package/dist/ai-client/providers/openai.js.map +1 -0
- package/dist/ai-client/providers/remote.d.ts +110 -0
- package/dist/ai-client/providers/remote.d.ts.map +1 -0
- package/dist/ai-client/providers/remote.js +352 -0
- package/dist/ai-client/providers/remote.js.map +1 -0
- package/dist/ai-client/registry.d.ts +51 -0
- package/dist/ai-client/registry.d.ts.map +1 -0
- package/dist/ai-client/registry.js +81 -0
- package/dist/ai-client/registry.js.map +1 -0
- package/dist/ai-client/types.d.ts +274 -0
- package/dist/ai-client/types.d.ts.map +1 -0
- package/dist/ai-client/types.js +90 -0
- package/dist/ai-client/types.js.map +1 -0
- package/dist/ai-client-factory.d.ts +62 -0
- package/dist/ai-client-factory.d.ts.map +1 -0
- package/dist/ai-client-factory.js +157 -0
- package/dist/ai-client-factory.js.map +1 -0
- package/dist/auth.d.ts +23 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +164 -174
- package/dist/auth.js.map +1 -1
- package/dist/cancellation.d.ts +5 -4
- package/dist/cancellation.d.ts.map +1 -1
- package/dist/cancellation.js +53 -32
- package/dist/cancellation.js.map +1 -1
- package/dist/checkpoint.d.ts +2 -1
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +39 -6
- package/dist/checkpoint.js.map +1 -1
- package/dist/cli.js +742 -29
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +10 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +62 -25
- package/dist/config.js.map +1 -1
- package/dist/context-compressor.d.ts +82 -18
- package/dist/context-compressor.d.ts.map +1 -1
- package/dist/context-compressor.js +718 -154
- package/dist/context-compressor.js.map +1 -1
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +8 -7
- package/dist/conversation.js.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.js +6 -4
- package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.d.ts +39 -2
- package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.js +189 -74
- package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
- package/dist/gui-subagent/index.d.ts +23 -1
- package/dist/gui-subagent/index.d.ts.map +1 -1
- package/dist/gui-subagent/index.js +6 -0
- package/dist/gui-subagent/index.js.map +1 -1
- package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
- package/dist/gui-subagent/operator/base-operator.js +0 -1
- package/dist/gui-subagent/operator/base-operator.js.map +1 -1
- package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
- package/dist/gui-subagent/operator/computer-operator.js +31 -8
- package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
- package/dist/gui-subagent/types/actions.d.ts +1 -1
- package/dist/gui-subagent/types/actions.d.ts.map +1 -1
- package/dist/gui-subagent/types/actions.js +0 -1
- package/dist/gui-subagent/types/actions.js.map +1 -1
- package/dist/gui-subagent/types/operator.d.ts +1 -1
- package/dist/gui-subagent/types/operator.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/input-processor.d.ts.map +1 -1
- package/dist/input-processor.js +8 -5
- package/dist/input-processor.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/mcp.d.ts +7 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +157 -49
- package/dist/mcp.js.map +1 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +3 -3
- package/dist/memory.js.map +1 -1
- package/dist/output-util.d.ts +27 -0
- package/dist/output-util.d.ts.map +1 -0
- package/dist/output-util.js +74 -0
- package/dist/output-util.js.map +1 -0
- package/dist/retry.js +1 -1
- package/dist/retry.js.map +1 -1
- package/dist/ripgrep.d.ts +29 -0
- package/dist/ripgrep.d.ts.map +1 -0
- package/dist/ripgrep.js +294 -0
- package/dist/ripgrep.js.map +1 -0
- package/dist/sdk-output-adapter.d.ts +34 -1
- package/dist/sdk-output-adapter.d.ts.map +1 -1
- package/dist/sdk-output-adapter.js +67 -2
- package/dist/sdk-output-adapter.js.map +1 -1
- package/dist/sdk-session.d.ts.map +1 -1
- package/dist/sdk-session.js +2 -0
- package/dist/sdk-session.js.map +1 -1
- package/dist/session-manager.js +3 -3
- package/dist/session-manager.js.map +1 -1
- package/dist/session.d.ts +116 -6
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +1416 -448
- package/dist/session.js.map +1 -1
- package/dist/shell.d.ts +33 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +126 -0
- package/dist/shell.js.map +1 -0
- package/dist/skill-installer.d.ts +38 -0
- package/dist/skill-installer.d.ts.map +1 -0
- package/dist/skill-installer.js +447 -0
- package/dist/skill-installer.js.map +1 -0
- package/dist/skill-invoker.d.ts +8 -2
- package/dist/skill-invoker.d.ts.map +1 -1
- package/dist/skill-invoker.js +36 -15
- package/dist/skill-invoker.js.map +1 -1
- package/dist/skill-loader.d.ts +8 -3
- package/dist/skill-loader.d.ts.map +1 -1
- package/dist/skill-loader.js +51 -48
- package/dist/skill-loader.js.map +1 -1
- package/dist/skill-manager.d.ts +85 -0
- package/dist/skill-manager.d.ts.map +1 -0
- package/dist/skill-manager.js +341 -0
- package/dist/skill-manager.js.map +1 -0
- package/dist/slash-commands.d.ts +39 -2
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +934 -305
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts +20 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +125 -56
- package/dist/smart-approval.js.map +1 -1
- package/dist/system-prompt-generator.d.ts +6 -0
- package/dist/system-prompt-generator.d.ts.map +1 -1
- package/dist/system-prompt-generator.js +86 -36
- package/dist/system-prompt-generator.js.map +1 -1
- package/dist/terminal.d.ts +28 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +82 -0
- package/dist/terminal.js.map +1 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +8 -7
- package/dist/theme.js.map +1 -1
- package/dist/tools.d.ts +38 -7
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +1249 -617
- package/dist/tools.js.map +1 -1
- package/dist/truncate.d.ts +55 -0
- package/dist/truncate.d.ts.map +1 -0
- package/dist/truncate.js +130 -0
- package/dist/truncate.js.map +1 -0
- package/dist/types.d.ts +84 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +49 -0
- package/dist/types.js.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +28 -36
- package/dist/update.js.map +1 -1
- package/dist/workflow.d.ts +5 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +61 -49
- package/dist/workflow.js.map +1 -1
- package/docs/architecture/mcp-integration-guide.md +304 -194
- package/docs/architecture/overview.md +169 -169
- package/docs/architecture/tool-system-design.md +134 -134
- package/docs/cli/commands.md +349 -238
- package/docs/smart-mode.md +281 -281
- package/docs/third-party-models.md +440 -439
- package/find-skills/SKILL.md +133 -0
- package/package.json +91 -90
- package/scripts/install-ripgrep.js +241 -0
- package/src/agents.ts +7 -3
- package/src/ai-client/factory.ts +116 -0
- package/src/ai-client/index.ts +61 -0
- package/src/ai-client/providers/anthropic.ts +475 -0
- package/src/ai-client/providers/openai.ts +348 -0
- package/src/ai-client/providers/remote.ts +439 -0
- package/src/ai-client/registry.ts +97 -0
- package/src/ai-client/types.ts +364 -0
- package/src/ai-client-factory.ts +204 -0
- package/src/auth.ts +661 -614
- package/src/cancellation.ts +202 -176
- package/src/checkpoint.ts +255 -219
- package/src/cli.ts +1523 -743
- package/src/config.ts +341 -297
- package/src/context-compressor.ts +987 -290
- package/src/conversation.ts +290 -288
- package/src/gui-subagent/action-parser/actionParser.ts +318 -315
- package/src/gui-subagent/action-parser/constants.ts +14 -14
- package/src/gui-subagent/action-parser/index.ts +8 -8
- package/src/gui-subagent/action-parser/types.ts +31 -31
- package/src/gui-subagent/agent/gui-agent.ts +1234 -1089
- package/src/gui-subagent/agent/index.ts +5 -5
- package/src/gui-subagent/index.ts +185 -163
- package/src/gui-subagent/operator/base-operator.ts +244 -245
- package/src/gui-subagent/operator/computer-operator.ts +541 -520
- package/src/gui-subagent/operator/index.ts +6 -6
- package/src/gui-subagent/types/actions.ts +260 -262
- package/src/gui-subagent/types/index.ts +6 -6
- package/src/gui-subagent/types/operator.ts +106 -106
- package/src/gui-subagent/utils.ts +51 -51
- package/src/index.ts +17 -18
- package/src/input-processor.ts +8 -5
- package/src/logger.ts +436 -438
- package/src/mcp.ts +793 -682
- package/src/memory.ts +343 -344
- package/src/output-util.ts +80 -0
- package/src/retry.ts +1 -1
- package/src/ripgrep.ts +370 -0
- package/src/sdk-output-adapter.ts +842 -0
- package/src/sdk-session.ts +62 -0
- package/src/session-manager.ts +308 -308
- package/src/session.ts +1775 -573
- package/src/shell.ts +134 -0
- package/src/skill-installer.ts +518 -0
- package/src/skill-invoker.ts +959 -935
- package/src/skill-loader.ts +501 -496
- package/src/skill-manager.ts +385 -0
- package/src/slash-commands.ts +2189 -1389
- package/src/smart-approval.ts +193 -74
- package/src/system-prompt-generator.ts +91 -36
- package/src/terminal.ts +96 -0
- package/src/theme.ts +739 -738
- package/src/tools.ts +1790 -931
- package/src/truncate.ts +173 -0
- package/src/types.ts +337 -198
- package/src/update.ts +33 -40
- package/src/workflow.ts +521 -508
- package/test/cli-launch.test.ts +279 -0
- package/tsconfig.json +22 -22
- package/vitest.config.ts +21 -19
- package/dist/ai-client.d.ts +0 -86
- package/dist/ai-client.d.ts.map +0 -1
- package/dist/ai-client.js +0 -1372
- package/dist/ai-client.js.map +0 -1
- package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
- package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
- package/dist/gui-subagent/operator/browser-operator.js +0 -306
- package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
- package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
- package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
- package/dist/gui-subagent/operator/desktop-operator.js +0 -527
- package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
- package/dist/hook.d.ts +0 -73
- package/dist/hook.d.ts.map +0 -1
- package/dist/hook.js +0 -156
- package/dist/hook.js.map +0 -1
- package/dist/input-history.d.ts +0 -24
- package/dist/input-history.d.ts.map +0 -1
- package/dist/input-history.js +0 -94
- package/dist/input-history.js.map +0 -1
- package/dist/keyboard-manager.d.ts +0 -151
- package/dist/keyboard-manager.d.ts.map +0 -1
- package/dist/keyboard-manager.js +0 -396
- package/dist/keyboard-manager.js.map +0 -1
- package/dist/print-system-prompt.d.ts +0 -2
- package/dist/print-system-prompt.d.ts.map +0 -1
- package/dist/print-system-prompt.js +0 -40
- package/dist/print-system-prompt.js.map +0 -1
- package/dist/remote-ai-client.d.ts +0 -104
- package/dist/remote-ai-client.d.ts.map +0 -1
- package/dist/remote-ai-client.js +0 -552
- package/dist/remote-ai-client.js.map +0 -1
- package/dist/sdk-session-v2.d.ts +0 -13
- package/dist/sdk-session-v2.d.ts.map +0 -1
- package/dist/sdk-session-v2.js +0 -46
- package/dist/sdk-session-v2.js.map +0 -1
- package/dist/test-boundary-conditions.d.ts.map +0 -1
- package/dist/test-boundary-conditions.js.map +0 -1
- package/dist/test-cancellation-fix.d.ts.map +0 -1
- package/dist/test-cancellation-fix.js.map +0 -1
- package/dist/test-input-history.d.ts.map +0 -1
- package/dist/test-input-history.js.map +0 -1
- package/dist/test-interaction-flow.d.ts.map +0 -1
- package/dist/test-interaction-flow.js.map +0 -1
- package/dist/test-quick.d.ts.map +0 -1
- package/dist/test-quick.js.map +0 -1
- package/dist/test-user-interaction.d.ts.map +0 -1
- package/dist/test-user-interaction.js.map +0 -1
- package/dist/tools/edit-diff.d.ts +0 -32
- package/dist/tools/edit-diff.d.ts.map +0 -1
- package/dist/tools/edit-diff.js +0 -185
- package/dist/tools/edit-diff.js.map +0 -1
- package/dist/tools/edit.d.ts +0 -11
- package/dist/tools/edit.d.ts.map +0 -1
- package/dist/tools/edit.js +0 -129
- package/dist/tools/edit.js.map +0 -1
- package/dist/unified-session.d.ts +0 -42
- package/dist/unified-session.d.ts.map +0 -1
- package/dist/unified-session.js +0 -271
- package/dist/unified-session.js.map +0 -1
- package/skills/.claude-plugin/marketplace.json +0 -45
- package/skills/README.md +0 -94
- package/skills/THIRD_PARTY_NOTICES.md +0 -405
- package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
- package/skills/skills/algorithmic-art/SKILL.md +0 -405
- package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
- package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
- package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
- package/skills/skills/brand-guidelines/SKILL.md +0 -73
- package/skills/skills/canvas-design/LICENSE.txt +0 -202
- package/skills/skills/canvas-design/SKILL.md +0 -130
- package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
- package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/skills/skills/doc-coauthoring/SKILL.md +0 -375
- package/skills/skills/docx/LICENSE.txt +0 -30
- package/skills/skills/docx/SKILL.md +0 -197
- package/skills/skills/docx/docx-js.md +0 -350
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
- package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
- package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
- package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
- package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
- package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
- package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
- package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
- package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
- package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
- package/skills/skills/docx/ooxml.md +0 -610
- package/skills/skills/docx/scripts/__init__.py +0 -1
- package/skills/skills/docx/scripts/document.py +0 -1276
- package/skills/skills/docx/scripts/templates/comments.xml +0 -3
- package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
- package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
- package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
- package/skills/skills/docx/scripts/templates/people.xml +0 -3
- package/skills/skills/docx/scripts/utilities.py +0 -374
- package/skills/skills/frontend-design/LICENSE.txt +0 -177
- package/skills/skills/frontend-design/SKILL.md +0 -42
- package/skills/skills/internal-comms/LICENSE.txt +0 -202
- package/skills/skills/internal-comms/SKILL.md +0 -32
- package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
- package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
- package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
- package/skills/skills/internal-comms/examples/general-comms.md +0 -16
- package/skills/skills/mcp-builder/LICENSE.txt +0 -202
- package/skills/skills/mcp-builder/SKILL.md +0 -236
- package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
- package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
- package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
- package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
- package/skills/skills/mcp-builder/scripts/connections.py +0 -151
- package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
- package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
- package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
- package/skills/skills/pdf/LICENSE.txt +0 -30
- package/skills/skills/pdf/SKILL.md +0 -294
- package/skills/skills/pdf/forms.md +0 -205
- package/skills/skills/pdf/reference.md +0 -612
- package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
- package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
- package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
- package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
- package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
- package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
- package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
- package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
- package/skills/skills/pptx/LICENSE.txt +0 -30
- package/skills/skills/pptx/SKILL.md +0 -484
- package/skills/skills/pptx/html2pptx.md +0 -625
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
- package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
- package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
- package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
- package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
- package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
- package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
- package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
- package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
- package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
- package/skills/skills/pptx/ooxml.md +0 -427
- package/skills/skills/pptx/scripts/html2pptx.js +0 -979
- package/skills/skills/pptx/scripts/inventory.py +0 -1020
- package/skills/skills/pptx/scripts/rearrange.py +0 -231
- package/skills/skills/pptx/scripts/replace.py +0 -385
- package/skills/skills/pptx/scripts/thumbnail.py +0 -450
- package/skills/skills/skill-creator/LICENSE.txt +0 -202
- package/skills/skills/skill-creator/SKILL.md +0 -356
- package/skills/skills/skill-creator/references/output-patterns.md +0 -82
- package/skills/skills/skill-creator/references/workflows.md +0 -28
- package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
- package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
- package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
- package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
- package/skills/skills/slack-gif-creator/SKILL.md +0 -254
- package/skills/skills/slack-gif-creator/core/easing.py +0 -234
- package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
- package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
- package/skills/skills/slack-gif-creator/core/validators.py +0 -136
- package/skills/skills/slack-gif-creator/requirements.txt +0 -4
- package/skills/skills/theme-factory/LICENSE.txt +0 -202
- package/skills/skills/theme-factory/SKILL.md +0 -59
- package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
- package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
- package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
- package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
- package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
- package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
- package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
- package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
- package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
- package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
- package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
- package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
- package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
- package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
- package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
- package/skills/skills/webapp-testing/LICENSE.txt +0 -202
- package/skills/skills/webapp-testing/SKILL.md +0 -96
- package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
- package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
- package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
- package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
- package/skills/skills/xlsx/LICENSE.txt +0 -30
- package/skills/skills/xlsx/SKILL.md +0 -289
- package/skills/skills/xlsx/recalc.py +0 -178
- package/skills/spec/agent-skills-spec.md +0 -3
- package/skills/template/SKILL.md +0 -6
- package/src/ai-client.ts +0 -1560
- package/src/remote-ai-client.ts +0 -664
- /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
|
@@ -1,290 +1,987 @@
|
|
|
1
|
-
import { ChatMessage, CompressionConfig } from './types.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
1
|
+
import { ChatMessage, CompressionConfig, AuthConfig } from './types.js';
|
|
2
|
+
import type { Message } from './ai-client/types.js';
|
|
3
|
+
import { getCancellationManager } from './cancellation.js';
|
|
4
|
+
import { createAIClient, AIClientInterface } from './ai-client-factory.js';
|
|
5
|
+
import { output as logOutput } from './output-util.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Model context window sizes (in tokens)
|
|
9
|
+
* Add models here as needed
|
|
10
|
+
*/
|
|
11
|
+
const MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
12
|
+
// OpenAI
|
|
13
|
+
'gpt-4': 8192,
|
|
14
|
+
'gpt-4-32k': 32768,
|
|
15
|
+
'gpt-4-turbo': 128000,
|
|
16
|
+
'gpt-4o': 128000,
|
|
17
|
+
'gpt-4o-mini': 128000,
|
|
18
|
+
'gpt-5': 200000,
|
|
19
|
+
|
|
20
|
+
// Anthropic Claude
|
|
21
|
+
'claude-sonnet-4-20250514': 200000,
|
|
22
|
+
'claude-sonnet-4': 200000,
|
|
23
|
+
'claude-opus-4': 200000,
|
|
24
|
+
'claude-3-5-sonnet': 200000,
|
|
25
|
+
'claude-3-opus': 200000,
|
|
26
|
+
|
|
27
|
+
// Google
|
|
28
|
+
'gemini-pro': 32768,
|
|
29
|
+
'gemini-ultra': 1000000,
|
|
30
|
+
|
|
31
|
+
// DeepSeek
|
|
32
|
+
'deepseek-chat': 128000,
|
|
33
|
+
'deepseek-coder': 128000,
|
|
34
|
+
'deepseek-reasoner': 128000,
|
|
35
|
+
|
|
36
|
+
// Qwen (Tongyi Qianwen)
|
|
37
|
+
'qwen-max': 32768,
|
|
38
|
+
'qwen-plus': 64000,
|
|
39
|
+
'qwen-turbo': 8000,
|
|
40
|
+
'qwen-long': 100000,
|
|
41
|
+
'qwen-vl-max': 128000,
|
|
42
|
+
'Qwen3-Coder': 32768,
|
|
43
|
+
|
|
44
|
+
// Zhipu AI (GLM)
|
|
45
|
+
'glm-4': 128000,
|
|
46
|
+
'glm-4-plus': 128000,
|
|
47
|
+
'glm-4-air': 128000,
|
|
48
|
+
'glm-4.7': 200000,
|
|
49
|
+
'glm-5': 200000,
|
|
50
|
+
|
|
51
|
+
// MiniMax
|
|
52
|
+
'MiniMax-M2': 200000,
|
|
53
|
+
'MiniMax-M2.1': 200000,
|
|
54
|
+
'MiniMax-M2.5': 200000,
|
|
55
|
+
|
|
56
|
+
// Moonshot (Kimi)
|
|
57
|
+
'moonshot-v1-8k': 8192,
|
|
58
|
+
'moonshot-v1-32k': 32768,
|
|
59
|
+
'moonshot-v1-128k': 131072,
|
|
60
|
+
|
|
61
|
+
// Doubao
|
|
62
|
+
'doubao-seed-1-8-251228': 256000,
|
|
63
|
+
'doubao-1-5-ui-tars-250428': 256000,
|
|
64
|
+
|
|
65
|
+
// Default fallback
|
|
66
|
+
'default': 200000
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Compression ratio constants - easier to tune and maintain
|
|
70
|
+
const COMPRESSION_RATIO = {
|
|
71
|
+
RESERVE_RATIO: 0.50, // Reserve 50% of context window for system prompt and recent messages
|
|
72
|
+
SUMMARY_THRESHOLD_RATIO: 0.15, // Use 15% of available space for summary
|
|
73
|
+
MAX_TOKENS_RATIO: 0.8, // Use 80% of reserved tokens for compression
|
|
74
|
+
SUMMARY_MAX_TOKENS_RATIO: 0.5, // Use 50% of reserved tokens for summary
|
|
75
|
+
MIN_SUMMARY_TOKENS: 800 // Minimum tokens for summary
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get the context window for a model
|
|
80
|
+
*/
|
|
81
|
+
export function getModelContextWindow(modelName?: string): number {
|
|
82
|
+
if (!modelName) return MODEL_CONTEXT_WINDOWS['default'];
|
|
83
|
+
|
|
84
|
+
// Try exact match first
|
|
85
|
+
if (MODEL_CONTEXT_WINDOWS[modelName]) {
|
|
86
|
+
return MODEL_CONTEXT_WINDOWS[modelName];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Try case-insensitive match
|
|
90
|
+
const lowerName = modelName.toLowerCase();
|
|
91
|
+
for (const [key, value] of Object.entries(MODEL_CONTEXT_WINDOWS)) {
|
|
92
|
+
if (key.toLowerCase() === lowerName) {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Try partial match (e.g., "claude" matches "claude-sonnet-4")
|
|
98
|
+
for (const [key, value] of Object.entries(MODEL_CONTEXT_WINDOWS)) {
|
|
99
|
+
if (lowerName.includes(key.toLowerCase()) || key.toLowerCase().includes(lowerName)) {
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return MODEL_CONTEXT_WINDOWS['default'];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface CompressionResult {
|
|
108
|
+
compressedMessages: ChatMessage[];
|
|
109
|
+
wasCompressed: boolean;
|
|
110
|
+
originalMessageCount: number;
|
|
111
|
+
compressedMessageCount: number;
|
|
112
|
+
originalSize: number;
|
|
113
|
+
compressedSize: number;
|
|
114
|
+
compressionMethod: 'summary' | 'truncate' | 'none';
|
|
115
|
+
tokensBefore?: number;
|
|
116
|
+
details?: CompactionDetails;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface CompactionDetails {
|
|
120
|
+
readFiles: string[];
|
|
121
|
+
modifiedFiles: string[];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface FileOperations {
|
|
125
|
+
read: Set<string>;
|
|
126
|
+
modified: Set<string>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface DetailedCompressionResult extends CompressionResult {
|
|
130
|
+
fileOperations?: FileOperations;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface CutPointResult {
|
|
134
|
+
firstKeptEntryIndex: number;
|
|
135
|
+
turnStartIndex: number;
|
|
136
|
+
isSplitTurn: boolean;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface CompactionPreparation {
|
|
140
|
+
firstKeptEntryIndex: number;
|
|
141
|
+
messagesToSummarize: ChatMessage[];
|
|
142
|
+
turnPrefixMessages: ChatMessage[];
|
|
143
|
+
isSplitTurn: boolean;
|
|
144
|
+
tokensBefore: number;
|
|
145
|
+
previousSummary?: string;
|
|
146
|
+
fileOps: FileOperations;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
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.
|
|
150
|
+
|
|
151
|
+
Use this EXACT format:
|
|
152
|
+
|
|
153
|
+
## Goal
|
|
154
|
+
[What is the user trying to accomplish? Can be multiple items if the session covers different tasks.]
|
|
155
|
+
|
|
156
|
+
## Constraints & Preferences
|
|
157
|
+
- [Any constraints, preferences, or requirements mentioned by user]
|
|
158
|
+
- [Or "(none)" if none were mentioned]
|
|
159
|
+
|
|
160
|
+
## Progress
|
|
161
|
+
### Done
|
|
162
|
+
- [x] [Completed tasks/changes]
|
|
163
|
+
|
|
164
|
+
### In Progress
|
|
165
|
+
- [ ] [Current work]
|
|
166
|
+
|
|
167
|
+
### Blocked
|
|
168
|
+
- [Issues preventing progress, if any]
|
|
169
|
+
|
|
170
|
+
## Key Decisions
|
|
171
|
+
- **[Decision]**: [Brief rationale]
|
|
172
|
+
|
|
173
|
+
## Next Steps
|
|
174
|
+
1. [Ordered list of what should happen next]
|
|
175
|
+
|
|
176
|
+
## Critical Context
|
|
177
|
+
|
|
178
|
+
### Key Files & Code
|
|
179
|
+
- [File path]: [Brief description of key content/structure]
|
|
180
|
+
- [File path]: [Brief description of key content/structure]
|
|
181
|
+
|
|
182
|
+
### Execution Results
|
|
183
|
+
- **Files**: [What files were read, written, or edited and key findings]
|
|
184
|
+
- **Commands**: [Key commands run and their outputs]
|
|
185
|
+
- **Search/Analysis**: [Key findings from code search or analysis]
|
|
186
|
+
|
|
187
|
+
### Project Context
|
|
188
|
+
- [Architecture patterns identified]
|
|
189
|
+
- [Important configurations]
|
|
190
|
+
- [Dependencies or libraries relevant to the task]
|
|
191
|
+
|
|
192
|
+
Keep each section concise. Preserve exact file paths, function names, and error messages.`;
|
|
193
|
+
|
|
194
|
+
const UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.
|
|
195
|
+
|
|
196
|
+
Update the existing structured summary with new information. RULES:
|
|
197
|
+
- PRESERVE all existing information from the previous summary
|
|
198
|
+
- ADD new progress, decisions, and context from the new messages
|
|
199
|
+
- UPDATE the Progress section: move items from "In Progress" to "Done" when completed
|
|
200
|
+
- UPDATE "Next Steps" based on what was accomplished
|
|
201
|
+
- PRESERVE exact file paths, function names, and error messages
|
|
202
|
+
- If something is no longer relevant, you may remove it
|
|
203
|
+
|
|
204
|
+
Use this EXACT format:
|
|
205
|
+
|
|
206
|
+
## Goal
|
|
207
|
+
[Preserve existing goals, add new ones if the task expanded]
|
|
208
|
+
|
|
209
|
+
## Constraints & Preferences
|
|
210
|
+
- [Preserve existing, add new ones discovered]
|
|
211
|
+
|
|
212
|
+
## Progress
|
|
213
|
+
### Done
|
|
214
|
+
- [x] [Include previously done items AND newly completed items]
|
|
215
|
+
|
|
216
|
+
### In Progress
|
|
217
|
+
- [ ] [Current work - update based on progress]
|
|
218
|
+
|
|
219
|
+
### Blocked
|
|
220
|
+
- [Current blockers - remove if resolved]
|
|
221
|
+
|
|
222
|
+
## Key Decisions
|
|
223
|
+
- **[Decision]**: [Brief rationale] (preserve all previous, add new)
|
|
224
|
+
|
|
225
|
+
## Next Steps
|
|
226
|
+
1. [Update based on current state]
|
|
227
|
+
|
|
228
|
+
## Critical Context
|
|
229
|
+
|
|
230
|
+
### Key Files & Code
|
|
231
|
+
- [Preserve existing file info, add new files read]
|
|
232
|
+
- [Include brief descriptions of key code structures]
|
|
233
|
+
|
|
234
|
+
### Execution Results
|
|
235
|
+
- **Files**: [Preserve file list, add new files read/written/edited]
|
|
236
|
+
- **Commands**: [Preserve outputs, add new command results]
|
|
237
|
+
- **Search/Analysis**: [Preserve findings, add new search results]
|
|
238
|
+
|
|
239
|
+
### Project Context
|
|
240
|
+
- [Preserve architecture info, add new patterns discovered]
|
|
241
|
+
- [Preserve configs, add new relevant dependencies]
|
|
242
|
+
|
|
243
|
+
Keep each section concise. Preserve exact file paths, function names, and error messages.`;
|
|
244
|
+
|
|
245
|
+
const TURN_PREFIX_SUMMARIZATION_PROMPT = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained.
|
|
246
|
+
|
|
247
|
+
Summarize the prefix to provide context for the retained suffix:
|
|
248
|
+
|
|
249
|
+
## Original Request
|
|
250
|
+
[What did the user ask for in this turn?]
|
|
251
|
+
|
|
252
|
+
## Early Progress
|
|
253
|
+
- [Key decisions and work done in the prefix]
|
|
254
|
+
|
|
255
|
+
## Critical Context
|
|
256
|
+
|
|
257
|
+
### Key Files & Code
|
|
258
|
+
- [File path]: [Brief description of key content/structure]
|
|
259
|
+
|
|
260
|
+
### Execution Results
|
|
261
|
+
- **Files**: [What files were read, written, or edited in this prefix]
|
|
262
|
+
- **Commands**: [Key commands run and outputs]
|
|
263
|
+
|
|
264
|
+
### Context for Suffix
|
|
265
|
+
- [Information needed to understand the retained recent work]
|
|
266
|
+
|
|
267
|
+
Be concise. Focus on what's needed to understand the kept suffix.`;
|
|
268
|
+
|
|
269
|
+
export class ContextCompressor {
|
|
270
|
+
private aiClient: AIClientInterface | null = null;
|
|
271
|
+
private defaultConfig: CompressionConfig = {
|
|
272
|
+
enabled: true
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
constructor(authConfig?: AuthConfig) {
|
|
276
|
+
if (authConfig) {
|
|
277
|
+
this.aiClient = createAIClient(authConfig);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
setAIClient(aiClient: AIClientInterface): void {
|
|
282
|
+
this.aiClient = aiClient;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Check if compression is needed based on token budget and model context window
|
|
287
|
+
* @param messages - Conversation messages
|
|
288
|
+
* @param config - Compression config
|
|
289
|
+
* @param modelName - Optional model name to determine context window
|
|
290
|
+
*/
|
|
291
|
+
needsCompression(
|
|
292
|
+
messages: ChatMessage[],
|
|
293
|
+
config?: Partial<CompressionConfig>,
|
|
294
|
+
modelName?: string
|
|
295
|
+
): { needsCompression: boolean; reason: string; tokenCount: number } {
|
|
296
|
+
const _cfg = { ...this.defaultConfig, ...config };
|
|
297
|
+
const _messageCount = messages.length;
|
|
298
|
+
const tokenCount = this.estimateContextTokens(messages);
|
|
299
|
+
|
|
300
|
+
// Get model context window
|
|
301
|
+
const contextWindow = getModelContextWindow(modelName);
|
|
302
|
+
|
|
303
|
+
// Calculate threshold using compression ratio constants
|
|
304
|
+
const reserveTokens = Math.floor(contextWindow * COMPRESSION_RATIO.RESERVE_RATIO);
|
|
305
|
+
const threshold = contextWindow - reserveTokens;
|
|
306
|
+
|
|
307
|
+
if (tokenCount > threshold) {
|
|
308
|
+
return {
|
|
309
|
+
needsCompression: true,
|
|
310
|
+
reason: `Token count (${tokenCount}) exceeds ${modelName ? `${modelName}` : ''} context budget (${threshold}, contextWindow: ${contextWindow})`,
|
|
311
|
+
tokenCount
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return { needsCompression: false, reason: '', tokenCount };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Estimate token count for a single message using message-type-aware heuristic
|
|
320
|
+
*/
|
|
321
|
+
estimateMessageTokens(message: ChatMessage): number {
|
|
322
|
+
let chars = 0;
|
|
323
|
+
|
|
324
|
+
switch (message.role) {
|
|
325
|
+
case 'user':
|
|
326
|
+
case 'system':
|
|
327
|
+
case 'tool': {
|
|
328
|
+
chars = message.content.length;
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
case 'assistant': {
|
|
332
|
+
if (message.reasoning_content) {
|
|
333
|
+
chars += message.reasoning_content.length;
|
|
334
|
+
}
|
|
335
|
+
const toolCalls = message.tool_calls as any[] | undefined;
|
|
336
|
+
if (toolCalls && toolCalls.length > 0) {
|
|
337
|
+
for (const toolCall of toolCalls) {
|
|
338
|
+
chars += JSON.stringify(toolCall).length;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
chars += message.content.length;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return Math.ceil(chars / 4);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Estimate total token count for a conversation
|
|
351
|
+
*/
|
|
352
|
+
estimateContextTokens(messages: ChatMessage[]): number {
|
|
353
|
+
let total = 0;
|
|
354
|
+
for (const msg of messages) {
|
|
355
|
+
total += this.estimateMessageTokens(msg);
|
|
356
|
+
}
|
|
357
|
+
return total;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Find valid cut points: indices of messages that can be cut at
|
|
362
|
+
* Never cut at tool results (they must follow their tool call)
|
|
363
|
+
*/
|
|
364
|
+
findValidCutPoints(messages: ChatMessage[], startIndex: number, endIndex: number): number[] {
|
|
365
|
+
const cutPoints: number[] = [];
|
|
366
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
367
|
+
const msg = messages[i];
|
|
368
|
+
switch (msg.role) {
|
|
369
|
+
case 'user':
|
|
370
|
+
case 'assistant':
|
|
371
|
+
case 'system':
|
|
372
|
+
cutPoints.push(i);
|
|
373
|
+
break;
|
|
374
|
+
case 'tool':
|
|
375
|
+
// Tool results cannot be cut at (they must follow their tool call)
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return cutPoints;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Find the user message that starts the turn containing the given index
|
|
384
|
+
*/
|
|
385
|
+
findTurnStartIndex(messages: ChatMessage[], entryIndex: number, startIndex: number): number {
|
|
386
|
+
for (let i = entryIndex; i >= startIndex; i--) {
|
|
387
|
+
const role = messages[i].role;
|
|
388
|
+
if (role === 'user') {
|
|
389
|
+
return i;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return -1;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Find the cut point that keeps approximately keepRecentTokens
|
|
397
|
+
* Walks backwards from newest, accumulating estimated message sizes
|
|
398
|
+
*/
|
|
399
|
+
findCutPoint(
|
|
400
|
+
messages: ChatMessage[],
|
|
401
|
+
startIndex: number,
|
|
402
|
+
endIndex: number,
|
|
403
|
+
keepRecentTokens: number
|
|
404
|
+
): CutPointResult {
|
|
405
|
+
const cutPoints = this.findValidCutPoints(messages, startIndex, endIndex);
|
|
406
|
+
|
|
407
|
+
if (cutPoints.length === 0) {
|
|
408
|
+
return { firstKeptEntryIndex: startIndex, turnStartIndex: -1, isSplitTurn: false };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Walk backwards from newest, accumulating estimated message sizes
|
|
412
|
+
let accumulatedTokens = 0;
|
|
413
|
+
let cutIndex = cutPoints[cutPoints.length - 1]; // Start with the last cut point
|
|
414
|
+
|
|
415
|
+
for (let i = endIndex - 1; i >= startIndex; i--) {
|
|
416
|
+
const messageTokens = this.estimateMessageTokens(messages[i]);
|
|
417
|
+
accumulatedTokens += messageTokens;
|
|
418
|
+
|
|
419
|
+
if (accumulatedTokens >= keepRecentTokens) {
|
|
420
|
+
// Find the closest valid cut point at or after this entry
|
|
421
|
+
// Search from the END of cutPoints array (closest to i)
|
|
422
|
+
for (let c = cutPoints.length - 1; c >= 0; c--) {
|
|
423
|
+
if (cutPoints[c] >= i) {
|
|
424
|
+
cutIndex = cutPoints[c];
|
|
425
|
+
} else {
|
|
426
|
+
// Since cutPoints is sorted ascending, no need to continue
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Determine if this is a split turn
|
|
435
|
+
const isUserMessage = messages[cutIndex].role === 'user';
|
|
436
|
+
const turnStartIndex = isUserMessage ? -1 : this.findTurnStartIndex(messages, cutIndex, startIndex);
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
firstKeptEntryIndex: cutIndex,
|
|
440
|
+
turnStartIndex,
|
|
441
|
+
isSplitTurn: !isUserMessage && turnStartIndex !== -1
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Extract file operations from messages by analyzing tool calls
|
|
447
|
+
*/
|
|
448
|
+
extractFileOperations(messages: ChatMessage[]): FileOperations {
|
|
449
|
+
const fileOps: FileOperations = {
|
|
450
|
+
read: new Set<string>(),
|
|
451
|
+
modified: new Set<string>()
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
let _totalToolCalls = 0;
|
|
455
|
+
let _matchedToolCalls = 0;
|
|
456
|
+
|
|
457
|
+
// Normalize tool name (handle both API format and internal format)
|
|
458
|
+
const isReadTool = (name: string) => name === 'read_file' || name === 'Read';
|
|
459
|
+
const isWriteTool = (name: string) => name === 'write_file' || name === 'Write';
|
|
460
|
+
const isEditTool = (name: string) => name === 'Edit';
|
|
461
|
+
const isDeleteTool = (name: string) => name === 'DeleteFile';
|
|
462
|
+
|
|
463
|
+
const getFilePath = (args: Record<string, unknown>): string => {
|
|
464
|
+
return (args.filePath as string) || (args.absolute_path as string) || (args.path as string) || '';
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
for (const msg of messages) {
|
|
468
|
+
// Case 1: assistant with tool_calls field
|
|
469
|
+
if (msg.role === 'assistant' && msg.tool_calls) {
|
|
470
|
+
for (const toolCall of msg.tool_calls) {
|
|
471
|
+
_totalToolCalls++;
|
|
472
|
+
const toolName = toolCall.function?.name || '';
|
|
473
|
+
let args: Record<string, unknown> = {};
|
|
474
|
+
|
|
475
|
+
try {
|
|
476
|
+
args = JSON.parse(toolCall.function?.arguments || '{}');
|
|
477
|
+
} catch {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const filePath = getFilePath(args);
|
|
482
|
+
if (!filePath) continue;
|
|
483
|
+
|
|
484
|
+
if (isReadTool(toolName)) {
|
|
485
|
+
fileOps.read.add(filePath);
|
|
486
|
+
_matchedToolCalls++;
|
|
487
|
+
} else if (isWriteTool(toolName) || isEditTool(toolName) || isDeleteTool(toolName)) {
|
|
488
|
+
fileOps.modified.add(filePath);
|
|
489
|
+
_matchedToolCalls++;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Case 2: tool role with JSON content (like {"name":"Read","parameters":...})
|
|
495
|
+
if (msg.role === 'tool' && typeof msg.content === 'string') {
|
|
496
|
+
try {
|
|
497
|
+
const content = JSON.parse(msg.content);
|
|
498
|
+
_totalToolCalls++;
|
|
499
|
+
const toolName = content.name || '';
|
|
500
|
+
const args = content.parameters || {};
|
|
501
|
+
|
|
502
|
+
const filePath = getFilePath(args);
|
|
503
|
+
if (!filePath) continue;
|
|
504
|
+
|
|
505
|
+
if (isReadTool(toolName)) {
|
|
506
|
+
fileOps.read.add(filePath);
|
|
507
|
+
_matchedToolCalls++;
|
|
508
|
+
} else if (isWriteTool(toolName) || isEditTool(toolName) || isDeleteTool(toolName)) {
|
|
509
|
+
fileOps.modified.add(filePath);
|
|
510
|
+
_matchedToolCalls++;
|
|
511
|
+
}
|
|
512
|
+
} catch {
|
|
513
|
+
// Not JSON, skip
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return fileOps;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Merge file operations from previous compaction
|
|
523
|
+
*/
|
|
524
|
+
mergeFileOps(ops1: FileOperations, ops2: FileOperations): FileOperations {
|
|
525
|
+
return {
|
|
526
|
+
read: new Set([...ops1.read, ...ops2.read]),
|
|
527
|
+
modified: new Set([...ops1.modified, ...ops2.modified])
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Format file operations for inclusion in summary
|
|
533
|
+
*/
|
|
534
|
+
formatFileOperations(fileOps: FileOperations): string {
|
|
535
|
+
const readFiles = Array.from(fileOps.read);
|
|
536
|
+
const modifiedFiles = Array.from(fileOps.modified);
|
|
537
|
+
|
|
538
|
+
if (readFiles.length === 0 && modifiedFiles.length === 0) {
|
|
539
|
+
return '';
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
let formatted = '\n\n## File Operations\n\n';
|
|
543
|
+
|
|
544
|
+
if (readFiles.length > 0) {
|
|
545
|
+
formatted += '### Files read_file\n';
|
|
546
|
+
for (const file of readFiles) {
|
|
547
|
+
formatted += `- ${file}\n`;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (modifiedFiles.length > 0) {
|
|
552
|
+
formatted += '\n### Files Modified\n';
|
|
553
|
+
for (const file of modifiedFiles) {
|
|
554
|
+
formatted += `- ${file}\n`;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return formatted;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Prepare compaction - calculate cut point and extract messages to summarize
|
|
563
|
+
*/
|
|
564
|
+
prepareCompaction(
|
|
565
|
+
messages: ChatMessage[],
|
|
566
|
+
keepRecentTokens: number
|
|
567
|
+
): CompactionPreparation | undefined {
|
|
568
|
+
if (messages.length === 0) {
|
|
569
|
+
return undefined;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Check if last message already contains a compression summary
|
|
573
|
+
const lastMsg = messages[messages.length - 1];
|
|
574
|
+
const isAlreadyCompressed = lastMsg.role === 'user' &&
|
|
575
|
+
lastMsg.content.includes('[Previous conversation summarized');
|
|
576
|
+
|
|
577
|
+
if (isAlreadyCompressed) {
|
|
578
|
+
return undefined;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const startIndex = 0;
|
|
582
|
+
const endIndex = messages.length;
|
|
583
|
+
|
|
584
|
+
// Find cut point
|
|
585
|
+
const cutPoint = this.findCutPoint(messages, startIndex, endIndex, keepRecentTokens);
|
|
586
|
+
|
|
587
|
+
// Extract messages to summarize
|
|
588
|
+
|
|
589
|
+
const historyEnd = cutPoint.firstKeptEntryIndex;
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
const messagesToSummarize: ChatMessage[] = [];
|
|
594
|
+
|
|
595
|
+
for (let i = startIndex; i < historyEnd; i++) {
|
|
596
|
+
|
|
597
|
+
messagesToSummarize.push(messages[i]);
|
|
598
|
+
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
// Extract turn prefix messages if splitting (disabled for simplicity)
|
|
604
|
+
|
|
605
|
+
const turnPrefixMessages: ChatMessage[] = [];
|
|
606
|
+
if (cutPoint.isSplitTurn) {
|
|
607
|
+
for (let i = cutPoint.turnStartIndex; i < cutPoint.firstKeptEntryIndex; i++) {
|
|
608
|
+
turnPrefixMessages.push(messages[i]);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Get previous summary if exists (look for embedded summary in user messages)
|
|
613
|
+
let previousSummary: string | undefined;
|
|
614
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
615
|
+
const msg = messages[i];
|
|
616
|
+
if (msg.role === 'user' && msg.content.includes('[Previous conversation summarized')) {
|
|
617
|
+
// Extract the summary part from the content
|
|
618
|
+
const match = msg.content.match(/\[Previous conversation summarized.*?\]\n(.+?)(?=\n\n---\n\n|\n\n\[)/s);
|
|
619
|
+
if (match) {
|
|
620
|
+
previousSummary = match[1];
|
|
621
|
+
} else {
|
|
622
|
+
previousSummary = msg.content;
|
|
623
|
+
}
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Extract file operations
|
|
629
|
+
const fileOps = this.extractFileOperations(messagesToSummarize);
|
|
630
|
+
|
|
631
|
+
// Also extract from turn prefix
|
|
632
|
+
if (cutPoint.isSplitTurn) {
|
|
633
|
+
const prefixOps = this.extractFileOperations(turnPrefixMessages);
|
|
634
|
+
return {
|
|
635
|
+
firstKeptEntryIndex: cutPoint.firstKeptEntryIndex,
|
|
636
|
+
messagesToSummarize,
|
|
637
|
+
turnPrefixMessages,
|
|
638
|
+
isSplitTurn: cutPoint.isSplitTurn,
|
|
639
|
+
tokensBefore: this.estimateContextTokens(messagesToSummarize),
|
|
640
|
+
previousSummary,
|
|
641
|
+
fileOps: this.mergeFileOps(fileOps, prefixOps)
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return {
|
|
646
|
+
firstKeptEntryIndex: cutPoint.firstKeptEntryIndex,
|
|
647
|
+
messagesToSummarize,
|
|
648
|
+
turnPrefixMessages,
|
|
649
|
+
isSplitTurn: cutPoint.isSplitTurn,
|
|
650
|
+
tokensBefore: this.estimateContextTokens(messagesToSummarize),
|
|
651
|
+
previousSummary,
|
|
652
|
+
fileOps
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Generate summary using AI
|
|
658
|
+
*/
|
|
659
|
+
async generateSummary(
|
|
660
|
+
messages: ChatMessage[],
|
|
661
|
+
systemPrompt: string,
|
|
662
|
+
reserveTokens: number,
|
|
663
|
+
previousSummary?: string,
|
|
664
|
+
customInstructions?: string
|
|
665
|
+
): Promise<string> {
|
|
666
|
+
if (!this.aiClient) {
|
|
667
|
+
throw new Error('AI client not initialized for summarization');
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// Serialize conversation
|
|
671
|
+
const conversationText = messages
|
|
672
|
+
.map((m, idx) => {
|
|
673
|
+
const role = m.role === 'user' ? 'User' :
|
|
674
|
+
m.role === 'assistant' ? 'Assistant' :
|
|
675
|
+
m.role === 'tool' ? 'Tool' : m.role;
|
|
676
|
+
return `[${idx + 1}] ${role}:\n${m.content}`;
|
|
677
|
+
})
|
|
678
|
+
.join('\n\n' + '='.repeat(50) + '\n\n');
|
|
679
|
+
|
|
680
|
+
// Select prompt based on whether we have previous summary
|
|
681
|
+
let basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;
|
|
682
|
+
if (customInstructions) {
|
|
683
|
+
basePrompt = `${basePrompt}\n\nAdditional focus: ${customInstructions}`;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Build prompt
|
|
687
|
+
let promptText = `<conversation>\n${conversationText}\n</conversation>\n\n`;
|
|
688
|
+
if (previousSummary) {
|
|
689
|
+
promptText += `<previous-summary>\n${previousSummary}\n</previous-summary>\n\n`;
|
|
690
|
+
}
|
|
691
|
+
promptText += basePrompt;
|
|
692
|
+
|
|
693
|
+
const maxTokens = Math.floor(reserveTokens * COMPRESSION_RATIO.MAX_TOKENS_RATIO);
|
|
694
|
+
|
|
695
|
+
const summaryMessage: Message = {
|
|
696
|
+
role: 'user',
|
|
697
|
+
content: promptText
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
const aiPromise = this.aiClient.compress([summaryMessage], {
|
|
701
|
+
maxTokens,
|
|
702
|
+
temperature: 0.3
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
try {
|
|
706
|
+
const response = await getCancellationManager().withCancellation(
|
|
707
|
+
aiPromise,
|
|
708
|
+
'context-compression-summary'
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
const summary = response.choices[0]?.message?.content || '';
|
|
712
|
+
return typeof summary === 'string' ? summary : JSON.stringify(summary);
|
|
713
|
+
} catch (error: any) {
|
|
714
|
+
if (error.message === 'Operation cancelled by user') {
|
|
715
|
+
throw error;
|
|
716
|
+
}
|
|
717
|
+
console.error('Failed to generate summary:', error);
|
|
718
|
+
await logOutput('error', 'Failed to generate summary', { error: error.message });
|
|
719
|
+
const userCount = messages.filter(m => m.role === 'user').length;
|
|
720
|
+
const toolCount = messages.filter(m => m.role === 'tool').length;
|
|
721
|
+
return `[Summary of ${messages.length} messages: ${userCount} user exchanges, ${toolCount} tool calls. Key topics discussed but details unavailable due to summarization error.]`;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Generate turn prefix summary when splitting a turn
|
|
727
|
+
*/
|
|
728
|
+
async generateTurnPrefixSummary(
|
|
729
|
+
messages: ChatMessage[],
|
|
730
|
+
reserveTokens: number
|
|
731
|
+
): Promise<string> {
|
|
732
|
+
if (!this.aiClient) {
|
|
733
|
+
throw new Error('AI client not initialized for summarization');
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const conversationText = messages
|
|
737
|
+
.map((m, idx) => {
|
|
738
|
+
const role = m.role === 'user' ? 'User' :
|
|
739
|
+
m.role === 'assistant' ? 'Assistant' :
|
|
740
|
+
m.role === 'tool' ? 'Tool' : m.role;
|
|
741
|
+
return `[${idx + 1}] ${role}:\n${m.content}`;
|
|
742
|
+
})
|
|
743
|
+
.join('\n\n' + '='.repeat(50) + '\n\n');
|
|
744
|
+
|
|
745
|
+
const promptText = `<conversation>\n${conversationText}\n</conversation>\n\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`;
|
|
746
|
+
const maxTokens = Math.floor(reserveTokens * COMPRESSION_RATIO.SUMMARY_MAX_TOKENS_RATIO);
|
|
747
|
+
|
|
748
|
+
const summaryMessage: Message = {
|
|
749
|
+
role: 'user',
|
|
750
|
+
content: promptText
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
const aiPromise = this.aiClient.compress([summaryMessage], {
|
|
754
|
+
maxTokens,
|
|
755
|
+
temperature: 0.3
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
try {
|
|
759
|
+
const response = await getCancellationManager().withCancellation(
|
|
760
|
+
aiPromise,
|
|
761
|
+
'context-compression-turn-prefix'
|
|
762
|
+
);
|
|
763
|
+
|
|
764
|
+
const content = response.choices[0]?.message?.content || '';
|
|
765
|
+
return typeof content === 'string' ? content : JSON.stringify(content);
|
|
766
|
+
} catch (error: any) {
|
|
767
|
+
if (error.message === 'Operation cancelled by user') {
|
|
768
|
+
throw error;
|
|
769
|
+
}
|
|
770
|
+
console.error('Failed to generate turn prefix summary:', error);
|
|
771
|
+
await logOutput('error', 'Failed to generate turn prefix summary', { error: error.message });
|
|
772
|
+
return '[Turn prefix summary unavailable]';
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Main compression function with incremental compaction support
|
|
778
|
+
*/
|
|
779
|
+
async compressContext(
|
|
780
|
+
messages: ChatMessage[],
|
|
781
|
+
systemPrompt: string,
|
|
782
|
+
config?: Partial<CompressionConfig>,
|
|
783
|
+
previousSummary?: string,
|
|
784
|
+
modelName?: string
|
|
785
|
+
): Promise<CompressionResult> {
|
|
786
|
+
const _cfg = { ...this.defaultConfig, ...config };
|
|
787
|
+
const originalMessageCount = messages.length;
|
|
788
|
+
const originalSize = messages.reduce((total, msg) => total + msg.content.length, 0);
|
|
789
|
+
const _originalTokens = this.estimateContextTokens(messages);
|
|
790
|
+
const contextWindow = getModelContextWindow(modelName);
|
|
791
|
+
|
|
792
|
+
// Check if compression is needed
|
|
793
|
+
const { needsCompression } = this.needsCompression(messages, config, modelName);
|
|
794
|
+
if (!needsCompression) {
|
|
795
|
+
return {
|
|
796
|
+
compressedMessages: messages,
|
|
797
|
+
wasCompressed: false,
|
|
798
|
+
originalMessageCount,
|
|
799
|
+
compressedMessageCount: messages.length,
|
|
800
|
+
originalSize,
|
|
801
|
+
compressedSize: originalSize,
|
|
802
|
+
compressionMethod: 'none'
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Prepare compaction
|
|
807
|
+
// Reserve 50% of context window for new conversation, 15% for summary
|
|
808
|
+
const reserveTokens = Math.floor(contextWindow * COMPRESSION_RATIO.RESERVE_RATIO);
|
|
809
|
+
const summaryReserveTokens = Math.max(COMPRESSION_RATIO.MIN_SUMMARY_TOKENS, Math.floor((contextWindow - reserveTokens) * COMPRESSION_RATIO.SUMMARY_THRESHOLD_RATIO));
|
|
810
|
+
const keepRecentTokens = contextWindow - reserveTokens - summaryReserveTokens;
|
|
811
|
+
const preparation = this.prepareCompaction(messages, Math.max(0, keepRecentTokens));
|
|
812
|
+
|
|
813
|
+
if (!preparation) {
|
|
814
|
+
// Already compressed or no valid cut point
|
|
815
|
+
return {
|
|
816
|
+
compressedMessages: messages,
|
|
817
|
+
wasCompressed: false,
|
|
818
|
+
originalMessageCount,
|
|
819
|
+
compressedMessageCount: messages.length,
|
|
820
|
+
originalSize,
|
|
821
|
+
compressedSize: originalSize,
|
|
822
|
+
compressionMethod: 'none'
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const {
|
|
827
|
+
firstKeptEntryIndex,
|
|
828
|
+
messagesToSummarize,
|
|
829
|
+
turnPrefixMessages,
|
|
830
|
+
isSplitTurn,
|
|
831
|
+
tokensBefore,
|
|
832
|
+
fileOps
|
|
833
|
+
} = preparation;
|
|
834
|
+
|
|
835
|
+
// Generate summary
|
|
836
|
+
let summary: string;
|
|
837
|
+
|
|
838
|
+
if (isSplitTurn && turnPrefixMessages.length > 0) {
|
|
839
|
+
// Generate both summaries in parallel
|
|
840
|
+
const [historyResult, turnPrefixResult] = await Promise.all([
|
|
841
|
+
messagesToSummarize.length > 0
|
|
842
|
+
? this.generateSummary(messagesToSummarize, systemPrompt, summaryReserveTokens, previousSummary)
|
|
843
|
+
: Promise.resolve('No prior history.'),
|
|
844
|
+
this.generateTurnPrefixSummary(turnPrefixMessages, summaryReserveTokens)
|
|
845
|
+
]);
|
|
846
|
+
summary = `${historyResult}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefixResult}`;
|
|
847
|
+
} else {
|
|
848
|
+
summary = await this.generateSummary(
|
|
849
|
+
messagesToSummarize,
|
|
850
|
+
systemPrompt,
|
|
851
|
+
summaryReserveTokens,
|
|
852
|
+
previousSummary
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// Add file operations to summary
|
|
857
|
+
summary += this.formatFileOperations(fileOps);
|
|
858
|
+
|
|
859
|
+
// Build compressed messages: summary + kept messages
|
|
860
|
+
// Summary is inserted as prefix in first user message to maintain valid message order
|
|
861
|
+
const compressedMessages: ChatMessage[] = [];
|
|
862
|
+
|
|
863
|
+
if (messagesToSummarize.length > 0) {
|
|
864
|
+
// Find first user message in kept messages
|
|
865
|
+
let firstKeptUserMsg: ChatMessage | null = null;
|
|
866
|
+
let firstKeptUserIndex = -1;
|
|
867
|
+
for (let i = firstKeptEntryIndex; i < messages.length; i++) {
|
|
868
|
+
if (messages[i].role === 'user') {
|
|
869
|
+
firstKeptUserMsg = messages[i];
|
|
870
|
+
firstKeptUserIndex = i;
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (firstKeptUserMsg) {
|
|
876
|
+
// Prepend summary to first user message content
|
|
877
|
+
const summaryPrefix = `[Previous conversation summarized (${messagesToSummarize.length} messages):]\n${summary}\n\n---\n\n`;
|
|
878
|
+
compressedMessages.push({
|
|
879
|
+
role: 'user',
|
|
880
|
+
content: summaryPrefix + firstKeptUserMsg.content,
|
|
881
|
+
timestamp: firstKeptUserMsg.timestamp,
|
|
882
|
+
images: firstKeptUserMsg.images
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
// Add remaining kept messages (skip the modified first user message)
|
|
886
|
+
for (let i = firstKeptUserIndex + 1; i < messages.length; i++) {
|
|
887
|
+
const msg = messages[i];
|
|
888
|
+
compressedMessages.push({
|
|
889
|
+
role: msg.role,
|
|
890
|
+
content: msg.content,
|
|
891
|
+
timestamp: msg.timestamp,
|
|
892
|
+
images: msg.images,
|
|
893
|
+
reasoning_content: msg.reasoning_content,
|
|
894
|
+
tool_calls: msg.tool_calls,
|
|
895
|
+
tool_call_id: msg.tool_call_id
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
} else {
|
|
899
|
+
// No user message in kept messages (rare case)
|
|
900
|
+
// Insert summary as a user message, then add all kept messages
|
|
901
|
+
// This ensures valid message order: user �?assistant �?tool �?tool...
|
|
902
|
+
compressedMessages.push({
|
|
903
|
+
role: 'user',
|
|
904
|
+
content: `[Conversation Summary - ${messagesToSummarize.length} messages compressed]\n\n${summary}`,
|
|
905
|
+
timestamp: Date.now()
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
// Add all kept messages (they may start with assistant or tool)
|
|
909
|
+
for (let i = firstKeptEntryIndex; i < messages.length; i++) {
|
|
910
|
+
const msg = messages[i];
|
|
911
|
+
compressedMessages.push({
|
|
912
|
+
role: msg.role,
|
|
913
|
+
content: msg.content,
|
|
914
|
+
timestamp: msg.timestamp,
|
|
915
|
+
images: msg.images,
|
|
916
|
+
reasoning_content: msg.reasoning_content,
|
|
917
|
+
tool_calls: msg.tool_calls,
|
|
918
|
+
tool_call_id: msg.tool_call_id
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
} else {
|
|
923
|
+
// No messages to summarize, just keep all messages
|
|
924
|
+
for (let i = firstKeptEntryIndex; i < messages.length; i++) {
|
|
925
|
+
const msg = messages[i];
|
|
926
|
+
compressedMessages.push({
|
|
927
|
+
role: msg.role,
|
|
928
|
+
content: msg.content,
|
|
929
|
+
timestamp: msg.timestamp,
|
|
930
|
+
images: msg.images,
|
|
931
|
+
reasoning_content: msg.reasoning_content,
|
|
932
|
+
tool_calls: msg.tool_calls,
|
|
933
|
+
tool_call_id: msg.tool_call_id
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
const compressedSize = compressedMessages.reduce((total, msg) => total + msg.content.length, 0);
|
|
939
|
+
const _compressedTokens = this.estimateContextTokens(compressedMessages);
|
|
940
|
+
const _reductionPercent = Math.round((1 - compressedSize / originalSize) * 100);
|
|
941
|
+
|
|
942
|
+
return {
|
|
943
|
+
compressedMessages,
|
|
944
|
+
wasCompressed: true,
|
|
945
|
+
originalMessageCount,
|
|
946
|
+
compressedMessageCount: compressedMessages.length,
|
|
947
|
+
originalSize,
|
|
948
|
+
compressedSize,
|
|
949
|
+
compressionMethod: 'summary',
|
|
950
|
+
tokensBefore,
|
|
951
|
+
details: {
|
|
952
|
+
readFiles: Array.from(fileOps.read),
|
|
953
|
+
modifiedFiles: Array.from(fileOps.modified)
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* Create compressed message copy for saving
|
|
960
|
+
*/
|
|
961
|
+
createCompressedSnapshot(
|
|
962
|
+
messages: ChatMessage[],
|
|
963
|
+
compressionResult: CompressionResult
|
|
964
|
+
): object {
|
|
965
|
+
return {
|
|
966
|
+
timestamp: Date.now(),
|
|
967
|
+
originalMessageCount: compressionResult.originalMessageCount,
|
|
968
|
+
compressedMessageCount: compressionResult.compressedMessageCount,
|
|
969
|
+
originalSize: compressionResult.originalSize,
|
|
970
|
+
compressedSize: compressionResult.compressedSize,
|
|
971
|
+
compressionMethod: compressionResult.compressionMethod,
|
|
972
|
+
tokensBefore: compressionResult.tokensBefore,
|
|
973
|
+
details: compressionResult.details,
|
|
974
|
+
messages: compressionResult.compressedMessages
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
let compressorInstance: ContextCompressor | null = null;
|
|
980
|
+
|
|
981
|
+
export function getContextCompressor(authConfig?: AuthConfig): ContextCompressor {
|
|
982
|
+
if (!compressorInstance) {
|
|
983
|
+
compressorInstance = new ContextCompressor(authConfig);
|
|
984
|
+
}
|
|
985
|
+
return compressorInstance;
|
|
986
|
+
}
|
|
987
|
+
|