@travisennis/acai 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.acai/acai.json +9 -0
- package/.acai/prompts/add-openrouter-model.md +13 -0
- package/.acai/prompts/project-status.md +4 -0
- package/.acai/prompts/update-architecture-document.md +9 -0
- package/.acai/rules/learned-rules.md +9 -0
- package/.ai/docs/available-tools.txt +3 -0
- package/.ai/docs/cognitive_complexity_refactoring_progress.md +65 -0
- package/.ai/docs/deleted_tools.md +168 -0
- package/.ai/docs/deleted_tools_88ced9ef.md +56 -0
- package/.ai/docs/image-pasting.md +46 -0
- package/.ai/docs/initialize-app.md +117 -0
- package/.ai/docs/issue-4-plan.md +44 -0
- package/.ai/docs/marked-renderer-debug.md +15 -0
- package/.ai/docs/marked-renderer-refactor-plan.md +64 -0
- package/.ai/docs/memory-use-cases.md +55 -0
- package/.ai/docs/prompt-consistency.md +31 -0
- package/.ai/docs/refactoring-tools.md +98 -0
- package/.ai/docs/system-prompt-update.md +174 -0
- package/.ai/docs/system_prompt.txt +210 -0
- package/.ai/docs/tasks.md +49 -0
- package/.ai/plan.md +131 -0
- package/.ai/prompt.md +1 -0
- package/.ai/scripts/fetch_models.js +27 -0
- package/.ai/scripts/generateSystemPrompt.ts +15 -0
- package/.ai/scripts/list-tools.mjs +4 -0
- package/.ai/scripts/p5_geometric_shapes.js +149 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +3 -0
- package/.husky/pre-push +1 -0
- package/.ignore +4 -0
- package/AGENTS.md +25 -0
- package/ARCHITECTURE.md +304 -0
- package/LICENSE +21 -0
- package/README.md +392 -0
- package/TODO.md +2 -0
- package/biome.json +61 -0
- package/commitlint.config.js +3 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +116 -0
- package/dist/commands/application-log-command.d.ts +2 -0
- package/dist/commands/application-log-command.js +43 -0
- package/dist/commands/clear-command.d.ts +2 -0
- package/dist/commands/clear-command.js +12 -0
- package/dist/commands/compact-command.d.ts +2 -0
- package/dist/commands/compact-command.js +51 -0
- package/dist/commands/copy-command.d.ts +2 -0
- package/dist/commands/copy-command.js +51 -0
- package/dist/commands/edit-command.d.ts +2 -0
- package/dist/commands/edit-command.js +53 -0
- package/dist/commands/edit-prompt-command.d.ts +2 -0
- package/dist/commands/edit-prompt-command.js +25 -0
- package/dist/commands/exit-command.d.ts +2 -0
- package/dist/commands/exit-command.js +14 -0
- package/dist/commands/files-command.d.ts +2 -0
- package/dist/commands/files-command.js +63 -0
- package/dist/commands/generate-rules-command.d.ts +2 -0
- package/dist/commands/generate-rules-command.js +61 -0
- package/dist/commands/help-command.d.ts +2 -0
- package/dist/commands/help-command.js +19 -0
- package/dist/commands/init-command.d.ts +2 -0
- package/dist/commands/init-command.js +40 -0
- package/dist/commands/last-log-command.d.ts +2 -0
- package/dist/commands/last-log-command.js +76 -0
- package/dist/commands/manager.d.ts +22 -0
- package/dist/commands/manager.js +123 -0
- package/dist/commands/model-command.d.ts +2 -0
- package/dist/commands/model-command.js +84 -0
- package/dist/commands/paste-command.d.ts +2 -0
- package/dist/commands/paste-command.js +40 -0
- package/dist/commands/prompt-command.d.ts +2 -0
- package/dist/commands/prompt-command.js +111 -0
- package/dist/commands/reset-command.d.ts +2 -0
- package/dist/commands/reset-command.js +16 -0
- package/dist/commands/rules-command.d.ts +2 -0
- package/dist/commands/rules-command.js +68 -0
- package/dist/commands/save-command.d.ts +2 -0
- package/dist/commands/save-command.js +14 -0
- package/dist/commands/types.d.ts +26 -0
- package/dist/commands/types.js +1 -0
- package/dist/commands/usage-command.d.ts +2 -0
- package/dist/commands/usage-command.js +21 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.js +193 -0
- package/dist/conversation-analyzer.d.ts +10 -0
- package/dist/conversation-analyzer.js +88 -0
- package/dist/dedent.d.ts +3 -0
- package/dist/dedent.js +38 -0
- package/dist/formatting.d.ts +17 -0
- package/dist/formatting.js +103 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +213 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +24 -0
- package/dist/mentions.d.ts +9 -0
- package/dist/mentions.js +182 -0
- package/dist/messages.d.ts +69 -0
- package/dist/messages.js +261 -0
- package/dist/middleware/audit-message.d.ts +5 -0
- package/dist/middleware/audit-message.js +95 -0
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/rate-limit.d.ts +4 -0
- package/dist/middleware/rate-limit.js +17 -0
- package/dist/models/ai-config.d.ts +12 -0
- package/dist/models/ai-config.js +87 -0
- package/dist/models/anthropic-provider.d.ts +25 -0
- package/dist/models/anthropic-provider.js +184 -0
- package/dist/models/deepseek-provider.d.ts +20 -0
- package/dist/models/deepseek-provider.js +42 -0
- package/dist/models/google-provider.d.ts +19 -0
- package/dist/models/google-provider.js +56 -0
- package/dist/models/manager.d.ts +15 -0
- package/dist/models/manager.js +48 -0
- package/dist/models/openai-provider.d.ts +22 -0
- package/dist/models/openai-provider.js +70 -0
- package/dist/models/openrouter-provider.d.ts +36 -0
- package/dist/models/openrouter-provider.js +276 -0
- package/dist/models/providers.d.ts +33 -0
- package/dist/models/providers.js +116 -0
- package/dist/models/xai-provider.d.ts +20 -0
- package/dist/models/xai-provider.js +47 -0
- package/dist/parsing.d.ts +2 -0
- package/dist/parsing.js +18 -0
- package/dist/prompts/manager.d.ts +19 -0
- package/dist/prompts/manager.js +71 -0
- package/dist/prompts.d.ts +4 -0
- package/dist/prompts.js +158 -0
- package/dist/repl-prompt.d.ts +14 -0
- package/dist/repl-prompt.js +147 -0
- package/dist/repl.d.ts +27 -0
- package/dist/repl.js +431 -0
- package/dist/source/cli.d.ts +19 -0
- package/dist/source/cli.js +116 -0
- package/dist/source/commands/application-log-command.d.ts +2 -0
- package/dist/source/commands/application-log-command.js +43 -0
- package/dist/source/commands/clear-command.d.ts +2 -0
- package/dist/source/commands/clear-command.js +12 -0
- package/dist/source/commands/compact-command.d.ts +2 -0
- package/dist/source/commands/compact-command.js +51 -0
- package/dist/source/commands/copy-command.d.ts +2 -0
- package/dist/source/commands/copy-command.js +51 -0
- package/dist/source/commands/edit-command.d.ts +2 -0
- package/dist/source/commands/edit-command.js +53 -0
- package/dist/source/commands/edit-prompt-command.d.ts +2 -0
- package/dist/source/commands/edit-prompt-command.js +25 -0
- package/dist/source/commands/exit-command.d.ts +2 -0
- package/dist/source/commands/exit-command.js +14 -0
- package/dist/source/commands/files-command.d.ts +2 -0
- package/dist/source/commands/files-command.js +63 -0
- package/dist/source/commands/generate-rules-command.d.ts +2 -0
- package/dist/source/commands/generate-rules-command.js +61 -0
- package/dist/source/commands/help-command.d.ts +2 -0
- package/dist/source/commands/help-command.js +19 -0
- package/dist/source/commands/init-command.d.ts +2 -0
- package/dist/source/commands/init-command.js +40 -0
- package/dist/source/commands/last-log-command.d.ts +2 -0
- package/dist/source/commands/last-log-command.js +76 -0
- package/dist/source/commands/manager.d.ts +22 -0
- package/dist/source/commands/manager.js +123 -0
- package/dist/source/commands/model-command.d.ts +2 -0
- package/dist/source/commands/model-command.js +84 -0
- package/dist/source/commands/paste-command.d.ts +2 -0
- package/dist/source/commands/paste-command.js +40 -0
- package/dist/source/commands/prompt-command.d.ts +2 -0
- package/dist/source/commands/prompt-command.js +111 -0
- package/dist/source/commands/reset-command.d.ts +2 -0
- package/dist/source/commands/reset-command.js +16 -0
- package/dist/source/commands/rules-command.d.ts +2 -0
- package/dist/source/commands/rules-command.js +68 -0
- package/dist/source/commands/save-command.d.ts +2 -0
- package/dist/source/commands/save-command.js +14 -0
- package/dist/source/commands/types.d.ts +26 -0
- package/dist/source/commands/types.js +1 -0
- package/dist/source/commands/usage-command.d.ts +2 -0
- package/dist/source/commands/usage-command.js +21 -0
- package/dist/source/config.d.ts +60 -0
- package/dist/source/config.js +193 -0
- package/dist/source/conversation-analyzer.d.ts +10 -0
- package/dist/source/conversation-analyzer.js +88 -0
- package/dist/source/dedent.d.ts +3 -0
- package/dist/source/dedent.js +38 -0
- package/dist/source/formatting.d.ts +17 -0
- package/dist/source/formatting.js +103 -0
- package/dist/source/index.d.ts +18 -0
- package/dist/source/index.js +213 -0
- package/dist/source/logger.d.ts +2 -0
- package/dist/source/logger.js +24 -0
- package/dist/source/mentions.d.ts +9 -0
- package/dist/source/mentions.js +182 -0
- package/dist/source/messages.d.ts +69 -0
- package/dist/source/messages.js +261 -0
- package/dist/source/middleware/audit-message.d.ts +5 -0
- package/dist/source/middleware/audit-message.js +95 -0
- package/dist/source/middleware/index.d.ts +2 -0
- package/dist/source/middleware/index.js +2 -0
- package/dist/source/middleware/rate-limit.d.ts +4 -0
- package/dist/source/middleware/rate-limit.js +17 -0
- package/dist/source/models/ai-config.d.ts +12 -0
- package/dist/source/models/ai-config.js +87 -0
- package/dist/source/models/anthropic-provider.d.ts +25 -0
- package/dist/source/models/anthropic-provider.js +184 -0
- package/dist/source/models/deepseek-provider.d.ts +20 -0
- package/dist/source/models/deepseek-provider.js +42 -0
- package/dist/source/models/google-provider.d.ts +19 -0
- package/dist/source/models/google-provider.js +56 -0
- package/dist/source/models/manager.d.ts +15 -0
- package/dist/source/models/manager.js +48 -0
- package/dist/source/models/openai-provider.d.ts +22 -0
- package/dist/source/models/openai-provider.js +70 -0
- package/dist/source/models/openrouter-provider.d.ts +36 -0
- package/dist/source/models/openrouter-provider.js +276 -0
- package/dist/source/models/providers.d.ts +33 -0
- package/dist/source/models/providers.js +116 -0
- package/dist/source/models/xai-provider.d.ts +20 -0
- package/dist/source/models/xai-provider.js +47 -0
- package/dist/source/parsing.d.ts +2 -0
- package/dist/source/parsing.js +18 -0
- package/dist/source/prompts/manager.d.ts +19 -0
- package/dist/source/prompts/manager.js +71 -0
- package/dist/source/prompts.d.ts +4 -0
- package/dist/source/prompts.js +158 -0
- package/dist/source/repl-prompt.d.ts +14 -0
- package/dist/source/repl-prompt.js +147 -0
- package/dist/source/repl.d.ts +27 -0
- package/dist/source/repl.js +431 -0
- package/dist/source/terminal/formatting.d.ts +37 -0
- package/dist/source/terminal/formatting.js +106 -0
- package/dist/source/terminal/index.d.ts +94 -0
- package/dist/source/terminal/index.js +420 -0
- package/dist/source/terminal/markdown-utils.d.ts +2 -0
- package/dist/source/terminal/markdown-utils.js +81 -0
- package/dist/source/terminal/markdown.d.ts +1 -0
- package/dist/source/terminal/markdown.js +111 -0
- package/dist/source/terminal/types.d.ts +71 -0
- package/dist/source/terminal/types.js +1 -0
- package/dist/source/terminal-output.d.ts +8 -0
- package/dist/source/terminal-output.js +213 -0
- package/dist/source/terminal-output.test.d.ts +8 -0
- package/dist/source/terminal-output.test.js +213 -0
- package/dist/source/token-tracker.d.ts +14 -0
- package/dist/source/token-tracker.js +53 -0
- package/dist/source/token-utils.d.ts +7 -0
- package/dist/source/token-utils.js +13 -0
- package/dist/source/tools/agent.d.ts +17 -0
- package/dist/source/tools/agent.js +87 -0
- package/dist/source/tools/bash.d.ts +19 -0
- package/dist/source/tools/bash.js +294 -0
- package/dist/source/tools/code-interpreter.d.ts +12 -0
- package/dist/source/tools/code-interpreter.js +131 -0
- package/dist/source/tools/command-validation.d.ts +8 -0
- package/dist/source/tools/command-validation.js +69 -0
- package/dist/source/tools/delete-file.d.ts +12 -0
- package/dist/source/tools/delete-file.js +56 -0
- package/dist/source/tools/directory-tree.d.ts +12 -0
- package/dist/source/tools/directory-tree.js +38 -0
- package/dist/source/tools/edit-file.d.ts +19 -0
- package/dist/source/tools/edit-file.js +107 -0
- package/dist/source/tools/filesystem-utils.d.ts +22 -0
- package/dist/source/tools/filesystem-utils.js +191 -0
- package/dist/source/tools/git-utils.d.ts +14 -0
- package/dist/source/tools/git-utils.js +64 -0
- package/dist/source/tools/grep.d.ts +17 -0
- package/dist/source/tools/grep.js +138 -0
- package/dist/source/tools/index.d.ts +161 -0
- package/dist/source/tools/index.js +209 -0
- package/dist/source/tools/memory-read.d.ts +13 -0
- package/dist/source/tools/memory-read.js +135 -0
- package/dist/source/tools/memory-write.d.ts +12 -0
- package/dist/source/tools/memory-write.js +83 -0
- package/dist/source/tools/move-file.d.ts +13 -0
- package/dist/source/tools/move-file.js +44 -0
- package/dist/source/tools/read-file.d.ts +17 -0
- package/dist/source/tools/read-file.js +86 -0
- package/dist/source/tools/read-multiple-files.d.ts +14 -0
- package/dist/source/tools/read-multiple-files.js +55 -0
- package/dist/source/tools/save-file.d.ts +17 -0
- package/dist/source/tools/save-file.js +98 -0
- package/dist/source/tools/think.d.ts +11 -0
- package/dist/source/tools/think.js +45 -0
- package/dist/source/tools/types.d.ts +29 -0
- package/dist/source/tools/types.js +14 -0
- package/dist/source/tools/web-fetch.d.ts +47 -0
- package/dist/source/tools/web-fetch.js +246 -0
- package/dist/source/tools/web-search.d.ts +13 -0
- package/dist/source/tools/web-search.js +80 -0
- package/dist/source/utils/process.d.ts +36 -0
- package/dist/source/utils/process.js +75 -0
- package/dist/source/version.d.ts +1 -0
- package/dist/source/version.js +21 -0
- package/dist/terminal/formatting.d.ts +37 -0
- package/dist/terminal/formatting.js +106 -0
- package/dist/terminal/index.d.ts +94 -0
- package/dist/terminal/index.js +420 -0
- package/dist/terminal/markdown-utils.d.ts +2 -0
- package/dist/terminal/markdown-utils.js +81 -0
- package/dist/terminal/markdown.d.ts +1 -0
- package/dist/terminal/markdown.js +111 -0
- package/dist/terminal/types.d.ts +71 -0
- package/dist/terminal/types.js +1 -0
- package/dist/terminal-output.d.ts +8 -0
- package/dist/terminal-output.js +213 -0
- package/dist/token-tracker.d.ts +14 -0
- package/dist/token-tracker.js +53 -0
- package/dist/token-utils.d.ts +7 -0
- package/dist/token-utils.js +13 -0
- package/dist/tools/agent.d.ts +17 -0
- package/dist/tools/agent.js +87 -0
- package/dist/tools/bash.d.ts +19 -0
- package/dist/tools/bash.js +294 -0
- package/dist/tools/code-interpreter.d.ts +12 -0
- package/dist/tools/code-interpreter.js +131 -0
- package/dist/tools/command-validation.d.ts +8 -0
- package/dist/tools/command-validation.js +69 -0
- package/dist/tools/delete-file.d.ts +12 -0
- package/dist/tools/delete-file.js +56 -0
- package/dist/tools/directory-tree.d.ts +12 -0
- package/dist/tools/directory-tree.js +38 -0
- package/dist/tools/edit-file.d.ts +19 -0
- package/dist/tools/edit-file.js +107 -0
- package/dist/tools/filesystem-utils.d.ts +22 -0
- package/dist/tools/filesystem-utils.js +191 -0
- package/dist/tools/git-utils.d.ts +14 -0
- package/dist/tools/git-utils.js +64 -0
- package/dist/tools/grep.d.ts +17 -0
- package/dist/tools/grep.js +138 -0
- package/dist/tools/index.d.ts +161 -0
- package/dist/tools/index.js +209 -0
- package/dist/tools/memory-read.d.ts +13 -0
- package/dist/tools/memory-read.js +135 -0
- package/dist/tools/memory-write.d.ts +12 -0
- package/dist/tools/memory-write.js +83 -0
- package/dist/tools/move-file.d.ts +13 -0
- package/dist/tools/move-file.js +44 -0
- package/dist/tools/read-file.d.ts +17 -0
- package/dist/tools/read-file.js +86 -0
- package/dist/tools/read-multiple-files.d.ts +14 -0
- package/dist/tools/read-multiple-files.js +55 -0
- package/dist/tools/save-file.d.ts +17 -0
- package/dist/tools/save-file.js +98 -0
- package/dist/tools/think.d.ts +11 -0
- package/dist/tools/think.js +45 -0
- package/dist/tools/types.d.ts +29 -0
- package/dist/tools/types.js +14 -0
- package/dist/tools/web-fetch.d.ts +47 -0
- package/dist/tools/web-fetch.js +246 -0
- package/dist/tools/web-search.d.ts +13 -0
- package/dist/tools/web-search.js +80 -0
- package/dist/utils/process.d.ts +36 -0
- package/dist/utils/process.js +75 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +21 -0
- package/knip.json +5 -0
- package/package.json +83 -0
- package/source/cli.ts +172 -0
- package/source/commands/application-log-command.ts +53 -0
- package/source/commands/clear-command.ts +14 -0
- package/source/commands/compact-command.ts +64 -0
- package/source/commands/copy-command.ts +55 -0
- package/source/commands/edit-command.ts +63 -0
- package/source/commands/edit-prompt-command.ts +31 -0
- package/source/commands/exit-command.ts +18 -0
- package/source/commands/files-command.ts +85 -0
- package/source/commands/generate-rules-command.ts +82 -0
- package/source/commands/help-command.ts +27 -0
- package/source/commands/init-command.ts +48 -0
- package/source/commands/last-log-command.ts +88 -0
- package/source/commands/manager.ts +151 -0
- package/source/commands/model-command.ts +123 -0
- package/source/commands/paste-command.ts +62 -0
- package/source/commands/prompt-command.ts +150 -0
- package/source/commands/reset-command.ts +22 -0
- package/source/commands/rules-command.ts +76 -0
- package/source/commands/save-command.ts +20 -0
- package/source/commands/types.ts +28 -0
- package/source/commands/usage-command.ts +26 -0
- package/source/config.ts +223 -0
- package/source/conversation-analyzer.ts +115 -0
- package/source/dedent.ts +53 -0
- package/source/formatting.ts +132 -0
- package/source/index.ts +240 -0
- package/source/logger.ts +29 -0
- package/source/mentions.ts +227 -0
- package/source/messages.ts +360 -0
- package/source/middleware/audit-message.ts +133 -0
- package/source/middleware/index.ts +2 -0
- package/source/middleware/rate-limit.ts +24 -0
- package/source/models/ai-config.ts +109 -0
- package/source/models/anthropic-provider.ts +199 -0
- package/source/models/deepseek-provider.ts +53 -0
- package/source/models/google-provider.ts +68 -0
- package/source/models/manager.ts +84 -0
- package/source/models/openai-provider.ts +81 -0
- package/source/models/openrouter-provider.ts +288 -0
- package/source/models/providers.ts +197 -0
- package/source/models/xai-provider.ts +59 -0
- package/source/parsing.ts +20 -0
- package/source/prompts/manager.ts +90 -0
- package/source/prompts.ts +172 -0
- package/source/repl-prompt.ts +196 -0
- package/source/repl.ts +572 -0
- package/source/terminal/formatting.ts +121 -0
- package/source/terminal/index.ts +518 -0
- package/source/terminal/markdown-utils.ts +89 -0
- package/source/terminal/markdown.ts +155 -0
- package/source/terminal/types.ts +84 -0
- package/source/terminal-output.test.ts +266 -0
- package/source/token-tracker.ts +78 -0
- package/source/token-utils.ts +17 -0
- package/source/tools/agent.ts +107 -0
- package/source/tools/bash.ts +367 -0
- package/source/tools/code-interpreter.ts +172 -0
- package/source/tools/command-validation.ts +81 -0
- package/source/tools/delete-file.ts +71 -0
- package/source/tools/directory-tree.ts +54 -0
- package/source/tools/edit-file.ts +155 -0
- package/source/tools/filesystem-utils.ts +265 -0
- package/source/tools/git-utils.ts +70 -0
- package/source/tools/grep.ts +184 -0
- package/source/tools/index.ts +278 -0
- package/source/tools/memory-read.ts +174 -0
- package/source/tools/memory-write.ts +105 -0
- package/source/tools/move-file.ts +59 -0
- package/source/tools/read-file.ts +129 -0
- package/source/tools/read-multiple-files.ts +80 -0
- package/source/tools/save-file.ts +147 -0
- package/source/tools/think.ts +51 -0
- package/source/tools/types.ts +58 -0
- package/source/tools/web-fetch.ts +327 -0
- package/source/tools/web-search.ts +101 -0
- package/source/utils/process.ts +121 -0
- package/source/version.ts +21 -0
- package/test/commands/copy-command.test.ts +69 -0
- package/test/config.test.ts +200 -0
- package/test/terminal/markdown-utils.test.ts +124 -0
- package/test/tools/bash-tool.test.ts +58 -0
- package/test/tools/code-interpreter.test.ts +91 -0
- package/test/tools/command-validation.test.ts +48 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +30 -0
package/dist/repl.js
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { isNumber, isRecord } from "@travisennis/stdlib/typeguards";
|
|
2
|
+
import { generateObject, NoSuchToolError, stepCountIs, streamText, } from "ai";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { config as configManager } from "./config.js";
|
|
5
|
+
import { logger } from "./logger.js";
|
|
6
|
+
import { processPrompt } from "./mentions.js";
|
|
7
|
+
import { AiConfig } from "./models/ai-config.js";
|
|
8
|
+
import { systemPrompt } from "./prompts.js";
|
|
9
|
+
import { ReplPrompt } from "./repl-prompt.js";
|
|
10
|
+
import { isMarkdown } from "./terminal/markdown-utils.js";
|
|
11
|
+
import { getCurrentBranch, getDiffStat, hasUncommittedChanges, inGitDirectory, } from "./tools/git-utils.js"; // Modified import
|
|
12
|
+
import { initAgents, initTools } from "./tools/index.js";
|
|
13
|
+
export class Repl {
|
|
14
|
+
options;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
}
|
|
18
|
+
async run() {
|
|
19
|
+
const { config, promptManager, terminal, modelManager, tokenTracker, messageHistory, commands, tokenCounter, toolEvents, autoAcceptAll, } = this.options;
|
|
20
|
+
logger.info(config, "Config:");
|
|
21
|
+
terminal.displayWelcome();
|
|
22
|
+
const promptHistory = [];
|
|
23
|
+
let currentContextWindow = 0;
|
|
24
|
+
messageHistory.on("clear-history", () => {
|
|
25
|
+
currentContextWindow = 0;
|
|
26
|
+
});
|
|
27
|
+
let prevCb = null;
|
|
28
|
+
while (true) {
|
|
29
|
+
const abortController = new AbortController();
|
|
30
|
+
const { signal } = abortController;
|
|
31
|
+
const cb = () => {
|
|
32
|
+
abortController.abort();
|
|
33
|
+
};
|
|
34
|
+
if (prevCb) {
|
|
35
|
+
process.removeListener("SIGINT", prevCb);
|
|
36
|
+
}
|
|
37
|
+
// Handle Ctrl+C (SIGINT)
|
|
38
|
+
process.on("SIGINT", cb);
|
|
39
|
+
prevCb = cb;
|
|
40
|
+
const langModel = modelManager.getModel("repl");
|
|
41
|
+
const modelConfig = modelManager.getModelMetadata("repl");
|
|
42
|
+
const currentDir = process.cwd().split("/").pop() || process.cwd();
|
|
43
|
+
const branch = await getCurrentBranch();
|
|
44
|
+
let branchDisplay = "";
|
|
45
|
+
if (branch) {
|
|
46
|
+
const hasChanges = await hasUncommittedChanges();
|
|
47
|
+
const asterisk = hasChanges ? "*" : "";
|
|
48
|
+
branchDisplay = ` ${chalk.gray(branch + asterisk)}`;
|
|
49
|
+
}
|
|
50
|
+
terminal.hr();
|
|
51
|
+
terminal.writeln(`${chalk.blue(currentDir)}${branchDisplay}`);
|
|
52
|
+
terminal.writeln(chalk.dim(langModel.modelId));
|
|
53
|
+
terminal.displayProgressBar(currentContextWindow, modelConfig.contextWindow);
|
|
54
|
+
if (!promptManager.isPending()) {
|
|
55
|
+
// For interactive input
|
|
56
|
+
const prompt = new ReplPrompt({ commands, history: promptHistory });
|
|
57
|
+
const userInput = await prompt.input();
|
|
58
|
+
prompt.close();
|
|
59
|
+
// see if the userInput contains a command
|
|
60
|
+
const commandResult = await commands.handle({ userInput });
|
|
61
|
+
if (commandResult.break) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (commandResult.continue) {
|
|
65
|
+
terminal.lineBreak();
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (!userInput.trim()) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// if there is no pending prompt then use the user's input. otherwise, the prompt was loaded from a command
|
|
72
|
+
if (!promptManager.isPending()) {
|
|
73
|
+
const processedPrompt = await processPrompt(userInput, {
|
|
74
|
+
baseDir: process.cwd(),
|
|
75
|
+
model: modelConfig,
|
|
76
|
+
});
|
|
77
|
+
for (const context of processedPrompt.context) {
|
|
78
|
+
promptManager.addContext(context);
|
|
79
|
+
}
|
|
80
|
+
promptManager.set(processedPrompt.message);
|
|
81
|
+
}
|
|
82
|
+
terminal.lineBreak();
|
|
83
|
+
}
|
|
84
|
+
// flag to see if the user prompt has added context
|
|
85
|
+
const hasAddedContext = promptManager.hasContext();
|
|
86
|
+
if (hasAddedContext) {
|
|
87
|
+
terminal.info("Context will be added to prompt.");
|
|
88
|
+
terminal.lineBreak();
|
|
89
|
+
}
|
|
90
|
+
const userPrompt = promptManager.get();
|
|
91
|
+
const userMsg = promptManager.getUserMessage();
|
|
92
|
+
messageHistory.appendUserMessage(userMsg);
|
|
93
|
+
const finalSystemPrompt = await systemPrompt({
|
|
94
|
+
supportsToolCalling: modelConfig.supportsToolCalling,
|
|
95
|
+
});
|
|
96
|
+
const aiConfig = new AiConfig({
|
|
97
|
+
modelMetadata: modelConfig,
|
|
98
|
+
prompt: userPrompt,
|
|
99
|
+
});
|
|
100
|
+
const maxTokens = aiConfig.getMaxTokens();
|
|
101
|
+
const tools = modelConfig.supportsToolCalling
|
|
102
|
+
? {
|
|
103
|
+
...(await initTools({
|
|
104
|
+
terminal,
|
|
105
|
+
tokenCounter,
|
|
106
|
+
autoAcceptAll,
|
|
107
|
+
events: toolEvents,
|
|
108
|
+
})),
|
|
109
|
+
...(await initAgents({
|
|
110
|
+
terminal,
|
|
111
|
+
modelManager,
|
|
112
|
+
tokenTracker,
|
|
113
|
+
tokenCounter,
|
|
114
|
+
events: toolEvents,
|
|
115
|
+
})),
|
|
116
|
+
}
|
|
117
|
+
: undefined;
|
|
118
|
+
try {
|
|
119
|
+
const result = streamText({
|
|
120
|
+
model: langModel,
|
|
121
|
+
maxOutputTokens: maxTokens,
|
|
122
|
+
messages: [
|
|
123
|
+
{
|
|
124
|
+
role: "system",
|
|
125
|
+
content: finalSystemPrompt,
|
|
126
|
+
providerOptions: {
|
|
127
|
+
anthropic: { cacheControl: { type: "ephemeral" } },
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
...messageHistory.get(),
|
|
131
|
+
],
|
|
132
|
+
temperature: modelConfig.defaultTemperature,
|
|
133
|
+
stopWhen: stepCountIs(60),
|
|
134
|
+
maxRetries: 2,
|
|
135
|
+
providerOptions: aiConfig.getProviderOptions(),
|
|
136
|
+
tools,
|
|
137
|
+
// biome-ignore lint/style/useNamingConvention: third-party controlled
|
|
138
|
+
experimental_repairToolCall: modelConfig.supportsToolCalling
|
|
139
|
+
? toolCallRepair(modelManager, terminal)
|
|
140
|
+
: undefined,
|
|
141
|
+
abortSignal: signal,
|
|
142
|
+
onFinish: async (result) => {
|
|
143
|
+
logger.debug("onFinish called");
|
|
144
|
+
if (result.response.messages.length > 0) {
|
|
145
|
+
messageHistory.appendResponseMessages(result.response.messages);
|
|
146
|
+
}
|
|
147
|
+
terminal.hr();
|
|
148
|
+
// Notify if configured in project config (acai.json)
|
|
149
|
+
const projectConfig = await configManager.readProjectConfig();
|
|
150
|
+
if (projectConfig.notify) {
|
|
151
|
+
terminal.alert();
|
|
152
|
+
}
|
|
153
|
+
// Create a more visual representation of steps/tool usage
|
|
154
|
+
this.displayToolUse(result, terminal);
|
|
155
|
+
if (await inGitDirectory()) {
|
|
156
|
+
// Added check
|
|
157
|
+
const stats = await getDiffStat();
|
|
158
|
+
terminal.writeln(`${chalk.dim("Files changed:")} ${chalk.yellow(stats.filesChanged)} ` +
|
|
159
|
+
`${chalk.green(`+${stats.insertions}`)} ` + // Insertions first (green)
|
|
160
|
+
`${chalk.red(`-${stats.deletions}`)}`);
|
|
161
|
+
}
|
|
162
|
+
const total = result.totalUsage ??
|
|
163
|
+
result.usage;
|
|
164
|
+
const outgoingTokens = isNumber(total.inputTokens)
|
|
165
|
+
? total.inputTokens
|
|
166
|
+
: 0;
|
|
167
|
+
const incomingTokens = isNumber(total.outputTokens)
|
|
168
|
+
? total.outputTokens
|
|
169
|
+
: 0;
|
|
170
|
+
const tokenSummary = `Tokens: ↑ ${outgoingTokens} ↓ ${incomingTokens}`;
|
|
171
|
+
terminal.writeln(chalk.dim(tokenSummary));
|
|
172
|
+
// Track aggregate usage across all steps when available
|
|
173
|
+
tokenTracker.trackUsage("repl", total);
|
|
174
|
+
// Derive current context window from final step usage
|
|
175
|
+
const finalTotalTokens = result.usage.totalTokens;
|
|
176
|
+
if (isNumber(finalTotalTokens)) {
|
|
177
|
+
currentContextWindow = finalTotalTokens ?? 0;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// Fallback: find the stopped step
|
|
181
|
+
for (const step of result.steps) {
|
|
182
|
+
if (step.finishReason === "stop") {
|
|
183
|
+
const usage = step.usage;
|
|
184
|
+
currentContextWindow = Number.isNaN(usage.totalTokens)
|
|
185
|
+
? 0
|
|
186
|
+
: (usage.totalTokens ?? 0);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// comment out auto-summarization for now. it's been causing issues.
|
|
191
|
+
// if (currentContextWindow > 70000) {
|
|
192
|
+
// logger.info(
|
|
193
|
+
// `Condensing history from ${currentContextWindow} to 0`,
|
|
194
|
+
// );
|
|
195
|
+
// await messageHistory.summarizeAndReset();
|
|
196
|
+
// }
|
|
197
|
+
terminal.hr();
|
|
198
|
+
},
|
|
199
|
+
onError: ({ error }) => {
|
|
200
|
+
logger.error(error, // Log the full error object
|
|
201
|
+
"Error on REPL streamText");
|
|
202
|
+
terminal.error(error.message.length > 100
|
|
203
|
+
? `${error.message.slice(0, 100)}...`
|
|
204
|
+
: error.message);
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
let accumulatedText = "";
|
|
208
|
+
let lastType = null;
|
|
209
|
+
for await (const chunk of result.fullStream) {
|
|
210
|
+
// Handle text-related chunks (reasoning or text-delta)
|
|
211
|
+
if (chunk.type === "reasoning-delta" || chunk.type === "text-delta") {
|
|
212
|
+
if (chunk.type === "reasoning-delta") {
|
|
213
|
+
if (lastType !== "reasoning") {
|
|
214
|
+
terminal.writeln(chalk.dim("<think>"));
|
|
215
|
+
}
|
|
216
|
+
terminal.write(chalk.dim(chunk.text)); // Stream reasoning directly
|
|
217
|
+
lastType = "reasoning";
|
|
218
|
+
}
|
|
219
|
+
else if (chunk.type === "text-delta") {
|
|
220
|
+
if (lastType === "reasoning") {
|
|
221
|
+
// Finishing reasoning: Print </think>
|
|
222
|
+
terminal.writeln(chalk.dim("\n</think>\n"));
|
|
223
|
+
}
|
|
224
|
+
accumulatedText += chunk.text;
|
|
225
|
+
lastType = "text";
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else if (chunk.type === "tool-result") {
|
|
229
|
+
const messages = toolEvents.get(chunk.toolCallId);
|
|
230
|
+
if (messages) {
|
|
231
|
+
displayToolMessages(messages, terminal);
|
|
232
|
+
toolEvents.delete(chunk.toolCallId);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
logger.warn(`No tool events found for ${chunk.toolCallId}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Close thinking tags when moving from reasoning to any other chunk type
|
|
240
|
+
if (lastType === "reasoning") {
|
|
241
|
+
terminal.write(chalk.dim("\n</think>\n\n"));
|
|
242
|
+
}
|
|
243
|
+
// if there is accumulatedText, display it
|
|
244
|
+
if (accumulatedText) {
|
|
245
|
+
terminal.writeln(`${chalk.blue.bold("●")} Response:`);
|
|
246
|
+
terminal.display(accumulatedText, true);
|
|
247
|
+
terminal.lineBreak();
|
|
248
|
+
}
|
|
249
|
+
accumulatedText = "";
|
|
250
|
+
lastType = null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Ensure the final closing tag for reasoning is written if it was the last type
|
|
254
|
+
if (lastType === "reasoning") {
|
|
255
|
+
terminal.write(chalk.gray("\n</think>\n\n"));
|
|
256
|
+
}
|
|
257
|
+
// if there is accumulatedText, display it
|
|
258
|
+
if (accumulatedText) {
|
|
259
|
+
terminal.writeln(`${chalk.green.bold("●")} Response:`);
|
|
260
|
+
terminal.display(accumulatedText, true);
|
|
261
|
+
terminal.lineBreak();
|
|
262
|
+
}
|
|
263
|
+
terminal.lineBreak(); // Add a final newline for clarity
|
|
264
|
+
await result.consumeStream();
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
if (isRecord(e) && isRecord(e["data"]) && "error" in e["data"]) {
|
|
268
|
+
terminal.error(e["data"]["error"].message);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
terminal.error(e.message.length > 100
|
|
272
|
+
? `${e.message.slice(0, 100)}...`
|
|
273
|
+
: e.message);
|
|
274
|
+
}
|
|
275
|
+
terminal.lineBreak();
|
|
276
|
+
if (e instanceof Error) {
|
|
277
|
+
logger.error(e);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
logger.error(JSON.stringify(e, null, 2));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
displayToolUse(result, terminal) {
|
|
286
|
+
const toolsCalled = [];
|
|
287
|
+
const toolColors = new Map();
|
|
288
|
+
const chalkColors = [
|
|
289
|
+
"red",
|
|
290
|
+
"green",
|
|
291
|
+
"yellow",
|
|
292
|
+
"blue",
|
|
293
|
+
"magenta",
|
|
294
|
+
"cyan",
|
|
295
|
+
"white",
|
|
296
|
+
"gray",
|
|
297
|
+
"redBright",
|
|
298
|
+
"greenBright",
|
|
299
|
+
"yellowBright",
|
|
300
|
+
"blueBright",
|
|
301
|
+
"magentaBright",
|
|
302
|
+
"cyanBright",
|
|
303
|
+
"whiteBright",
|
|
304
|
+
"blackBright",
|
|
305
|
+
];
|
|
306
|
+
terminal.writeln(chalk.dim(`Steps: ${result.steps.length}`));
|
|
307
|
+
for (const step of result.steps) {
|
|
308
|
+
let currentToolCalls = [];
|
|
309
|
+
if (step.toolResults.length > 0) {
|
|
310
|
+
currentToolCalls = step.toolResults;
|
|
311
|
+
}
|
|
312
|
+
else if (step.toolCalls.length > 0) {
|
|
313
|
+
currentToolCalls = step.toolCalls;
|
|
314
|
+
}
|
|
315
|
+
for (const toolCallOrResult of currentToolCalls) {
|
|
316
|
+
const toolName = toolCallOrResult.toolName;
|
|
317
|
+
if (!toolColors.has(toolName)) {
|
|
318
|
+
const availableColors = chalkColors.filter((color) => !Array.from(toolColors.values()).some((c) => c === chalk[color]));
|
|
319
|
+
const color = availableColors.length > 0
|
|
320
|
+
? (availableColors[Math.floor(Math.random() * availableColors.length)] ?? "white")
|
|
321
|
+
: "white";
|
|
322
|
+
toolColors.set(toolName, chalk[color]);
|
|
323
|
+
}
|
|
324
|
+
toolsCalled.push(toolName);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (toolsCalled.length > 0) {
|
|
328
|
+
terminal.writeln(chalk.dim("Tools:"));
|
|
329
|
+
for (const toolCalled of toolsCalled) {
|
|
330
|
+
const colorFn = toolColors.get(toolCalled) ?? chalk.white;
|
|
331
|
+
terminal.write(`${colorFn("██")} `);
|
|
332
|
+
}
|
|
333
|
+
terminal.lineBreak();
|
|
334
|
+
const uniqueTools = new Set(toolsCalled);
|
|
335
|
+
for (const [index, toolCalled] of Array.from(uniqueTools).entries()) {
|
|
336
|
+
const colorFn = toolColors.get(toolCalled) ?? chalk.white;
|
|
337
|
+
terminal.write(colorFn(toolCalled));
|
|
338
|
+
if (index < new Set(toolsCalled).size - 1) {
|
|
339
|
+
terminal.write(" - ");
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
terminal.lineBreak();
|
|
343
|
+
terminal.lineBreak();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function displayToolMessages(messages, terminal) {
|
|
348
|
+
const isError = messages[messages.length - 1]?.event === "tool-error";
|
|
349
|
+
const indicator = isError ? chalk.red.bold("●") : chalk.blue.bold("●");
|
|
350
|
+
const initMessage = messages.find((m) => m.event === "tool-init")?.data ?? "Tool Execution";
|
|
351
|
+
terminal.write(`${indicator} `); // Write indicator without newline (sync)
|
|
352
|
+
terminal.display(initMessage); // Display initial message (async)
|
|
353
|
+
for (const msg of messages) {
|
|
354
|
+
switch (msg.event) {
|
|
355
|
+
case "tool-update":
|
|
356
|
+
_handleToolUpdateMessage(msg.data, terminal);
|
|
357
|
+
break;
|
|
358
|
+
case "tool-completion":
|
|
359
|
+
_handleToolCompletionMessage(msg.data, terminal);
|
|
360
|
+
break;
|
|
361
|
+
case "tool-error":
|
|
362
|
+
_handleToolErrorMessage(msg.data, terminal);
|
|
363
|
+
break;
|
|
364
|
+
// 'tool-init' is handled before the loop, so no case needed here.
|
|
365
|
+
default:
|
|
366
|
+
// Optional: Log an unexpected event type for debugging, or do nothing.
|
|
367
|
+
logger.debug(`Unhandled tool message event: ${msg.event}`);
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
terminal.lineBreak();
|
|
372
|
+
}
|
|
373
|
+
// Helper function to handle tool update messages
|
|
374
|
+
function _handleToolUpdateMessage(data, terminal) {
|
|
375
|
+
if (data.secondary && data.secondary.length > 0) {
|
|
376
|
+
const content = data.secondary.join("\n");
|
|
377
|
+
if (content.trim().length !== 0) {
|
|
378
|
+
terminal.display(`└── ${data.primary}`);
|
|
379
|
+
terminal.hr();
|
|
380
|
+
if (isMarkdown(content)) {
|
|
381
|
+
terminal.display(content, true);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
terminal.write(chalk.green(content));
|
|
385
|
+
terminal.lineBreak();
|
|
386
|
+
}
|
|
387
|
+
terminal.hr();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
terminal.display(`└── ${data.primary}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// Helper function to handle tool completion messages
|
|
395
|
+
function _handleToolCompletionMessage(data, terminal) {
|
|
396
|
+
terminal.display(`└── ${data}`);
|
|
397
|
+
}
|
|
398
|
+
// Helper function to handle tool error messages
|
|
399
|
+
function _handleToolErrorMessage(data, terminal) {
|
|
400
|
+
terminal.write("└── ");
|
|
401
|
+
terminal.error(data);
|
|
402
|
+
}
|
|
403
|
+
const toolCallRepair = (modelManager, terminal) => {
|
|
404
|
+
const fn = async ({ toolCall, tools, inputSchema, error, }) => {
|
|
405
|
+
if (NoSuchToolError.isInstance(error)) {
|
|
406
|
+
return null; // do not attempt to fix invalid tool names
|
|
407
|
+
}
|
|
408
|
+
terminal.warn(`Attempting to repair tool call: ${toolCall.toolName}.`);
|
|
409
|
+
terminal.lineBreak();
|
|
410
|
+
const tool = tools[toolCall.toolName];
|
|
411
|
+
try {
|
|
412
|
+
const { object: repairedArgs } = await generateObject({
|
|
413
|
+
model: modelManager.getModel("tool-repair"),
|
|
414
|
+
schema: tool.inputSchema,
|
|
415
|
+
prompt: [
|
|
416
|
+
`The model tried to call the tool "${toolCall.toolName}" with the following arguments:`,
|
|
417
|
+
JSON.stringify(toolCall.input),
|
|
418
|
+
"The tool accepts the following schema:",
|
|
419
|
+
JSON.stringify(inputSchema(toolCall)),
|
|
420
|
+
"Please fix the arguments.",
|
|
421
|
+
].join("\n"),
|
|
422
|
+
});
|
|
423
|
+
return { ...toolCall, args: JSON.stringify(repairedArgs) };
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
logger.error(err, `Failed to repair tool call: ${toolCall.toolName}.`);
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
return fn;
|
|
431
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MessageHistory } from "./messages.ts";
|
|
2
|
+
import type { ModelManager } from "./models/manager.js";
|
|
3
|
+
import type { PromptManager } from "./prompts/manager.ts";
|
|
4
|
+
import type { TokenTracker } from "./token-tracker.ts";
|
|
5
|
+
import type { TokenCounter } from "./token-utils.ts";
|
|
6
|
+
interface CliOptions {
|
|
7
|
+
messageHistory: MessageHistory;
|
|
8
|
+
promptManager: PromptManager;
|
|
9
|
+
modelManager: ModelManager;
|
|
10
|
+
tokenTracker: TokenTracker;
|
|
11
|
+
config: Record<PropertyKey, unknown>;
|
|
12
|
+
tokenCounter: TokenCounter;
|
|
13
|
+
}
|
|
14
|
+
export declare class Cli {
|
|
15
|
+
private options;
|
|
16
|
+
constructor(options: CliOptions);
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { generateObject, generateText, NoSuchToolError, stepCountIs, } from "ai";
|
|
2
|
+
import { logger } from "./logger.js";
|
|
3
|
+
import { AiConfig } from "./models/ai-config.js";
|
|
4
|
+
import { minSystemPrompt } from "./prompts.js";
|
|
5
|
+
import { DeleteFileTool } from "./tools/delete-file.js";
|
|
6
|
+
import { EditFileTool } from "./tools/edit-file.js";
|
|
7
|
+
import { initCliTools } from "./tools/index.js";
|
|
8
|
+
import { MoveFileTool } from "./tools/move-file.js";
|
|
9
|
+
import { SaveFileTool } from "./tools/save-file.js";
|
|
10
|
+
import { ThinkTool } from "./tools/think.js";
|
|
11
|
+
export class Cli {
|
|
12
|
+
options;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
async run() {
|
|
17
|
+
const { config, promptManager, modelManager, tokenTracker, messageHistory, tokenCounter, } = this.options;
|
|
18
|
+
logger.info(config, "Config:");
|
|
19
|
+
const abortController = new AbortController();
|
|
20
|
+
const { signal } = abortController;
|
|
21
|
+
const cb = () => {
|
|
22
|
+
abortController.abort();
|
|
23
|
+
};
|
|
24
|
+
// Handle Ctrl+C (SIGINT)
|
|
25
|
+
process.on("SIGINT", cb);
|
|
26
|
+
const langModel = modelManager.getModel("cli");
|
|
27
|
+
const modelConfig = modelManager.getModelMetadata("cli");
|
|
28
|
+
const userPrompt = promptManager.get();
|
|
29
|
+
const userMsg = promptManager.getUserMessage();
|
|
30
|
+
messageHistory.appendUserMessage(userMsg);
|
|
31
|
+
const finalSystemPrompt = await minSystemPrompt();
|
|
32
|
+
const aiConfig = new AiConfig({
|
|
33
|
+
modelMetadata: modelConfig,
|
|
34
|
+
prompt: userPrompt,
|
|
35
|
+
});
|
|
36
|
+
const maxTokens = aiConfig.getMaxTokens();
|
|
37
|
+
const tools = modelConfig.supportsToolCalling
|
|
38
|
+
? await initCliTools({ tokenCounter })
|
|
39
|
+
: undefined;
|
|
40
|
+
try {
|
|
41
|
+
const result = await generateText({
|
|
42
|
+
model: langModel,
|
|
43
|
+
maxOutputTokens: maxTokens,
|
|
44
|
+
messages: [
|
|
45
|
+
{
|
|
46
|
+
role: "system",
|
|
47
|
+
content: finalSystemPrompt,
|
|
48
|
+
providerOptions: {
|
|
49
|
+
anthropic: { cacheControl: { type: "ephemeral" } },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
...messageHistory.get(),
|
|
53
|
+
],
|
|
54
|
+
temperature: modelConfig.defaultTemperature,
|
|
55
|
+
stopWhen: stepCountIs(60),
|
|
56
|
+
maxRetries: 2,
|
|
57
|
+
providerOptions: aiConfig.getProviderOptions(),
|
|
58
|
+
tools,
|
|
59
|
+
// biome-ignore lint/style/useNamingConvention: third-party controlled
|
|
60
|
+
experimental_activeTools: [
|
|
61
|
+
EditFileTool.name,
|
|
62
|
+
SaveFileTool.name,
|
|
63
|
+
MoveFileTool.name,
|
|
64
|
+
DeleteFileTool.name,
|
|
65
|
+
ThinkTool.name,
|
|
66
|
+
],
|
|
67
|
+
// biome-ignore lint/style/useNamingConvention: third-party controlled
|
|
68
|
+
experimental_repairToolCall: modelConfig.supportsToolCalling
|
|
69
|
+
? toolCallRepair(modelManager)
|
|
70
|
+
: undefined,
|
|
71
|
+
abortSignal: signal,
|
|
72
|
+
});
|
|
73
|
+
if (result.response.messages.length > 0) {
|
|
74
|
+
messageHistory.appendResponseMessages(result.response.messages);
|
|
75
|
+
}
|
|
76
|
+
// this tracks the usage of every step in the call to streamText. it's a cumulative usage.
|
|
77
|
+
tokenTracker.trackUsage("cli", result.usage);
|
|
78
|
+
process.stdout.end(result.text.endsWith("\n") ? result.text : `${result.text}\n`);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
if (e instanceof Error) {
|
|
82
|
+
logger.error(e);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
logger.error(JSON.stringify(e, null, 2));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const toolCallRepair = (modelManager) => {
|
|
91
|
+
const fn = async ({ toolCall, tools, inputSchema, error, }) => {
|
|
92
|
+
if (NoSuchToolError.isInstance(error)) {
|
|
93
|
+
return null; // do not attempt to fix invalid tool names
|
|
94
|
+
}
|
|
95
|
+
const tool = tools[toolCall.toolName];
|
|
96
|
+
try {
|
|
97
|
+
const { object: repairedArgs } = await generateObject({
|
|
98
|
+
model: modelManager.getModel("tool-repair"),
|
|
99
|
+
schema: tool.inputSchema,
|
|
100
|
+
prompt: [
|
|
101
|
+
`The model tried to call the tool "${toolCall.toolName}" with the following arguments:`,
|
|
102
|
+
JSON.stringify(toolCall.input),
|
|
103
|
+
"The tool accepts the following schema:",
|
|
104
|
+
JSON.stringify(inputSchema(toolCall)),
|
|
105
|
+
"Please fix the arguments.",
|
|
106
|
+
].join("\n"),
|
|
107
|
+
});
|
|
108
|
+
return { ...toolCall, args: JSON.stringify(repairedArgs) };
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
logger.error(err, `Failed to repair tool call: ${toolCall.toolName}.`);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
return fn;
|
|
116
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { editor } from "@inquirer/prompts";
|
|
3
|
+
import { config } from "../config.js";
|
|
4
|
+
export const applicationLogCommand = ({ terminal, }) => {
|
|
5
|
+
return {
|
|
6
|
+
command: "/application-logs",
|
|
7
|
+
description: "Opens the application log file defined in acai.json in the editor.",
|
|
8
|
+
result: "continue",
|
|
9
|
+
getSubCommands: () => Promise.resolve([]),
|
|
10
|
+
execute: async () => {
|
|
11
|
+
let logFilePath;
|
|
12
|
+
try {
|
|
13
|
+
const projectConfig = await config.readProjectConfig();
|
|
14
|
+
logFilePath = projectConfig.logs?.path;
|
|
15
|
+
if (!logFilePath) {
|
|
16
|
+
terminal.error("Application log path is not defined in .acai/acai.json under the 'logs.path' key.");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const content = await readFile(logFilePath, { encoding: "utf8" });
|
|
20
|
+
// Use the editor prompt to display the content (read-only)
|
|
21
|
+
await editor({
|
|
22
|
+
message: `Viewing ${logFilePath}`,
|
|
23
|
+
// Attempt to infer postfix from file extension, default otherwise
|
|
24
|
+
postfix: logFilePath.includes(".")
|
|
25
|
+
? `.${logFilePath.split(".").pop()}`
|
|
26
|
+
: ".log",
|
|
27
|
+
default: content,
|
|
28
|
+
// By not providing an onSubmit or similar handler to write the file,
|
|
29
|
+
// and not calling writeFileSync after, this effectively becomes read-only.
|
|
30
|
+
});
|
|
31
|
+
terminal.info(`Closed log view for: ${logFilePath}`);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (logFilePath && error.code === "ENOENT") {
|
|
35
|
+
terminal.error(`Application log file not found at: ${logFilePath}`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
terminal.error(`Error reading or displaying log file ${logFilePath ?? "specified in config"}: ${error}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const clearCommand = ({ terminal }) => {
|
|
2
|
+
return {
|
|
3
|
+
command: "/clear",
|
|
4
|
+
description: "Clears the terminal screen.",
|
|
5
|
+
result: "continue", // Keep the REPL running
|
|
6
|
+
getSubCommands: () => Promise.resolve([]),
|
|
7
|
+
execute: () => {
|
|
8
|
+
terminal.clear();
|
|
9
|
+
return Promise.resolve();
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
};
|