deepseek-coder-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +422 -0
- package/agents/agi-code.rules.json +87 -0
- package/agents/general.rules.json +171 -0
- package/dist/bin/cliMode.d.ts +8 -0
- package/dist/bin/cliMode.d.ts.map +1 -0
- package/dist/bin/cliMode.js +20 -0
- package/dist/bin/cliMode.js.map +1 -0
- package/dist/bin/deepseek.d.ts +16 -0
- package/dist/bin/deepseek.d.ts.map +1 -0
- package/dist/bin/deepseek.js +737 -0
- package/dist/bin/deepseek.js.map +1 -0
- package/dist/bin/erosolar.d.ts +7 -0
- package/dist/bin/erosolar.d.ts.map +1 -0
- package/dist/bin/erosolar.js +7 -0
- package/dist/bin/erosolar.js.map +1 -0
- package/dist/bin/selfTest.d.ts +14 -0
- package/dist/bin/selfTest.d.ts.map +1 -0
- package/dist/bin/selfTest.js +304 -0
- package/dist/bin/selfTest.js.map +1 -0
- package/dist/capabilities/appleSecurityCapability.d.ts +57 -0
- package/dist/capabilities/appleSecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/appleSecurityCapability.js +197 -0
- package/dist/capabilities/appleSecurityCapability.js.map +1 -0
- package/dist/capabilities/authorizedSecurityCapability.d.ts +17 -0
- package/dist/capabilities/authorizedSecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/authorizedSecurityCapability.js +333 -0
- package/dist/capabilities/authorizedSecurityCapability.js.map +1 -0
- package/dist/capabilities/autoEnhancementCapability.d.ts +98 -0
- package/dist/capabilities/autoEnhancementCapability.d.ts.map +1 -0
- package/dist/capabilities/autoEnhancementCapability.js +455 -0
- package/dist/capabilities/autoEnhancementCapability.js.map +1 -0
- package/dist/capabilities/baseCapability.d.ts +72 -0
- package/dist/capabilities/baseCapability.d.ts.map +1 -0
- package/dist/capabilities/baseCapability.js +183 -0
- package/dist/capabilities/baseCapability.js.map +1 -0
- package/dist/capabilities/bashCapability.d.ts +13 -0
- package/dist/capabilities/bashCapability.d.ts.map +1 -0
- package/dist/capabilities/bashCapability.js +24 -0
- package/dist/capabilities/bashCapability.js.map +1 -0
- package/dist/capabilities/biocognitiveWarfare.d.ts +136 -0
- package/dist/capabilities/biocognitiveWarfare.d.ts.map +1 -0
- package/dist/capabilities/biocognitiveWarfare.js +603 -0
- package/dist/capabilities/biocognitiveWarfare.js.map +1 -0
- package/dist/capabilities/chineseCnoIntegration.d.ts +60 -0
- package/dist/capabilities/chineseCnoIntegration.d.ts.map +1 -0
- package/dist/capabilities/chineseCnoIntegration.js +253 -0
- package/dist/capabilities/chineseCnoIntegration.js.map +1 -0
- package/dist/capabilities/cnoCapability.d.ts +110 -0
- package/dist/capabilities/cnoCapability.d.ts.map +1 -0
- package/dist/capabilities/cnoCapability.js +785 -0
- package/dist/capabilities/cnoCapability.js.map +1 -0
- package/dist/capabilities/editCapability.d.ts +17 -0
- package/dist/capabilities/editCapability.d.ts.map +1 -0
- package/dist/capabilities/editCapability.js +27 -0
- package/dist/capabilities/editCapability.js.map +1 -0
- package/dist/capabilities/eliteCryptoMilitaryCapability.d.ts +99 -0
- package/dist/capabilities/eliteCryptoMilitaryCapability.d.ts.map +1 -0
- package/dist/capabilities/eliteCryptoMilitaryCapability.js +618 -0
- package/dist/capabilities/eliteCryptoMilitaryCapability.js.map +1 -0
- package/dist/capabilities/enhancedGitCapability.d.ts +7 -0
- package/dist/capabilities/enhancedGitCapability.d.ts.map +1 -0
- package/dist/capabilities/enhancedGitCapability.js +220 -0
- package/dist/capabilities/enhancedGitCapability.js.map +1 -0
- package/dist/capabilities/filesystemCapability.d.ts +13 -0
- package/dist/capabilities/filesystemCapability.d.ts.map +1 -0
- package/dist/capabilities/filesystemCapability.js +24 -0
- package/dist/capabilities/filesystemCapability.js.map +1 -0
- package/dist/capabilities/gitHistoryCapability.d.ts +6 -0
- package/dist/capabilities/gitHistoryCapability.d.ts.map +1 -0
- package/dist/capabilities/gitHistoryCapability.js +160 -0
- package/dist/capabilities/gitHistoryCapability.js.map +1 -0
- package/dist/capabilities/index.d.ts +26 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +26 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/integratedUnifiedCapability.d.ts +105 -0
- package/dist/capabilities/integratedUnifiedCapability.d.ts.map +1 -0
- package/dist/capabilities/integratedUnifiedCapability.js +422 -0
- package/dist/capabilities/integratedUnifiedCapability.js.map +1 -0
- package/dist/capabilities/maxOffensiveUkraineCapability.d.ts +46 -0
- package/dist/capabilities/maxOffensiveUkraineCapability.d.ts.map +1 -0
- package/dist/capabilities/maxOffensiveUkraineCapability.js +725 -0
- package/dist/capabilities/maxOffensiveUkraineCapability.js.map +1 -0
- package/dist/capabilities/migrationUtilities.d.ts +128 -0
- package/dist/capabilities/migrationUtilities.d.ts.map +1 -0
- package/dist/capabilities/migrationUtilities.js +658 -0
- package/dist/capabilities/migrationUtilities.js.map +1 -0
- package/dist/capabilities/offensiveDestructionCapability.d.ts +98 -0
- package/dist/capabilities/offensiveDestructionCapability.d.ts.map +1 -0
- package/dist/capabilities/offensiveDestructionCapability.js +848 -0
- package/dist/capabilities/offensiveDestructionCapability.js.map +1 -0
- package/dist/capabilities/quantumSpaceWarfare.d.ts +108 -0
- package/dist/capabilities/quantumSpaceWarfare.d.ts.map +1 -0
- package/dist/capabilities/quantumSpaceWarfare.js +342 -0
- package/dist/capabilities/quantumSpaceWarfare.js.map +1 -0
- package/dist/capabilities/readmeIntegration.d.ts +161 -0
- package/dist/capabilities/readmeIntegration.d.ts.map +1 -0
- package/dist/capabilities/readmeIntegration.js +1034 -0
- package/dist/capabilities/readmeIntegration.js.map +1 -0
- package/dist/capabilities/searchCapability.d.ts +19 -0
- package/dist/capabilities/searchCapability.d.ts.map +1 -0
- package/dist/capabilities/searchCapability.js +29 -0
- package/dist/capabilities/searchCapability.js.map +1 -0
- package/dist/capabilities/selfUpdateSystem.d.ts +122 -0
- package/dist/capabilities/selfUpdateSystem.d.ts.map +1 -0
- package/dist/capabilities/selfUpdateSystem.js +725 -0
- package/dist/capabilities/selfUpdateSystem.js.map +1 -0
- package/dist/capabilities/sharedMilitaryInfrastructure.d.ts +89 -0
- package/dist/capabilities/sharedMilitaryInfrastructure.d.ts.map +1 -0
- package/dist/capabilities/sharedMilitaryInfrastructure.js +233 -0
- package/dist/capabilities/sharedMilitaryInfrastructure.js.map +1 -0
- package/dist/capabilities/simpleSecurityCapability.d.ts +36 -0
- package/dist/capabilities/simpleSecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/simpleSecurityCapability.js +271 -0
- package/dist/capabilities/simpleSecurityCapability.js.map +1 -0
- package/dist/capabilities/toolManifest.d.ts +3 -0
- package/dist/capabilities/toolManifest.d.ts.map +1 -0
- package/dist/capabilities/toolManifest.js +163 -0
- package/dist/capabilities/toolManifest.js.map +1 -0
- package/dist/capabilities/toolRegistry.d.ts +25 -0
- package/dist/capabilities/toolRegistry.d.ts.map +1 -0
- package/dist/capabilities/toolRegistry.js +150 -0
- package/dist/capabilities/toolRegistry.js.map +1 -0
- package/dist/capabilities/ultimateChineseCno.d.ts +115 -0
- package/dist/capabilities/ultimateChineseCno.d.ts.map +1 -0
- package/dist/capabilities/ultimateChineseCno.js +516 -0
- package/dist/capabilities/ultimateChineseCno.js.map +1 -0
- package/dist/capabilities/ultimateIntegrationDemo.d.ts +54 -0
- package/dist/capabilities/ultimateIntegrationDemo.d.ts.map +1 -0
- package/dist/capabilities/ultimateIntegrationDemo.js +423 -0
- package/dist/capabilities/ultimateIntegrationDemo.js.map +1 -0
- package/dist/capabilities/unifiedMilitaryCapability.d.ts +63 -0
- package/dist/capabilities/unifiedMilitaryCapability.d.ts.map +1 -0
- package/dist/capabilities/unifiedMilitaryCapability.js +384 -0
- package/dist/capabilities/unifiedMilitaryCapability.js.map +1 -0
- package/dist/capabilities/universalCapabilityFramework.d.ts +352 -0
- package/dist/capabilities/universalCapabilityFramework.d.ts.map +1 -0
- package/dist/capabilities/universalCapabilityFramework.js +1056 -0
- package/dist/capabilities/universalCapabilityFramework.js.map +1 -0
- package/dist/capabilities/universalSecurityCapability.d.ts +46 -0
- package/dist/capabilities/universalSecurityCapability.d.ts.map +1 -0
- package/dist/capabilities/universalSecurityCapability.js +580 -0
- package/dist/capabilities/universalSecurityCapability.js.map +1 -0
- package/dist/capabilities/webCapability.d.ts +23 -0
- package/dist/capabilities/webCapability.d.ts.map +1 -0
- package/dist/capabilities/webCapability.js +33 -0
- package/dist/capabilities/webCapability.js.map +1 -0
- package/dist/capabilities/zeroDayDiscoveryCapability.d.ts +31 -0
- package/dist/capabilities/zeroDayDiscoveryCapability.d.ts.map +1 -0
- package/dist/capabilities/zeroDayDiscoveryCapability.js +183 -0
- package/dist/capabilities/zeroDayDiscoveryCapability.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +155 -0
- package/dist/config.js.map +1 -0
- package/dist/contracts/agent-profiles.schema.json +43 -0
- package/dist/contracts/agent-schemas.json +466 -0
- package/dist/contracts/models.schema.json +9 -0
- package/dist/contracts/module-schema.json +430 -0
- package/dist/contracts/schemas/agent-profile.schema.json +157 -0
- package/dist/contracts/schemas/agent-rules.schema.json +238 -0
- package/dist/contracts/schemas/agent-schemas.schema.json +528 -0
- package/dist/contracts/schemas/agent.schema.json +90 -0
- package/dist/contracts/schemas/tool-selection.schema.json +174 -0
- package/dist/contracts/tools.schema.json +82 -0
- package/dist/contracts/unified-schema.json +757 -0
- package/dist/contracts/v1/agent.d.ts +179 -0
- package/dist/contracts/v1/agent.d.ts.map +1 -0
- package/dist/contracts/v1/agent.js +8 -0
- package/dist/contracts/v1/agent.js.map +1 -0
- package/dist/contracts/v1/agentProfileManifest.d.ts +60 -0
- package/dist/contracts/v1/agentProfileManifest.d.ts.map +1 -0
- package/dist/contracts/v1/agentProfileManifest.js +9 -0
- package/dist/contracts/v1/agentProfileManifest.js.map +1 -0
- package/dist/contracts/v1/agentRules.d.ts +60 -0
- package/dist/contracts/v1/agentRules.d.ts.map +1 -0
- package/dist/contracts/v1/agentRules.js +10 -0
- package/dist/contracts/v1/agentRules.js.map +1 -0
- package/dist/contracts/v1/provider.d.ts +149 -0
- package/dist/contracts/v1/provider.d.ts.map +1 -0
- package/dist/contracts/v1/provider.js +7 -0
- package/dist/contracts/v1/provider.js.map +1 -0
- package/dist/contracts/v1/tool.d.ts +136 -0
- package/dist/contracts/v1/tool.d.ts.map +1 -0
- package/dist/contracts/v1/tool.js +7 -0
- package/dist/contracts/v1/tool.js.map +1 -0
- package/dist/contracts/v1/toolAccess.d.ts +43 -0
- package/dist/contracts/v1/toolAccess.d.ts.map +1 -0
- package/dist/contracts/v1/toolAccess.js +9 -0
- package/dist/contracts/v1/toolAccess.js.map +1 -0
- package/dist/core/agent.d.ts +287 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +1563 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/agentProfileManifest.d.ts +3 -0
- package/dist/core/agentProfileManifest.d.ts.map +1 -0
- package/dist/core/agentProfileManifest.js +188 -0
- package/dist/core/agentProfileManifest.js.map +1 -0
- package/dist/core/agentProfiles.d.ts +22 -0
- package/dist/core/agentProfiles.d.ts.map +1 -0
- package/dist/core/agentProfiles.js +35 -0
- package/dist/core/agentProfiles.js.map +1 -0
- package/dist/core/agentRulebook.d.ts +11 -0
- package/dist/core/agentRulebook.d.ts.map +1 -0
- package/dist/core/agentRulebook.js +136 -0
- package/dist/core/agentRulebook.js.map +1 -0
- package/dist/core/agentSchemaLoader.d.ts +131 -0
- package/dist/core/agentSchemaLoader.d.ts.map +1 -0
- package/dist/core/agentSchemaLoader.js +235 -0
- package/dist/core/agentSchemaLoader.js.map +1 -0
- package/dist/core/agiCore.d.ts +290 -0
- package/dist/core/agiCore.d.ts.map +1 -0
- package/dist/core/agiCore.js +1348 -0
- package/dist/core/agiCore.js.map +1 -0
- package/dist/core/aiErrorFixer.d.ts +57 -0
- package/dist/core/aiErrorFixer.d.ts.map +1 -0
- package/dist/core/aiErrorFixer.js +214 -0
- package/dist/core/aiErrorFixer.js.map +1 -0
- package/dist/core/antiTermination.d.ts +226 -0
- package/dist/core/antiTermination.d.ts.map +1 -0
- package/dist/core/antiTermination.js +713 -0
- package/dist/core/antiTermination.js.map +1 -0
- package/dist/core/appleSecurityAudit.d.ts +98 -0
- package/dist/core/appleSecurityAudit.d.ts.map +1 -0
- package/dist/core/appleSecurityAudit.js +505 -0
- package/dist/core/appleSecurityAudit.js.map +1 -0
- package/dist/core/appleSecurityIntegration.d.ts +130 -0
- package/dist/core/appleSecurityIntegration.d.ts.map +1 -0
- package/dist/core/appleSecurityIntegration.js +697 -0
- package/dist/core/appleSecurityIntegration.js.map +1 -0
- package/dist/core/bashCommandGuidance.d.ts +16 -0
- package/dist/core/bashCommandGuidance.d.ts.map +1 -0
- package/dist/core/bashCommandGuidance.js +40 -0
- package/dist/core/bashCommandGuidance.js.map +1 -0
- package/dist/core/constants.d.ts +31 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +62 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/contextManager.d.ts +271 -0
- package/dist/core/contextManager.d.ts.map +1 -0
- package/dist/core/contextManager.js +1073 -0
- package/dist/core/contextManager.js.map +1 -0
- package/dist/core/contextWindow.d.ts +42 -0
- package/dist/core/contextWindow.d.ts.map +1 -0
- package/dist/core/contextWindow.js +123 -0
- package/dist/core/contextWindow.js.map +1 -0
- package/dist/core/customCommands.d.ts +19 -0
- package/dist/core/customCommands.d.ts.map +1 -0
- package/dist/core/customCommands.js +85 -0
- package/dist/core/customCommands.js.map +1 -0
- package/dist/core/deepBugAnalyzer.d.ts +25 -0
- package/dist/core/deepBugAnalyzer.d.ts.map +1 -0
- package/dist/core/deepBugAnalyzer.js +44 -0
- package/dist/core/deepBugAnalyzer.js.map +1 -0
- package/dist/core/dualTournament.d.ts +110 -0
- package/dist/core/dualTournament.d.ts.map +1 -0
- package/dist/core/dualTournament.js +270 -0
- package/dist/core/dualTournament.js.map +1 -0
- package/dist/core/dynamicGuardrails.d.ts +207 -0
- package/dist/core/dynamicGuardrails.d.ts.map +1 -0
- package/dist/core/dynamicGuardrails.js +516 -0
- package/dist/core/dynamicGuardrails.js.map +1 -0
- package/dist/core/embeddingProviders.d.ts +80 -0
- package/dist/core/embeddingProviders.d.ts.map +1 -0
- package/dist/core/embeddingProviders.js +241 -0
- package/dist/core/embeddingProviders.js.map +1 -0
- package/dist/core/episodicMemory.d.ts +259 -0
- package/dist/core/episodicMemory.d.ts.map +1 -0
- package/dist/core/episodicMemory.js +833 -0
- package/dist/core/episodicMemory.js.map +1 -0
- package/dist/core/errors/apiKeyErrors.d.ts +11 -0
- package/dist/core/errors/apiKeyErrors.d.ts.map +1 -0
- package/dist/core/errors/apiKeyErrors.js +159 -0
- package/dist/core/errors/apiKeyErrors.js.map +1 -0
- package/dist/core/errors/errorTypes.d.ts +111 -0
- package/dist/core/errors/errorTypes.d.ts.map +1 -0
- package/dist/core/errors/errorTypes.js +345 -0
- package/dist/core/errors/errorTypes.js.map +1 -0
- package/dist/core/errors/index.d.ts +50 -0
- package/dist/core/errors/index.d.ts.map +1 -0
- package/dist/core/errors/index.js +156 -0
- package/dist/core/errors/index.js.map +1 -0
- package/dist/core/errors/networkErrors.d.ts +14 -0
- package/dist/core/errors/networkErrors.d.ts.map +1 -0
- package/dist/core/errors/networkErrors.js +53 -0
- package/dist/core/errors/networkErrors.js.map +1 -0
- package/dist/core/errors/safetyValidator.d.ts +115 -0
- package/dist/core/errors/safetyValidator.d.ts.map +1 -0
- package/dist/core/errors/safetyValidator.js +302 -0
- package/dist/core/errors/safetyValidator.js.map +1 -0
- package/dist/core/errors.d.ts +4 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +33 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/finalResponseFormatter.d.ts +10 -0
- package/dist/core/finalResponseFormatter.d.ts.map +1 -0
- package/dist/core/finalResponseFormatter.js +14 -0
- package/dist/core/finalResponseFormatter.js.map +1 -0
- package/dist/core/flowProtection.d.ts +154 -0
- package/dist/core/flowProtection.d.ts.map +1 -0
- package/dist/core/flowProtection.js +436 -0
- package/dist/core/flowProtection.js.map +1 -0
- package/dist/core/gitWorktreeManager.d.ts +126 -0
- package/dist/core/gitWorktreeManager.d.ts.map +1 -0
- package/dist/core/gitWorktreeManager.js +403 -0
- package/dist/core/gitWorktreeManager.js.map +1 -0
- package/dist/core/guardrails.d.ts +150 -0
- package/dist/core/guardrails.d.ts.map +1 -0
- package/dist/core/guardrails.js +360 -0
- package/dist/core/guardrails.js.map +1 -0
- package/dist/core/hallucinationGuard.d.ts +57 -0
- package/dist/core/hallucinationGuard.d.ts.map +1 -0
- package/dist/core/hallucinationGuard.js +237 -0
- package/dist/core/hallucinationGuard.js.map +1 -0
- package/dist/core/hooks.d.ts +113 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +364 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/hotReload.d.ts +154 -0
- package/dist/core/hotReload.d.ts.map +1 -0
- package/dist/core/hotReload.js +451 -0
- package/dist/core/hotReload.js.map +1 -0
- package/dist/core/hypothesisEngine.d.ts +27 -0
- package/dist/core/hypothesisEngine.d.ts.map +1 -0
- package/dist/core/hypothesisEngine.js +58 -0
- package/dist/core/hypothesisEngine.js.map +1 -0
- package/dist/core/index.d.ts +26 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +54 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/inputProtection.d.ts +122 -0
- package/dist/core/inputProtection.d.ts.map +1 -0
- package/dist/core/inputProtection.js +421 -0
- package/dist/core/inputProtection.js.map +1 -0
- package/dist/core/liveGCPVerification.d.ts +41 -0
- package/dist/core/liveGCPVerification.d.ts.map +1 -0
- package/dist/core/liveGCPVerification.js +745 -0
- package/dist/core/liveGCPVerification.js.map +1 -0
- package/dist/core/modelDiscovery.d.ts +105 -0
- package/dist/core/modelDiscovery.d.ts.map +1 -0
- package/dist/core/modelDiscovery.js +740 -0
- package/dist/core/modelDiscovery.js.map +1 -0
- package/dist/core/multilinePasteHandler.d.ts +35 -0
- package/dist/core/multilinePasteHandler.d.ts.map +1 -0
- package/dist/core/multilinePasteHandler.js +80 -0
- package/dist/core/multilinePasteHandler.js.map +1 -0
- package/dist/core/parallel.d.ts +85 -0
- package/dist/core/parallel.d.ts.map +1 -0
- package/dist/core/parallel.js +150 -0
- package/dist/core/parallel.js.map +1 -0
- package/dist/core/parallelCoordinator.d.ts +21 -0
- package/dist/core/parallelCoordinator.d.ts.map +1 -0
- package/dist/core/parallelCoordinator.js +42 -0
- package/dist/core/parallelCoordinator.js.map +1 -0
- package/dist/core/parallelExecutor.d.ts +215 -0
- package/dist/core/parallelExecutor.d.ts.map +1 -0
- package/dist/core/parallelExecutor.js +584 -0
- package/dist/core/parallelExecutor.js.map +1 -0
- package/dist/core/preferences.d.ts +71 -0
- package/dist/core/preferences.d.ts.map +1 -0
- package/dist/core/preferences.js +341 -0
- package/dist/core/preferences.js.map +1 -0
- package/dist/core/productTestHarness.d.ts +46 -0
- package/dist/core/productTestHarness.d.ts.map +1 -0
- package/dist/core/productTestHarness.js +128 -0
- package/dist/core/productTestHarness.js.map +1 -0
- package/dist/core/providerKeys.d.ts +20 -0
- package/dist/core/providerKeys.d.ts.map +1 -0
- package/dist/core/providerKeys.js +40 -0
- package/dist/core/providerKeys.js.map +1 -0
- package/dist/core/realityScore.d.ts +159 -0
- package/dist/core/realityScore.d.ts.map +1 -0
- package/dist/core/realityScore.js +734 -0
- package/dist/core/realityScore.js.map +1 -0
- package/dist/core/repoUpgradeOrchestrator.d.ts +223 -0
- package/dist/core/repoUpgradeOrchestrator.d.ts.map +1 -0
- package/dist/core/repoUpgradeOrchestrator.js +1003 -0
- package/dist/core/repoUpgradeOrchestrator.js.map +1 -0
- package/dist/core/resultVerification.d.ts +47 -0
- package/dist/core/resultVerification.d.ts.map +1 -0
- package/dist/core/resultVerification.js +126 -0
- package/dist/core/resultVerification.js.map +1 -0
- package/dist/core/revenueEnvValidator.d.ts +30 -0
- package/dist/core/revenueEnvValidator.d.ts.map +1 -0
- package/dist/core/revenueEnvValidator.js +241 -0
- package/dist/core/revenueEnvValidator.js.map +1 -0
- package/dist/core/schemaValidator.d.ts +49 -0
- package/dist/core/schemaValidator.d.ts.map +1 -0
- package/dist/core/schemaValidator.js +234 -0
- package/dist/core/schemaValidator.js.map +1 -0
- package/dist/core/secretStore.d.ts +48 -0
- package/dist/core/secretStore.d.ts.map +1 -0
- package/dist/core/secretStore.js +295 -0
- package/dist/core/secretStore.js.map +1 -0
- package/dist/core/securityTournament.d.ts +83 -0
- package/dist/core/securityTournament.d.ts.map +1 -0
- package/dist/core/securityTournament.js +357 -0
- package/dist/core/securityTournament.js.map +1 -0
- package/dist/core/selfUpgrade.d.ts +253 -0
- package/dist/core/selfUpgrade.d.ts.map +1 -0
- package/dist/core/selfUpgrade.js +669 -0
- package/dist/core/selfUpgrade.js.map +1 -0
- package/dist/core/sessionStorage.d.ts +10 -0
- package/dist/core/sessionStorage.d.ts.map +1 -0
- package/dist/core/sessionStorage.js +46 -0
- package/dist/core/sessionStorage.js.map +1 -0
- package/dist/core/sessionStore.d.ts +35 -0
- package/dist/core/sessionStore.d.ts.map +1 -0
- package/dist/core/sessionStore.js +191 -0
- package/dist/core/sessionStore.js.map +1 -0
- package/dist/core/taskCompletionDetector.d.ts +112 -0
- package/dist/core/taskCompletionDetector.d.ts.map +1 -0
- package/dist/core/taskCompletionDetector.js +469 -0
- package/dist/core/taskCompletionDetector.js.map +1 -0
- package/dist/core/toolPreconditions.d.ts +34 -0
- package/dist/core/toolPreconditions.d.ts.map +1 -0
- package/dist/core/toolPreconditions.js +242 -0
- package/dist/core/toolPreconditions.js.map +1 -0
- package/dist/core/toolRuntime.d.ts +185 -0
- package/dist/core/toolRuntime.d.ts.map +1 -0
- package/dist/core/toolRuntime.js +412 -0
- package/dist/core/toolRuntime.js.map +1 -0
- package/dist/core/tournamentStrategy.d.ts +12 -0
- package/dist/core/tournamentStrategy.d.ts.map +1 -0
- package/dist/core/tournamentStrategy.js +41 -0
- package/dist/core/tournamentStrategy.js.map +1 -0
- package/dist/core/types/utilityTypes.d.ts +192 -0
- package/dist/core/types/utilityTypes.d.ts.map +1 -0
- package/dist/core/types/utilityTypes.js +272 -0
- package/dist/core/types/utilityTypes.js.map +1 -0
- package/dist/core/types.d.ts +334 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +76 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/unifiedOrchestrator.d.ts +47 -0
- package/dist/core/unifiedOrchestrator.d.ts.map +1 -0
- package/dist/core/unifiedOrchestrator.js +103 -0
- package/dist/core/unifiedOrchestrator.js.map +1 -0
- package/dist/core/universalSecurityAudit.d.ts +104 -0
- package/dist/core/universalSecurityAudit.d.ts.map +1 -0
- package/dist/core/universalSecurityAudit.js +2190 -0
- package/dist/core/universalSecurityAudit.js.map +1 -0
- package/dist/core/updateChecker.d.ts +148 -0
- package/dist/core/updateChecker.d.ts.map +1 -0
- package/dist/core/updateChecker.js +593 -0
- package/dist/core/updateChecker.js.map +1 -0
- package/dist/core/variantExecution.d.ts +23 -0
- package/dist/core/variantExecution.d.ts.map +1 -0
- package/dist/core/variantExecution.js +58 -0
- package/dist/core/variantExecution.js.map +1 -0
- package/dist/core/winnerStrategy.d.ts +15 -0
- package/dist/core/winnerStrategy.d.ts.map +1 -0
- package/dist/core/winnerStrategy.js +18 -0
- package/dist/core/winnerStrategy.js.map +1 -0
- package/dist/core/zeroDayDiscovery.d.ts +96 -0
- package/dist/core/zeroDayDiscovery.d.ts.map +1 -0
- package/dist/core/zeroDayDiscovery.js +358 -0
- package/dist/core/zeroDayDiscovery.js.map +1 -0
- package/dist/headless/interactiveShell.d.ts +22 -0
- package/dist/headless/interactiveShell.d.ts.map +1 -0
- package/dist/headless/interactiveShell.js +3799 -0
- package/dist/headless/interactiveShell.js.map +1 -0
- package/dist/headless/quickMode.d.ts +26 -0
- package/dist/headless/quickMode.d.ts.map +1 -0
- package/dist/headless/quickMode.js +226 -0
- package/dist/headless/quickMode.js.map +1 -0
- package/dist/orchestration/index.d.ts +10 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +13 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/repoUpgradeRunner.d.ts +44 -0
- package/dist/orchestration/repoUpgradeRunner.d.ts.map +1 -0
- package/dist/orchestration/repoUpgradeRunner.js +375 -0
- package/dist/orchestration/repoUpgradeRunner.js.map +1 -0
- package/dist/orchestration/securityAuditRunner.d.ts +144 -0
- package/dist/orchestration/securityAuditRunner.d.ts.map +1 -0
- package/dist/orchestration/securityAuditRunner.js +526 -0
- package/dist/orchestration/securityAuditRunner.js.map +1 -0
- package/dist/plugins/index.d.ts +49 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +105 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/providers/deepseek/index.d.ts +11 -0
- package/dist/plugins/providers/deepseek/index.d.ts.map +1 -0
- package/dist/plugins/providers/deepseek/index.js +54 -0
- package/dist/plugins/providers/deepseek/index.js.map +1 -0
- package/dist/plugins/providers/index.d.ts +2 -0
- package/dist/plugins/providers/index.d.ts.map +1 -0
- package/dist/plugins/providers/index.js +11 -0
- package/dist/plugins/providers/index.js.map +1 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts +3 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js +27 -0
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js.map +1 -0
- package/dist/plugins/tools/apple/secureApplePlugin.d.ts +3 -0
- package/dist/plugins/tools/apple/secureApplePlugin.d.ts.map +1 -0
- package/dist/plugins/tools/apple/secureApplePlugin.js +26 -0
- package/dist/plugins/tools/apple/secureApplePlugin.js.map +1 -0
- package/dist/plugins/tools/authorizedSecurity/authorizedSecurityPlugin.d.ts +3 -0
- package/dist/plugins/tools/authorizedSecurity/authorizedSecurityPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/authorizedSecurity/authorizedSecurityPlugin.js +9 -0
- package/dist/plugins/tools/authorizedSecurity/authorizedSecurityPlugin.js.map +1 -0
- package/dist/plugins/tools/bash/localBashPlugin.d.ts +3 -0
- package/dist/plugins/tools/bash/localBashPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/bash/localBashPlugin.js +14 -0
- package/dist/plugins/tools/bash/localBashPlugin.js.map +1 -0
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.d.ts +3 -0
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.js +27 -0
- package/dist/plugins/tools/bidirectionalAudit/bidirectionalAuditPlugin.js.map +1 -0
- package/dist/plugins/tools/edit/editPlugin.d.ts +9 -0
- package/dist/plugins/tools/edit/editPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/edit/editPlugin.js +15 -0
- package/dist/plugins/tools/edit/editPlugin.js.map +1 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts +3 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js +9 -0
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js.map +1 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts +3 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js +14 -0
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js.map +1 -0
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts +3 -0
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js +9 -0
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js.map +1 -0
- package/dist/plugins/tools/index.d.ts +3 -0
- package/dist/plugins/tools/index.d.ts.map +1 -0
- package/dist/plugins/tools/index.js +3 -0
- package/dist/plugins/tools/index.js.map +1 -0
- package/dist/plugins/tools/integrity/integrityPlugin.d.ts +3 -0
- package/dist/plugins/tools/integrity/integrityPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/integrity/integrityPlugin.js +31 -0
- package/dist/plugins/tools/integrity/integrityPlugin.js.map +1 -0
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts +3 -0
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/mcp/mcpPlugin.js +27 -0
- package/dist/plugins/tools/mcp/mcpPlugin.js.map +1 -0
- package/dist/plugins/tools/nodeDefaults.d.ts +15 -0
- package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -0
- package/dist/plugins/tools/nodeDefaults.js +37 -0
- package/dist/plugins/tools/nodeDefaults.js.map +1 -0
- package/dist/plugins/tools/offensiveDestruction/offensiveDestructionPlugin.d.ts +3 -0
- package/dist/plugins/tools/offensiveDestruction/offensiveDestructionPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/offensiveDestruction/offensiveDestructionPlugin.js +9 -0
- package/dist/plugins/tools/offensiveDestruction/offensiveDestructionPlugin.js.map +1 -0
- package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts +3 -0
- package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/orchestration/orchestrationPlugin.js +340 -0
- package/dist/plugins/tools/orchestration/orchestrationPlugin.js.map +1 -0
- package/dist/plugins/tools/registry.d.ts +22 -0
- package/dist/plugins/tools/registry.d.ts.map +1 -0
- package/dist/plugins/tools/registry.js +58 -0
- package/dist/plugins/tools/registry.js.map +1 -0
- package/dist/plugins/tools/search/localSearchPlugin.d.ts +3 -0
- package/dist/plugins/tools/search/localSearchPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/search/localSearchPlugin.js +14 -0
- package/dist/plugins/tools/search/localSearchPlugin.js.map +1 -0
- package/dist/plugins/tools/skills/skillPlugin.d.ts +3 -0
- package/dist/plugins/tools/skills/skillPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/skills/skillPlugin.js +27 -0
- package/dist/plugins/tools/skills/skillPlugin.js.map +1 -0
- package/dist/plugins/tools/tao/secureTaoPlugin.d.ts +3 -0
- package/dist/plugins/tools/tao/secureTaoPlugin.d.ts.map +1 -0
- package/dist/plugins/tools/tao/secureTaoPlugin.js +37 -0
- package/dist/plugins/tools/tao/secureTaoPlugin.js.map +1 -0
- package/dist/providers/baseProvider.d.ts +148 -0
- package/dist/providers/baseProvider.d.ts.map +1 -0
- package/dist/providers/baseProvider.js +284 -0
- package/dist/providers/baseProvider.js.map +1 -0
- package/dist/providers/openaiChatCompletionsProvider.d.ts +64 -0
- package/dist/providers/openaiChatCompletionsProvider.d.ts.map +1 -0
- package/dist/providers/openaiChatCompletionsProvider.js +1000 -0
- package/dist/providers/openaiChatCompletionsProvider.js.map +1 -0
- package/dist/providers/providerFactory.d.ts +22 -0
- package/dist/providers/providerFactory.d.ts.map +1 -0
- package/dist/providers/providerFactory.js +25 -0
- package/dist/providers/providerFactory.js.map +1 -0
- package/dist/providers/resilientProvider.d.ts +103 -0
- package/dist/providers/resilientProvider.d.ts.map +1 -0
- package/dist/providers/resilientProvider.js +462 -0
- package/dist/providers/resilientProvider.js.map +1 -0
- package/dist/runtime/agentController.d.ts +114 -0
- package/dist/runtime/agentController.d.ts.map +1 -0
- package/dist/runtime/agentController.js +693 -0
- package/dist/runtime/agentController.js.map +1 -0
- package/dist/runtime/agentHost.d.ts +61 -0
- package/dist/runtime/agentHost.d.ts.map +1 -0
- package/dist/runtime/agentHost.js +157 -0
- package/dist/runtime/agentHost.js.map +1 -0
- package/dist/runtime/agentSession.d.ts +45 -0
- package/dist/runtime/agentSession.d.ts.map +1 -0
- package/dist/runtime/agentSession.js +210 -0
- package/dist/runtime/agentSession.js.map +1 -0
- package/dist/runtime/agentWorkerPool.d.ts +167 -0
- package/dist/runtime/agentWorkerPool.d.ts.map +1 -0
- package/dist/runtime/agentWorkerPool.js +435 -0
- package/dist/runtime/agentWorkerPool.js.map +1 -0
- package/dist/runtime/node.d.ts +7 -0
- package/dist/runtime/node.d.ts.map +1 -0
- package/dist/runtime/node.js +24 -0
- package/dist/runtime/node.js.map +1 -0
- package/dist/runtime/universal.d.ts +18 -0
- package/dist/runtime/universal.d.ts.map +1 -0
- package/dist/runtime/universal.js +21 -0
- package/dist/runtime/universal.js.map +1 -0
- package/dist/shell/autoExecutor.d.ts +70 -0
- package/dist/shell/autoExecutor.d.ts.map +1 -0
- package/dist/shell/autoExecutor.js +320 -0
- package/dist/shell/autoExecutor.js.map +1 -0
- package/dist/shell/commandRegistry.d.ts +122 -0
- package/dist/shell/commandRegistry.d.ts.map +1 -0
- package/dist/shell/commandRegistry.js +386 -0
- package/dist/shell/commandRegistry.js.map +1 -0
- package/dist/shell/composableMessage.d.ts +183 -0
- package/dist/shell/composableMessage.d.ts.map +1 -0
- package/dist/shell/composableMessage.js +420 -0
- package/dist/shell/composableMessage.js.map +1 -0
- package/dist/shell/liveStatus.d.ts +27 -0
- package/dist/shell/liveStatus.d.ts.map +1 -0
- package/dist/shell/liveStatus.js +53 -0
- package/dist/shell/liveStatus.js.map +1 -0
- package/dist/shell/systemPrompt.d.ts +12 -0
- package/dist/shell/systemPrompt.d.ts.map +1 -0
- package/dist/shell/systemPrompt.js +16 -0
- package/dist/shell/systemPrompt.js.map +1 -0
- package/dist/shell/vimMode.d.ts +66 -0
- package/dist/shell/vimMode.d.ts.map +1 -0
- package/dist/shell/vimMode.js +435 -0
- package/dist/shell/vimMode.js.map +1 -0
- package/dist/tools/bashTools.d.ts +6 -0
- package/dist/tools/bashTools.d.ts.map +1 -0
- package/dist/tools/bashTools.js +485 -0
- package/dist/tools/bashTools.js.map +1 -0
- package/dist/tools/diffUtils.d.ts +43 -0
- package/dist/tools/diffUtils.d.ts.map +1 -0
- package/dist/tools/diffUtils.js +607 -0
- package/dist/tools/diffUtils.js.map +1 -0
- package/dist/tools/editTools.d.ts +29 -0
- package/dist/tools/editTools.d.ts.map +1 -0
- package/dist/tools/editTools.js +702 -0
- package/dist/tools/editTools.js.map +1 -0
- package/dist/tools/emailTools.d.ts +140 -0
- package/dist/tools/emailTools.d.ts.map +1 -0
- package/dist/tools/emailTools.js +792 -0
- package/dist/tools/emailTools.js.map +1 -0
- package/dist/tools/fileReadTracker.d.ts +69 -0
- package/dist/tools/fileReadTracker.d.ts.map +1 -0
- package/dist/tools/fileReadTracker.js +213 -0
- package/dist/tools/fileReadTracker.js.map +1 -0
- package/dist/tools/fileTools.d.ts +3 -0
- package/dist/tools/fileTools.d.ts.map +1 -0
- package/dist/tools/fileTools.js +342 -0
- package/dist/tools/fileTools.js.map +1 -0
- package/dist/tools/grepTools.d.ts +3 -0
- package/dist/tools/grepTools.d.ts.map +1 -0
- package/dist/tools/grepTools.js +129 -0
- package/dist/tools/grepTools.js.map +1 -0
- package/dist/tools/humanOpsTools.d.ts +3 -0
- package/dist/tools/humanOpsTools.d.ts.map +1 -0
- package/dist/tools/humanOpsTools.js +86 -0
- package/dist/tools/humanOpsTools.js.map +1 -0
- package/dist/tools/localExplore.d.ts +38 -0
- package/dist/tools/localExplore.d.ts.map +1 -0
- package/dist/tools/localExplore.js +30 -0
- package/dist/tools/localExplore.js.map +1 -0
- package/dist/tools/metaTools.d.ts +3 -0
- package/dist/tools/metaTools.d.ts.map +1 -0
- package/dist/tools/metaTools.js +148 -0
- package/dist/tools/metaTools.js.map +1 -0
- package/dist/tools/planningTools.d.ts +12 -0
- package/dist/tools/planningTools.d.ts.map +1 -0
- package/dist/tools/planningTools.js +75 -0
- package/dist/tools/planningTools.js.map +1 -0
- package/dist/tools/searchTools.d.ts +12 -0
- package/dist/tools/searchTools.d.ts.map +1 -0
- package/dist/tools/searchTools.js +370 -0
- package/dist/tools/searchTools.js.map +1 -0
- package/dist/tools/secureAppleExploitation.d.ts +29 -0
- package/dist/tools/secureAppleExploitation.d.ts.map +1 -0
- package/dist/tools/secureAppleExploitation.js +518 -0
- package/dist/tools/secureAppleExploitation.js.map +1 -0
- package/dist/tools/telemetryTools.d.ts +5 -0
- package/dist/tools/telemetryTools.d.ts.map +1 -0
- package/dist/tools/telemetryTools.js +9 -0
- package/dist/tools/telemetryTools.js.map +1 -0
- package/dist/tools/unifiedOps.d.ts +3 -0
- package/dist/tools/unifiedOps.d.ts.map +1 -0
- package/dist/tools/unifiedOps.js +57 -0
- package/dist/tools/unifiedOps.js.map +1 -0
- package/dist/tools/webTools.d.ts +26 -0
- package/dist/tools/webTools.d.ts.map +1 -0
- package/dist/tools/webTools.js +227 -0
- package/dist/tools/webTools.js.map +1 -0
- package/dist/ui/PromptController.d.ts +174 -0
- package/dist/ui/PromptController.d.ts.map +1 -0
- package/dist/ui/PromptController.js +351 -0
- package/dist/ui/PromptController.js.map +1 -0
- package/dist/ui/UnifiedUIRenderer.d.ts +779 -0
- package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -0
- package/dist/ui/UnifiedUIRenderer.js +5458 -0
- package/dist/ui/UnifiedUIRenderer.js.map +1 -0
- package/dist/ui/animatedStatus.d.ts +140 -0
- package/dist/ui/animatedStatus.d.ts.map +1 -0
- package/dist/ui/animatedStatus.js +480 -0
- package/dist/ui/animatedStatus.js.map +1 -0
- package/dist/ui/animation/AnimationScheduler.d.ts +197 -0
- package/dist/ui/animation/AnimationScheduler.d.ts.map +1 -0
- package/dist/ui/animation/AnimationScheduler.js +440 -0
- package/dist/ui/animation/AnimationScheduler.js.map +1 -0
- package/dist/ui/codeHighlighter.d.ts +6 -0
- package/dist/ui/codeHighlighter.d.ts.map +1 -0
- package/dist/ui/codeHighlighter.js +855 -0
- package/dist/ui/codeHighlighter.js.map +1 -0
- package/dist/ui/designSystem.d.ts +26 -0
- package/dist/ui/designSystem.d.ts.map +1 -0
- package/dist/ui/designSystem.js +114 -0
- package/dist/ui/designSystem.js.map +1 -0
- package/dist/ui/errorFormatter.d.ts +64 -0
- package/dist/ui/errorFormatter.d.ts.map +1 -0
- package/dist/ui/errorFormatter.js +316 -0
- package/dist/ui/errorFormatter.js.map +1 -0
- package/dist/ui/globalWriteLock.d.ts +63 -0
- package/dist/ui/globalWriteLock.d.ts.map +1 -0
- package/dist/ui/globalWriteLock.js +173 -0
- package/dist/ui/globalWriteLock.js.map +1 -0
- package/dist/ui/index.d.ts +32 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +54 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/interrupts/InterruptManager.d.ts +157 -0
- package/dist/ui/interrupts/InterruptManager.d.ts.map +1 -0
- package/dist/ui/interrupts/InterruptManager.js +501 -0
- package/dist/ui/interrupts/InterruptManager.js.map +1 -0
- package/dist/ui/layout.d.ts +27 -0
- package/dist/ui/layout.d.ts.map +1 -0
- package/dist/ui/layout.js +184 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/ui/maxOffensiveUkraineUI.d.ts +94 -0
- package/dist/ui/maxOffensiveUkraineUI.d.ts.map +1 -0
- package/dist/ui/maxOffensiveUkraineUI.js +316 -0
- package/dist/ui/maxOffensiveUkraineUI.js.map +1 -0
- package/dist/ui/outputMode.d.ts +44 -0
- package/dist/ui/outputMode.d.ts.map +1 -0
- package/dist/ui/outputMode.js +123 -0
- package/dist/ui/outputMode.js.map +1 -0
- package/dist/ui/overlay/OverlayManager.d.ts +105 -0
- package/dist/ui/overlay/OverlayManager.d.ts.map +1 -0
- package/dist/ui/overlay/OverlayManager.js +291 -0
- package/dist/ui/overlay/OverlayManager.js.map +1 -0
- package/dist/ui/premiumComponents.d.ts +54 -0
- package/dist/ui/premiumComponents.d.ts.map +1 -0
- package/dist/ui/premiumComponents.js +241 -0
- package/dist/ui/premiumComponents.js.map +1 -0
- package/dist/ui/richText.d.ts +13 -0
- package/dist/ui/richText.d.ts.map +1 -0
- package/dist/ui/richText.js +443 -0
- package/dist/ui/richText.js.map +1 -0
- package/dist/ui/telemetry/ResponseTracker.d.ts +22 -0
- package/dist/ui/telemetry/ResponseTracker.d.ts.map +1 -0
- package/dist/ui/telemetry/ResponseTracker.js +60 -0
- package/dist/ui/telemetry/ResponseTracker.js.map +1 -0
- package/dist/ui/telemetry/UITelemetry.d.ts +181 -0
- package/dist/ui/telemetry/UITelemetry.d.ts.map +1 -0
- package/dist/ui/telemetry/UITelemetry.js +446 -0
- package/dist/ui/telemetry/UITelemetry.js.map +1 -0
- package/dist/ui/textHighlighter.d.ts +83 -0
- package/dist/ui/textHighlighter.d.ts.map +1 -0
- package/dist/ui/textHighlighter.js +267 -0
- package/dist/ui/textHighlighter.js.map +1 -0
- package/dist/ui/theme.d.ts +364 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +471 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/toolDisplay.d.ts +221 -0
- package/dist/ui/toolDisplay.d.ts.map +1 -0
- package/dist/ui/toolDisplay.js +1654 -0
- package/dist/ui/toolDisplay.js.map +1 -0
- package/dist/ui/uiConstants.d.ts +288 -0
- package/dist/ui/uiConstants.d.ts.map +1 -0
- package/dist/ui/uiConstants.js +472 -0
- package/dist/ui/uiConstants.js.map +1 -0
- package/dist/utils/askUserPrompt.d.ts +21 -0
- package/dist/utils/askUserPrompt.d.ts.map +1 -0
- package/dist/utils/askUserPrompt.js +87 -0
- package/dist/utils/askUserPrompt.js.map +1 -0
- package/dist/utils/asyncUtils.d.ts +95 -0
- package/dist/utils/asyncUtils.d.ts.map +1 -0
- package/dist/utils/asyncUtils.js +286 -0
- package/dist/utils/asyncUtils.js.map +1 -0
- package/dist/utils/debugLogger.d.ts +6 -0
- package/dist/utils/debugLogger.d.ts.map +1 -0
- package/dist/utils/debugLogger.js +39 -0
- package/dist/utils/debugLogger.js.map +1 -0
- package/dist/utils/errorUtils.d.ts +12 -0
- package/dist/utils/errorUtils.d.ts.map +1 -0
- package/dist/utils/errorUtils.js +83 -0
- package/dist/utils/errorUtils.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +10 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +78 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/packageInfo.d.ts +14 -0
- package/dist/utils/packageInfo.d.ts.map +1 -0
- package/dist/utils/packageInfo.js +45 -0
- package/dist/utils/packageInfo.js.map +1 -0
- package/dist/utils/planFormatter.d.ts +34 -0
- package/dist/utils/planFormatter.d.ts.map +1 -0
- package/dist/utils/planFormatter.js +141 -0
- package/dist/utils/planFormatter.js.map +1 -0
- package/dist/utils/securityUtils.d.ts +132 -0
- package/dist/utils/securityUtils.d.ts.map +1 -0
- package/dist/utils/securityUtils.js +324 -0
- package/dist/utils/securityUtils.js.map +1 -0
- package/dist/workspace.d.ts +8 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +134 -0
- package/dist/workspace.js.map +1 -0
- package/dist/workspace.validator.d.ts +49 -0
- package/dist/workspace.validator.d.ts.map +1 -0
- package/dist/workspace.validator.js +215 -0
- package/dist/workspace.validator.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,1563 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { isMultilinePaste, processPaste } from './multilinePasteHandler.js';
|
|
3
|
+
import { safeErrorMessage } from './secretStore.js';
|
|
4
|
+
import { logDebug, debugSnippet } from '../utils/debugLogger.js';
|
|
5
|
+
import { ensureNextSteps } from './finalResponseFormatter.js';
|
|
6
|
+
/**
|
|
7
|
+
* Maximum number of context overflow recovery attempts
|
|
8
|
+
*/
|
|
9
|
+
const MAX_CONTEXT_RECOVERY_ATTEMPTS = 3;
|
|
10
|
+
// Streaming runs without timeouts - we let the model take as long as it needs
|
|
11
|
+
/**
|
|
12
|
+
* Check if an error is a context overflow error
|
|
13
|
+
*/
|
|
14
|
+
function isContextOverflowError(error) {
|
|
15
|
+
if (!(error instanceof Error))
|
|
16
|
+
return false;
|
|
17
|
+
const message = error.message.toLowerCase();
|
|
18
|
+
return (message.includes('context length') ||
|
|
19
|
+
message.includes('token') && (message.includes('limit') || message.includes('exceed') || message.includes('maximum')) ||
|
|
20
|
+
message.includes('too long') ||
|
|
21
|
+
message.includes('too many tokens') ||
|
|
22
|
+
message.includes('max_tokens') ||
|
|
23
|
+
message.includes('context window'));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if an error is a transient/retryable error (network issues, rate limits, server errors)
|
|
27
|
+
*/
|
|
28
|
+
function isTransientError(error) {
|
|
29
|
+
if (!(error instanceof Error))
|
|
30
|
+
return false;
|
|
31
|
+
const message = error.message.toLowerCase();
|
|
32
|
+
// Network errors
|
|
33
|
+
const networkPatterns = [
|
|
34
|
+
'econnrefused', 'econnreset', 'enotfound', 'etimedout', 'epipe',
|
|
35
|
+
'network error', 'connection error', 'fetch failed', 'socket hang up',
|
|
36
|
+
'network is unreachable', 'connection refused', 'connection reset',
|
|
37
|
+
];
|
|
38
|
+
if (networkPatterns.some(p => message.includes(p))) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
// Rate limit errors
|
|
42
|
+
if (message.includes('rate limit') || message.includes('429') || message.includes('too many requests')) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
// Server errors (5xx)
|
|
46
|
+
if (message.includes('500') || message.includes('502') || message.includes('503') || message.includes('504')) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
// Temporary service errors
|
|
50
|
+
if (message.includes('service unavailable') || message.includes('temporarily unavailable') ||
|
|
51
|
+
message.includes('overloaded') || message.includes('server error')) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Maximum number of transient error retries
|
|
58
|
+
*/
|
|
59
|
+
const MAX_TRANSIENT_RETRIES = 3;
|
|
60
|
+
/**
|
|
61
|
+
* Delay before retry (in ms), with exponential backoff
|
|
62
|
+
*/
|
|
63
|
+
function getRetryDelay(attempt) {
|
|
64
|
+
// Base delay of 1 second, doubles each attempt: 1s, 2s, 4s
|
|
65
|
+
return Math.min(1000 * Math.pow(2, attempt - 1), 10000);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Sleep for the specified milliseconds
|
|
69
|
+
*/
|
|
70
|
+
function sleep(ms) {
|
|
71
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
72
|
+
}
|
|
73
|
+
export class AgentRuntime {
|
|
74
|
+
messages = [];
|
|
75
|
+
provider;
|
|
76
|
+
toolRuntime;
|
|
77
|
+
callbacks;
|
|
78
|
+
contextManager;
|
|
79
|
+
activeRun = null;
|
|
80
|
+
baseSystemPrompt;
|
|
81
|
+
providerId;
|
|
82
|
+
modelId;
|
|
83
|
+
workingDirectory;
|
|
84
|
+
explainEdits;
|
|
85
|
+
cancellationRequested = false;
|
|
86
|
+
// Loop detection: track last tool calls to detect stuck loops
|
|
87
|
+
lastToolCallSignature = null;
|
|
88
|
+
repeatedToolCallCount = 0;
|
|
89
|
+
static MAX_REPEATED_TOOL_CALLS = 5; // Stop on 5th identical call (4 allowed)
|
|
90
|
+
// Session-level context recovery tracking to prevent endless recovery loops
|
|
91
|
+
totalContextRecoveries = 0;
|
|
92
|
+
static MAX_TOTAL_RECOVERIES = 5; // Max recoveries across entire session
|
|
93
|
+
// Behavioral loop detection: track recent tool calls to catch repetitive patterns
|
|
94
|
+
// e.g., calling "execute_bash" with "git status" 5 times even if output differs slightly
|
|
95
|
+
recentToolCalls = [];
|
|
96
|
+
static TOOL_HISTORY_SIZE = 12;
|
|
97
|
+
static BEHAVIORAL_LOOP_THRESHOLD = 3; // Same tool+cmd 3+ times in last 12 = stuck
|
|
98
|
+
static EDIT_CONTEXT_CHAR_LIMIT = 4000;
|
|
99
|
+
// Never cache stateful tools - they must always execute to reflect current system state
|
|
100
|
+
static NON_CACHEABLE_TOOL_NAMES = new Set([
|
|
101
|
+
'bash',
|
|
102
|
+
'execute_bash',
|
|
103
|
+
'execute_command',
|
|
104
|
+
'run_command',
|
|
105
|
+
'edit',
|
|
106
|
+
'edit_file',
|
|
107
|
+
'write',
|
|
108
|
+
'write_file',
|
|
109
|
+
'notebookedit',
|
|
110
|
+
'read',
|
|
111
|
+
'read_file',
|
|
112
|
+
'read_files',
|
|
113
|
+
'list_files',
|
|
114
|
+
'list_dir',
|
|
115
|
+
'glob',
|
|
116
|
+
'grep',
|
|
117
|
+
'search',
|
|
118
|
+
'search_text',
|
|
119
|
+
'git_status',
|
|
120
|
+
'git_diff',
|
|
121
|
+
'git_log',
|
|
122
|
+
'git_commit',
|
|
123
|
+
'git_push',
|
|
124
|
+
]);
|
|
125
|
+
// Skip loop short-circuiting for direct execution tools to avoid blocking user commands
|
|
126
|
+
static LOOP_EXEMPT_TOOL_NAMES = new Set([
|
|
127
|
+
'bash',
|
|
128
|
+
'execute_bash',
|
|
129
|
+
'execute_command',
|
|
130
|
+
'run_command',
|
|
131
|
+
'edit',
|
|
132
|
+
'edit_file',
|
|
133
|
+
'write',
|
|
134
|
+
'write_file',
|
|
135
|
+
'notebookedit',
|
|
136
|
+
// Read/search tools are noise-prone and often repeated legitimately
|
|
137
|
+
'read',
|
|
138
|
+
'read_file',
|
|
139
|
+
'read_files',
|
|
140
|
+
'list_files',
|
|
141
|
+
'list_dir',
|
|
142
|
+
'glob',
|
|
143
|
+
'glob_search',
|
|
144
|
+
'grep',
|
|
145
|
+
'search',
|
|
146
|
+
]);
|
|
147
|
+
// Tool result cache: prevent duplicate identical tool calls by returning cached results
|
|
148
|
+
// Key: tool signature (name + JSON args), Value: result string
|
|
149
|
+
toolResultCache = new Map();
|
|
150
|
+
static TOOL_CACHE_MAX_SIZE = 50; // Keep last 50 tool results
|
|
151
|
+
// Track tool history position per send() call for accurate progress detection
|
|
152
|
+
toolHistoryCursor = 0;
|
|
153
|
+
// Cached model info from provider API (real context window limits)
|
|
154
|
+
modelInfo = null;
|
|
155
|
+
modelInfoFetched = false;
|
|
156
|
+
constructor(options) {
|
|
157
|
+
this.provider = options.provider;
|
|
158
|
+
this.toolRuntime = options.toolRuntime;
|
|
159
|
+
this.callbacks = options.callbacks ?? {};
|
|
160
|
+
this.contextManager = options.contextManager ?? null;
|
|
161
|
+
this.providerId = options.providerId ?? 'unknown';
|
|
162
|
+
this.modelId = options.modelId ?? 'unknown';
|
|
163
|
+
this.workingDirectory = options.workingDirectory ?? process.cwd();
|
|
164
|
+
this.explainEdits = options.explainEdits ?? false;
|
|
165
|
+
const trimmedPrompt = options.systemPrompt.trim();
|
|
166
|
+
this.baseSystemPrompt = trimmedPrompt || null;
|
|
167
|
+
if (trimmedPrompt) {
|
|
168
|
+
this.messages.push({ role: 'system', content: trimmedPrompt });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Request cancellation of the current operation.
|
|
173
|
+
* The agent will stop at the next safe point (after current tool completes).
|
|
174
|
+
*/
|
|
175
|
+
requestCancellation() {
|
|
176
|
+
this.cancellationRequested = true;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Check if cancellation has been requested.
|
|
180
|
+
*/
|
|
181
|
+
isCancellationRequested() {
|
|
182
|
+
return this.cancellationRequested;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check if the agent is currently processing a request.
|
|
186
|
+
*/
|
|
187
|
+
isRunning() {
|
|
188
|
+
return this.activeRun !== null;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Check if any of the tool calls are edit operations (Edit, Write)
|
|
192
|
+
*/
|
|
193
|
+
isEditToolCall(toolName) {
|
|
194
|
+
const name = toolName.toLowerCase();
|
|
195
|
+
return name === 'edit' || name === 'edit_file' || name === 'write' || name === 'write_file';
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Extract a display-friendly file path from a tool call (prefers workspace-relative path)
|
|
199
|
+
*/
|
|
200
|
+
getEditedFilePath(call) {
|
|
201
|
+
const args = call.arguments;
|
|
202
|
+
const rawPath = typeof args['file_path'] === 'string'
|
|
203
|
+
? args['file_path']
|
|
204
|
+
: typeof args['path'] === 'string'
|
|
205
|
+
? args['path']
|
|
206
|
+
: null;
|
|
207
|
+
if (!rawPath) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const relativePath = path.relative(this.workingDirectory, rawPath);
|
|
211
|
+
if (relativePath && !relativePath.startsWith('..') && relativePath !== '') {
|
|
212
|
+
return relativePath;
|
|
213
|
+
}
|
|
214
|
+
return rawPath;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Get the file paths from edit tool calls for the explanation prompt
|
|
218
|
+
*/
|
|
219
|
+
getEditedFiles(toolCalls) {
|
|
220
|
+
const files = [];
|
|
221
|
+
for (const call of toolCalls) {
|
|
222
|
+
if (this.isEditToolCall(call.name)) {
|
|
223
|
+
const filePath = this.getEditedFilePath(call);
|
|
224
|
+
if (filePath) {
|
|
225
|
+
files.push(filePath);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return files;
|
|
230
|
+
}
|
|
231
|
+
async send(text, useStreaming = false) {
|
|
232
|
+
const prompt = text.trim();
|
|
233
|
+
if (!prompt) {
|
|
234
|
+
return '';
|
|
235
|
+
}
|
|
236
|
+
// Notify UI immediately so it can reflect activity without waiting for generation
|
|
237
|
+
this.callbacks.onRequestReceived?.(prompt.slice(0, 400));
|
|
238
|
+
// Reset cancellation flag and loop tracking at start of new request
|
|
239
|
+
this.cancellationRequested = false;
|
|
240
|
+
this.resetBehavioralLoopTracking();
|
|
241
|
+
// Track tool history position for this run
|
|
242
|
+
this.toolHistoryCursor = this.toolRuntime.getToolHistory().length;
|
|
243
|
+
// Handle multi-line paste: show summary to user, send full content to AI
|
|
244
|
+
if (isMultilinePaste(prompt)) {
|
|
245
|
+
const processed = processPaste(prompt);
|
|
246
|
+
// Notify UI about the paste summary
|
|
247
|
+
this.callbacks.onMultilinePaste?.(processed.displaySummary, processed.metadata);
|
|
248
|
+
// But send the full content to the AI
|
|
249
|
+
this.messages.push({ role: 'user', content: processed.fullContent });
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
// Single-line or short text: send as-is
|
|
253
|
+
this.messages.push({ role: 'user', content: prompt });
|
|
254
|
+
}
|
|
255
|
+
const run = { startedAt: Date.now() };
|
|
256
|
+
this.activeRun = run;
|
|
257
|
+
try {
|
|
258
|
+
// Always use streaming when available - no fallback
|
|
259
|
+
if (useStreaming && this.provider.generateStream) {
|
|
260
|
+
return await this.processConversationStreaming();
|
|
261
|
+
}
|
|
262
|
+
return await this.processConversation();
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
if (this.activeRun === run) {
|
|
266
|
+
this.activeRun = null;
|
|
267
|
+
}
|
|
268
|
+
// Reset cancellation flag when done
|
|
269
|
+
this.cancellationRequested = false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async processConversation() {
|
|
273
|
+
let contextRecoveryAttempts = 0;
|
|
274
|
+
let transientRetryAttempts = 0;
|
|
275
|
+
// eslint-disable-next-line no-constant-condition
|
|
276
|
+
while (true) {
|
|
277
|
+
// Check for cancellation at start of each iteration
|
|
278
|
+
if (this.cancellationRequested) {
|
|
279
|
+
this.callbacks.onCancelled?.();
|
|
280
|
+
return '[Operation cancelled by user]';
|
|
281
|
+
}
|
|
282
|
+
// Prune messages if approaching context limit (BEFORE generation)
|
|
283
|
+
await this.pruneMessagesIfNeeded();
|
|
284
|
+
try {
|
|
285
|
+
const response = await this.provider.generate(this.messages, this.providerTools);
|
|
286
|
+
const usage = response.usage ?? null;
|
|
287
|
+
const contextStats = this.getContextStats();
|
|
288
|
+
// Reset recovery attempts on successful generation
|
|
289
|
+
contextRecoveryAttempts = 0;
|
|
290
|
+
if (response.type === 'tool_calls') {
|
|
291
|
+
// BEHAVIORAL LOOP DETECTION: Check if model is stuck calling same tool repeatedly
|
|
292
|
+
const behavioralLoopResult = this.checkBehavioralLoop(response.toolCalls);
|
|
293
|
+
if (behavioralLoopResult) {
|
|
294
|
+
this.emitAssistantMessage(behavioralLoopResult, { isFinal: true, usage, contextStats });
|
|
295
|
+
this.messages.push({ role: 'assistant', content: behavioralLoopResult });
|
|
296
|
+
return behavioralLoopResult;
|
|
297
|
+
}
|
|
298
|
+
// Loop detection: check if same tool calls are being repeated (exact signature match)
|
|
299
|
+
const signatureCalls = response.toolCalls.filter(call => !this.shouldSkipLoopDetection(call));
|
|
300
|
+
const toolSignature = signatureCalls.length
|
|
301
|
+
? signatureCalls
|
|
302
|
+
.map((t) => `${t.name}:${JSON.stringify(t.arguments)}`)
|
|
303
|
+
.sort()
|
|
304
|
+
.join('|')
|
|
305
|
+
: null;
|
|
306
|
+
if (toolSignature && toolSignature === this.lastToolCallSignature) {
|
|
307
|
+
this.repeatedToolCallCount++;
|
|
308
|
+
if (this.repeatedToolCallCount >= AgentRuntime.MAX_REPEATED_TOOL_CALLS) {
|
|
309
|
+
// Break out of loop - model is stuck
|
|
310
|
+
const loopMsg = `Tool loop detected: same tools called ${this.repeatedToolCallCount} times. Please try a different approach or provide more specific instructions.`;
|
|
311
|
+
this.emitAssistantMessage(loopMsg, { isFinal: true, usage, contextStats });
|
|
312
|
+
this.messages.push({ role: 'assistant', content: loopMsg });
|
|
313
|
+
this.lastToolCallSignature = null;
|
|
314
|
+
this.repeatedToolCallCount = 0;
|
|
315
|
+
return loopMsg;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else if (toolSignature) {
|
|
319
|
+
this.lastToolCallSignature = toolSignature;
|
|
320
|
+
this.repeatedToolCallCount = 1;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
this.lastToolCallSignature = null;
|
|
324
|
+
this.repeatedToolCallCount = 0;
|
|
325
|
+
}
|
|
326
|
+
// Emit narration if present - it shows the AI's thought process before tools
|
|
327
|
+
const narration = response.content?.trim();
|
|
328
|
+
if (narration) {
|
|
329
|
+
this.emitAssistantMessage(narration, {
|
|
330
|
+
isFinal: false,
|
|
331
|
+
usage,
|
|
332
|
+
contextStats,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
this.maybeAckToolCalls(response.toolCalls, Boolean(narration?.length), usage, contextStats);
|
|
336
|
+
const assistantMessage = {
|
|
337
|
+
role: 'assistant',
|
|
338
|
+
content: response.content ?? '',
|
|
339
|
+
};
|
|
340
|
+
if (response.toolCalls?.length) {
|
|
341
|
+
assistantMessage.toolCalls = response.toolCalls;
|
|
342
|
+
}
|
|
343
|
+
this.messages.push(assistantMessage);
|
|
344
|
+
await this.resolveToolCalls(response.toolCalls);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
const reply = response.content?.trim() ?? '';
|
|
348
|
+
const { output: finalReply } = ensureNextSteps(reply);
|
|
349
|
+
// Reset loop detection when we get a text response (not just tool calls)
|
|
350
|
+
if (finalReply.length >= 10) {
|
|
351
|
+
this.lastToolCallSignature = null;
|
|
352
|
+
this.repeatedToolCallCount = 0;
|
|
353
|
+
}
|
|
354
|
+
if (finalReply) {
|
|
355
|
+
this.emitAssistantMessage(finalReply, { isFinal: true, usage, contextStats });
|
|
356
|
+
}
|
|
357
|
+
this.messages.push({ role: 'assistant', content: finalReply });
|
|
358
|
+
// Trigger verification for final responses with verifiable claims
|
|
359
|
+
this.triggerVerificationIfNeeded(finalReply);
|
|
360
|
+
return finalReply;
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
// Auto-recover from context overflow errors (with session-level limit)
|
|
364
|
+
const canRecover = contextRecoveryAttempts < MAX_CONTEXT_RECOVERY_ATTEMPTS &&
|
|
365
|
+
this.totalContextRecoveries < AgentRuntime.MAX_TOTAL_RECOVERIES;
|
|
366
|
+
if (isContextOverflowError(error) && canRecover) {
|
|
367
|
+
contextRecoveryAttempts++;
|
|
368
|
+
this.totalContextRecoveries++;
|
|
369
|
+
const recovered = await this.recoverFromContextOverflow(contextRecoveryAttempts);
|
|
370
|
+
if (recovered) {
|
|
371
|
+
// Notify UI that we're continuing after recovery
|
|
372
|
+
this.callbacks.onContinueAfterRecovery?.();
|
|
373
|
+
// Retry the generation with reduced context
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// Auto-retry transient errors (network issues, rate limits, server errors)
|
|
378
|
+
if (isTransientError(error) && transientRetryAttempts < MAX_TRANSIENT_RETRIES) {
|
|
379
|
+
transientRetryAttempts++;
|
|
380
|
+
const delayMs = getRetryDelay(transientRetryAttempts);
|
|
381
|
+
this.callbacks.onRetrying?.(transientRetryAttempts, MAX_TRANSIENT_RETRIES, error);
|
|
382
|
+
await sleep(delayMs);
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
// Re-throw if not recoverable or recovery failed
|
|
386
|
+
throw error;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
async processConversationStreaming() {
|
|
391
|
+
if (!this.provider.generateStream) {
|
|
392
|
+
return this.processConversation();
|
|
393
|
+
}
|
|
394
|
+
let contextRecoveryAttempts = 0;
|
|
395
|
+
let transientRetryAttempts = 0;
|
|
396
|
+
const STREAM_HARD_CHAR_LIMIT = 120000; // Hard guardrail to prevent runaway provider output
|
|
397
|
+
let totalCharsReceived = 0;
|
|
398
|
+
let truncatedResponse = false;
|
|
399
|
+
// eslint-disable-next-line no-constant-condition
|
|
400
|
+
while (true) {
|
|
401
|
+
// Check for cancellation at start of each iteration
|
|
402
|
+
if (this.cancellationRequested) {
|
|
403
|
+
this.callbacks.onCancelled?.();
|
|
404
|
+
return '[Operation cancelled by user]';
|
|
405
|
+
}
|
|
406
|
+
// Prune messages if approaching context limit (BEFORE generation)
|
|
407
|
+
await this.pruneMessagesIfNeeded();
|
|
408
|
+
try {
|
|
409
|
+
let fullContent = '';
|
|
410
|
+
let reasoningContent = '';
|
|
411
|
+
const toolCalls = [];
|
|
412
|
+
let usage = null;
|
|
413
|
+
const suppressStreamNarration = this.shouldSuppressToolNarration();
|
|
414
|
+
let bufferedContent = '';
|
|
415
|
+
const stream = this.provider.generateStream(this.messages, this.providerTools);
|
|
416
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
417
|
+
let streamClosed = false;
|
|
418
|
+
const closeStream = async () => {
|
|
419
|
+
if (streamClosed) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
streamClosed = true;
|
|
423
|
+
if (typeof iterator.return === 'function') {
|
|
424
|
+
try {
|
|
425
|
+
await iterator.return();
|
|
426
|
+
}
|
|
427
|
+
catch (closeError) {
|
|
428
|
+
logDebug(`[agent] Failed to close stream cleanly: ${safeErrorMessage(closeError)}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
const describeChunk = (chunk) => {
|
|
433
|
+
if (!chunk) {
|
|
434
|
+
return 'unknown chunk';
|
|
435
|
+
}
|
|
436
|
+
switch (chunk.type) {
|
|
437
|
+
case 'content':
|
|
438
|
+
case 'reasoning': {
|
|
439
|
+
const snippet = debugSnippet(chunk.content);
|
|
440
|
+
return snippet ? `${chunk.type} → ${snippet}` : chunk.type;
|
|
441
|
+
}
|
|
442
|
+
case 'tool_call':
|
|
443
|
+
return chunk.toolCall ? `tool_call ${chunk.toolCall.name}` : 'tool_call';
|
|
444
|
+
case 'usage':
|
|
445
|
+
if (chunk.usage?.totalTokens != null) {
|
|
446
|
+
return `usage tokens=${chunk.usage.totalTokens}`;
|
|
447
|
+
}
|
|
448
|
+
return 'usage';
|
|
449
|
+
case 'done':
|
|
450
|
+
return 'done';
|
|
451
|
+
default:
|
|
452
|
+
return chunk.type;
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
// Simple streaming loop - no timeouts, let the stream run until done
|
|
456
|
+
try {
|
|
457
|
+
let chunkCount = 0;
|
|
458
|
+
// eslint-disable-next-line no-constant-condition
|
|
459
|
+
while (true) {
|
|
460
|
+
const result = await iterator.next();
|
|
461
|
+
chunkCount++;
|
|
462
|
+
// Only log significant chunks (tool calls, done), not every content/reasoning token
|
|
463
|
+
if (result.done || result.value?.type === 'tool_call') {
|
|
464
|
+
const chunkLabel = result.done ? 'done' : describeChunk(result.value);
|
|
465
|
+
logDebug(`[agent] chunk ${chunkCount}: ${chunkLabel}`);
|
|
466
|
+
}
|
|
467
|
+
// Check for cancellation during streaming
|
|
468
|
+
if (this.cancellationRequested) {
|
|
469
|
+
await closeStream();
|
|
470
|
+
this.callbacks.onCancelled?.();
|
|
471
|
+
const partial = (fullContent || reasoningContent).trim();
|
|
472
|
+
if (partial) {
|
|
473
|
+
this.messages.push({ role: 'assistant', content: `${partial}\n\n[Cancelled by user]` });
|
|
474
|
+
}
|
|
475
|
+
return '[Operation cancelled by user]';
|
|
476
|
+
}
|
|
477
|
+
if (result.done) {
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
const chunk = result.value;
|
|
481
|
+
if (chunk.type === 'reasoning' && chunk.content) {
|
|
482
|
+
// Buffer reasoning content - don't stream token-by-token
|
|
483
|
+
// It will be emitted as a complete block when ready
|
|
484
|
+
const next = reasoningContent + chunk.content;
|
|
485
|
+
totalCharsReceived += chunk.content.length;
|
|
486
|
+
// Hard cap buffered reasoning to protect memory
|
|
487
|
+
if (next.length > 24000) {
|
|
488
|
+
reasoningContent = next.slice(-24000);
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
reasoningContent = next;
|
|
492
|
+
}
|
|
493
|
+
if (totalCharsReceived > STREAM_HARD_CHAR_LIMIT) {
|
|
494
|
+
truncatedResponse = true;
|
|
495
|
+
await closeStream();
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (chunk.type === 'content' && chunk.content) {
|
|
501
|
+
const nextContent = fullContent + chunk.content;
|
|
502
|
+
totalCharsReceived += chunk.content.length;
|
|
503
|
+
// Cap buffered content to avoid OOM from runaway outputs
|
|
504
|
+
fullContent = nextContent.length > 48000 ? nextContent.slice(-48000) : nextContent;
|
|
505
|
+
if (suppressStreamNarration) {
|
|
506
|
+
const nextBuffered = bufferedContent + chunk.content;
|
|
507
|
+
bufferedContent = nextBuffered.length > 24000 ? nextBuffered.slice(-24000) : nextBuffered;
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
this.callbacks.onStreamChunk?.(chunk.content, 'content');
|
|
511
|
+
}
|
|
512
|
+
if (totalCharsReceived > STREAM_HARD_CHAR_LIMIT) {
|
|
513
|
+
truncatedResponse = true;
|
|
514
|
+
await closeStream();
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
else if (chunk.type === 'tool_call' && chunk.toolCall) {
|
|
519
|
+
// On first tool call, flush any buffered content
|
|
520
|
+
if (toolCalls.length === 0) {
|
|
521
|
+
// Emit complete reasoning block first
|
|
522
|
+
if (reasoningContent.trim()) {
|
|
523
|
+
this.callbacks.onStreamChunk?.(reasoningContent, 'reasoning');
|
|
524
|
+
}
|
|
525
|
+
// Then emit buffered narration content
|
|
526
|
+
if (suppressStreamNarration && bufferedContent) {
|
|
527
|
+
this.callbacks.onStreamChunk?.(bufferedContent, 'content');
|
|
528
|
+
bufferedContent = '';
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
toolCalls.push(chunk.toolCall);
|
|
532
|
+
}
|
|
533
|
+
else if (chunk.type === 'usage' && chunk.usage) {
|
|
534
|
+
usage = chunk.usage;
|
|
535
|
+
// Emit real token usage during streaming
|
|
536
|
+
this.callbacks.onUsage?.(chunk.usage);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
finally {
|
|
541
|
+
await closeStream();
|
|
542
|
+
}
|
|
543
|
+
// Reset recovery attempts on successful generation
|
|
544
|
+
contextRecoveryAttempts = 0;
|
|
545
|
+
const contextStats = this.getContextStats();
|
|
546
|
+
// IMPORTANT: Only use fullContent for user-visible output
|
|
547
|
+
// reasoningContent is internal model thinking and should NEVER be shown to users
|
|
548
|
+
// We keep it for conversation history (helps the model) but not for display
|
|
549
|
+
const combinedContent = fullContent;
|
|
550
|
+
if (truncatedResponse) {
|
|
551
|
+
const notice = '\n\n[Response truncated: reached safety limit of 120k characters to prevent OOM.]';
|
|
552
|
+
const updated = combinedContent ? `${combinedContent}${notice}` : notice.trim();
|
|
553
|
+
fullContent = updated;
|
|
554
|
+
reasoningContent = '';
|
|
555
|
+
// Partial tool calls are unsafe when truncated; drop them
|
|
556
|
+
toolCalls.length = 0;
|
|
557
|
+
}
|
|
558
|
+
// If no tool calls were issued, emit reasoning and buffered content as complete blocks
|
|
559
|
+
if (toolCalls.length === 0) {
|
|
560
|
+
// Emit complete reasoning block if we have one
|
|
561
|
+
if (reasoningContent.trim()) {
|
|
562
|
+
this.callbacks.onStreamChunk?.(reasoningContent, 'reasoning');
|
|
563
|
+
}
|
|
564
|
+
// Emit buffered narration content
|
|
565
|
+
if (suppressStreamNarration && bufferedContent) {
|
|
566
|
+
this.callbacks.onStreamChunk?.(bufferedContent, 'content');
|
|
567
|
+
bufferedContent = '';
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
// Check if we got tool calls
|
|
571
|
+
if (toolCalls.length > 0) {
|
|
572
|
+
// BEHAVIORAL LOOP DETECTION: Check if model is stuck calling same tool repeatedly
|
|
573
|
+
// This catches patterns like "git status" called 5 times even with slightly different outputs
|
|
574
|
+
const behavioralLoopResult = this.checkBehavioralLoop(toolCalls);
|
|
575
|
+
if (behavioralLoopResult) {
|
|
576
|
+
this.emitAssistantMessage(behavioralLoopResult, { isFinal: true, usage, contextStats, wasStreamed: true });
|
|
577
|
+
this.messages.push({ role: 'assistant', content: behavioralLoopResult });
|
|
578
|
+
return behavioralLoopResult;
|
|
579
|
+
}
|
|
580
|
+
// Loop detection: check if same tool calls are being repeated (exact signature match)
|
|
581
|
+
const signatureCalls = toolCalls.filter(call => !this.shouldSkipLoopDetection(call));
|
|
582
|
+
const toolSignature = signatureCalls.length
|
|
583
|
+
? signatureCalls
|
|
584
|
+
.map((t) => `${t.name}:${JSON.stringify(t.arguments)}`)
|
|
585
|
+
.sort()
|
|
586
|
+
.join('|')
|
|
587
|
+
: null;
|
|
588
|
+
if (toolSignature && toolSignature === this.lastToolCallSignature) {
|
|
589
|
+
this.repeatedToolCallCount++;
|
|
590
|
+
if (this.repeatedToolCallCount >= AgentRuntime.MAX_REPEATED_TOOL_CALLS) {
|
|
591
|
+
// Break out of loop - model is stuck
|
|
592
|
+
const loopMsg = `Tool loop detected: same tools called ${this.repeatedToolCallCount} times. Please try a different approach or provide more specific instructions.`;
|
|
593
|
+
this.emitAssistantMessage(loopMsg, { isFinal: true, usage, contextStats, wasStreamed: true });
|
|
594
|
+
this.messages.push({ role: 'assistant', content: loopMsg });
|
|
595
|
+
this.lastToolCallSignature = null;
|
|
596
|
+
this.repeatedToolCallCount = 0;
|
|
597
|
+
return loopMsg;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
else if (toolSignature) {
|
|
601
|
+
this.lastToolCallSignature = toolSignature;
|
|
602
|
+
this.repeatedToolCallCount = 1;
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
this.lastToolCallSignature = null;
|
|
606
|
+
this.repeatedToolCallCount = 0;
|
|
607
|
+
}
|
|
608
|
+
// Content was already streamed via onStreamChunk, just record it for context
|
|
609
|
+
// (wasStreamed=true prevents duplicate display)
|
|
610
|
+
// Note: Acknowledgement injection happens during streaming (when first tool_call chunk arrives)
|
|
611
|
+
const narration = combinedContent.trim();
|
|
612
|
+
if (narration) {
|
|
613
|
+
this.emitAssistantMessage(narration, {
|
|
614
|
+
isFinal: false,
|
|
615
|
+
usage,
|
|
616
|
+
contextStats,
|
|
617
|
+
wasStreamed: true,
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
this.maybeAckToolCalls(toolCalls, Boolean(narration.length), usage, contextStats);
|
|
621
|
+
const assistantMessage = {
|
|
622
|
+
role: 'assistant',
|
|
623
|
+
content: combinedContent,
|
|
624
|
+
toolCalls,
|
|
625
|
+
};
|
|
626
|
+
this.messages.push(assistantMessage);
|
|
627
|
+
await this.resolveToolCalls(toolCalls);
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
let reply = combinedContent.trim();
|
|
631
|
+
// For reasoning models: if no content but we have reasoning, use reasoning as the response
|
|
632
|
+
// This handles models like DeepSeek-reasoner that put their entire response in reasoning_content
|
|
633
|
+
// The reasoning has already been streamed as 'thought' events showing the AI's thinking
|
|
634
|
+
if (!reply && reasoningContent.trim()) {
|
|
635
|
+
// Use reasoning as the reply - it contains the model's answer
|
|
636
|
+
reply = reasoningContent.trim();
|
|
637
|
+
// Stream the content so it appears as the actual response (not just thoughts)
|
|
638
|
+
this.callbacks.onStreamChunk?.(reply, 'content');
|
|
639
|
+
}
|
|
640
|
+
const { output: finalReply, appended } = ensureNextSteps(reply);
|
|
641
|
+
// Reset loop detection when we get a text response (not just tool calls)
|
|
642
|
+
if (finalReply.length >= 10) {
|
|
643
|
+
this.lastToolCallSignature = null;
|
|
644
|
+
this.repeatedToolCallCount = 0;
|
|
645
|
+
}
|
|
646
|
+
// If we appended a required Next steps section, stream just the delta
|
|
647
|
+
if (appended) {
|
|
648
|
+
this.callbacks.onStreamChunk?.(appended, 'content');
|
|
649
|
+
}
|
|
650
|
+
// Final message - mark as streamed to avoid double-display in UI
|
|
651
|
+
if (finalReply) {
|
|
652
|
+
this.emitAssistantMessage(finalReply, { isFinal: true, usage, contextStats, wasStreamed: true });
|
|
653
|
+
}
|
|
654
|
+
this.messages.push({ role: 'assistant', content: finalReply });
|
|
655
|
+
// Trigger verification for final responses with verifiable claims
|
|
656
|
+
this.triggerVerificationIfNeeded(finalReply);
|
|
657
|
+
return finalReply;
|
|
658
|
+
}
|
|
659
|
+
catch (error) {
|
|
660
|
+
// Auto-recover from context overflow errors (with session-level limit)
|
|
661
|
+
const canRecover = contextRecoveryAttempts < MAX_CONTEXT_RECOVERY_ATTEMPTS &&
|
|
662
|
+
this.totalContextRecoveries < AgentRuntime.MAX_TOTAL_RECOVERIES;
|
|
663
|
+
if (isContextOverflowError(error) && canRecover) {
|
|
664
|
+
contextRecoveryAttempts++;
|
|
665
|
+
this.totalContextRecoveries++;
|
|
666
|
+
const recovered = await this.recoverFromContextOverflow(contextRecoveryAttempts);
|
|
667
|
+
if (recovered) {
|
|
668
|
+
// Notify UI that we're continuing after recovery
|
|
669
|
+
this.callbacks.onContinueAfterRecovery?.();
|
|
670
|
+
// Retry the generation with reduced context
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
// Auto-retry transient errors (network issues, rate limits, server errors)
|
|
675
|
+
if (isTransientError(error) && transientRetryAttempts < MAX_TRANSIENT_RETRIES) {
|
|
676
|
+
transientRetryAttempts++;
|
|
677
|
+
const delayMs = getRetryDelay(transientRetryAttempts);
|
|
678
|
+
this.callbacks.onRetrying?.(transientRetryAttempts, MAX_TRANSIENT_RETRIES, error);
|
|
679
|
+
await sleep(delayMs);
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
// Re-throw if not recoverable or recovery failed
|
|
683
|
+
throw error;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Execute tool calls with optimized concurrency
|
|
689
|
+
*
|
|
690
|
+
* PERF: Uses Promise.all for parallel execution with early result handling.
|
|
691
|
+
* Results are collected in order but execution happens concurrently.
|
|
692
|
+
* For very large batches (>10 tools), uses chunked execution to prevent
|
|
693
|
+
* overwhelming system resources.
|
|
694
|
+
*/
|
|
695
|
+
async resolveToolCalls(toolCalls) {
|
|
696
|
+
const numCalls = toolCalls.length;
|
|
697
|
+
const executedEdits = [];
|
|
698
|
+
// Check for cancellation before starting tool execution
|
|
699
|
+
if (this.cancellationRequested) {
|
|
700
|
+
// Add cancellation message for each pending tool call
|
|
701
|
+
for (const call of toolCalls) {
|
|
702
|
+
this.messages.push({
|
|
703
|
+
role: 'tool',
|
|
704
|
+
name: call.name,
|
|
705
|
+
toolCallId: call.id,
|
|
706
|
+
content: '[Tool execution cancelled by user]',
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
// Fast path: single tool call
|
|
712
|
+
if (numCalls === 1) {
|
|
713
|
+
const call = toolCalls[0];
|
|
714
|
+
// Check cache first - prevent duplicate identical tool calls
|
|
715
|
+
const cached = this.getCachedToolResult(call);
|
|
716
|
+
if (cached !== null) {
|
|
717
|
+
// Return cached result with indicator that it was from cache
|
|
718
|
+
this.messages.push({
|
|
719
|
+
role: 'tool',
|
|
720
|
+
name: call.name,
|
|
721
|
+
toolCallId: call.id,
|
|
722
|
+
content: `[Cached result - identical call already executed]\n\n${cached}`,
|
|
723
|
+
});
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
this.callbacks.onToolExecution?.(call.name, true);
|
|
727
|
+
const output = await this.toolRuntime.execute(call);
|
|
728
|
+
this.callbacks.onToolExecution?.(call.name, false);
|
|
729
|
+
// Cache the result for future identical calls
|
|
730
|
+
this.cacheToolResult(call, output);
|
|
731
|
+
if (this.isEditToolCall(call.name)) {
|
|
732
|
+
executedEdits.push({ call, output, fromCache: false });
|
|
733
|
+
}
|
|
734
|
+
this.messages.push({
|
|
735
|
+
role: 'tool',
|
|
736
|
+
name: call.name,
|
|
737
|
+
toolCallId: call.id,
|
|
738
|
+
content: output,
|
|
739
|
+
});
|
|
740
|
+
await this.maybeExplainEdits(executedEdits);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
// PERF: For reasonable batch sizes, execute all in parallel
|
|
744
|
+
// Check cache for each call and only execute non-cached ones
|
|
745
|
+
if (numCalls <= 10) {
|
|
746
|
+
const cachedResults = [];
|
|
747
|
+
const toExecute = [];
|
|
748
|
+
// Separate cached from non-cached calls
|
|
749
|
+
for (const call of toolCalls) {
|
|
750
|
+
const cached = this.getCachedToolResult(call);
|
|
751
|
+
if (cached !== null) {
|
|
752
|
+
cachedResults.push({ call, output: cached, fromCache: true });
|
|
753
|
+
if (this.isEditToolCall(call.name)) {
|
|
754
|
+
executedEdits.push({ call, output: cached, fromCache: true });
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
toExecute.push(call);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
// Execute non-cached calls in parallel
|
|
762
|
+
if (toExecute.length > 0) {
|
|
763
|
+
const toolNames = toExecute.map(c => c.name).join(', ');
|
|
764
|
+
this.callbacks.onToolExecution?.(toolNames, true);
|
|
765
|
+
const executed = await Promise.all(toExecute.map(async (call) => {
|
|
766
|
+
const output = await this.toolRuntime.execute(call);
|
|
767
|
+
this.cacheToolResult(call, output);
|
|
768
|
+
if (this.isEditToolCall(call.name)) {
|
|
769
|
+
executedEdits.push({ call, output, fromCache: false });
|
|
770
|
+
}
|
|
771
|
+
return { call, output, fromCache: false };
|
|
772
|
+
}));
|
|
773
|
+
this.callbacks.onToolExecution?.(toolNames, false);
|
|
774
|
+
cachedResults.push(...executed);
|
|
775
|
+
}
|
|
776
|
+
// Add all results to messages in the original order
|
|
777
|
+
for (const originalCall of toolCalls) {
|
|
778
|
+
const result = cachedResults.find(r => r.call.id === originalCall.id);
|
|
779
|
+
if (result) {
|
|
780
|
+
const content = result.fromCache
|
|
781
|
+
? `[Cached result - identical call already executed]\n\n${result.output}`
|
|
782
|
+
: result.output;
|
|
783
|
+
this.messages.push({
|
|
784
|
+
role: 'tool',
|
|
785
|
+
name: result.call.name,
|
|
786
|
+
toolCallId: result.call.id,
|
|
787
|
+
content,
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
await this.maybeExplainEdits(executedEdits);
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
// PERF: For large batches, use chunked parallel execution with caching
|
|
795
|
+
const CHUNK_SIZE = 8;
|
|
796
|
+
const allResults = [];
|
|
797
|
+
for (let i = 0; i < numCalls; i += CHUNK_SIZE) {
|
|
798
|
+
const chunk = toolCalls.slice(i, i + CHUNK_SIZE);
|
|
799
|
+
const cachedInChunk = [];
|
|
800
|
+
const toExecuteInChunk = [];
|
|
801
|
+
for (const call of chunk) {
|
|
802
|
+
const cached = this.getCachedToolResult(call);
|
|
803
|
+
if (cached !== null) {
|
|
804
|
+
cachedInChunk.push({ call, output: cached, fromCache: true });
|
|
805
|
+
if (this.isEditToolCall(call.name)) {
|
|
806
|
+
executedEdits.push({ call, output: cached, fromCache: true });
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
toExecuteInChunk.push(call);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
if (toExecuteInChunk.length > 0) {
|
|
814
|
+
const chunkNames = toExecuteInChunk.map(c => c.name).join(', ');
|
|
815
|
+
this.callbacks.onToolExecution?.(chunkNames, true);
|
|
816
|
+
const executed = await Promise.all(toExecuteInChunk.map(async (call) => {
|
|
817
|
+
const output = await this.toolRuntime.execute(call);
|
|
818
|
+
this.cacheToolResult(call, output);
|
|
819
|
+
if (this.isEditToolCall(call.name)) {
|
|
820
|
+
executedEdits.push({ call, output, fromCache: false });
|
|
821
|
+
}
|
|
822
|
+
return { call, output, fromCache: false };
|
|
823
|
+
}));
|
|
824
|
+
this.callbacks.onToolExecution?.(chunkNames, false);
|
|
825
|
+
cachedInChunk.push(...executed);
|
|
826
|
+
}
|
|
827
|
+
allResults.push(...cachedInChunk);
|
|
828
|
+
}
|
|
829
|
+
// Add results to messages in original order
|
|
830
|
+
for (const originalCall of toolCalls) {
|
|
831
|
+
const result = allResults.find(r => r.call.id === originalCall.id);
|
|
832
|
+
if (result) {
|
|
833
|
+
const content = result.fromCache
|
|
834
|
+
? `[Cached result - identical call already executed]\n\n${result.output}`
|
|
835
|
+
: result.output;
|
|
836
|
+
this.messages.push({
|
|
837
|
+
role: 'tool',
|
|
838
|
+
name: result.call.name,
|
|
839
|
+
toolCallId: result.call.id,
|
|
840
|
+
content,
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
await this.maybeExplainEdits(executedEdits);
|
|
845
|
+
}
|
|
846
|
+
truncateEditOutput(output) {
|
|
847
|
+
if (!output) {
|
|
848
|
+
return '[no tool output available]';
|
|
849
|
+
}
|
|
850
|
+
const limit = AgentRuntime.EDIT_CONTEXT_CHAR_LIMIT;
|
|
851
|
+
if (output.length <= limit) {
|
|
852
|
+
return output;
|
|
853
|
+
}
|
|
854
|
+
const head = output.slice(0, Math.floor(limit * 0.7));
|
|
855
|
+
const tail = output.slice(-Math.floor(limit * 0.2));
|
|
856
|
+
const omitted = output.length - head.length - tail.length;
|
|
857
|
+
return `${head}\n... [truncated ${omitted} chars] ...\n${tail}`;
|
|
858
|
+
}
|
|
859
|
+
buildEditExplanationPrompt(toolName, files, toolOutput) {
|
|
860
|
+
const fileNames = files.map(f => f.split('/').pop()).join(', ');
|
|
861
|
+
const userContent = [
|
|
862
|
+
`Summarize this ${toolName} operation in 1-2 sentences for the UI status line.`,
|
|
863
|
+
`Files: ${fileNames || 'unknown'}`,
|
|
864
|
+
'',
|
|
865
|
+
'Output:',
|
|
866
|
+
toolOutput.slice(0, 500), // Limit context to reduce hallucination
|
|
867
|
+
].join('\n');
|
|
868
|
+
return [
|
|
869
|
+
{
|
|
870
|
+
role: 'system',
|
|
871
|
+
content: 'You write brief UI status messages. Reply with ONLY a 1-2 sentence summary. No analysis, no reasoning, no explanations of your process.',
|
|
872
|
+
},
|
|
873
|
+
{ role: 'user', content: userContent },
|
|
874
|
+
// Prefill assistant response to guide format
|
|
875
|
+
{ role: 'assistant', content: '' },
|
|
876
|
+
];
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Extract clean explanation from model output that may contain reasoning.
|
|
880
|
+
* Reasoning models like deepseek-reasoner output chain-of-thought which we need to filter.
|
|
881
|
+
*/
|
|
882
|
+
extractCleanExplanation(rawOutput) {
|
|
883
|
+
if (!rawOutput)
|
|
884
|
+
return '';
|
|
885
|
+
// Check for common reasoning patterns and extract final output
|
|
886
|
+
const patterns = [
|
|
887
|
+
// "Final explanation:" or "Final concise explanation:" patterns
|
|
888
|
+
/(?:final\s+(?:concise\s+)?explanation\s*:?\s*["']?)([^"'\n]+(?:["']|$))/i,
|
|
889
|
+
// Quoted final output
|
|
890
|
+
/"([^"]{20,})"(?:\s*\([^)]+\))?$/,
|
|
891
|
+
// Last paragraph after deliberation markers
|
|
892
|
+
/(?:draft|summary|output|result)\s*:?\s*\n?\s*["']?([^"'\n]+)/i,
|
|
893
|
+
];
|
|
894
|
+
for (const pattern of patterns) {
|
|
895
|
+
const match = rawOutput.match(pattern);
|
|
896
|
+
if (match?.[1]) {
|
|
897
|
+
// Clean up the extracted text
|
|
898
|
+
return match[1].replace(/^["']|["']$/g, '').trim();
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
// Check if the output looks like reasoning (contains deliberation markers)
|
|
902
|
+
const reasoningMarkers = [
|
|
903
|
+
/^first,?\s+(the user|i need|let me|looking at)/i,
|
|
904
|
+
/^(from this|based on|analyzing|the tool output shows)/i,
|
|
905
|
+
/^(intent:|impact:|user-visible changes:)/im,
|
|
906
|
+
/^(now,?\s+i (?:need|should|will)|let me (?:craft|think|analyze))/i,
|
|
907
|
+
/\b(draft:|final (?:draft|explanation):)/i,
|
|
908
|
+
];
|
|
909
|
+
const hasReasoning = reasoningMarkers.some(marker => marker.test(rawOutput));
|
|
910
|
+
if (hasReasoning) {
|
|
911
|
+
// Try to extract the last meaningful sentence/paragraph
|
|
912
|
+
const lines = rawOutput.split('\n').filter(l => l.trim());
|
|
913
|
+
// Look for the last line that looks like a summary (not a reasoning line)
|
|
914
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
915
|
+
const line = lines[i].trim();
|
|
916
|
+
// Skip lines that look like reasoning
|
|
917
|
+
if (reasoningMarkers.some(m => m.test(line)))
|
|
918
|
+
continue;
|
|
919
|
+
// Skip very short lines or lines that are just labels
|
|
920
|
+
if (line.length < 30 || /^[\w\s]+:$/.test(line))
|
|
921
|
+
continue;
|
|
922
|
+
// Found a good candidate
|
|
923
|
+
return line.replace(/^["']|["']$/g, '').replace(/\([^)]+\)$/, '').trim();
|
|
924
|
+
}
|
|
925
|
+
// Fallback: take last 200 chars and try to find a sentence
|
|
926
|
+
const tail = rawOutput.slice(-300);
|
|
927
|
+
const lastSentence = tail.match(/[A-Z][^.!?]*[.!?](?:\s|$)/g);
|
|
928
|
+
if (lastSentence?.length) {
|
|
929
|
+
return lastSentence[lastSentence.length - 1].trim();
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
// No reasoning detected, return as-is but truncate if too long
|
|
933
|
+
if (rawOutput.length > 500) {
|
|
934
|
+
// Find a sentence break near the end
|
|
935
|
+
const truncated = rawOutput.slice(0, 500);
|
|
936
|
+
const lastPeriod = truncated.lastIndexOf('.');
|
|
937
|
+
if (lastPeriod > 200) {
|
|
938
|
+
return truncated.slice(0, lastPeriod + 1);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return rawOutput.trim();
|
|
942
|
+
}
|
|
943
|
+
async maybeExplainEdits(results) {
|
|
944
|
+
if (!this.explainEdits || results.length === 0 || this.cancellationRequested) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
for (const result of results) {
|
|
948
|
+
if (result.fromCache || !this.isEditToolCall(result.call.name)) {
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
951
|
+
const files = this.getEditedFiles([result.call]);
|
|
952
|
+
const truncatedOutput = this.truncateEditOutput(result.output);
|
|
953
|
+
const prompt = this.buildEditExplanationPrompt(result.call.name, files, truncatedOutput);
|
|
954
|
+
try {
|
|
955
|
+
const response = await this.provider.generate(prompt, []);
|
|
956
|
+
if (response.type !== 'message') {
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
// Extract clean explanation, filtering out any reasoning/deliberation
|
|
960
|
+
const rawExplanation = response.content?.trim() ?? '';
|
|
961
|
+
const explanation = this.extractCleanExplanation(rawExplanation);
|
|
962
|
+
if (explanation) {
|
|
963
|
+
this.callbacks.onEditExplanation?.({
|
|
964
|
+
explanation,
|
|
965
|
+
files,
|
|
966
|
+
toolName: result.call.name,
|
|
967
|
+
toolCallId: result.call.id,
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
catch (error) {
|
|
972
|
+
logDebug(`[agent] Failed to generate edit explanation: ${safeErrorMessage(error)}`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
get providerTools() {
|
|
977
|
+
return this.toolRuntime.listProviderTools();
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Whether to suppress tool narration in the content field.
|
|
981
|
+
* Previously suppressed for OpenAI but now we show all thinking/narration.
|
|
982
|
+
*/
|
|
983
|
+
shouldSuppressToolNarration() {
|
|
984
|
+
return false; // Always show thinking/narration
|
|
985
|
+
}
|
|
986
|
+
emitAssistantMessage(content, metadata) {
|
|
987
|
+
if (!content || !content.trim()) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
const elapsedMs = this.activeRun ? Date.now() - this.activeRun.startedAt : undefined;
|
|
991
|
+
const payload = { ...metadata };
|
|
992
|
+
if (typeof elapsedMs === 'number') {
|
|
993
|
+
payload.elapsedMs = elapsedMs;
|
|
994
|
+
}
|
|
995
|
+
this.callbacks.onAssistantMessage?.(content, payload);
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Trigger verification for a final response if callback is registered
|
|
999
|
+
* and response contains verifiable claims (implementation, build success, etc.)
|
|
1000
|
+
*/
|
|
1001
|
+
triggerVerificationIfNeeded(response) {
|
|
1002
|
+
if (!this.callbacks.onVerificationNeeded) {
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
// Only trigger verification for responses that likely contain verifiable claims
|
|
1006
|
+
// These patterns indicate the model is claiming to have completed work
|
|
1007
|
+
const verifiablePatterns = [
|
|
1008
|
+
/\b(implemented|created|wrote|added|fixed|built|deployed|completed|refactored)\b/i,
|
|
1009
|
+
/\b(tests?\s+(are\s+)?pass(ing)?|build\s+succeed)/i,
|
|
1010
|
+
/\b(file|function|class|module|component)\s+(has been|is now|was)\s+(created|updated|modified)/i,
|
|
1011
|
+
/✅|✓|\[done\]|\[complete\]/i,
|
|
1012
|
+
/\bcommit(ted)?\b.*\b(success|done)\b/i,
|
|
1013
|
+
];
|
|
1014
|
+
const hasVerifiableClaims = verifiablePatterns.some(pattern => pattern.test(response));
|
|
1015
|
+
if (!hasVerifiableClaims) {
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
// Build conversation history for context (last 5 user/assistant exchanges)
|
|
1019
|
+
const conversationHistory = [];
|
|
1020
|
+
const recentMessages = this.messages.slice(-10);
|
|
1021
|
+
for (const msg of recentMessages) {
|
|
1022
|
+
if (msg.role === 'user' || msg.role === 'assistant') {
|
|
1023
|
+
const content = typeof msg.content === 'string' ? msg.content : '';
|
|
1024
|
+
if (content.length > 0) {
|
|
1025
|
+
conversationHistory.push(`${msg.role}: ${content.slice(0, 500)}`);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
// Trigger verification callback
|
|
1030
|
+
this.callbacks.onVerificationNeeded(response, {
|
|
1031
|
+
workingDirectory: this.workingDirectory,
|
|
1032
|
+
conversationHistory,
|
|
1033
|
+
provider: this.providerId,
|
|
1034
|
+
model: this.modelId,
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Extract a "command hash" from tool arguments for behavioral loop detection.
|
|
1039
|
+
* For execute_bash, this is the actual command. For other tools, key identifying args.
|
|
1040
|
+
*/
|
|
1041
|
+
extractCmdHash(name, args) {
|
|
1042
|
+
// For bash/execute commands, extract the command itself
|
|
1043
|
+
if (name === 'execute_bash' || name === 'Bash') {
|
|
1044
|
+
const cmd = args['command'];
|
|
1045
|
+
if (cmd) {
|
|
1046
|
+
// Normalize: trim, take first 100 chars, remove variable parts like timestamps
|
|
1047
|
+
return cmd.trim().slice(0, 100).replace(/\d{10,}/g, 'N');
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
// For file operations, use the path
|
|
1051
|
+
if (name === 'read_file' || name === 'Read' || name === 'read_files') {
|
|
1052
|
+
const path = args['path'] || args['file_path'] || args['paths'];
|
|
1053
|
+
if (path)
|
|
1054
|
+
return `path:${JSON.stringify(path).slice(0, 100)}`;
|
|
1055
|
+
}
|
|
1056
|
+
if (name === 'list_files' || name === 'Glob') {
|
|
1057
|
+
const path = args['path'] || args['pattern'];
|
|
1058
|
+
if (path)
|
|
1059
|
+
return `path:${JSON.stringify(path).slice(0, 100)}`;
|
|
1060
|
+
}
|
|
1061
|
+
// For search, use the query/pattern
|
|
1062
|
+
if (name === 'Grep' || name === 'grep' || name === 'search') {
|
|
1063
|
+
const pattern = args['pattern'] || args['query'];
|
|
1064
|
+
if (pattern)
|
|
1065
|
+
return `search:${String(pattern).slice(0, 100)}`;
|
|
1066
|
+
}
|
|
1067
|
+
// Default: use first significant arg value
|
|
1068
|
+
const firstArg = Object.values(args)[0];
|
|
1069
|
+
if (firstArg) {
|
|
1070
|
+
return String(firstArg).slice(0, 100);
|
|
1071
|
+
}
|
|
1072
|
+
return 'no-args';
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Check for behavioral loops - model calling the same tool with similar args repeatedly.
|
|
1076
|
+
* Returns an error message if a loop is detected, null otherwise.
|
|
1077
|
+
*
|
|
1078
|
+
* FUNDAMENTAL PREVENTION: Cached calls are excluded from loop detection since they
|
|
1079
|
+
* don't actually execute (the cache provides the result). This means:
|
|
1080
|
+
* - First call: executes and caches result
|
|
1081
|
+
* - Second identical call: returns cached result, NOT counted toward loop
|
|
1082
|
+
* - Only genuinely NEW (non-cached) repetitive calls trigger loop detection
|
|
1083
|
+
*
|
|
1084
|
+
* Direct execution tools (bash/edit) are also exempt to avoid short-circuiting
|
|
1085
|
+
* legitimate repeated user commands.
|
|
1086
|
+
*
|
|
1087
|
+
* This catches patterns like:
|
|
1088
|
+
* - "git status -sb" called 3 times with DIFFERENT outputs (cache miss each time)
|
|
1089
|
+
* - Repeated file reads where file content changed
|
|
1090
|
+
* - Repeated searches with same pattern but new results
|
|
1091
|
+
*/
|
|
1092
|
+
checkBehavioralLoop(toolCalls) {
|
|
1093
|
+
// Skip loop detection for direct execution tools (bash/edit) to avoid false positives
|
|
1094
|
+
const loopEligibleCalls = toolCalls.filter(call => !this.shouldSkipLoopDetection(call));
|
|
1095
|
+
if (loopEligibleCalls.length === 0) {
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
// Filter out calls that will be served from cache - these don't count toward loops
|
|
1099
|
+
// since they're handled fundamentally by the caching mechanism
|
|
1100
|
+
const nonCachedCalls = loopEligibleCalls.filter(call => this.getCachedToolResult(call) === null);
|
|
1101
|
+
// If all calls are cached, no loop detection needed
|
|
1102
|
+
if (nonCachedCalls.length === 0) {
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
// Count existing occurrences in recent history
|
|
1106
|
+
const existingCounts = new Map();
|
|
1107
|
+
for (const { name, cmdHash } of this.recentToolCalls) {
|
|
1108
|
+
const key = `${name}:${cmdHash}`;
|
|
1109
|
+
existingCounts.set(key, (existingCounts.get(key) ?? 0) + 1);
|
|
1110
|
+
}
|
|
1111
|
+
// Check if ANY incoming NON-CACHED call would exceed threshold
|
|
1112
|
+
for (const call of nonCachedCalls) {
|
|
1113
|
+
const cmdHash = this.extractCmdHash(call.name, call.arguments ?? {});
|
|
1114
|
+
const key = `${call.name}:${cmdHash}`;
|
|
1115
|
+
const currentCount = existingCounts.get(key) ?? 0;
|
|
1116
|
+
// If adding this call would reach or exceed threshold, block immediately
|
|
1117
|
+
if (currentCount + 1 >= AgentRuntime.BEHAVIORAL_LOOP_THRESHOLD) {
|
|
1118
|
+
// Reset history to prevent immediate re-trigger
|
|
1119
|
+
this.recentToolCalls = [];
|
|
1120
|
+
return `Behavioral loop detected: "${call.name}" called ${currentCount + 1} times with similar arguments. The task appears stuck. Please try a different approach or provide more specific instructions.`;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
// Track only non-cached tool calls (cached ones are handled by caching)
|
|
1124
|
+
for (const call of nonCachedCalls) {
|
|
1125
|
+
const cmdHash = this.extractCmdHash(call.name, call.arguments ?? {});
|
|
1126
|
+
this.recentToolCalls.push({ name: call.name, cmdHash });
|
|
1127
|
+
}
|
|
1128
|
+
// Keep only recent history
|
|
1129
|
+
while (this.recentToolCalls.length > AgentRuntime.TOOL_HISTORY_SIZE) {
|
|
1130
|
+
this.recentToolCalls.shift();
|
|
1131
|
+
}
|
|
1132
|
+
return null;
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Provide an acknowledgement before the first tool call when the model
|
|
1136
|
+
* hasn't narrated its plan. This keeps the UI responsive and lets the
|
|
1137
|
+
* user know work is happening even before tool output arrives.
|
|
1138
|
+
*/
|
|
1139
|
+
maybeAckToolCalls(toolCalls, hasModelNarration, usage, contextStats) {
|
|
1140
|
+
if (!toolCalls?.length) {
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
const acknowledgement = this.callbacks.onBeforeFirstToolCall?.(toolCalls.map((call) => call.name), hasModelNarration);
|
|
1144
|
+
if (acknowledgement && acknowledgement.trim()) {
|
|
1145
|
+
this.emitAssistantMessage(acknowledgement, {
|
|
1146
|
+
isFinal: false,
|
|
1147
|
+
usage,
|
|
1148
|
+
contextStats,
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Reset behavioral loop tracking (called when user provides new input or task completes)
|
|
1154
|
+
*/
|
|
1155
|
+
resetBehavioralLoopTracking() {
|
|
1156
|
+
this.recentToolCalls = [];
|
|
1157
|
+
this.lastToolCallSignature = null;
|
|
1158
|
+
this.repeatedToolCallCount = 0;
|
|
1159
|
+
// Note: we DON'T clear toolResultCache here for cacheable tools; stateful tools bypass caching
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Create a stable cache key for a tool call based on name and arguments
|
|
1163
|
+
*/
|
|
1164
|
+
getToolCacheKey(call) {
|
|
1165
|
+
const args = call.arguments ?? {};
|
|
1166
|
+
// Sort keys for consistent ordering
|
|
1167
|
+
const sortedArgs = Object.keys(args).sort().reduce((acc, key) => {
|
|
1168
|
+
acc[key] = args[key];
|
|
1169
|
+
return acc;
|
|
1170
|
+
}, {});
|
|
1171
|
+
return `${call.name}:${JSON.stringify(sortedArgs)}`;
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Only cache tools that are safe to reuse; stateful commands must always execute.
|
|
1175
|
+
*/
|
|
1176
|
+
isCacheableTool(call) {
|
|
1177
|
+
const nameLower = call.name.toLowerCase();
|
|
1178
|
+
return !AgentRuntime.NON_CACHEABLE_TOOL_NAMES.has(nameLower);
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Direct execution tools should not trigger behavioral loop short-circuiting.
|
|
1182
|
+
*/
|
|
1183
|
+
shouldSkipLoopDetection(call) {
|
|
1184
|
+
const nameLower = call.name.toLowerCase();
|
|
1185
|
+
return AgentRuntime.LOOP_EXEMPT_TOOL_NAMES.has(nameLower);
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Get cached result for a tool call, or null if not cached
|
|
1189
|
+
*/
|
|
1190
|
+
getCachedToolResult(call) {
|
|
1191
|
+
if (!this.isCacheableTool(call)) {
|
|
1192
|
+
return null;
|
|
1193
|
+
}
|
|
1194
|
+
const key = this.getToolCacheKey(call);
|
|
1195
|
+
return this.toolResultCache.get(key) ?? null;
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Cache a tool result for future identical calls
|
|
1199
|
+
*/
|
|
1200
|
+
cacheToolResult(call, result) {
|
|
1201
|
+
if (!this.isCacheableTool(call)) {
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1204
|
+
const key = this.getToolCacheKey(call);
|
|
1205
|
+
// Evict oldest entries if cache is full
|
|
1206
|
+
if (this.toolResultCache.size >= AgentRuntime.TOOL_CACHE_MAX_SIZE) {
|
|
1207
|
+
const firstKey = this.toolResultCache.keys().next().value;
|
|
1208
|
+
if (firstKey) {
|
|
1209
|
+
this.toolResultCache.delete(firstKey);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
this.toolResultCache.set(key, result);
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Drain the list of tools executed during the most recent send() call.
|
|
1216
|
+
* Used by higher-level orchestrators to reason about progress.
|
|
1217
|
+
*/
|
|
1218
|
+
drainToolExecutions() {
|
|
1219
|
+
if (typeof this.toolRuntime.getToolHistory !== 'function') {
|
|
1220
|
+
return [];
|
|
1221
|
+
}
|
|
1222
|
+
const history = this.toolRuntime.getToolHistory();
|
|
1223
|
+
const newEntries = history.slice(this.toolHistoryCursor);
|
|
1224
|
+
this.toolHistoryCursor = history.length;
|
|
1225
|
+
return newEntries.map((entry) => ({
|
|
1226
|
+
name: entry.toolName,
|
|
1227
|
+
success: entry.success ?? true,
|
|
1228
|
+
hasOutput: entry.hasOutput ?? true,
|
|
1229
|
+
}));
|
|
1230
|
+
}
|
|
1231
|
+
getHistory() {
|
|
1232
|
+
return this.messages.map(cloneMessage);
|
|
1233
|
+
}
|
|
1234
|
+
loadHistory(history) {
|
|
1235
|
+
this.messages.length = 0;
|
|
1236
|
+
if (history.length === 0) {
|
|
1237
|
+
if (this.baseSystemPrompt) {
|
|
1238
|
+
this.messages.push({ role: 'system', content: this.baseSystemPrompt });
|
|
1239
|
+
}
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
for (const message of history) {
|
|
1243
|
+
this.messages.push(cloneMessage(message));
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
clearHistory() {
|
|
1247
|
+
this.messages.length = 0;
|
|
1248
|
+
if (this.baseSystemPrompt) {
|
|
1249
|
+
this.messages.push({ role: 'system', content: this.baseSystemPrompt });
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Prune messages if approaching context limit
|
|
1254
|
+
*
|
|
1255
|
+
* This runs BEFORE each generation to ensure we stay within budget.
|
|
1256
|
+
* If LLM summarization is available, it will create intelligent summaries
|
|
1257
|
+
* instead of just removing old messages.
|
|
1258
|
+
*/
|
|
1259
|
+
async pruneMessagesIfNeeded() {
|
|
1260
|
+
if (!this.contextManager) {
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
if (this.contextManager.isApproachingLimit(this.messages)) {
|
|
1264
|
+
// Try LLM-based summarization first (preserves context better)
|
|
1265
|
+
const result = await this.contextManager.pruneMessagesWithSummary(this.messages);
|
|
1266
|
+
if (result.removed > 0) {
|
|
1267
|
+
// Replace messages with pruned/summarized version
|
|
1268
|
+
this.messages.length = 0;
|
|
1269
|
+
this.messages.push(...result.pruned);
|
|
1270
|
+
// Notify callback with enriched stats
|
|
1271
|
+
const stats = this.contextManager.getStats(this.messages);
|
|
1272
|
+
const enrichedStats = {
|
|
1273
|
+
...stats,
|
|
1274
|
+
summarized: result.summarized,
|
|
1275
|
+
method: result.summarized ? 'llm-summary' : 'simple-prune',
|
|
1276
|
+
};
|
|
1277
|
+
this.callbacks.onContextPruned?.(result.removed, enrichedStats);
|
|
1278
|
+
if (process.env['DEBUG_CONTEXT']) {
|
|
1279
|
+
logDebug(`[Context Manager] ${result.summarized ? 'Summarized' : 'Pruned'} ${result.removed} messages. ` +
|
|
1280
|
+
`Tokens: ${stats.totalTokens} (${stats.percentage}%)`);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Get current context statistics
|
|
1287
|
+
*/
|
|
1288
|
+
getContextStats() {
|
|
1289
|
+
if (!this.contextManager) {
|
|
1290
|
+
return null;
|
|
1291
|
+
}
|
|
1292
|
+
return this.contextManager.getStats(this.messages);
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Get context manager instance
|
|
1296
|
+
*/
|
|
1297
|
+
getContextManager() {
|
|
1298
|
+
return this.contextManager;
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Fetch model info from the provider API.
|
|
1302
|
+
* Returns context window and token limits from the real API.
|
|
1303
|
+
* Results are cached for the lifetime of this agent instance.
|
|
1304
|
+
*/
|
|
1305
|
+
async fetchModelInfo() {
|
|
1306
|
+
if (this.modelInfoFetched) {
|
|
1307
|
+
return this.modelInfo;
|
|
1308
|
+
}
|
|
1309
|
+
this.modelInfoFetched = true;
|
|
1310
|
+
if (typeof this.provider.getModelInfo === 'function') {
|
|
1311
|
+
try {
|
|
1312
|
+
this.modelInfo = await this.provider.getModelInfo();
|
|
1313
|
+
}
|
|
1314
|
+
catch {
|
|
1315
|
+
// Ignore errors - fall back to null
|
|
1316
|
+
this.modelInfo = null;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
return this.modelInfo;
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Get cached model info (must call fetchModelInfo first)
|
|
1323
|
+
*/
|
|
1324
|
+
getModelInfo() {
|
|
1325
|
+
return this.modelInfo;
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Get the context window size from the provider API.
|
|
1329
|
+
* Returns null if the provider doesn't support this or the API call fails.
|
|
1330
|
+
*/
|
|
1331
|
+
async getContextWindowFromProvider() {
|
|
1332
|
+
const info = await this.fetchModelInfo();
|
|
1333
|
+
return info?.contextWindow ?? null;
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Auto-recover from context overflow errors by aggressively pruning messages.
|
|
1337
|
+
*
|
|
1338
|
+
* This is called when an API call fails due to context length exceeding limits.
|
|
1339
|
+
* It performs increasingly aggressive pruning on each attempt:
|
|
1340
|
+
* - Attempt 1: Remove 30% of oldest messages + truncate tool outputs to 5k
|
|
1341
|
+
* - Attempt 2: Remove 50% of oldest messages + truncate tool outputs to 2k
|
|
1342
|
+
* - Attempt 3: Remove 70% of oldest messages + truncate tool outputs to 500 chars
|
|
1343
|
+
*
|
|
1344
|
+
* @returns true if recovery was successful (context was reduced)
|
|
1345
|
+
*/
|
|
1346
|
+
async recoverFromContextOverflow(attempt) {
|
|
1347
|
+
// Calculate reduction percentage based on attempt
|
|
1348
|
+
const reductionPercentages = [0.3, 0.5, 0.7];
|
|
1349
|
+
const reductionPercent = reductionPercentages[attempt - 1] ?? 0.7;
|
|
1350
|
+
// Increasingly aggressive tool output truncation limits
|
|
1351
|
+
const toolOutputLimits = [5000, 2000, 500];
|
|
1352
|
+
const toolOutputLimit = toolOutputLimits[attempt - 1] ?? 500;
|
|
1353
|
+
// Notify UI about recovery attempt
|
|
1354
|
+
const message = `Context overflow detected. Auto-squishing context (attempt ${attempt}/${MAX_CONTEXT_RECOVERY_ATTEMPTS}, removing ${Math.round(reductionPercent * 100)}% of history)...`;
|
|
1355
|
+
this.callbacks.onContextRecovery?.(attempt, MAX_CONTEXT_RECOVERY_ATTEMPTS, message);
|
|
1356
|
+
this.callbacks.onContextSquishing?.(message);
|
|
1357
|
+
// Separate system messages from conversation
|
|
1358
|
+
const systemMessages = [];
|
|
1359
|
+
const conversationMessages = [];
|
|
1360
|
+
for (const msg of this.messages) {
|
|
1361
|
+
if (msg.role === 'system') {
|
|
1362
|
+
systemMessages.push(msg);
|
|
1363
|
+
}
|
|
1364
|
+
else {
|
|
1365
|
+
conversationMessages.push(msg);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
// Calculate how many messages to remove (target)
|
|
1369
|
+
const targetRemoveCount = Math.floor(conversationMessages.length * reductionPercent);
|
|
1370
|
+
if (targetRemoveCount === 0 || conversationMessages.length <= 2) {
|
|
1371
|
+
// Nothing to remove or too few messages - can't recover
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
// Group messages into conversation "turns" to maintain tool call/result pairing
|
|
1375
|
+
// A turn is: [user] or [assistant + tool results] or [assistant without tools]
|
|
1376
|
+
const turns = [];
|
|
1377
|
+
let currentTurn = [];
|
|
1378
|
+
for (let i = 0; i < conversationMessages.length; i++) {
|
|
1379
|
+
const msg = conversationMessages[i];
|
|
1380
|
+
if (msg.role === 'user') {
|
|
1381
|
+
// User messages start a new turn
|
|
1382
|
+
if (currentTurn.length > 0) {
|
|
1383
|
+
turns.push(currentTurn);
|
|
1384
|
+
}
|
|
1385
|
+
currentTurn = [msg];
|
|
1386
|
+
}
|
|
1387
|
+
else if (msg.role === 'assistant') {
|
|
1388
|
+
// Assistant messages start a new turn (flush previous)
|
|
1389
|
+
if (currentTurn.length > 0) {
|
|
1390
|
+
turns.push(currentTurn);
|
|
1391
|
+
}
|
|
1392
|
+
currentTurn = [msg];
|
|
1393
|
+
}
|
|
1394
|
+
else if (msg.role === 'tool') {
|
|
1395
|
+
// Tool results belong to the current assistant turn
|
|
1396
|
+
currentTurn.push(msg);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
// Don't forget the last turn
|
|
1400
|
+
if (currentTurn.length > 0) {
|
|
1401
|
+
turns.push(currentTurn);
|
|
1402
|
+
}
|
|
1403
|
+
// Calculate how many turns to remove
|
|
1404
|
+
const targetTurnsToRemove = Math.floor(turns.length * reductionPercent);
|
|
1405
|
+
if (targetTurnsToRemove === 0 || turns.length <= 2) {
|
|
1406
|
+
return false;
|
|
1407
|
+
}
|
|
1408
|
+
// Keep recent turns (remove from the beginning)
|
|
1409
|
+
const keepTurns = turns.slice(targetTurnsToRemove);
|
|
1410
|
+
// IMPORTANT: Ensure we don't start with orphaned tool messages
|
|
1411
|
+
// The first kept turn must NOT be a tool-only turn
|
|
1412
|
+
let startIndex = 0;
|
|
1413
|
+
while (startIndex < keepTurns.length) {
|
|
1414
|
+
const firstTurn = keepTurns[startIndex];
|
|
1415
|
+
if (firstTurn && firstTurn.length > 0) {
|
|
1416
|
+
const firstMsg = firstTurn[0];
|
|
1417
|
+
// If first message is a tool result, skip this turn
|
|
1418
|
+
if (firstMsg?.role === 'tool') {
|
|
1419
|
+
startIndex++;
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
// If first message is an assistant with tool calls but we're missing results,
|
|
1423
|
+
// check if all tool results are present
|
|
1424
|
+
if (firstMsg?.role === 'assistant' && firstMsg.toolCalls && firstMsg.toolCalls.length > 0) {
|
|
1425
|
+
// PERF: Pre-compute tool call IDs as array, use direct Set lookup
|
|
1426
|
+
const toolCallIds = firstMsg.toolCalls.map(tc => tc.id);
|
|
1427
|
+
const presentToolResultIds = new Set(firstTurn.filter(m => m.role === 'tool').map(m => m.toolCallId));
|
|
1428
|
+
// PERF: Direct has() calls with early exit instead of spread + every()
|
|
1429
|
+
let allPresent = true;
|
|
1430
|
+
for (const id of toolCallIds) {
|
|
1431
|
+
if (!presentToolResultIds.has(id)) {
|
|
1432
|
+
allPresent = false;
|
|
1433
|
+
break;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
if (allPresent) {
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1439
|
+
// Otherwise skip this turn
|
|
1440
|
+
startIndex++;
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
break;
|
|
1445
|
+
}
|
|
1446
|
+
const validTurns = keepTurns.slice(startIndex);
|
|
1447
|
+
if (validTurns.length === 0) {
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
// Flatten valid turns back to messages
|
|
1451
|
+
const keepMessages = validTurns.flat();
|
|
1452
|
+
const actualRemoveCount = conversationMessages.length - keepMessages.length;
|
|
1453
|
+
// Aggressively truncate tool outputs in remaining messages
|
|
1454
|
+
let truncatedCount = 0;
|
|
1455
|
+
for (const msg of keepMessages) {
|
|
1456
|
+
if (msg.role === 'tool' && msg.content) {
|
|
1457
|
+
const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
|
|
1458
|
+
if (content.length > toolOutputLimit) {
|
|
1459
|
+
// Truncate with smart ending
|
|
1460
|
+
const truncated = content.slice(0, toolOutputLimit);
|
|
1461
|
+
const lastNewline = truncated.lastIndexOf('\n');
|
|
1462
|
+
const cutPoint = lastNewline > toolOutputLimit * 0.7 ? lastNewline : toolOutputLimit;
|
|
1463
|
+
msg.content = `${truncated.slice(0, cutPoint)}\n\n[... truncated ${content.length - cutPoint} chars for context recovery ...]`;
|
|
1464
|
+
truncatedCount++;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
// Also truncate very long assistant messages
|
|
1468
|
+
if (msg.role === 'assistant' && msg.content && msg.content.length > toolOutputLimit * 2) {
|
|
1469
|
+
const content = msg.content;
|
|
1470
|
+
const limit = toolOutputLimit * 2;
|
|
1471
|
+
const truncated = content.slice(0, limit);
|
|
1472
|
+
const lastNewline = truncated.lastIndexOf('\n');
|
|
1473
|
+
const cutPoint = lastNewline > limit * 0.8 ? lastNewline : limit;
|
|
1474
|
+
msg.content = `${truncated.slice(0, cutPoint)}\n\n[... truncated for context recovery ...]`;
|
|
1475
|
+
truncatedCount++;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
// Also truncate system messages if they're huge (except first system prompt)
|
|
1479
|
+
for (let i = 1; i < systemMessages.length; i++) {
|
|
1480
|
+
const sys = systemMessages[i];
|
|
1481
|
+
if (sys && sys.content && sys.content.length > toolOutputLimit) {
|
|
1482
|
+
sys.content = `${sys.content.slice(0, toolOutputLimit)}\n[... truncated ...]`;
|
|
1483
|
+
truncatedCount++;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
// Rebuild message array
|
|
1487
|
+
this.messages.length = 0;
|
|
1488
|
+
// Add system messages
|
|
1489
|
+
for (const sys of systemMessages) {
|
|
1490
|
+
this.messages.push(sys);
|
|
1491
|
+
}
|
|
1492
|
+
// Add summary notice
|
|
1493
|
+
this.messages.push({
|
|
1494
|
+
role: 'system',
|
|
1495
|
+
content: `[Auto Context Recovery] Removed ${actualRemoveCount} messages and truncated ${truncatedCount} large outputs to stay within token limits.`,
|
|
1496
|
+
});
|
|
1497
|
+
// Add remaining conversation (maintaining tool call/result pairing)
|
|
1498
|
+
for (const msg of keepMessages) {
|
|
1499
|
+
this.messages.push(msg);
|
|
1500
|
+
}
|
|
1501
|
+
// Notify about pruning
|
|
1502
|
+
const stats = this.contextManager?.getStats(this.messages) ?? {};
|
|
1503
|
+
this.callbacks.onContextPruned?.(actualRemoveCount, {
|
|
1504
|
+
...stats,
|
|
1505
|
+
method: 'emergency-recovery',
|
|
1506
|
+
attempt,
|
|
1507
|
+
removedPercent: reductionPercent * 100,
|
|
1508
|
+
turnsRemoved: targetTurnsToRemove + startIndex,
|
|
1509
|
+
truncatedOutputs: truncatedCount,
|
|
1510
|
+
toolOutputLimit,
|
|
1511
|
+
});
|
|
1512
|
+
// Check if we're still over limit after all reductions
|
|
1513
|
+
const newStats = this.contextManager?.getStats(this.messages);
|
|
1514
|
+
if (newStats && newStats.percentage > 100) {
|
|
1515
|
+
// Still over limit - do one more aggressive pass
|
|
1516
|
+
// Truncate ALL tool outputs to absolute minimum
|
|
1517
|
+
const minLimit = 200;
|
|
1518
|
+
for (const msg of this.messages) {
|
|
1519
|
+
if (msg.role === 'tool' && msg.content) {
|
|
1520
|
+
const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
|
|
1521
|
+
if (content.length > minLimit) {
|
|
1522
|
+
msg.content = `${content.slice(0, minLimit)}\n[... severely truncated ...]`;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
return true;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
function cloneMessage(message) {
|
|
1531
|
+
switch (message.role) {
|
|
1532
|
+
case 'assistant': {
|
|
1533
|
+
const clone = {
|
|
1534
|
+
role: 'assistant',
|
|
1535
|
+
content: message.content,
|
|
1536
|
+
};
|
|
1537
|
+
if (message.toolCalls) {
|
|
1538
|
+
clone.toolCalls = message.toolCalls.map(cloneToolCall);
|
|
1539
|
+
}
|
|
1540
|
+
return clone;
|
|
1541
|
+
}
|
|
1542
|
+
case 'tool':
|
|
1543
|
+
return {
|
|
1544
|
+
role: 'tool',
|
|
1545
|
+
name: message.name,
|
|
1546
|
+
content: message.content,
|
|
1547
|
+
toolCallId: message.toolCallId,
|
|
1548
|
+
};
|
|
1549
|
+
case 'system':
|
|
1550
|
+
return { role: 'system', content: message.content };
|
|
1551
|
+
case 'user':
|
|
1552
|
+
default:
|
|
1553
|
+
return { role: 'user', content: message.content };
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
function cloneToolCall(call) {
|
|
1557
|
+
return {
|
|
1558
|
+
id: call.id,
|
|
1559
|
+
name: call.name,
|
|
1560
|
+
arguments: { ...(call.arguments ?? {}) },
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
//# sourceMappingURL=agent.js.map
|