@travisennis/acai 0.0.9 → 0.0.11
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/README.md +51 -760
- package/bin/acai +52 -0
- package/dist/agent/index.d.ts +12 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +380 -199
- package/dist/agent/sub-agent.d.ts +23 -0
- package/dist/agent/sub-agent.d.ts.map +1 -0
- package/dist/agent/sub-agent.js +109 -0
- package/dist/cli/index.d.ts +26 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{cli.js → cli/index.js} +84 -77
- package/dist/{stdin.d.ts → cli/stdin.d.ts} +2 -1
- package/dist/cli/stdin.d.ts.map +1 -0
- package/dist/{stdin.js → cli/stdin.js} +11 -0
- package/dist/commands/copy/index.js +2 -2
- package/dist/commands/copy/utils.d.ts.map +1 -1
- package/dist/commands/copy/utils.js +15 -13
- package/dist/commands/generate-rules/index.d.ts +1 -1
- package/dist/commands/generate-rules/index.d.ts.map +1 -1
- package/dist/commands/generate-rules/index.js +16 -101
- package/dist/commands/generate-rules/service.d.ts +22 -0
- package/dist/commands/generate-rules/service.d.ts.map +1 -0
- package/dist/commands/generate-rules/service.js +103 -0
- package/dist/commands/handoff/index.js +2 -2
- package/dist/commands/health/index.js +1 -1
- package/dist/commands/health/utils.d.ts +3 -2
- package/dist/commands/health/utils.d.ts.map +1 -1
- package/dist/commands/health/utils.js +6 -0
- package/dist/commands/history/index.d.ts +1 -1
- package/dist/commands/history/index.d.ts.map +1 -1
- package/dist/commands/history/index.js +17 -18
- package/dist/commands/history/types.d.ts +38 -0
- package/dist/commands/history/types.d.ts.map +1 -1
- package/dist/commands/history/utils.d.ts.map +1 -1
- package/dist/commands/history/utils.js +63 -58
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +3 -8
- package/dist/commands/init-project/index.d.ts.map +1 -1
- package/dist/commands/init-project/index.js +3 -3
- package/dist/commands/init-project/utils.d.ts +2 -1
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +10 -2
- package/dist/commands/list-tools/index.d.ts.map +1 -1
- package/dist/commands/list-tools/index.js +7 -31
- package/dist/commands/manager.d.ts +2 -2
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +55 -33
- package/dist/commands/model/index.d.ts.map +1 -1
- package/dist/commands/model/index.js +20 -151
- package/dist/commands/model/model-panel.d.ts +4 -0
- package/dist/commands/model/model-panel.d.ts.map +1 -0
- package/dist/commands/model/model-panel.js +144 -0
- package/dist/commands/paste/index.d.ts.map +1 -1
- package/dist/commands/paste/index.js +59 -62
- package/dist/commands/paste/utils.d.ts.map +1 -1
- package/dist/commands/paste/utils.js +88 -58
- package/dist/commands/pickup/index.d.ts.map +1 -1
- package/dist/commands/pickup/index.js +6 -3
- package/dist/commands/pickup/utils.js +3 -3
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +33 -50
- package/dist/commands/review/index.d.ts.map +1 -1
- package/dist/commands/review/index.js +3 -117
- package/dist/commands/review/review-panel.d.ts +3 -0
- package/dist/commands/review/review-panel.d.ts.map +1 -0
- package/dist/commands/review/review-panel.js +186 -0
- package/dist/commands/review/utils.d.ts +15 -1
- package/dist/commands/review/utils.d.ts.map +1 -1
- package/dist/commands/review/utils.js +127 -68
- package/dist/commands/session/index.d.ts +1 -1
- package/dist/commands/session/index.d.ts.map +1 -1
- package/dist/commands/session/index.js +124 -135
- package/dist/commands/shell/index.d.ts.map +1 -1
- package/dist/commands/shell/index.js +16 -1
- package/dist/commands/types.d.ts +2 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/{config.d.ts → config/index.d.ts} +20 -9
- package/dist/config/index.d.ts.map +1 -0
- package/dist/{config.js → config/index.js} +43 -42
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +75 -55
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -141
- package/dist/middleware/cache.d.ts.map +1 -1
- package/dist/middleware/cache.js +18 -36
- package/dist/models/ai-config.d.ts +1 -0
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +4 -3
- package/dist/models/anthropic-provider.d.ts +2 -5
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -70
- package/dist/models/deepseek-provider.d.ts +1 -0
- package/dist/models/deepseek-provider.d.ts.map +1 -1
- package/dist/models/google-provider.d.ts +2 -3
- package/dist/models/google-provider.d.ts.map +1 -1
- package/dist/models/google-provider.js +0 -26
- package/dist/models/groq-provider.d.ts +1 -0
- package/dist/models/groq-provider.d.ts.map +1 -1
- package/dist/models/manager.d.ts +13 -2
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +20 -8
- package/dist/models/openai-provider.d.ts +2 -5
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +0 -52
- package/dist/models/opencode-go-provider.d.ts +25 -0
- package/dist/models/opencode-go-provider.d.ts.map +1 -0
- package/dist/models/opencode-go-provider.js +78 -0
- package/dist/models/opencode-zen-provider.d.ts +7 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +49 -10
- package/dist/models/openrouter-provider.d.ts +27 -31
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +121 -180
- package/dist/models/providers.d.ts +3 -3
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +6 -0
- package/dist/models/xai-provider.d.ts +4 -3
- package/dist/models/xai-provider.d.ts.map +1 -1
- package/dist/models/xai-provider.js +18 -18
- package/dist/modes/manager.d.ts +24 -0
- package/dist/modes/manager.d.ts.map +1 -0
- package/dist/modes/manager.js +77 -0
- package/dist/modes/prompts.d.ts +2 -0
- package/dist/modes/prompts.d.ts.map +1 -0
- package/dist/modes/prompts.js +142 -0
- package/dist/prompts/mentions.d.ts +11 -0
- package/dist/prompts/mentions.d.ts.map +1 -0
- package/dist/{mentions.js → prompts/mentions.js} +55 -85
- package/dist/{prompts.d.ts → prompts/system-prompt.d.ts} +7 -2
- package/dist/prompts/system-prompt.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/system-prompt.js} +31 -16
- package/dist/repl/index.d.ts +174 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/{repl-new.js → repl/index.js} +397 -76
- package/dist/repl/project-status.d.ts +1 -0
- package/dist/repl/project-status.d.ts.map +1 -1
- package/dist/repl/project-status.js +4 -1
- package/dist/sessions/manager.d.ts +92 -0
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +262 -9
- package/dist/sessions/summary.d.ts +4 -0
- package/dist/sessions/summary.d.ts.map +1 -0
- package/dist/sessions/summary.js +30 -0
- package/dist/skills/index.d.ts +29 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +294 -0
- package/dist/subagents/index.d.ts +16 -0
- package/dist/subagents/index.d.ts.map +1 -0
- package/dist/subagents/index.js +231 -0
- package/dist/terminal/control.d.ts +1 -1
- package/dist/terminal/control.d.ts.map +1 -1
- package/dist/terminal/control.js +3 -3
- package/dist/terminal/east-asian-width.d.ts.map +1 -1
- package/dist/terminal/east-asian-width.js +404 -351
- package/dist/terminal/keys.d.ts +17 -0
- package/dist/terminal/keys.d.ts.map +1 -1
- package/dist/terminal/keys.js +37 -0
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +24 -12
- package/dist/terminal/string-width.d.ts.map +1 -1
- package/dist/terminal/string-width.js +25 -27
- package/dist/terminal/style.d.ts.map +1 -1
- package/dist/terminal/style.js +4 -7
- package/dist/terminal/supports-color.d.ts.map +1 -1
- package/dist/terminal/supports-color.js +41 -27
- package/dist/terminal/table/cell.d.ts +12 -0
- package/dist/terminal/table/cell.d.ts.map +1 -1
- package/dist/terminal/table/cell.js +40 -25
- package/dist/terminal/table/layout-manager.d.ts.map +1 -1
- package/dist/terminal/table/layout-manager.js +100 -68
- package/dist/terminal/table/utils.d.ts +1 -1
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/table/utils.js +17 -10
- package/dist/terminal/wrap-ansi.d.ts.map +1 -1
- package/dist/terminal/wrap-ansi.js +174 -105
- package/dist/tokens/tracker.d.ts +1 -0
- package/dist/tokens/tracker.d.ts.map +1 -1
- package/dist/tokens/tracker.js +3 -0
- package/dist/tools/agent.d.ts +27 -0
- package/dist/tools/agent.d.ts.map +1 -0
- package/dist/tools/agent.js +81 -0
- package/dist/tools/apply-patch.d.ts +62 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +377 -0
- package/dist/tools/bash.d.ts +4 -3
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +349 -141
- package/dist/tools/directory-tree.d.ts +3 -3
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +8 -5
- package/dist/tools/dynamic-tool-loader.d.ts +3 -6
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +20 -4
- package/dist/tools/edit-file.d.ts +7 -7
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +292 -85
- package/dist/tools/glob.d.ts +6 -6
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +110 -63
- package/dist/tools/grep.d.ts +15 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +315 -193
- package/dist/tools/index.d.ts +114 -9
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +39 -24
- package/dist/tools/ls.d.ts +2 -2
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +7 -5
- package/dist/tools/read-file.d.ts +4 -6
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +84 -39
- package/dist/tools/save-file.d.ts +3 -3
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +36 -31
- package/dist/tools/skill.d.ts +23 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +65 -0
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +2 -9
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +12 -0
- package/dist/tools/web-fetch.d.ts +50 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +446 -0
- package/dist/tools/web-search.d.ts +44 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +226 -0
- package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
- package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/attachment-provider.js +25 -78
- package/dist/tui/autocomplete/base-provider.d.ts +1 -0
- package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
- package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.js +3 -17
- package/dist/tui/autocomplete/command-provider.d.ts +1 -0
- package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/command-provider.js +3 -0
- package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
- package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/file-search-provider.js +37 -17
- package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
- package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
- package/dist/tui/autocomplete/skill-provider.js +49 -0
- package/dist/tui/autocomplete/utils.d.ts +2 -1
- package/dist/tui/autocomplete/utils.d.ts.map +1 -1
- package/dist/tui/autocomplete/utils.js +25 -23
- package/dist/tui/autocomplete.d.ts +2 -2
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +3 -5
- package/dist/tui/components/assistant-message.d.ts.map +1 -1
- package/dist/tui/components/assistant-message.js +0 -4
- package/dist/tui/components/editor.d.ts +18 -3
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +211 -237
- package/dist/tui/components/footer.d.ts +6 -4
- package/dist/tui/components/footer.d.ts.map +1 -1
- package/dist/tui/components/footer.js +49 -25
- package/dist/tui/components/markdown.d.ts +10 -7
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +57 -39
- package/dist/tui/components/modal.d.ts.map +1 -1
- package/dist/tui/components/modal.js +35 -33
- package/dist/tui/components/notification.d.ts +13 -2
- package/dist/tui/components/notification.d.ts.map +1 -1
- package/dist/tui/components/notification.js +36 -2
- package/dist/tui/components/progress-bar.js +1 -1
- package/dist/tui/components/select-list.d.ts +1 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +14 -11
- package/dist/tui/components/text.d.ts +16 -0
- package/dist/tui/components/text.d.ts.map +1 -1
- package/dist/tui/components/text.js +72 -57
- package/dist/tui/components/thinking-block.d.ts +9 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -1
- package/dist/tui/components/thinking-block.js +43 -11
- package/dist/tui/components/tool-execution.d.ts +5 -1
- package/dist/tui/components/tool-execution.d.ts.map +1 -1
- package/dist/tui/components/tool-execution.js +19 -10
- package/dist/tui/components/user-message.d.ts.map +1 -1
- package/dist/tui/components/user-message.js +0 -3
- package/dist/tui/components/welcome.d.ts +2 -1
- package/dist/tui/components/welcome.d.ts.map +1 -1
- package/dist/tui/components/welcome.js +2 -2
- package/dist/tui/editor-launcher.d.ts +3 -2
- package/dist/tui/editor-launcher.d.ts.map +1 -1
- package/dist/tui/index.d.ts +0 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +10 -2
- package/dist/tui/tui.d.ts +43 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +166 -41
- package/dist/tui/utils.d.ts +1 -5
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +271 -44
- package/dist/utils/bash/parse.d.ts +19 -0
- package/dist/utils/bash/parse.d.ts.map +1 -0
- package/dist/utils/bash/parse.js +223 -0
- package/dist/utils/bash/quote.d.ts +6 -0
- package/dist/utils/bash/quote.d.ts.map +1 -0
- package/dist/utils/bash/quote.js +23 -0
- package/dist/utils/bash.d.ts.map +1 -1
- package/dist/utils/bash.js +211 -126
- package/dist/utils/command-protection.d.ts +28 -0
- package/dist/utils/command-protection.d.ts.map +1 -0
- package/dist/utils/command-protection.js +324 -0
- package/dist/utils/dedent.d.ts.map +1 -0
- package/dist/utils/env-expand.d.ts +2 -0
- package/dist/utils/env-expand.d.ts.map +1 -0
- package/dist/utils/env-expand.js +8 -0
- package/dist/utils/filesystem/path-display.d.ts +11 -0
- package/dist/utils/filesystem/path-display.d.ts.map +1 -0
- package/dist/utils/filesystem/path-display.js +32 -0
- package/dist/utils/filesystem/security.d.ts +2 -2
- package/dist/utils/filesystem/security.d.ts.map +1 -1
- package/dist/utils/filesystem/security.js +28 -30
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/{formatting.js → utils/formatting.js} +1 -1
- package/dist/utils/git.d.ts +4 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +30 -0
- package/dist/utils/glob.d.ts +1 -1
- package/dist/utils/glob.d.ts.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/{logger.js → utils/logger.js} +1 -1
- package/dist/utils/parsing.d.ts.map +1 -0
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +90 -37
- package/dist/utils/templates.d.ts +2 -0
- package/dist/utils/templates.d.ts.map +1 -0
- package/dist/utils/templates.js +24 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/{version.js → utils/version.js} +1 -1
- package/package.json +35 -26
- package/dist/cli.d.ts +0 -23
- package/dist/cli.d.ts.map +0 -1
- package/dist/commands/add-directory/types.d.ts +0 -6
- package/dist/commands/add-directory/types.d.ts.map +0 -1
- package/dist/commands/add-directory/types.js +0 -1
- package/dist/commands/copy/types.d.ts +0 -3
- package/dist/commands/copy/types.d.ts.map +0 -1
- package/dist/commands/copy/types.js +0 -1
- package/dist/commands/exit/index.d.ts +0 -10
- package/dist/commands/exit/index.d.ts.map +0 -1
- package/dist/commands/exit/index.js +0 -21
- package/dist/commands/exit/types.d.ts +0 -8
- package/dist/commands/exit/types.d.ts.map +0 -1
- package/dist/commands/exit/types.js +0 -1
- package/dist/commands/exit/utils.d.ts +0 -2
- package/dist/commands/exit/utils.d.ts.map +0 -1
- package/dist/commands/exit/utils.js +0 -13
- package/dist/commands/prompt/index.d.ts +0 -5
- package/dist/commands/prompt/index.d.ts.map +0 -1
- package/dist/commands/prompt/index.js +0 -122
- package/dist/commands/prompt/types.d.ts +0 -15
- package/dist/commands/prompt/types.d.ts.map +0 -1
- package/dist/commands/prompt/types.js +0 -1
- package/dist/commands/prompt/utils.d.ts +0 -12
- package/dist/commands/prompt/utils.d.ts.map +0 -1
- package/dist/commands/prompt/utils.js +0 -107
- package/dist/commands/reset/index.d.ts +0 -3
- package/dist/commands/reset/index.d.ts.map +0 -1
- package/dist/commands/reset/index.js +0 -25
- package/dist/commands/reset/types.d.ts +0 -1
- package/dist/commands/reset/types.d.ts.map +0 -1
- package/dist/commands/reset/types.js +0 -3
- package/dist/commands/review/types.d.ts +0 -12
- package/dist/commands/review/types.d.ts.map +0 -1
- package/dist/commands/review/types.js +0 -1
- package/dist/commands/save/index.d.ts +0 -3
- package/dist/commands/save/index.d.ts.map +0 -1
- package/dist/commands/save/index.js +0 -19
- package/dist/config.d.ts.map +0 -1
- package/dist/dedent.d.ts.map +0 -1
- package/dist/formatting.d.ts.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/mentions.d.ts +0 -14
- package/dist/mentions.d.ts.map +0 -1
- package/dist/parsing.d.ts.map +0 -1
- package/dist/prompts.d.ts.map +0 -1
- package/dist/repl-new.d.ts +0 -65
- package/dist/repl-new.d.ts.map +0 -1
- package/dist/skills.d.ts +0 -16
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -233
- package/dist/stdin.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.d.ts +0 -21
- package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.js +0 -164
- package/dist/utils/iterables.d.ts +0 -2
- package/dist/utils/iterables.d.ts.map +0 -1
- package/dist/utils/iterables.js +0 -6
- package/dist/version.d.ts.map +0 -1
- /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
- /package/dist/{dedent.js → utils/dedent.js} +0 -0
- /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
- /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
- /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
- /package/dist/{parsing.js → utils/parsing.js} +0 -0
- /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
package/dist/agent/index.js
CHANGED
|
@@ -1,41 +1,44 @@
|
|
|
1
|
-
import { generateText, InvalidToolInputError, NoOutputGeneratedError, NoSuchToolError, Output, streamText,
|
|
2
|
-
import { config } from "../config.js";
|
|
3
|
-
import { logger } from "../logger.js";
|
|
1
|
+
import { generateText, InvalidToolInputError, NoOutputGeneratedError, NoSuchToolError, Output, streamText, } from "ai";
|
|
4
2
|
import { AiConfig } from "../models/ai-config.js";
|
|
3
|
+
import { toAiSdkTools } from "../tools/utils.js";
|
|
4
|
+
import { logger } from "../utils/logger.js";
|
|
5
5
|
export class Agent {
|
|
6
6
|
opts;
|
|
7
|
+
config;
|
|
7
8
|
_state;
|
|
8
9
|
abortController;
|
|
9
10
|
constructor(opts) {
|
|
10
11
|
this.opts = opts;
|
|
12
|
+
this.config = opts.config;
|
|
11
13
|
this.abortController = new AbortController();
|
|
12
14
|
this._state = this.resetState();
|
|
13
15
|
}
|
|
16
|
+
setConfig(config) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
14
19
|
get state() {
|
|
15
20
|
return this._state;
|
|
16
21
|
}
|
|
17
22
|
get abortSignal() {
|
|
18
23
|
return this.abortController.signal;
|
|
19
24
|
}
|
|
25
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: will be refactored in a future task
|
|
20
26
|
async *run(args) {
|
|
21
|
-
|
|
27
|
+
yield {
|
|
28
|
+
type: "agent-start",
|
|
29
|
+
};
|
|
30
|
+
const { systemPrompt, input, tools, activeTools, abortSignal } = args;
|
|
22
31
|
this.resetState();
|
|
23
32
|
this._state.timestamps.start = performance.now();
|
|
24
|
-
const {
|
|
33
|
+
const { modelManager, sessionManager, tokenTracker } = this.opts;
|
|
34
|
+
const maxIterations = args.maxIterations ?? this.config.loop.maxIterations ?? 200;
|
|
35
|
+
const maxRetries = args.maxRetries ?? 2;
|
|
25
36
|
const langModel = modelManager.getModel("repl");
|
|
26
37
|
const modelConfig = modelManager.getModelMetadata("repl");
|
|
27
38
|
const aiConfig = new AiConfig({
|
|
28
39
|
modelMetadata: modelConfig,
|
|
29
40
|
prompt: input,
|
|
30
41
|
});
|
|
31
|
-
yield {
|
|
32
|
-
type: "agent-start",
|
|
33
|
-
};
|
|
34
|
-
yield {
|
|
35
|
-
type: "message",
|
|
36
|
-
role: "user",
|
|
37
|
-
content: input,
|
|
38
|
-
};
|
|
39
42
|
let iter = 0;
|
|
40
43
|
let consecutiveErrors = 0;
|
|
41
44
|
let hasEmittedTerminalEvent = false;
|
|
@@ -57,18 +60,18 @@ export class Agent {
|
|
|
57
60
|
if (abortSignal?.aborted) {
|
|
58
61
|
throw new Error("Agent aborted before streamText");
|
|
59
62
|
}
|
|
63
|
+
const messages = sessionManager.get();
|
|
64
|
+
const aiSdkTools = toAiSdkTools(tools, false);
|
|
60
65
|
const result = streamText({
|
|
61
66
|
model: langModel,
|
|
62
67
|
maxOutputTokens: aiConfig.maxOutputTokens(),
|
|
63
68
|
system: systemPrompt,
|
|
64
|
-
messages
|
|
69
|
+
messages,
|
|
65
70
|
temperature: aiConfig.temperature(),
|
|
66
71
|
topP: aiConfig.topP(),
|
|
67
72
|
maxRetries: 2,
|
|
68
73
|
providerOptions: aiConfig.providerOptions(),
|
|
69
|
-
tools:
|
|
70
|
-
// biome-ignore lint/suspicious/noExplicitAny: temporary
|
|
71
|
-
Object.entries(tools).map((t) => [t[0], tool(t[1].toolDef)])),
|
|
74
|
+
tools: aiSdkTools,
|
|
72
75
|
activeTools,
|
|
73
76
|
// biome-ignore lint/style/useNamingConvention: third-party controlled
|
|
74
77
|
experimental_repairToolCall: toolCallRepair(modelManager),
|
|
@@ -98,195 +101,58 @@ export class Agent {
|
|
|
98
101
|
toolCalls: thisStepToolCalls,
|
|
99
102
|
toolResults: thisStepToolResults,
|
|
100
103
|
});
|
|
101
|
-
const
|
|
104
|
+
const pendingToolCalls = [];
|
|
102
105
|
for await (const chunk of result.fullStream) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
else if (chunk.type === "reasoning-end") {
|
|
117
|
-
yield {
|
|
118
|
-
type: "thinking-end",
|
|
119
|
-
content: accumulatedReasoning,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
else if (chunk.type === "text-start") {
|
|
123
|
-
yield {
|
|
124
|
-
type: "message-start",
|
|
125
|
-
role: "assistant",
|
|
126
|
-
content: "",
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
else if (chunk.type === "text-delta") {
|
|
130
|
-
accumulatedText += chunk.text;
|
|
131
|
-
yield {
|
|
132
|
-
type: "message",
|
|
133
|
-
role: "assistant",
|
|
134
|
-
content: accumulatedText,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
else if (chunk.type === "text-end") {
|
|
138
|
-
yield {
|
|
139
|
-
type: "message-end",
|
|
140
|
-
role: "assistant",
|
|
141
|
-
content: accumulatedText,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
else if (chunk.type === "tool-call") {
|
|
145
|
-
const call = chunk;
|
|
146
|
-
const toolName = call.toolName;
|
|
147
|
-
const iTool = tools[toolName];
|
|
148
|
-
yield this.processToolEvent(toolsCalled, {
|
|
149
|
-
type: "tool-call-start",
|
|
150
|
-
name: toolName,
|
|
151
|
-
toolCallId: call.toolCallId,
|
|
152
|
-
// biome-ignore lint/suspicious/noExplicitAny: unknown
|
|
153
|
-
msg: iTool ? iTool.display(call.input) : "",
|
|
154
|
-
args: call.input,
|
|
155
|
-
});
|
|
156
|
-
if (call.invalid) {
|
|
157
|
-
yield this.processToolEvent(toolsCalled, {
|
|
158
|
-
type: "tool-call-error",
|
|
159
|
-
name: call.toolName,
|
|
160
|
-
toolCallId: call.toolCallId,
|
|
161
|
-
msg: String(call.error),
|
|
162
|
-
args: call.input,
|
|
163
|
-
});
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
let resultOutput = "Unknown result.";
|
|
167
|
-
try {
|
|
168
|
-
thisStepToolCalls.push({ toolName });
|
|
169
|
-
thisStepToolResults.push({ toolName });
|
|
170
|
-
const iTool = tools[toolName];
|
|
171
|
-
if (!iTool) {
|
|
172
|
-
resultOutput = `No executor for tool ${toolName}`;
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
// Pre-validate tool input to catch malformed JSON early
|
|
176
|
-
if (typeof call.input === "string") {
|
|
177
|
-
// If input is a string, try to validate it's proper JSON
|
|
178
|
-
try {
|
|
179
|
-
JSON.parse(call.input);
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
// Malformed JSON detected - emit error and skip execution
|
|
183
|
-
const errorMsg = `Invalid tool input: malformed JSON. Received: "${call.input.slice(0, 50)}${call.input.length > 50 ? "..." : ""}". Expected a JSON object.`;
|
|
184
|
-
yield this.processToolEvent(toolsCalled, {
|
|
185
|
-
type: "tool-call-error",
|
|
186
|
-
name: toolName,
|
|
187
|
-
toolCallId: call.toolCallId,
|
|
188
|
-
msg: errorMsg,
|
|
189
|
-
args: null,
|
|
190
|
-
});
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
else if (call.input === null || call.input === undefined) {
|
|
195
|
-
// Null/undefined input
|
|
196
|
-
const errorMsg = "Invalid tool input: received null/undefined. Expected a JSON object matching the schema.";
|
|
197
|
-
yield this.processToolEvent(toolsCalled, {
|
|
198
|
-
type: "tool-call-error",
|
|
199
|
-
name: toolName,
|
|
200
|
-
toolCallId: call.toolCallId,
|
|
201
|
-
msg: errorMsg,
|
|
202
|
-
args: null,
|
|
203
|
-
});
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
const toolExec = iTool.execute;
|
|
207
|
-
try {
|
|
208
|
-
const output = await toolExec(call.input, {
|
|
209
|
-
toolCallId: call.toolCallId,
|
|
210
|
-
messages: sessionManager.get(),
|
|
211
|
-
abortSignal,
|
|
212
|
-
});
|
|
213
|
-
resultOutput = formatToolResult(output);
|
|
214
|
-
yield this.processToolEvent(toolsCalled, {
|
|
215
|
-
type: "tool-call-end",
|
|
216
|
-
name: call.toolName,
|
|
217
|
-
toolCallId: call.toolCallId,
|
|
218
|
-
msg: resultOutput,
|
|
219
|
-
args: call.input,
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
catch (err) {
|
|
223
|
-
resultOutput = `Tool error: ${err instanceof Error ? err.message : String(err)}`;
|
|
224
|
-
yield this.processToolEvent(toolsCalled, {
|
|
225
|
-
type: "tool-call-error",
|
|
226
|
-
name: toolName,
|
|
227
|
-
toolCallId: call.toolCallId,
|
|
228
|
-
msg: resultOutput,
|
|
229
|
-
args: null,
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
catch (error) {
|
|
235
|
-
resultOutput = `Tool error: ${error instanceof Error ? error.message : String(error)}`;
|
|
236
|
-
yield this.processToolEvent(toolsCalled, {
|
|
237
|
-
type: "tool-call-error",
|
|
238
|
-
name: toolName,
|
|
239
|
-
toolCallId: call.toolCallId,
|
|
240
|
-
msg: resultOutput,
|
|
241
|
-
args: null,
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
toolMessages.push({
|
|
245
|
-
role: "tool",
|
|
246
|
-
content: [
|
|
247
|
-
{
|
|
248
|
-
type: "tool-result",
|
|
249
|
-
toolName,
|
|
250
|
-
toolCallId: call.toolCallId,
|
|
251
|
-
output: {
|
|
252
|
-
type: "text",
|
|
253
|
-
value: resultOutput,
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
],
|
|
257
|
-
});
|
|
106
|
+
const event = this.handleStreamChunk(chunk, {
|
|
107
|
+
accumulatedText,
|
|
108
|
+
accumulatedReasoning,
|
|
109
|
+
toolsCalled,
|
|
110
|
+
tools,
|
|
111
|
+
pendingToolCalls,
|
|
112
|
+
});
|
|
113
|
+
if (event) {
|
|
114
|
+
accumulatedText = event.accumulatedText;
|
|
115
|
+
accumulatedReasoning = event.accumulatedReasoning;
|
|
116
|
+
yield event.agentEvent;
|
|
258
117
|
}
|
|
259
118
|
}
|
|
119
|
+
// ============================================================
|
|
120
|
+
// PARALLEL TOOL EXECUTION
|
|
121
|
+
// ============================================================
|
|
122
|
+
const { collectedEvents, parallelToolMessages } = await this.executeToolsInParallel({
|
|
123
|
+
pendingToolCalls,
|
|
124
|
+
abortSignal,
|
|
125
|
+
toolsCalled,
|
|
126
|
+
stepToolCalls: thisStepToolCalls,
|
|
127
|
+
stepToolResults: thisStepToolResults,
|
|
128
|
+
});
|
|
129
|
+
// Yield all collected events in order
|
|
130
|
+
for (const event of collectedEvents) {
|
|
131
|
+
yield event;
|
|
132
|
+
}
|
|
260
133
|
// Get response and tool calls
|
|
261
134
|
const response = await result.response;
|
|
262
135
|
const responseMessages = response.messages;
|
|
263
|
-
|
|
136
|
+
// Filter out tool-result messages from responseMessages since we manually
|
|
137
|
+
// execute tools and add their results via appendToolMessages below.
|
|
138
|
+
// The AI SDK may include tool-result messages in response.messages even
|
|
139
|
+
// when tools don't have an execute function.
|
|
140
|
+
const nonToolMessages = responseMessages.filter((msg) => msg.role !== "tool");
|
|
141
|
+
sessionManager.appendResponseMessages(nonToolMessages);
|
|
264
142
|
const stepUsage = await result.usage;
|
|
265
|
-
this.
|
|
266
|
-
this._state.usage.outputTokens = stepUsage.outputTokens ?? 0;
|
|
267
|
-
this._state.usage.totalTokens = stepUsage.totalTokens ?? 0;
|
|
268
|
-
this._state.usage.cachedInputTokens =
|
|
269
|
-
stepUsage.inputTokenDetails.cacheReadTokens ?? 0;
|
|
270
|
-
this._state.usage.reasoningTokens =
|
|
271
|
-
stepUsage.outputTokenDetails.reasoningTokens ?? 0;
|
|
272
|
-
sessionManager.setContextWindow(stepUsage.totalTokens ?? 0);
|
|
273
|
-
this._state.totalUsage.inputTokens += stepUsage.inputTokens ?? 0;
|
|
274
|
-
this._state.totalUsage.outputTokens += stepUsage.outputTokens ?? 0;
|
|
275
|
-
this._state.totalUsage.totalTokens += stepUsage.totalTokens ?? 0;
|
|
276
|
-
this._state.totalUsage.cachedInputTokens +=
|
|
277
|
-
stepUsage.inputTokenDetails.cacheReadTokens ?? 0;
|
|
278
|
-
this._state.totalUsage.reasoningTokens +=
|
|
279
|
-
stepUsage.outputTokenDetails.reasoningTokens ?? 0;
|
|
143
|
+
this.updateUsageStats(stepUsage, sessionManager);
|
|
280
144
|
// If finishReason is not tool-calls, break
|
|
281
145
|
const finishReason = await result.finishReason;
|
|
282
146
|
if (finishReason !== "tool-calls") {
|
|
147
|
+
// Track aggregate usage before yielding agent-stop so footer can display it
|
|
148
|
+
tokenTracker.trackUsage("repl", this._state.totalUsage);
|
|
283
149
|
yield {
|
|
284
150
|
type: "agent-stop",
|
|
285
151
|
};
|
|
286
152
|
hasEmittedTerminalEvent = true;
|
|
287
153
|
break;
|
|
288
154
|
}
|
|
289
|
-
sessionManager.appendToolMessages(
|
|
155
|
+
sessionManager.appendToolMessages(parallelToolMessages);
|
|
290
156
|
// Consume the rest of the team if necessary
|
|
291
157
|
// await result.consumeStream();
|
|
292
158
|
yield {
|
|
@@ -307,8 +173,30 @@ export class Agent {
|
|
|
307
173
|
// Continue loop to allow user to provide corrected input
|
|
308
174
|
}
|
|
309
175
|
else {
|
|
310
|
-
|
|
311
|
-
|
|
176
|
+
// Extract additional error context for better debugging
|
|
177
|
+
const err = error;
|
|
178
|
+
const errorContext = {
|
|
179
|
+
modelId: modelConfig?.id ?? langModel.modelId ?? "unknown",
|
|
180
|
+
sessionId: sessionManager.getSessionId(),
|
|
181
|
+
messageCount: sessionManager.get().length,
|
|
182
|
+
attempt: consecutiveErrors,
|
|
183
|
+
maxRetries,
|
|
184
|
+
};
|
|
185
|
+
// Add response info if available (common for Bad Request errors from AI SDK)
|
|
186
|
+
if (err.cause) {
|
|
187
|
+
const cause = err.cause;
|
|
188
|
+
if (cause.response) {
|
|
189
|
+
errorContext["responseStatus"] = cause.response.status;
|
|
190
|
+
errorContext["responseStatusText"] = cause.response.statusText;
|
|
191
|
+
// Add body snippet if available (truncated to avoid log bloat)
|
|
192
|
+
if (cause.response.body &&
|
|
193
|
+
typeof cause.response.body === "object") {
|
|
194
|
+
const body = cause.response.body;
|
|
195
|
+
errorContext["responseBody"] = JSON.stringify(body).slice(0, 500);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
logger.error({ ...errorContext, error: err }, `Error on manual agent loop streamText (attempt ${consecutiveErrors}/${maxRetries + 1})`);
|
|
312
200
|
const errorMsg = error.message.length > 100
|
|
313
201
|
? `${error.message.slice(0, 100)}...`
|
|
314
202
|
: error.message;
|
|
@@ -337,12 +225,12 @@ export class Agent {
|
|
|
337
225
|
}
|
|
338
226
|
// Emit agent-stop if loop ended without emitting a terminal event (maxIterations reached)
|
|
339
227
|
if (!hasEmittedTerminalEvent) {
|
|
228
|
+
// Track aggregate usage before yielding agent-stop so footer can display it
|
|
229
|
+
tokenTracker.trackUsage("repl", this._state.totalUsage);
|
|
340
230
|
yield {
|
|
341
231
|
type: "agent-stop",
|
|
342
232
|
};
|
|
343
233
|
}
|
|
344
|
-
// Track aggregate usage across all steps when available
|
|
345
|
-
tokenTracker.trackUsage("repl", this._state.totalUsage);
|
|
346
234
|
}
|
|
347
235
|
abort() {
|
|
348
236
|
this.abortController.abort();
|
|
@@ -396,6 +284,124 @@ export class Agent {
|
|
|
396
284
|
};
|
|
397
285
|
return this._state;
|
|
398
286
|
}
|
|
287
|
+
handleStreamChunk(
|
|
288
|
+
// biome-ignore lint/suspicious/noExplicitAny: chunk type from AI SDK fullStream is a complex discriminated union
|
|
289
|
+
chunk, ctx) {
|
|
290
|
+
if (chunk.type === "reasoning-start") {
|
|
291
|
+
return {
|
|
292
|
+
agentEvent: { type: "thinking-start", content: "" },
|
|
293
|
+
accumulatedText: ctx.accumulatedText,
|
|
294
|
+
accumulatedReasoning: ctx.accumulatedReasoning,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if (chunk.type === "reasoning-delta") {
|
|
298
|
+
const accumulatedReasoning = ctx.accumulatedReasoning + chunk.text;
|
|
299
|
+
return {
|
|
300
|
+
agentEvent: { type: "thinking", content: accumulatedReasoning },
|
|
301
|
+
accumulatedText: ctx.accumulatedText,
|
|
302
|
+
accumulatedReasoning,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
if (chunk.type === "reasoning-end") {
|
|
306
|
+
return {
|
|
307
|
+
agentEvent: {
|
|
308
|
+
type: "thinking-end",
|
|
309
|
+
content: ctx.accumulatedReasoning,
|
|
310
|
+
},
|
|
311
|
+
accumulatedText: ctx.accumulatedText,
|
|
312
|
+
accumulatedReasoning: ctx.accumulatedReasoning,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
if (chunk.type === "text-start") {
|
|
316
|
+
return {
|
|
317
|
+
agentEvent: { type: "message-start", role: "assistant", content: "" },
|
|
318
|
+
accumulatedText: ctx.accumulatedText,
|
|
319
|
+
accumulatedReasoning: ctx.accumulatedReasoning,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
if (chunk.type === "text-delta") {
|
|
323
|
+
const accumulatedText = ctx.accumulatedText + chunk.text;
|
|
324
|
+
return {
|
|
325
|
+
agentEvent: {
|
|
326
|
+
type: "message",
|
|
327
|
+
role: "assistant",
|
|
328
|
+
content: accumulatedText,
|
|
329
|
+
},
|
|
330
|
+
accumulatedText,
|
|
331
|
+
accumulatedReasoning: ctx.accumulatedReasoning,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (chunk.type === "text-end") {
|
|
335
|
+
return {
|
|
336
|
+
agentEvent: {
|
|
337
|
+
type: "message-end",
|
|
338
|
+
role: "assistant",
|
|
339
|
+
content: ctx.accumulatedText,
|
|
340
|
+
},
|
|
341
|
+
accumulatedText: ctx.accumulatedText,
|
|
342
|
+
accumulatedReasoning: ctx.accumulatedReasoning,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
if (chunk.type === "tool-call") {
|
|
346
|
+
const call = chunk;
|
|
347
|
+
const toolName = call.toolName;
|
|
348
|
+
const iTool = ctx.tools[toolName];
|
|
349
|
+
const agentEvent = this.processToolEvent(ctx.toolsCalled, {
|
|
350
|
+
type: "tool-call-start",
|
|
351
|
+
name: toolName,
|
|
352
|
+
toolCallId: call.toolCallId,
|
|
353
|
+
// biome-ignore lint/suspicious/noExplicitAny: unknown
|
|
354
|
+
msg: iTool ? iTool.display(call.input) : "",
|
|
355
|
+
args: call.input,
|
|
356
|
+
});
|
|
357
|
+
ctx.pendingToolCalls.push({ call, toolName, iTool });
|
|
358
|
+
return {
|
|
359
|
+
agentEvent,
|
|
360
|
+
accumulatedText: ctx.accumulatedText,
|
|
361
|
+
accumulatedReasoning: ctx.accumulatedReasoning,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
updateUsageStats(stepUsage, sessionManager) {
|
|
367
|
+
// Extract values with null coalescing once
|
|
368
|
+
const inputTokens = stepUsage.inputTokens ?? 0;
|
|
369
|
+
const outputTokens = stepUsage.outputTokens ?? 0;
|
|
370
|
+
const totalTokens = stepUsage.totalTokens ?? 0;
|
|
371
|
+
const cacheReadTokens = stepUsage.inputTokenDetails.cacheReadTokens ?? 0;
|
|
372
|
+
const reasoningTokens = stepUsage.outputTokenDetails.reasoningTokens ?? 0;
|
|
373
|
+
// Update step usage
|
|
374
|
+
this._state.usage.inputTokens = inputTokens;
|
|
375
|
+
this._state.usage.outputTokens = outputTokens;
|
|
376
|
+
this._state.usage.totalTokens = totalTokens;
|
|
377
|
+
this._state.usage.cachedInputTokens = cacheReadTokens;
|
|
378
|
+
this._state.usage.inputTokenDetails.cacheReadTokens = cacheReadTokens;
|
|
379
|
+
this._state.usage.reasoningTokens = reasoningTokens;
|
|
380
|
+
sessionManager.setContextWindow(totalTokens);
|
|
381
|
+
// Update total usage (accumulate)
|
|
382
|
+
this._state.totalUsage.inputTokens += inputTokens;
|
|
383
|
+
this._state.totalUsage.outputTokens += outputTokens;
|
|
384
|
+
this._state.totalUsage.totalTokens += totalTokens;
|
|
385
|
+
this._state.totalUsage.cachedInputTokens += cacheReadTokens;
|
|
386
|
+
this._state.totalUsage.inputTokenDetails.cacheReadTokens += cacheReadTokens;
|
|
387
|
+
this._state.totalUsage.reasoningTokens += reasoningTokens;
|
|
388
|
+
sessionManager.recordTurnUsage({
|
|
389
|
+
inputTokens,
|
|
390
|
+
outputTokens,
|
|
391
|
+
totalTokens,
|
|
392
|
+
cachedInputTokens: cacheReadTokens,
|
|
393
|
+
reasoningTokens,
|
|
394
|
+
inputTokenDetails: {
|
|
395
|
+
noCacheTokens: stepUsage.inputTokenDetails.noCacheTokens ?? 0,
|
|
396
|
+
cacheReadTokens,
|
|
397
|
+
cacheWriteTokens: stepUsage.inputTokenDetails.cacheWriteTokens ?? 0,
|
|
398
|
+
},
|
|
399
|
+
outputTokenDetails: {
|
|
400
|
+
textTokens: stepUsage.outputTokenDetails.textTokens ?? 0,
|
|
401
|
+
reasoningTokens,
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
}
|
|
399
405
|
processToolEvent(toolsCalled, event) {
|
|
400
406
|
const toolCallId = event.toolCallId;
|
|
401
407
|
let events;
|
|
@@ -420,6 +426,172 @@ export class Agent {
|
|
|
420
426
|
events,
|
|
421
427
|
};
|
|
422
428
|
}
|
|
429
|
+
async executeToolsInParallel({ pendingToolCalls, abortSignal, toolsCalled, stepToolCalls, stepToolResults, }) {
|
|
430
|
+
const results = new Array(pendingToolCalls.length);
|
|
431
|
+
const collectedEvents = [];
|
|
432
|
+
// Phase 2a: Validate all inputs first (before any execution)
|
|
433
|
+
const validationErrors = this.validateToolInputs(pendingToolCalls);
|
|
434
|
+
// Emit validation errors and mark those tools as failed
|
|
435
|
+
for (const { index, error } of validationErrors) {
|
|
436
|
+
const { call, toolName } = pendingToolCalls[index];
|
|
437
|
+
const event = this.processToolEvent(toolsCalled, {
|
|
438
|
+
type: "tool-call-error",
|
|
439
|
+
name: toolName,
|
|
440
|
+
toolCallId: call.toolCallId,
|
|
441
|
+
msg: error,
|
|
442
|
+
args: null,
|
|
443
|
+
});
|
|
444
|
+
collectedEvents.push(event);
|
|
445
|
+
results[index] = {
|
|
446
|
+
toolCallId: call.toolCallId,
|
|
447
|
+
toolName,
|
|
448
|
+
resultOutput: error,
|
|
449
|
+
success: false,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
// Phase 2b: Execute valid tools in parallel
|
|
453
|
+
const sessionManager = this.opts.sessionManager;
|
|
454
|
+
const executionPromises = pendingToolCalls.map(async (pending, index) => {
|
|
455
|
+
if (validationErrors.some((e) => e.index === index)) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
await this.executeSingleTool({
|
|
459
|
+
pending,
|
|
460
|
+
index,
|
|
461
|
+
sessionManager,
|
|
462
|
+
abortSignal,
|
|
463
|
+
toolsCalled,
|
|
464
|
+
collectedEvents,
|
|
465
|
+
results,
|
|
466
|
+
stepToolCalls,
|
|
467
|
+
stepToolResults,
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
// Wait for all executions to complete
|
|
471
|
+
await Promise.allSettled(executionPromises);
|
|
472
|
+
// Phase 2c: Build toolMessages in original call order
|
|
473
|
+
const parallelToolMessages = this.buildToolMessages(results);
|
|
474
|
+
return { collectedEvents, parallelToolMessages };
|
|
475
|
+
}
|
|
476
|
+
validateToolInputs(pendingToolCalls) {
|
|
477
|
+
const validationErrors = [];
|
|
478
|
+
for (let i = 0; i < pendingToolCalls.length; i++) {
|
|
479
|
+
const { call } = pendingToolCalls[i];
|
|
480
|
+
// Check for invalid call from AI SDK
|
|
481
|
+
if (call.invalid) {
|
|
482
|
+
validationErrors.push({
|
|
483
|
+
index: i,
|
|
484
|
+
error: String(call.error),
|
|
485
|
+
});
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
// Validate JSON input
|
|
489
|
+
if (typeof call.input === "string") {
|
|
490
|
+
try {
|
|
491
|
+
JSON.parse(call.input);
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
validationErrors.push({
|
|
495
|
+
index: i,
|
|
496
|
+
error: `Invalid tool input: malformed JSON. Received: "${call.input.slice(0, 50)}${call.input.length > 50 ? "..." : ""}". Expected a JSON object.`,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else if (call.input === null || call.input === undefined) {
|
|
501
|
+
validationErrors.push({
|
|
502
|
+
index: i,
|
|
503
|
+
error: "Invalid tool input: received null/undefined. Expected a JSON object matching the schema.",
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return validationErrors;
|
|
508
|
+
}
|
|
509
|
+
async executeSingleTool({ pending, index, sessionManager, abortSignal, toolsCalled, collectedEvents, results, stepToolCalls, stepToolResults, }) {
|
|
510
|
+
const { call, toolName, iTool } = pending;
|
|
511
|
+
// Track in step stats
|
|
512
|
+
stepToolCalls.push({ toolName });
|
|
513
|
+
if (!iTool) {
|
|
514
|
+
const errorMsg = `No executor for tool ${toolName}`;
|
|
515
|
+
const event = this.processToolEvent(toolsCalled, {
|
|
516
|
+
type: "tool-call-error",
|
|
517
|
+
name: toolName,
|
|
518
|
+
toolCallId: call.toolCallId,
|
|
519
|
+
msg: errorMsg,
|
|
520
|
+
args: null,
|
|
521
|
+
});
|
|
522
|
+
collectedEvents.push(event);
|
|
523
|
+
results[index] = {
|
|
524
|
+
toolCallId: call.toolCallId,
|
|
525
|
+
toolName,
|
|
526
|
+
resultOutput: errorMsg,
|
|
527
|
+
success: false,
|
|
528
|
+
};
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const toolExec = iTool.execute;
|
|
532
|
+
try {
|
|
533
|
+
const output = await toolExec(call.input, {
|
|
534
|
+
toolCallId: call.toolCallId,
|
|
535
|
+
messages: sessionManager.get(),
|
|
536
|
+
abortSignal,
|
|
537
|
+
});
|
|
538
|
+
const resultOutput = formatToolResult(output);
|
|
539
|
+
const event = this.processToolEvent(toolsCalled, {
|
|
540
|
+
type: "tool-call-end",
|
|
541
|
+
name: call.toolName,
|
|
542
|
+
toolCallId: call.toolCallId,
|
|
543
|
+
msg: resultOutput,
|
|
544
|
+
args: call.input,
|
|
545
|
+
});
|
|
546
|
+
collectedEvents.push(event);
|
|
547
|
+
stepToolResults.push({ toolName });
|
|
548
|
+
results[index] = {
|
|
549
|
+
toolCallId: call.toolCallId,
|
|
550
|
+
toolName,
|
|
551
|
+
resultOutput,
|
|
552
|
+
success: true,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
catch (err) {
|
|
556
|
+
const resultOutput = `Tool error: ${err instanceof Error ? err.message : String(err)}`;
|
|
557
|
+
const event = this.processToolEvent(toolsCalled, {
|
|
558
|
+
type: "tool-call-error",
|
|
559
|
+
name: toolName,
|
|
560
|
+
toolCallId: call.toolCallId,
|
|
561
|
+
msg: resultOutput,
|
|
562
|
+
args: null,
|
|
563
|
+
});
|
|
564
|
+
collectedEvents.push(event);
|
|
565
|
+
results[index] = {
|
|
566
|
+
toolCallId: call.toolCallId,
|
|
567
|
+
toolName,
|
|
568
|
+
resultOutput,
|
|
569
|
+
success: false,
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
buildToolMessages(results) {
|
|
574
|
+
const parallelToolMessages = [];
|
|
575
|
+
for (const result of results) {
|
|
576
|
+
if (!result)
|
|
577
|
+
continue; // Skip if somehow undefined
|
|
578
|
+
parallelToolMessages.push({
|
|
579
|
+
role: "tool",
|
|
580
|
+
content: [
|
|
581
|
+
{
|
|
582
|
+
type: "tool-result",
|
|
583
|
+
toolName: result.toolName,
|
|
584
|
+
toolCallId: result.toolCallId,
|
|
585
|
+
output: {
|
|
586
|
+
type: "text",
|
|
587
|
+
value: result.resultOutput,
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
],
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
return parallelToolMessages;
|
|
594
|
+
}
|
|
423
595
|
}
|
|
424
596
|
function formatToolResult(value) {
|
|
425
597
|
if (typeof value === "string") {
|
|
@@ -450,6 +622,7 @@ const toolCallRepair = (modelManager) => {
|
|
|
450
622
|
if (NoSuchToolError.isInstance(error)) {
|
|
451
623
|
return null; // do not attempt to fix invalid tool names
|
|
452
624
|
}
|
|
625
|
+
logger.error(`Attemping to repair tool call: ${toolCall.toolName} - ${toolCall.input}`);
|
|
453
626
|
const tool = tools[toolCall.toolName];
|
|
454
627
|
try {
|
|
455
628
|
const { output: repairedArgs } = await generateText({
|
|
@@ -458,11 +631,19 @@ const toolCallRepair = (modelManager) => {
|
|
|
458
631
|
schema: tool.inputSchema,
|
|
459
632
|
}),
|
|
460
633
|
prompt: [
|
|
461
|
-
`The model tried to call the tool "${toolCall.toolName}"
|
|
462
|
-
|
|
463
|
-
"
|
|
464
|
-
JSON.stringify(
|
|
465
|
-
"
|
|
634
|
+
`The model tried to call the tool "${toolCall.toolName}" but the input did not match the expected schema.`,
|
|
635
|
+
"",
|
|
636
|
+
"<invalid_input>",
|
|
637
|
+
JSON.stringify(toolCall.input, null, 2),
|
|
638
|
+
"</invalid_input>",
|
|
639
|
+
"",
|
|
640
|
+
"<expected_schema>",
|
|
641
|
+
JSON.stringify(await inputSchema({ toolName: toolCall.toolName }), null, 2),
|
|
642
|
+
"</expected_schema>",
|
|
643
|
+
"",
|
|
644
|
+
"If any field is missing or undefined in the corrected input, you MUST explicitly set its value to null. Do NOT omit fields - every field in the schema must be present, even if with a null value.",
|
|
645
|
+
"",
|
|
646
|
+
"Return a corrected version of the input that conforms to the expected schema.",
|
|
466
647
|
].join("\n"),
|
|
467
648
|
});
|
|
468
649
|
return { ...toolCall, args: JSON.stringify(repairedArgs) };
|