@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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/workflows/ci.yml +72 -0
- package/.github/workflows/release.yml +109 -0
- package/.gitmodules +3 -3
- package/README.md +326 -280
- package/README_CN.md +325 -279
- package/dist/ai-client/factory.d.ts +52 -0
- package/dist/ai-client/factory.d.ts.map +1 -0
- package/dist/ai-client/factory.js +132 -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 +400 -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 +286 -0
- package/dist/ai-client/providers/openai.js.map +1 -0
- package/dist/ai-client/providers/remote.d.ts +111 -0
- package/dist/ai-client/providers/remote.d.ts.map +1 -0
- package/dist/ai-client/providers/remote.js +351 -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 +260 -0
- package/dist/ai-client/types.d.ts.map +1 -0
- package/dist/ai-client/types.js +73 -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 +160 -168
- 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 +55 -32
- package/dist/cancellation.js.map +1 -1
- package/dist/checkpoint.d.ts +1 -1
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +2 -2
- package/dist/checkpoint.js.map +1 -1
- package/dist/cli.js +626 -13
- 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 +81 -16
- package/dist/context-compressor.d.ts.map +1 -1
- package/dist/context-compressor.js +712 -153
- package/dist/context-compressor.js.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.js +4 -2
- package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.d.ts +29 -2
- package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.js +87 -45
- package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
- package/dist/gui-subagent/index.d.ts +16 -1
- package/dist/gui-subagent/index.d.ts.map +1 -1
- package/dist/gui-subagent/index.js +4 -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 +29 -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 +6 -3
- package/dist/input-processor.js.map +1 -1
- package/dist/mcp.d.ts +5 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +81 -35
- package/dist/mcp.js.map +1 -1
- package/dist/ripgrep.d.ts +29 -0
- package/dist/ripgrep.d.ts.map +1 -0
- package/dist/ripgrep.js +292 -0
- package/dist/ripgrep.js.map +1 -0
- package/dist/session.d.ts +23 -7
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +624 -243
- 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 +125 -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 +7 -1
- package/dist/skill-invoker.d.ts.map +1 -1
- package/dist/skill-invoker.js +34 -13
- 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 +46 -44
- 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 +340 -0
- package/dist/skill-manager.js.map +1 -0
- package/dist/slash-commands.d.ts +38 -1
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +912 -296
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +67 -55
- 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 +84 -34
- 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/tools.d.ts +23 -7
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +797 -437
- 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 +27 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +17 -28
- 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 +60 -47
- 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 +439 -439
- package/find-skills/SKILL.md +133 -0
- package/package.json +89 -90
- package/scripts/install-ripgrep.js +241 -0
- package/src/ai-client/factory.ts +151 -0
- package/src/ai-client/index.ts +61 -0
- package/src/ai-client/providers/anthropic.ts +466 -0
- package/src/ai-client/providers/openai.ts +342 -0
- package/src/ai-client/providers/remote.ts +436 -0
- package/src/ai-client/registry.ts +97 -0
- package/src/ai-client/types.ts +345 -0
- package/src/ai-client-factory.ts +204 -0
- package/src/auth.ts +663 -614
- package/src/cancellation.ts +205 -176
- package/src/checkpoint.ts +219 -219
- package/src/cli.ts +1406 -743
- package/src/config.ts +341 -297
- package/src/context-compressor.ts +982 -290
- package/src/conversation.ts +288 -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 +1151 -1089
- package/src/gui-subagent/agent/index.ts +5 -5
- package/src/gui-subagent/index.ts +177 -163
- package/src/gui-subagent/operator/base-operator.ts +244 -245
- package/src/gui-subagent/operator/computer-operator.ts +540 -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 +6 -3
- package/src/logger.ts +438 -438
- package/src/mcp.ts +730 -682
- package/src/memory.ts +344 -344
- package/src/ripgrep.ts +368 -0
- package/src/session-manager.ts +308 -308
- package/src/session.ts +948 -386
- package/src/shell.ts +133 -0
- package/src/skill-installer.ts +518 -0
- package/src/skill-invoker.ts +960 -935
- package/src/skill-loader.ts +501 -496
- package/src/skill-manager.ts +384 -0
- package/src/slash-commands.ts +2181 -1389
- package/src/smart-approval.ts +117 -73
- package/src/system-prompt-generator.ts +89 -34
- package/src/terminal.ts +96 -0
- package/src/theme.ts +738 -738
- package/src/tools.ts +1336 -773
- package/src/truncate.ts +173 -0
- package/src/types.ts +219 -198
- package/src/update.ts +22 -32
- package/src/workflow.ts +523 -508
- package/tsconfig.json +22 -22
- package/vitest.config.ts +19 -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-output-adapter.d.ts +0 -232
- package/dist/sdk-output-adapter.d.ts.map +0 -1
- package/dist/sdk-output-adapter.js +0 -636
- package/dist/sdk-output-adapter.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/sdk-session.d.ts +0 -13
- package/dist/sdk-session.d.ts.map +0 -1
- package/dist/sdk-session.js +0 -48
- package/dist/sdk-session.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/dist/tools.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
|
+
import { select, text } from '@clack/prompts';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import { fileURLToPath } from 'url';
|
|
4
5
|
import readline from 'readline';
|
|
5
|
-
import {
|
|
6
|
-
import { promisify } from 'util';
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
7
|
import { glob } from 'glob';
|
|
8
8
|
import axios from 'axios';
|
|
9
|
-
import inquirer from 'inquirer';
|
|
10
9
|
import { ExecutionMode, AuthType } from './types.js';
|
|
11
10
|
import { colors, icons } from './theme.js';
|
|
12
11
|
import { getLogger } from './logger.js';
|
|
13
12
|
import { getCancellationManager } from './cancellation.js';
|
|
14
13
|
import { SystemPromptGenerator } from './system-prompt-generator.js';
|
|
15
|
-
|
|
14
|
+
import { getSingletonSession } from './session.js';
|
|
15
|
+
import { ripgrep, fdFind } from './ripgrep.js';
|
|
16
|
+
import { getShellConfig, killProcessTree, quoteShellCommand } from './shell.js';
|
|
17
|
+
import { truncateTail, buildTruncationNotice } from './truncate.js';
|
|
18
|
+
import { createAIClient } from './ai-client-factory.js';
|
|
16
19
|
//
|
|
17
20
|
// Tool Description Pattern
|
|
18
21
|
//
|
|
@@ -64,8 +67,16 @@ export class ReadTool {
|
|
|
64
67
|
- Use offset and limit for large files to avoid loading entire content
|
|
65
68
|
- Combine with ListDirectory to explore project structure first
|
|
66
69
|
- Don't re-read files unnecessarily`;
|
|
67
|
-
allowedModes = [
|
|
70
|
+
allowedModes = [
|
|
71
|
+
ExecutionMode.YOLO,
|
|
72
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
73
|
+
ExecutionMode.PLAN,
|
|
74
|
+
ExecutionMode.SMART,
|
|
75
|
+
];
|
|
68
76
|
async execute(params) {
|
|
77
|
+
if (!params || typeof params.filePath !== 'string') {
|
|
78
|
+
throw new Error('filePath is required and must be a string');
|
|
79
|
+
}
|
|
69
80
|
const { filePath, offset = 0, limit } = params;
|
|
70
81
|
try {
|
|
71
82
|
// Handle ~ (user home directory) in file paths
|
|
@@ -82,10 +93,18 @@ export class ReadTool {
|
|
|
82
93
|
const absolutePath = path.resolve(resolvedPath);
|
|
83
94
|
const content = await fs.readFile(absolutePath, 'utf-8');
|
|
84
95
|
const lines = content.split('\n');
|
|
96
|
+
const totalLines = lines.length;
|
|
85
97
|
const startLine = Math.max(0, offset);
|
|
86
|
-
const endLine = limit !== undefined ? Math.min(
|
|
98
|
+
const endLine = limit !== undefined ? Math.min(totalLines, startLine + limit) : totalLines;
|
|
87
99
|
const selectedLines = lines.slice(startLine, endLine);
|
|
88
|
-
|
|
100
|
+
const result = selectedLines.join('\n');
|
|
101
|
+
// Add truncation notice if content is limited
|
|
102
|
+
if (limit !== undefined && endLine < totalLines) {
|
|
103
|
+
const remaining = totalLines - endLine;
|
|
104
|
+
const nextOffset = endLine;
|
|
105
|
+
return (result + `\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue]`);
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
89
108
|
}
|
|
90
109
|
catch (error) {
|
|
91
110
|
// Show user-friendly path in error message
|
|
@@ -146,7 +165,7 @@ export class WriteTool {
|
|
|
146
165
|
message: `Successfully wrote to ${filePath}`,
|
|
147
166
|
filePath,
|
|
148
167
|
lineCount,
|
|
149
|
-
preview: isTruncated ? preview + '\n...' : preview
|
|
168
|
+
preview: isTruncated ? preview + '\n...' : preview,
|
|
150
169
|
};
|
|
151
170
|
}
|
|
152
171
|
catch (error) {
|
|
@@ -156,7 +175,7 @@ export class WriteTool {
|
|
|
156
175
|
}
|
|
157
176
|
export class GrepTool {
|
|
158
177
|
name = 'Grep';
|
|
159
|
-
description = `Search for text patterns within files using
|
|
178
|
+
description = `Search for text patterns within files using ripgrep. This is your PRIMARY tool for finding specific code, functions, or content.
|
|
160
179
|
|
|
161
180
|
# When to Use
|
|
162
181
|
- Finding specific function definitions or calls
|
|
@@ -173,89 +192,41 @@ export class GrepTool {
|
|
|
173
192
|
# Parameters
|
|
174
193
|
- \`pattern\`: Regex or literal string to search for
|
|
175
194
|
- \`path\`: (Optional) Directory to search in, default: "."
|
|
176
|
-
- \`
|
|
177
|
-
- \`
|
|
178
|
-
- \`
|
|
179
|
-
- \`fixed_strings\`: (Optional) Treat pattern as literal string, default: false
|
|
195
|
+
- \`glob\`: (Optional) File glob pattern to include (e.g., "*.ts", "**/*.js")
|
|
196
|
+
- \`ignoreCase\`: (Optional) Case-insensitive search, default: false
|
|
197
|
+
- \`literal\`: (Optional) Treat pattern as literal string, default: false
|
|
180
198
|
- \`context\`: (Optional) Lines of context before/after matches
|
|
181
|
-
- \`no_ignore\`: (Optional) Don't ignore node_modules/.git, default: false
|
|
182
199
|
|
|
183
200
|
# Examples
|
|
184
201
|
- Find function: Grep(pattern="function myFunction")
|
|
185
202
|
- Find with context: Grep(pattern="TODO", context=3)
|
|
186
|
-
- TypeScript only: Grep(pattern="interface",
|
|
203
|
+
- TypeScript only: Grep(pattern="interface", glob="*.ts")
|
|
204
|
+
- Case-insensitive: Grep(pattern="error", ignoreCase=true)
|
|
187
205
|
|
|
188
206
|
# Best Practices
|
|
189
|
-
- Use
|
|
190
|
-
- Use
|
|
207
|
+
- Use ignoreCase=true for short patterns to reduce false positives
|
|
208
|
+
- Use literal=true if your pattern has special regex characters
|
|
191
209
|
- Use context to see the surrounding code for each match
|
|
192
|
-
- Combine with
|
|
193
|
-
allowedModes = [
|
|
210
|
+
- Combine with glob to narrow down file types`;
|
|
211
|
+
allowedModes = [
|
|
212
|
+
ExecutionMode.YOLO,
|
|
213
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
214
|
+
ExecutionMode.PLAN,
|
|
215
|
+
ExecutionMode.SMART,
|
|
216
|
+
];
|
|
194
217
|
async execute(params) {
|
|
195
|
-
const { pattern, path: searchPath = '.',
|
|
218
|
+
const { pattern, path: searchPath = '.', glob: includeGlob, ignoreCase = false, literal = false, context, limit, } = params;
|
|
196
219
|
try {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
ignore: ignorePatterns
|
|
220
|
+
const result = await ripgrep({
|
|
221
|
+
pattern,
|
|
222
|
+
path: searchPath,
|
|
223
|
+
glob: includeGlob,
|
|
224
|
+
ignoreCase,
|
|
225
|
+
literal,
|
|
226
|
+
context,
|
|
227
|
+
limit,
|
|
206
228
|
});
|
|
207
|
-
|
|
208
|
-
for (const file of files) {
|
|
209
|
-
const fullPath = path.join(absolutePath, file);
|
|
210
|
-
if (include && !file.match(include)) {
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
try {
|
|
214
|
-
const content = await fs.readFile(fullPath, 'utf-8');
|
|
215
|
-
const lines = content.split('\n');
|
|
216
|
-
lines.forEach((line, index) => {
|
|
217
|
-
let matches = false;
|
|
218
|
-
if (fixed_strings) {
|
|
219
|
-
matches = case_sensitive
|
|
220
|
-
? line.includes(pattern)
|
|
221
|
-
: line.toLowerCase().includes(pattern.toLowerCase());
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
try {
|
|
225
|
-
const flags = case_sensitive ? 'g' : 'gi';
|
|
226
|
-
const regex = new RegExp(pattern, flags);
|
|
227
|
-
matches = regex.test(line);
|
|
228
|
-
}
|
|
229
|
-
catch (e) {
|
|
230
|
-
matches = case_sensitive
|
|
231
|
-
? line.includes(pattern)
|
|
232
|
-
: line.toLowerCase().includes(pattern.toLowerCase());
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
if (matches) {
|
|
236
|
-
const contextLines = [];
|
|
237
|
-
if (before || context) {
|
|
238
|
-
const beforeCount = before || context || 0;
|
|
239
|
-
for (let i = Math.max(0, index - beforeCount); i < index; i++) {
|
|
240
|
-
contextLines.push(`${fullPath}:${i + 1}:${lines[i].trim()}`);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
contextLines.push(`${fullPath}:${index + 1}:${line.trim()}`);
|
|
244
|
-
if (after || context) {
|
|
245
|
-
const afterCount = after || context || 0;
|
|
246
|
-
for (let i = index + 1; i < Math.min(lines.length, index + 1 + afterCount); i++) {
|
|
247
|
-
contextLines.push(`${fullPath}:${i + 1}:${lines[i].trim()}`);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
results.push(...contextLines);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
catch (error) {
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
return results;
|
|
229
|
+
return result.split('\n').filter((line) => line.trim());
|
|
259
230
|
}
|
|
260
231
|
catch (error) {
|
|
261
232
|
throw new Error(`Grep failed: ${error.message}`);
|
|
@@ -287,13 +258,23 @@ export class BashTool {
|
|
|
287
258
|
- \`description\`: (Optional) Description of what the command does
|
|
288
259
|
- \`timeout\`: (Optional) Timeout in seconds, default: 120
|
|
289
260
|
- \`run_in_bg\`: (Optional) Run in background, default: false
|
|
261
|
+
- \`skillPath\`: (Optional) Skill directory path - when provided, NODE_PATH will include the skill's node_modules for dependency resolution
|
|
290
262
|
|
|
291
263
|
# Examples
|
|
292
264
|
- Install dependencies: Bash(command="npm install", description="Install npm dependencies")
|
|
265
|
+
- Run in skill directory with local deps: Bash(command="npm install docx", skillPath="~/.xagent/skills/docx")
|
|
266
|
+
|
|
267
|
+
# NODE_PATH Resolution
|
|
268
|
+
When \`skillPath\` is provided, the command will have access to:
|
|
269
|
+
- \`<skillPath>/node_modules\` (skill's local dependencies)
|
|
270
|
+
- xAgent's global node_modules
|
|
271
|
+
|
|
272
|
+
This is useful when working with skills that have local dependencies.
|
|
293
273
|
- Run tests: Bash(command="npm test", description="Run unit tests")
|
|
294
274
|
- Build project: Bash(command="npm run build", description="Build the project")
|
|
295
275
|
|
|
296
276
|
# Best Practices
|
|
277
|
+
- To install npm packages that persist across sessions, use: \`XAGENT_USER_NPM=1 npm install <package>\`
|
|
297
278
|
- Always provide a description for context
|
|
298
279
|
- Set appropriate timeout for long-running commands
|
|
299
280
|
- Use run_in_bg=true for commands that take a long time
|
|
@@ -301,7 +282,7 @@ export class BashTool {
|
|
|
301
282
|
- Use absolute paths or paths relative to project root`;
|
|
302
283
|
allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
|
|
303
284
|
async execute(params) {
|
|
304
|
-
const { command, cwd, description, timeout = 120, run_in_bg = false } = params;
|
|
285
|
+
const { command, cwd, description, timeout = 120, run_in_bg = false, skillPath } = params;
|
|
305
286
|
// Determine effective working directory
|
|
306
287
|
// Only use cwd if the command doesn't contain 'cd' (let LLM control directory)
|
|
307
288
|
let effectiveCwd;
|
|
@@ -318,26 +299,104 @@ export class BashTool {
|
|
|
318
299
|
// No cwd provided, use default
|
|
319
300
|
effectiveCwd = undefined;
|
|
320
301
|
}
|
|
321
|
-
//
|
|
322
|
-
const
|
|
302
|
+
// Resolve actual working directory
|
|
303
|
+
const actualCwd = effectiveCwd || process.cwd();
|
|
304
|
+
// Set up environment with NODE_PATH for node commands
|
|
305
|
+
const builtinNodeModulesPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'node_modules');
|
|
306
|
+
// Get user skills path from config (unified path: ~/.xagent/skills)
|
|
307
|
+
const { getConfigManager } = await import('./config.js');
|
|
308
|
+
const configManager = getConfigManager();
|
|
309
|
+
const userSkillsPath = configManager.getUserSkillsPath();
|
|
310
|
+
// Skill deps path: ~/.xagent/skills/{skillName}/node_modules
|
|
311
|
+
const builtinDepsPath = userSkillsPath ? path.join(userSkillsPath, 'builtin-deps') : null;
|
|
312
|
+
// Determine which node_modules to use
|
|
313
|
+
let skillNodeModulesPath = null;
|
|
314
|
+
// Priority 1: skillPath parameter (workspace scenario - LLM works in workspace, not skill dir)
|
|
315
|
+
if (skillPath) {
|
|
316
|
+
if (skillPath.includes('/builtin-deps/')) {
|
|
317
|
+
// Skill with deps in builtin-deps directory
|
|
318
|
+
const match = skillPath.match(/\/builtin-deps\/([^/]+)/);
|
|
319
|
+
if (match) {
|
|
320
|
+
skillNodeModulesPath = path.join(builtinDepsPath, match[1], 'node_modules');
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
// Regular skill
|
|
325
|
+
skillNodeModulesPath = path.join(skillPath, 'node_modules');
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Priority 2: Check if we're inside a skill directory
|
|
329
|
+
else if (userSkillsPath && userSkillsPath.trim() && actualCwd.startsWith(userSkillsPath)) {
|
|
330
|
+
const relativePath = actualCwd.substring(userSkillsPath.length);
|
|
331
|
+
const pathParts = relativePath.split(path.sep).filter(Boolean);
|
|
332
|
+
if (pathParts.length > 0) {
|
|
333
|
+
if (pathParts[0] === 'builtin-deps' && pathParts.length > 1) {
|
|
334
|
+
// Skill with local deps in builtin-deps
|
|
335
|
+
const skillName = pathParts[1];
|
|
336
|
+
skillNodeModulesPath = path.join(builtinDepsPath, skillName, 'node_modules');
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
// Regular skill
|
|
340
|
+
const skillName = pathParts[0];
|
|
341
|
+
const skillRoot = path.join(userSkillsPath, skillName);
|
|
342
|
+
try {
|
|
343
|
+
const skillMdPath = path.join(skillRoot, 'SKILL.md');
|
|
344
|
+
await fs.access(skillMdPath);
|
|
345
|
+
skillNodeModulesPath = path.join(skillRoot, 'node_modules');
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// Not a skill directory, skip
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Build NODE_PATH - skill's node_modules takes precedence (last-wins)
|
|
354
|
+
let nodePath;
|
|
355
|
+
if (skillNodeModulesPath) {
|
|
356
|
+
nodePath = `${skillNodeModulesPath}${path.delimiter}${builtinNodeModulesPath}`;
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
nodePath = builtinNodeModulesPath;
|
|
360
|
+
}
|
|
323
361
|
const env = {
|
|
324
362
|
...process.env,
|
|
325
|
-
NODE_PATH:
|
|
363
|
+
NODE_PATH: nodePath
|
|
326
364
|
};
|
|
327
|
-
//
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
365
|
+
// Handle npm install commands
|
|
366
|
+
const isNpmInstall = /\bnpm\s+install\b/i.test(command);
|
|
367
|
+
let finalCommand = command;
|
|
368
|
+
if (isNpmInstall && skillNodeModulesPath) {
|
|
369
|
+
// Install to skill's own node_modules
|
|
370
|
+
await fs.mkdir(skillNodeModulesPath, { recursive: true }).catch(() => { });
|
|
371
|
+
finalCommand = command.replace(/\bnpm\s+install\b/i, `npm install --prefix "${skillNodeModulesPath}"`);
|
|
372
|
+
}
|
|
373
|
+
// Get shell configuration (Windows Git Bash detection, etc.)
|
|
374
|
+
const { shell, args } = getShellConfig();
|
|
375
|
+
// Set up cross-platform encoding environment for command execution
|
|
376
|
+
if (process.platform === 'win32') {
|
|
377
|
+
// Windows: set code page to UTF-8 and ensure console output encoding
|
|
378
|
+
// chcp 65001 sets the console code page to UTF-8
|
|
379
|
+
// Use *>$null to suppress output (PowerShell-style, not CMD-style)
|
|
380
|
+
finalCommand = `chcp 65001 *>$null; [Console]::OutputEncoding = [System.Text.Encoding]::UTF8; [System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ${finalCommand}`;
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
// Unix/macOS: set locale to UTF-8 for proper encoding handling
|
|
384
|
+
finalCommand = `export LC_ALL=C.UTF-8; export LANG=C.UTF-8; export PYTHONIOENCODING=utf-8; ${finalCommand}`;
|
|
385
|
+
}
|
|
386
|
+
const shellArgs = [...args, quoteShellCommand(finalCommand)];
|
|
332
387
|
try {
|
|
333
388
|
if (run_in_bg) {
|
|
334
389
|
const taskId = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
335
|
-
const
|
|
390
|
+
const spawnOptions = {
|
|
336
391
|
cwd: effectiveCwd || process.cwd(),
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
392
|
+
env,
|
|
393
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
394
|
+
};
|
|
395
|
+
// On Windows, don't use detached mode for PowerShell as it breaks output piping
|
|
396
|
+
if (process.platform !== 'win32') {
|
|
397
|
+
spawnOptions.detached = true;
|
|
398
|
+
}
|
|
399
|
+
const childProcess = spawn(shell, shellArgs, spawnOptions);
|
|
341
400
|
const output = [];
|
|
342
401
|
childProcess.stdout?.on('data', (data) => {
|
|
343
402
|
const text = data.toString();
|
|
@@ -348,43 +407,127 @@ export class BashTool {
|
|
|
348
407
|
output.push(text);
|
|
349
408
|
});
|
|
350
409
|
childProcess.on('close', (code) => {
|
|
351
|
-
|
|
410
|
+
// Silent cleanup - don't log to avoid noise during normal operation
|
|
411
|
+
// Note: On Windows with PowerShell, the shell process exits after
|
|
412
|
+
// the command completes
|
|
352
413
|
});
|
|
353
414
|
const toolRegistry = getToolRegistry();
|
|
354
415
|
toolRegistry.addBackgroundTask(taskId, {
|
|
355
416
|
process: childProcess,
|
|
356
417
|
startTime: Date.now(),
|
|
357
|
-
output
|
|
418
|
+
output,
|
|
358
419
|
});
|
|
359
420
|
return {
|
|
360
421
|
stdout: '',
|
|
361
422
|
stderr: '',
|
|
362
423
|
exitCode: 0,
|
|
363
|
-
taskId
|
|
424
|
+
taskId,
|
|
364
425
|
};
|
|
365
426
|
}
|
|
366
427
|
else {
|
|
367
|
-
|
|
428
|
+
// Execute command with spawn for better control
|
|
429
|
+
const result = await this.spawnWithTimeout(shell, shellArgs, {
|
|
368
430
|
cwd: effectiveCwd || process.cwd(),
|
|
369
|
-
|
|
370
|
-
timeout
|
|
371
|
-
env
|
|
431
|
+
env,
|
|
432
|
+
timeout,
|
|
372
433
|
});
|
|
434
|
+
// Apply truncation to stdout and stderr separately
|
|
435
|
+
const stdoutResult = truncateTail(result.stdout);
|
|
436
|
+
const stderrResult = truncateTail(result.stderr);
|
|
437
|
+
let stdout = stdoutResult.content;
|
|
438
|
+
let stderr = stderrResult.content;
|
|
439
|
+
let truncationNotice = '';
|
|
440
|
+
if (stdoutResult.truncated) {
|
|
441
|
+
truncationNotice += buildTruncationNotice(stdoutResult) + '\n';
|
|
442
|
+
}
|
|
443
|
+
if (stderrResult.truncated) {
|
|
444
|
+
truncationNotice += buildTruncationNotice(stderrResult) + '\n';
|
|
445
|
+
}
|
|
373
446
|
return {
|
|
374
447
|
stdout,
|
|
375
448
|
stderr,
|
|
376
|
-
exitCode:
|
|
449
|
+
exitCode: result.exitCode,
|
|
450
|
+
truncated: stdoutResult.truncated || stderrResult.truncated,
|
|
451
|
+
truncationNotice: truncationNotice || undefined,
|
|
377
452
|
};
|
|
378
453
|
}
|
|
379
454
|
}
|
|
380
455
|
catch (error) {
|
|
456
|
+
// Check if this was a timeout
|
|
457
|
+
if (error.message === 'timeout') {
|
|
458
|
+
return {
|
|
459
|
+
stdout: '',
|
|
460
|
+
stderr: 'Command timed out',
|
|
461
|
+
exitCode: -1,
|
|
462
|
+
truncated: false,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
381
465
|
return {
|
|
382
466
|
stdout: error.stdout || '',
|
|
383
467
|
stderr: error.stderr || error.message,
|
|
384
|
-
exitCode: error.code || 1
|
|
468
|
+
exitCode: error.code || 1,
|
|
385
469
|
};
|
|
386
470
|
}
|
|
387
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* Execute a command with timeout support and proper process termination.
|
|
474
|
+
*/
|
|
475
|
+
spawnWithTimeout(shell, args, options) {
|
|
476
|
+
return new Promise((resolve, reject) => {
|
|
477
|
+
const { cwd, env, timeout } = options;
|
|
478
|
+
let timedOut = false;
|
|
479
|
+
let timeoutHandle;
|
|
480
|
+
const spawnOptions = {
|
|
481
|
+
cwd,
|
|
482
|
+
env,
|
|
483
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
484
|
+
};
|
|
485
|
+
// On Windows, don't use detached mode for PowerShell as it breaks output piping
|
|
486
|
+
if (process.platform !== 'win32') {
|
|
487
|
+
spawnOptions.detached = true;
|
|
488
|
+
}
|
|
489
|
+
const child = spawn(shell, args, spawnOptions);
|
|
490
|
+
const stdoutChunks = [];
|
|
491
|
+
const stderrChunks = [];
|
|
492
|
+
// Set timeout if provided
|
|
493
|
+
if (timeout > 0) {
|
|
494
|
+
timeoutHandle = setTimeout(() => {
|
|
495
|
+
timedOut = true;
|
|
496
|
+
if (child.pid) {
|
|
497
|
+
killProcessTree(child.pid);
|
|
498
|
+
}
|
|
499
|
+
}, timeout * 1000);
|
|
500
|
+
}
|
|
501
|
+
// Stream stdout
|
|
502
|
+
child.stdout?.on('data', (data) => {
|
|
503
|
+
stdoutChunks.push(data);
|
|
504
|
+
});
|
|
505
|
+
// Stream stderr
|
|
506
|
+
child.stderr?.on('data', (data) => {
|
|
507
|
+
stderrChunks.push(data);
|
|
508
|
+
});
|
|
509
|
+
// Handle process exit
|
|
510
|
+
child.on('close', (code) => {
|
|
511
|
+
if (timeoutHandle)
|
|
512
|
+
clearTimeout(timeoutHandle);
|
|
513
|
+
if (timedOut) {
|
|
514
|
+
reject(new Error('timeout'));
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
resolve({
|
|
518
|
+
stdout: Buffer.concat(stdoutChunks).toString('utf-8'),
|
|
519
|
+
stderr: Buffer.concat(stderrChunks).toString('utf-8'),
|
|
520
|
+
exitCode: code ?? -1,
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
// Handle spawn errors
|
|
524
|
+
child.on('error', (err) => {
|
|
525
|
+
if (timeoutHandle)
|
|
526
|
+
clearTimeout(timeoutHandle);
|
|
527
|
+
reject(err);
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
}
|
|
388
531
|
}
|
|
389
532
|
export class ListDirectoryTool {
|
|
390
533
|
name = 'ListDirectory';
|
|
@@ -416,7 +559,12 @@ export class ListDirectoryTool {
|
|
|
416
559
|
- Results are absolute paths
|
|
417
560
|
- Ignores node_modules and .git by default
|
|
418
561
|
- Combine with Read to examine file contents`;
|
|
419
|
-
allowedModes = [
|
|
562
|
+
allowedModes = [
|
|
563
|
+
ExecutionMode.YOLO,
|
|
564
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
565
|
+
ExecutionMode.PLAN,
|
|
566
|
+
ExecutionMode.SMART,
|
|
567
|
+
];
|
|
420
568
|
async execute(params) {
|
|
421
569
|
const { path: dirPath = '.', recursive = false } = params;
|
|
422
570
|
try {
|
|
@@ -429,9 +577,9 @@ export class ListDirectoryTool {
|
|
|
429
577
|
const files = await glob(pattern, {
|
|
430
578
|
cwd: absolutePath,
|
|
431
579
|
nodir: false,
|
|
432
|
-
ignore: ['node_modules/**', '.git/**']
|
|
580
|
+
ignore: ['node_modules/**', '.git/**'],
|
|
433
581
|
});
|
|
434
|
-
return files.map(file => path.join(absolutePath, file));
|
|
582
|
+
return files.map((file) => path.join(absolutePath, file));
|
|
435
583
|
}
|
|
436
584
|
catch (error) {
|
|
437
585
|
throw new Error(`Failed to list directory: ${error.message}`);
|
|
@@ -440,7 +588,7 @@ export class ListDirectoryTool {
|
|
|
440
588
|
}
|
|
441
589
|
export class SearchFilesTool {
|
|
442
590
|
name = 'SearchFiles';
|
|
443
|
-
description = `Search for files matching a glob pattern. This is your PRIMARY tool for finding files by name or extension.
|
|
591
|
+
description = `Search for files matching a glob pattern using fd. This is your PRIMARY tool for finding files by name or extension.
|
|
444
592
|
|
|
445
593
|
# When to Use
|
|
446
594
|
- Finding all files of a certain type (*.ts, *.json, *.md)
|
|
@@ -475,21 +623,35 @@ export class SearchFilesTool {
|
|
|
475
623
|
- Combine with path parameter to search specific directories
|
|
476
624
|
- Use limit parameter to avoid huge result sets
|
|
477
625
|
- Results are file paths, not content (use Grep on results if needed)`;
|
|
478
|
-
allowedModes = [
|
|
626
|
+
allowedModes = [
|
|
627
|
+
ExecutionMode.YOLO,
|
|
628
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
629
|
+
ExecutionMode.PLAN,
|
|
630
|
+
ExecutionMode.SMART,
|
|
631
|
+
];
|
|
479
632
|
async execute(params) {
|
|
480
633
|
const { pattern, path: searchPath = '.', limit = 1000 } = params;
|
|
481
634
|
try {
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
635
|
+
const output = await fdFind({
|
|
636
|
+
pattern,
|
|
637
|
+
path: searchPath,
|
|
638
|
+
limit,
|
|
485
639
|
});
|
|
640
|
+
if (output === 'No files found') {
|
|
641
|
+
return {
|
|
642
|
+
files: [],
|
|
643
|
+
total: 0,
|
|
644
|
+
truncated: false,
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
const files = output.split('\n').filter((line) => line.trim());
|
|
486
648
|
const total = files.length;
|
|
487
649
|
const truncated = total > limit;
|
|
488
650
|
const result = truncated ? files.slice(0, limit) : files;
|
|
489
651
|
return {
|
|
490
652
|
files: result,
|
|
491
653
|
total,
|
|
492
|
-
truncated
|
|
654
|
+
truncated,
|
|
493
655
|
};
|
|
494
656
|
}
|
|
495
657
|
catch (error) {
|
|
@@ -532,7 +694,7 @@ export class DeleteFileTool {
|
|
|
532
694
|
return {
|
|
533
695
|
success: true,
|
|
534
696
|
message: `Successfully deleted ${filePath}`,
|
|
535
|
-
filePath
|
|
697
|
+
filePath,
|
|
536
698
|
};
|
|
537
699
|
}
|
|
538
700
|
catch (error) {
|
|
@@ -574,7 +736,7 @@ export class CreateDirectoryTool {
|
|
|
574
736
|
await fs.mkdir(absolutePath, { recursive });
|
|
575
737
|
return {
|
|
576
738
|
success: true,
|
|
577
|
-
message: `Successfully created directory ${dirPath}
|
|
739
|
+
message: `Successfully created directory ${dirPath}`,
|
|
578
740
|
};
|
|
579
741
|
}
|
|
580
742
|
catch (error) {
|
|
@@ -584,29 +746,29 @@ export class CreateDirectoryTool {
|
|
|
584
746
|
}
|
|
585
747
|
// 编辑工具辅助函数
|
|
586
748
|
function detectLineEnding(content) {
|
|
587
|
-
const crlfIdx = content.indexOf(
|
|
588
|
-
const lfIdx = content.indexOf(
|
|
749
|
+
const crlfIdx = content.indexOf('\r\n');
|
|
750
|
+
const lfIdx = content.indexOf('\n');
|
|
589
751
|
if (lfIdx === -1)
|
|
590
|
-
return
|
|
752
|
+
return '\n';
|
|
591
753
|
if (crlfIdx === -1)
|
|
592
|
-
return
|
|
593
|
-
return crlfIdx < lfIdx ?
|
|
754
|
+
return '\n';
|
|
755
|
+
return crlfIdx < lfIdx ? '\r\n' : '\n';
|
|
594
756
|
}
|
|
595
757
|
function normalizeToLF(text) {
|
|
596
|
-
return text.replace(/\r\n/g,
|
|
758
|
+
return text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
597
759
|
}
|
|
598
760
|
function restoreLineEndings(text, ending) {
|
|
599
|
-
return ending ===
|
|
761
|
+
return ending === '\r\n' ? text.replace(/\n/g, '\r\n') : text;
|
|
600
762
|
}
|
|
601
763
|
function normalizeForFuzzyMatch(text) {
|
|
602
|
-
return
|
|
603
|
-
.split(
|
|
764
|
+
return text
|
|
765
|
+
.split('\n')
|
|
604
766
|
.map((line) => line.trimEnd())
|
|
605
|
-
.join(
|
|
767
|
+
.join('\n')
|
|
606
768
|
.replace(/['‘’""]/g, "'")
|
|
607
769
|
.replace(/["""]/g, '"')
|
|
608
|
-
.replace(/[—–‑−]/g,
|
|
609
|
-
.replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g,
|
|
770
|
+
.replace(/[—–‑−]/g, '-')
|
|
771
|
+
.replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g, ' ');
|
|
610
772
|
}
|
|
611
773
|
function fuzzyFindText(content, oldText) {
|
|
612
774
|
const exactIndex = content.indexOf(oldText);
|
|
@@ -640,14 +802,16 @@ function fuzzyFindText(content, oldText) {
|
|
|
640
802
|
};
|
|
641
803
|
}
|
|
642
804
|
function stripBom(content) {
|
|
643
|
-
return content.startsWith(
|
|
805
|
+
return content.startsWith('\uFEFF')
|
|
806
|
+
? { bom: '\uFEFF', text: content.slice(1) }
|
|
807
|
+
: { bom: '', text: content };
|
|
644
808
|
}
|
|
645
809
|
async function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
646
|
-
const diffModule = await import(
|
|
810
|
+
const diffModule = await import('diff');
|
|
647
811
|
const parts = diffModule.diffLines(oldContent, newContent);
|
|
648
812
|
const output = [];
|
|
649
|
-
const oldLines = oldContent.split(
|
|
650
|
-
const newLines = newContent.split(
|
|
813
|
+
const oldLines = oldContent.split('\n');
|
|
814
|
+
const newLines = newContent.split('\n');
|
|
651
815
|
const maxLineNum = Math.max(oldLines.length, newLines.length);
|
|
652
816
|
const lineNumWidth = String(maxLineNum).length;
|
|
653
817
|
let oldLineNum = 1;
|
|
@@ -656,8 +820,8 @@ async function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
|
656
820
|
let firstChangedLine;
|
|
657
821
|
for (let i = 0; i < parts.length; i++) {
|
|
658
822
|
const part = parts[i];
|
|
659
|
-
const raw = part.value.split(
|
|
660
|
-
if (raw[raw.length - 1] ===
|
|
823
|
+
const raw = part.value.split('\n');
|
|
824
|
+
if (raw[raw.length - 1] === '') {
|
|
661
825
|
raw.pop();
|
|
662
826
|
}
|
|
663
827
|
if (part.added || part.removed) {
|
|
@@ -666,12 +830,12 @@ async function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
|
666
830
|
}
|
|
667
831
|
for (const line of raw) {
|
|
668
832
|
if (part.added) {
|
|
669
|
-
const lineNum = String(newLineNum).padStart(lineNumWidth,
|
|
833
|
+
const lineNum = String(newLineNum).padStart(lineNumWidth, ' ');
|
|
670
834
|
output.push(`+${lineNum} ${line}`);
|
|
671
835
|
newLineNum++;
|
|
672
836
|
}
|
|
673
837
|
else {
|
|
674
|
-
const lineNum = String(oldLineNum).padStart(lineNumWidth,
|
|
838
|
+
const lineNum = String(oldLineNum).padStart(lineNumWidth, ' ');
|
|
675
839
|
output.push(`-${lineNum} ${line}`);
|
|
676
840
|
oldLineNum++;
|
|
677
841
|
}
|
|
@@ -693,18 +857,18 @@ async function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
|
693
857
|
linesToShow = linesToShow.slice(0, contextLines);
|
|
694
858
|
}
|
|
695
859
|
if (skipStart > 0) {
|
|
696
|
-
output.push(` ${
|
|
860
|
+
output.push(` ${''.padStart(lineNumWidth, ' ')} ...`);
|
|
697
861
|
oldLineNum += skipStart;
|
|
698
862
|
newLineNum += skipStart;
|
|
699
863
|
}
|
|
700
864
|
for (const line of linesToShow) {
|
|
701
|
-
const lineNum = String(oldLineNum).padStart(lineNumWidth,
|
|
865
|
+
const lineNum = String(oldLineNum).padStart(lineNumWidth, ' ');
|
|
702
866
|
output.push(` ${lineNum} ${line}`);
|
|
703
867
|
oldLineNum++;
|
|
704
868
|
newLineNum++;
|
|
705
869
|
}
|
|
706
870
|
if (skipEnd > 0) {
|
|
707
|
-
output.push(` ${
|
|
871
|
+
output.push(` ${''.padStart(lineNumWidth, ' ')} ...`);
|
|
708
872
|
}
|
|
709
873
|
}
|
|
710
874
|
else {
|
|
@@ -714,7 +878,7 @@ async function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
|
714
878
|
lastWasChange = false;
|
|
715
879
|
}
|
|
716
880
|
}
|
|
717
|
-
return { diff: output.join(
|
|
881
|
+
return { diff: output.join('\n'), firstChangedLine };
|
|
718
882
|
}
|
|
719
883
|
export class EditTool {
|
|
720
884
|
name = 'Edit';
|
|
@@ -779,7 +943,7 @@ edit(
|
|
|
779
943
|
}
|
|
780
944
|
// Read the file
|
|
781
945
|
const buffer = await fs.readFile(absolutePath);
|
|
782
|
-
const rawContent = buffer.toString(
|
|
946
|
+
const rawContent = buffer.toString('utf-8');
|
|
783
947
|
// Strip BOM before matching
|
|
784
948
|
const { bom, text: content } = stripBom(rawContent);
|
|
785
949
|
const originalEnding = detectLineEnding(content);
|
|
@@ -817,7 +981,7 @@ edit(
|
|
|
817
981
|
};
|
|
818
982
|
}
|
|
819
983
|
const finalContent = bom + restoreLineEndings(newContent, originalEnding);
|
|
820
|
-
await fs.writeFile(absolutePath, finalContent,
|
|
984
|
+
await fs.writeFile(absolutePath, finalContent, 'utf-8');
|
|
821
985
|
const diffResult = await generateDiffString(baseContent, newContent);
|
|
822
986
|
return {
|
|
823
987
|
success: true,
|
|
@@ -863,7 +1027,12 @@ export class WebSearchTool {
|
|
|
863
1027
|
- Combine with web_fetch to get full content from relevant URLs
|
|
864
1028
|
- Use quotes for exact phrase matching
|
|
865
1029
|
- Consider adding context like year or version in query`;
|
|
866
|
-
allowedModes = [
|
|
1030
|
+
allowedModes = [
|
|
1031
|
+
ExecutionMode.YOLO,
|
|
1032
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
1033
|
+
ExecutionMode.PLAN,
|
|
1034
|
+
ExecutionMode.SMART,
|
|
1035
|
+
];
|
|
867
1036
|
async execute(params) {
|
|
868
1037
|
const { query } = params;
|
|
869
1038
|
try {
|
|
@@ -877,14 +1046,14 @@ export class WebSearchTool {
|
|
|
877
1046
|
}
|
|
878
1047
|
const response = await axios.post(`${baseUrl}/search`, { query }, {
|
|
879
1048
|
headers: {
|
|
880
|
-
|
|
881
|
-
'Content-Type': 'application/json'
|
|
1049
|
+
Authorization: `Bearer ${searchApiKey}`,
|
|
1050
|
+
'Content-Type': 'application/json',
|
|
882
1051
|
},
|
|
883
|
-
timeout: 30000
|
|
1052
|
+
timeout: 30000,
|
|
884
1053
|
});
|
|
885
1054
|
return {
|
|
886
1055
|
results: response.data.results || [],
|
|
887
|
-
message: `Found ${response.data.results?.length || 0} results for "${query}"
|
|
1056
|
+
message: `Found ${response.data.results?.length || 0} results for "${query}"`,
|
|
888
1057
|
};
|
|
889
1058
|
}
|
|
890
1059
|
catch (error) {
|
|
@@ -940,22 +1109,27 @@ Each task needs:
|
|
|
940
1109
|
- Don't batch multiple completions - update as you go
|
|
941
1110
|
- Keep task descriptions clear and actionable
|
|
942
1111
|
- Use appropriate priority levels to indicate urgency`;
|
|
943
|
-
allowedModes = [
|
|
1112
|
+
allowedModes = [
|
|
1113
|
+
ExecutionMode.YOLO,
|
|
1114
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
1115
|
+
ExecutionMode.PLAN,
|
|
1116
|
+
ExecutionMode.SMART,
|
|
1117
|
+
];
|
|
944
1118
|
todoList = [];
|
|
945
1119
|
async execute(params) {
|
|
946
1120
|
const { todos } = params;
|
|
947
1121
|
try {
|
|
948
1122
|
this.todoList = todos;
|
|
949
1123
|
const summary = {
|
|
950
|
-
pending: todos.filter(t => t.status === 'pending').length,
|
|
951
|
-
in_progress: todos.filter(t => t.status === 'in_progress').length,
|
|
952
|
-
completed: todos.filter(t => t.status === 'completed').length,
|
|
953
|
-
failed: todos.filter(t => t.status === 'failed').length
|
|
1124
|
+
pending: todos.filter((t) => t.status === 'pending').length,
|
|
1125
|
+
in_progress: todos.filter((t) => t.status === 'in_progress').length,
|
|
1126
|
+
completed: todos.filter((t) => t.status === 'completed').length,
|
|
1127
|
+
failed: todos.filter((t) => t.status === 'failed').length,
|
|
954
1128
|
};
|
|
955
1129
|
return {
|
|
956
1130
|
success: true,
|
|
957
1131
|
message: `Updated todo list: ${summary.pending} pending, ${summary.in_progress} in progress, ${summary.completed} completed, ${summary.failed} failed`,
|
|
958
|
-
todos: this.todoList
|
|
1132
|
+
todos: this.todoList,
|
|
959
1133
|
};
|
|
960
1134
|
}
|
|
961
1135
|
catch (error) {
|
|
@@ -987,7 +1161,12 @@ export class TodoReadTool {
|
|
|
987
1161
|
# Best Practices
|
|
988
1162
|
- Use todo_write to modify the list, not todo_read
|
|
989
1163
|
- Check todo_read after todo_write to verify updates`;
|
|
990
|
-
allowedModes = [
|
|
1164
|
+
allowedModes = [
|
|
1165
|
+
ExecutionMode.YOLO,
|
|
1166
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
1167
|
+
ExecutionMode.PLAN,
|
|
1168
|
+
ExecutionMode.SMART,
|
|
1169
|
+
];
|
|
991
1170
|
todoWriteTool;
|
|
992
1171
|
constructor(todoWriteTool) {
|
|
993
1172
|
this.todoWriteTool = todoWriteTool;
|
|
@@ -997,14 +1176,14 @@ export class TodoReadTool {
|
|
|
997
1176
|
const todos = this.todoWriteTool.getTodos();
|
|
998
1177
|
const summary = {
|
|
999
1178
|
total: todos.length,
|
|
1000
|
-
pending: todos.filter(t => t.status === 'pending').length,
|
|
1001
|
-
in_progress: todos.filter(t => t.status === 'in_progress').length,
|
|
1002
|
-
completed: todos.filter(t => t.status === 'completed').length,
|
|
1003
|
-
failed: todos.filter(t => t.status === 'failed').length
|
|
1179
|
+
pending: todos.filter((t) => t.status === 'pending').length,
|
|
1180
|
+
in_progress: todos.filter((t) => t.status === 'in_progress').length,
|
|
1181
|
+
completed: todos.filter((t) => t.status === 'completed').length,
|
|
1182
|
+
failed: todos.filter((t) => t.status === 'failed').length,
|
|
1004
1183
|
};
|
|
1005
1184
|
return {
|
|
1006
1185
|
todos,
|
|
1007
|
-
summary
|
|
1186
|
+
summary,
|
|
1008
1187
|
};
|
|
1009
1188
|
}
|
|
1010
1189
|
catch (error) {
|
|
@@ -1051,7 +1230,12 @@ export class TaskTool {
|
|
|
1051
1230
|
- Include relevant context (file paths, requirements, constraints)
|
|
1052
1231
|
- Set appropriate executionMode if needed
|
|
1053
1232
|
- For parallel execution, ensure tasks are truly independent`;
|
|
1054
|
-
allowedModes = [
|
|
1233
|
+
allowedModes = [
|
|
1234
|
+
ExecutionMode.YOLO,
|
|
1235
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
1236
|
+
ExecutionMode.PLAN,
|
|
1237
|
+
ExecutionMode.SMART,
|
|
1238
|
+
];
|
|
1055
1239
|
async execute(params, _executionMode) {
|
|
1056
1240
|
const mode = params.executionMode || _executionMode || ExecutionMode.YOLO;
|
|
1057
1241
|
try {
|
|
@@ -1059,13 +1243,8 @@ export class TaskTool {
|
|
|
1059
1243
|
const agentManager = getAgentManager(process.cwd());
|
|
1060
1244
|
const { getConfigManager } = await import('./config.js');
|
|
1061
1245
|
const config = getConfigManager();
|
|
1062
|
-
const
|
|
1063
|
-
const aiClient =
|
|
1064
|
-
type: AuthType.OPENAI_COMPATIBLE,
|
|
1065
|
-
apiKey: config.get('apiKey'),
|
|
1066
|
-
baseUrl: config.get('baseUrl'),
|
|
1067
|
-
modelName: config.get('modelName') || 'Qwen3-Coder'
|
|
1068
|
-
});
|
|
1246
|
+
const authConfig = config.getAuthConfig();
|
|
1247
|
+
const aiClient = createAIClient(authConfig);
|
|
1069
1248
|
const toolRegistry = getToolRegistry();
|
|
1070
1249
|
if (params.agents && params.agents.length > 0) {
|
|
1071
1250
|
return await this.executeParallelAgents(params.agents, params.description, mode, agentManager, toolRegistry, aiClient);
|
|
@@ -1076,13 +1255,14 @@ export class TaskTool {
|
|
|
1076
1255
|
// Support both 'prompt' and 'query' parameter names (tool definition uses 'query')
|
|
1077
1256
|
const prompt = params.prompt || params.query;
|
|
1078
1257
|
if (!prompt) {
|
|
1079
|
-
throw new Error('Task query/prompt is required. Received params: ' +
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1258
|
+
throw new Error('Task query/prompt is required. Received params: ' +
|
|
1259
|
+
JSON.stringify({
|
|
1260
|
+
subagent_type: params.subagent_type,
|
|
1261
|
+
prompt: params.prompt,
|
|
1262
|
+
query: params.query,
|
|
1263
|
+
description: params.description,
|
|
1264
|
+
agents: params.agents?.length,
|
|
1265
|
+
}));
|
|
1086
1266
|
}
|
|
1087
1267
|
const result = await this.executeSingleAgent(params.subagent_type, prompt, params.description, params.useContext ?? true, params.constraints || [], mode, agentManager, toolRegistry, aiClient, config);
|
|
1088
1268
|
return result;
|
|
@@ -1095,11 +1275,16 @@ export class TaskTool {
|
|
|
1095
1275
|
* Create unified VLM caller
|
|
1096
1276
|
* Uses remote VLM if remoteAIClient is provided, otherwise uses local VLM
|
|
1097
1277
|
* Both modes receive full messages array for consistent behavior
|
|
1278
|
+
* @param remoteAIClient - Remote AI client for VLM calls
|
|
1279
|
+
* @param taskId - Task identifier for backend tracking
|
|
1280
|
+
* @param localConfig - Local VLM configuration
|
|
1281
|
+
* @param isFirstVlmCallRef - Reference to boolean tracking if this is the first VLM call
|
|
1282
|
+
* @param signal - Abort signal for cancellation
|
|
1098
1283
|
*/
|
|
1099
|
-
createRemoteVlmCaller(remoteAIClient, taskId, localConfig, signal) {
|
|
1284
|
+
createRemoteVlmCaller(remoteAIClient, taskId, localConfig, isFirstVlmCallRef, signal) {
|
|
1100
1285
|
// Remote mode: use RemoteAIClient
|
|
1101
1286
|
if (remoteAIClient) {
|
|
1102
|
-
return this.createRemoteVLMCaller(remoteAIClient, taskId, signal);
|
|
1287
|
+
return this.createRemoteVLMCaller(remoteAIClient, taskId, isFirstVlmCallRef, signal);
|
|
1103
1288
|
}
|
|
1104
1289
|
// Local mode: use local API
|
|
1105
1290
|
return this.createLocalVLMCaller(localConfig, signal);
|
|
@@ -1107,11 +1292,24 @@ export class TaskTool {
|
|
|
1107
1292
|
/**
|
|
1108
1293
|
* Create remote VLM caller using RemoteAIClient
|
|
1109
1294
|
* Now receives full messages array for consistent behavior with local mode
|
|
1295
|
+
* @param remoteAIClient - Remote AI client
|
|
1296
|
+
* @param taskId - Task identifier for backend tracking
|
|
1297
|
+
* @param isFirstVlmCallRef - Reference to boolean tracking if this is the first VLM call
|
|
1298
|
+
* @param signal - Abort signal for cancellation
|
|
1110
1299
|
*/
|
|
1111
|
-
createRemoteVLMCaller(remoteAIClient, taskId, signal) {
|
|
1112
|
-
return async (messages, systemPrompt) => {
|
|
1300
|
+
createRemoteVLMCaller(remoteAIClient, taskId, isFirstVlmCallRef, signal) {
|
|
1301
|
+
return async (messages, systemPrompt, _taskId, _isFirstVlmCallRef) => {
|
|
1113
1302
|
try {
|
|
1114
|
-
|
|
1303
|
+
// Use the ref to track first call status for the backend
|
|
1304
|
+
const status = isFirstVlmCallRef.current ? 'begin' : 'continue';
|
|
1305
|
+
const result = await remoteAIClient.invokeVLM(messages, systemPrompt, {
|
|
1306
|
+
signal,
|
|
1307
|
+
taskId,
|
|
1308
|
+
status,
|
|
1309
|
+
});
|
|
1310
|
+
// Update ref after call so subsequent calls use 'continue'
|
|
1311
|
+
isFirstVlmCallRef.current = false;
|
|
1312
|
+
return result;
|
|
1115
1313
|
}
|
|
1116
1314
|
catch (error) {
|
|
1117
1315
|
throw new Error(`Remote VLM call failed: ${error.message}`);
|
|
@@ -1141,7 +1339,7 @@ export class TaskTool {
|
|
|
1141
1339
|
method: 'POST',
|
|
1142
1340
|
headers: {
|
|
1143
1341
|
'Content-Type': 'application/json',
|
|
1144
|
-
|
|
1342
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1145
1343
|
},
|
|
1146
1344
|
body: JSON.stringify(requestBody),
|
|
1147
1345
|
signal: abortSignal,
|
|
@@ -1150,7 +1348,7 @@ export class TaskTool {
|
|
|
1150
1348
|
const errorText = await response.text();
|
|
1151
1349
|
throw new Error(`VLM API error: ${errorText}`);
|
|
1152
1350
|
}
|
|
1153
|
-
const result = await response.json();
|
|
1351
|
+
const result = (await response.json());
|
|
1154
1352
|
return result.choices?.[0]?.message?.content || '';
|
|
1155
1353
|
};
|
|
1156
1354
|
}
|
|
@@ -1163,10 +1361,11 @@ export class TaskTool {
|
|
|
1163
1361
|
console.log(`${indent}${colors.primaryBright(`${icons.robot} GUI Agent`)}: ${description}`);
|
|
1164
1362
|
console.log(`${indent}${colors.border(icons.separator.repeat(Math.min(60, process.stdout.columns || 80) - indent.length))}`);
|
|
1165
1363
|
console.log('');
|
|
1166
|
-
// Get VLM configuration
|
|
1167
|
-
|
|
1168
|
-
const
|
|
1169
|
-
const
|
|
1364
|
+
// Get VLM configuration for local mode
|
|
1365
|
+
// NOTE: guiSubagentBaseUrl must be explicitly configured, NOT fallback to baseUrl
|
|
1366
|
+
const baseUrl = config.get('guiSubagentBaseUrl') || '';
|
|
1367
|
+
const apiKey = config.get('guiSubagentApiKey') || '';
|
|
1368
|
+
const modelName = config.get('guiSubagentModel') || '';
|
|
1170
1369
|
// Determine mode: remote if remoteAIClient exists, otherwise local
|
|
1171
1370
|
const isRemoteMode = !!remoteAIClient;
|
|
1172
1371
|
// Log mode information
|
|
@@ -1175,11 +1374,11 @@ export class TaskTool {
|
|
|
1175
1374
|
}
|
|
1176
1375
|
else {
|
|
1177
1376
|
console.log(`${indent}${colors.info(`${icons.brain} Using local VLM configuration`)}`);
|
|
1178
|
-
// Local mode requires configuration
|
|
1179
|
-
if (!baseUrl) {
|
|
1377
|
+
// Local mode requires explicit VLM configuration
|
|
1378
|
+
if (!baseUrl || !apiKey || !modelName) {
|
|
1180
1379
|
return {
|
|
1181
1380
|
success: false,
|
|
1182
|
-
message: `GUI task "${description}" failed:
|
|
1381
|
+
message: `GUI task "${description}" failed: VLM not configured. Please run /model to configure Vision-Language Model first.`,
|
|
1183
1382
|
};
|
|
1184
1383
|
}
|
|
1185
1384
|
console.log(`${indent}${colors.textMuted(` Model: ${modelName}`)}`);
|
|
@@ -1198,23 +1397,27 @@ export class TaskTool {
|
|
|
1198
1397
|
taskId = null;
|
|
1199
1398
|
}
|
|
1200
1399
|
}
|
|
1400
|
+
// Track first VLM call for proper status management
|
|
1401
|
+
const isFirstVlmCallRef = { current: true };
|
|
1201
1402
|
// Create remoteVlmCaller using the unified method (handles both local and remote modes)
|
|
1202
|
-
const remoteVlmCaller = this.createRemoteVlmCaller(remoteAIClient, taskId, { baseUrl, apiKey, modelName });
|
|
1403
|
+
const remoteVlmCaller = this.createRemoteVlmCaller(remoteAIClient, taskId, { baseUrl, apiKey, modelName }, isFirstVlmCallRef);
|
|
1203
1404
|
// Set up stdin polling for ESC cancellation
|
|
1204
1405
|
let rawModeEnabled = false;
|
|
1205
1406
|
let stdinPollingInterval = null;
|
|
1206
1407
|
const cancellationManager = getCancellationManager();
|
|
1207
1408
|
const logger = getLogger();
|
|
1208
1409
|
const setupStdinPolling = () => {
|
|
1410
|
+
logger.debug(`[GUIAgent ESC] setupStdinPolling called, process.stdin.isTTY: ${process.stdin.isTTY}`);
|
|
1209
1411
|
if (process.stdin.isTTY) {
|
|
1210
1412
|
try {
|
|
1211
1413
|
process.stdin.setRawMode(true);
|
|
1212
1414
|
rawModeEnabled = true;
|
|
1213
1415
|
process.stdin.resume();
|
|
1214
1416
|
readline.emitKeypressEvents(process.stdin);
|
|
1417
|
+
logger.debug(`[GUIAgent ESC] Raw mode enabled successfully`);
|
|
1215
1418
|
}
|
|
1216
1419
|
catch (e) {
|
|
1217
|
-
logger.debug(`[GUIAgent] Could not set raw mode: ${e}`);
|
|
1420
|
+
logger.debug(`[GUIAgent ESC] Could not set raw mode: ${e.message}`);
|
|
1218
1421
|
}
|
|
1219
1422
|
stdinPollingInterval = setInterval(() => {
|
|
1220
1423
|
try {
|
|
@@ -1222,14 +1425,23 @@ export class TaskTool {
|
|
|
1222
1425
|
const chunk = process.stdin.read(1);
|
|
1223
1426
|
if (chunk && chunk.length > 0) {
|
|
1224
1427
|
const code = chunk[0];
|
|
1225
|
-
if (code ===
|
|
1226
|
-
|
|
1428
|
+
if (code === 0x1b) {
|
|
1429
|
+
// ESC
|
|
1430
|
+
logger.debug('[GUIAgent ESC Polling] ESC detected! Code: 0x1b');
|
|
1227
1431
|
cancellationManager.cancel();
|
|
1228
1432
|
}
|
|
1433
|
+
else {
|
|
1434
|
+
// Log other key codes for debugging
|
|
1435
|
+
logger.debug(`[GUIAgent ESC Polling] Key code: 0x${code.toString(16)}`);
|
|
1436
|
+
}
|
|
1229
1437
|
}
|
|
1230
1438
|
}
|
|
1439
|
+
else {
|
|
1440
|
+
logger.debug('[GUIAgent ESC Polling] rawModeEnabled is false');
|
|
1441
|
+
}
|
|
1231
1442
|
}
|
|
1232
1443
|
catch (e) {
|
|
1444
|
+
logger.debug(`[GUIAgent ESC Polling] Error: ${e.message}`);
|
|
1233
1445
|
// Ignore polling errors
|
|
1234
1446
|
}
|
|
1235
1447
|
}, 10);
|
|
@@ -1248,7 +1460,9 @@ export class TaskTool {
|
|
|
1248
1460
|
};
|
|
1249
1461
|
cancellationManager.on('cancelled', cancelHandler);
|
|
1250
1462
|
// Start polling for ESC
|
|
1463
|
+
logger.debug(`[GUIAgent ESC] About to call setupStdinPolling`);
|
|
1251
1464
|
setupStdinPolling();
|
|
1465
|
+
logger.debug(`[GUIAgent ESC] setupStdinPolling called`);
|
|
1252
1466
|
try {
|
|
1253
1467
|
// Import and create GUIAgent
|
|
1254
1468
|
const { createGUISubAgent } = await import('./gui-subagent/index.js');
|
|
@@ -1256,11 +1470,14 @@ export class TaskTool {
|
|
|
1256
1470
|
model: !isRemoteMode ? modelName : undefined,
|
|
1257
1471
|
modelBaseUrl: !isRemoteMode ? baseUrl : undefined,
|
|
1258
1472
|
modelApiKey: !isRemoteMode ? apiKey : undefined,
|
|
1473
|
+
taskId: taskId || undefined,
|
|
1474
|
+
isFirstVlmCallRef,
|
|
1259
1475
|
remoteVlmCaller,
|
|
1260
1476
|
isLocalMode: !isRemoteMode,
|
|
1261
|
-
maxLoopCount:
|
|
1477
|
+
maxLoopCount: 100,
|
|
1262
1478
|
loopIntervalInMs: 500,
|
|
1263
1479
|
showAIDebugInfo: config.get('showAIDebugInfo') || false,
|
|
1480
|
+
indentLevel: indentLevel,
|
|
1264
1481
|
});
|
|
1265
1482
|
// Add constraints to prompt if any
|
|
1266
1483
|
const fullPrompt = prompt;
|
|
@@ -1278,7 +1495,7 @@ export class TaskTool {
|
|
|
1278
1495
|
success: true,
|
|
1279
1496
|
cancelled: true, // Mark as cancelled so main agent won't continue
|
|
1280
1497
|
message: `GUI task "${description}" cancelled by user`,
|
|
1281
|
-
result: 'Task cancelled'
|
|
1498
|
+
result: 'Task cancelled',
|
|
1282
1499
|
};
|
|
1283
1500
|
}
|
|
1284
1501
|
cleanupStdinPolling();
|
|
@@ -1286,20 +1503,58 @@ export class TaskTool {
|
|
|
1286
1503
|
// Flush stdout to ensure all output is displayed before returning
|
|
1287
1504
|
process.stdout.write('\n');
|
|
1288
1505
|
// Return result based on GUIAgent status
|
|
1506
|
+
// Always return all info except screenshots (base64) to avoid huge payload
|
|
1507
|
+
const conversationsWithoutScreenshots = result.conversations.map((conv) => ({
|
|
1508
|
+
...conv,
|
|
1509
|
+
screenshotBase64: undefined, // Remove screenshots to avoid huge payload
|
|
1510
|
+
}));
|
|
1289
1511
|
if (result.status === 'end') {
|
|
1290
|
-
const iterations =
|
|
1512
|
+
const iterations = conversationsWithoutScreenshots.filter((c) => c.from === 'human' && c.screenshotContext).length;
|
|
1291
1513
|
console.log(`${indent}${colors.success(`${icons.check} GUI task completed in ${iterations} iterations`)}`);
|
|
1292
1514
|
return {
|
|
1293
1515
|
success: true,
|
|
1294
1516
|
message: `GUI task "${description}" completed`,
|
|
1295
|
-
result:
|
|
1517
|
+
result: {
|
|
1518
|
+
status: result.status,
|
|
1519
|
+
iterations,
|
|
1520
|
+
actions: conversationsWithoutScreenshots
|
|
1521
|
+
.filter((c) => c.from === 'assistant' && c.actionType)
|
|
1522
|
+
.map((c) => c.actionType),
|
|
1523
|
+
conversations: conversationsWithoutScreenshots,
|
|
1524
|
+
error: result.error,
|
|
1525
|
+
},
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
else if (result.status === 'call_llm') {
|
|
1529
|
+
// Empty action or needs LLM decision - return to main agent with full context
|
|
1530
|
+
console.log(`${indent}${colors.warning(`${icons.warning} GUI agent returned to main agent for LLM decision`)}`);
|
|
1531
|
+
return {
|
|
1532
|
+
success: true,
|
|
1533
|
+
message: `GUI task "${description}" returned for LLM decision`,
|
|
1534
|
+
result: {
|
|
1535
|
+
status: result.status,
|
|
1536
|
+
iterations: conversationsWithoutScreenshots.filter((c) => c.from === 'human' && c.screenshotContext).length,
|
|
1537
|
+
actions: conversationsWithoutScreenshots
|
|
1538
|
+
.filter((c) => c.from === 'assistant' && c.actionType)
|
|
1539
|
+
.map((c) => c.actionType),
|
|
1540
|
+
conversations: conversationsWithoutScreenshots,
|
|
1541
|
+
error: result.error,
|
|
1542
|
+
},
|
|
1296
1543
|
};
|
|
1297
1544
|
}
|
|
1298
1545
|
else if (result.status === 'user_stopped') {
|
|
1299
1546
|
return {
|
|
1300
1547
|
success: true,
|
|
1301
1548
|
message: `GUI task "${description}" stopped by user`,
|
|
1302
|
-
result:
|
|
1549
|
+
result: {
|
|
1550
|
+
status: result.status,
|
|
1551
|
+
iterations: conversationsWithoutScreenshots.filter((c) => c.from === 'human' && c.screenshotContext).length,
|
|
1552
|
+
actions: conversationsWithoutScreenshots
|
|
1553
|
+
.filter((c) => c.from === 'assistant' && c.actionType)
|
|
1554
|
+
.map((c) => c.actionType),
|
|
1555
|
+
conversations: conversationsWithoutScreenshots,
|
|
1556
|
+
stopped: true,
|
|
1557
|
+
},
|
|
1303
1558
|
};
|
|
1304
1559
|
}
|
|
1305
1560
|
else {
|
|
@@ -1307,7 +1562,16 @@ export class TaskTool {
|
|
|
1307
1562
|
const errorMsg = result.error || 'Unknown error';
|
|
1308
1563
|
return {
|
|
1309
1564
|
success: false,
|
|
1310
|
-
message: `GUI task "${description}" failed: ${errorMsg}
|
|
1565
|
+
message: `GUI task "${description}" failed: ${errorMsg}`,
|
|
1566
|
+
result: {
|
|
1567
|
+
status: result.status,
|
|
1568
|
+
iterations: conversationsWithoutScreenshots.filter((c) => c.from === 'human' && c.screenshotContext).length,
|
|
1569
|
+
actions: conversationsWithoutScreenshots
|
|
1570
|
+
.filter((c) => c.from === 'assistant' && c.actionType)
|
|
1571
|
+
.map((c) => c.actionType),
|
|
1572
|
+
conversations: conversationsWithoutScreenshots,
|
|
1573
|
+
error: result.error,
|
|
1574
|
+
},
|
|
1311
1575
|
};
|
|
1312
1576
|
}
|
|
1313
1577
|
}
|
|
@@ -1323,20 +1587,20 @@ export class TaskTool {
|
|
|
1323
1587
|
success: true,
|
|
1324
1588
|
cancelled: true, // Mark as cancelled so main agent won't continue
|
|
1325
1589
|
message: `GUI task "${description}" cancelled by user`,
|
|
1326
|
-
result: 'Task cancelled'
|
|
1590
|
+
result: 'Task cancelled',
|
|
1327
1591
|
};
|
|
1328
1592
|
}
|
|
1329
1593
|
if (error.message === 'Operation cancelled by user') {
|
|
1330
1594
|
return {
|
|
1331
1595
|
success: true,
|
|
1332
1596
|
message: `GUI task "${description}" cancelled by user`,
|
|
1333
|
-
result: 'Task cancelled'
|
|
1597
|
+
result: 'Task cancelled',
|
|
1334
1598
|
};
|
|
1335
1599
|
}
|
|
1336
1600
|
// Return failure without throwing - let the main agent handle it
|
|
1337
1601
|
return {
|
|
1338
1602
|
success: false,
|
|
1339
|
-
message: `GUI task "${description}" failed: ${error.message}
|
|
1603
|
+
message: `GUI task "${description}" failed: ${error.message}`,
|
|
1340
1604
|
};
|
|
1341
1605
|
}
|
|
1342
1606
|
}
|
|
@@ -1385,15 +1649,37 @@ export class TaskTool {
|
|
|
1385
1649
|
modelName = agent.model;
|
|
1386
1650
|
}
|
|
1387
1651
|
}
|
|
1388
|
-
// Create
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1652
|
+
// Create AI client for this subagent
|
|
1653
|
+
let subAgentClient;
|
|
1654
|
+
let isRemoteMode = false;
|
|
1655
|
+
let mainTaskId = null;
|
|
1656
|
+
const authConfig = config.getAuthConfig();
|
|
1657
|
+
if (authConfig.type === AuthType.OAUTH_XAGENT) {
|
|
1658
|
+
// Remote mode: try to reuse session's RemoteAIClient first
|
|
1659
|
+
const session = getSingletonSession();
|
|
1660
|
+
const existingClient = session?.getRemoteAIClient();
|
|
1661
|
+
if (existingClient) {
|
|
1662
|
+
subAgentClient = existingClient;
|
|
1663
|
+
isRemoteMode = true;
|
|
1664
|
+
// Get the main taskId from session - subagent shares the same taskId as the parent task
|
|
1665
|
+
mainTaskId = session?.getTaskId() || null;
|
|
1666
|
+
}
|
|
1667
|
+
else {
|
|
1668
|
+
subAgentClient = createAIClient(authConfig);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
else {
|
|
1672
|
+
// Local mode: create client with subagent-specific model config
|
|
1673
|
+
const subAuthConfig = {
|
|
1674
|
+
...authConfig,
|
|
1675
|
+
type: AuthType.OPENAI_COMPATIBLE,
|
|
1676
|
+
apiKey: apiKey,
|
|
1677
|
+
baseUrl: baseUrl,
|
|
1678
|
+
modelName: modelName,
|
|
1679
|
+
showAIDebugInfo: config.get('showAIDebugInfo') || false,
|
|
1680
|
+
};
|
|
1681
|
+
subAgentClient = createAIClient(subAuthConfig);
|
|
1682
|
+
}
|
|
1397
1683
|
const indent = ' '.repeat(indentLevel);
|
|
1398
1684
|
const indentNext = ' '.repeat(indentLevel + 1);
|
|
1399
1685
|
const agentName = agent.name || subagent_type;
|
|
@@ -1401,12 +1687,15 @@ export class TaskTool {
|
|
|
1401
1687
|
const executionHistory = [];
|
|
1402
1688
|
// Helper function to indent multi-line content
|
|
1403
1689
|
const indentMultiline = (content, baseIndent) => {
|
|
1404
|
-
return content
|
|
1690
|
+
return content
|
|
1691
|
+
.split('\n')
|
|
1692
|
+
.map((line) => `${baseIndent} ${line}`)
|
|
1693
|
+
.join('\n');
|
|
1405
1694
|
};
|
|
1406
1695
|
const systemPromptGenerator = new SystemPromptGenerator(toolRegistry, mode, agent);
|
|
1407
1696
|
const enhancedSystemPrompt = await systemPromptGenerator.generateEnhancedSystemPrompt(agent.systemPrompt);
|
|
1408
1697
|
const fullPrompt = constraints.length > 0
|
|
1409
|
-
? `${prompt}\n\nConstraints:\n${constraints.map(c => `- ${c}`).join('\n')}`
|
|
1698
|
+
? `${prompt}\n\nConstraints:\n${constraints.map((c) => `- ${c}`).join('\n')}`
|
|
1410
1699
|
: prompt;
|
|
1411
1700
|
// Set up raw mode and stdin polling for ESC detection
|
|
1412
1701
|
const cancellationManager = getCancellationManager();
|
|
@@ -1432,7 +1721,8 @@ export class TaskTool {
|
|
|
1432
1721
|
const chunk = process.stdin.read(1);
|
|
1433
1722
|
if (chunk && chunk.length > 0) {
|
|
1434
1723
|
const code = chunk[0];
|
|
1435
|
-
if (code ===
|
|
1724
|
+
if (code === 0x1b) {
|
|
1725
|
+
// ESC
|
|
1436
1726
|
logger.debug('[TaskTool] ESC detected via polling!');
|
|
1437
1727
|
cancellationManager.cancel();
|
|
1438
1728
|
}
|
|
@@ -1468,7 +1758,7 @@ export class TaskTool {
|
|
|
1468
1758
|
};
|
|
1469
1759
|
let messages = [
|
|
1470
1760
|
{ role: 'system', content: enhancedSystemPrompt },
|
|
1471
|
-
{ role: 'user', content: fullPrompt }
|
|
1761
|
+
{ role: 'user', content: fullPrompt },
|
|
1472
1762
|
];
|
|
1473
1763
|
const availableTools = agentManager.getAvailableToolsForAgent(agent, mode);
|
|
1474
1764
|
const allToolDefinitions = toolRegistry.getToolDefinitions();
|
|
@@ -1482,8 +1772,8 @@ export class TaskTool {
|
|
|
1482
1772
|
function: {
|
|
1483
1773
|
name: toolName,
|
|
1484
1774
|
description: `Tool: ${toolName}`,
|
|
1485
|
-
parameters: { type: 'object', properties: {}, required: [] }
|
|
1486
|
-
}
|
|
1775
|
+
parameters: { type: 'object', properties: {}, required: [] },
|
|
1776
|
+
},
|
|
1487
1777
|
};
|
|
1488
1778
|
});
|
|
1489
1779
|
let iteration = 0;
|
|
@@ -1492,11 +1782,22 @@ export class TaskTool {
|
|
|
1492
1782
|
iteration++;
|
|
1493
1783
|
// Check for cancellation before each iteration
|
|
1494
1784
|
checkCancellation();
|
|
1495
|
-
//
|
|
1496
|
-
const
|
|
1785
|
+
// Prepare chat options with taskId and model names for remote mode
|
|
1786
|
+
const chatOptions = {
|
|
1497
1787
|
tools: toolDefinitions,
|
|
1498
|
-
temperature: 0.7
|
|
1499
|
-
}
|
|
1788
|
+
temperature: 0.7,
|
|
1789
|
+
};
|
|
1790
|
+
// Pass taskId, status, and model names for remote mode subagent calls
|
|
1791
|
+
// Subagent shares the same taskId as the main task
|
|
1792
|
+
if (isRemoteMode && mainTaskId) {
|
|
1793
|
+
chatOptions.taskId = mainTaskId;
|
|
1794
|
+
chatOptions.status = iteration === 1 ? 'begin' : 'continue';
|
|
1795
|
+
// Pass model names to ensure subagent uses the same models as main task
|
|
1796
|
+
chatOptions.llmModelName = config.get('remote_llmModelName');
|
|
1797
|
+
chatOptions.vlmModelName = config.get('remote_vlmModelName');
|
|
1798
|
+
}
|
|
1799
|
+
// Use withCancellation to make API call cancellable
|
|
1800
|
+
const result = (await cancellationManager.withCancellation(subAgentClient.chatCompletion(messages, chatOptions), `api-${subagent_type}-${iteration}`));
|
|
1500
1801
|
// Check for cancellation after API call
|
|
1501
1802
|
checkCancellation();
|
|
1502
1803
|
if (!result || !result.choices || result.choices.length === 0) {
|
|
@@ -1514,8 +1815,8 @@ export class TaskTool {
|
|
|
1514
1815
|
}
|
|
1515
1816
|
else if (Array.isArray(messageContent)) {
|
|
1516
1817
|
const textParts = messageContent
|
|
1517
|
-
.filter(item => typeof item?.text === 'string' && item.text.trim() !== '')
|
|
1518
|
-
.map(item => item.text);
|
|
1818
|
+
.filter((item) => typeof item?.text === 'string' && item.text.trim() !== '')
|
|
1819
|
+
.map((item) => item.text);
|
|
1519
1820
|
contentStr = textParts.join('');
|
|
1520
1821
|
hasValidContent = textParts.length > 0;
|
|
1521
1822
|
}
|
|
@@ -1531,12 +1832,21 @@ export class TaskTool {
|
|
|
1531
1832
|
if (choice.finish_reason === 'length') {
|
|
1532
1833
|
throw new Error(`Sub-agent ${subagent_type} response truncated due to length limits`);
|
|
1533
1834
|
}
|
|
1534
|
-
// Add assistant message to conversation
|
|
1535
|
-
|
|
1835
|
+
// Add assistant message to conversation (必须包含 tool_calls,否则 tool_result 无法匹配)
|
|
1836
|
+
const assistantMessage = { role: 'assistant', content: contentStr };
|
|
1837
|
+
if (toolCalls && toolCalls.length > 0) {
|
|
1838
|
+
assistantMessage.tool_calls = toolCalls;
|
|
1839
|
+
}
|
|
1840
|
+
if (reasoningContent) {
|
|
1841
|
+
assistantMessage.reasoning_content = reasoningContent;
|
|
1842
|
+
}
|
|
1843
|
+
messages.push(assistantMessage);
|
|
1536
1844
|
// Display reasoning content if present
|
|
1537
1845
|
if (reasoningContent) {
|
|
1538
1846
|
console.log(`\n${indent}${colors.textDim(`${icons.brain} Thinking Process:`)}`);
|
|
1539
|
-
const truncatedReasoning = reasoningContent.length > 500
|
|
1847
|
+
const truncatedReasoning = reasoningContent.length > 500
|
|
1848
|
+
? reasoningContent.substring(0, 500) + '...'
|
|
1849
|
+
: reasoningContent;
|
|
1540
1850
|
const indentedReasoning = indentMultiline(truncatedReasoning, indent);
|
|
1541
1851
|
console.log(`${indentedReasoning}\n`);
|
|
1542
1852
|
}
|
|
@@ -1587,10 +1897,10 @@ export class TaskTool {
|
|
|
1587
1897
|
}
|
|
1588
1898
|
else {
|
|
1589
1899
|
const statusConfig = {
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1900
|
+
pending: { icon: icons.circle, color: colors.textMuted, label: 'Pending' },
|
|
1901
|
+
in_progress: { icon: icons.loading, color: colors.warning, label: 'In Progress' },
|
|
1902
|
+
completed: { icon: icons.success, color: colors.success, label: 'Completed' },
|
|
1903
|
+
failed: { icon: icons.error, color: colors.error, label: 'Failed' },
|
|
1594
1904
|
};
|
|
1595
1905
|
for (const todo of todos) {
|
|
1596
1906
|
const status = statusConfig[todo.status] || statusConfig['pending'];
|
|
@@ -1606,7 +1916,10 @@ export class TaskTool {
|
|
|
1606
1916
|
// Display edit result with diff
|
|
1607
1917
|
console.log('');
|
|
1608
1918
|
const diffOutput = renderDiff(toolResult.diff);
|
|
1609
|
-
const indentedDiff = diffOutput
|
|
1919
|
+
const indentedDiff = diffOutput
|
|
1920
|
+
.split('\n')
|
|
1921
|
+
.map((line) => `${indent} ${line}`)
|
|
1922
|
+
.join('\n');
|
|
1610
1923
|
console.log(`${indentedDiff}\n`);
|
|
1611
1924
|
}
|
|
1612
1925
|
else if (hasFilePreview) {
|
|
@@ -1647,12 +1960,12 @@ export class TaskTool {
|
|
|
1647
1960
|
status: 'success',
|
|
1648
1961
|
params: parsedParams,
|
|
1649
1962
|
result: truncatedPreview,
|
|
1650
|
-
timestamp: new Date().toISOString()
|
|
1963
|
+
timestamp: new Date().toISOString(),
|
|
1651
1964
|
});
|
|
1652
1965
|
messages.push({
|
|
1653
1966
|
role: 'tool',
|
|
1654
1967
|
content: JSON.stringify(toolResult),
|
|
1655
|
-
tool_call_id: toolCall.id
|
|
1968
|
+
tool_call_id: toolCall.id,
|
|
1656
1969
|
});
|
|
1657
1970
|
}
|
|
1658
1971
|
catch (error) {
|
|
@@ -1669,12 +1982,12 @@ export class TaskTool {
|
|
|
1669
1982
|
executionHistory: {
|
|
1670
1983
|
totalIterations: iteration,
|
|
1671
1984
|
toolsExecuted: executionHistory.length,
|
|
1672
|
-
successfulTools: executionHistory.filter(t => t.status === 'success').length,
|
|
1673
|
-
failedTools: executionHistory.filter(t => t.status === 'error').length,
|
|
1985
|
+
successfulTools: executionHistory.filter((t) => t.status === 'success').length,
|
|
1986
|
+
failedTools: executionHistory.filter((t) => t.status === 'error').length,
|
|
1674
1987
|
history: executionHistory,
|
|
1675
|
-
cancelled: true
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1988
|
+
cancelled: true,
|
|
1989
|
+
},
|
|
1990
|
+
},
|
|
1678
1991
|
};
|
|
1679
1992
|
}
|
|
1680
1993
|
console.log(`${indent}${colors.error(`${icons.cross} Error:`)} ${error.message}\n`);
|
|
@@ -1684,12 +1997,12 @@ export class TaskTool {
|
|
|
1684
1997
|
status: 'error',
|
|
1685
1998
|
params: parsedParams,
|
|
1686
1999
|
error: error.message,
|
|
1687
|
-
timestamp: new Date().toISOString()
|
|
2000
|
+
timestamp: new Date().toISOString(),
|
|
1688
2001
|
});
|
|
1689
2002
|
messages.push({
|
|
1690
2003
|
role: 'tool',
|
|
1691
2004
|
content: JSON.stringify({ error: error.message }),
|
|
1692
|
-
tool_call_id: toolCall.id
|
|
2005
|
+
tool_call_id: toolCall.id,
|
|
1693
2006
|
});
|
|
1694
2007
|
}
|
|
1695
2008
|
}
|
|
@@ -1708,16 +2021,16 @@ export class TaskTool {
|
|
|
1708
2021
|
executionHistory: {
|
|
1709
2022
|
totalIterations: iteration,
|
|
1710
2023
|
toolsExecuted: executionHistory.length,
|
|
1711
|
-
successfulTools: executionHistory.filter(t => t.status === 'success').length,
|
|
1712
|
-
failedTools: executionHistory.filter(t => t.status === 'error').length,
|
|
1713
|
-
history: executionHistory
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
2024
|
+
successfulTools: executionHistory.filter((t) => t.status === 'success').length,
|
|
2025
|
+
failedTools: executionHistory.filter((t) => t.status === 'error').length,
|
|
2026
|
+
history: executionHistory,
|
|
2027
|
+
},
|
|
2028
|
+
},
|
|
1716
2029
|
};
|
|
1717
2030
|
}
|
|
1718
2031
|
// Max iterations reached - return accumulated results instead of throwing error
|
|
1719
2032
|
// Get the last assistant message content
|
|
1720
|
-
const lastAssistantMsg = messages.filter(m => m.role === 'assistant').pop();
|
|
2033
|
+
const lastAssistantMsg = messages.filter((m) => m.role === 'assistant').pop();
|
|
1721
2034
|
const lastContentStr = typeof lastAssistantMsg?.content === 'string'
|
|
1722
2035
|
? lastAssistantMsg.content
|
|
1723
2036
|
: JSON.stringify(lastAssistantMsg?.content || '');
|
|
@@ -1732,12 +2045,12 @@ export class TaskTool {
|
|
|
1732
2045
|
executionHistory: {
|
|
1733
2046
|
totalIterations: iteration,
|
|
1734
2047
|
toolsExecuted: executionHistory.length,
|
|
1735
|
-
successfulTools: executionHistory.filter(t => t.status === 'success').length,
|
|
1736
|
-
failedTools: executionHistory.filter(t => t.status === 'error').length,
|
|
2048
|
+
successfulTools: executionHistory.filter((t) => t.status === 'success').length,
|
|
2049
|
+
failedTools: executionHistory.filter((t) => t.status === 'error').length,
|
|
1737
2050
|
history: executionHistory,
|
|
1738
|
-
maxIterationsReached: true
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
2051
|
+
maxIterationsReached: true,
|
|
2052
|
+
},
|
|
2053
|
+
},
|
|
1741
2054
|
};
|
|
1742
2055
|
}
|
|
1743
2056
|
async executeParallelAgents(agents, description, mode, agentManager, toolRegistry, aiClient, indentLevel = 1) {
|
|
@@ -1765,7 +2078,8 @@ export class TaskTool {
|
|
|
1765
2078
|
const chunk = process.stdin.read(1);
|
|
1766
2079
|
if (chunk && chunk.length > 0) {
|
|
1767
2080
|
const code = chunk[0];
|
|
1768
|
-
if (code ===
|
|
2081
|
+
if (code === 0x1b) {
|
|
2082
|
+
// ESC
|
|
1769
2083
|
logger.debug('[ParallelAgents] ESC detected via polling!');
|
|
1770
2084
|
cancellationManager.cancel();
|
|
1771
2085
|
}
|
|
@@ -1801,7 +2115,7 @@ export class TaskTool {
|
|
|
1801
2115
|
success: false,
|
|
1802
2116
|
agent: agentTask.subagent_type,
|
|
1803
2117
|
description: agentTask.description,
|
|
1804
|
-
error: 'Operation cancelled by user'
|
|
2118
|
+
error: 'Operation cancelled by user',
|
|
1805
2119
|
};
|
|
1806
2120
|
}
|
|
1807
2121
|
try {
|
|
@@ -1810,7 +2124,7 @@ export class TaskTool {
|
|
|
1810
2124
|
success: true,
|
|
1811
2125
|
agent: agentTask.subagent_type,
|
|
1812
2126
|
description: agentTask.description,
|
|
1813
|
-
result: result.result
|
|
2127
|
+
result: result.result,
|
|
1814
2128
|
};
|
|
1815
2129
|
}
|
|
1816
2130
|
catch (error) {
|
|
@@ -1818,14 +2132,14 @@ export class TaskTool {
|
|
|
1818
2132
|
success: false,
|
|
1819
2133
|
agent: agentTask.subagent_type,
|
|
1820
2134
|
description: agentTask.description,
|
|
1821
|
-
error: error.message
|
|
2135
|
+
error: error.message,
|
|
1822
2136
|
};
|
|
1823
2137
|
}
|
|
1824
2138
|
});
|
|
1825
2139
|
const results = await Promise.all(agentPromises);
|
|
1826
2140
|
const duration = Date.now() - startTime;
|
|
1827
|
-
const successfulAgents = results.filter(r => r.success);
|
|
1828
|
-
const failedAgents = results.filter(r => !r.success);
|
|
2141
|
+
const successfulAgents = results.filter((r) => r.success);
|
|
2142
|
+
const failedAgents = results.filter((r) => !r.success);
|
|
1829
2143
|
console.log(`${indent}${colors.success('✔')} Parallel task completed in ${colors.textMuted(duration + 'ms')}`);
|
|
1830
2144
|
console.log(`${indent}${colors.info('ℹ')} Success: ${successfulAgents.length}/${agents.length} agents\n`);
|
|
1831
2145
|
if (failedAgents.length > 0) {
|
|
@@ -1841,16 +2155,16 @@ export class TaskTool {
|
|
|
1841
2155
|
return {
|
|
1842
2156
|
success: failedAgents.length === 0,
|
|
1843
2157
|
message: `Parallel task "${description}" completed: ${successfulAgents.length}/${agents.length} successful`,
|
|
1844
|
-
results: successfulAgents.map(r => ({
|
|
2158
|
+
results: successfulAgents.map((r) => ({
|
|
1845
2159
|
agent: r.agent,
|
|
1846
2160
|
description: r.description,
|
|
1847
|
-
result: r.result
|
|
2161
|
+
result: r.result,
|
|
1848
2162
|
})),
|
|
1849
|
-
errors: failedAgents.map(r => ({
|
|
2163
|
+
errors: failedAgents.map((r) => ({
|
|
1850
2164
|
agent: r.agent,
|
|
1851
2165
|
description: r.description,
|
|
1852
|
-
error: r.error
|
|
1853
|
-
}))
|
|
2166
|
+
error: r.error,
|
|
2167
|
+
})),
|
|
1854
2168
|
};
|
|
1855
2169
|
}
|
|
1856
2170
|
}
|
|
@@ -1882,7 +2196,12 @@ export class ReadBashOutputTool {
|
|
|
1882
2196
|
- Use appropriate poll_interval based on expected task duration
|
|
1883
2197
|
- Check status to see if task is still running or completed
|
|
1884
2198
|
- Combine with todo_write to track background task progress`;
|
|
1885
|
-
allowedModes = [
|
|
2199
|
+
allowedModes = [
|
|
2200
|
+
ExecutionMode.YOLO,
|
|
2201
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
2202
|
+
ExecutionMode.PLAN,
|
|
2203
|
+
ExecutionMode.SMART,
|
|
2204
|
+
];
|
|
1886
2205
|
async execute(params) {
|
|
1887
2206
|
const { task_id, poll_interval = 10 } = params;
|
|
1888
2207
|
try {
|
|
@@ -1892,7 +2211,7 @@ export class ReadBashOutputTool {
|
|
|
1892
2211
|
throw new Error(`Task ${task_id} not found`);
|
|
1893
2212
|
}
|
|
1894
2213
|
const interval = Math.min(Math.max(poll_interval, 1), 120);
|
|
1895
|
-
await new Promise(resolve => setTimeout(resolve, interval * 1000));
|
|
2214
|
+
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
|
|
1896
2215
|
const duration = Date.now() - task.startTime;
|
|
1897
2216
|
const output = task.output.join('');
|
|
1898
2217
|
const status = task.process.exitCode === null ? 'running' : 'completed';
|
|
@@ -1900,7 +2219,7 @@ export class ReadBashOutputTool {
|
|
|
1900
2219
|
taskId: task_id,
|
|
1901
2220
|
output,
|
|
1902
2221
|
status,
|
|
1903
|
-
duration: Math.floor(duration / 1000)
|
|
2222
|
+
duration: Math.floor(duration / 1000),
|
|
1904
2223
|
};
|
|
1905
2224
|
}
|
|
1906
2225
|
catch (error) {
|
|
@@ -1936,7 +2255,12 @@ export class WebFetchTool {
|
|
|
1936
2255
|
- Use specific prompts to extract relevant information
|
|
1937
2256
|
- Check if the page is accessible if you get errors
|
|
1938
2257
|
- Large pages may be truncated due to size limits`;
|
|
1939
|
-
allowedModes = [
|
|
2258
|
+
allowedModes = [
|
|
2259
|
+
ExecutionMode.YOLO,
|
|
2260
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
2261
|
+
ExecutionMode.PLAN,
|
|
2262
|
+
ExecutionMode.SMART,
|
|
2263
|
+
];
|
|
1940
2264
|
async execute(params) {
|
|
1941
2265
|
const { prompt } = params;
|
|
1942
2266
|
try {
|
|
@@ -1948,7 +2272,7 @@ export class WebFetchTool {
|
|
|
1948
2272
|
const response = await axios.get(url, {
|
|
1949
2273
|
timeout: 30000,
|
|
1950
2274
|
maxContentLength: 10 * 1024 * 1024,
|
|
1951
|
-
validateStatus: () => true
|
|
2275
|
+
validateStatus: () => true,
|
|
1952
2276
|
});
|
|
1953
2277
|
let content = response.data;
|
|
1954
2278
|
if (typeof content === 'object') {
|
|
@@ -1957,7 +2281,7 @@ export class WebFetchTool {
|
|
|
1957
2281
|
return {
|
|
1958
2282
|
content,
|
|
1959
2283
|
url,
|
|
1960
|
-
status: response.status
|
|
2284
|
+
status: response.status,
|
|
1961
2285
|
};
|
|
1962
2286
|
}
|
|
1963
2287
|
catch (error) {
|
|
@@ -1998,7 +2322,12 @@ export class AskUserQuestionTool {
|
|
|
1998
2322
|
- Provide options when possible for faster response
|
|
1999
2323
|
- Use multiSelect=true when multiple answers are valid
|
|
2000
2324
|
- Be clear and concise in question wording`;
|
|
2001
|
-
allowedModes = [
|
|
2325
|
+
allowedModes = [
|
|
2326
|
+
ExecutionMode.YOLO,
|
|
2327
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
2328
|
+
ExecutionMode.PLAN,
|
|
2329
|
+
ExecutionMode.SMART,
|
|
2330
|
+
];
|
|
2002
2331
|
async execute(params) {
|
|
2003
2332
|
const { questions } = params;
|
|
2004
2333
|
try {
|
|
@@ -2008,26 +2337,18 @@ export class AskUserQuestionTool {
|
|
|
2008
2337
|
const answers = [];
|
|
2009
2338
|
for (const q of questions) {
|
|
2010
2339
|
if (q.options && q.options.length > 0) {
|
|
2011
|
-
const
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
default: q.multiSelect ? [] : q.options[0]
|
|
2018
|
-
}
|
|
2019
|
-
]);
|
|
2020
|
-
answers.push(Array.isArray(result.answer) ? result.answer.join(', ') : result.answer);
|
|
2340
|
+
const options = q.options.map((opt) => ({ value: opt, label: opt }));
|
|
2341
|
+
const result = await select({
|
|
2342
|
+
message: q.question,
|
|
2343
|
+
options,
|
|
2344
|
+
});
|
|
2345
|
+
answers.push(result);
|
|
2021
2346
|
}
|
|
2022
2347
|
else {
|
|
2023
|
-
const result = await
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
message: q.question
|
|
2028
|
-
}
|
|
2029
|
-
]);
|
|
2030
|
-
answers.push(result.answer);
|
|
2348
|
+
const result = (await text({
|
|
2349
|
+
message: q.question,
|
|
2350
|
+
}));
|
|
2351
|
+
answers.push(result);
|
|
2031
2352
|
}
|
|
2032
2353
|
}
|
|
2033
2354
|
return { answers };
|
|
@@ -2066,7 +2387,12 @@ export class SaveMemoryTool {
|
|
|
2066
2387
|
- Keep facts concise and specific
|
|
2067
2388
|
- Remember project-specific conventions for consistency
|
|
2068
2389
|
- This persists across sessions (global memory)`;
|
|
2069
|
-
allowedModes = [
|
|
2390
|
+
allowedModes = [
|
|
2391
|
+
ExecutionMode.YOLO,
|
|
2392
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
2393
|
+
ExecutionMode.PLAN,
|
|
2394
|
+
ExecutionMode.SMART,
|
|
2395
|
+
];
|
|
2070
2396
|
async execute(params) {
|
|
2071
2397
|
const { fact } = params;
|
|
2072
2398
|
try {
|
|
@@ -2075,7 +2401,7 @@ export class SaveMemoryTool {
|
|
|
2075
2401
|
await memoryManager.saveMemory(fact, 'global');
|
|
2076
2402
|
return {
|
|
2077
2403
|
success: true,
|
|
2078
|
-
message: `Successfully saved fact to memory
|
|
2404
|
+
message: `Successfully saved fact to memory`,
|
|
2079
2405
|
};
|
|
2080
2406
|
}
|
|
2081
2407
|
catch (error) {
|
|
@@ -2111,14 +2437,19 @@ export class ExitPlanModeTool {
|
|
|
2111
2437
|
- Include all necessary steps and considerations
|
|
2112
2438
|
- The plan will be saved for reference during execution
|
|
2113
2439
|
- Use this only when truly ready to start coding`;
|
|
2114
|
-
allowedModes = [
|
|
2440
|
+
allowedModes = [
|
|
2441
|
+
ExecutionMode.YOLO,
|
|
2442
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
2443
|
+
ExecutionMode.PLAN,
|
|
2444
|
+
ExecutionMode.SMART,
|
|
2445
|
+
];
|
|
2115
2446
|
async execute(params) {
|
|
2116
2447
|
const { plan } = params;
|
|
2117
2448
|
try {
|
|
2118
2449
|
return {
|
|
2119
2450
|
success: true,
|
|
2120
2451
|
message: 'Plan completed and ready for execution',
|
|
2121
|
-
plan
|
|
2452
|
+
plan,
|
|
2122
2453
|
};
|
|
2123
2454
|
}
|
|
2124
2455
|
catch (error) {
|
|
@@ -2162,7 +2493,7 @@ export class XmlEscapeTool {
|
|
|
2162
2493
|
{ char: '<', replacement: '<' },
|
|
2163
2494
|
{ char: '>', replacement: '>' },
|
|
2164
2495
|
{ char: '"', replacement: '"' },
|
|
2165
|
-
{ char: "'", replacement: ''' }
|
|
2496
|
+
{ char: "'", replacement: ''' },
|
|
2166
2497
|
];
|
|
2167
2498
|
let changes = 0;
|
|
2168
2499
|
for (const { char, replacement } of specialChars) {
|
|
@@ -2177,7 +2508,7 @@ export class XmlEscapeTool {
|
|
|
2177
2508
|
const additionalChars = [
|
|
2178
2509
|
{ char: '©', replacement: '©' },
|
|
2179
2510
|
{ char: '®', replacement: '®' },
|
|
2180
|
-
{ char: '€', replacement: '€' }
|
|
2511
|
+
{ char: '€', replacement: '€' },
|
|
2181
2512
|
];
|
|
2182
2513
|
for (const { char, replacement } of additionalChars) {
|
|
2183
2514
|
const regex = new RegExp(this.escapeRegExp(char), 'g');
|
|
@@ -2192,7 +2523,7 @@ export class XmlEscapeTool {
|
|
|
2192
2523
|
return {
|
|
2193
2524
|
success: true,
|
|
2194
2525
|
message: `Successfully escaped ${changes} character(s) in ${file_path}`,
|
|
2195
|
-
changes
|
|
2526
|
+
changes,
|
|
2196
2527
|
};
|
|
2197
2528
|
}
|
|
2198
2529
|
catch (error) {
|
|
@@ -2232,7 +2563,12 @@ export class ImageReadTool {
|
|
|
2232
2563
|
- Provide clear prompts for what to look for
|
|
2233
2564
|
- Use task_brief for context
|
|
2234
2565
|
- Supports PNG, JPG, GIF, WEBP, SVG, BMP`;
|
|
2235
|
-
allowedModes = [
|
|
2566
|
+
allowedModes = [
|
|
2567
|
+
ExecutionMode.YOLO,
|
|
2568
|
+
ExecutionMode.ACCEPT_EDITS,
|
|
2569
|
+
ExecutionMode.PLAN,
|
|
2570
|
+
ExecutionMode.SMART,
|
|
2571
|
+
];
|
|
2236
2572
|
async execute(params) {
|
|
2237
2573
|
const { image_input, prompt, task_brief, input_type = 'file_path', mime_type } = params;
|
|
2238
2574
|
try {
|
|
@@ -2245,16 +2581,11 @@ export class ImageReadTool {
|
|
|
2245
2581
|
else {
|
|
2246
2582
|
imageData = image_input;
|
|
2247
2583
|
}
|
|
2248
|
-
const { AIClient } = await import('./ai-client.js');
|
|
2249
2584
|
const configManager = await import('./config.js');
|
|
2250
2585
|
const { getConfigManager } = configManager;
|
|
2251
2586
|
const config = getConfigManager();
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2254
|
-
apiKey: config.get('apiKey'),
|
|
2255
|
-
baseUrl: config.get('baseUrl'),
|
|
2256
|
-
modelName: config.get('modelName') || 'Qwen3-Coder'
|
|
2257
|
-
});
|
|
2587
|
+
const authConfig = config.getAuthConfig();
|
|
2588
|
+
const aiClient = createAIClient(authConfig);
|
|
2258
2589
|
const textContent = task_brief ? `${task_brief}\n\n${prompt}` : prompt;
|
|
2259
2590
|
const messages = [
|
|
2260
2591
|
{
|
|
@@ -2262,19 +2593,19 @@ export class ImageReadTool {
|
|
|
2262
2593
|
content: [
|
|
2263
2594
|
{
|
|
2264
2595
|
type: 'text',
|
|
2265
|
-
text: textContent
|
|
2596
|
+
text: textContent,
|
|
2266
2597
|
},
|
|
2267
2598
|
{
|
|
2268
2599
|
type: 'image_url',
|
|
2269
2600
|
image_url: {
|
|
2270
|
-
url: `data:${mime_type || 'image/jpeg'};base64,${imageData}
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
]
|
|
2274
|
-
}
|
|
2601
|
+
url: `data:${mime_type || 'image/jpeg'};base64,${imageData}`,
|
|
2602
|
+
},
|
|
2603
|
+
},
|
|
2604
|
+
],
|
|
2605
|
+
},
|
|
2275
2606
|
];
|
|
2276
2607
|
const result = await aiClient.chatCompletion(messages, {
|
|
2277
|
-
temperature: 0.7
|
|
2608
|
+
temperature: 0.7,
|
|
2278
2609
|
});
|
|
2279
2610
|
const messageContent = result.choices[0]?.message?.content;
|
|
2280
2611
|
const analysis = typeof messageContent === 'string' ? messageContent : '';
|
|
@@ -2283,8 +2614,8 @@ export class ImageReadTool {
|
|
|
2283
2614
|
image_info: {
|
|
2284
2615
|
input_type,
|
|
2285
2616
|
prompt,
|
|
2286
|
-
task_brief
|
|
2287
|
-
}
|
|
2617
|
+
task_brief,
|
|
2618
|
+
},
|
|
2288
2619
|
};
|
|
2289
2620
|
}
|
|
2290
2621
|
catch (error) {
|
|
@@ -2365,7 +2696,7 @@ export class InvokeSkillTool {
|
|
|
2365
2696
|
const { skillId, taskDescription, inputFile, outputFile, options } = params;
|
|
2366
2697
|
try {
|
|
2367
2698
|
const { getSkillInvoker } = await import('./skill-invoker.js');
|
|
2368
|
-
const { SkillExecutionParams } = await import('./skill-invoker.js');
|
|
2699
|
+
const { SkillExecutionParams } = (await import('./skill-invoker.js'));
|
|
2369
2700
|
const skillInvoker = getSkillInvoker();
|
|
2370
2701
|
await skillInvoker.initialize();
|
|
2371
2702
|
// Verify skill exists
|
|
@@ -2380,7 +2711,7 @@ export class InvokeSkillTool {
|
|
|
2380
2711
|
taskDescription,
|
|
2381
2712
|
inputFile,
|
|
2382
2713
|
outputFile,
|
|
2383
|
-
options
|
|
2714
|
+
options,
|
|
2384
2715
|
});
|
|
2385
2716
|
if (result.success) {
|
|
2386
2717
|
return {
|
|
@@ -2390,7 +2721,7 @@ export class InvokeSkillTool {
|
|
|
2390
2721
|
task: taskDescription,
|
|
2391
2722
|
result: result.output,
|
|
2392
2723
|
files: result.files,
|
|
2393
|
-
nextSteps: result.nextSteps
|
|
2724
|
+
nextSteps: result.nextSteps,
|
|
2394
2725
|
};
|
|
2395
2726
|
}
|
|
2396
2727
|
else {
|
|
@@ -2404,7 +2735,7 @@ export class InvokeSkillTool {
|
|
|
2404
2735
|
taskDescription,
|
|
2405
2736
|
inputFile,
|
|
2406
2737
|
outputFile,
|
|
2407
|
-
options
|
|
2738
|
+
options,
|
|
2408
2739
|
});
|
|
2409
2740
|
if (result.success) {
|
|
2410
2741
|
return {
|
|
@@ -2414,7 +2745,8 @@ export class InvokeSkillTool {
|
|
|
2414
2745
|
task: taskDescription,
|
|
2415
2746
|
result: result.output,
|
|
2416
2747
|
files: result.files,
|
|
2417
|
-
nextSteps: result.nextSteps
|
|
2748
|
+
nextSteps: result.nextSteps,
|
|
2749
|
+
skillPath: result.skillPath
|
|
2418
2750
|
};
|
|
2419
2751
|
}
|
|
2420
2752
|
else {
|
|
@@ -2542,7 +2874,8 @@ export class ToolRegistry {
|
|
|
2542
2874
|
let registeredCount = 0;
|
|
2543
2875
|
for (const [fullName, tool] of mcpTools) {
|
|
2544
2876
|
const firstUnderscoreIndex = fullName.indexOf('__');
|
|
2545
|
-
if (firstUnderscoreIndex === -1 ||
|
|
2877
|
+
if (firstUnderscoreIndex === -1 ||
|
|
2878
|
+
firstUnderscoreIndex === 0 ||
|
|
2546
2879
|
firstUnderscoreIndex === fullName.length - 2)
|
|
2547
2880
|
continue;
|
|
2548
2881
|
const serverName = fullName.substring(0, firstUnderscoreIndex);
|
|
@@ -2577,7 +2910,7 @@ export class ToolRegistry {
|
|
|
2577
2910
|
const { getMCPManager } = await import('./mcp.js');
|
|
2578
2911
|
const mcpManager = getMCPManager();
|
|
2579
2912
|
return await mcpManager.callTool(fullName, params);
|
|
2580
|
-
}
|
|
2913
|
+
},
|
|
2581
2914
|
};
|
|
2582
2915
|
this.tools.set(toolName, mcpTool);
|
|
2583
2916
|
registeredCount++;
|
|
@@ -2621,11 +2954,11 @@ export class ToolRegistry {
|
|
|
2621
2954
|
this.backgroundTasks.delete(taskId);
|
|
2622
2955
|
}
|
|
2623
2956
|
getToolDefinitions() {
|
|
2624
|
-
return Array.from(this.tools.values()).map(tool => {
|
|
2957
|
+
return Array.from(this.tools.values()).map((tool) => {
|
|
2625
2958
|
let parameters = {
|
|
2626
2959
|
type: 'object',
|
|
2627
2960
|
properties: {},
|
|
2628
|
-
required: []
|
|
2961
|
+
required: [],
|
|
2629
2962
|
};
|
|
2630
2963
|
// Define specific parameters for each tool
|
|
2631
2964
|
switch (tool.name) {
|
|
@@ -2635,18 +2968,18 @@ export class ToolRegistry {
|
|
|
2635
2968
|
properties: {
|
|
2636
2969
|
filePath: {
|
|
2637
2970
|
type: 'string',
|
|
2638
|
-
description: 'The absolute path to the file to read'
|
|
2971
|
+
description: 'The absolute path to the file to read',
|
|
2639
2972
|
},
|
|
2640
2973
|
offset: {
|
|
2641
2974
|
type: 'number',
|
|
2642
|
-
description: 'Optional: Line number to start reading from (0-based)'
|
|
2975
|
+
description: 'Optional: Line number to start reading from (0-based)',
|
|
2643
2976
|
},
|
|
2644
2977
|
limit: {
|
|
2645
2978
|
type: 'number',
|
|
2646
|
-
description: 'Optional: Maximum number of lines to read'
|
|
2647
|
-
}
|
|
2979
|
+
description: 'Optional: Maximum number of lines to read',
|
|
2980
|
+
},
|
|
2648
2981
|
},
|
|
2649
|
-
required: ['filePath']
|
|
2982
|
+
required: ['filePath'],
|
|
2650
2983
|
};
|
|
2651
2984
|
break;
|
|
2652
2985
|
case 'Write':
|
|
@@ -2655,14 +2988,14 @@ export class ToolRegistry {
|
|
|
2655
2988
|
properties: {
|
|
2656
2989
|
filePath: {
|
|
2657
2990
|
type: 'string',
|
|
2658
|
-
description: 'The absolute path to the file to write'
|
|
2991
|
+
description: 'The absolute path to the file to write',
|
|
2659
2992
|
},
|
|
2660
2993
|
content: {
|
|
2661
2994
|
type: 'string',
|
|
2662
|
-
description: 'The content to write to the file'
|
|
2663
|
-
}
|
|
2995
|
+
description: 'The content to write to the file',
|
|
2996
|
+
},
|
|
2664
2997
|
},
|
|
2665
|
-
required: ['filePath', 'content']
|
|
2998
|
+
required: ['filePath', 'content'],
|
|
2666
2999
|
};
|
|
2667
3000
|
break;
|
|
2668
3001
|
case 'Grep':
|
|
@@ -2671,26 +3004,34 @@ export class ToolRegistry {
|
|
|
2671
3004
|
properties: {
|
|
2672
3005
|
pattern: {
|
|
2673
3006
|
type: 'string',
|
|
2674
|
-
description: 'The regex pattern to search for'
|
|
3007
|
+
description: 'The regex pattern or literal string to search for',
|
|
2675
3008
|
},
|
|
2676
3009
|
path: {
|
|
2677
3010
|
type: 'string',
|
|
2678
|
-
description: 'Optional: The path to search in (default: current directory)'
|
|
3011
|
+
description: 'Optional: The path to search in (default: current directory)',
|
|
2679
3012
|
},
|
|
2680
|
-
|
|
3013
|
+
glob: {
|
|
2681
3014
|
type: 'string',
|
|
2682
|
-
description: 'Optional: Glob pattern to filter files'
|
|
3015
|
+
description: 'Optional: Glob pattern to filter files (e.g., "*.ts", "**/*.js")',
|
|
2683
3016
|
},
|
|
2684
|
-
|
|
3017
|
+
ignoreCase: {
|
|
2685
3018
|
type: 'boolean',
|
|
2686
|
-
description: 'Optional: Case-
|
|
3019
|
+
description: 'Optional: Case-insensitive search (default: false)',
|
|
3020
|
+
},
|
|
3021
|
+
literal: {
|
|
3022
|
+
type: 'boolean',
|
|
3023
|
+
description: 'Optional: Treat pattern as literal string (default: false)',
|
|
2687
3024
|
},
|
|
2688
3025
|
context: {
|
|
2689
3026
|
type: 'number',
|
|
2690
|
-
description: 'Optional: Number of context lines to show'
|
|
2691
|
-
}
|
|
3027
|
+
description: 'Optional: Number of context lines to show before and after',
|
|
3028
|
+
},
|
|
3029
|
+
limit: {
|
|
3030
|
+
type: 'number',
|
|
3031
|
+
description: 'Optional: Maximum number of matches to return',
|
|
3032
|
+
},
|
|
2692
3033
|
},
|
|
2693
|
-
required: ['pattern']
|
|
3034
|
+
required: ['pattern'],
|
|
2694
3035
|
};
|
|
2695
3036
|
break;
|
|
2696
3037
|
case 'Bash':
|
|
@@ -2699,26 +3040,26 @@ export class ToolRegistry {
|
|
|
2699
3040
|
properties: {
|
|
2700
3041
|
command: {
|
|
2701
3042
|
type: 'string',
|
|
2702
|
-
description: 'The shell command to execute'
|
|
3043
|
+
description: 'The shell command to execute',
|
|
2703
3044
|
},
|
|
2704
3045
|
cwd: {
|
|
2705
3046
|
type: 'string',
|
|
2706
|
-
description: 'Optional: Working directory'
|
|
3047
|
+
description: 'Optional: Working directory',
|
|
2707
3048
|
},
|
|
2708
3049
|
description: {
|
|
2709
3050
|
type: 'string',
|
|
2710
|
-
description: 'Optional: Brief description of the command'
|
|
3051
|
+
description: 'Optional: Brief description of the command',
|
|
2711
3052
|
},
|
|
2712
3053
|
timeout: {
|
|
2713
3054
|
type: 'number',
|
|
2714
|
-
description: 'Optional: Timeout in seconds (default: 120)'
|
|
3055
|
+
description: 'Optional: Timeout in seconds (default: 120)',
|
|
2715
3056
|
},
|
|
2716
3057
|
run_in_bg: {
|
|
2717
3058
|
type: 'boolean',
|
|
2718
|
-
description: 'Optional: Run in background (default: false)'
|
|
2719
|
-
}
|
|
3059
|
+
description: 'Optional: Run in background (default: false)',
|
|
3060
|
+
},
|
|
2720
3061
|
},
|
|
2721
|
-
required: ['command']
|
|
3062
|
+
required: ['command'],
|
|
2722
3063
|
};
|
|
2723
3064
|
break;
|
|
2724
3065
|
case 'ListDirectory':
|
|
@@ -2727,14 +3068,14 @@ export class ToolRegistry {
|
|
|
2727
3068
|
properties: {
|
|
2728
3069
|
path: {
|
|
2729
3070
|
type: 'string',
|
|
2730
|
-
description: 'Optional: The directory path to list (default: current directory)'
|
|
3071
|
+
description: 'Optional: The directory path to list (default: current directory)',
|
|
2731
3072
|
},
|
|
2732
3073
|
recursive: {
|
|
2733
3074
|
type: 'boolean',
|
|
2734
|
-
description: 'Optional: List recursively (default: false)'
|
|
2735
|
-
}
|
|
3075
|
+
description: 'Optional: List recursively (default: false)',
|
|
3076
|
+
},
|
|
2736
3077
|
},
|
|
2737
|
-
required: []
|
|
3078
|
+
required: [],
|
|
2738
3079
|
};
|
|
2739
3080
|
break;
|
|
2740
3081
|
case 'SearchFiles':
|
|
@@ -2743,18 +3084,18 @@ export class ToolRegistry {
|
|
|
2743
3084
|
properties: {
|
|
2744
3085
|
pattern: {
|
|
2745
3086
|
type: 'string',
|
|
2746
|
-
description: 'The glob pattern to match files'
|
|
3087
|
+
description: 'The glob pattern to match files',
|
|
2747
3088
|
},
|
|
2748
3089
|
path: {
|
|
2749
3090
|
type: 'string',
|
|
2750
|
-
description: 'Optional: The path to search in (default: current directory)'
|
|
3091
|
+
description: 'Optional: The path to search in (default: current directory)',
|
|
2751
3092
|
},
|
|
2752
3093
|
limit: {
|
|
2753
3094
|
type: 'integer',
|
|
2754
|
-
description: 'Optional: Maximum number of results to return (default: 1000)'
|
|
2755
|
-
}
|
|
3095
|
+
description: 'Optional: Maximum number of results to return (default: 1000)',
|
|
3096
|
+
},
|
|
2756
3097
|
},
|
|
2757
|
-
required: ['pattern']
|
|
3098
|
+
required: ['pattern'],
|
|
2758
3099
|
};
|
|
2759
3100
|
break;
|
|
2760
3101
|
case 'DeleteFile':
|
|
@@ -2763,10 +3104,10 @@ export class ToolRegistry {
|
|
|
2763
3104
|
properties: {
|
|
2764
3105
|
filePath: {
|
|
2765
3106
|
type: 'string',
|
|
2766
|
-
description: 'The path to the file to delete'
|
|
2767
|
-
}
|
|
3107
|
+
description: 'The path to the file to delete',
|
|
3108
|
+
},
|
|
2768
3109
|
},
|
|
2769
|
-
required: ['filePath']
|
|
3110
|
+
required: ['filePath'],
|
|
2770
3111
|
};
|
|
2771
3112
|
break;
|
|
2772
3113
|
case 'CreateDirectory':
|
|
@@ -2775,14 +3116,14 @@ export class ToolRegistry {
|
|
|
2775
3116
|
properties: {
|
|
2776
3117
|
dirPath: {
|
|
2777
3118
|
type: 'string',
|
|
2778
|
-
description: 'The directory path to create'
|
|
3119
|
+
description: 'The directory path to create',
|
|
2779
3120
|
},
|
|
2780
3121
|
recursive: {
|
|
2781
3122
|
type: 'boolean',
|
|
2782
|
-
description: 'Optional: Create parent directories (default: true)'
|
|
2783
|
-
}
|
|
3123
|
+
description: 'Optional: Create parent directories (default: true)',
|
|
3124
|
+
},
|
|
2784
3125
|
},
|
|
2785
|
-
required: ['dirPath']
|
|
3126
|
+
required: ['dirPath'],
|
|
2786
3127
|
};
|
|
2787
3128
|
break;
|
|
2788
3129
|
case 'Edit':
|
|
@@ -2791,22 +3132,22 @@ export class ToolRegistry {
|
|
|
2791
3132
|
properties: {
|
|
2792
3133
|
file_path: {
|
|
2793
3134
|
type: 'string',
|
|
2794
|
-
description: 'The absolute path to the file to edit'
|
|
3135
|
+
description: 'The absolute path to the file to edit',
|
|
2795
3136
|
},
|
|
2796
3137
|
instruction: {
|
|
2797
3138
|
type: 'string',
|
|
2798
|
-
description: 'Description of what needs to be changed'
|
|
3139
|
+
description: 'Description of what needs to be changed',
|
|
2799
3140
|
},
|
|
2800
3141
|
old_string: {
|
|
2801
3142
|
type: 'string',
|
|
2802
|
-
description: 'The exact text to replace (supports fuzzy matching)'
|
|
3143
|
+
description: 'The exact text to replace (supports fuzzy matching)',
|
|
2803
3144
|
},
|
|
2804
3145
|
new_string: {
|
|
2805
3146
|
type: 'string',
|
|
2806
|
-
description: 'The new text to replace with'
|
|
2807
|
-
}
|
|
3147
|
+
description: 'The new text to replace with',
|
|
3148
|
+
},
|
|
2808
3149
|
},
|
|
2809
|
-
required: ['file_path', 'instruction', 'old_string', 'new_string']
|
|
3150
|
+
required: ['file_path', 'instruction', 'old_string', 'new_string'],
|
|
2810
3151
|
};
|
|
2811
3152
|
break;
|
|
2812
3153
|
case 'web_search':
|
|
@@ -2815,10 +3156,10 @@ export class ToolRegistry {
|
|
|
2815
3156
|
properties: {
|
|
2816
3157
|
query: {
|
|
2817
3158
|
type: 'string',
|
|
2818
|
-
description: 'The search query'
|
|
2819
|
-
}
|
|
3159
|
+
description: 'The search query',
|
|
3160
|
+
},
|
|
2820
3161
|
},
|
|
2821
|
-
required: ['query']
|
|
3162
|
+
required: ['query'],
|
|
2822
3163
|
};
|
|
2823
3164
|
break;
|
|
2824
3165
|
case 'todo_write':
|
|
@@ -2833,21 +3174,24 @@ export class ToolRegistry {
|
|
|
2833
3174
|
properties: {
|
|
2834
3175
|
id: { type: 'string' },
|
|
2835
3176
|
task: { type: 'string' },
|
|
2836
|
-
status: {
|
|
2837
|
-
|
|
3177
|
+
status: {
|
|
3178
|
+
type: 'string',
|
|
3179
|
+
enum: ['pending', 'in_progress', 'completed', 'failed'],
|
|
3180
|
+
},
|
|
3181
|
+
priority: { type: 'string', enum: ['high', 'medium', 'low'] },
|
|
2838
3182
|
},
|
|
2839
|
-
required: ['id', 'task', 'status']
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
3183
|
+
required: ['id', 'task', 'status'],
|
|
3184
|
+
},
|
|
3185
|
+
},
|
|
2842
3186
|
},
|
|
2843
|
-
required: ['todos']
|
|
3187
|
+
required: ['todos'],
|
|
2844
3188
|
};
|
|
2845
3189
|
break;
|
|
2846
3190
|
case 'todo_read':
|
|
2847
3191
|
parameters = {
|
|
2848
3192
|
type: 'object',
|
|
2849
3193
|
properties: {},
|
|
2850
|
-
required: []
|
|
3194
|
+
required: [],
|
|
2851
3195
|
};
|
|
2852
3196
|
break;
|
|
2853
3197
|
case 'task':
|
|
@@ -2856,7 +3200,7 @@ export class ToolRegistry {
|
|
|
2856
3200
|
properties: {
|
|
2857
3201
|
description: {
|
|
2858
3202
|
type: 'string',
|
|
2859
|
-
description: 'Brief description of the task (3-5 words)'
|
|
3203
|
+
description: 'Brief description of the task (3-5 words)',
|
|
2860
3204
|
},
|
|
2861
3205
|
agents: {
|
|
2862
3206
|
type: 'array',
|
|
@@ -2866,50 +3210,66 @@ export class ToolRegistry {
|
|
|
2866
3210
|
properties: {
|
|
2867
3211
|
description: {
|
|
2868
3212
|
type: 'string',
|
|
2869
|
-
description: 'Brief description of the sub-agent task'
|
|
3213
|
+
description: 'Brief description of the sub-agent task',
|
|
2870
3214
|
},
|
|
2871
3215
|
prompt: {
|
|
2872
3216
|
type: 'string',
|
|
2873
|
-
description: 'The task for the sub-agent to perform'
|
|
3217
|
+
description: 'The task for the sub-agent to perform',
|
|
2874
3218
|
},
|
|
2875
3219
|
subagent_type: {
|
|
2876
3220
|
type: 'string',
|
|
2877
|
-
enum: [
|
|
2878
|
-
|
|
3221
|
+
enum: [
|
|
3222
|
+
'general-purpose',
|
|
3223
|
+
'plan-agent',
|
|
3224
|
+
'explore-agent',
|
|
3225
|
+
'frontend-tester',
|
|
3226
|
+
'code-reviewer',
|
|
3227
|
+
'frontend-developer',
|
|
3228
|
+
'backend-developer',
|
|
3229
|
+
],
|
|
3230
|
+
description: 'The type of specialized agent',
|
|
2879
3231
|
},
|
|
2880
3232
|
constraints: {
|
|
2881
3233
|
type: 'array',
|
|
2882
3234
|
items: { type: 'string' },
|
|
2883
|
-
description: 'Optional: Constraints or limitations'
|
|
2884
|
-
}
|
|
3235
|
+
description: 'Optional: Constraints or limitations',
|
|
3236
|
+
},
|
|
2885
3237
|
},
|
|
2886
|
-
required: ['description', 'prompt', 'subagent_type']
|
|
2887
|
-
}
|
|
3238
|
+
required: ['description', 'prompt', 'subagent_type'],
|
|
3239
|
+
},
|
|
2888
3240
|
},
|
|
2889
3241
|
prompt: {
|
|
2890
3242
|
type: 'string',
|
|
2891
|
-
description: 'Optional: The task for the agent to perform (use agents for parallel execution)'
|
|
3243
|
+
description: 'Optional: The task for the agent to perform (use agents for parallel execution)',
|
|
2892
3244
|
},
|
|
2893
3245
|
subagent_type: {
|
|
2894
3246
|
type: 'string',
|
|
2895
|
-
enum: [
|
|
2896
|
-
|
|
3247
|
+
enum: [
|
|
3248
|
+
'general-purpose',
|
|
3249
|
+
'plan-agent',
|
|
3250
|
+
'explore-agent',
|
|
3251
|
+
'frontend-tester',
|
|
3252
|
+
'code-reviewer',
|
|
3253
|
+
'frontend-developer',
|
|
3254
|
+
'backend-developer',
|
|
3255
|
+
],
|
|
3256
|
+
description: 'Optional: The type of specialized agent (use agents for parallel execution)',
|
|
2897
3257
|
},
|
|
2898
3258
|
useContext: {
|
|
2899
3259
|
type: 'boolean',
|
|
2900
|
-
description: 'Optional: Include main agent context'
|
|
3260
|
+
description: 'Optional: Include main agent context',
|
|
2901
3261
|
},
|
|
2902
3262
|
outputFormat: {
|
|
2903
3263
|
type: 'string',
|
|
2904
|
-
description: 'Optional: Output format template'
|
|
3264
|
+
description: 'Optional: Output format template',
|
|
2905
3265
|
},
|
|
2906
3266
|
constraints: {
|
|
2907
3267
|
type: 'array',
|
|
2908
3268
|
items: { type: 'string' },
|
|
2909
|
-
description: 'Optional: Constraints or limitations'
|
|
2910
|
-
}
|
|
3269
|
+
description: 'Optional: Constraints or limitations',
|
|
3270
|
+
},
|
|
2911
3271
|
},
|
|
2912
|
-
required: ['description']
|
|
3272
|
+
required: ['description'],
|
|
2913
3273
|
};
|
|
2914
3274
|
break;
|
|
2915
3275
|
case 'ReadBashOutput':
|
|
@@ -2918,14 +3278,14 @@ export class ToolRegistry {
|
|
|
2918
3278
|
properties: {
|
|
2919
3279
|
task_id: {
|
|
2920
3280
|
type: 'string',
|
|
2921
|
-
description: 'The ID of the task'
|
|
3281
|
+
description: 'The ID of the task',
|
|
2922
3282
|
},
|
|
2923
3283
|
poll_interval: {
|
|
2924
3284
|
type: 'number',
|
|
2925
|
-
description: 'Optional: Polling interval in seconds (default: 10)'
|
|
2926
|
-
}
|
|
3285
|
+
description: 'Optional: Polling interval in seconds (default: 10)',
|
|
3286
|
+
},
|
|
2927
3287
|
},
|
|
2928
|
-
required: ['task_id']
|
|
3288
|
+
required: ['task_id'],
|
|
2929
3289
|
};
|
|
2930
3290
|
break;
|
|
2931
3291
|
case 'web_fetch':
|
|
@@ -2934,10 +3294,10 @@ export class ToolRegistry {
|
|
|
2934
3294
|
properties: {
|
|
2935
3295
|
prompt: {
|
|
2936
3296
|
type: 'string',
|
|
2937
|
-
description: 'Prompt containing URL(s) and processing instructions'
|
|
2938
|
-
}
|
|
3297
|
+
description: 'Prompt containing URL(s) and processing instructions',
|
|
3298
|
+
},
|
|
2939
3299
|
},
|
|
2940
|
-
required: ['prompt']
|
|
3300
|
+
required: ['prompt'],
|
|
2941
3301
|
};
|
|
2942
3302
|
break;
|
|
2943
3303
|
case 'ask_user_question':
|
|
@@ -2955,15 +3315,15 @@ export class ToolRegistry {
|
|
|
2955
3315
|
options: {
|
|
2956
3316
|
type: 'array',
|
|
2957
3317
|
items: { type: 'string' },
|
|
2958
|
-
description: 'Available choices (2-4 options)'
|
|
3318
|
+
description: 'Available choices (2-4 options)',
|
|
2959
3319
|
},
|
|
2960
|
-
multiSelect: { type: 'boolean' }
|
|
3320
|
+
multiSelect: { type: 'boolean' },
|
|
2961
3321
|
},
|
|
2962
|
-
required: ['question', 'header', 'options', 'multiSelect']
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
3322
|
+
required: ['question', 'header', 'options', 'multiSelect'],
|
|
3323
|
+
},
|
|
3324
|
+
},
|
|
2965
3325
|
},
|
|
2966
|
-
required: ['questions']
|
|
3326
|
+
required: ['questions'],
|
|
2967
3327
|
};
|
|
2968
3328
|
break;
|
|
2969
3329
|
case 'save_memory':
|
|
@@ -2972,10 +3332,10 @@ export class ToolRegistry {
|
|
|
2972
3332
|
properties: {
|
|
2973
3333
|
fact: {
|
|
2974
3334
|
type: 'string',
|
|
2975
|
-
description: 'The specific fact to remember'
|
|
2976
|
-
}
|
|
3335
|
+
description: 'The specific fact to remember',
|
|
3336
|
+
},
|
|
2977
3337
|
},
|
|
2978
|
-
required: ['fact']
|
|
3338
|
+
required: ['fact'],
|
|
2979
3339
|
};
|
|
2980
3340
|
break;
|
|
2981
3341
|
case 'exit_plan_mode':
|
|
@@ -2984,10 +3344,10 @@ export class ToolRegistry {
|
|
|
2984
3344
|
properties: {
|
|
2985
3345
|
plan: {
|
|
2986
3346
|
type: 'string',
|
|
2987
|
-
description: 'The plan to present'
|
|
2988
|
-
}
|
|
3347
|
+
description: 'The plan to present',
|
|
3348
|
+
},
|
|
2989
3349
|
},
|
|
2990
|
-
required: ['plan']
|
|
3350
|
+
required: ['plan'],
|
|
2991
3351
|
};
|
|
2992
3352
|
break;
|
|
2993
3353
|
case 'xml_escape':
|
|
@@ -2996,14 +3356,14 @@ export class ToolRegistry {
|
|
|
2996
3356
|
properties: {
|
|
2997
3357
|
file_path: {
|
|
2998
3358
|
type: 'string',
|
|
2999
|
-
description: 'The absolute path to the XML/HTML file'
|
|
3359
|
+
description: 'The absolute path to the XML/HTML file',
|
|
3000
3360
|
},
|
|
3001
3361
|
escape_all: {
|
|
3002
3362
|
type: 'boolean',
|
|
3003
|
-
description: 'Optional: Escape all special characters (default: false)'
|
|
3004
|
-
}
|
|
3363
|
+
description: 'Optional: Escape all special characters (default: false)',
|
|
3364
|
+
},
|
|
3005
3365
|
},
|
|
3006
|
-
required: ['file_path']
|
|
3366
|
+
required: ['file_path'],
|
|
3007
3367
|
};
|
|
3008
3368
|
break;
|
|
3009
3369
|
case 'image_read':
|
|
@@ -3012,27 +3372,27 @@ export class ToolRegistry {
|
|
|
3012
3372
|
properties: {
|
|
3013
3373
|
image_input: {
|
|
3014
3374
|
type: 'string',
|
|
3015
|
-
description: 'Image file path or base64 data'
|
|
3375
|
+
description: 'Image file path or base64 data',
|
|
3016
3376
|
},
|
|
3017
3377
|
prompt: {
|
|
3018
3378
|
type: 'string',
|
|
3019
|
-
description: 'Comprehensive VLM instruction'
|
|
3379
|
+
description: 'Comprehensive VLM instruction',
|
|
3020
3380
|
},
|
|
3021
3381
|
task_brief: {
|
|
3022
3382
|
type: 'string',
|
|
3023
|
-
description: 'Brief task description (max 15 words)'
|
|
3383
|
+
description: 'Brief task description (max 15 words)',
|
|
3024
3384
|
},
|
|
3025
3385
|
input_type: {
|
|
3026
3386
|
type: 'string',
|
|
3027
3387
|
enum: ['file_path', 'base64'],
|
|
3028
|
-
description: 'Input type (default: file_path)'
|
|
3388
|
+
description: 'Input type (default: file_path)',
|
|
3029
3389
|
},
|
|
3030
3390
|
mime_type: {
|
|
3031
3391
|
type: 'string',
|
|
3032
|
-
description: 'Optional: MIME type for base64 input'
|
|
3033
|
-
}
|
|
3392
|
+
description: 'Optional: MIME type for base64 input',
|
|
3393
|
+
},
|
|
3034
3394
|
},
|
|
3035
|
-
required: ['image_input', 'prompt']
|
|
3395
|
+
required: ['image_input', 'prompt'],
|
|
3036
3396
|
};
|
|
3037
3397
|
break;
|
|
3038
3398
|
case 'Skill':
|
|
@@ -3041,17 +3401,17 @@ export class ToolRegistry {
|
|
|
3041
3401
|
properties: {
|
|
3042
3402
|
skill: {
|
|
3043
3403
|
type: 'string',
|
|
3044
|
-
description: 'The skill name to execute'
|
|
3045
|
-
}
|
|
3404
|
+
description: 'The skill name to execute',
|
|
3405
|
+
},
|
|
3046
3406
|
},
|
|
3047
|
-
required: ['skill']
|
|
3407
|
+
required: ['skill'],
|
|
3048
3408
|
};
|
|
3049
3409
|
break;
|
|
3050
3410
|
case 'ListSkills':
|
|
3051
3411
|
parameters = {
|
|
3052
3412
|
type: 'object',
|
|
3053
3413
|
properties: {},
|
|
3054
|
-
required: []
|
|
3414
|
+
required: [],
|
|
3055
3415
|
};
|
|
3056
3416
|
break;
|
|
3057
3417
|
case 'GetSkillDetails':
|
|
@@ -3060,10 +3420,10 @@ export class ToolRegistry {
|
|
|
3060
3420
|
properties: {
|
|
3061
3421
|
skill: {
|
|
3062
3422
|
type: 'string',
|
|
3063
|
-
description: 'The skill name/id to get details for'
|
|
3064
|
-
}
|
|
3423
|
+
description: 'The skill name/id to get details for',
|
|
3424
|
+
},
|
|
3065
3425
|
},
|
|
3066
|
-
required: ['skill']
|
|
3426
|
+
required: ['skill'],
|
|
3067
3427
|
};
|
|
3068
3428
|
break;
|
|
3069
3429
|
default:
|
|
@@ -3074,13 +3434,13 @@ export class ToolRegistry {
|
|
|
3074
3434
|
parameters = {
|
|
3075
3435
|
type: 'object',
|
|
3076
3436
|
properties: {},
|
|
3077
|
-
required: []
|
|
3437
|
+
required: [],
|
|
3078
3438
|
};
|
|
3079
3439
|
if (mcpTool.inputSchema.properties) {
|
|
3080
3440
|
for (const [paramName, paramDef] of Object.entries(mcpTool.inputSchema.properties)) {
|
|
3081
3441
|
parameters.properties[paramName] = {
|
|
3082
3442
|
type: paramDef.type || 'string',
|
|
3083
|
-
description: paramDef.description || ''
|
|
3443
|
+
description: paramDef.description || '',
|
|
3084
3444
|
};
|
|
3085
3445
|
}
|
|
3086
3446
|
}
|
|
@@ -3092,7 +3452,7 @@ export class ToolRegistry {
|
|
|
3092
3452
|
parameters = {
|
|
3093
3453
|
type: 'object',
|
|
3094
3454
|
properties: {},
|
|
3095
|
-
required: []
|
|
3455
|
+
required: [],
|
|
3096
3456
|
};
|
|
3097
3457
|
}
|
|
3098
3458
|
}
|
|
@@ -3101,8 +3461,8 @@ export class ToolRegistry {
|
|
|
3101
3461
|
function: {
|
|
3102
3462
|
name: tool.name,
|
|
3103
3463
|
description: tool.description,
|
|
3104
|
-
parameters
|
|
3105
|
-
}
|
|
3464
|
+
parameters,
|
|
3465
|
+
},
|
|
3106
3466
|
};
|
|
3107
3467
|
});
|
|
3108
3468
|
}
|
|
@@ -3128,7 +3488,7 @@ export class ToolRegistry {
|
|
|
3128
3488
|
continue;
|
|
3129
3489
|
const [serverName, actualToolName] = [
|
|
3130
3490
|
fullName.substring(0, firstUnderscoreIndex),
|
|
3131
|
-
fullName.substring(firstUnderscoreIndex + 2)
|
|
3491
|
+
fullName.substring(firstUnderscoreIndex + 2),
|
|
3132
3492
|
];
|
|
3133
3493
|
if (actualToolName === toolName) {
|
|
3134
3494
|
return await this.executeMCPTool(fullName, params, executionMode, indent);
|
|
@@ -3179,7 +3539,7 @@ export class ToolRegistry {
|
|
|
3179
3539
|
const result = await approvalEngine.evaluate({
|
|
3180
3540
|
toolName,
|
|
3181
3541
|
params,
|
|
3182
|
-
timestamp: Date.now()
|
|
3542
|
+
timestamp: Date.now(),
|
|
3183
3543
|
});
|
|
3184
3544
|
// Decide whether to execute based on approval result
|
|
3185
3545
|
if (result.decision === 'approved') {
|
|
@@ -3254,7 +3614,7 @@ export class ToolRegistry {
|
|
|
3254
3614
|
const result = await approvalEngine.evaluate({
|
|
3255
3615
|
toolName: `MCP[${serverName}]::${actualToolName}`,
|
|
3256
3616
|
params,
|
|
3257
|
-
timestamp: Date.now()
|
|
3617
|
+
timestamp: Date.now(),
|
|
3258
3618
|
});
|
|
3259
3619
|
if (result.decision === 'approved') {
|
|
3260
3620
|
console.log(`${indent}${colors.success(`✅ [Smart Mode] MCP tool '${serverName}::${actualToolName}' passed approval`)}`);
|