orquesta-cli 0.1.12
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/.eslintrc.json +26 -0
- package/.prettierrc.json +10 -0
- package/CLAUDE.md +199 -0
- package/LICENSE +21 -0
- package/README.md +280 -0
- package/SECURITY.md +290 -0
- package/TEST_LOCAL.md +245 -0
- package/dist/agents/base/base-agent.d.ts +38 -0
- package/dist/agents/base/base-agent.d.ts.map +1 -0
- package/dist/agents/base/base-agent.js +69 -0
- package/dist/agents/base/base-agent.js.map +1 -0
- package/dist/agents/docs-search/index.d.ts +33 -0
- package/dist/agents/docs-search/index.d.ts.map +1 -0
- package/dist/agents/docs-search/index.js +244 -0
- package/dist/agents/docs-search/index.js.map +1 -0
- package/dist/agents/index.d.ts +4 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +4 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/planner/index.d.ts +17 -0
- package/dist/agents/planner/index.d.ts.map +1 -0
- package/dist/agents/planner/index.js +250 -0
- package/dist/agents/planner/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +144 -0
- package/dist/cli.js.map +1 -0
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/compact/compact-manager.d.ts +22 -0
- package/dist/core/compact/compact-manager.d.ts.map +1 -0
- package/dist/core/compact/compact-manager.js +75 -0
- package/dist/core/compact/compact-manager.js.map +1 -0
- package/dist/core/compact/compact-prompts.d.ts +11 -0
- package/dist/core/compact/compact-prompts.d.ts.map +1 -0
- package/dist/core/compact/compact-prompts.js +90 -0
- package/dist/core/compact/compact-prompts.js.map +1 -0
- package/dist/core/compact/context-tracker.d.ts +28 -0
- package/dist/core/compact/context-tracker.d.ts.map +1 -0
- package/dist/core/compact/context-tracker.js +71 -0
- package/dist/core/compact/context-tracker.js.map +1 -0
- package/dist/core/compact/index.d.ts +4 -0
- package/dist/core/compact/index.d.ts.map +1 -0
- package/dist/core/compact/index.js +4 -0
- package/dist/core/compact/index.js.map +1 -0
- package/dist/core/config/config-manager.d.ts +44 -0
- package/dist/core/config/config-manager.d.ts.map +1 -0
- package/dist/core/config/config-manager.js +259 -0
- package/dist/core/config/config-manager.js.map +1 -0
- package/dist/core/config/index.d.ts +2 -0
- package/dist/core/config/index.d.ts.map +1 -0
- package/dist/core/config/index.js +2 -0
- package/dist/core/config/index.js.map +1 -0
- package/dist/core/docs-manager.d.ts +46 -0
- package/dist/core/docs-manager.d.ts.map +1 -0
- package/dist/core/docs-manager.js +475 -0
- package/dist/core/docs-manager.js.map +1 -0
- package/dist/core/git-auto-updater.d.ts +58 -0
- package/dist/core/git-auto-updater.d.ts.map +1 -0
- package/dist/core/git-auto-updater.js +374 -0
- package/dist/core/git-auto-updater.js.map +1 -0
- package/dist/core/llm/index.d.ts +2 -0
- package/dist/core/llm/index.d.ts.map +1 -0
- package/dist/core/llm/index.js +2 -0
- package/dist/core/llm/index.js.map +1 -0
- package/dist/core/llm/llm-client.d.ts +97 -0
- package/dist/core/llm/llm-client.d.ts.map +1 -0
- package/dist/core/llm/llm-client.js +1000 -0
- package/dist/core/llm/llm-client.js.map +1 -0
- package/dist/core/session/index.d.ts +2 -0
- package/dist/core/session/index.d.ts.map +1 -0
- package/dist/core/session/index.js +2 -0
- package/dist/core/session/index.js.map +1 -0
- package/dist/core/session/session-manager.d.ts +71 -0
- package/dist/core/session/session-manager.d.ts.map +1 -0
- package/dist/core/session/session-manager.js +250 -0
- package/dist/core/session/session-manager.js.map +1 -0
- package/dist/core/slash-command-handler.d.ts +31 -0
- package/dist/core/slash-command-handler.d.ts.map +1 -0
- package/dist/core/slash-command-handler.js +302 -0
- package/dist/core/slash-command-handler.js.map +1 -0
- package/dist/core/usage-tracker.d.ts +70 -0
- package/dist/core/usage-tracker.d.ts.map +1 -0
- package/dist/core/usage-tracker.js +251 -0
- package/dist/core/usage-tracker.js.map +1 -0
- package/dist/errors/base.d.ts +22 -0
- package/dist/errors/base.d.ts.map +1 -0
- package/dist/errors/base.js +43 -0
- package/dist/errors/base.js.map +1 -0
- package/dist/errors/file.d.ts +31 -0
- package/dist/errors/file.d.ts.map +1 -0
- package/dist/errors/file.js +110 -0
- package/dist/errors/file.js.map +1 -0
- package/dist/errors/index.d.ts +10 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +41 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/llm.d.ts +26 -0
- package/dist/errors/llm.d.ts.map +1 -0
- package/dist/errors/llm.js +86 -0
- package/dist/errors/llm.js.map +1 -0
- package/dist/errors/network.d.ts +19 -0
- package/dist/errors/network.d.ts.map +1 -0
- package/dist/errors/network.js +82 -0
- package/dist/errors/network.js.map +1 -0
- package/dist/errors/validation.d.ts +19 -0
- package/dist/errors/validation.d.ts.map +1 -0
- package/dist/errors/validation.js +62 -0
- package/dist/errors/validation.js.map +1 -0
- package/dist/eval/eval-runner.d.ts +24 -0
- package/dist/eval/eval-runner.d.ts.map +1 -0
- package/dist/eval/eval-runner.js +309 -0
- package/dist/eval/eval-runner.js.map +1 -0
- package/dist/eval/index.d.ts +3 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +3 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/types.d.ts +77 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +2 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestration/index.d.ts +4 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +3 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/plan-executor.d.ts +28 -0
- package/dist/orchestration/plan-executor.d.ts.map +1 -0
- package/dist/orchestration/plan-executor.js +382 -0
- package/dist/orchestration/plan-executor.js.map +1 -0
- package/dist/orchestration/types.d.ts +66 -0
- package/dist/orchestration/types.d.ts.map +1 -0
- package/dist/orchestration/types.js +2 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/orchestration/utils.d.ts +13 -0
- package/dist/orchestration/utils.d.ts.map +1 -0
- package/dist/orchestration/utils.js +78 -0
- package/dist/orchestration/utils.js.map +1 -0
- package/dist/orquesta/connection.d.ts +35 -0
- package/dist/orquesta/connection.d.ts.map +1 -0
- package/dist/orquesta/connection.js +189 -0
- package/dist/orquesta/connection.js.map +1 -0
- package/dist/prompts/agents/docs-search-decision.d.ts +6 -0
- package/dist/prompts/agents/docs-search-decision.d.ts.map +1 -0
- package/dist/prompts/agents/docs-search-decision.js +46 -0
- package/dist/prompts/agents/docs-search-decision.js.map +1 -0
- package/dist/prompts/agents/docs-search.d.ts +4 -0
- package/dist/prompts/agents/docs-search.d.ts.map +1 -0
- package/dist/prompts/agents/docs-search.js +70 -0
- package/dist/prompts/agents/docs-search.js.map +1 -0
- package/dist/prompts/agents/planning.d.ts +4 -0
- package/dist/prompts/agents/planning.d.ts.map +1 -0
- package/dist/prompts/agents/planning.js +119 -0
- package/dist/prompts/agents/planning.js.map +1 -0
- package/dist/prompts/index.d.ts +10 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +10 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/shared/codebase-rules.d.ts +4 -0
- package/dist/prompts/shared/codebase-rules.d.ts.map +1 -0
- package/dist/prompts/shared/codebase-rules.js +16 -0
- package/dist/prompts/shared/codebase-rules.js.map +1 -0
- package/dist/prompts/shared/git-rules.d.ts +2 -0
- package/dist/prompts/shared/git-rules.d.ts.map +1 -0
- package/dist/prompts/shared/git-rules.js +87 -0
- package/dist/prompts/shared/git-rules.js.map +1 -0
- package/dist/prompts/shared/language-rules.d.ts +4 -0
- package/dist/prompts/shared/language-rules.d.ts.map +1 -0
- package/dist/prompts/shared/language-rules.js +22 -0
- package/dist/prompts/shared/language-rules.js.map +1 -0
- package/dist/prompts/shared/tool-usage.d.ts +12 -0
- package/dist/prompts/shared/tool-usage.d.ts.map +1 -0
- package/dist/prompts/shared/tool-usage.js +51 -0
- package/dist/prompts/shared/tool-usage.js.map +1 -0
- package/dist/prompts/system/compact.d.ts +3 -0
- package/dist/prompts/system/compact.d.ts.map +1 -0
- package/dist/prompts/system/compact.js +73 -0
- package/dist/prompts/system/compact.js.map +1 -0
- package/dist/prompts/system/plan-execute.d.ts +3 -0
- package/dist/prompts/system/plan-execute.d.ts.map +1 -0
- package/dist/prompts/system/plan-execute.js +83 -0
- package/dist/prompts/system/plan-execute.js.map +1 -0
- package/dist/tools/browser/browser-client.d.ts +107 -0
- package/dist/tools/browser/browser-client.d.ts.map +1 -0
- package/dist/tools/browser/browser-client.js +958 -0
- package/dist/tools/browser/browser-client.js.map +1 -0
- package/dist/tools/browser/browser-tools.d.ts +17 -0
- package/dist/tools/browser/browser-tools.d.ts.map +1 -0
- package/dist/tools/browser/browser-tools.js +972 -0
- package/dist/tools/browser/browser-tools.js.map +1 -0
- package/dist/tools/browser/index.d.ts +7 -0
- package/dist/tools/browser/index.d.ts.map +1 -0
- package/dist/tools/browser/index.js +17 -0
- package/dist/tools/browser/index.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/llm/agents/docs-search-tools.d.ts +17 -0
- package/dist/tools/llm/agents/docs-search-tools.d.ts.map +1 -0
- package/dist/tools/llm/agents/docs-search-tools.js +265 -0
- package/dist/tools/llm/agents/docs-search-tools.js.map +1 -0
- package/dist/tools/llm/agents/index.d.ts +4 -0
- package/dist/tools/llm/agents/index.d.ts.map +1 -0
- package/dist/tools/llm/agents/index.js +3 -0
- package/dist/tools/llm/agents/index.js.map +1 -0
- package/dist/tools/llm/index.d.ts +3 -0
- package/dist/tools/llm/index.d.ts.map +1 -0
- package/dist/tools/llm/index.js +3 -0
- package/dist/tools/llm/index.js.map +1 -0
- package/dist/tools/llm/simple/ask-user-tool.d.ts +5 -0
- package/dist/tools/llm/simple/ask-user-tool.d.ts.map +1 -0
- package/dist/tools/llm/simple/ask-user-tool.js +7 -0
- package/dist/tools/llm/simple/ask-user-tool.js.map +1 -0
- package/dist/tools/llm/simple/background-bash-tool.d.ts +30 -0
- package/dist/tools/llm/simple/background-bash-tool.d.ts.map +1 -0
- package/dist/tools/llm/simple/background-bash-tool.js +323 -0
- package/dist/tools/llm/simple/background-bash-tool.js.map +1 -0
- package/dist/tools/llm/simple/background-powershell-tool.d.ts +30 -0
- package/dist/tools/llm/simple/background-powershell-tool.d.ts.map +1 -0
- package/dist/tools/llm/simple/background-powershell-tool.js +305 -0
- package/dist/tools/llm/simple/background-powershell-tool.js.map +1 -0
- package/dist/tools/llm/simple/bash-tool.d.ts +4 -0
- package/dist/tools/llm/simple/bash-tool.d.ts.map +1 -0
- package/dist/tools/llm/simple/bash-tool.js +178 -0
- package/dist/tools/llm/simple/bash-tool.js.map +1 -0
- package/dist/tools/llm/simple/docs-search-agent-tool.d.ts +6 -0
- package/dist/tools/llm/simple/docs-search-agent-tool.d.ts.map +1 -0
- package/dist/tools/llm/simple/docs-search-agent-tool.js +104 -0
- package/dist/tools/llm/simple/docs-search-agent-tool.js.map +1 -0
- package/dist/tools/llm/simple/file-tools.d.ts +13 -0
- package/dist/tools/llm/simple/file-tools.d.ts.map +1 -0
- package/dist/tools/llm/simple/file-tools.js +785 -0
- package/dist/tools/llm/simple/file-tools.js.map +1 -0
- package/dist/tools/llm/simple/final-response-tool.d.ts +12 -0
- package/dist/tools/llm/simple/final-response-tool.d.ts.map +1 -0
- package/dist/tools/llm/simple/final-response-tool.js +107 -0
- package/dist/tools/llm/simple/final-response-tool.js.map +1 -0
- package/dist/tools/llm/simple/index.d.ts +11 -0
- package/dist/tools/llm/simple/index.d.ts.map +1 -0
- package/dist/tools/llm/simple/index.js +20 -0
- package/dist/tools/llm/simple/index.js.map +1 -0
- package/dist/tools/llm/simple/planning-tools.d.ts +5 -0
- package/dist/tools/llm/simple/planning-tools.d.ts.map +1 -0
- package/dist/tools/llm/simple/planning-tools.js +117 -0
- package/dist/tools/llm/simple/planning-tools.js.map +1 -0
- package/dist/tools/llm/simple/powershell-tool.d.ts +4 -0
- package/dist/tools/llm/simple/powershell-tool.d.ts.map +1 -0
- package/dist/tools/llm/simple/powershell-tool.js +178 -0
- package/dist/tools/llm/simple/powershell-tool.js.map +1 -0
- package/dist/tools/llm/simple/simple-tool-executor.d.ts +38 -0
- package/dist/tools/llm/simple/simple-tool-executor.d.ts.map +1 -0
- package/dist/tools/llm/simple/simple-tool-executor.js +134 -0
- package/dist/tools/llm/simple/simple-tool-executor.js.map +1 -0
- package/dist/tools/llm/simple/todo-tools.d.ts +15 -0
- package/dist/tools/llm/simple/todo-tools.d.ts.map +1 -0
- package/dist/tools/llm/simple/todo-tools.js +145 -0
- package/dist/tools/llm/simple/todo-tools.js.map +1 -0
- package/dist/tools/llm/simple/user-interaction-tools.d.ts +22 -0
- package/dist/tools/llm/simple/user-interaction-tools.d.ts.map +1 -0
- package/dist/tools/llm/simple/user-interaction-tools.js +168 -0
- package/dist/tools/llm/simple/user-interaction-tools.js.map +1 -0
- package/dist/tools/office/common/constants.d.ts +194 -0
- package/dist/tools/office/common/constants.d.ts.map +1 -0
- package/dist/tools/office/common/constants.js +169 -0
- package/dist/tools/office/common/constants.js.map +1 -0
- package/dist/tools/office/common/index.d.ts +4 -0
- package/dist/tools/office/common/index.d.ts.map +1 -0
- package/dist/tools/office/common/index.js +3 -0
- package/dist/tools/office/common/index.js.map +1 -0
- package/dist/tools/office/common/types.d.ts +82 -0
- package/dist/tools/office/common/types.d.ts.map +1 -0
- package/dist/tools/office/common/types.js +2 -0
- package/dist/tools/office/common/types.js.map +1 -0
- package/dist/tools/office/common/utils.d.ts +14 -0
- package/dist/tools/office/common/utils.d.ts.map +1 -0
- package/dist/tools/office/common/utils.js +58 -0
- package/dist/tools/office/common/utils.js.map +1 -0
- package/dist/tools/office/excel-client.d.ts +123 -0
- package/dist/tools/office/excel-client.d.ts.map +1 -0
- package/dist/tools/office/excel-client.js +1037 -0
- package/dist/tools/office/excel-client.js.map +1 -0
- package/dist/tools/office/excel-tools/cells.d.ts +10 -0
- package/dist/tools/office/excel-tools/cells.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/cells.js +279 -0
- package/dist/tools/office/excel-tools/cells.js.map +1 -0
- package/dist/tools/office/excel-tools/charts.d.ts +6 -0
- package/dist/tools/office/excel-tools/charts.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/charts.js +124 -0
- package/dist/tools/office/excel-tools/charts.js.map +1 -0
- package/dist/tools/office/excel-tools/comments.d.ts +6 -0
- package/dist/tools/office/excel-tools/comments.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/comments.js +114 -0
- package/dist/tools/office/excel-tools/comments.js.map +1 -0
- package/dist/tools/office/excel-tools/data-ops.d.ts +10 -0
- package/dist/tools/office/excel-tools/data-ops.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/data-ops.js +266 -0
- package/dist/tools/office/excel-tools/data-ops.js.map +1 -0
- package/dist/tools/office/excel-tools/export.d.ts +5 -0
- package/dist/tools/office/excel-tools/export.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/export.js +75 -0
- package/dist/tools/office/excel-tools/export.js.map +1 -0
- package/dist/tools/office/excel-tools/formatting.d.ts +10 -0
- package/dist/tools/office/excel-tools/formatting.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/formatting.js +276 -0
- package/dist/tools/office/excel-tools/formatting.js.map +1 -0
- package/dist/tools/office/excel-tools/index.d.ts +16 -0
- package/dist/tools/office/excel-tools/index.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/index.js +42 -0
- package/dist/tools/office/excel-tools/index.js.map +1 -0
- package/dist/tools/office/excel-tools/launch.d.ts +10 -0
- package/dist/tools/office/excel-tools/launch.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/launch.js +248 -0
- package/dist/tools/office/excel-tools/launch.js.map +1 -0
- package/dist/tools/office/excel-tools/media.d.ts +5 -0
- package/dist/tools/office/excel-tools/media.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/media.js +84 -0
- package/dist/tools/office/excel-tools/media.js.map +1 -0
- package/dist/tools/office/excel-tools/named-ranges.d.ts +6 -0
- package/dist/tools/office/excel-tools/named-ranges.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/named-ranges.js +113 -0
- package/dist/tools/office/excel-tools/named-ranges.js.map +1 -0
- package/dist/tools/office/excel-tools/protection.d.ts +5 -0
- package/dist/tools/office/excel-tools/protection.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/protection.js +75 -0
- package/dist/tools/office/excel-tools/protection.js.map +1 -0
- package/dist/tools/office/excel-tools/rows-columns.d.ts +11 -0
- package/dist/tools/office/excel-tools/rows-columns.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/rows-columns.js +293 -0
- package/dist/tools/office/excel-tools/rows-columns.js.map +1 -0
- package/dist/tools/office/excel-tools/sheets.d.ts +8 -0
- package/dist/tools/office/excel-tools/sheets.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/sheets.js +177 -0
- package/dist/tools/office/excel-tools/sheets.js.map +1 -0
- package/dist/tools/office/excel-tools/validation.d.ts +7 -0
- package/dist/tools/office/excel-tools/validation.d.ts.map +1 -0
- package/dist/tools/office/excel-tools/validation.js +175 -0
- package/dist/tools/office/excel-tools/validation.js.map +1 -0
- package/dist/tools/office/excel-tools.d.ts +3 -0
- package/dist/tools/office/excel-tools.d.ts.map +1 -0
- package/dist/tools/office/excel-tools.js +3 -0
- package/dist/tools/office/excel-tools.js.map +1 -0
- package/dist/tools/office/index.d.ts +6 -0
- package/dist/tools/office/index.d.ts.map +1 -0
- package/dist/tools/office/index.js +9 -0
- package/dist/tools/office/index.js.map +1 -0
- package/dist/tools/office/office-client-base.d.ts +31 -0
- package/dist/tools/office/office-client-base.d.ts.map +1 -0
- package/dist/tools/office/office-client-base.js +154 -0
- package/dist/tools/office/office-client-base.js.map +1 -0
- package/dist/tools/office/office-client.d.ts +196 -0
- package/dist/tools/office/office-client.d.ts.map +1 -0
- package/dist/tools/office/office-client.js +200 -0
- package/dist/tools/office/office-client.js.map +1 -0
- package/dist/tools/office/powerpoint-client.d.ts +135 -0
- package/dist/tools/office/powerpoint-client.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-client.js +1136 -0
- package/dist/tools/office/powerpoint-client.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/effects.d.ts +9 -0
- package/dist/tools/office/powerpoint-tools/effects.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/effects.js +246 -0
- package/dist/tools/office/powerpoint-tools/effects.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/export.d.ts +6 -0
- package/dist/tools/office/powerpoint-tools/export.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/export.js +108 -0
- package/dist/tools/office/powerpoint-tools/export.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/index.d.ts +13 -0
- package/dist/tools/office/powerpoint-tools/index.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/index.js +33 -0
- package/dist/tools/office/powerpoint-tools/index.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/launch.d.ts +9 -0
- package/dist/tools/office/powerpoint-tools/launch.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/launch.js +214 -0
- package/dist/tools/office/powerpoint-tools/launch.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/media.d.ts +8 -0
- package/dist/tools/office/powerpoint-tools/media.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/media.js +211 -0
- package/dist/tools/office/powerpoint-tools/media.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/notes.d.ts +8 -0
- package/dist/tools/office/powerpoint-tools/notes.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/notes.js +171 -0
- package/dist/tools/office/powerpoint-tools/notes.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/sections.d.ts +6 -0
- package/dist/tools/office/powerpoint-tools/sections.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/sections.js +104 -0
- package/dist/tools/office/powerpoint-tools/sections.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/shapes.d.ts +22 -0
- package/dist/tools/office/powerpoint-tools/shapes.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/shapes.js +681 -0
- package/dist/tools/office/powerpoint-tools/shapes.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/slides.d.ts +11 -0
- package/dist/tools/office/powerpoint-tools/slides.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/slides.js +283 -0
- package/dist/tools/office/powerpoint-tools/slides.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/tables.d.ts +6 -0
- package/dist/tools/office/powerpoint-tools/tables.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/tables.js +132 -0
- package/dist/tools/office/powerpoint-tools/tables.js.map +1 -0
- package/dist/tools/office/powerpoint-tools/text.d.ts +12 -0
- package/dist/tools/office/powerpoint-tools/text.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools/text.js +366 -0
- package/dist/tools/office/powerpoint-tools/text.js.map +1 -0
- package/dist/tools/office/powerpoint-tools.d.ts +3 -0
- package/dist/tools/office/powerpoint-tools.d.ts.map +1 -0
- package/dist/tools/office/powerpoint-tools.js +3 -0
- package/dist/tools/office/powerpoint-tools.js.map +1 -0
- package/dist/tools/office/word-client.d.ts +147 -0
- package/dist/tools/office/word-client.d.ts.map +1 -0
- package/dist/tools/office/word-client.js +1341 -0
- package/dist/tools/office/word-client.js.map +1 -0
- package/dist/tools/office/word-tools/bookmarks.d.ts +7 -0
- package/dist/tools/office/word-tools/bookmarks.d.ts.map +1 -0
- package/dist/tools/office/word-tools/bookmarks.js +146 -0
- package/dist/tools/office/word-tools/bookmarks.js.map +1 -0
- package/dist/tools/office/word-tools/comments.d.ts +7 -0
- package/dist/tools/office/word-tools/comments.d.ts.map +1 -0
- package/dist/tools/office/word-tools/comments.js +146 -0
- package/dist/tools/office/word-tools/comments.js.map +1 -0
- package/dist/tools/office/word-tools/content.d.ts +7 -0
- package/dist/tools/office/word-tools/content.d.ts.map +1 -0
- package/dist/tools/office/word-tools/content.js +168 -0
- package/dist/tools/office/word-tools/content.js.map +1 -0
- package/dist/tools/office/word-tools/export.d.ts +5 -0
- package/dist/tools/office/word-tools/export.d.ts.map +1 -0
- package/dist/tools/office/word-tools/export.js +73 -0
- package/dist/tools/office/word-tools/export.js.map +1 -0
- package/dist/tools/office/word-tools/formatting.d.ts +6 -0
- package/dist/tools/office/word-tools/formatting.d.ts.map +1 -0
- package/dist/tools/office/word-tools/formatting.js +129 -0
- package/dist/tools/office/word-tools/formatting.js.map +1 -0
- package/dist/tools/office/word-tools/headers-footers.d.ts +6 -0
- package/dist/tools/office/word-tools/headers-footers.d.ts.map +1 -0
- package/dist/tools/office/word-tools/headers-footers.js +117 -0
- package/dist/tools/office/word-tools/headers-footers.js.map +1 -0
- package/dist/tools/office/word-tools/index.d.ts +16 -0
- package/dist/tools/office/word-tools/index.d.ts.map +1 -0
- package/dist/tools/office/word-tools/index.js +45 -0
- package/dist/tools/office/word-tools/index.js.map +1 -0
- package/dist/tools/office/word-tools/launch.d.ts +10 -0
- package/dist/tools/office/word-tools/launch.d.ts.map +1 -0
- package/dist/tools/office/word-tools/launch.js +255 -0
- package/dist/tools/office/word-tools/launch.js.map +1 -0
- package/dist/tools/office/word-tools/lists.d.ts +5 -0
- package/dist/tools/office/word-tools/lists.d.ts.map +1 -0
- package/dist/tools/office/word-tools/lists.js +73 -0
- package/dist/tools/office/word-tools/lists.js.map +1 -0
- package/dist/tools/office/word-tools/navigation.d.ts +5 -0
- package/dist/tools/office/word-tools/navigation.d.ts.map +1 -0
- package/dist/tools/office/word-tools/navigation.js +85 -0
- package/dist/tools/office/word-tools/navigation.js.map +1 -0
- package/dist/tools/office/word-tools/page-setup.d.ts +7 -0
- package/dist/tools/office/word-tools/page-setup.d.ts.map +1 -0
- package/dist/tools/office/word-tools/page-setup.js +152 -0
- package/dist/tools/office/word-tools/page-setup.js.map +1 -0
- package/dist/tools/office/word-tools/tables.d.ts +8 -0
- package/dist/tools/office/word-tools/tables.d.ts.map +1 -0
- package/dist/tools/office/word-tools/tables.js +197 -0
- package/dist/tools/office/word-tools/tables.js.map +1 -0
- package/dist/tools/office/word-tools/text.d.ts +9 -0
- package/dist/tools/office/word-tools/text.d.ts.map +1 -0
- package/dist/tools/office/word-tools/text.js +235 -0
- package/dist/tools/office/word-tools/text.js.map +1 -0
- package/dist/tools/office/word-tools/undo-redo.d.ts +5 -0
- package/dist/tools/office/word-tools/undo-redo.d.ts.map +1 -0
- package/dist/tools/office/word-tools/undo-redo.js +73 -0
- package/dist/tools/office/word-tools/undo-redo.js.map +1 -0
- package/dist/tools/office/word-tools/watermarks.d.ts +5 -0
- package/dist/tools/office/word-tools/watermarks.d.ts.map +1 -0
- package/dist/tools/office/word-tools/watermarks.js +81 -0
- package/dist/tools/office/word-tools/watermarks.js.map +1 -0
- package/dist/tools/office/word-tools.d.ts +3 -0
- package/dist/tools/office/word-tools.d.ts.map +1 -0
- package/dist/tools/office/word-tools.js +3 -0
- package/dist/tools/office/word-tools.js.map +1 -0
- package/dist/tools/registry.d.ts +53 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +278 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +88 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +19 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/types/index.d.ts +126 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/PlanExecuteView.d.ts +11 -0
- package/dist/ui/PlanExecuteView.d.ts.map +1 -0
- package/dist/ui/PlanExecuteView.js +29 -0
- package/dist/ui/PlanExecuteView.js.map +1 -0
- package/dist/ui/TodoPanel.d.ts +13 -0
- package/dist/ui/TodoPanel.d.ts.map +1 -0
- package/dist/ui/TodoPanel.js +135 -0
- package/dist/ui/TodoPanel.js.map +1 -0
- package/dist/ui/UpdateNotification.d.ts +13 -0
- package/dist/ui/UpdateNotification.d.ts.map +1 -0
- package/dist/ui/UpdateNotification.js +42 -0
- package/dist/ui/UpdateNotification.js.map +1 -0
- package/dist/ui/components/ActivityIndicator.d.ts +25 -0
- package/dist/ui/components/ActivityIndicator.d.ts.map +1 -0
- package/dist/ui/components/ActivityIndicator.js +115 -0
- package/dist/ui/components/ActivityIndicator.js.map +1 -0
- package/dist/ui/components/CommandBrowser.d.ts +10 -0
- package/dist/ui/components/CommandBrowser.d.ts.map +1 -0
- package/dist/ui/components/CommandBrowser.js +53 -0
- package/dist/ui/components/CommandBrowser.js.map +1 -0
- package/dist/ui/components/CustomTextInput.d.ts +13 -0
- package/dist/ui/components/CustomTextInput.d.ts.map +1 -0
- package/dist/ui/components/CustomTextInput.js +245 -0
- package/dist/ui/components/CustomTextInput.js.map +1 -0
- package/dist/ui/components/DocsSearchProgress.d.ts +13 -0
- package/dist/ui/components/DocsSearchProgress.d.ts.map +1 -0
- package/dist/ui/components/DocsSearchProgress.js +37 -0
- package/dist/ui/components/DocsSearchProgress.js.map +1 -0
- package/dist/ui/components/FileBrowser.d.ts +11 -0
- package/dist/ui/components/FileBrowser.d.ts.map +1 -0
- package/dist/ui/components/FileBrowser.js +45 -0
- package/dist/ui/components/FileBrowser.js.map +1 -0
- package/dist/ui/components/LLMSetupWizard.d.ts +8 -0
- package/dist/ui/components/LLMSetupWizard.d.ts.map +1 -0
- package/dist/ui/components/LLMSetupWizard.js +192 -0
- package/dist/ui/components/LLMSetupWizard.js.map +1 -0
- package/dist/ui/components/Logo.d.ts +19 -0
- package/dist/ui/components/Logo.d.ts.map +1 -0
- package/dist/ui/components/Logo.js +55 -0
- package/dist/ui/components/Logo.js.map +1 -0
- package/dist/ui/components/MarkdownRenderer.d.ts +9 -0
- package/dist/ui/components/MarkdownRenderer.d.ts.map +1 -0
- package/dist/ui/components/MarkdownRenderer.js +198 -0
- package/dist/ui/components/MarkdownRenderer.js.map +1 -0
- package/dist/ui/components/ModelSelector.d.ts +8 -0
- package/dist/ui/components/ModelSelector.d.ts.map +1 -0
- package/dist/ui/components/ModelSelector.js +111 -0
- package/dist/ui/components/ModelSelector.js.map +1 -0
- package/dist/ui/components/PlanExecuteApp.d.ts +23 -0
- package/dist/ui/components/PlanExecuteApp.d.ts.map +1 -0
- package/dist/ui/components/PlanExecuteApp.js +1324 -0
- package/dist/ui/components/PlanExecuteApp.js.map +1 -0
- package/dist/ui/components/ProgressBar.d.ts +10 -0
- package/dist/ui/components/ProgressBar.d.ts.map +1 -0
- package/dist/ui/components/ProgressBar.js +26 -0
- package/dist/ui/components/ProgressBar.js.map +1 -0
- package/dist/ui/components/StatusBar.d.ts +23 -0
- package/dist/ui/components/StatusBar.d.ts.map +1 -0
- package/dist/ui/components/StatusBar.js +162 -0
- package/dist/ui/components/StatusBar.js.map +1 -0
- package/dist/ui/components/ThinkingIndicator.d.ts +14 -0
- package/dist/ui/components/ThinkingIndicator.d.ts.map +1 -0
- package/dist/ui/components/ThinkingIndicator.js +63 -0
- package/dist/ui/components/ThinkingIndicator.js.map +1 -0
- package/dist/ui/components/TodoListView.d.ts +11 -0
- package/dist/ui/components/TodoListView.d.ts.map +1 -0
- package/dist/ui/components/TodoListView.js +69 -0
- package/dist/ui/components/TodoListView.js.map +1 -0
- package/dist/ui/components/ToolSelector.d.ts +7 -0
- package/dist/ui/components/ToolSelector.d.ts.map +1 -0
- package/dist/ui/components/ToolSelector.js +111 -0
- package/dist/ui/components/ToolSelector.js.map +1 -0
- package/dist/ui/components/dialogs/ApprovalDialog.d.ts +13 -0
- package/dist/ui/components/dialogs/ApprovalDialog.d.ts.map +1 -0
- package/dist/ui/components/dialogs/ApprovalDialog.js +173 -0
- package/dist/ui/components/dialogs/ApprovalDialog.js.map +1 -0
- package/dist/ui/components/dialogs/AskUserDialog.d.ts +9 -0
- package/dist/ui/components/dialogs/AskUserDialog.d.ts.map +1 -0
- package/dist/ui/components/dialogs/AskUserDialog.js +111 -0
- package/dist/ui/components/dialogs/AskUserDialog.js.map +1 -0
- package/dist/ui/components/dialogs/DocsBrowser.d.ts +8 -0
- package/dist/ui/components/dialogs/DocsBrowser.d.ts.map +1 -0
- package/dist/ui/components/dialogs/DocsBrowser.js +127 -0
- package/dist/ui/components/dialogs/DocsBrowser.js.map +1 -0
- package/dist/ui/components/dialogs/SettingsDialog.d.ts +10 -0
- package/dist/ui/components/dialogs/SettingsDialog.d.ts.map +1 -0
- package/dist/ui/components/dialogs/SettingsDialog.js +563 -0
- package/dist/ui/components/dialogs/SettingsDialog.js.map +1 -0
- package/dist/ui/components/dialogs/index.d.ts +4 -0
- package/dist/ui/components/dialogs/index.d.ts.map +1 -0
- package/dist/ui/components/dialogs/index.js +4 -0
- package/dist/ui/components/dialogs/index.js.map +1 -0
- package/dist/ui/components/index.d.ts +12 -0
- package/dist/ui/components/index.d.ts.map +1 -0
- package/dist/ui/components/index.js +9 -0
- package/dist/ui/components/index.js.map +1 -0
- package/dist/ui/components/panels/LogPanel.d.ts +7 -0
- package/dist/ui/components/panels/LogPanel.d.ts.map +1 -0
- package/dist/ui/components/panels/LogPanel.js +280 -0
- package/dist/ui/components/panels/LogPanel.js.map +1 -0
- package/dist/ui/components/panels/SessionPanel.d.ts +8 -0
- package/dist/ui/components/panels/SessionPanel.d.ts.map +1 -0
- package/dist/ui/components/panels/SessionPanel.js +81 -0
- package/dist/ui/components/panels/SessionPanel.js.map +1 -0
- package/dist/ui/components/panels/index.d.ts +4 -0
- package/dist/ui/components/panels/index.d.ts.map +1 -0
- package/dist/ui/components/panels/index.js +4 -0
- package/dist/ui/components/panels/index.js.map +1 -0
- package/dist/ui/components/views/ChatView.d.ts +12 -0
- package/dist/ui/components/views/ChatView.d.ts.map +1 -0
- package/dist/ui/components/views/ChatView.js +289 -0
- package/dist/ui/components/views/ChatView.js.map +1 -0
- package/dist/ui/components/views/index.d.ts +2 -0
- package/dist/ui/components/views/index.d.ts.map +1 -0
- package/dist/ui/components/views/index.js +2 -0
- package/dist/ui/components/views/index.js.map +1 -0
- package/dist/ui/contexts/TokenContext.d.ts +29 -0
- package/dist/ui/contexts/TokenContext.d.ts.map +1 -0
- package/dist/ui/contexts/TokenContext.js +79 -0
- package/dist/ui/contexts/TokenContext.js.map +1 -0
- package/dist/ui/hooks/atFileProcessor.d.ts +15 -0
- package/dist/ui/hooks/atFileProcessor.d.ts.map +1 -0
- package/dist/ui/hooks/atFileProcessor.js +88 -0
- package/dist/ui/hooks/atFileProcessor.js.map +1 -0
- package/dist/ui/hooks/index.d.ts +8 -0
- package/dist/ui/hooks/index.d.ts.map +1 -0
- package/dist/ui/hooks/index.js +8 -0
- package/dist/ui/hooks/index.js.map +1 -0
- package/dist/ui/hooks/slashCommandProcessor.d.ts +21 -0
- package/dist/ui/hooks/slashCommandProcessor.d.ts.map +1 -0
- package/dist/ui/hooks/slashCommandProcessor.js +100 -0
- package/dist/ui/hooks/slashCommandProcessor.js.map +1 -0
- package/dist/ui/hooks/useCommandBrowserState.d.ts +12 -0
- package/dist/ui/hooks/useCommandBrowserState.d.ts.map +1 -0
- package/dist/ui/hooks/useCommandBrowserState.js +66 -0
- package/dist/ui/hooks/useCommandBrowserState.js.map +1 -0
- package/dist/ui/hooks/useFileBrowserState.d.ts +15 -0
- package/dist/ui/hooks/useFileBrowserState.d.ts.map +1 -0
- package/dist/ui/hooks/useFileBrowserState.js +80 -0
- package/dist/ui/hooks/useFileBrowserState.js.map +1 -0
- package/dist/ui/hooks/useFileList.d.ts +20 -0
- package/dist/ui/hooks/useFileList.d.ts.map +1 -0
- package/dist/ui/hooks/useFileList.js +57 -0
- package/dist/ui/hooks/useFileList.js.map +1 -0
- package/dist/ui/hooks/useInputHistory.d.ts +9 -0
- package/dist/ui/hooks/useInputHistory.d.ts.map +1 -0
- package/dist/ui/hooks/useInputHistory.js +68 -0
- package/dist/ui/hooks/useInputHistory.js.map +1 -0
- package/dist/ui/hooks/usePlanExecution.d.ts +8 -0
- package/dist/ui/hooks/usePlanExecution.d.ts.map +1 -0
- package/dist/ui/hooks/usePlanExecution.js +214 -0
- package/dist/ui/hooks/usePlanExecution.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +7 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/ink-entry.d.ts +3 -0
- package/dist/ui/ink-entry.d.ts.map +1 -0
- package/dist/ui/ink-entry.js +22 -0
- package/dist/ui/ink-entry.js.map +1 -0
- package/dist/utils/env-filter.d.ts +4 -0
- package/dist/utils/env-filter.d.ts.map +1 -0
- package/dist/utils/env-filter.js +101 -0
- package/dist/utils/env-filter.js.map +1 -0
- package/dist/utils/file-system.d.ts +9 -0
- package/dist/utils/file-system.d.ts.map +1 -0
- package/dist/utils/file-system.js +99 -0
- package/dist/utils/file-system.js.map +1 -0
- package/dist/utils/git-utils.d.ts +2 -0
- package/dist/utils/git-utils.d.ts.map +1 -0
- package/dist/utils/git-utils.js +16 -0
- package/dist/utils/git-utils.js.map +1 -0
- package/dist/utils/json-stream-logger.d.ts +74 -0
- package/dist/utils/json-stream-logger.d.ts.map +1 -0
- package/dist/utils/json-stream-logger.js +808 -0
- package/dist/utils/json-stream-logger.js.map +1 -0
- package/dist/utils/logger.d.ts +152 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +1672 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/platform-utils.d.ts +19 -0
- package/dist/utils/platform-utils.d.ts.map +1 -0
- package/dist/utils/platform-utils.js +134 -0
- package/dist/utils/platform-utils.js.map +1 -0
- package/dist/utils/wsl-utils.d.ts +4 -0
- package/dist/utils/wsl-utils.d.ts.map +1 -0
- package/dist/utils/wsl-utils.js +72 -0
- package/dist/utils/wsl-utils.js.map +1 -0
- package/electron.vite.config.ts +63 -0
- package/google374b9eba0c52b043.html +1 -0
- package/package.json +122 -0
- package/src/agents/base/base-agent.ts +159 -0
- package/src/agents/docs-search/index.ts +365 -0
- package/src/agents/index.ts +34 -0
- package/src/agents/planner/index.ts +544 -0
- package/src/cli.ts +201 -0
- package/src/constants.ts +47 -0
- package/src/core/compact/compact-manager.ts +160 -0
- package/src/core/compact/compact-prompts.ts +150 -0
- package/src/core/compact/context-tracker.ts +164 -0
- package/src/core/compact/index.ts +25 -0
- package/src/core/config/config-manager.ts +460 -0
- package/src/core/config/index.ts +5 -0
- package/src/core/docs-manager.ts +678 -0
- package/src/core/llm/index.ts +7 -0
- package/src/core/llm/llm-client.ts +1550 -0
- package/src/core/session/index.ts +5 -0
- package/src/core/session/session-manager.ts +464 -0
- package/src/core/slash-command-handler.ts +410 -0
- package/src/core/usage-tracker.ts +438 -0
- package/src/errors/base.ts +81 -0
- package/src/errors/file.ts +183 -0
- package/src/errors/index.ts +95 -0
- package/src/errors/llm.ts +151 -0
- package/src/errors/network.ts +124 -0
- package/src/errors/validation.ts +111 -0
- package/src/eval/eval-runner.ts +456 -0
- package/src/eval/index.ts +8 -0
- package/src/eval/types.ts +139 -0
- package/src/index.ts +22 -0
- package/src/orchestration/index.ts +30 -0
- package/src/orchestration/plan-executor.ts +652 -0
- package/src/orchestration/types.ts +127 -0
- package/src/orchestration/utils.ts +119 -0
- package/src/orquesta/connection.ts +291 -0
- package/src/prompts/agents/docs-search-decision.ts +74 -0
- package/src/prompts/agents/docs-search.ts +84 -0
- package/src/prompts/agents/planning.ts +143 -0
- package/src/prompts/index.ts +31 -0
- package/src/prompts/shared/codebase-rules.ts +29 -0
- package/src/prompts/shared/git-rules.ts +94 -0
- package/src/prompts/shared/language-rules.ts +36 -0
- package/src/prompts/shared/tool-usage.ts +72 -0
- package/src/prompts/system/compact.ts +80 -0
- package/src/prompts/system/plan-execute.ts +89 -0
- package/src/tools/browser/browser-client.ts +1363 -0
- package/src/tools/browser/browser-tools.ts +1139 -0
- package/src/tools/browser/index.ts +65 -0
- package/src/tools/index.ts +23 -0
- package/src/tools/llm/agents/docs-search-tools.ts +368 -0
- package/src/tools/llm/agents/index.ts +22 -0
- package/src/tools/llm/index.ts +11 -0
- package/src/tools/llm/simple/ask-user-tool.ts +25 -0
- package/src/tools/llm/simple/background-bash-tool.ts +443 -0
- package/src/tools/llm/simple/background-powershell-tool.ts +421 -0
- package/src/tools/llm/simple/bash-tool.ts +238 -0
- package/src/tools/llm/simple/docs-search-agent-tool.ts +146 -0
- package/src/tools/llm/simple/file-tools.ts +1051 -0
- package/src/tools/llm/simple/final-response-tool.ts +180 -0
- package/src/tools/llm/simple/index.ts +42 -0
- package/src/tools/llm/simple/planning-tools.ts +143 -0
- package/src/tools/llm/simple/powershell-tool.ts +241 -0
- package/src/tools/llm/simple/simple-tool-executor.ts +279 -0
- package/src/tools/llm/simple/todo-tools.ts +207 -0
- package/src/tools/llm/simple/user-interaction-tools.ts +277 -0
- package/src/tools/office/common/constants.ts +335 -0
- package/src/tools/office/common/index.ts +133 -0
- package/src/tools/office/common/types.ts +286 -0
- package/src/tools/office/common/utils.ts +116 -0
- package/src/tools/office/excel-client.ts +1336 -0
- package/src/tools/office/excel-tools/cells.ts +359 -0
- package/src/tools/office/excel-tools/charts.ts +166 -0
- package/src/tools/office/excel-tools/comments.ts +155 -0
- package/src/tools/office/excel-tools/data-ops.ts +349 -0
- package/src/tools/office/excel-tools/export.ts +105 -0
- package/src/tools/office/excel-tools/formatting.ts +357 -0
- package/src/tools/office/excel-tools/index.ts +55 -0
- package/src/tools/office/excel-tools/launch.ts +303 -0
- package/src/tools/office/excel-tools/media.ts +117 -0
- package/src/tools/office/excel-tools/named-ranges.ts +148 -0
- package/src/tools/office/excel-tools/protection.ts +105 -0
- package/src/tools/office/excel-tools/rows-columns.ts +386 -0
- package/src/tools/office/excel-tools/sheets.ts +228 -0
- package/src/tools/office/excel-tools/validation.ts +226 -0
- package/src/tools/office/excel-tools.ts +9 -0
- package/src/tools/office/index.ts +259 -0
- package/src/tools/office/office-client-base.ts +242 -0
- package/src/tools/office/office-client.ts +377 -0
- package/src/tools/office/powerpoint-client.ts +1498 -0
- package/src/tools/office/powerpoint-tools/effects.ts +315 -0
- package/src/tools/office/powerpoint-tools/export.ts +138 -0
- package/src/tools/office/powerpoint-tools/index.ts +45 -0
- package/src/tools/office/powerpoint-tools/launch.ts +263 -0
- package/src/tools/office/powerpoint-tools/media.ts +291 -0
- package/src/tools/office/powerpoint-tools/notes.ts +220 -0
- package/src/tools/office/powerpoint-tools/sections.ts +140 -0
- package/src/tools/office/powerpoint-tools/shapes.ts +870 -0
- package/src/tools/office/powerpoint-tools/slides.ts +350 -0
- package/src/tools/office/powerpoint-tools/tables.ts +182 -0
- package/src/tools/office/powerpoint-tools/text.ts +473 -0
- package/src/tools/office/powerpoint-tools.ts +9 -0
- package/src/tools/office/word-client.ts +1697 -0
- package/src/tools/office/word-tools/bookmarks.ts +186 -0
- package/src/tools/office/word-tools/comments.ts +185 -0
- package/src/tools/office/word-tools/content.ts +229 -0
- package/src/tools/office/word-tools/export.ts +97 -0
- package/src/tools/office/word-tools/formatting.ts +161 -0
- package/src/tools/office/word-tools/headers-footers.ts +155 -0
- package/src/tools/office/word-tools/index.ts +57 -0
- package/src/tools/office/word-tools/launch.ts +312 -0
- package/src/tools/office/word-tools/lists.ts +97 -0
- package/src/tools/office/word-tools/navigation.ts +114 -0
- package/src/tools/office/word-tools/page-setup.ts +195 -0
- package/src/tools/office/word-tools/tables.ts +262 -0
- package/src/tools/office/word-tools/text.ts +294 -0
- package/src/tools/office/word-tools/undo-redo.ts +97 -0
- package/src/tools/office/word-tools/watermarks.ts +105 -0
- package/src/tools/office/word-tools.ts +9 -0
- package/src/tools/registry.ts +527 -0
- package/src/tools/types.ts +231 -0
- package/src/types/index.ts +181 -0
- package/src/ui/PlanExecuteView.tsx +119 -0
- package/src/ui/TodoPanel.tsx +240 -0
- package/src/ui/UpdateNotification.tsx +105 -0
- package/src/ui/components/ActivityIndicator.tsx +234 -0
- package/src/ui/components/CommandBrowser.tsx +114 -0
- package/src/ui/components/CustomTextInput.tsx +389 -0
- package/src/ui/components/DocsSearchProgress.tsx +85 -0
- package/src/ui/components/FileBrowser.tsx +93 -0
- package/src/ui/components/LLMSetupWizard.tsx +333 -0
- package/src/ui/components/Logo.tsx +125 -0
- package/src/ui/components/MarkdownRenderer.tsx +358 -0
- package/src/ui/components/ModelSelector.tsx +203 -0
- package/src/ui/components/PlanExecuteApp.tsx +2007 -0
- package/src/ui/components/ProgressBar.tsx +51 -0
- package/src/ui/components/StatusBar.tsx +302 -0
- package/src/ui/components/ThinkingIndicator.tsx +120 -0
- package/src/ui/components/TodoListView.tsx +140 -0
- package/src/ui/components/ToolSelector.tsx +215 -0
- package/src/ui/components/dialogs/ApprovalDialog.tsx +259 -0
- package/src/ui/components/dialogs/AskUserDialog.tsx +159 -0
- package/src/ui/components/dialogs/DocsBrowser.tsx +222 -0
- package/src/ui/components/dialogs/SettingsDialog.tsx +939 -0
- package/src/ui/components/dialogs/index.ts +13 -0
- package/src/ui/components/index.ts +27 -0
- package/src/ui/components/panels/LogPanel.tsx +385 -0
- package/src/ui/components/panels/SessionPanel.tsx +146 -0
- package/src/ui/components/panels/index.ts +13 -0
- package/src/ui/components/views/ChatView.tsx +447 -0
- package/src/ui/components/views/index.ts +5 -0
- package/src/ui/contexts/TokenContext.tsx +139 -0
- package/src/ui/hooks/atFileProcessor.ts +167 -0
- package/src/ui/hooks/index.ts +11 -0
- package/src/ui/hooks/slashCommandProcessor.ts +174 -0
- package/src/ui/hooks/useCommandBrowserState.ts +97 -0
- package/src/ui/hooks/useFileBrowserState.ts +116 -0
- package/src/ui/hooks/useFileList.ts +132 -0
- package/src/ui/hooks/useInputHistory.ts +89 -0
- package/src/ui/hooks/usePlanExecution.ts +339 -0
- package/src/ui/index.ts +10 -0
- package/src/ui/ink-entry.tsx +36 -0
- package/src/utils/env-filter.ts +164 -0
- package/src/utils/file-system.ts +133 -0
- package/src/utils/git-utils.ts +30 -0
- package/src/utils/json-stream-logger.ts +1259 -0
- package/src/utils/logger.ts +2767 -0
- package/src/utils/platform-utils.ts +256 -0
- package/src/utils/wsl-utils.ts +113 -0
- package/tsconfig.electron.json +39 -0
- package/tsconfig.json +64 -0
|
@@ -0,0 +1,1550 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Client
|
|
3
|
+
*
|
|
4
|
+
* OpenAI Compatible API client
|
|
5
|
+
* Supports Gemini (HTTPS) and LiteLLM (HTTP)
|
|
6
|
+
*
|
|
7
|
+
* Logger usage guide:
|
|
8
|
+
* - This file already uses logger.httpRequest(), logger.httpResponse(), logger.error(), etc.
|
|
9
|
+
* - Additional improvements: Add logger.enter/exit to main public functions
|
|
10
|
+
* - Example: logger.enter('sendMessage', { messageLength: userMessage.length });
|
|
11
|
+
* - For detailed usage, see docs/LOGGER_USAGE_KR.md
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import axios, { AxiosInstance, AxiosError } from 'axios';
|
|
15
|
+
import { Message, LLMRequestOptions } from '../../types/index.js';
|
|
16
|
+
import { configManager } from '../config/config-manager.js';
|
|
17
|
+
import {
|
|
18
|
+
NetworkError,
|
|
19
|
+
APIError,
|
|
20
|
+
TimeoutError,
|
|
21
|
+
ConnectionError,
|
|
22
|
+
} from '../../errors/network.js';
|
|
23
|
+
import {
|
|
24
|
+
LLMError,
|
|
25
|
+
TokenLimitError,
|
|
26
|
+
RateLimitError,
|
|
27
|
+
ContextLengthError,
|
|
28
|
+
} from '../../errors/llm.js';
|
|
29
|
+
import { logger, isLLMLogEnabled } from '../../utils/logger.js';
|
|
30
|
+
import { usageTracker } from '../usage-tracker.js';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* LLM response interface (OpenAI Compatible)
|
|
34
|
+
*/
|
|
35
|
+
export interface LLMResponse {
|
|
36
|
+
id: string;
|
|
37
|
+
object: string;
|
|
38
|
+
created: number;
|
|
39
|
+
model: string;
|
|
40
|
+
choices: Array<{
|
|
41
|
+
index: number;
|
|
42
|
+
message: Message & {
|
|
43
|
+
reasoning?: string;
|
|
44
|
+
};
|
|
45
|
+
finish_reason: string | null;
|
|
46
|
+
}>;
|
|
47
|
+
usage?: {
|
|
48
|
+
prompt_tokens: number;
|
|
49
|
+
completion_tokens: number;
|
|
50
|
+
total_tokens: number;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Streaming chunk interface
|
|
56
|
+
*/
|
|
57
|
+
export interface LLMStreamChunk {
|
|
58
|
+
id: string;
|
|
59
|
+
object: string;
|
|
60
|
+
created: number;
|
|
61
|
+
model: string;
|
|
62
|
+
choices: Array<{
|
|
63
|
+
index: number;
|
|
64
|
+
delta: {
|
|
65
|
+
role?: string;
|
|
66
|
+
content?: string;
|
|
67
|
+
reasoning?: string;
|
|
68
|
+
};
|
|
69
|
+
finish_reason: string | null;
|
|
70
|
+
}>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Retry configuration interface
|
|
75
|
+
*/
|
|
76
|
+
export interface RetryConfig {
|
|
77
|
+
/** Maximum retry attempts (default: 3) */
|
|
78
|
+
maxRetries?: number;
|
|
79
|
+
/** Current attempt number (internal use) */
|
|
80
|
+
currentAttempt?: number;
|
|
81
|
+
/** Whether retry is disabled */
|
|
82
|
+
disableRetry?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* LLM Client class
|
|
87
|
+
*/
|
|
88
|
+
export class LLMClient {
|
|
89
|
+
private axiosInstance: AxiosInstance;
|
|
90
|
+
private baseUrl: string;
|
|
91
|
+
private apiKey: string;
|
|
92
|
+
private model: string;
|
|
93
|
+
private modelName: string;
|
|
94
|
+
private currentAbortController: AbortController | null = null;
|
|
95
|
+
private isInterrupted: boolean = false;
|
|
96
|
+
|
|
97
|
+
/** Default maximum retry attempts */
|
|
98
|
+
private static readonly DEFAULT_MAX_RETRIES = 3;
|
|
99
|
+
|
|
100
|
+
constructor() {
|
|
101
|
+
// Get current settings from ConfigManager
|
|
102
|
+
const endpoint = configManager.getCurrentEndpoint();
|
|
103
|
+
const currentModel = configManager.getCurrentModel();
|
|
104
|
+
|
|
105
|
+
if (!endpoint || !currentModel) {
|
|
106
|
+
throw new Error('No endpoint or model configured. Run: open config init');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.baseUrl = endpoint.baseUrl;
|
|
110
|
+
this.apiKey = endpoint.apiKey || '';
|
|
111
|
+
this.model = currentModel.id;
|
|
112
|
+
this.modelName = currentModel.name;
|
|
113
|
+
|
|
114
|
+
// Create Axios instance
|
|
115
|
+
this.axiosInstance = axios.create({
|
|
116
|
+
baseURL: this.baseUrl,
|
|
117
|
+
headers: {
|
|
118
|
+
'Content-Type': 'application/json',
|
|
119
|
+
...(this.apiKey && { Authorization: `Bearer ${this.apiKey}` }),
|
|
120
|
+
},
|
|
121
|
+
timeout: 600000, // 600 seconds (10 minutes)
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Preprocess messages for model-specific requirements
|
|
127
|
+
*
|
|
128
|
+
* Handles:
|
|
129
|
+
* 1. reasoning_content → content conversion (for reasoning LLM responses)
|
|
130
|
+
* 2. Harmony format for gpt-oss models
|
|
131
|
+
*/
|
|
132
|
+
private preprocessMessages(messages: Message[], modelId: string): Message[] {
|
|
133
|
+
return messages.map((msg) => {
|
|
134
|
+
// Skip non-assistant messages
|
|
135
|
+
if (msg.role !== 'assistant') {
|
|
136
|
+
return msg;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const msgAny = msg as any;
|
|
140
|
+
let processedMsg = { ...msg };
|
|
141
|
+
|
|
142
|
+
// Handle reasoning_content from reasoning LLMs (DeepSeek-V3, etc.)
|
|
143
|
+
// When switching between reasoning LLM and regular LLM, content field is required
|
|
144
|
+
if (msgAny.reasoning_content && (!msg.content || msg.content.trim() === '')) {
|
|
145
|
+
processedMsg.content = msgAny.reasoning_content;
|
|
146
|
+
// Remove reasoning_content to avoid confusion
|
|
147
|
+
delete (processedMsg as any).reasoning_content;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// gpt-oss-120b / gpt-oss-20b: Harmony format handling
|
|
151
|
+
// These models require content field even when tool_calls are present
|
|
152
|
+
if (/^gpt-oss-(120b|20b)$/i.test(modelId)) {
|
|
153
|
+
if (msg.tool_calls && msg.tool_calls.length > 0) {
|
|
154
|
+
if (!processedMsg.content || processedMsg.content.trim() === '') {
|
|
155
|
+
const toolNames = msg.tool_calls.map(tc => tc.function.name).join(', ');
|
|
156
|
+
processedMsg.content = msgAny.reasoning || `Calling tools: ${toolNames}`;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Ensure content is at least empty string for assistant messages
|
|
162
|
+
if (processedMsg.content === undefined || processedMsg.content === null) {
|
|
163
|
+
processedMsg.content = '';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return processedMsg;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Chat Completion API call (Non-streaming)
|
|
172
|
+
* Retries up to 3 times by default, errors not shown in UI during retry
|
|
173
|
+
*/
|
|
174
|
+
async chatCompletion(
|
|
175
|
+
options: Partial<LLMRequestOptions>,
|
|
176
|
+
retryConfig?: RetryConfig
|
|
177
|
+
): Promise<LLMResponse> {
|
|
178
|
+
const maxRetries = retryConfig?.disableRetry ? 1 : (retryConfig?.maxRetries ?? LLMClient.DEFAULT_MAX_RETRIES);
|
|
179
|
+
const currentAttempt = retryConfig?.currentAttempt ?? 1;
|
|
180
|
+
|
|
181
|
+
logger.enter('chatCompletion', {
|
|
182
|
+
model: options.model || this.model,
|
|
183
|
+
messagesCount: options.messages?.length || 0,
|
|
184
|
+
hasTools: !!options.tools,
|
|
185
|
+
attempt: currentAttempt,
|
|
186
|
+
maxRetries
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const url = '/chat/completions';
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
logger.flow('Starting message preprocessing');
|
|
193
|
+
// Preprocess messages for model-specific requirements
|
|
194
|
+
const modelId = options.model || this.model;
|
|
195
|
+
const processedMessages = options.messages ?
|
|
196
|
+
this.preprocessMessages(options.messages, modelId) : [];
|
|
197
|
+
|
|
198
|
+
logger.vars(
|
|
199
|
+
{ name: 'modelId', value: modelId },
|
|
200
|
+
{ name: 'originalMessages', value: options.messages?.length || 0 },
|
|
201
|
+
{ name: 'processedMessages', value: processedMessages.length },
|
|
202
|
+
{ name: 'temperature', value: options.temperature ?? 0.7 }
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const requestBody = {
|
|
206
|
+
model: modelId,
|
|
207
|
+
messages: processedMessages,
|
|
208
|
+
temperature: options.temperature ?? 0.7,
|
|
209
|
+
max_tokens: options.max_tokens,
|
|
210
|
+
stream: false,
|
|
211
|
+
...(options.tools && {
|
|
212
|
+
tools: options.tools,
|
|
213
|
+
parallel_tool_calls: false, // Enforce one tool at a time via API
|
|
214
|
+
...(options.tool_choice && { tool_choice: options.tool_choice }),
|
|
215
|
+
}),
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
logger.flow('API request preparation complete');
|
|
219
|
+
|
|
220
|
+
// Log request
|
|
221
|
+
logger.httpRequest('POST', `${this.baseUrl}${url}`, {
|
|
222
|
+
model: modelId,
|
|
223
|
+
messages: `${processedMessages.length} messages`,
|
|
224
|
+
temperature: requestBody.temperature,
|
|
225
|
+
max_tokens: requestBody.max_tokens,
|
|
226
|
+
tools: options.tools ? `${options.tools.length} tools` : 'none',
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
logger.verbose('Full Request Body', requestBody);
|
|
230
|
+
|
|
231
|
+
// LLM Log mode: Log request
|
|
232
|
+
if (isLLMLogEnabled()) {
|
|
233
|
+
logger.llmRequest(processedMessages, modelId, options.tools);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
logger.startTimer('llm-api-call');
|
|
237
|
+
|
|
238
|
+
// Create AbortController for this request
|
|
239
|
+
this.currentAbortController = new AbortController();
|
|
240
|
+
|
|
241
|
+
const response = await this.axiosInstance.post<LLMResponse>(url, requestBody, {
|
|
242
|
+
signal: this.currentAbortController.signal,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
this.currentAbortController = null;
|
|
246
|
+
const elapsed = logger.endTimer('llm-api-call');
|
|
247
|
+
|
|
248
|
+
logger.flow('API response received');
|
|
249
|
+
|
|
250
|
+
// Validate response structure
|
|
251
|
+
if (!response.data.choices || !Array.isArray(response.data.choices)) {
|
|
252
|
+
logger.error('Invalid response structure - missing choices array', response.data);
|
|
253
|
+
throw new Error('Invalid LLM response format. Missing choices array.');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Log response
|
|
257
|
+
logger.httpResponse(response.status, response.statusText, {
|
|
258
|
+
choices: response.data.choices.length,
|
|
259
|
+
usage: response.data.usage,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
logger.verbose('Full Response', response.data);
|
|
263
|
+
|
|
264
|
+
logger.vars(
|
|
265
|
+
{ name: 'responseChoices', value: response.data.choices.length },
|
|
266
|
+
{ name: 'tokensUsed', value: response.data.usage?.total_tokens || 0 },
|
|
267
|
+
{ name: 'responseTime', value: elapsed }
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
// LLM Log mode: Log response
|
|
271
|
+
if (isLLMLogEnabled()) {
|
|
272
|
+
const responseContent = response.data.choices[0]?.message?.content || '';
|
|
273
|
+
const toolCalls = response.data.choices[0]?.message?.tool_calls;
|
|
274
|
+
logger.llmResponse(responseContent, toolCalls);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Emit reasoning if present (extended thinking from o1 models)
|
|
278
|
+
// Only emit for user-facing responses (skip internal classifier calls)
|
|
279
|
+
const reasoningContent = response.data.choices[0]?.message?.reasoning;
|
|
280
|
+
const maxTokens = options.max_tokens;
|
|
281
|
+
const isInternalCall = maxTokens && maxTokens < 500; // Internal calls use small max_tokens
|
|
282
|
+
|
|
283
|
+
if (reasoningContent && !isInternalCall) {
|
|
284
|
+
const { emitReasoning } = await import('../../tools/llm/simple/file-tools.js');
|
|
285
|
+
emitReasoning(reasoningContent, false);
|
|
286
|
+
logger.debug('Reasoning content emitted', { length: reasoningContent.length });
|
|
287
|
+
} else if (reasoningContent && isInternalCall) {
|
|
288
|
+
logger.debug('Reasoning skipped (internal call)', { maxTokens, length: reasoningContent.length });
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Track token usage (Phase 3) + context tracking for auto-compact
|
|
292
|
+
if (response.data.usage) {
|
|
293
|
+
const promptTokens = response.data.usage.prompt_tokens || 0;
|
|
294
|
+
usageTracker.recordUsage(
|
|
295
|
+
this.model,
|
|
296
|
+
promptTokens,
|
|
297
|
+
response.data.usage.completion_tokens || 0,
|
|
298
|
+
undefined, // sessionId
|
|
299
|
+
promptTokens // lastPromptTokens for context tracking
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
logger.exit('chatCompletion', {
|
|
304
|
+
success: true,
|
|
305
|
+
choices: response.data.choices.length,
|
|
306
|
+
elapsed
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
return response.data;
|
|
310
|
+
} catch (error) {
|
|
311
|
+
this.currentAbortController = null;
|
|
312
|
+
|
|
313
|
+
// Check if this was an abort/cancel
|
|
314
|
+
if (axios.isCancel(error) || (error instanceof Error && error.name === 'CanceledError')) {
|
|
315
|
+
logger.flow('API call canceled (user interrupt)');
|
|
316
|
+
logger.exit('chatCompletion', { success: false, aborted: true });
|
|
317
|
+
throw new Error('INTERRUPTED');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// If retryable error and retries remaining, retry
|
|
321
|
+
if (currentAttempt < maxRetries && this.isRetryableError(error)) {
|
|
322
|
+
// During retry, only log at debug level (not shown in UI)
|
|
323
|
+
const delay = Math.pow(2, currentAttempt - 1) * 1000; // Exponential backoff: 1s, 2s, 4s
|
|
324
|
+
logger.debug(`LLM call failed (${currentAttempt}/${maxRetries}), retrying after ${delay}ms...`, {
|
|
325
|
+
error: (error as Error).message,
|
|
326
|
+
attempt: currentAttempt,
|
|
327
|
+
maxRetries,
|
|
328
|
+
delay
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
await this.sleep(delay);
|
|
332
|
+
|
|
333
|
+
// Retry recursively
|
|
334
|
+
return this.chatCompletion(options, {
|
|
335
|
+
maxRetries,
|
|
336
|
+
currentAttempt: currentAttempt + 1,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Final failure: Log error and throw
|
|
341
|
+
logger.flow('API call failed - Error handling');
|
|
342
|
+
if (currentAttempt > 1) {
|
|
343
|
+
// Only show error log if final failure after retries
|
|
344
|
+
logger.error(`LLM call final failure after ${maxRetries} retries`, {
|
|
345
|
+
error: (error as Error).message,
|
|
346
|
+
attempts: currentAttempt
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
logger.exit('chatCompletion', { success: false, error: (error as Error).message, attempts: currentAttempt });
|
|
350
|
+
throw this.handleError(error, {
|
|
351
|
+
method: 'POST',
|
|
352
|
+
url,
|
|
353
|
+
body: options,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Abort current LLM request and set interrupt flag (for ESC interrupt)
|
|
360
|
+
*/
|
|
361
|
+
abort(): void {
|
|
362
|
+
logger.flow('LLM interrupt - Stopping all operations');
|
|
363
|
+
this.isInterrupted = true;
|
|
364
|
+
|
|
365
|
+
if (this.currentAbortController) {
|
|
366
|
+
this.currentAbortController.abort();
|
|
367
|
+
this.currentAbortController = null;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Check if interrupted
|
|
373
|
+
*/
|
|
374
|
+
checkInterrupted(): boolean {
|
|
375
|
+
return this.isInterrupted;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Reset interrupt flag (call before starting new operation)
|
|
380
|
+
*/
|
|
381
|
+
resetInterrupt(): void {
|
|
382
|
+
this.isInterrupted = false;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Check if there's an active request
|
|
387
|
+
*/
|
|
388
|
+
isRequestActive(): boolean {
|
|
389
|
+
return this.currentAbortController !== null;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Check if error is retryable
|
|
394
|
+
* - 5xx server errors
|
|
395
|
+
* - Network errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, etc.)
|
|
396
|
+
* - Rate Limit (429)
|
|
397
|
+
* - Tool argument parsing errors are not retried (LLM response issue)
|
|
398
|
+
*/
|
|
399
|
+
private isRetryableError(error: unknown): boolean {
|
|
400
|
+
// Do not retry user interrupts
|
|
401
|
+
if (error instanceof Error && error.message === 'INTERRUPTED') {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (axios.isAxiosError(error)) {
|
|
406
|
+
const axiosError = error as AxiosError;
|
|
407
|
+
|
|
408
|
+
// Network error (no response)
|
|
409
|
+
if (!axiosError.response) {
|
|
410
|
+
const retryableCodes = ['ECONNREFUSED', 'ETIMEDOUT', 'ECONNRESET', 'ECONNABORTED', 'ENOTFOUND', 'EHOSTUNREACH'];
|
|
411
|
+
if (axiosError.code && retryableCodes.includes(axiosError.code)) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
// Timeout
|
|
415
|
+
if (axiosError.message.includes('timeout')) {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
return true; // Retry other network errors too
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const status = axiosError.response.status;
|
|
422
|
+
|
|
423
|
+
// Rate Limit (429)
|
|
424
|
+
if (status === 429) {
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Server error (5xx)
|
|
429
|
+
if (status >= 500) {
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Do not retry auth/permission errors (401, 403)
|
|
434
|
+
// Do not retry bad requests (400)
|
|
435
|
+
// Do not retry Context Length exceeded
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Do not retry other errors
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Wait for specified time (for retry)
|
|
445
|
+
*/
|
|
446
|
+
private sleep(ms: number): Promise<void> {
|
|
447
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Chat Completion API call (Streaming)
|
|
452
|
+
*/
|
|
453
|
+
async *chatCompletionStream(
|
|
454
|
+
options: Partial<LLMRequestOptions>
|
|
455
|
+
): AsyncGenerator<LLMStreamChunk, void, unknown> {
|
|
456
|
+
const url = '/chat/completions';
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
// Preprocess messages for model-specific requirements
|
|
460
|
+
const modelId = options.model || this.model;
|
|
461
|
+
const processedMessages = options.messages ?
|
|
462
|
+
this.preprocessMessages(options.messages, modelId) : [];
|
|
463
|
+
|
|
464
|
+
const requestBody = {
|
|
465
|
+
model: modelId,
|
|
466
|
+
messages: processedMessages,
|
|
467
|
+
temperature: options.temperature ?? 0.7,
|
|
468
|
+
max_tokens: options.max_tokens,
|
|
469
|
+
stream: true,
|
|
470
|
+
...(options.tools && {
|
|
471
|
+
tools: options.tools,
|
|
472
|
+
...(options.tool_choice && { tool_choice: options.tool_choice }),
|
|
473
|
+
}),
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
// Log request
|
|
477
|
+
logger.httpRequest('POST (stream)', `${this.baseUrl}${url}`, {
|
|
478
|
+
model: modelId,
|
|
479
|
+
messages: `${processedMessages.length} messages`,
|
|
480
|
+
temperature: requestBody.temperature,
|
|
481
|
+
max_tokens: requestBody.max_tokens,
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
logger.verbose('Full Streaming Request Body', requestBody);
|
|
485
|
+
|
|
486
|
+
// Create AbortController for streaming request
|
|
487
|
+
this.currentAbortController = new AbortController();
|
|
488
|
+
|
|
489
|
+
const response = await this.axiosInstance.post(url, requestBody, {
|
|
490
|
+
responseType: 'stream',
|
|
491
|
+
signal: this.currentAbortController.signal,
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
logger.debug('Streaming response started', { status: response.status });
|
|
495
|
+
|
|
496
|
+
// SSE (Server-Sent Events) parsing
|
|
497
|
+
const stream = response.data as AsyncIterable<Buffer>;
|
|
498
|
+
let buffer = '';
|
|
499
|
+
let chunkCount = 0;
|
|
500
|
+
|
|
501
|
+
// Check if this is an internal call (skip reasoning for classifier calls)
|
|
502
|
+
const maxTokens = options.max_tokens;
|
|
503
|
+
const isInternalCall = maxTokens && maxTokens < 500;
|
|
504
|
+
|
|
505
|
+
// Import emitReasoning once before loop
|
|
506
|
+
const { emitReasoning } = await import('../../tools/llm/simple/file-tools.js');
|
|
507
|
+
|
|
508
|
+
try {
|
|
509
|
+
for await (const chunk of stream) {
|
|
510
|
+
// Check for interrupt at the start of each chunk
|
|
511
|
+
if (this.isInterrupted) {
|
|
512
|
+
logger.flow('Interrupt detected during streaming - stopping');
|
|
513
|
+
throw new Error('INTERRUPTED');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
buffer += chunk.toString();
|
|
517
|
+
const lines = buffer.split('\n');
|
|
518
|
+
buffer = lines.pop() || '';
|
|
519
|
+
|
|
520
|
+
for (const line of lines) {
|
|
521
|
+
const trimmed = line.trim();
|
|
522
|
+
if (!trimmed || trimmed === 'data: [DONE]') continue;
|
|
523
|
+
|
|
524
|
+
if (trimmed.startsWith('data: ')) {
|
|
525
|
+
try {
|
|
526
|
+
const jsonStr = trimmed.slice(6);
|
|
527
|
+
const data = JSON.parse(jsonStr) as LLMStreamChunk;
|
|
528
|
+
chunkCount++;
|
|
529
|
+
|
|
530
|
+
// Emit reasoning if present in stream (extended thinking)
|
|
531
|
+
// Skip for internal classifier calls
|
|
532
|
+
const reasoningDelta = data.choices[0]?.delta?.reasoning;
|
|
533
|
+
if (reasoningDelta && !isInternalCall) {
|
|
534
|
+
emitReasoning(reasoningDelta, true);
|
|
535
|
+
logger.debug('Reasoning delta emitted', { length: reasoningDelta.length });
|
|
536
|
+
} else if (reasoningDelta && isInternalCall) {
|
|
537
|
+
logger.debug('Reasoning delta skipped (internal call)', { maxTokens });
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
yield data;
|
|
541
|
+
} catch (parseError) {
|
|
542
|
+
// Ignore JSON parsing error (incomplete chunk)
|
|
543
|
+
logger.debug('Skipping invalid chunk', { line: trimmed });
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
} finally {
|
|
550
|
+
// Clear abort controller after streaming completes
|
|
551
|
+
this.currentAbortController = null;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
logger.debug('Streaming response completed', { chunkCount });
|
|
555
|
+
|
|
556
|
+
} catch (error) {
|
|
557
|
+
throw this.handleError(error, {
|
|
558
|
+
method: 'POST (stream)',
|
|
559
|
+
url,
|
|
560
|
+
body: options,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Send simple chat message (helper method)
|
|
567
|
+
*/
|
|
568
|
+
async sendMessage(userMessage: string, systemPrompt?: string): Promise<string> {
|
|
569
|
+
logger.enter('sendMessage', {
|
|
570
|
+
messageLength: userMessage.length,
|
|
571
|
+
hasSystemPrompt: !!systemPrompt
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
logger.flow('Constructing message array');
|
|
575
|
+
const messages: Message[] = [];
|
|
576
|
+
|
|
577
|
+
if (systemPrompt) {
|
|
578
|
+
logger.vars({ name: 'systemPrompt', value: systemPrompt.substring(0, 100) + (systemPrompt.length > 100 ? '...' : '') });
|
|
579
|
+
messages.push({
|
|
580
|
+
role: 'system',
|
|
581
|
+
content: systemPrompt,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
messages.push({
|
|
586
|
+
role: 'user',
|
|
587
|
+
content: userMessage,
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
logger.vars(
|
|
591
|
+
{ name: 'totalMessages', value: messages.length },
|
|
592
|
+
{ name: 'userMessage', value: userMessage.substring(0, 100) + (userMessage.length > 100 ? '...' : '') }
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
logger.flow('Calling LLM API');
|
|
596
|
+
logger.startTimer('sendMessage-api');
|
|
597
|
+
|
|
598
|
+
const response = await this.chatCompletion({ messages });
|
|
599
|
+
|
|
600
|
+
const elapsed = logger.endTimer('sendMessage-api');
|
|
601
|
+
|
|
602
|
+
logger.flow('Processing response');
|
|
603
|
+
if (response.choices.length === 0) {
|
|
604
|
+
logger.flow('No response - Error occurred');
|
|
605
|
+
logger.exit('sendMessage', { success: false, reason: 'No response from LLM' });
|
|
606
|
+
throw new Error('No response from LLM');
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const responseContent = response.choices[0]?.message.content || '';
|
|
610
|
+
|
|
611
|
+
logger.vars(
|
|
612
|
+
{ name: 'responseLength', value: responseContent.length },
|
|
613
|
+
{ name: 'apiTime', value: elapsed }
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
logger.exit('sendMessage', {
|
|
617
|
+
success: true,
|
|
618
|
+
responseLength: responseContent.length,
|
|
619
|
+
elapsed
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
return responseContent;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Send streaming chat message
|
|
627
|
+
*/
|
|
628
|
+
async *sendMessageStream(
|
|
629
|
+
userMessage: string,
|
|
630
|
+
systemPrompt?: string
|
|
631
|
+
): AsyncGenerator<string, void, unknown> {
|
|
632
|
+
const messages: Message[] = [];
|
|
633
|
+
|
|
634
|
+
if (systemPrompt) {
|
|
635
|
+
messages.push({
|
|
636
|
+
role: 'system',
|
|
637
|
+
content: systemPrompt,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
messages.push({
|
|
642
|
+
role: 'user',
|
|
643
|
+
content: userMessage,
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
for await (const chunk of this.chatCompletionStream({ messages })) {
|
|
647
|
+
const content = chunk.choices[0]?.delta?.content;
|
|
648
|
+
if (content) {
|
|
649
|
+
yield content;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Chat Completion with Tools (maintain conversation history)
|
|
656
|
+
* Used in Interactive Mode - supports tool calling with full conversation history
|
|
657
|
+
* No iteration limit - continues until LLM stops calling tools
|
|
658
|
+
*
|
|
659
|
+
* @param messages - Conversation history
|
|
660
|
+
* @param tools - Available tools
|
|
661
|
+
* @param options - Additional options
|
|
662
|
+
* @param options.getPendingMessage - Callback to get pending user message
|
|
663
|
+
* @param options.clearPendingMessage - Callback to clear pending message after processing
|
|
664
|
+
*/
|
|
665
|
+
async chatCompletionWithTools(
|
|
666
|
+
messages: Message[],
|
|
667
|
+
tools: import('../../types/index.js').ToolDefinition[],
|
|
668
|
+
options?: {
|
|
669
|
+
getPendingMessage?: () => string | null;
|
|
670
|
+
clearPendingMessage?: () => void;
|
|
671
|
+
}
|
|
672
|
+
): Promise<{
|
|
673
|
+
message: Message;
|
|
674
|
+
toolCalls: Array<{ tool: string; args: unknown; result: string }>;
|
|
675
|
+
allMessages: Message[];
|
|
676
|
+
}> {
|
|
677
|
+
let workingMessages = [...messages];
|
|
678
|
+
const toolCallHistory: Array<{ tool: string; args: unknown; result: string }> = [];
|
|
679
|
+
let iterations = 0;
|
|
680
|
+
let contextLengthRecoveryAttempted = false; // Prevent infinite recovery loop
|
|
681
|
+
let noToolCallRetries = 0; // Prevent infinite loop when LLM doesn't use tools
|
|
682
|
+
let finalResponseFailures = 0; // Prevent infinite loop when final_response keeps failing
|
|
683
|
+
const MAX_NO_TOOL_CALL_RETRIES = 3; // Max retries for enforcing tool usage
|
|
684
|
+
const MAX_FINAL_RESPONSE_FAILURES = 3; // Max retries for final_response failures
|
|
685
|
+
|
|
686
|
+
while (true) {
|
|
687
|
+
// Check for interrupt at start of each iteration
|
|
688
|
+
if (this.isInterrupted) {
|
|
689
|
+
logger.flow('Interrupt detected - stopping tool loop');
|
|
690
|
+
throw new Error('INTERRUPTED');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
iterations++;
|
|
694
|
+
|
|
695
|
+
// Check for pending user message and inject it
|
|
696
|
+
if (options?.getPendingMessage && options?.clearPendingMessage) {
|
|
697
|
+
const pendingMsg = options.getPendingMessage();
|
|
698
|
+
if (pendingMsg) {
|
|
699
|
+
logger.flow('Injecting pending user message into conversation');
|
|
700
|
+
workingMessages.push({ role: 'user' as const, content: pendingMsg });
|
|
701
|
+
options.clearPendingMessage();
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Call LLM (with tools) - with ContextLengthError recovery
|
|
706
|
+
// tool_choice: 'required' forces LLM to always use a tool (use final_response for final answer)
|
|
707
|
+
let response: LLMResponse;
|
|
708
|
+
try {
|
|
709
|
+
response = await this.chatCompletion({
|
|
710
|
+
messages: workingMessages,
|
|
711
|
+
tools,
|
|
712
|
+
tool_choice: 'required',
|
|
713
|
+
});
|
|
714
|
+
} catch (error) {
|
|
715
|
+
// ContextLengthError recovery: rollback last tool + compact + retry
|
|
716
|
+
if (error instanceof ContextLengthError && !contextLengthRecoveryAttempted) {
|
|
717
|
+
contextLengthRecoveryAttempted = true;
|
|
718
|
+
logger.flow('ContextLengthError detected - attempting recovery with compact');
|
|
719
|
+
|
|
720
|
+
// Rollback: remove last tool results and assistant message with tool_calls
|
|
721
|
+
let rollbackIdx = workingMessages.length - 1;
|
|
722
|
+
while (rollbackIdx >= 0 && workingMessages[rollbackIdx]?.role === 'tool') {
|
|
723
|
+
rollbackIdx--;
|
|
724
|
+
}
|
|
725
|
+
// rollbackIdx now points to last assistant message (with tool_calls)
|
|
726
|
+
if (rollbackIdx >= 0 && workingMessages[rollbackIdx]?.tool_calls) {
|
|
727
|
+
workingMessages = workingMessages.slice(0, rollbackIdx);
|
|
728
|
+
logger.debug('Rolled back messages to before last tool execution', {
|
|
729
|
+
removedCount: workingMessages.length - rollbackIdx,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Execute compact
|
|
734
|
+
const { CompactManager } = await import('../compact/compact-manager.js');
|
|
735
|
+
const { buildCompactedMessages } = await import('../compact/compact-prompts.js');
|
|
736
|
+
const compactManager = new CompactManager(this);
|
|
737
|
+
|
|
738
|
+
const compactResult = await compactManager.compact(workingMessages, {
|
|
739
|
+
workingDirectory: process.cwd(),
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
if (compactResult.success && compactResult.compactedSummary) {
|
|
743
|
+
// Replace workingMessages with compacted result
|
|
744
|
+
const compactedMessages = buildCompactedMessages(compactResult.compactedSummary, {
|
|
745
|
+
workingDirectory: process.cwd(),
|
|
746
|
+
});
|
|
747
|
+
workingMessages = [...compactedMessages];
|
|
748
|
+
logger.flow('Compact completed, retrying with reduced context', {
|
|
749
|
+
originalCount: compactResult.originalMessageCount,
|
|
750
|
+
newCount: compactedMessages.length,
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
// Retry loop
|
|
754
|
+
continue;
|
|
755
|
+
} else {
|
|
756
|
+
// Compact failed - throw original error
|
|
757
|
+
logger.error('Compact failed during recovery', { error: compactResult.error });
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Other errors or second ContextLengthError - rethrow
|
|
763
|
+
throw error;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// Check for interrupt after LLM call
|
|
767
|
+
if (this.isInterrupted) {
|
|
768
|
+
logger.flow('Interrupt detected after LLM call - stopping');
|
|
769
|
+
throw new Error('INTERRUPTED');
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
const choice = response.choices[0];
|
|
773
|
+
if (!choice) {
|
|
774
|
+
throw new Error('Cannot find choice in response.');
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const assistantMessage = choice.message;
|
|
778
|
+
workingMessages.push(assistantMessage);
|
|
779
|
+
|
|
780
|
+
// Check tool calls
|
|
781
|
+
if (assistantMessage.tool_calls && assistantMessage.tool_calls.length > 0) {
|
|
782
|
+
// Multi-tool detection logging
|
|
783
|
+
if (assistantMessage.tool_calls.length > 1) {
|
|
784
|
+
const toolNames = assistantMessage.tool_calls.map(tc => tc.function.name).join(', ');
|
|
785
|
+
logger.warn(`[MULTI-TOOL DETECTED] LLM returned ${assistantMessage.tool_calls.length} tools: ${toolNames}`);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Execute tool calls (parallel_tool_calls: false ensures single tool from API)
|
|
789
|
+
for (const toolCall of assistantMessage.tool_calls) {
|
|
790
|
+
const toolName = toolCall.function.name;
|
|
791
|
+
let toolArgs: Record<string, unknown>;
|
|
792
|
+
|
|
793
|
+
try {
|
|
794
|
+
toolArgs = JSON.parse(toolCall.function.arguments) as Record<string, unknown>;
|
|
795
|
+
} catch (parseError) {
|
|
796
|
+
const errorMsg = `Tool argument parsing failed for ${toolName}`;
|
|
797
|
+
logger.error(errorMsg, parseError);
|
|
798
|
+
logger.debug('Raw arguments', { raw: toolCall.function.arguments });
|
|
799
|
+
|
|
800
|
+
workingMessages.push({
|
|
801
|
+
role: 'tool',
|
|
802
|
+
content: `Error: Failed to parse tool arguments - ${parseError instanceof Error ? parseError.message : 'Unknown error'}`,
|
|
803
|
+
tool_call_id: toolCall.id,
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
toolCallHistory.push({
|
|
807
|
+
tool: toolName,
|
|
808
|
+
args: { raw: toolCall.function.arguments },
|
|
809
|
+
result: `Error: Argument parsing failed`,
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Execute tool
|
|
816
|
+
const { executeFileTool, requestToolApproval } = await import('../../tools/llm/simple/file-tools.js');
|
|
817
|
+
|
|
818
|
+
// Supervised Mode: Request user approval before tool execution
|
|
819
|
+
const approvalResult = await requestToolApproval(toolName, toolArgs);
|
|
820
|
+
|
|
821
|
+
if (approvalResult && typeof approvalResult === 'object' && approvalResult.reject) {
|
|
822
|
+
// User rejected the tool execution
|
|
823
|
+
logger.flow(`Tool rejected by user: ${toolName}`);
|
|
824
|
+
|
|
825
|
+
const rejectMessage = approvalResult.comment
|
|
826
|
+
? `Tool execution rejected by user. Reason: ${approvalResult.comment}`
|
|
827
|
+
: 'Tool execution rejected by user.';
|
|
828
|
+
|
|
829
|
+
workingMessages.push({
|
|
830
|
+
role: 'tool',
|
|
831
|
+
content: rejectMessage,
|
|
832
|
+
tool_call_id: toolCall.id,
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
toolCallHistory.push({
|
|
836
|
+
tool: toolName,
|
|
837
|
+
args: toolArgs,
|
|
838
|
+
result: rejectMessage,
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
logger.debug(`Executing tool: ${toolName}`, toolArgs);
|
|
845
|
+
|
|
846
|
+
let result: { success: boolean; result?: string; error?: string; metadata?: Record<string, unknown> };
|
|
847
|
+
|
|
848
|
+
try {
|
|
849
|
+
result = await executeFileTool(toolName, toolArgs);
|
|
850
|
+
logger.toolExecution(toolName, toolArgs, result);
|
|
851
|
+
|
|
852
|
+
// LLM Log mode: Log tool result
|
|
853
|
+
if (isLLMLogEnabled()) {
|
|
854
|
+
logger.llmToolResult(toolName, result.result || '', result.success);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// Handle final_response tool
|
|
858
|
+
if (toolName === 'final_response') {
|
|
859
|
+
if (result.success && result.metadata?.['isFinalResponse']) {
|
|
860
|
+
// Success - return immediately
|
|
861
|
+
// Note: emitAssistantResponse is already called via finalResponseCallback in final-response-tool.ts
|
|
862
|
+
logger.flow('final_response tool executed successfully - returning');
|
|
863
|
+
|
|
864
|
+
// Add tool result to messages for completeness
|
|
865
|
+
workingMessages.push({
|
|
866
|
+
role: 'tool',
|
|
867
|
+
content: result.result || '',
|
|
868
|
+
tool_call_id: toolCall.id,
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
// Add to history
|
|
872
|
+
toolCallHistory.push({
|
|
873
|
+
tool: toolName,
|
|
874
|
+
args: toolArgs,
|
|
875
|
+
result: result.result || '',
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
// Return final response
|
|
879
|
+
return {
|
|
880
|
+
message: {
|
|
881
|
+
role: 'assistant' as const,
|
|
882
|
+
content: result.result || '',
|
|
883
|
+
},
|
|
884
|
+
toolCalls: toolCallHistory,
|
|
885
|
+
allMessages: workingMessages,
|
|
886
|
+
};
|
|
887
|
+
} else {
|
|
888
|
+
// Failure - track attempts to prevent infinite loop
|
|
889
|
+
finalResponseFailures++;
|
|
890
|
+
logger.flow(`final_response failed (attempt ${finalResponseFailures}/${MAX_FINAL_RESPONSE_FAILURES}): ${result.error}`);
|
|
891
|
+
|
|
892
|
+
if (finalResponseFailures >= MAX_FINAL_RESPONSE_FAILURES) {
|
|
893
|
+
logger.warn('Max final_response failures exceeded - forcing completion');
|
|
894
|
+
const fallbackMessage = (toolArgs['message'] as string) || 'Task completed with incomplete TODOs.';
|
|
895
|
+
|
|
896
|
+
// Emit as assistant response
|
|
897
|
+
const { emitAssistantResponse } = await import('../../tools/llm/simple/file-tools.js');
|
|
898
|
+
emitAssistantResponse(fallbackMessage);
|
|
899
|
+
|
|
900
|
+
return {
|
|
901
|
+
message: { role: 'assistant' as const, content: fallbackMessage },
|
|
902
|
+
toolCalls: toolCallHistory,
|
|
903
|
+
allMessages: workingMessages,
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
} catch (toolError) {
|
|
909
|
+
logger.toolExecution(toolName, toolArgs, undefined, toolError as Error);
|
|
910
|
+
|
|
911
|
+
// LLM Log mode: Log tool error
|
|
912
|
+
if (isLLMLogEnabled()) {
|
|
913
|
+
const errorMsg = toolError instanceof Error ? toolError.message : String(toolError);
|
|
914
|
+
logger.llmToolResult(toolName, `Error: ${errorMsg}`, false);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
result = {
|
|
918
|
+
success: false,
|
|
919
|
+
error: toolError instanceof Error ? toolError.message : String(toolError),
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Add result to messages
|
|
924
|
+
workingMessages.push({
|
|
925
|
+
role: 'tool',
|
|
926
|
+
content: result.success ? result.result || '' : `Error: ${result.error}`,
|
|
927
|
+
tool_call_id: toolCall.id,
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
// Add to history
|
|
931
|
+
toolCallHistory.push({
|
|
932
|
+
tool: toolName,
|
|
933
|
+
args: toolArgs,
|
|
934
|
+
result: result.success ? result.result || '' : `Error: ${result.error}`,
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
// Check for interrupt after tool execution
|
|
938
|
+
if (this.isInterrupted) {
|
|
939
|
+
logger.flow('Interrupt detected after tool execution - stopping');
|
|
940
|
+
throw new Error('INTERRUPTED');
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Tool execution complete - Continue calling LLM (continue)
|
|
945
|
+
// Loop continues until LLM returns finish_reason: stop
|
|
946
|
+
continue;
|
|
947
|
+
} else {
|
|
948
|
+
// No tool call - Force tool call
|
|
949
|
+
// LLM must use tools (including final_response)
|
|
950
|
+
noToolCallRetries++;
|
|
951
|
+
logger.flow(`No tool call - enforcing tool usage (attempt ${noToolCallRetries}/${MAX_NO_TOOL_CALL_RETRIES})`);
|
|
952
|
+
|
|
953
|
+
// Max retries exceeded - return content as final response to prevent infinite loop
|
|
954
|
+
if (noToolCallRetries > MAX_NO_TOOL_CALL_RETRIES) {
|
|
955
|
+
logger.warn('Max no-tool-call retries exceeded - returning content as final response');
|
|
956
|
+
const fallbackContent = assistantMessage.content || 'Task completed.';
|
|
957
|
+
|
|
958
|
+
// Emit as assistant response
|
|
959
|
+
const { emitAssistantResponse } = await import('../../tools/llm/simple/file-tools.js');
|
|
960
|
+
emitAssistantResponse(fallbackContent);
|
|
961
|
+
|
|
962
|
+
return {
|
|
963
|
+
message: { role: 'assistant' as const, content: fallbackContent },
|
|
964
|
+
toolCalls: toolCallHistory,
|
|
965
|
+
allMessages: workingMessages,
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Check for malformed tool call patterns in content
|
|
970
|
+
const hasMalformedToolCall = assistantMessage.content &&
|
|
971
|
+
(/<tool_call>/i.test(assistantMessage.content) ||
|
|
972
|
+
/<arg_key>/i.test(assistantMessage.content) ||
|
|
973
|
+
/<arg_value>/i.test(assistantMessage.content) ||
|
|
974
|
+
/<\/tool_call>/i.test(assistantMessage.content) ||
|
|
975
|
+
/bash<arg_key>/i.test(assistantMessage.content));
|
|
976
|
+
|
|
977
|
+
const retryMessage = hasMalformedToolCall
|
|
978
|
+
? 'Your previous response contained a malformed tool call (XML tags in content). You MUST use the proper tool_calls API format. Use final_response tool to deliver your message to the user.'
|
|
979
|
+
: 'You must use tools for all actions. Use final_response tool to deliver your final message to the user after completing all tasks.';
|
|
980
|
+
|
|
981
|
+
// Add assistant message (to preserve context) and retry instruction
|
|
982
|
+
workingMessages.push({
|
|
983
|
+
role: 'user',
|
|
984
|
+
content: retryMessage,
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
logger.debug('Enforcing tool call - added retry message');
|
|
988
|
+
|
|
989
|
+
// Continue loop to retry
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* Get current model information
|
|
997
|
+
*/
|
|
998
|
+
getModelInfo(): { model: string; endpoint: string } {
|
|
999
|
+
return {
|
|
1000
|
+
model: this.modelName,
|
|
1001
|
+
endpoint: this.baseUrl,
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Enhanced error handler with detailed logging
|
|
1007
|
+
*/
|
|
1008
|
+
private handleError(error: unknown, requestContext?: { method?: string; url?: string; body?: unknown }): Error {
|
|
1009
|
+
// Log the error with context
|
|
1010
|
+
logger.error('LLM Client Error', error);
|
|
1011
|
+
|
|
1012
|
+
if (requestContext) {
|
|
1013
|
+
logger.debug('Request Context', requestContext);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
if (axios.isAxiosError(error)) {
|
|
1017
|
+
const axiosError = error as AxiosError;
|
|
1018
|
+
|
|
1019
|
+
// Timeout error
|
|
1020
|
+
if (axiosError.code === 'ECONNABORTED' || axiosError.message.includes('timeout')) {
|
|
1021
|
+
logger.error('Request Timeout', {
|
|
1022
|
+
timeout: this.axiosInstance.defaults.timeout,
|
|
1023
|
+
endpoint: this.baseUrl,
|
|
1024
|
+
});
|
|
1025
|
+
return new TimeoutError(
|
|
1026
|
+
this.axiosInstance.defaults.timeout || 60000,
|
|
1027
|
+
{
|
|
1028
|
+
cause: axiosError,
|
|
1029
|
+
details: {
|
|
1030
|
+
endpoint: this.baseUrl,
|
|
1031
|
+
method: requestContext?.method,
|
|
1032
|
+
url: requestContext?.url,
|
|
1033
|
+
},
|
|
1034
|
+
}
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
if (axiosError.response) {
|
|
1039
|
+
// Server responded with error status (4xx, 5xx)
|
|
1040
|
+
const status = axiosError.response.status;
|
|
1041
|
+
const data = axiosError.response.data as any;
|
|
1042
|
+
const errorMessage = data?.error?.message || data?.message || axiosError.message;
|
|
1043
|
+
const errorType = data?.error?.type || 'unknown';
|
|
1044
|
+
const errorCode = data?.error?.code || data?.code;
|
|
1045
|
+
|
|
1046
|
+
// Enhanced error logging for debugging
|
|
1047
|
+
logger.error('=== API ERROR DETAILS ===', {
|
|
1048
|
+
status,
|
|
1049
|
+
statusText: axiosError.response.statusText,
|
|
1050
|
+
endpoint: this.baseUrl,
|
|
1051
|
+
model: this.model,
|
|
1052
|
+
errorMessage,
|
|
1053
|
+
errorType,
|
|
1054
|
+
errorCode,
|
|
1055
|
+
// Full API response body
|
|
1056
|
+
responseBody: JSON.stringify(data, null, 2),
|
|
1057
|
+
// Request info
|
|
1058
|
+
requestMethod: requestContext?.method,
|
|
1059
|
+
requestUrl: requestContext?.url,
|
|
1060
|
+
// Request body (truncated for large payloads)
|
|
1061
|
+
requestBody: requestContext?.body
|
|
1062
|
+
? JSON.stringify(requestContext.body, null, 2).substring(0, 5000)
|
|
1063
|
+
: undefined,
|
|
1064
|
+
// Response headers
|
|
1065
|
+
responseHeaders: axiosError.response.headers,
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
logger.httpResponse(status, axiosError.response.statusText, data);
|
|
1069
|
+
|
|
1070
|
+
// Context length exceeded (common OpenAI error)
|
|
1071
|
+
if (
|
|
1072
|
+
errorType === 'invalid_request_error' &&
|
|
1073
|
+
(errorMessage.includes('context_length_exceeded') ||
|
|
1074
|
+
errorMessage.includes('maximum context length') ||
|
|
1075
|
+
errorCode === 'context_length_exceeded')
|
|
1076
|
+
) {
|
|
1077
|
+
const maxLength = data?.error?.param?.max_tokens || 'unknown';
|
|
1078
|
+
logger.error('Context Length Exceeded', {
|
|
1079
|
+
maxLength,
|
|
1080
|
+
errorMessage,
|
|
1081
|
+
model: this.model,
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
return new ContextLengthError(
|
|
1085
|
+
typeof maxLength === 'number' ? maxLength : 0,
|
|
1086
|
+
undefined,
|
|
1087
|
+
{
|
|
1088
|
+
cause: axiosError,
|
|
1089
|
+
details: {
|
|
1090
|
+
model: this.model,
|
|
1091
|
+
endpoint: this.baseUrl,
|
|
1092
|
+
errorType,
|
|
1093
|
+
fullError: data,
|
|
1094
|
+
},
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// Token limit error
|
|
1100
|
+
if (
|
|
1101
|
+
errorMessage.includes('token') &&
|
|
1102
|
+
(errorMessage.includes('limit') || errorMessage.includes('exceeded'))
|
|
1103
|
+
) {
|
|
1104
|
+
logger.error('Token Limit Error', {
|
|
1105
|
+
errorMessage,
|
|
1106
|
+
model: this.model,
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
return new TokenLimitError(
|
|
1110
|
+
0, // We don't know the exact limit from error message
|
|
1111
|
+
undefined,
|
|
1112
|
+
{
|
|
1113
|
+
cause: axiosError,
|
|
1114
|
+
details: {
|
|
1115
|
+
model: this.model,
|
|
1116
|
+
endpoint: this.baseUrl,
|
|
1117
|
+
fullError: data,
|
|
1118
|
+
},
|
|
1119
|
+
userMessage: errorMessage,
|
|
1120
|
+
}
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// Rate limit (429)
|
|
1125
|
+
if (status === 429) {
|
|
1126
|
+
const retryAfter = axiosError.response.headers['retry-after'];
|
|
1127
|
+
const retrySeconds = retryAfter ? parseInt(retryAfter) : undefined;
|
|
1128
|
+
|
|
1129
|
+
logger.error('Rate Limit Exceeded', {
|
|
1130
|
+
retryAfter: retrySeconds,
|
|
1131
|
+
errorMessage,
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
return new RateLimitError(retrySeconds, {
|
|
1135
|
+
cause: axiosError,
|
|
1136
|
+
details: {
|
|
1137
|
+
endpoint: this.baseUrl,
|
|
1138
|
+
model: this.model,
|
|
1139
|
+
fullError: data,
|
|
1140
|
+
},
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// Authentication error (401)
|
|
1145
|
+
if (status === 401) {
|
|
1146
|
+
logger.error('Authentication Failed', {
|
|
1147
|
+
endpoint: this.baseUrl,
|
|
1148
|
+
errorMessage,
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
return new APIError(
|
|
1152
|
+
`Authentication failed: ${errorMessage}`,
|
|
1153
|
+
status,
|
|
1154
|
+
this.baseUrl,
|
|
1155
|
+
{
|
|
1156
|
+
cause: axiosError,
|
|
1157
|
+
details: {
|
|
1158
|
+
apiKeyProvided: !!this.apiKey,
|
|
1159
|
+
apiKeyLength: this.apiKey?.length || 0,
|
|
1160
|
+
fullError: data,
|
|
1161
|
+
},
|
|
1162
|
+
isRecoverable: false,
|
|
1163
|
+
userMessage: `Invalid API key. Please check your settings.\nDetails: ${errorMessage}`,
|
|
1164
|
+
}
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// Forbidden (403)
|
|
1169
|
+
if (status === 403) {
|
|
1170
|
+
logger.error('Access Forbidden', {
|
|
1171
|
+
endpoint: this.baseUrl,
|
|
1172
|
+
errorMessage,
|
|
1173
|
+
});
|
|
1174
|
+
|
|
1175
|
+
return new APIError(
|
|
1176
|
+
`Access denied: ${errorMessage}`,
|
|
1177
|
+
status,
|
|
1178
|
+
this.baseUrl,
|
|
1179
|
+
{
|
|
1180
|
+
cause: axiosError,
|
|
1181
|
+
details: {
|
|
1182
|
+
fullError: data,
|
|
1183
|
+
},
|
|
1184
|
+
isRecoverable: false,
|
|
1185
|
+
}
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// Not found (404)
|
|
1190
|
+
if (status === 404) {
|
|
1191
|
+
logger.error('Endpoint Not Found', {
|
|
1192
|
+
endpoint: this.baseUrl,
|
|
1193
|
+
url: requestContext?.url,
|
|
1194
|
+
errorMessage,
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
return new APIError(
|
|
1198
|
+
`Endpoint not found: ${errorMessage}`,
|
|
1199
|
+
status,
|
|
1200
|
+
this.baseUrl,
|
|
1201
|
+
{
|
|
1202
|
+
cause: axiosError,
|
|
1203
|
+
details: {
|
|
1204
|
+
url: requestContext?.url,
|
|
1205
|
+
fullError: data,
|
|
1206
|
+
},
|
|
1207
|
+
isRecoverable: false,
|
|
1208
|
+
userMessage: `API endpoint does not exist.\nURL: ${this.baseUrl}${requestContext?.url || ''}\nDetails: ${errorMessage}`,
|
|
1209
|
+
}
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// Server error (5xx)
|
|
1214
|
+
if (status >= 500) {
|
|
1215
|
+
logger.error('Server Error', {
|
|
1216
|
+
status,
|
|
1217
|
+
endpoint: this.baseUrl,
|
|
1218
|
+
errorMessage,
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1221
|
+
return new APIError(
|
|
1222
|
+
`Server error (${status}): ${errorMessage}`,
|
|
1223
|
+
status,
|
|
1224
|
+
this.baseUrl,
|
|
1225
|
+
{
|
|
1226
|
+
cause: axiosError,
|
|
1227
|
+
details: {
|
|
1228
|
+
fullError: data,
|
|
1229
|
+
},
|
|
1230
|
+
isRecoverable: true, // Server errors are usually temporary
|
|
1231
|
+
}
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// Other API errors (4xx)
|
|
1236
|
+
logger.error('API Error', {
|
|
1237
|
+
status,
|
|
1238
|
+
endpoint: this.baseUrl,
|
|
1239
|
+
errorMessage,
|
|
1240
|
+
errorType,
|
|
1241
|
+
errorCode,
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
return new APIError(
|
|
1245
|
+
`API error (${status}): ${errorMessage}`,
|
|
1246
|
+
status,
|
|
1247
|
+
this.baseUrl,
|
|
1248
|
+
{
|
|
1249
|
+
cause: axiosError,
|
|
1250
|
+
details: {
|
|
1251
|
+
errorType,
|
|
1252
|
+
errorCode,
|
|
1253
|
+
fullError: data,
|
|
1254
|
+
},
|
|
1255
|
+
userMessage: `API request failed (${status}):\n${errorMessage}\n\nError type: ${errorType}\nError code: ${errorCode}`,
|
|
1256
|
+
}
|
|
1257
|
+
);
|
|
1258
|
+
|
|
1259
|
+
} else if (axiosError.request) {
|
|
1260
|
+
// Request sent but no response received (network error)
|
|
1261
|
+
const errorCode = axiosError.code;
|
|
1262
|
+
|
|
1263
|
+
logger.error('Network Error - No Response', {
|
|
1264
|
+
code: errorCode,
|
|
1265
|
+
endpoint: this.baseUrl,
|
|
1266
|
+
message: axiosError.message,
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
// Connection refused, host not found, etc.
|
|
1270
|
+
if (
|
|
1271
|
+
errorCode === 'ECONNREFUSED' ||
|
|
1272
|
+
errorCode === 'ENOTFOUND' ||
|
|
1273
|
+
errorCode === 'ECONNRESET' ||
|
|
1274
|
+
errorCode === 'EHOSTUNREACH'
|
|
1275
|
+
) {
|
|
1276
|
+
return new ConnectionError(this.baseUrl, {
|
|
1277
|
+
cause: axiosError,
|
|
1278
|
+
details: {
|
|
1279
|
+
code: errorCode,
|
|
1280
|
+
message: axiosError.message,
|
|
1281
|
+
},
|
|
1282
|
+
userMessage: `Cannot connect to server.\nEndpoint: ${this.baseUrl}\nError code: ${errorCode}\nDetails: ${axiosError.message}\n\nPlease check network connection and endpoint URL.`,
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// General network error
|
|
1287
|
+
return new NetworkError(
|
|
1288
|
+
`Network error: ${axiosError.message}`,
|
|
1289
|
+
{
|
|
1290
|
+
cause: axiosError,
|
|
1291
|
+
details: {
|
|
1292
|
+
code: errorCode,
|
|
1293
|
+
endpoint: this.baseUrl,
|
|
1294
|
+
},
|
|
1295
|
+
userMessage: `Network connection failed.\nEndpoint: ${this.baseUrl}\nError: ${axiosError.message}`,
|
|
1296
|
+
}
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// Axios error without response or request
|
|
1301
|
+
logger.error('Axios Error', {
|
|
1302
|
+
code: axiosError.code,
|
|
1303
|
+
message: axiosError.message,
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
return new LLMError(
|
|
1307
|
+
`LLM client error: ${axiosError.message}`,
|
|
1308
|
+
{
|
|
1309
|
+
cause: axiosError,
|
|
1310
|
+
details: {
|
|
1311
|
+
code: axiosError.code,
|
|
1312
|
+
},
|
|
1313
|
+
}
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// Non-axios error
|
|
1318
|
+
if (error instanceof Error) {
|
|
1319
|
+
logger.error('Unexpected Error', error);
|
|
1320
|
+
return new LLMError(
|
|
1321
|
+
`Unexpected error: ${error.message}`,
|
|
1322
|
+
{
|
|
1323
|
+
cause: error,
|
|
1324
|
+
userMessage: `An error occurred:\n${error.message}\n\nStack:\n${error.stack}`,
|
|
1325
|
+
}
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// Unknown error type
|
|
1330
|
+
logger.error('Unknown Error Type', { error });
|
|
1331
|
+
return new LLMError('An unknown error occurred.', {
|
|
1332
|
+
details: { unknownError: error },
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
/**
|
|
1337
|
+
* Chat Completion with retry logic
|
|
1338
|
+
* @deprecated chatCompletion now performs retry by default
|
|
1339
|
+
*/
|
|
1340
|
+
async chatCompletionWithRetry(
|
|
1341
|
+
options: Partial<LLMRequestOptions>,
|
|
1342
|
+
maxRetries = 3
|
|
1343
|
+
): Promise<LLMResponse> {
|
|
1344
|
+
// Call directly as chatCompletion now performs retry internally
|
|
1345
|
+
return this.chatCompletion(options, { maxRetries });
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/**
|
|
1349
|
+
* Health check for currently configured endpoint
|
|
1350
|
+
*/
|
|
1351
|
+
async healthCheck(): Promise<{
|
|
1352
|
+
success: boolean;
|
|
1353
|
+
latency?: number;
|
|
1354
|
+
error?: string;
|
|
1355
|
+
}> {
|
|
1356
|
+
const endpoint = configManager.getCurrentEndpoint();
|
|
1357
|
+
const model = configManager.getCurrentModel();
|
|
1358
|
+
|
|
1359
|
+
if (!endpoint || !model) {
|
|
1360
|
+
return { success: false, error: 'No endpoint or model configured' };
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
const startTime = Date.now();
|
|
1364
|
+
|
|
1365
|
+
try {
|
|
1366
|
+
const response = await this.axiosInstance.post<LLMResponse>('/chat/completions', {
|
|
1367
|
+
model: model.id,
|
|
1368
|
+
messages: [{ role: 'user', content: 'ping' }],
|
|
1369
|
+
max_tokens: 5,
|
|
1370
|
+
});
|
|
1371
|
+
|
|
1372
|
+
const latency = Date.now() - startTime;
|
|
1373
|
+
|
|
1374
|
+
if (response.status === 200 && response.data.choices?.[0]?.message) {
|
|
1375
|
+
return { success: true, latency };
|
|
1376
|
+
} else {
|
|
1377
|
+
return { success: false, latency, error: 'Invalid response format' };
|
|
1378
|
+
}
|
|
1379
|
+
} catch (error) {
|
|
1380
|
+
const latency = Date.now() - startTime;
|
|
1381
|
+
const axiosError = error as AxiosError;
|
|
1382
|
+
|
|
1383
|
+
if (axiosError.response) {
|
|
1384
|
+
const status = axiosError.response.status;
|
|
1385
|
+
return { success: false, latency, error: `HTTP ${status}` };
|
|
1386
|
+
} else if (axiosError.request) {
|
|
1387
|
+
return { success: false, latency, error: 'Connection failed' };
|
|
1388
|
+
} else {
|
|
1389
|
+
return { success: false, latency, error: axiosError.message || 'Unknown error' };
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Bulk health check for all registered endpoints
|
|
1396
|
+
*/
|
|
1397
|
+
static async healthCheckAll(): Promise<
|
|
1398
|
+
Map<string, { modelId: string; healthy: boolean; latency?: number; error?: string }[]>
|
|
1399
|
+
> {
|
|
1400
|
+
const endpoints = configManager.getAllEndpoints();
|
|
1401
|
+
const results = new Map<
|
|
1402
|
+
string,
|
|
1403
|
+
{ modelId: string; healthy: boolean; latency?: number; error?: string }[]
|
|
1404
|
+
>();
|
|
1405
|
+
|
|
1406
|
+
for (const endpoint of endpoints) {
|
|
1407
|
+
const modelResults: { modelId: string; healthy: boolean; latency?: number; error?: string }[] = [];
|
|
1408
|
+
|
|
1409
|
+
for (const model of endpoint.models) {
|
|
1410
|
+
if (!model.enabled) {
|
|
1411
|
+
modelResults.push({
|
|
1412
|
+
modelId: model.id,
|
|
1413
|
+
healthy: false,
|
|
1414
|
+
error: 'Model disabled',
|
|
1415
|
+
});
|
|
1416
|
+
continue;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
const startTime = Date.now();
|
|
1420
|
+
|
|
1421
|
+
try {
|
|
1422
|
+
const axiosInstance = axios.create({
|
|
1423
|
+
baseURL: endpoint.baseUrl,
|
|
1424
|
+
headers: {
|
|
1425
|
+
'Content-Type': 'application/json',
|
|
1426
|
+
...(endpoint.apiKey && { Authorization: `Bearer ${endpoint.apiKey}` }),
|
|
1427
|
+
},
|
|
1428
|
+
timeout: 30000, // 30 second timeout
|
|
1429
|
+
});
|
|
1430
|
+
|
|
1431
|
+
const response = await axiosInstance.post<LLMResponse>('/chat/completions', {
|
|
1432
|
+
model: model.id,
|
|
1433
|
+
messages: [{ role: 'user', content: 'ping' }],
|
|
1434
|
+
max_tokens: 5,
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
const latency = Date.now() - startTime;
|
|
1438
|
+
|
|
1439
|
+
if (response.status === 200 && response.data.choices?.[0]?.message) {
|
|
1440
|
+
modelResults.push({ modelId: model.id, healthy: true, latency });
|
|
1441
|
+
} else {
|
|
1442
|
+
modelResults.push({
|
|
1443
|
+
modelId: model.id,
|
|
1444
|
+
healthy: false,
|
|
1445
|
+
latency,
|
|
1446
|
+
error: 'Invalid response',
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
const latency = Date.now() - startTime;
|
|
1451
|
+
const axiosError = error as AxiosError;
|
|
1452
|
+
|
|
1453
|
+
let errorMessage = 'Unknown error';
|
|
1454
|
+
if (axiosError.response) {
|
|
1455
|
+
errorMessage = `HTTP ${axiosError.response.status}`;
|
|
1456
|
+
} else if (axiosError.code === 'ECONNREFUSED') {
|
|
1457
|
+
errorMessage = 'Connection refused';
|
|
1458
|
+
} else if (axiosError.code === 'ETIMEDOUT' || axiosError.code === 'ECONNABORTED') {
|
|
1459
|
+
errorMessage = 'Timeout';
|
|
1460
|
+
} else if (axiosError.request) {
|
|
1461
|
+
errorMessage = 'Network error';
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
modelResults.push({
|
|
1465
|
+
modelId: model.id,
|
|
1466
|
+
healthy: false,
|
|
1467
|
+
latency,
|
|
1468
|
+
error: errorMessage,
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
results.set(endpoint.id, modelResults);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
return results;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
/**
|
|
1480
|
+
* Endpoint connection test (Static)
|
|
1481
|
+
* Static method for use during config init
|
|
1482
|
+
*/
|
|
1483
|
+
static async testConnection(
|
|
1484
|
+
baseUrl: string,
|
|
1485
|
+
apiKey: string,
|
|
1486
|
+
model: string
|
|
1487
|
+
): Promise<{ success: boolean; latency?: number; error?: string }> {
|
|
1488
|
+
const startTime = Date.now();
|
|
1489
|
+
|
|
1490
|
+
try {
|
|
1491
|
+
const axiosInstance = axios.create({
|
|
1492
|
+
baseURL: baseUrl,
|
|
1493
|
+
headers: {
|
|
1494
|
+
'Content-Type': 'application/json',
|
|
1495
|
+
...(apiKey && { Authorization: `Bearer ${apiKey}` }),
|
|
1496
|
+
},
|
|
1497
|
+
timeout: 60000, // 60 second timeout
|
|
1498
|
+
});
|
|
1499
|
+
|
|
1500
|
+
// Verify connection with simple test message
|
|
1501
|
+
const response = await axiosInstance.post<LLMResponse>('/chat/completions', {
|
|
1502
|
+
model: model,
|
|
1503
|
+
messages: [
|
|
1504
|
+
{
|
|
1505
|
+
role: 'user',
|
|
1506
|
+
content: 'test',
|
|
1507
|
+
},
|
|
1508
|
+
],
|
|
1509
|
+
max_tokens: 10,
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
const latency = Date.now() - startTime;
|
|
1513
|
+
|
|
1514
|
+
if (response.status === 200 && response.data.choices?.[0]?.message) {
|
|
1515
|
+
return { success: true, latency };
|
|
1516
|
+
} else {
|
|
1517
|
+
return { success: false, latency, error: 'Invalid response format' };
|
|
1518
|
+
}
|
|
1519
|
+
} catch (error) {
|
|
1520
|
+
const latency = Date.now() - startTime;
|
|
1521
|
+
const axiosError = error as AxiosError;
|
|
1522
|
+
|
|
1523
|
+
if (axiosError.response) {
|
|
1524
|
+
const status = axiosError.response.status;
|
|
1525
|
+
const data = axiosError.response.data as { error?: { message?: string } };
|
|
1526
|
+
const message = data?.error?.message || axiosError.message;
|
|
1527
|
+
|
|
1528
|
+
if (status === 401) {
|
|
1529
|
+
return { success: false, latency, error: 'Invalid API key.' };
|
|
1530
|
+
} else if (status === 404) {
|
|
1531
|
+
return { success: false, latency, error: 'Endpoint or model not found.' };
|
|
1532
|
+
} else {
|
|
1533
|
+
return { success: false, latency, error: `API error (${status}): ${message}` };
|
|
1534
|
+
}
|
|
1535
|
+
} else if (axiosError.request) {
|
|
1536
|
+
return { success: false, latency, error: `Network error: Cannot connect to endpoint.` };
|
|
1537
|
+
} else {
|
|
1538
|
+
return { success: false, latency, error: axiosError.message || 'Unknown error' };
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* LLMClient singleton instance
|
|
1546
|
+
* Available after ConfigManager initialization
|
|
1547
|
+
*/
|
|
1548
|
+
export function createLLMClient(): LLMClient {
|
|
1549
|
+
return new LLMClient();
|
|
1550
|
+
}
|