whale-code 6.5.5 → 6.5.6
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 +39 -31
- package/bin/{swagmanager-mcp.js → whale-code.js} +17 -2
- package/dist/cli/app.js +148 -72
- package/dist/cli/app.js.map +1 -0
- package/dist/cli/chat/AgentSelector.js +105 -10
- package/dist/cli/chat/AgentSelector.js.map +1 -0
- package/dist/cli/chat/ChatApp.d.ts +31 -0
- package/dist/cli/chat/ChatApp.js +539 -286
- package/dist/cli/chat/ChatApp.js.map +1 -0
- package/dist/cli/chat/ChatInput.js +1088 -770
- package/dist/cli/chat/ChatInput.js.map +1 -0
- package/dist/cli/chat/MarkdownText.js +39 -14
- package/dist/cli/chat/MarkdownText.js.map +1 -0
- package/dist/cli/chat/MemoryManager.js +181 -46
- package/dist/cli/chat/MemoryManager.js.map +1 -0
- package/dist/cli/chat/MessageList.d.ts +2 -3
- package/dist/cli/chat/MessageList.js +186 -45
- package/dist/cli/chat/MessageList.js.map +1 -0
- package/dist/cli/chat/ModelSelector.js +282 -63
- package/dist/cli/chat/ModelSelector.js.map +1 -0
- package/dist/cli/chat/NodeManager.js +165 -75
- package/dist/cli/chat/NodeManager.js.map +1 -0
- package/dist/cli/chat/NodeSelector.js +171 -30
- package/dist/cli/chat/NodeSelector.js.map +1 -0
- package/dist/cli/chat/PlanApproval.js +281 -57
- package/dist/cli/chat/PlanApproval.js.map +1 -0
- package/dist/cli/chat/RewindViewer.js +559 -144
- package/dist/cli/chat/RewindViewer.js.map +1 -0
- package/dist/cli/chat/SessionManager.js +137 -30
- package/dist/cli/chat/SessionManager.js.map +1 -0
- package/dist/cli/chat/SlashMenu.js +293 -164
- package/dist/cli/chat/SlashMenu.js.map +1 -0
- package/dist/cli/chat/StatusBar.js +172 -9
- package/dist/cli/chat/StatusBar.js.map +1 -0
- package/dist/cli/chat/StoreSelector.js +147 -18
- package/dist/cli/chat/StoreSelector.js.map +1 -0
- package/dist/cli/chat/StreamingText.d.ts +1 -5
- package/dist/cli/chat/StreamingText.js +22 -7
- package/dist/cli/chat/StreamingText.js.map +1 -0
- package/dist/cli/chat/SubagentPanel.d.ts +1 -2
- package/dist/cli/chat/SubagentPanel.js +612 -72
- package/dist/cli/chat/SubagentPanel.js.map +1 -0
- package/dist/cli/chat/TeamPanel.d.ts +1 -0
- package/dist/cli/chat/TeamPanel.js +230 -30
- package/dist/cli/chat/TeamPanel.js.map +1 -0
- package/dist/cli/chat/ThemeSelector.js +84 -24
- package/dist/cli/chat/ThemeSelector.js.map +1 -0
- package/dist/cli/chat/ToolIndicator.js +1476 -371
- package/dist/cli/chat/ToolIndicator.js.map +1 -0
- package/dist/cli/chat/hooks/useAgentLoop.d.ts +1 -0
- package/dist/cli/chat/hooks/useAgentLoop.js +481 -367
- package/dist/cli/chat/hooks/useAgentLoop.js.map +1 -0
- package/dist/cli/chat/hooks/useSlashCommands.d.ts +3 -14
- package/dist/cli/chat/hooks/useSlashCommands.js +744 -572
- package/dist/cli/chat/hooks/useSlashCommands.js.map +1 -0
- package/dist/cli/commands/config-cmd.js +56 -57
- package/dist/cli/commands/config-cmd.js.map +1 -0
- package/dist/cli/commands/db.js +184 -169
- package/dist/cli/commands/db.js.map +1 -0
- package/dist/cli/commands/doctor.js +212 -122
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init.js +211 -244
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/mcp.js +127 -122
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/login/LoginApp.js +355 -141
- package/dist/cli/login/LoginApp.js.map +1 -0
- package/dist/cli/print-mode.js +196 -177
- package/dist/cli/print-mode.js.map +1 -0
- package/dist/cli/serve-mode.js +615 -530
- package/dist/cli/serve-mode.js.map +1 -0
- package/dist/cli/services/agent-config.d.ts +5 -1
- package/dist/cli/services/agent-config.js +66 -36
- package/dist/cli/services/agent-config.js.map +1 -0
- package/dist/cli/services/agent-definitions.d.ts +4 -1
- package/dist/cli/services/agent-definitions.js +97 -56
- package/dist/cli/services/agent-definitions.js.map +1 -0
- package/dist/cli/services/agent-events.js +225 -162
- package/dist/cli/services/agent-events.js.map +1 -0
- package/dist/cli/services/agent-loop.js +976 -688
- package/dist/cli/services/agent-loop.js.map +1 -0
- package/dist/cli/services/agent-worker-base.d.ts +35 -5
- package/dist/cli/services/agent-worker-base.js +337 -153
- package/dist/cli/services/agent-worker-base.js.map +1 -0
- package/dist/cli/services/api-retry.js +69 -64
- package/dist/cli/services/api-retry.js.map +1 -0
- package/dist/cli/services/auth-service.d.ts +3 -3
- package/dist/cli/services/auth-service.js +209 -132
- package/dist/cli/services/auth-service.js.map +1 -0
- package/dist/cli/services/background-processes.js +343 -267
- package/dist/cli/services/background-processes.js.map +1 -0
- package/dist/cli/services/browser-auth.d.ts +2 -2
- package/dist/cli/services/browser-auth.js +159 -118
- package/dist/cli/services/browser-auth.js.map +1 -0
- package/dist/cli/services/claude-md-loader.js +40 -36
- package/dist/cli/services/claude-md-loader.js.map +1 -0
- package/dist/cli/services/config-store.d.ts +9 -4
- package/dist/cli/services/config-store.js +164 -117
- package/dist/cli/services/config-store.js.map +1 -0
- package/dist/cli/services/debug-log.d.ts +1 -1
- package/dist/cli/services/debug-log.js +34 -35
- package/dist/cli/services/debug-log.js.map +1 -0
- package/dist/cli/services/env-detect.d.ts +7 -0
- package/dist/cli/services/env-detect.js +9 -0
- package/dist/cli/services/env-detect.js.map +1 -0
- package/dist/cli/services/error-logger.js +187 -169
- package/dist/cli/services/error-logger.js.map +1 -0
- package/dist/cli/services/file-history.d.ts +1 -1
- package/dist/cli/services/file-history.js +50 -54
- package/dist/cli/services/file-history.js.map +1 -0
- package/dist/cli/services/format-server-response.js +332 -372
- package/dist/cli/services/format-server-response.js.map +1 -0
- package/dist/cli/services/git-context.js +61 -45
- package/dist/cli/services/git-context.js.map +1 -0
- package/dist/cli/services/hooks.d.ts +2 -2
- package/dist/cli/services/hooks.js +195 -180
- package/dist/cli/services/hooks.js.map +1 -0
- package/dist/cli/services/ink-incremental.d.ts +19 -0
- package/dist/cli/services/ink-incremental.js +59 -0
- package/dist/cli/services/ink-incremental.js.map +1 -0
- package/dist/cli/services/ink-resize-fix.js +54 -44
- package/dist/cli/services/ink-resize-fix.js.map +1 -0
- package/dist/cli/services/ink-sync-output.d.ts +12 -0
- package/dist/cli/services/ink-sync-output.js +16 -0
- package/dist/cli/services/ink-sync-output.js.map +1 -0
- package/dist/cli/services/interactive-tools.js +268 -212
- package/dist/cli/services/interactive-tools.js.map +1 -0
- package/dist/cli/services/keybinding-manager.d.ts +11 -1
- package/dist/cli/services/keybinding-manager.js +126 -63
- package/dist/cli/services/keybinding-manager.js.map +1 -0
- package/dist/cli/services/local-tools.d.ts +1 -1
- package/dist/cli/services/local-tools.js +939 -656
- package/dist/cli/services/local-tools.js.map +1 -0
- package/dist/cli/services/lsp-manager.js +757 -594
- package/dist/cli/services/lsp-manager.js.map +1 -0
- package/dist/cli/services/mcp-client.d.ts +1 -1
- package/dist/cli/services/mcp-client.js +173 -134
- package/dist/cli/services/mcp-client.js.map +1 -0
- package/dist/cli/services/memory-manager.js +53 -40
- package/dist/cli/services/memory-manager.js.map +1 -0
- package/dist/cli/services/model-manager.js +55 -40
- package/dist/cli/services/model-manager.js.map +1 -0
- package/dist/cli/services/model-router.js +115 -85
- package/dist/cli/services/model-router.js.map +1 -0
- package/dist/cli/services/paths.d.ts +30 -0
- package/dist/cli/services/paths.js +81 -0
- package/dist/cli/services/paths.js.map +1 -0
- package/dist/cli/services/permission-modes.js +32 -25
- package/dist/cli/services/permission-modes.js.map +1 -0
- package/dist/cli/services/rewind.js +182 -168
- package/dist/cli/services/rewind.js.map +1 -0
- package/dist/cli/services/ripgrep.js +115 -115
- package/dist/cli/services/ripgrep.js.map +1 -0
- package/dist/cli/services/sandbox.d.ts +1 -1
- package/dist/cli/services/sandbox.js +58 -37
- package/dist/cli/services/sandbox.js.map +1 -0
- package/dist/cli/services/server-tools.js +738 -565
- package/dist/cli/services/server-tools.js.map +1 -0
- package/dist/cli/services/session-persistence.js +69 -74
- package/dist/cli/services/session-persistence.js.map +1 -0
- package/dist/cli/services/subagent-worker.js +42 -27
- package/dist/cli/services/subagent-worker.js.map +1 -0
- package/dist/cli/services/subagent.d.ts +2 -0
- package/dist/cli/services/subagent.js +605 -433
- package/dist/cli/services/subagent.js.map +1 -0
- package/dist/cli/services/system-prompt.js +86 -78
- package/dist/cli/services/system-prompt.js.map +1 -0
- package/dist/cli/services/task-decomposer.d.ts +1 -1
- package/dist/cli/services/task-decomposer.js +172 -139
- package/dist/cli/services/task-decomposer.js.map +1 -0
- package/dist/cli/services/team-lead.d.ts +2 -2
- package/dist/cli/services/team-lead.js +727 -529
- package/dist/cli/services/team-lead.js.map +1 -0
- package/dist/cli/services/team-state.js +319 -319
- package/dist/cli/services/team-state.js.map +1 -0
- package/dist/cli/services/teammate.d.ts +8 -2
- package/dist/cli/services/teammate.js +857 -569
- package/dist/cli/services/teammate.js.map +1 -0
- package/dist/cli/services/telemetry.d.ts +6 -1
- package/dist/cli/services/telemetry.js +180 -157
- package/dist/cli/services/telemetry.js.map +1 -0
- package/dist/cli/services/tools/agent-tools.d.ts +3 -3
- package/dist/cli/services/tools/agent-tools.js +480 -322
- package/dist/cli/services/tools/agent-tools.js.map +1 -0
- package/dist/cli/services/tools/file-ops.js +563 -450
- package/dist/cli/services/tools/file-ops.js.map +1 -0
- package/dist/cli/services/tools/search-tools.js +231 -162
- package/dist/cli/services/tools/search-tools.js.map +1 -0
- package/dist/cli/services/tools/shell-exec.js +197 -151
- package/dist/cli/services/tools/shell-exec.js.map +1 -0
- package/dist/cli/services/tools/task-manager.js +206 -173
- package/dist/cli/services/tools/task-manager.js.map +1 -0
- package/dist/cli/services/tools/web-tools.js +388 -341
- package/dist/cli/services/tools/web-tools.js.map +1 -0
- package/dist/cli/setup/SetupApp.d.ts +2 -2
- package/dist/cli/setup/SetupApp.js +608 -160
- package/dist/cli/setup/SetupApp.js.map +1 -0
- package/dist/cli/shared/ErrorBoundary.d.ts +22 -0
- package/dist/cli/shared/ErrorBoundary.js +73 -0
- package/dist/cli/shared/ErrorBoundary.js.map +1 -0
- package/dist/cli/shared/MatrixIntro.js +66 -69
- package/dist/cli/shared/MatrixIntro.js.map +1 -0
- package/dist/cli/shared/SpinnerSlot.d.ts +14 -0
- package/dist/cli/shared/SpinnerSlot.js +63 -0
- package/dist/cli/shared/SpinnerSlot.js.map +1 -0
- package/dist/cli/shared/Theme.d.ts +1 -1
- package/dist/cli/shared/Theme.js +136 -92
- package/dist/cli/shared/Theme.js.map +1 -0
- package/dist/cli/shared/WhaleBanner.js +99 -11
- package/dist/cli/shared/WhaleBanner.js.map +1 -0
- package/dist/cli/shared/markdown.d.ts +3 -1
- package/dist/cli/shared/markdown.js +736 -674
- package/dist/cli/shared/markdown.js.map +1 -0
- package/dist/cli/shared/marked-terminal.d.js +2 -0
- package/dist/cli/shared/marked-terminal.d.js.map +1 -0
- package/dist/cli/shared/theme-manager.js +99 -90
- package/dist/cli/shared/theme-manager.js.map +1 -0
- package/dist/cli/shared/theme-presets.js +256 -254
- package/dist/cli/shared/theme-presets.js.map +1 -0
- package/dist/cli/status/StatusApp.js +235 -86
- package/dist/cli/status/StatusApp.js.map +1 -0
- package/dist/cli/stores/StoreApp.js +275 -65
- package/dist/cli/stores/StoreApp.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +509 -396
- package/dist/index.js.map +1 -0
- package/dist/local-agent/connection.d.ts +2 -2
- package/dist/local-agent/connection.js +352 -293
- package/dist/local-agent/connection.js.map +1 -0
- package/dist/local-agent/discovery.js +259 -122
- package/dist/local-agent/discovery.js.map +1 -0
- package/dist/local-agent/executor.js +216 -193
- package/dist/local-agent/executor.js.map +1 -0
- package/dist/local-agent/index.d.ts +2 -2
- package/dist/local-agent/index.js +156 -156
- package/dist/local-agent/index.js.map +1 -0
- package/dist/node/adapters/base.js +18 -8
- package/dist/node/adapters/base.js.map +1 -0
- package/dist/node/adapters/discord.js +286 -275
- package/dist/node/adapters/discord.js.map +1 -0
- package/dist/node/adapters/email.js +189 -202
- package/dist/node/adapters/email.js.map +1 -0
- package/dist/node/adapters/imessage.js +145 -142
- package/dist/node/adapters/imessage.js.map +1 -0
- package/dist/node/adapters/slack.js +237 -236
- package/dist/node/adapters/slack.js.map +1 -0
- package/dist/node/adapters/sms.js +149 -151
- package/dist/node/adapters/sms.js.map +1 -0
- package/dist/node/adapters/telegram.js +88 -92
- package/dist/node/adapters/telegram.js.map +1 -0
- package/dist/node/adapters/webchat.js +160 -136
- package/dist/node/adapters/webchat.js.map +1 -0
- package/dist/node/adapters/whatsapp.js +212 -215
- package/dist/node/adapters/whatsapp.js.map +1 -0
- package/dist/node/cli.js +884 -653
- package/dist/node/cli.js.map +1 -0
- package/dist/node/config.js +20 -18
- package/dist/node/config.js.map +1 -0
- package/dist/node/gateway-client.js +191 -181
- package/dist/node/gateway-client.js.map +1 -0
- package/dist/node/portal/clipboard.js +161 -130
- package/dist/node/portal/clipboard.js.map +1 -0
- package/dist/node/portal/discovery.js +51 -45
- package/dist/node/portal/discovery.js.map +1 -0
- package/dist/node/portal/forward.js +64 -58
- package/dist/node/portal/forward.js.map +1 -0
- package/dist/node/portal/index.js +246 -221
- package/dist/node/portal/index.js.map +1 -0
- package/dist/node/portal/multiplexer.js +192 -182
- package/dist/node/portal/multiplexer.js.map +1 -0
- package/dist/node/portal/permissions.js +102 -70
- package/dist/node/portal/permissions.js.map +1 -0
- package/dist/node/portal/protocol.js +153 -116
- package/dist/node/portal/protocol.js.map +1 -0
- package/dist/node/portal/screen.js +80 -69
- package/dist/node/portal/screen.js.map +1 -0
- package/dist/node/portal/session.js +124 -117
- package/dist/node/portal/session.js.map +1 -0
- package/dist/node/portal/shell.js +140 -113
- package/dist/node/portal/shell.js.map +1 -0
- package/dist/node/portal/stream.js +77 -75
- package/dist/node/portal/stream.js.map +1 -0
- package/dist/node/portal/transfer.js +190 -167
- package/dist/node/portal/transfer.js.map +1 -0
- package/dist/node/portal/ui.js +124 -99
- package/dist/node/portal/ui.js.map +1 -0
- package/dist/node/remote-desktop/compile-helper.js +50 -45
- package/dist/node/remote-desktop/compile-helper.js.map +1 -0
- package/dist/node/remote-desktop/index.js +215 -187
- package/dist/node/remote-desktop/index.js.map +1 -0
- package/dist/node/remote-desktop/protocol.js +45 -29
- package/dist/node/remote-desktop/protocol.js.map +1 -0
- package/dist/node/runtime.js +493 -410
- package/dist/node/runtime.js.map +1 -0
- package/dist/server/handlers/__test-utils__/test-db.js +39 -89
- package/dist/server/handlers/__test-utils__/test-db.js.map +1 -0
- package/dist/server/handlers/analytics.js +467 -261
- package/dist/server/handlers/analytics.js.map +1 -0
- package/dist/server/handlers/api-docs.js +1030 -895
- package/dist/server/handlers/api-docs.js.map +1 -0
- package/dist/server/handlers/api-keys.js +291 -242
- package/dist/server/handlers/api-keys.js.map +1 -0
- package/dist/server/handlers/billing.js +330 -239
- package/dist/server/handlers/billing.js.map +1 -0
- package/dist/server/handlers/browser.js +468 -395
- package/dist/server/handlers/browser.js.map +1 -0
- package/dist/server/handlers/catalog.js +1377 -978
- package/dist/server/handlers/catalog.js.map +1 -0
- package/dist/server/handlers/clickhouse.js +157 -109
- package/dist/server/handlers/clickhouse.js.map +1 -0
- package/dist/server/handlers/comms.js +1439 -984
- package/dist/server/handlers/comms.js.map +1 -0
- package/dist/server/handlers/creations.js +461 -394
- package/dist/server/handlers/creations.js.map +1 -0
- package/dist/server/handlers/crm.js +1082 -791
- package/dist/server/handlers/crm.js.map +1 -0
- package/dist/server/handlers/discovery.js +251 -232
- package/dist/server/handlers/discovery.js.map +1 -0
- package/dist/server/handlers/embeddings.js +241 -164
- package/dist/server/handlers/embeddings.js.map +1 -0
- package/dist/server/handlers/enrichment.js +887 -718
- package/dist/server/handlers/enrichment.js.map +1 -0
- package/dist/server/handlers/image-gen.js +467 -376
- package/dist/server/handlers/image-gen.js.map +1 -0
- package/dist/server/handlers/inventory.js +797 -424
- package/dist/server/handlers/inventory.js.map +1 -0
- package/dist/server/handlers/kali.js +272 -230
- package/dist/server/handlers/kali.js.map +1 -0
- package/dist/server/handlers/llm-providers.js +803 -580
- package/dist/server/handlers/llm-providers.js.map +1 -0
- package/dist/server/handlers/local-agent.js +133 -105
- package/dist/server/handlers/local-agent.js.map +1 -0
- package/dist/server/handlers/media.js +1179 -857
- package/dist/server/handlers/media.js.map +1 -0
- package/dist/server/handlers/meta-ads.js +2669 -2093
- package/dist/server/handlers/meta-ads.js.map +1 -0
- package/dist/server/handlers/nodes.js +1321 -913
- package/dist/server/handlers/nodes.js.map +1 -0
- package/dist/server/handlers/operations.js +183 -157
- package/dist/server/handlers/operations.js.map +1 -0
- package/dist/server/handlers/platform.js +346 -210
- package/dist/server/handlers/platform.js.map +1 -0
- package/dist/server/handlers/remove-bg.js +118 -86
- package/dist/server/handlers/remove-bg.js.map +1 -0
- package/dist/server/handlers/storefront.js +586 -446
- package/dist/server/handlers/storefront.js.map +1 -0
- package/dist/server/handlers/supply-chain.js +546 -326
- package/dist/server/handlers/supply-chain.js.map +1 -0
- package/dist/server/handlers/transcription.js +106 -97
- package/dist/server/handlers/transcription.js.map +1 -0
- package/dist/server/handlers/video-gen.js +593 -424
- package/dist/server/handlers/video-gen.js.map +1 -0
- package/dist/server/handlers/voice.js +1458 -1039
- package/dist/server/handlers/voice.js.map +1 -0
- package/dist/server/handlers/workflow-steps.js +2837 -2116
- package/dist/server/handlers/workflow-steps.js.map +1 -0
- package/dist/server/handlers/workflows.js +1630 -933
- package/dist/server/handlers/workflows.js.map +1 -0
- package/dist/server/index.js +3167 -2422
- package/dist/server/index.js.map +1 -0
- package/dist/server/lib/batch-client.js +471 -409
- package/dist/server/lib/batch-client.js.map +1 -0
- package/dist/server/lib/clickhouse-buffer.js +118 -104
- package/dist/server/lib/clickhouse-buffer.js.map +1 -0
- package/dist/server/lib/clickhouse-client.js +107 -107
- package/dist/server/lib/clickhouse-client.js.map +1 -0
- package/dist/server/lib/coa-renderer.js +1786 -356
- package/dist/server/lib/coa-renderer.js.map +1 -0
- package/dist/server/lib/code-worker-pool.js +227 -177
- package/dist/server/lib/code-worker-pool.js.map +1 -0
- package/dist/server/lib/code-worker.js +174 -164
- package/dist/server/lib/code-worker.js.map +1 -0
- package/dist/server/lib/compaction-service.d.ts +2 -12
- package/dist/server/lib/compaction-service.js +74 -184
- package/dist/server/lib/compaction-service.js.map +1 -0
- package/dist/server/lib/logger.js +36 -24
- package/dist/server/lib/logger.js.map +1 -0
- package/dist/server/lib/otel.js +101 -80
- package/dist/server/lib/otel.js.map +1 -0
- package/dist/server/lib/pdf-renderer.js +952 -788
- package/dist/server/lib/pdf-renderer.js.map +1 -0
- package/dist/server/lib/prompt-sanitizer.js +188 -108
- package/dist/server/lib/prompt-sanitizer.js.map +1 -0
- package/dist/server/lib/provider-capabilities.js +136 -138
- package/dist/server/lib/provider-capabilities.js.map +1 -0
- package/dist/server/lib/provider-failover.js +190 -168
- package/dist/server/lib/provider-failover.js.map +1 -0
- package/dist/server/lib/rate-limiter.js +186 -117
- package/dist/server/lib/rate-limiter.js.map +1 -0
- package/dist/server/lib/react-pdf-layout.js +551 -382
- package/dist/server/lib/react-pdf-layout.js.map +1 -0
- package/dist/server/lib/server-agent-loop.d.ts +4 -1
- package/dist/server/lib/server-agent-loop.js +906 -634
- package/dist/server/lib/server-agent-loop.js.map +1 -0
- package/dist/server/lib/server-subagent.js +260 -164
- package/dist/server/lib/server-subagent.js.map +1 -0
- package/dist/server/lib/session-checkpoint.js +105 -96
- package/dist/server/lib/session-checkpoint.js.map +1 -0
- package/dist/server/lib/ssrf-guard.js +193 -184
- package/dist/server/lib/ssrf-guard.js.map +1 -0
- package/dist/server/lib/supabase-client.js +94 -82
- package/dist/server/lib/supabase-client.js.map +1 -0
- package/dist/server/lib/template-resolver.js +154 -176
- package/dist/server/lib/template-resolver.js.map +1 -0
- package/dist/server/lib/utils.js +242 -133
- package/dist/server/lib/utils.js.map +1 -0
- package/dist/server/local-agent-gateway.d.ts +2 -2
- package/dist/server/local-agent-gateway.js +785 -627
- package/dist/server/local-agent-gateway.js.map +1 -0
- package/dist/server/providers/anthropic.js +250 -172
- package/dist/server/providers/anthropic.js.map +1 -0
- package/dist/server/providers/bedrock.js +217 -158
- package/dist/server/providers/bedrock.js.map +1 -0
- package/dist/server/providers/gemini.js +548 -418
- package/dist/server/providers/gemini.js.map +1 -0
- package/dist/server/providers/openai.js +571 -437
- package/dist/server/providers/openai.js.map +1 -0
- package/dist/server/providers/registry.js +23 -18
- package/dist/server/providers/registry.js.map +1 -0
- package/dist/server/providers/shared.js +123 -95
- package/dist/server/providers/shared.js.map +1 -0
- package/dist/server/providers/types.js +1 -11
- package/dist/server/providers/types.js.map +1 -0
- package/dist/server/proxy-handlers.js +209 -165
- package/dist/server/proxy-handlers.js.map +1 -0
- package/dist/server/tool-router.js +959 -599
- package/dist/server/tool-router.js.map +1 -0
- package/dist/server/validation.js +248 -188
- package/dist/server/validation.js.map +1 -0
- package/dist/server/worker.js +202 -133
- package/dist/server/worker.js.map +1 -0
- package/dist/setup.d.ts +2 -2
- package/dist/setup.js +151 -147
- package/dist/setup.js.map +1 -0
- package/dist/shared/agent-core.d.ts +115 -26
- package/dist/shared/agent-core.js +956 -522
- package/dist/shared/agent-core.js.map +1 -0
- package/dist/shared/anthropic-types.js +1 -6
- package/dist/shared/anthropic-types.js.map +1 -0
- package/dist/shared/api-client.d.ts +16 -9
- package/dist/shared/api-client.js +419 -327
- package/dist/shared/api-client.js.map +1 -0
- package/dist/shared/compaction.d.ts +36 -0
- package/dist/shared/compaction.js +138 -0
- package/dist/shared/compaction.js.map +1 -0
- package/dist/shared/constants.js +67 -64
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/sse-parser.js +221 -219
- package/dist/shared/sse-parser.js.map +1 -0
- package/dist/shared/tool-dispatch.d.ts +4 -0
- package/dist/shared/tool-dispatch.js +226 -165
- package/dist/shared/tool-dispatch.js.map +1 -0
- package/dist/shared/types.js +1 -6
- package/dist/shared/types.js.map +1 -0
- package/dist/types/cli-highlight.d.js +2 -0
- package/dist/types/cli-highlight.d.js.map +1 -0
- package/dist/types/diff.d.js +2 -0
- package/dist/types/diff.d.js.map +1 -0
- package/dist/types/pdf-parse.d.js +2 -0
- package/dist/types/pdf-parse.d.js.map +1 -0
- package/dist/updater.d.ts +1 -1
- package/dist/updater.js +118 -92
- package/dist/updater.js.map +1 -0
- package/dist/webchat/widget.js +227 -380
- package/dist/webchat/widget.js.map +1 -0
- package/package.json +22 -10
- package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
- package/vendor/ink/build/ansi-tokenizer.js +316 -0
- package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
- package/vendor/ink/build/apply-styles.js +175 -0
- package/vendor/ink/build/build-layout.js +77 -0
- package/vendor/ink/build/calculate-wrapped-text.js +53 -0
- package/vendor/ink/build/colorize.d.ts +3 -0
- package/vendor/ink/build/colorize.js +48 -0
- package/vendor/ink/build/colorize.js.map +1 -0
- package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
- package/vendor/ink/build/components/AccessibilityContext.js +5 -0
- package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
- package/vendor/ink/build/components/App.d.ts +18 -0
- package/vendor/ink/build/components/App.js +351 -0
- package/vendor/ink/build/components/App.js.map +1 -0
- package/vendor/ink/build/components/AppContext.d.ts +15 -0
- package/vendor/ink/build/components/AppContext.js +11 -0
- package/vendor/ink/build/components/AppContext.js.map +1 -0
- package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
- package/vendor/ink/build/components/BackgroundContext.js +3 -0
- package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
- package/vendor/ink/build/components/Box.d.ts +117 -0
- package/vendor/ink/build/components/Box.js +34 -0
- package/vendor/ink/build/components/Box.js.map +1 -0
- package/vendor/ink/build/components/Color.js +62 -0
- package/vendor/ink/build/components/Cursor.d.ts +83 -0
- package/vendor/ink/build/components/Cursor.js +53 -0
- package/vendor/ink/build/components/Cursor.js.map +1 -0
- package/vendor/ink/build/components/CursorContext.d.ts +11 -0
- package/vendor/ink/build/components/CursorContext.js +8 -0
- package/vendor/ink/build/components/CursorContext.js.map +1 -0
- package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
- package/vendor/ink/build/components/ErrorBoundary.js +23 -0
- package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
- package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
- package/vendor/ink/build/components/ErrorOverview.js +84 -0
- package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
- package/vendor/ink/build/components/FocusContext.d.ts +16 -0
- package/vendor/ink/build/components/FocusContext.js +17 -0
- package/vendor/ink/build/components/FocusContext.js.map +1 -0
- package/vendor/ink/build/components/Newline.d.ts +13 -0
- package/vendor/ink/build/components/Newline.js +8 -0
- package/vendor/ink/build/components/Newline.js.map +1 -0
- package/vendor/ink/build/components/Spacer.d.ts +7 -0
- package/vendor/ink/build/components/Spacer.js +11 -0
- package/vendor/ink/build/components/Spacer.js.map +1 -0
- package/vendor/ink/build/components/Static.d.ts +24 -0
- package/vendor/ink/build/components/Static.js +28 -0
- package/vendor/ink/build/components/Static.js.map +1 -0
- package/vendor/ink/build/components/StderrContext.d.ts +15 -0
- package/vendor/ink/build/components/StderrContext.js +13 -0
- package/vendor/ink/build/components/StderrContext.js.map +1 -0
- package/vendor/ink/build/components/StdinContext.d.ts +22 -0
- package/vendor/ink/build/components/StdinContext.js +19 -0
- package/vendor/ink/build/components/StdinContext.js.map +1 -0
- package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
- package/vendor/ink/build/components/StdoutContext.js +13 -0
- package/vendor/ink/build/components/StdoutContext.js.map +1 -0
- package/vendor/ink/build/components/Text.d.ts +55 -0
- package/vendor/ink/build/components/Text.js +50 -0
- package/vendor/ink/build/components/Text.js.map +1 -0
- package/vendor/ink/build/components/Transform.d.ts +16 -0
- package/vendor/ink/build/components/Transform.js +15 -0
- package/vendor/ink/build/components/Transform.js.map +1 -0
- package/vendor/ink/build/cursor-helpers.d.ts +38 -0
- package/vendor/ink/build/cursor-helpers.js +56 -0
- package/vendor/ink/build/cursor-helpers.js.map +1 -0
- package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
- package/vendor/ink/build/devtools-window-polyfill.js +65 -0
- package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
- package/vendor/ink/build/devtools.d.ts +1 -0
- package/vendor/ink/build/devtools.js +11 -0
- package/vendor/ink/build/devtools.js.map +1 -0
- package/vendor/ink/build/dom.d.ts +56 -0
- package/vendor/ink/build/dom.js +124 -0
- package/vendor/ink/build/dom.js.map +1 -0
- package/vendor/ink/build/experimental/apply-style.js +140 -0
- package/vendor/ink/build/experimental/dom.js +123 -0
- package/vendor/ink/build/experimental/output.js +91 -0
- package/vendor/ink/build/experimental/reconciler.js +141 -0
- package/vendor/ink/build/experimental/renderer.js +81 -0
- package/vendor/ink/build/get-max-width.d.ts +3 -0
- package/vendor/ink/build/get-max-width.js +10 -0
- package/vendor/ink/build/get-max-width.js.map +1 -0
- package/vendor/ink/build/hooks/use-app.d.ts +5 -0
- package/vendor/ink/build/hooks/use-app.js +8 -0
- package/vendor/ink/build/hooks/use-app.js.map +1 -0
- package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
- package/vendor/ink/build/hooks/use-cursor.js +29 -0
- package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
- package/vendor/ink/build/hooks/use-focus-manager.d.ts +28 -0
- package/vendor/ink/build/hooks/use-focus-manager.js +17 -0
- package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
- package/vendor/ink/build/hooks/use-focus.d.ts +29 -0
- package/vendor/ink/build/hooks/use-focus.js +42 -0
- package/vendor/ink/build/hooks/use-focus.js.map +1 -0
- package/vendor/ink/build/hooks/use-input.d.ts +131 -0
- package/vendor/ink/build/hooks/use-input.js +124 -0
- package/vendor/ink/build/hooks/use-input.js.map +1 -0
- package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +5 -0
- package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +11 -0
- package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
- package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
- package/vendor/ink/build/hooks/use-stderr.js +8 -0
- package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
- package/vendor/ink/build/hooks/use-stdin.d.ts +5 -0
- package/vendor/ink/build/hooks/use-stdin.js +8 -0
- package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
- package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
- package/vendor/ink/build/hooks/use-stdout.js +8 -0
- package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
- package/vendor/ink/build/hooks/useInput.js +38 -0
- package/vendor/ink/build/index.d.ts +34 -0
- package/vendor/ink/build/index.js +20 -0
- package/vendor/ink/build/index.js.map +1 -0
- package/vendor/ink/build/ink.d.ts +90 -0
- package/vendor/ink/build/ink.js +654 -0
- package/vendor/ink/build/ink.js.map +1 -0
- package/vendor/ink/build/input-parser.d.ts +7 -0
- package/vendor/ink/build/input-parser.js +154 -0
- package/vendor/ink/build/input-parser.js.map +1 -0
- package/vendor/ink/build/instance.js +205 -0
- package/vendor/ink/build/instances.d.ts +3 -0
- package/vendor/ink/build/instances.js +8 -0
- package/vendor/ink/build/instances.js.map +1 -0
- package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
- package/vendor/ink/build/kitty-keyboard.js +32 -0
- package/vendor/ink/build/kitty-keyboard.js.map +1 -0
- package/vendor/ink/build/layout.d.ts +7 -0
- package/vendor/ink/build/layout.js +33 -0
- package/vendor/ink/build/layout.js.map +1 -0
- package/vendor/ink/build/log-update.d.ts +19 -0
- package/vendor/ink/build/log-update.js +243 -0
- package/vendor/ink/build/log-update.js.map +1 -0
- package/vendor/ink/build/measure-element.d.ts +16 -0
- package/vendor/ink/build/measure-element.js +9 -0
- package/vendor/ink/build/measure-element.js.map +1 -0
- package/vendor/ink/build/measure-text.d.ts +6 -0
- package/vendor/ink/build/measure-text.js +21 -0
- package/vendor/ink/build/measure-text.js.map +1 -0
- package/vendor/ink/build/options.d.ts +52 -0
- package/vendor/ink/build/options.js +2 -0
- package/vendor/ink/build/options.js.map +1 -0
- package/vendor/ink/build/output.d.ts +35 -0
- package/vendor/ink/build/output.js +183 -0
- package/vendor/ink/build/output.js.map +1 -0
- package/vendor/ink/build/parse-keypress.d.ts +22 -0
- package/vendor/ink/build/parse-keypress.js +493 -0
- package/vendor/ink/build/parse-keypress.js.map +1 -0
- package/vendor/ink/build/reconciler.d.ts +4 -0
- package/vendor/ink/build/reconciler.js +274 -0
- package/vendor/ink/build/reconciler.js.map +1 -0
- package/vendor/ink/build/render-background.d.ts +4 -0
- package/vendor/ink/build/render-background.js +25 -0
- package/vendor/ink/build/render-background.js.map +1 -0
- package/vendor/ink/build/render-border.d.ts +4 -0
- package/vendor/ink/build/render-border.js +73 -0
- package/vendor/ink/build/render-border.js.map +1 -0
- package/vendor/ink/build/render-node-to-output.d.ts +14 -0
- package/vendor/ink/build/render-node-to-output.js +147 -0
- package/vendor/ink/build/render-node-to-output.js.map +1 -0
- package/vendor/ink/build/render-to-string.d.ts +38 -0
- package/vendor/ink/build/render-to-string.js +115 -0
- package/vendor/ink/build/render-to-string.js.map +1 -0
- package/vendor/ink/build/render.d.ts +121 -0
- package/vendor/ink/build/render.js +55 -0
- package/vendor/ink/build/render.js.map +1 -0
- package/vendor/ink/build/renderer.d.ts +8 -0
- package/vendor/ink/build/renderer.js +55 -0
- package/vendor/ink/build/renderer.js.map +1 -0
- package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
- package/vendor/ink/build/sanitize-ansi.js +27 -0
- package/vendor/ink/build/sanitize-ansi.js.map +1 -0
- package/vendor/ink/build/screen-reader-update.d.ts +13 -0
- package/vendor/ink/build/screen-reader-update.js +38 -0
- package/vendor/ink/build/screen-reader-update.js.map +1 -0
- package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
- package/vendor/ink/build/squash-text-nodes.js +36 -0
- package/vendor/ink/build/squash-text-nodes.js.map +1 -0
- package/vendor/ink/build/styles.d.ts +240 -0
- package/vendor/ink/build/styles.js +232 -0
- package/vendor/ink/build/styles.js.map +1 -0
- package/vendor/ink/build/utils.d.ts +2 -0
- package/vendor/ink/build/utils.js +4 -0
- package/vendor/ink/build/utils.js.map +1 -0
- package/vendor/ink/build/wrap-text.d.ts +3 -0
- package/vendor/ink/build/wrap-text.js +31 -0
- package/vendor/ink/build/wrap-text.js.map +1 -0
- package/vendor/ink/build/write-synchronized.d.ts +4 -0
- package/vendor/ink/build/write-synchronized.js +7 -0
- package/vendor/ink/build/write-synchronized.js.map +1 -0
- package/vendor/ink/license +10 -0
- package/vendor/ink/node_modules/@types/node/LICENSE +21 -0
- package/vendor/ink/node_modules/@types/node/README.md +15 -0
- package/vendor/ink/node_modules/@types/node/assert/strict.d.ts +105 -0
- package/vendor/ink/node_modules/@types/node/assert.d.ts +955 -0
- package/vendor/ink/node_modules/@types/node/async_hooks.d.ts +623 -0
- package/vendor/ink/node_modules/@types/node/buffer.buffer.d.ts +466 -0
- package/vendor/ink/node_modules/@types/node/buffer.d.ts +1810 -0
- package/vendor/ink/node_modules/@types/node/child_process.d.ts +1428 -0
- package/vendor/ink/node_modules/@types/node/cluster.d.ts +486 -0
- package/vendor/ink/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
- package/vendor/ink/node_modules/@types/node/console.d.ts +151 -0
- package/vendor/ink/node_modules/@types/node/constants.d.ts +20 -0
- package/vendor/ink/node_modules/@types/node/crypto.d.ts +4065 -0
- package/vendor/ink/node_modules/@types/node/dgram.d.ts +564 -0
- package/vendor/ink/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
- package/vendor/ink/node_modules/@types/node/dns/promises.d.ts +503 -0
- package/vendor/ink/node_modules/@types/node/dns.d.ts +922 -0
- package/vendor/ink/node_modules/@types/node/domain.d.ts +166 -0
- package/vendor/ink/node_modules/@types/node/events.d.ts +1054 -0
- package/vendor/ink/node_modules/@types/node/fs/promises.d.ts +1329 -0
- package/vendor/ink/node_modules/@types/node/fs.d.ts +4676 -0
- package/vendor/ink/node_modules/@types/node/globals.d.ts +150 -0
- package/vendor/ink/node_modules/@types/node/globals.typedarray.d.ts +101 -0
- package/vendor/ink/node_modules/@types/node/http.d.ts +2167 -0
- package/vendor/ink/node_modules/@types/node/http2.d.ts +2480 -0
- package/vendor/ink/node_modules/@types/node/https.d.ts +405 -0
- package/vendor/ink/node_modules/@types/node/index.d.ts +115 -0
- package/vendor/ink/node_modules/@types/node/inspector/promises.d.ts +41 -0
- package/vendor/ink/node_modules/@types/node/inspector.d.ts +224 -0
- package/vendor/ink/node_modules/@types/node/inspector.generated.d.ts +4226 -0
- package/vendor/ink/node_modules/@types/node/module.d.ts +819 -0
- package/vendor/ink/node_modules/@types/node/net.d.ts +933 -0
- package/vendor/ink/node_modules/@types/node/os.d.ts +507 -0
- package/vendor/ink/node_modules/@types/node/package.json +155 -0
- package/vendor/ink/node_modules/@types/node/path/posix.d.ts +8 -0
- package/vendor/ink/node_modules/@types/node/path/win32.d.ts +8 -0
- package/vendor/ink/node_modules/@types/node/path.d.ts +187 -0
- package/vendor/ink/node_modules/@types/node/perf_hooks.d.ts +643 -0
- package/vendor/ink/node_modules/@types/node/process.d.ts +2156 -0
- package/vendor/ink/node_modules/@types/node/punycode.d.ts +117 -0
- package/vendor/ink/node_modules/@types/node/querystring.d.ts +152 -0
- package/vendor/ink/node_modules/@types/node/quic.d.ts +910 -0
- package/vendor/ink/node_modules/@types/node/readline/promises.d.ts +161 -0
- package/vendor/ink/node_modules/@types/node/readline.d.ts +541 -0
- package/vendor/ink/node_modules/@types/node/repl.d.ts +415 -0
- package/vendor/ink/node_modules/@types/node/sea.d.ts +162 -0
- package/vendor/ink/node_modules/@types/node/sqlite.d.ts +955 -0
- package/vendor/ink/node_modules/@types/node/stream/consumers.d.ts +38 -0
- package/vendor/ink/node_modules/@types/node/stream/promises.d.ts +211 -0
- package/vendor/ink/node_modules/@types/node/stream/web.d.ts +296 -0
- package/vendor/ink/node_modules/@types/node/stream.d.ts +1760 -0
- package/vendor/ink/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/vendor/ink/node_modules/@types/node/test/reporters.d.ts +96 -0
- package/vendor/ink/node_modules/@types/node/test.d.ts +2240 -0
- package/vendor/ink/node_modules/@types/node/timers/promises.d.ts +108 -0
- package/vendor/ink/node_modules/@types/node/timers.d.ts +159 -0
- package/vendor/ink/node_modules/@types/node/tls.d.ts +1198 -0
- package/vendor/ink/node_modules/@types/node/trace_events.d.ts +197 -0
- package/vendor/ink/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +462 -0
- package/vendor/ink/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
- package/vendor/ink/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
- package/vendor/ink/node_modules/@types/node/ts5.6/index.d.ts +117 -0
- package/vendor/ink/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
- package/vendor/ink/node_modules/@types/node/ts5.7/index.d.ts +117 -0
- package/vendor/ink/node_modules/@types/node/tty.d.ts +250 -0
- package/vendor/ink/node_modules/@types/node/url.d.ts +519 -0
- package/vendor/ink/node_modules/@types/node/util/types.d.ts +558 -0
- package/vendor/ink/node_modules/@types/node/util.d.ts +1662 -0
- package/vendor/ink/node_modules/@types/node/v8.d.ts +983 -0
- package/vendor/ink/node_modules/@types/node/vm.d.ts +1208 -0
- package/vendor/ink/node_modules/@types/node/wasi.d.ts +202 -0
- package/vendor/ink/node_modules/@types/node/web-globals/abortcontroller.d.ts +59 -0
- package/vendor/ink/node_modules/@types/node/web-globals/blob.d.ts +23 -0
- package/vendor/ink/node_modules/@types/node/web-globals/console.d.ts +9 -0
- package/vendor/ink/node_modules/@types/node/web-globals/crypto.d.ts +39 -0
- package/vendor/ink/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
- package/vendor/ink/node_modules/@types/node/web-globals/encoding.d.ts +11 -0
- package/vendor/ink/node_modules/@types/node/web-globals/events.d.ts +106 -0
- package/vendor/ink/node_modules/@types/node/web-globals/fetch.d.ts +69 -0
- package/vendor/ink/node_modules/@types/node/web-globals/importmeta.d.ts +13 -0
- package/vendor/ink/node_modules/@types/node/web-globals/messaging.d.ts +23 -0
- package/vendor/ink/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
- package/vendor/ink/node_modules/@types/node/web-globals/performance.d.ts +45 -0
- package/vendor/ink/node_modules/@types/node/web-globals/storage.d.ts +24 -0
- package/vendor/ink/node_modules/@types/node/web-globals/streams.d.ts +115 -0
- package/vendor/ink/node_modules/@types/node/web-globals/timers.d.ts +44 -0
- package/vendor/ink/node_modules/@types/node/web-globals/url.d.ts +24 -0
- package/vendor/ink/node_modules/@types/node/worker_threads.d.ts +717 -0
- package/vendor/ink/node_modules/@types/node/zlib.d.ts +618 -0
- package/vendor/ink/node_modules/node-pty/LICENSE +69 -0
- package/vendor/ink/node_modules/node-pty/README.md +164 -0
- package/vendor/ink/node_modules/node-pty/binding.gyp +150 -0
- package/vendor/ink/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
- package/vendor/ink/node_modules/node-pty/lib/eventEmitter2.js +47 -0
- package/vendor/ink/node_modules/node-pty/lib/index.js +52 -0
- package/vendor/ink/node_modules/node-pty/lib/interfaces.js +7 -0
- package/vendor/ink/node_modules/node-pty/lib/shared/conout.js +11 -0
- package/vendor/ink/node_modules/node-pty/lib/terminal.js +190 -0
- package/vendor/ink/node_modules/node-pty/lib/types.js +7 -0
- package/vendor/ink/node_modules/node-pty/lib/unixTerminal.js +349 -0
- package/vendor/ink/node_modules/node-pty/lib/utils.js +39 -0
- package/vendor/ink/node_modules/node-pty/lib/windowsConoutConnection.js +125 -0
- package/vendor/ink/node_modules/node-pty/lib/windowsPtyAgent.js +287 -0
- package/vendor/ink/node_modules/node-pty/lib/windowsTerminal.js +201 -0
- package/vendor/ink/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/vendor/ink/node_modules/node-pty/package.json +65 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty.pdb +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty.pdb +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
- package/vendor/ink/node_modules/node-pty/scripts/post-install.js +76 -0
- package/vendor/ink/node_modules/node-pty/scripts/prebuild.js +34 -0
- package/vendor/ink/node_modules/node-pty/src/unix/pty.cc +875 -0
- package/vendor/ink/node_modules/node-pty/src/unix/spawn-helper.cc +23 -0
- package/vendor/ink/node_modules/node-pty/src/win/conpty.cc +582 -0
- package/vendor/ink/node_modules/node-pty/src/win/conpty.h +41 -0
- package/vendor/ink/node_modules/node-pty/src/win/conpty_console_list.cc +44 -0
- package/vendor/ink/node_modules/node-pty/src/win/path_util.cc +95 -0
- package/vendor/ink/node_modules/node-pty/src/win/path_util.h +26 -0
- package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/OpenConsole.exe +0 -0
- package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/conpty.dll +0 -0
- package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/OpenConsole.exe +0 -0
- package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/conpty.dll +0 -0
- package/vendor/ink/node_modules/node-pty/typings/node-pty.d.ts +215 -0
- package/vendor/ink/node_modules/undici-types/LICENSE +21 -0
- package/vendor/ink/node_modules/undici-types/README.md +6 -0
- package/vendor/ink/node_modules/undici-types/agent.d.ts +32 -0
- package/vendor/ink/node_modules/undici-types/api.d.ts +43 -0
- package/vendor/ink/node_modules/undici-types/balanced-pool.d.ts +30 -0
- package/vendor/ink/node_modules/undici-types/cache-interceptor.d.ts +173 -0
- package/vendor/ink/node_modules/undici-types/cache.d.ts +36 -0
- package/vendor/ink/node_modules/undici-types/client-stats.d.ts +15 -0
- package/vendor/ink/node_modules/undici-types/client.d.ts +108 -0
- package/vendor/ink/node_modules/undici-types/connector.d.ts +34 -0
- package/vendor/ink/node_modules/undici-types/content-type.d.ts +21 -0
- package/vendor/ink/node_modules/undici-types/cookies.d.ts +30 -0
- package/vendor/ink/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
- package/vendor/ink/node_modules/undici-types/dispatcher.d.ts +276 -0
- package/vendor/ink/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
- package/vendor/ink/node_modules/undici-types/errors.d.ts +161 -0
- package/vendor/ink/node_modules/undici-types/eventsource.d.ts +66 -0
- package/vendor/ink/node_modules/undici-types/fetch.d.ts +211 -0
- package/vendor/ink/node_modules/undici-types/formdata.d.ts +108 -0
- package/vendor/ink/node_modules/undici-types/global-dispatcher.d.ts +9 -0
- package/vendor/ink/node_modules/undici-types/global-origin.d.ts +7 -0
- package/vendor/ink/node_modules/undici-types/h2c-client.d.ts +73 -0
- package/vendor/ink/node_modules/undici-types/handlers.d.ts +15 -0
- package/vendor/ink/node_modules/undici-types/header.d.ts +160 -0
- package/vendor/ink/node_modules/undici-types/index.d.ts +88 -0
- package/vendor/ink/node_modules/undici-types/interceptors.d.ts +73 -0
- package/vendor/ink/node_modules/undici-types/mock-agent.d.ts +68 -0
- package/vendor/ink/node_modules/undici-types/mock-call-history.d.ts +111 -0
- package/vendor/ink/node_modules/undici-types/mock-client.d.ts +27 -0
- package/vendor/ink/node_modules/undici-types/mock-errors.d.ts +12 -0
- package/vendor/ink/node_modules/undici-types/mock-interceptor.d.ts +94 -0
- package/vendor/ink/node_modules/undici-types/mock-pool.d.ts +27 -0
- package/vendor/ink/node_modules/undici-types/package.json +55 -0
- package/vendor/ink/node_modules/undici-types/patch.d.ts +29 -0
- package/vendor/ink/node_modules/undici-types/pool-stats.d.ts +19 -0
- package/vendor/ink/node_modules/undici-types/pool.d.ts +41 -0
- package/vendor/ink/node_modules/undici-types/proxy-agent.d.ts +29 -0
- package/vendor/ink/node_modules/undici-types/readable.d.ts +68 -0
- package/vendor/ink/node_modules/undici-types/retry-agent.d.ts +8 -0
- package/vendor/ink/node_modules/undici-types/retry-handler.d.ts +125 -0
- package/vendor/ink/node_modules/undici-types/round-robin-pool.d.ts +41 -0
- package/vendor/ink/node_modules/undici-types/snapshot-agent.d.ts +109 -0
- package/vendor/ink/node_modules/undici-types/util.d.ts +18 -0
- package/vendor/ink/node_modules/undici-types/utility.d.ts +7 -0
- package/vendor/ink/node_modules/undici-types/webidl.d.ts +341 -0
- package/vendor/ink/node_modules/undici-types/websocket.d.ts +186 -0
- package/vendor/ink/package.json +201 -0
- package/vendor/ink/readme.md +2636 -0
- package/bin/swag-agent.js +0 -9
- package/dist/server/lib/pg-rate-limiter.d.ts +0 -21
- package/dist/server/lib/pg-rate-limiter.js +0 -86
|
@@ -16,14 +16,15 @@
|
|
|
16
16
|
* - session-persistence.ts (SessionMeta, save/load/list/find sessions)
|
|
17
17
|
* - system-prompt.ts (buildSystemPrompt)
|
|
18
18
|
*/
|
|
19
|
-
|
|
20
|
-
import {
|
|
19
|
+
|
|
20
|
+
import { LOCAL_TOOL_DEFINITIONS, executeLocalTool, isLocalTool } from "./local-tools.js";
|
|
21
|
+
import { INTERACTIVE_TOOL_DEFINITIONS, executeInteractiveTool, waitForPlanApproval } from "./interactive-tools.js";
|
|
21
22
|
import { loadConfig, resolveConfig, getProxyUrl } from "./config-store.js";
|
|
22
23
|
import { getValidToken, refreshSession } from "./auth-service.js";
|
|
23
|
-
import { isServerTool, loadServerToolDefinitions, executeServerTool, getServerStatus, setServerToolContext
|
|
24
|
-
import { nextTurn, createTurnContext, logSpan, generateSpanId, flushCliSpans
|
|
24
|
+
import { isServerTool, loadServerToolDefinitions, executeServerTool, getServerStatus, setServerToolContext } from "./server-tools.js";
|
|
25
|
+
import { nextTurn, createTurnContext, logSpan, generateSpanId, flushCliSpans } from "./telemetry.js";
|
|
25
26
|
import { captureError, addBreadcrumb } from "./error-logger.js";
|
|
26
|
-
import { setGlobalEmitter, clearGlobalEmitter
|
|
27
|
+
import { setGlobalEmitter, clearGlobalEmitter } from "./agent-events.js";
|
|
27
28
|
import { mcpClientManager } from "./mcp-client.js";
|
|
28
29
|
import { loadHooks, runBeforeToolHook, runAfterToolHook, runSessionHook } from "./hooks.js";
|
|
29
30
|
import { LoopDetector, COMPACTION_TOTAL_BUDGET, getCompactionConfig, getContextManagement, DEFAULT_SESSION_COST_BUDGET_USD, emitCostWarningIfNeeded, resolveAgentLoopConfig, AGENT_DEFAULTS } from "../../shared/agent-core.js";
|
|
@@ -41,39 +42,60 @@ import { setPermissionMode, getPermissionMode, isToolAllowedByPermission } from
|
|
|
41
42
|
import { setModel, setModelById, getModel, getModelShortName, estimateCostUsd } from "./model-manager.js";
|
|
42
43
|
import { saveSession, loadSession, listSessions, findLatestSessionForCwd } from "./session-persistence.js";
|
|
43
44
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
45
|
+
|
|
44
46
|
// ============================================================================
|
|
45
47
|
// RE-EXPORTS — all consumers keep importing from agent-loop.ts
|
|
46
48
|
// ============================================================================
|
|
49
|
+
|
|
47
50
|
// Memory
|
|
48
51
|
export { loadMemory, addMemory, removeMemory, listMemories };
|
|
52
|
+
|
|
49
53
|
// Git context
|
|
50
54
|
export { refreshGitContext };
|
|
55
|
+
|
|
51
56
|
// CLAUDE.md
|
|
52
57
|
export { loadClaudeMd, reloadClaudeMd };
|
|
58
|
+
|
|
53
59
|
// Permission modes
|
|
54
60
|
export { setPermissionMode, getPermissionMode, isToolAllowedByPermission };
|
|
61
|
+
|
|
55
62
|
// Model management
|
|
56
63
|
export { setModel, getModel, getModelShortName, estimateCostUsd };
|
|
64
|
+
|
|
57
65
|
// Session persistence
|
|
58
66
|
export { saveSession, loadSession, listSessions, findLatestSessionForCwd };
|
|
67
|
+
|
|
59
68
|
// Server status (pass-through)
|
|
60
69
|
export { getServerStatus };
|
|
70
|
+
|
|
61
71
|
// MCP client manager
|
|
62
72
|
export { mcpClientManager };
|
|
73
|
+
|
|
63
74
|
// Re-export background process listing for /tasks command
|
|
64
75
|
export { listProcesses, listBackgroundAgents } from "./background-processes.js";
|
|
76
|
+
|
|
65
77
|
// Re-export event emitter for ChatApp
|
|
66
78
|
export { AgentEventEmitter } from "./agent-events.js";
|
|
79
|
+
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// TYPES
|
|
82
|
+
// ============================================================================
|
|
83
|
+
|
|
67
84
|
// ============================================================================
|
|
68
85
|
// SESSION STATE
|
|
69
86
|
// ============================================================================
|
|
87
|
+
|
|
70
88
|
// CLI-only: Session-wide token tracking (actual counts from API responses).
|
|
71
89
|
// Reset via resetSessionState() when starting a new conversation.
|
|
72
90
|
let sessionInputTokens = 0;
|
|
73
91
|
let sessionOutputTokens = 0;
|
|
74
92
|
export function getSessionTokens() {
|
|
75
|
-
|
|
93
|
+
return {
|
|
94
|
+
input: sessionInputTokens,
|
|
95
|
+
output: sessionOutputTokens
|
|
96
|
+
};
|
|
76
97
|
}
|
|
98
|
+
|
|
77
99
|
/**
|
|
78
100
|
* Reset all CLI-only session state. Call when starting a new conversation
|
|
79
101
|
* (e.g., /clear command, new print-mode run) to prevent stale token counts,
|
|
@@ -83,758 +105,1024 @@ export function getSessionTokens() {
|
|
|
83
105
|
* that persist intentionally until explicitly changed.
|
|
84
106
|
*/
|
|
85
107
|
export function resetSessionState() {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
sessionInputTokens = 0;
|
|
109
|
+
sessionOutputTokens = 0;
|
|
110
|
+
sessionLoopDetector = null;
|
|
111
|
+
resetGitContext();
|
|
112
|
+
resetClaudeMdCache();
|
|
113
|
+
clearReadCache();
|
|
114
|
+
resetAgentConfigCache();
|
|
93
115
|
}
|
|
116
|
+
|
|
94
117
|
/** CLI-only: loop detector — persists session error state across turns (reset by resetSessionState) */
|
|
95
118
|
let sessionLoopDetector = null;
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
|
|
119
|
+
|
|
120
|
+
// No artificial turn cap — agent self-regulates via end_turn (Claude Code parity).
|
|
121
|
+
// Safety: LoopDetector catches loops, cost budget catches runaway spending, user has Ctrl+C.
|
|
122
|
+
const CLI_NO_LIMIT = Number.MAX_SAFE_INTEGER;
|
|
123
|
+
|
|
99
124
|
// ============================================================================
|
|
100
125
|
// SHELL OUTPUT SUMMARIZATION
|
|
101
126
|
// ============================================================================
|
|
127
|
+
|
|
102
128
|
const SHELL_SUMMARIZE_LINE_THRESHOLD = 800;
|
|
103
129
|
const SHELL_SUMMARIZE_SIZE_THRESHOLD = 200_000; // 200KB — only summarize truly huge outputs
|
|
104
130
|
const SHELL_SUMMARIZE_MAX_INPUT = 300_000; // 300KB max to summarizer
|
|
105
131
|
const SHELL_SUMMARIZE_ORIGINAL_PREVIEW_LINES = 20;
|
|
132
|
+
|
|
106
133
|
/**
|
|
107
134
|
* Check if shell output should be summarized based on line count or size.
|
|
108
135
|
*/
|
|
109
136
|
function shouldSummarizeShellOutput(output) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return lineCount > SHELL_SUMMARIZE_LINE_THRESHOLD;
|
|
137
|
+
if (output.length > SHELL_SUMMARIZE_SIZE_THRESHOLD) return true;
|
|
138
|
+
const lineCount = output.split("\n").length;
|
|
139
|
+
return lineCount > SHELL_SUMMARIZE_LINE_THRESHOLD;
|
|
114
140
|
}
|
|
141
|
+
|
|
115
142
|
/**
|
|
116
143
|
* Summarize long shell output using Haiku via server proxy.
|
|
117
144
|
* Returns summarized output or original if summarization fails.
|
|
118
145
|
*/
|
|
119
146
|
async function summarizeShellOutput(output, proxyUrl, token, storeId) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
const lineCount = output.split("\n").length;
|
|
148
|
+
const truncatedForSummary = output.length > SHELL_SUMMARIZE_MAX_INPUT ? output.slice(0, SHELL_SUMMARIZE_MAX_INPUT) + "\n... (truncated for summarization)" : output;
|
|
149
|
+
try {
|
|
150
|
+
const summaryConfig = buildAPIRequest({
|
|
151
|
+
model: MODELS.HAIKU,
|
|
152
|
+
contextProfile: "subagent"
|
|
153
|
+
});
|
|
154
|
+
const stream = await callServerProxy({
|
|
155
|
+
proxyUrl,
|
|
156
|
+
token,
|
|
157
|
+
model: MODELS.HAIKU,
|
|
158
|
+
system: [{
|
|
159
|
+
type: "text",
|
|
160
|
+
text: "You are a concise technical summarizer. Summarize shell/command output preserving key information, errors, warnings, file paths, and actionable items. Be brief but thorough."
|
|
161
|
+
}],
|
|
162
|
+
messages: [{
|
|
163
|
+
role: "user",
|
|
164
|
+
content: `Summarize this shell output concisely, preserving key information, errors, and actionable items:\n\n${truncatedForSummary}`
|
|
165
|
+
}],
|
|
166
|
+
tools: [],
|
|
167
|
+
apiConfig: summaryConfig,
|
|
168
|
+
storeId,
|
|
169
|
+
timeoutMs: 15_000
|
|
170
|
+
});
|
|
171
|
+
const result = await collectStreamResult(parseSSEStream(stream));
|
|
172
|
+
const summary = result.text.trim();
|
|
173
|
+
if (!summary) return output; // Summarization failed, return original
|
|
174
|
+
|
|
175
|
+
// Build first N lines preview
|
|
176
|
+
const originalLines = output.split("\n");
|
|
177
|
+
const preview = originalLines.slice(0, SHELL_SUMMARIZE_ORIGINAL_PREVIEW_LINES).join("\n");
|
|
178
|
+
return `[Summarized from ${lineCount} lines]\n\n${summary}\n\n[First ${SHELL_SUMMARIZE_ORIGINAL_PREVIEW_LINES} lines of original output]\n${preview}`;
|
|
179
|
+
} catch {
|
|
180
|
+
// Summarization failed silently — return original output
|
|
181
|
+
return output;
|
|
182
|
+
}
|
|
153
183
|
}
|
|
184
|
+
|
|
154
185
|
/**
|
|
155
186
|
* Post-process tool results to summarize long bash output.
|
|
156
187
|
* Only affects bash tool results that exceed size/line thresholds.
|
|
157
188
|
*/
|
|
158
189
|
async function summarizeLongToolResults(toolResults, toolNames, proxyUrl, token, shellSummarization, storeId) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
190
|
+
if (!shellSummarization) return toolResults;
|
|
191
|
+
const tasks = toolResults.map(async result => {
|
|
192
|
+
// Only summarize bash tool string results
|
|
193
|
+
const toolName = toolNames.get(result.tool_use_id);
|
|
194
|
+
if (toolName !== "bash" || typeof result.content !== "string") return result;
|
|
195
|
+
|
|
196
|
+
// Check thresholds
|
|
197
|
+
if (!shouldSummarizeShellOutput(result.content)) return result;
|
|
198
|
+
const summarized = await summarizeShellOutput(result.content, proxyUrl, token, storeId);
|
|
199
|
+
return {
|
|
200
|
+
...result,
|
|
201
|
+
content: summarized
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
return Promise.all(tasks);
|
|
173
205
|
}
|
|
206
|
+
|
|
174
207
|
// ============================================================================
|
|
175
208
|
// TOOL DEFINITIONS
|
|
176
209
|
// ============================================================================
|
|
210
|
+
|
|
177
211
|
async function getTools(allowedTools, disallowedTools) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
212
|
+
const localTools = LOCAL_TOOL_DEFINITIONS.map(t => ({
|
|
213
|
+
name: t.name,
|
|
214
|
+
description: t.description,
|
|
215
|
+
input_schema: t.input_schema
|
|
216
|
+
}));
|
|
217
|
+
|
|
218
|
+
// Add interactive tools (ask_user_question, enter_plan_mode, exit_plan_mode)
|
|
219
|
+
const interactiveTools = INTERACTIVE_TOOL_DEFINITIONS.map(t => ({
|
|
220
|
+
name: t.name,
|
|
221
|
+
description: t.description,
|
|
222
|
+
input_schema: t.input_schema
|
|
223
|
+
}));
|
|
224
|
+
localTools.push(...interactiveTools);
|
|
225
|
+
let serverTools = [];
|
|
226
|
+
try {
|
|
227
|
+
serverTools = await loadServerToolDefinitions();
|
|
228
|
+
} catch {
|
|
229
|
+
// Server tools silently unavailable
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Deduplicate: local tools take priority over server tools with the same name
|
|
233
|
+
const localNames = new Set(localTools.map(t => t.name));
|
|
234
|
+
const uniqueServerTools = serverTools.filter(t => !localNames.has(t.name));
|
|
235
|
+
|
|
236
|
+
// MCP tools from external servers
|
|
237
|
+
const mcpTools = mcpClientManager.getTools();
|
|
238
|
+
let allTools = [...localTools, ...uniqueServerTools, ...mcpTools];
|
|
239
|
+
|
|
240
|
+
// Apply tool filtering
|
|
241
|
+
if (allowedTools && allowedTools.length > 0) {
|
|
242
|
+
const allowed = new Set(allowedTools);
|
|
243
|
+
allTools = allTools.filter(t => allowed.has(t.name));
|
|
244
|
+
}
|
|
245
|
+
if (disallowedTools && disallowedTools.length > 0) {
|
|
246
|
+
const disallowed = new Set(disallowedTools);
|
|
247
|
+
allTools = allTools.filter(t => !disallowed.has(t.name));
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
tools: allTools,
|
|
251
|
+
serverToolCount: uniqueServerTools.length
|
|
252
|
+
};
|
|
216
253
|
}
|
|
254
|
+
|
|
217
255
|
/** Exposed for /status command */
|
|
218
256
|
export async function getServerToolCount() {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
257
|
+
try {
|
|
258
|
+
const defs = await loadServerToolDefinitions();
|
|
259
|
+
return defs.length;
|
|
260
|
+
} catch {
|
|
261
|
+
return 0;
|
|
262
|
+
}
|
|
226
263
|
}
|
|
264
|
+
|
|
227
265
|
// ============================================================================
|
|
228
266
|
// MAIN LOOP
|
|
229
267
|
// ============================================================================
|
|
268
|
+
|
|
230
269
|
export async function runAgentLoop(opts) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
270
|
+
const {
|
|
271
|
+
message,
|
|
272
|
+
conversationHistory,
|
|
273
|
+
callbacks,
|
|
274
|
+
abortSignal,
|
|
275
|
+
emitter
|
|
276
|
+
} = opts;
|
|
277
|
+
if (opts.model) setModel(opts.model);
|
|
278
|
+
|
|
279
|
+
// Set global emitter for subagents to use
|
|
280
|
+
if (emitter) {
|
|
281
|
+
setGlobalEmitter(emitter);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// effectiveMaxTurns resolved after DB config fetch below
|
|
285
|
+
// 0 or unset = no limit (Claude Code parity — agent self-regulates via end_turn)
|
|
286
|
+
let effectiveMaxTurns = opts.maxTurns || CLI_NO_LIMIT;
|
|
287
|
+
|
|
288
|
+
// Load hooks from project and user config
|
|
289
|
+
const hooksCwd = opts.cwd || process.cwd();
|
|
290
|
+
const hooks = loadHooks(hooksCwd);
|
|
291
|
+
|
|
292
|
+
// Fire SessionStart hook (non-blocking)
|
|
293
|
+
if (hooks.length > 0) {
|
|
294
|
+
runSessionHook(hooks, "SessionStart", {
|
|
295
|
+
session_id: `turn-${Date.now()}`
|
|
296
|
+
}).catch(() => {});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Shell summarization config (default: true)
|
|
300
|
+
const shellSummarization = opts.shellSummarization !== false;
|
|
301
|
+
const {
|
|
302
|
+
tools,
|
|
303
|
+
serverToolCount
|
|
304
|
+
} = await getTools(opts.allowedTools, opts.disallowedTools);
|
|
305
|
+
const systemPrompt = await buildSystemPrompt(serverToolCount > 0, opts.effort);
|
|
306
|
+
|
|
307
|
+
// Build user content — text-only string or content blocks array with images
|
|
308
|
+
let userContent;
|
|
309
|
+
if (opts.images && opts.images.length > 0) {
|
|
310
|
+
const blocks = [];
|
|
311
|
+
for (const img of opts.images) {
|
|
312
|
+
blocks.push({
|
|
313
|
+
type: "image",
|
|
314
|
+
source: {
|
|
315
|
+
type: "base64",
|
|
316
|
+
media_type: img.mediaType,
|
|
317
|
+
data: img.base64
|
|
264
318
|
}
|
|
265
|
-
|
|
266
|
-
userContent = blocks;
|
|
319
|
+
});
|
|
267
320
|
}
|
|
268
|
-
|
|
269
|
-
|
|
321
|
+
blocks.push({
|
|
322
|
+
type: "text",
|
|
323
|
+
text: message || "(see attached images)"
|
|
324
|
+
});
|
|
325
|
+
userContent = blocks;
|
|
326
|
+
} else {
|
|
327
|
+
userContent = message;
|
|
328
|
+
}
|
|
329
|
+
const messages = [...conversationHistory, {
|
|
330
|
+
role: "user",
|
|
331
|
+
content: userContent
|
|
332
|
+
}];
|
|
333
|
+
let totalIn = 0;
|
|
334
|
+
let totalOut = 0;
|
|
335
|
+
let totalCacheCreation = 0;
|
|
336
|
+
let totalCacheRead = 0;
|
|
337
|
+
let totalThinking = 0;
|
|
338
|
+
let allAssistantText = [];
|
|
339
|
+
let prevIterationInputTokens = 0; // Tracks actual context size from last API call
|
|
340
|
+
|
|
341
|
+
// Telemetry: one turn per user message (not per API call)
|
|
342
|
+
const sessionStart = Date.now();
|
|
343
|
+
const {
|
|
344
|
+
storeId
|
|
345
|
+
} = resolveConfig();
|
|
346
|
+
const turnNum = nextTurn(); // ONCE per user message
|
|
347
|
+
const turnCtx = createTurnContext({
|
|
348
|
+
model: getModel(),
|
|
349
|
+
turnNumber: turnNum
|
|
350
|
+
});
|
|
351
|
+
addBreadcrumb("agent", `Turn ${turnNum}: ${message.slice(0, 100)}`, "info");
|
|
352
|
+
|
|
353
|
+
// Set server tool context so tool calls carry trace/user identity to Fly.io server
|
|
354
|
+
setServerToolContext({
|
|
355
|
+
traceId: turnCtx.traceId,
|
|
356
|
+
conversationId: turnCtx.conversationId,
|
|
357
|
+
userId: turnCtx.userId,
|
|
358
|
+
userEmail: turnCtx.userEmail,
|
|
359
|
+
source: "whale-code"
|
|
360
|
+
});
|
|
361
|
+
logSpan({
|
|
362
|
+
action: "chat.user_message",
|
|
363
|
+
durationMs: 0,
|
|
364
|
+
context: turnCtx,
|
|
365
|
+
storeId: storeId || undefined,
|
|
366
|
+
details: {
|
|
367
|
+
message: message,
|
|
368
|
+
conversation_history_length: conversationHistory.length
|
|
270
369
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
370
|
+
});
|
|
371
|
+
let sessionCostUsd = 0;
|
|
372
|
+
let compactionCount = 0;
|
|
373
|
+
let consecutiveCompactions = 0; // Circuit breaker: consecutive compactions without progress
|
|
374
|
+
let maxTokensContinuations = 0; // Cap continuation loops to prevent infinite looping
|
|
375
|
+
const costWarningsEmitted = new Set();
|
|
376
|
+
const activeModel = getModel();
|
|
377
|
+
|
|
378
|
+
// Fetch agent config from DB — single source of truth, nothing hardcoded.
|
|
379
|
+
// Falls back to AGENT_DEFAULTS only if DB is unreachable (never blocks).
|
|
380
|
+
const dbAgent = await loadCLIAgentConfig();
|
|
381
|
+
const resolved = dbAgent ? resolveAgentLoopConfig(dbAgent, "sse") : null;
|
|
382
|
+
|
|
383
|
+
// Session-level loop detector: persists failed strategies across turns.
|
|
384
|
+
// Created once per conversation, reset only when user starts a new conversation.
|
|
385
|
+
// Must be created AFTER config resolution so DB thresholds apply.
|
|
386
|
+
if (!sessionLoopDetector || conversationHistory.length === 0) {
|
|
387
|
+
sessionLoopDetector = resolved ? LoopDetector.fromResolved(resolved) : new LoopDetector();
|
|
388
|
+
}
|
|
389
|
+
const loopDetector = sessionLoopDetector;
|
|
390
|
+
loopDetector.resetTurn();
|
|
391
|
+
const effectiveBudget = opts.maxBudgetUsd ?? resolved?.contextOverrides.session_cost_budget_usd ?? DEFAULT_SESSION_COST_BUDGET_USD;
|
|
392
|
+
|
|
393
|
+
// Compaction settings from DB via getContextManagement — pass DB overrides so
|
|
394
|
+
// the trigger/budget values match what the Anthropic API actually uses.
|
|
395
|
+
const ctxOverrides = resolved?.contextOverrides;
|
|
396
|
+
const ctxMgmt = getContextManagement(activeModel, ctxOverrides);
|
|
397
|
+
const compactEdit = ctxMgmt.config.edits.find(e => e.type === "compact_20260112");
|
|
398
|
+
const effectiveCompactionTrigger = compactEdit?.trigger?.value ?? AGENT_DEFAULTS.compactionTriggerTokens;
|
|
399
|
+
const effectiveCompactionBudget = ctxOverrides?.compaction_total_budget ?? COMPACTION_TOTAL_BUDGET;
|
|
400
|
+
|
|
401
|
+
// Override maxTurns from DB config (if not explicitly set by caller)
|
|
402
|
+
// 0 = no limit (Claude Code parity)
|
|
403
|
+
if (!opts.maxTurns && resolved && resolved.maxTurns > 0) {
|
|
404
|
+
effectiveMaxTurns = resolved.maxTurns;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Max continuations: resolved from DB config → AGENT_DEFAULTS fallback
|
|
408
|
+
const maxContinuations = resolved?.maxContinuations ?? AGENT_DEFAULTS.maxContinuations;
|
|
409
|
+
|
|
410
|
+
// Tool executor — routes to interactive, local, server, or MCP tools.
|
|
411
|
+
// Wraps execution with before/after hooks when hooks are loaded.
|
|
412
|
+
const INTERACTIVE_TOOL_NAMES = new Set(INTERACTIVE_TOOL_DEFINITIONS.map(t => t.name));
|
|
413
|
+
const toolExecutor = async (name, input) => {
|
|
414
|
+
if (!name) {
|
|
415
|
+
return {
|
|
416
|
+
success: false,
|
|
417
|
+
output: "Tool call missing name — skipping."
|
|
418
|
+
};
|
|
279
419
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
let allAssistantText = [];
|
|
288
|
-
let prevIterationInputTokens = 0; // Tracks actual context size from last API call
|
|
289
|
-
// Telemetry: one turn per user message (not per API call)
|
|
290
|
-
const sessionStart = Date.now();
|
|
291
|
-
const { storeId } = resolveConfig();
|
|
292
|
-
const turnNum = nextTurn(); // ONCE per user message
|
|
293
|
-
const turnCtx = createTurnContext({ model: getModel(), turnNumber: turnNum });
|
|
294
|
-
addBreadcrumb("agent", `Turn ${turnNum}: ${message.slice(0, 100)}`, "info");
|
|
295
|
-
// Set server tool context so tool calls carry trace/user identity to Fly.io server
|
|
296
|
-
setServerToolContext({
|
|
297
|
-
traceId: turnCtx.traceId,
|
|
298
|
-
conversationId: turnCtx.conversationId,
|
|
299
|
-
userId: turnCtx.userId,
|
|
300
|
-
userEmail: turnCtx.userEmail,
|
|
301
|
-
source: "whale-code",
|
|
302
|
-
});
|
|
303
|
-
logSpan({
|
|
304
|
-
action: "chat.user_message",
|
|
305
|
-
durationMs: 0,
|
|
306
|
-
context: turnCtx,
|
|
307
|
-
storeId: storeId || undefined,
|
|
308
|
-
details: {
|
|
309
|
-
message: message,
|
|
310
|
-
conversation_history_length: conversationHistory.length,
|
|
311
|
-
},
|
|
312
|
-
});
|
|
313
|
-
let sessionCostUsd = 0;
|
|
314
|
-
let compactionCount = 0;
|
|
315
|
-
const costWarningsEmitted = new Set();
|
|
316
|
-
const activeModel = getModel();
|
|
317
|
-
// Fetch agent config from DB — single source of truth, nothing hardcoded.
|
|
318
|
-
// Falls back to AGENT_DEFAULTS only if DB is unreachable (never blocks).
|
|
319
|
-
const dbAgent = await loadCLIAgentConfig();
|
|
320
|
-
const resolved = dbAgent
|
|
321
|
-
? resolveAgentLoopConfig(dbAgent, "sse")
|
|
322
|
-
: null;
|
|
323
|
-
const effectiveBudget = opts.maxBudgetUsd
|
|
324
|
-
?? resolved?.contextOverrides.session_cost_budget_usd
|
|
325
|
-
?? DEFAULT_SESSION_COST_BUDGET_USD;
|
|
326
|
-
// Compaction settings from DB via getContextManagement — pass DB overrides so
|
|
327
|
-
// the trigger/budget values match what the Anthropic API actually uses.
|
|
328
|
-
const ctxOverrides = resolved?.contextOverrides;
|
|
329
|
-
const ctxMgmt = getContextManagement(activeModel, ctxOverrides);
|
|
330
|
-
const compactEdit = ctxMgmt.config.edits.find((e) => e.type === "compact_20260112");
|
|
331
|
-
const effectiveCompactionTrigger = compactEdit?.trigger?.value ?? AGENT_DEFAULTS.compactionTriggerTokens;
|
|
332
|
-
const effectiveCompactionBudget = ctxOverrides?.compaction_total_budget ?? COMPACTION_TOTAL_BUDGET;
|
|
333
|
-
// Override maxTurns from DB config (if not explicitly set by caller)
|
|
334
|
-
if (!opts.maxTurns && resolved) {
|
|
335
|
-
effectiveMaxTurns = resolved.maxTurns;
|
|
420
|
+
|
|
421
|
+
// Permission mode enforcement
|
|
422
|
+
if (!isToolAllowedByPermission(name)) {
|
|
423
|
+
return {
|
|
424
|
+
success: false,
|
|
425
|
+
output: `Tool "${name}" blocked by ${getPermissionMode()} mode. Switch modes with /mode.`
|
|
426
|
+
};
|
|
336
427
|
}
|
|
337
|
-
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
428
|
+
|
|
429
|
+
// BeforeTool hook — may block or modify input
|
|
430
|
+
let effectiveInput = input;
|
|
431
|
+
if (hooks.length > 0) {
|
|
432
|
+
const hookResult = await runBeforeToolHook(hooks, name, input);
|
|
433
|
+
if (!hookResult.allow) {
|
|
434
|
+
return {
|
|
435
|
+
success: false,
|
|
436
|
+
output: hookResult.message || "Blocked by hook"
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
if (hookResult.modifiedInput) {
|
|
440
|
+
effectiveInput = hookResult.modifiedInput;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
let result;
|
|
444
|
+
if (INTERACTIVE_TOOL_NAMES.has(name)) {
|
|
445
|
+
result = await executeInteractiveTool(name, effectiveInput);
|
|
446
|
+
|
|
447
|
+
// For exit_plan_mode: wait for UI approval, then map decision to result
|
|
448
|
+
if (name === "exit_plan_mode" && result.success) {
|
|
449
|
+
const decision = await waitForPlanApproval();
|
|
450
|
+
switch (decision.action) {
|
|
451
|
+
case "execute":
|
|
452
|
+
result = {
|
|
453
|
+
success: true,
|
|
454
|
+
output: `__PLAN_APPROVED_CLEAN__\n${result.output}`
|
|
455
|
+
};
|
|
456
|
+
break;
|
|
457
|
+
case "edit":
|
|
458
|
+
result = {
|
|
459
|
+
success: true,
|
|
460
|
+
output: "Plan returned for revision. Make changes and use ExitPlanMode again when ready."
|
|
461
|
+
};
|
|
462
|
+
break;
|
|
463
|
+
case "feedback":
|
|
464
|
+
result = {
|
|
465
|
+
success: true,
|
|
466
|
+
output: `User feedback on plan:\n\n${decision.feedback || "(no feedback provided)"}\n\nRevise the plan based on this feedback, then use ExitPlanMode again.`
|
|
467
|
+
};
|
|
468
|
+
break;
|
|
469
|
+
case "cancel":
|
|
470
|
+
result = {
|
|
471
|
+
success: true,
|
|
472
|
+
output: "Plan cancelled by user. Do not proceed with implementation."
|
|
473
|
+
};
|
|
474
|
+
break;
|
|
343
475
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
476
|
+
}
|
|
477
|
+
} else if (isLocalTool(name)) {
|
|
478
|
+
result = await executeLocalTool(name, effectiveInput, abortSignal);
|
|
479
|
+
} else if (isServerTool(name)) {
|
|
480
|
+
result = await executeServerTool(name, effectiveInput, emitter);
|
|
481
|
+
} else if (mcpClientManager.isMcpTool(name)) {
|
|
482
|
+
result = await mcpClientManager.callTool(name, effectiveInput);
|
|
483
|
+
} else {
|
|
484
|
+
result = {
|
|
485
|
+
success: false,
|
|
486
|
+
output: `Unknown tool: ${name}`
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// AfterTool hook — may modify output
|
|
491
|
+
if (hooks.length > 0) {
|
|
492
|
+
const afterResult = await runAfterToolHook(hooks, name, result.output, result.success);
|
|
493
|
+
if (afterResult.modifiedOutput !== undefined) {
|
|
494
|
+
result = {
|
|
495
|
+
...result,
|
|
496
|
+
output: afterResult.modifiedOutput
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return result;
|
|
501
|
+
};
|
|
502
|
+
try {
|
|
503
|
+
for (let iteration = 0; iteration < effectiveMaxTurns; iteration++) {
|
|
504
|
+
if (abortSignal?.aborted) {
|
|
505
|
+
logSpan({
|
|
506
|
+
action: "chat.cancelled",
|
|
507
|
+
durationMs: Date.now() - sessionStart,
|
|
508
|
+
context: turnCtx,
|
|
509
|
+
storeId: storeId || undefined,
|
|
510
|
+
details: {
|
|
511
|
+
iteration,
|
|
512
|
+
reason: "user_abort"
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
callbacks.onError("Cancelled", messages);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Budget enforcement — always enforced (defaults to DEFAULT_SESSION_COST_BUDGET_USD)
|
|
520
|
+
if (sessionCostUsd >= effectiveBudget) {
|
|
521
|
+
logSpan({
|
|
522
|
+
action: "chat.budget_exceeded",
|
|
523
|
+
durationMs: Date.now() - sessionStart,
|
|
524
|
+
context: turnCtx,
|
|
525
|
+
storeId: storeId || undefined,
|
|
526
|
+
severity: "warn",
|
|
527
|
+
details: {
|
|
528
|
+
session_cost_usd: sessionCostUsd,
|
|
529
|
+
max_budget_usd: effectiveBudget,
|
|
530
|
+
iteration
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
callbacks.onError(`Budget exceeded: $${sessionCostUsd.toFixed(4)} >= $${effectiveBudget}`, messages);
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const apiStart = Date.now();
|
|
537
|
+
const apiSpanId = generateSpanId();
|
|
538
|
+
const apiRowId = crypto.randomUUID(); // UUID for this span's row — children reference via parent_id
|
|
539
|
+
const costContext = `Session cost: $${sessionCostUsd.toFixed(2)} | Budget remaining: $${(effectiveBudget - sessionCostUsd).toFixed(2)}`;
|
|
540
|
+
|
|
541
|
+
// Build API request config
|
|
542
|
+
const currentModel = getModel();
|
|
543
|
+
const apiConfig = buildAPIRequest({
|
|
544
|
+
model: currentModel,
|
|
545
|
+
contextProfile: "main",
|
|
546
|
+
thinkingEnabled: opts.thinking,
|
|
547
|
+
contextOverrides: ctxOverrides
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// Prepare with prompt caching
|
|
551
|
+
let {
|
|
552
|
+
tools: cachedTools,
|
|
553
|
+
messages: cachedMessages
|
|
554
|
+
} = prepareWithCaching(tools, messages);
|
|
555
|
+
const system = buildSystemBlocks(systemPrompt, costContext);
|
|
556
|
+
|
|
557
|
+
// Client-side context trimming for non-Anthropic providers.
|
|
558
|
+
// Uses prevIterationInputTokens (actual context size from last API call) — NOT
|
|
559
|
+
// cumulative sessionInputTokens, which grows quadratically and would trigger too early.
|
|
560
|
+
const provider = getProvider(currentModel);
|
|
561
|
+
if (provider === "gemini" || provider === "openai") {
|
|
562
|
+
const preTrimMessages = cachedMessages;
|
|
563
|
+
if (provider === "gemini") {
|
|
564
|
+
// Emergency fallback only — compaction fires at 700K first; trim at 950K catches failures
|
|
565
|
+
cachedMessages = trimGeminiContext(cachedMessages, prevIterationInputTokens);
|
|
566
|
+
} else {
|
|
567
|
+
// Emergency fallback only — compaction fires at 120K first; trim at 190K catches failures
|
|
568
|
+
// GPT-4o: 128K context → 96K threshold (no compaction headroom)
|
|
569
|
+
const threshold = currentModel === "gpt-4o" ? 96_000 : 190_000;
|
|
570
|
+
cachedMessages = trimOpenAIContext(cachedMessages, prevIterationInputTokens, threshold);
|
|
347
571
|
}
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
572
|
+
// Notify UI when trimming actually occurred (trim returns same ref if no-op)
|
|
573
|
+
if (cachedMessages !== preTrimMessages) {
|
|
574
|
+
// Count tool results before/after to report meaningful numbers
|
|
575
|
+
const countToolResults = msgs => msgs.reduce((sum, m) => sum + (Array.isArray(m.content) ? m.content.filter(b => b.type === "tool_result" && b.content !== "[trimmed]").length : 0), 0);
|
|
576
|
+
const activeBefore = countToolResults(preTrimMessages);
|
|
577
|
+
const activeAfter = countToolResults(cachedMessages);
|
|
578
|
+
const estimatedSaved = Math.round(prevIterationInputTokens * ((activeBefore - activeAfter) / Math.max(activeBefore, 1)));
|
|
579
|
+
callbacks.onAutoCompact?.(activeBefore, activeAfter, estimatedSaved);
|
|
580
|
+
emitter?.emitCompact(activeBefore, activeAfter, estimatedSaved);
|
|
358
581
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Get auth token
|
|
585
|
+
const token = await getValidToken();
|
|
586
|
+
if (!token) {
|
|
587
|
+
throw new Error("Not logged in. Run: whale login");
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Call server proxy with built-in retry
|
|
591
|
+
const originalModel = currentModel;
|
|
592
|
+
const stream = await callServerProxy({
|
|
593
|
+
proxyUrl: getProxyUrl(),
|
|
594
|
+
token,
|
|
595
|
+
model: currentModel,
|
|
596
|
+
system,
|
|
597
|
+
messages: cachedMessages,
|
|
598
|
+
tools: cachedTools,
|
|
599
|
+
apiConfig,
|
|
600
|
+
signal: abortSignal,
|
|
601
|
+
fallbackModel: opts.fallbackModel,
|
|
602
|
+
storeId: storeId || undefined,
|
|
603
|
+
onFallback: (from, to) => {
|
|
604
|
+
setModel(to);
|
|
605
|
+
logSpan({
|
|
606
|
+
action: "claude_api_fallback",
|
|
607
|
+
durationMs: 0,
|
|
608
|
+
context: {
|
|
609
|
+
...turnCtx,
|
|
610
|
+
spanId: apiSpanId
|
|
611
|
+
},
|
|
612
|
+
storeId: storeId || undefined,
|
|
613
|
+
details: {
|
|
614
|
+
from_model: from,
|
|
615
|
+
to_model: to
|
|
379
616
|
}
|
|
617
|
+
});
|
|
618
|
+
},
|
|
619
|
+
onRetry: (attempt, max, err) => {
|
|
620
|
+
const msg = `\n\x1b[33m\u21BB Retrying (${attempt}/${max})... ${err.slice(0, 80)}\x1b[0m\n`;
|
|
621
|
+
if (emitter) {
|
|
622
|
+
emitter.emitText(msg);
|
|
623
|
+
} else {
|
|
624
|
+
callbacks.onText(msg);
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
onTokenRefresh: async () => {
|
|
628
|
+
const result = await refreshSession();
|
|
629
|
+
return result.success ? result.config.access_token : null;
|
|
380
630
|
}
|
|
381
|
-
|
|
382
|
-
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
// Process stream events with UI callbacks
|
|
634
|
+
let thinkingChunks = 0;
|
|
635
|
+
const result = await processStreamWithCallbacks(parseSSEStream(stream, abortSignal), {
|
|
636
|
+
onText: text => {
|
|
637
|
+
if (emitter) {
|
|
638
|
+
emitter.emitText(text);
|
|
639
|
+
} else {
|
|
640
|
+
callbacks.onText(text);
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
onThinking: () => {
|
|
644
|
+
thinkingChunks++;
|
|
645
|
+
emitter?.emitThinking(thinkingChunks);
|
|
646
|
+
},
|
|
647
|
+
onToolStart: (name, input) => {
|
|
648
|
+
// NOTE: Do NOT call callbacks.onToolStart here — dispatchTools.onStart
|
|
649
|
+
// fires it once per tool at execution time. Calling it here too would
|
|
650
|
+
// send duplicate tool_start events (stale spinners in WhaleChat).
|
|
651
|
+
if (input) {
|
|
652
|
+
// Tool block complete — emit structured start for CLI TUI only
|
|
653
|
+
emitter?.emitToolStart("", name);
|
|
654
|
+
}
|
|
383
655
|
}
|
|
384
|
-
|
|
385
|
-
|
|
656
|
+
}, abortSignal);
|
|
657
|
+
|
|
658
|
+
// Flush buffered text
|
|
659
|
+
emitter?.flushText();
|
|
660
|
+
|
|
661
|
+
// Restore original model after transient fallback
|
|
662
|
+
if (getModel() !== originalModel && opts.fallbackModel) {
|
|
663
|
+
setModelById(originalModel);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Update session token tracking
|
|
667
|
+
sessionInputTokens += result.usage.inputTokens;
|
|
668
|
+
sessionOutputTokens += result.usage.outputTokens;
|
|
669
|
+
prevIterationInputTokens = result.usage.inputTokens; // Actual context size for next trim check
|
|
670
|
+
|
|
671
|
+
// Emit usage with model + cost context for all providers
|
|
672
|
+
if (emitter && (result.usage.inputTokens > 0 || result.usage.outputTokens > 0)) {
|
|
673
|
+
const iterCost = estimateCostUsd(result.usage.inputTokens, result.usage.outputTokens, currentModel, result.thinkingTokens, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
674
|
+
emitter.emitUsage(result.usage.inputTokens, result.usage.outputTokens, currentModel, iterCost, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
675
|
+
}
|
|
676
|
+
totalIn += result.usage.inputTokens;
|
|
677
|
+
totalOut += result.usage.outputTokens;
|
|
678
|
+
totalCacheCreation += result.usage.cacheCreationTokens;
|
|
679
|
+
totalCacheRead += result.usage.cacheReadTokens;
|
|
680
|
+
totalThinking += result.thinkingTokens;
|
|
681
|
+
sessionCostUsd += estimateCostUsd(result.usage.inputTokens, result.usage.outputTokens, currentModel, result.thinkingTokens, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
682
|
+
|
|
683
|
+
// Graduated cost warnings
|
|
684
|
+
emitCostWarningIfNeeded(sessionCostUsd, effectiveBudget, costWarningsEmitted, text => {
|
|
685
|
+
if (emitter) {
|
|
686
|
+
emitter.emitText(text);
|
|
687
|
+
} else {
|
|
688
|
+
callbacks.onText(text);
|
|
386
689
|
}
|
|
387
|
-
|
|
388
|
-
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
// Server-side context management notification
|
|
693
|
+
if (result.contextManagementApplied) {
|
|
694
|
+
callbacks.onAutoCompact?.(messages.length, messages.length, 0);
|
|
695
|
+
emitter?.emitCompact(messages.length, messages.length, 0);
|
|
696
|
+
logSpan({
|
|
697
|
+
action: "chat.api_compaction",
|
|
698
|
+
durationMs: Date.now() - apiStart,
|
|
699
|
+
context: turnCtx,
|
|
700
|
+
storeId: storeId || undefined,
|
|
701
|
+
details: {
|
|
702
|
+
type: "server_side",
|
|
703
|
+
has_compaction_content: result.compactionContent !== null,
|
|
704
|
+
iteration
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
if (result.text) allAssistantText.push(result.text);
|
|
709
|
+
|
|
710
|
+
// Telemetry: API call span
|
|
711
|
+
const iterCostUsd = estimateCostUsd(result.usage.inputTokens, result.usage.outputTokens, currentModel, result.thinkingTokens, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
712
|
+
logSpan({
|
|
713
|
+
action: "claude_api_request",
|
|
714
|
+
durationMs: Date.now() - apiStart,
|
|
715
|
+
context: {
|
|
716
|
+
...turnCtx,
|
|
717
|
+
spanId: apiSpanId,
|
|
718
|
+
rowId: apiRowId,
|
|
719
|
+
inputTokens: result.usage.inputTokens,
|
|
720
|
+
outputTokens: result.usage.outputTokens,
|
|
721
|
+
totalCost: iterCostUsd,
|
|
722
|
+
model: currentModel
|
|
723
|
+
},
|
|
724
|
+
storeId: storeId || undefined,
|
|
725
|
+
details: {
|
|
726
|
+
"gen_ai.request.model": currentModel,
|
|
727
|
+
"gen_ai.usage.input_tokens": result.usage.inputTokens,
|
|
728
|
+
"gen_ai.usage.output_tokens": result.usage.outputTokens,
|
|
729
|
+
"gen_ai.usage.cache_creation_tokens": result.usage.cacheCreationTokens,
|
|
730
|
+
"gen_ai.usage.cache_read_tokens": result.usage.cacheReadTokens,
|
|
731
|
+
"gen_ai.usage.cost": iterCostUsd,
|
|
732
|
+
stop_reason: result.stopReason === "compaction" ? "compaction" : result.toolUseBlocks.length > 0 ? "tool_use" : "end_turn",
|
|
733
|
+
iteration,
|
|
734
|
+
tool_count: result.toolUseBlocks.length,
|
|
735
|
+
tool_names: result.toolUseBlocks.map(t => t.name)
|
|
389
736
|
}
|
|
390
|
-
|
|
391
|
-
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
// Compaction handling — API paused after generating summary.
|
|
740
|
+
// Per Anthropic docs: the compaction block replaces all prior context.
|
|
741
|
+
// Do NOT preserve old messages — they can exceed the trigger threshold
|
|
742
|
+
// and cause an infinite compaction loop. The summary captures all context.
|
|
743
|
+
if (result.stopReason === "compaction" && result.compactionContent) {
|
|
744
|
+
compactionCount++;
|
|
745
|
+
consecutiveCompactions++;
|
|
746
|
+
logSpan({
|
|
747
|
+
action: "chat.compaction_pause",
|
|
748
|
+
durationMs: Date.now() - apiStart,
|
|
749
|
+
context: turnCtx,
|
|
750
|
+
storeId: storeId || undefined,
|
|
751
|
+
details: {
|
|
752
|
+
compaction_count: compactionCount,
|
|
753
|
+
consecutive: consecutiveCompactions,
|
|
754
|
+
messages_before: messages.length
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
// Circuit breaker: if compaction fires repeatedly without progress,
|
|
759
|
+
// the summary + system prompt alone may exceed the trigger. Force wrap-up.
|
|
760
|
+
const MAX_CONSECUTIVE_COMPACTIONS = 3;
|
|
761
|
+
const shouldWrapUp = consecutiveCompactions > MAX_CONSECUTIVE_COMPACTIONS || compactionCount * effectiveCompactionTrigger >= effectiveCompactionBudget;
|
|
762
|
+
const compactedMessages = [{
|
|
763
|
+
role: "assistant",
|
|
764
|
+
content: [{
|
|
765
|
+
type: "compaction",
|
|
766
|
+
content: result.compactionContent
|
|
767
|
+
}]
|
|
768
|
+
}, {
|
|
769
|
+
role: "user",
|
|
770
|
+
content: [{
|
|
771
|
+
type: "text",
|
|
772
|
+
text: shouldWrapUp ? "You have reached the context budget. Please wrap up your current work and provide a final summary of what was accomplished and what remains." : "Continue with your task."
|
|
773
|
+
}]
|
|
774
|
+
}];
|
|
775
|
+
messages.length = 0;
|
|
776
|
+
messages.push(...compactedMessages);
|
|
777
|
+
if (shouldWrapUp) {
|
|
778
|
+
const budgetMsg = consecutiveCompactions > MAX_CONSECUTIVE_COMPACTIONS ? "\n[Compaction loop detected — wrapping up.]" : "\n[Context budget reached — wrapping up.]";
|
|
779
|
+
if (emitter) {
|
|
780
|
+
emitter.emitText(budgetMsg);
|
|
781
|
+
} else {
|
|
782
|
+
callbacks.onText(budgetMsg);
|
|
783
|
+
}
|
|
392
784
|
}
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
785
|
+
iteration--; // Don't count compaction as an iteration
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// No tool calls — check if we should continue or stop
|
|
790
|
+
if (result.toolUseBlocks.length === 0) {
|
|
791
|
+
// If model hit max_tokens, it was truncated mid-response — continue so it can finish.
|
|
792
|
+
// Cap at MAX_CONTINUATIONS to prevent infinite loops on very large outputs (e.g. HTML reports).
|
|
793
|
+
if (result.stopReason === "max_tokens" && maxTokensContinuations < maxContinuations) {
|
|
794
|
+
maxTokensContinuations++;
|
|
795
|
+
const truncatedText = result.text || "";
|
|
796
|
+
const assistantContent = buildAssistantContent({
|
|
797
|
+
text: truncatedText,
|
|
798
|
+
toolUseBlocks: [],
|
|
799
|
+
thinkingBlocks: result.thinkingBlocks,
|
|
800
|
+
compactionContent: result.compactionContent
|
|
801
|
+
});
|
|
802
|
+
messages.push({
|
|
803
|
+
role: "assistant",
|
|
804
|
+
content: assistantContent
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// Escalating continuation prompts — if the model keeps hitting max_tokens,
|
|
808
|
+
// it's probably trying to write a large file. Guide it toward smaller chunks.
|
|
809
|
+
const continuationText = maxTokensContinuations === 1 ? "[Your response was truncated due to the output token limit. If you were writing a large file, split it into multiple smaller write_file calls (~200 lines each) or use run_command with a heredoc. Continue concisely.]" : `[Your response was truncated again (attempt ${maxTokensContinuations}/${maxContinuations}). You MUST reduce output size. For large files: use multiple write_file calls of ~100-200 lines each, or write via run_command. Do NOT attempt to write the entire file in one call.]`;
|
|
810
|
+
messages.push({
|
|
811
|
+
role: "user",
|
|
812
|
+
content: [{
|
|
813
|
+
type: "text",
|
|
814
|
+
text: continuationText
|
|
815
|
+
}]
|
|
816
|
+
});
|
|
817
|
+
continue;
|
|
399
818
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
// Emergency fallback only — compaction fires at 700K first; trim at 950K catches failures
|
|
438
|
-
cachedMessages = trimGeminiContext(cachedMessages, prevIterationInputTokens);
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
// Emergency fallback only — compaction fires at 120K first; trim at 190K catches failures
|
|
442
|
-
// GPT-4o: 128K context → 96K threshold (no compaction headroom)
|
|
443
|
-
const threshold = currentModel === "gpt-4o" ? 96_000 : 190_000;
|
|
444
|
-
cachedMessages = trimOpenAIContext(cachedMessages, prevIterationInputTokens, threshold);
|
|
445
|
-
}
|
|
446
|
-
// Notify UI when trimming actually occurred (trim returns same ref if no-op)
|
|
447
|
-
if (cachedMessages !== preTrimMessages) {
|
|
448
|
-
// Count tool results before/after to report meaningful numbers
|
|
449
|
-
const countToolResults = (msgs) => msgs.reduce((sum, m) => sum + (Array.isArray(m.content)
|
|
450
|
-
? m.content.filter(b => b.type === "tool_result" && b.content !== "[trimmed]").length
|
|
451
|
-
: 0), 0);
|
|
452
|
-
const activeBefore = countToolResults(preTrimMessages);
|
|
453
|
-
const activeAfter = countToolResults(cachedMessages);
|
|
454
|
-
const estimatedSaved = Math.round(prevIterationInputTokens * ((activeBefore - activeAfter) / Math.max(activeBefore, 1)));
|
|
455
|
-
callbacks.onAutoCompact?.(activeBefore, activeAfter, estimatedSaved);
|
|
456
|
-
emitter?.emitCompact(activeBefore, activeAfter, estimatedSaved);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
// Get auth token
|
|
460
|
-
const token = await getValidToken();
|
|
461
|
-
if (!token) {
|
|
462
|
-
throw new Error("Not logged in. Run: whale login");
|
|
463
|
-
}
|
|
464
|
-
// Call server proxy with built-in retry
|
|
465
|
-
const originalModel = currentModel;
|
|
466
|
-
const stream = await callServerProxy({
|
|
467
|
-
proxyUrl: getProxyUrl(),
|
|
468
|
-
token,
|
|
469
|
-
model: currentModel,
|
|
470
|
-
system,
|
|
471
|
-
messages: cachedMessages,
|
|
472
|
-
tools: cachedTools,
|
|
473
|
-
apiConfig,
|
|
474
|
-
signal: abortSignal,
|
|
475
|
-
fallbackModel: opts.fallbackModel,
|
|
476
|
-
storeId: storeId || undefined,
|
|
477
|
-
onFallback: (from, to) => {
|
|
478
|
-
setModel(to);
|
|
479
|
-
logSpan({ action: "claude_api_fallback", durationMs: 0, context: { ...turnCtx, spanId: apiSpanId }, storeId: storeId || undefined, details: { from_model: from, to_model: to } });
|
|
480
|
-
},
|
|
481
|
-
onRetry: (attempt, max, err) => {
|
|
482
|
-
const msg = `\n\x1b[33m\u21BB Retrying (${attempt}/${max})... ${err.slice(0, 80)}\x1b[0m\n`;
|
|
483
|
-
if (emitter) {
|
|
484
|
-
emitter.emitText(msg);
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
callbacks.onText(msg);
|
|
488
|
-
}
|
|
489
|
-
},
|
|
490
|
-
onTokenRefresh: async () => {
|
|
491
|
-
const result = await refreshSession();
|
|
492
|
-
return result.success ? result.config.access_token : null;
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
// Process stream events with UI callbacks
|
|
496
|
-
let thinkingChunks = 0;
|
|
497
|
-
const result = await processStreamWithCallbacks(parseSSEStream(stream, abortSignal), {
|
|
498
|
-
onText: (text) => {
|
|
499
|
-
if (emitter) {
|
|
500
|
-
emitter.emitText(text);
|
|
501
|
-
}
|
|
502
|
-
else {
|
|
503
|
-
callbacks.onText(text);
|
|
504
|
-
}
|
|
505
|
-
},
|
|
506
|
-
onThinking: () => {
|
|
507
|
-
thinkingChunks++;
|
|
508
|
-
emitter?.emitThinking(thinkingChunks);
|
|
509
|
-
},
|
|
510
|
-
onToolStart: (name, input) => {
|
|
511
|
-
// NOTE: Do NOT call callbacks.onToolStart here — dispatchTools.onStart
|
|
512
|
-
// fires it once per tool at execution time. Calling it here too would
|
|
513
|
-
// send duplicate tool_start events (stale spinners in WhaleChat).
|
|
514
|
-
if (input) {
|
|
515
|
-
// Tool block complete — emit structured start for CLI TUI only
|
|
516
|
-
emitter?.emitToolStart("", name);
|
|
517
|
-
}
|
|
518
|
-
},
|
|
519
|
-
}, abortSignal);
|
|
520
|
-
// Flush buffered text
|
|
521
|
-
emitter?.flushText();
|
|
522
|
-
// Restore original model after transient fallback
|
|
523
|
-
if (getModel() !== originalModel && opts.fallbackModel) {
|
|
524
|
-
setModelById(originalModel);
|
|
525
|
-
}
|
|
526
|
-
// Update session token tracking
|
|
527
|
-
sessionInputTokens += result.usage.inputTokens;
|
|
528
|
-
sessionOutputTokens += result.usage.outputTokens;
|
|
529
|
-
prevIterationInputTokens = result.usage.inputTokens; // Actual context size for next trim check
|
|
530
|
-
// Emit usage with model + cost context for all providers
|
|
531
|
-
if (emitter && (result.usage.inputTokens > 0 || result.usage.outputTokens > 0)) {
|
|
532
|
-
const iterCost = estimateCostUsd(result.usage.inputTokens, result.usage.outputTokens, currentModel, result.thinkingTokens, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
533
|
-
emitter.emitUsage(result.usage.inputTokens, result.usage.outputTokens, currentModel, iterCost, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
534
|
-
}
|
|
535
|
-
totalIn += result.usage.inputTokens;
|
|
536
|
-
totalOut += result.usage.outputTokens;
|
|
537
|
-
totalCacheCreation += result.usage.cacheCreationTokens;
|
|
538
|
-
totalCacheRead += result.usage.cacheReadTokens;
|
|
539
|
-
totalThinking += result.thinkingTokens;
|
|
540
|
-
sessionCostUsd += estimateCostUsd(result.usage.inputTokens, result.usage.outputTokens, currentModel, result.thinkingTokens, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
541
|
-
// Graduated cost warnings
|
|
542
|
-
emitCostWarningIfNeeded(sessionCostUsd, effectiveBudget, costWarningsEmitted, (text) => { if (emitter) {
|
|
543
|
-
emitter.emitText(text);
|
|
544
|
-
}
|
|
545
|
-
else {
|
|
546
|
-
callbacks.onText(text);
|
|
547
|
-
} });
|
|
548
|
-
// Server-side context management notification
|
|
549
|
-
if (result.contextManagementApplied) {
|
|
550
|
-
callbacks.onAutoCompact?.(messages.length, messages.length, 0);
|
|
551
|
-
emitter?.emitCompact(messages.length, messages.length, 0);
|
|
552
|
-
logSpan({ action: "chat.api_compaction", durationMs: Date.now() - apiStart, context: turnCtx, storeId: storeId || undefined, details: { type: "server_side", has_compaction_content: result.compactionContent !== null, iteration } });
|
|
553
|
-
}
|
|
554
|
-
if (result.text)
|
|
555
|
-
allAssistantText.push(result.text);
|
|
556
|
-
// Telemetry: API call span
|
|
557
|
-
const iterCostUsd = estimateCostUsd(result.usage.inputTokens, result.usage.outputTokens, currentModel, result.thinkingTokens, result.usage.cacheReadTokens, result.usage.cacheCreationTokens);
|
|
558
|
-
logSpan({
|
|
559
|
-
action: "claude_api_request",
|
|
560
|
-
durationMs: Date.now() - apiStart,
|
|
561
|
-
context: { ...turnCtx, spanId: apiSpanId, rowId: apiRowId, inputTokens: result.usage.inputTokens, outputTokens: result.usage.outputTokens, totalCost: iterCostUsd, model: currentModel },
|
|
562
|
-
storeId: storeId || undefined,
|
|
563
|
-
details: {
|
|
564
|
-
"gen_ai.request.model": currentModel,
|
|
565
|
-
"gen_ai.usage.input_tokens": result.usage.inputTokens,
|
|
566
|
-
"gen_ai.usage.output_tokens": result.usage.outputTokens,
|
|
567
|
-
"gen_ai.usage.cache_creation_tokens": result.usage.cacheCreationTokens,
|
|
568
|
-
"gen_ai.usage.cache_read_tokens": result.usage.cacheReadTokens,
|
|
569
|
-
"gen_ai.usage.cost": iterCostUsd,
|
|
570
|
-
stop_reason: result.stopReason === "compaction" ? "compaction" : result.toolUseBlocks.length > 0 ? "tool_use" : "end_turn",
|
|
571
|
-
iteration,
|
|
572
|
-
tool_count: result.toolUseBlocks.length,
|
|
573
|
-
tool_names: result.toolUseBlocks.map(t => t.name),
|
|
574
|
-
},
|
|
575
|
-
});
|
|
576
|
-
// Compaction handling — API paused after generating summary.
|
|
577
|
-
// Preserve last 2 messages for continuity, then resume.
|
|
578
|
-
if (result.stopReason === "compaction" && result.compactionContent) {
|
|
579
|
-
compactionCount++;
|
|
580
|
-
logSpan({ action: "chat.compaction_pause", durationMs: Date.now() - apiStart, context: turnCtx, storeId: storeId || undefined, details: { compaction_count: compactionCount, messages_before: messages.length } });
|
|
581
|
-
// Budget enforcement
|
|
582
|
-
if (compactionCount * effectiveCompactionTrigger >= effectiveCompactionBudget) {
|
|
583
|
-
const budgetMsg = "\n[Context budget reached — wrapping up.]";
|
|
584
|
-
if (emitter) {
|
|
585
|
-
emitter.emitText(budgetMsg);
|
|
586
|
-
}
|
|
587
|
-
else {
|
|
588
|
-
callbacks.onText(budgetMsg);
|
|
589
|
-
}
|
|
590
|
-
const compactedMessages = [
|
|
591
|
-
{ role: "assistant", content: [{ type: "compaction", content: result.compactionContent }] },
|
|
592
|
-
{ role: "user", content: [{ type: "text", text: "You have reached the context budget. Please wrap up your current work and provide a final summary of what was accomplished and what remains." }] },
|
|
593
|
-
];
|
|
594
|
-
messages.length = 0;
|
|
595
|
-
messages.push(...compactedMessages);
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
// Normal compaction: preserve last 2 messages for continuity
|
|
599
|
-
const preserved = messages.slice(-2);
|
|
600
|
-
const compactedMessages = [
|
|
601
|
-
{ role: "assistant", content: [{ type: "compaction", content: result.compactionContent }] },
|
|
602
|
-
...preserved,
|
|
603
|
-
];
|
|
604
|
-
messages.length = 0;
|
|
605
|
-
messages.push(...compactedMessages);
|
|
606
|
-
iteration--; // Don't count compaction as an iteration
|
|
607
|
-
continue;
|
|
608
|
-
}
|
|
609
|
-
// No tool calls — check if we should continue or stop
|
|
610
|
-
if (result.toolUseBlocks.length === 0) {
|
|
611
|
-
// If model hit max_tokens, it was truncated mid-response — continue so it can finish
|
|
612
|
-
if (result.stopReason === "max_tokens") {
|
|
613
|
-
const truncatedText = result.text || "";
|
|
614
|
-
const assistantContent = buildAssistantContent({
|
|
615
|
-
text: truncatedText,
|
|
616
|
-
toolUseBlocks: [],
|
|
617
|
-
thinkingBlocks: result.thinkingBlocks,
|
|
618
|
-
compactionContent: result.compactionContent,
|
|
619
|
-
});
|
|
620
|
-
messages.push({ role: "assistant", content: assistantContent });
|
|
621
|
-
messages.push({ role: "user", content: [{ type: "text", text: "[Your response was truncated due to length. Please continue where you left off.]" }] });
|
|
622
|
-
continue;
|
|
623
|
-
}
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
// Execute tools via shared dispatch
|
|
627
|
-
const { results: toolResults, bailOut, bailMessage } = await dispatchTools(result.toolUseBlocks, toolExecutor, {
|
|
628
|
-
loopDetector,
|
|
629
|
-
maxConcurrent: 7,
|
|
630
|
-
onStart: (name, input) => {
|
|
631
|
-
callbacks.onToolStart(name, input);
|
|
632
|
-
},
|
|
633
|
-
onResult: (name, success, output, durationMs) => {
|
|
634
|
-
callbacks.onToolResult(name, success, output, undefined, durationMs);
|
|
635
|
-
logSpan({
|
|
636
|
-
action: `tool.${name}`,
|
|
637
|
-
durationMs,
|
|
638
|
-
context: { ...turnCtx, spanId: generateSpanId(), parentSpanId: apiSpanId, parentId: apiRowId },
|
|
639
|
-
storeId: storeId || undefined,
|
|
640
|
-
error: success ? undefined : output,
|
|
641
|
-
details: {
|
|
642
|
-
tool_input: {},
|
|
643
|
-
tool_result: truncateResult(output, 2000),
|
|
644
|
-
error_type: success ? undefined : classifyToolError(output),
|
|
645
|
-
iteration,
|
|
646
|
-
},
|
|
647
|
-
});
|
|
648
|
-
},
|
|
649
|
-
signal: abortSignal,
|
|
650
|
-
transcribeAudio: storeId
|
|
651
|
-
? async (base64, mediaType) => callTranscribe({
|
|
652
|
-
proxyUrl: getProxyUrl(),
|
|
653
|
-
token,
|
|
654
|
-
storeId: storeId,
|
|
655
|
-
audioBase64: base64,
|
|
656
|
-
mediaType,
|
|
657
|
-
})
|
|
658
|
-
: undefined,
|
|
659
|
-
});
|
|
660
|
-
if (bailOut) {
|
|
661
|
-
logSpan({ action: "chat.bail_out", durationMs: Date.now() - sessionStart, context: turnCtx, storeId: storeId || undefined, severity: "warn", details: { ...loopDetector.getSessionStats(), message: bailMessage, iteration } });
|
|
662
|
-
}
|
|
663
|
-
// Shell output summarization — summarize long bash output to save context window
|
|
664
|
-
const toolNameMap = new Map(result.toolUseBlocks.map(t => [t.id, t.name]));
|
|
665
|
-
const finalToolResults = await summarizeLongToolResults(toolResults, toolNameMap, getProxyUrl(), token, shellSummarization, storeId || undefined);
|
|
666
|
-
// Build assistant content and append to conversation
|
|
667
|
-
const assistantContent = buildAssistantContent({
|
|
668
|
-
text: result.text,
|
|
669
|
-
toolUseBlocks: result.toolUseBlocks,
|
|
670
|
-
thinkingBlocks: result.thinkingBlocks,
|
|
671
|
-
compactionContent: result.compactionContent,
|
|
672
|
-
});
|
|
673
|
-
messages.push({ role: "assistant", content: assistantContent });
|
|
674
|
-
// Check for __PLAN_APPROVED_CLEAN__ marker — clear context and start fresh with just the plan
|
|
675
|
-
const planCleanMarker = "__PLAN_APPROVED_CLEAN__\n";
|
|
676
|
-
const hasCleanPlanApproval = finalToolResults.some((tr) => {
|
|
677
|
-
const content = typeof tr.content === "string" ? tr.content : "";
|
|
678
|
-
return content.startsWith(planCleanMarker);
|
|
679
|
-
});
|
|
680
|
-
if (hasCleanPlanApproval) {
|
|
681
|
-
// Extract plan content from the marker
|
|
682
|
-
const planResult = finalToolResults.find((tr) => {
|
|
683
|
-
const content = typeof tr.content === "string" ? tr.content : "";
|
|
684
|
-
return content.startsWith(planCleanMarker);
|
|
685
|
-
});
|
|
686
|
-
const planText = planResult.content.slice(planCleanMarker.length);
|
|
687
|
-
const beforeCount = messages.length;
|
|
688
|
-
messages.length = 0;
|
|
689
|
-
messages.push({ role: "user", content: [{ type: "text", text: `Implement this plan:\n\n${planText}` }] });
|
|
690
|
-
callbacks.onAutoCompact?.(beforeCount, 1, 0);
|
|
691
|
-
continue;
|
|
692
|
-
}
|
|
693
|
-
messages.push({ role: "user", content: finalToolResults });
|
|
694
|
-
// Non-native compaction for OpenAI/Gemini — fires after tool results appended
|
|
695
|
-
const compactionCfg = getCompactionConfig(currentModel);
|
|
696
|
-
if (!compactionCfg.isNative && result.usage.inputTokens >= compactionCfg.triggerTokens) {
|
|
697
|
-
compactionCount++;
|
|
698
|
-
if (compactionCount * compactionCfg.triggerTokens >= compactionCfg.totalBudget) {
|
|
699
|
-
// Budget exhaustion — force wrap-up (same as native compaction budget logic)
|
|
700
|
-
const budgetMsg = "\n[Context budget reached — wrapping up.]";
|
|
701
|
-
if (emitter) {
|
|
702
|
-
emitter.emitText(budgetMsg);
|
|
703
|
-
}
|
|
704
|
-
else {
|
|
705
|
-
callbacks.onText(budgetMsg);
|
|
706
|
-
}
|
|
707
|
-
const summary = await requestProviderCompaction({
|
|
708
|
-
proxyUrl: getProxyUrl(),
|
|
709
|
-
token,
|
|
710
|
-
messages: messages,
|
|
711
|
-
systemPrompt,
|
|
712
|
-
});
|
|
713
|
-
const compactedMessages = [
|
|
714
|
-
...(summary
|
|
715
|
-
? [{ role: "assistant", content: [{ type: "compaction", content: summary }] }]
|
|
716
|
-
: []),
|
|
717
|
-
{ role: "user", content: [{ type: "text", text: "You have reached the context budget. Please wrap up your current work and provide a final summary of what was accomplished and what remains." }] },
|
|
718
|
-
];
|
|
719
|
-
messages.length = 0;
|
|
720
|
-
messages.push(...compactedMessages);
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
// Normal compaction — summarize and preserve last 2 messages
|
|
724
|
-
const summary = await requestProviderCompaction({
|
|
725
|
-
proxyUrl: getProxyUrl(),
|
|
726
|
-
token,
|
|
727
|
-
messages: messages,
|
|
728
|
-
systemPrompt,
|
|
729
|
-
});
|
|
730
|
-
if (summary) {
|
|
731
|
-
const preserved = messages.slice(-2);
|
|
732
|
-
const compactedMessages = [
|
|
733
|
-
{ role: "assistant", content: [{ type: "compaction", content: summary }] },
|
|
734
|
-
...preserved,
|
|
735
|
-
];
|
|
736
|
-
messages.length = 0;
|
|
737
|
-
messages.push(...compactedMessages);
|
|
738
|
-
iteration--; // Don't count compaction as an iteration
|
|
739
|
-
callbacks.onAutoCompact?.(messages.length + preserved.length, messages.length, Math.round(result.usage.inputTokens * 0.7));
|
|
740
|
-
emitter?.emitCompact(messages.length + preserved.length, messages.length, Math.round(result.usage.inputTokens * 0.7));
|
|
741
|
-
logSpan({ action: "chat.provider_compaction", durationMs: 0, context: turnCtx, storeId: storeId || undefined, details: { compaction_count: compactionCount, provider, model: currentModel, input_tokens: result.usage.inputTokens, trigger_tokens: compactionCfg.triggerTokens } });
|
|
742
|
-
}
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Reset counters — model is taking tool actions, making progress
|
|
823
|
+
maxTokensContinuations = 0;
|
|
824
|
+
consecutiveCompactions = 0;
|
|
825
|
+
|
|
826
|
+
// Execute tools via shared dispatch
|
|
827
|
+
const {
|
|
828
|
+
results: toolResults,
|
|
829
|
+
bailOut,
|
|
830
|
+
bailMessage
|
|
831
|
+
} = await dispatchTools(result.toolUseBlocks, toolExecutor, {
|
|
832
|
+
loopDetector,
|
|
833
|
+
maxConcurrent: resolved?.maxConcurrentTools ?? AGENT_DEFAULTS.maxConcurrentTools,
|
|
834
|
+
batchErrorLimit: resolved?.loopBatchErrorLimit ?? AGENT_DEFAULTS.loopBatchErrorLimit,
|
|
835
|
+
onStart: (name, input) => {
|
|
836
|
+
callbacks.onToolStart(name, input);
|
|
837
|
+
},
|
|
838
|
+
onResult: (name, success, output, durationMs) => {
|
|
839
|
+
callbacks.onToolResult(name, success, output, undefined, durationMs);
|
|
840
|
+
logSpan({
|
|
841
|
+
action: `tool.${name}`,
|
|
842
|
+
durationMs,
|
|
843
|
+
context: {
|
|
844
|
+
...turnCtx,
|
|
845
|
+
spanId: generateSpanId(),
|
|
846
|
+
parentSpanId: apiSpanId,
|
|
847
|
+
parentId: apiRowId
|
|
848
|
+
},
|
|
849
|
+
storeId: storeId || undefined,
|
|
850
|
+
error: success ? undefined : output,
|
|
851
|
+
details: {
|
|
852
|
+
tool_input: {},
|
|
853
|
+
tool_result: truncateResult(output, 2000),
|
|
854
|
+
error_type: success ? undefined : classifyToolError(output),
|
|
855
|
+
iteration
|
|
743
856
|
}
|
|
744
|
-
|
|
745
|
-
|
|
857
|
+
});
|
|
858
|
+
},
|
|
859
|
+
signal: abortSignal,
|
|
860
|
+
transcribeAudio: storeId ? async (base64, mediaType) => callTranscribe({
|
|
861
|
+
proxyUrl: getProxyUrl(),
|
|
862
|
+
token,
|
|
863
|
+
storeId: storeId,
|
|
864
|
+
audioBase64: base64,
|
|
865
|
+
mediaType
|
|
866
|
+
}) : undefined
|
|
867
|
+
});
|
|
868
|
+
if (bailOut) {
|
|
746
869
|
logSpan({
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
870
|
+
action: "chat.bail_out",
|
|
871
|
+
durationMs: Date.now() - sessionStart,
|
|
872
|
+
context: turnCtx,
|
|
873
|
+
storeId: storeId || undefined,
|
|
874
|
+
severity: "warn",
|
|
875
|
+
details: {
|
|
876
|
+
...loopDetector.getSessionStats(),
|
|
877
|
+
message: bailMessage,
|
|
878
|
+
iteration
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// Shell output summarization — summarize long bash output to save context window
|
|
884
|
+
const toolNameMap = new Map(result.toolUseBlocks.map(t => [t.id, t.name]));
|
|
885
|
+
const finalToolResults = await summarizeLongToolResults(toolResults, toolNameMap, getProxyUrl(), token, shellSummarization, storeId || undefined);
|
|
886
|
+
|
|
887
|
+
// Build assistant content and append to conversation
|
|
888
|
+
const assistantContent = buildAssistantContent({
|
|
889
|
+
text: result.text,
|
|
890
|
+
toolUseBlocks: result.toolUseBlocks,
|
|
891
|
+
thinkingBlocks: result.thinkingBlocks,
|
|
892
|
+
compactionContent: result.compactionContent
|
|
893
|
+
});
|
|
894
|
+
messages.push({
|
|
895
|
+
role: "assistant",
|
|
896
|
+
content: assistantContent
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// Check for __PLAN_APPROVED_CLEAN__ marker — clear context and start fresh with just the plan
|
|
900
|
+
const planCleanMarker = "__PLAN_APPROVED_CLEAN__\n";
|
|
901
|
+
const hasCleanPlanApproval = finalToolResults.some(tr => {
|
|
902
|
+
const content = typeof tr.content === "string" ? tr.content : "";
|
|
903
|
+
return content.startsWith(planCleanMarker);
|
|
904
|
+
});
|
|
905
|
+
if (hasCleanPlanApproval) {
|
|
906
|
+
// Extract plan content from the marker
|
|
907
|
+
const planResult = finalToolResults.find(tr => {
|
|
908
|
+
const content = typeof tr.content === "string" ? tr.content : "";
|
|
909
|
+
return content.startsWith(planCleanMarker);
|
|
910
|
+
});
|
|
911
|
+
const planText = planResult.content.slice(planCleanMarker.length);
|
|
912
|
+
const beforeCount = messages.length;
|
|
913
|
+
messages.length = 0;
|
|
914
|
+
messages.push({
|
|
915
|
+
role: "user",
|
|
916
|
+
content: [{
|
|
917
|
+
type: "text",
|
|
918
|
+
text: `Implement this plan:\n\n${planText}`
|
|
919
|
+
}]
|
|
920
|
+
});
|
|
921
|
+
callbacks.onAutoCompact?.(beforeCount, 1, 0);
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
messages.push({
|
|
925
|
+
role: "user",
|
|
926
|
+
content: finalToolResults
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
// Non-native compaction for OpenAI/Gemini — fires after tool results appended
|
|
930
|
+
const compactionCfg = getCompactionConfig(currentModel);
|
|
931
|
+
if (!compactionCfg.isNative && result.usage.inputTokens >= compactionCfg.triggerTokens) {
|
|
932
|
+
compactionCount++;
|
|
933
|
+
if (compactionCount * compactionCfg.triggerTokens >= compactionCfg.totalBudget) {
|
|
934
|
+
// Budget exhaustion — force wrap-up (same as native compaction budget logic)
|
|
935
|
+
const budgetMsg = "\n[Context budget reached — wrapping up.]";
|
|
936
|
+
if (emitter) {
|
|
937
|
+
emitter.emitText(budgetMsg);
|
|
938
|
+
} else {
|
|
939
|
+
callbacks.onText(budgetMsg);
|
|
940
|
+
}
|
|
941
|
+
const summary = await requestProviderCompaction({
|
|
942
|
+
proxyUrl: getProxyUrl(),
|
|
943
|
+
token,
|
|
944
|
+
messages,
|
|
945
|
+
systemPrompt
|
|
946
|
+
});
|
|
947
|
+
const compactedMessages = [...(summary ? [{
|
|
948
|
+
role: "assistant",
|
|
949
|
+
content: [{
|
|
950
|
+
type: "compaction",
|
|
951
|
+
content: summary
|
|
952
|
+
}]
|
|
953
|
+
}] : []), {
|
|
954
|
+
role: "user",
|
|
955
|
+
content: [{
|
|
956
|
+
type: "text",
|
|
957
|
+
text: "You have reached the context budget. Please wrap up your current work and provide a final summary of what was accomplished and what remains."
|
|
958
|
+
}]
|
|
959
|
+
}];
|
|
960
|
+
messages.length = 0;
|
|
961
|
+
messages.push(...compactedMessages);
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// Normal compaction — summarize, don't preserve old messages (prevents loop)
|
|
966
|
+
const summary = await requestProviderCompaction({
|
|
967
|
+
proxyUrl: getProxyUrl(),
|
|
968
|
+
token,
|
|
969
|
+
messages: messages,
|
|
970
|
+
systemPrompt
|
|
971
|
+
});
|
|
972
|
+
if (summary) {
|
|
973
|
+
const beforeCount = messages.length;
|
|
974
|
+
const compactedMessages = [{
|
|
975
|
+
role: "assistant",
|
|
976
|
+
content: [{
|
|
977
|
+
type: "compaction",
|
|
978
|
+
content: summary
|
|
979
|
+
}]
|
|
980
|
+
}, {
|
|
981
|
+
role: "user",
|
|
982
|
+
content: [{
|
|
983
|
+
type: "text",
|
|
984
|
+
text: "Continue with your task."
|
|
985
|
+
}]
|
|
986
|
+
}];
|
|
987
|
+
messages.length = 0;
|
|
988
|
+
messages.push(...compactedMessages);
|
|
989
|
+
iteration--; // Don't count compaction as an iteration
|
|
990
|
+
|
|
991
|
+
callbacks.onAutoCompact?.(beforeCount, messages.length, Math.round(result.usage.inputTokens * 0.7));
|
|
992
|
+
emitter?.emitCompact(beforeCount, messages.length, Math.round(result.usage.inputTokens * 0.7));
|
|
993
|
+
logSpan({
|
|
994
|
+
action: "chat.provider_compaction",
|
|
995
|
+
durationMs: 0,
|
|
996
|
+
context: turnCtx,
|
|
750
997
|
storeId: storeId || undefined,
|
|
751
998
|
details: {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
callbacks.onUsage(totalIn, totalOut, totalThinking, activeModel, turnCostUsd, totalCacheRead, totalCacheCreation);
|
|
760
|
-
// Flush telemetry spans to server before session ends
|
|
761
|
-
flushCliSpans();
|
|
762
|
-
// Fire SessionEnd hook (non-blocking)
|
|
763
|
-
if (hooks.length > 0) {
|
|
764
|
-
runSessionHook(hooks, "SessionEnd", { session_id: `turn-${sessionStart}` }).catch(() => { });
|
|
999
|
+
compaction_count: compactionCount,
|
|
1000
|
+
provider,
|
|
1001
|
+
model: currentModel,
|
|
1002
|
+
input_tokens: result.usage.inputTokens,
|
|
1003
|
+
trigger_tokens: compactionCfg.triggerTokens
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
765
1006
|
}
|
|
766
|
-
|
|
767
|
-
emitter?.emitDone(finalText, messages);
|
|
768
|
-
if (emitter)
|
|
769
|
-
clearGlobalEmitter();
|
|
770
|
-
callbacks.onDone(messages);
|
|
1007
|
+
}
|
|
771
1008
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
1009
|
+
|
|
1010
|
+
// Telemetry: session summary
|
|
1011
|
+
logSpan({
|
|
1012
|
+
action: "chat.session_complete",
|
|
1013
|
+
durationMs: Date.now() - sessionStart,
|
|
1014
|
+
context: {
|
|
1015
|
+
...turnCtx,
|
|
1016
|
+
inputTokens: totalIn,
|
|
1017
|
+
outputTokens: totalOut,
|
|
1018
|
+
model: activeModel
|
|
1019
|
+
},
|
|
1020
|
+
storeId: storeId || undefined,
|
|
1021
|
+
details: {
|
|
1022
|
+
input_tokens: totalIn,
|
|
1023
|
+
output_tokens: totalOut,
|
|
1024
|
+
total_tokens: totalIn + totalOut,
|
|
1025
|
+
cache_creation_tokens: totalCacheCreation,
|
|
1026
|
+
cache_read_tokens: totalCacheRead,
|
|
1027
|
+
session_input_tokens: sessionInputTokens,
|
|
1028
|
+
session_output_tokens: sessionOutputTokens,
|
|
1029
|
+
model: activeModel
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
const turnCostUsd = estimateCostUsd(totalIn, totalOut, activeModel, totalThinking, totalCacheRead, totalCacheCreation);
|
|
1033
|
+
callbacks.onUsage(totalIn, totalOut, totalThinking, activeModel, turnCostUsd, totalCacheRead, totalCacheCreation);
|
|
1034
|
+
|
|
1035
|
+
// Flush telemetry spans to server before session ends
|
|
1036
|
+
flushCliSpans();
|
|
1037
|
+
|
|
1038
|
+
// Fire SessionEnd hook (non-blocking)
|
|
1039
|
+
if (hooks.length > 0) {
|
|
1040
|
+
runSessionHook(hooks, "SessionEnd", {
|
|
1041
|
+
session_id: `turn-${sessionStart}`
|
|
1042
|
+
}).catch(() => {});
|
|
1043
|
+
}
|
|
1044
|
+
const finalText = allAssistantText.length > 0 ? allAssistantText[allAssistantText.length - 1] : "";
|
|
1045
|
+
emitter?.emitDone(finalText, messages);
|
|
1046
|
+
if (emitter) clearGlobalEmitter();
|
|
1047
|
+
callbacks.onDone(messages);
|
|
1048
|
+
} catch (err) {
|
|
1049
|
+
const errorMsg = abortSignal?.aborted || err?.message === "Cancelled" ? "Cancelled" : String(err?.message || err);
|
|
1050
|
+
logSpan({
|
|
1051
|
+
action: errorMsg === "Cancelled" ? "chat.cancelled" : "chat.fatal_error",
|
|
1052
|
+
durationMs: Date.now() - sessionStart,
|
|
1053
|
+
context: {
|
|
1054
|
+
...turnCtx,
|
|
1055
|
+
inputTokens: totalIn,
|
|
1056
|
+
outputTokens: totalOut,
|
|
1057
|
+
model: activeModel
|
|
1058
|
+
},
|
|
1059
|
+
storeId: storeId || undefined,
|
|
1060
|
+
severity: errorMsg === "Cancelled" ? "info" : "error",
|
|
1061
|
+
error: errorMsg === "Cancelled" ? undefined : errorMsg,
|
|
1062
|
+
details: {
|
|
1063
|
+
input_tokens: totalIn,
|
|
1064
|
+
output_tokens: totalOut,
|
|
1065
|
+
session_cost_usd: sessionCostUsd,
|
|
1066
|
+
model: activeModel
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
// Capture to error_events (not just audit_logs) for non-cancellations
|
|
1071
|
+
if (errorMsg !== "Cancelled") {
|
|
1072
|
+
captureError({
|
|
1073
|
+
error: err instanceof Error ? err : undefined,
|
|
1074
|
+
errorType: "AgentLoopError",
|
|
1075
|
+
errorMessage: errorMsg,
|
|
1076
|
+
severity: "error",
|
|
1077
|
+
traceId: turnCtx.traceId,
|
|
1078
|
+
spanId: turnCtx.spanId,
|
|
1079
|
+
storeId: storeId || undefined,
|
|
1080
|
+
tags: {
|
|
1081
|
+
model: activeModel,
|
|
1082
|
+
turn: String(turnNum)
|
|
797
1083
|
}
|
|
798
|
-
|
|
799
|
-
flushCliSpans();
|
|
800
|
-
emitter?.emitError(errorMsg);
|
|
801
|
-
if (emitter)
|
|
802
|
-
clearGlobalEmitter();
|
|
803
|
-
callbacks.onError(errorMsg, messages);
|
|
1084
|
+
});
|
|
804
1085
|
}
|
|
1086
|
+
|
|
1087
|
+
// Flush telemetry on error path too
|
|
1088
|
+
flushCliSpans();
|
|
1089
|
+
emitter?.emitError(errorMsg);
|
|
1090
|
+
if (emitter) clearGlobalEmitter();
|
|
1091
|
+
callbacks.onError(errorMsg, messages);
|
|
1092
|
+
}
|
|
805
1093
|
}
|
|
1094
|
+
|
|
806
1095
|
// ============================================================================
|
|
807
1096
|
// TELEMETRY HELPERS
|
|
808
1097
|
// ============================================================================
|
|
1098
|
+
|
|
809
1099
|
export function truncateResult(output, maxLen) {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
return output.slice(0, maxLen) + `... (${output.length} chars total)`;
|
|
1100
|
+
if (output.length <= maxLen) return output;
|
|
1101
|
+
return output.slice(0, maxLen) + `... (${output.length} chars total)`;
|
|
813
1102
|
}
|
|
814
1103
|
export function classifyToolError(output) {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (lower.includes("import") && lower.includes("error"))
|
|
825
|
-
return "import_error";
|
|
826
|
-
if (lower.includes("syntax") || lower.includes("parse"))
|
|
827
|
-
return "syntax_error";
|
|
828
|
-
if (lower.includes("externally-managed"))
|
|
829
|
-
return "env_managed";
|
|
830
|
-
return "unknown";
|
|
1104
|
+
const lower = output.toLowerCase();
|
|
1105
|
+
if (lower.includes("timed out") || lower.includes("timeout")) return "timeout";
|
|
1106
|
+
if (lower.includes("permission denied") || lower.includes("eacces")) return "permission";
|
|
1107
|
+
if (lower.includes("not found") || lower.includes("no such file")) return "not_found";
|
|
1108
|
+
if (lower.includes("command not found") || lower.includes("exit code 127")) return "command_not_found";
|
|
1109
|
+
if (lower.includes("import") && lower.includes("error")) return "import_error";
|
|
1110
|
+
if (lower.includes("syntax") || lower.includes("parse")) return "syntax_error";
|
|
1111
|
+
if (lower.includes("externally-managed")) return "env_managed";
|
|
1112
|
+
return "unknown";
|
|
831
1113
|
}
|
|
1114
|
+
|
|
832
1115
|
// Convenience: check if user can use the agent (logged in OR has API key)
|
|
833
1116
|
export function canUseAgent() {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1117
|
+
const config = loadConfig();
|
|
1118
|
+
const hasToken = !!(config.access_token && config.refresh_token);
|
|
1119
|
+
const hasApiKey = !!(process.env.ANTHROPIC_API_KEY || config.anthropic_api_key);
|
|
1120
|
+
if (hasToken || hasApiKey) return {
|
|
1121
|
+
ready: true
|
|
1122
|
+
};
|
|
1123
|
+
return {
|
|
1124
|
+
ready: false,
|
|
1125
|
+
reason: "Run `whale login` to authenticate."
|
|
1126
|
+
};
|
|
840
1127
|
}
|
|
1128
|
+
//# sourceMappingURL=agent-loop.js.map
|