@cleanslate/sdk 0.1.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 +22 -0
- package/NOTICE +48 -0
- package/README.md +103 -0
- package/VENDOR.md +60 -0
- package/dist/agent/cleanSlateAgentExecutionPhase.d.ts +55 -0
- package/dist/agent/cleanSlateAgentExecutionPhase.d.ts.map +1 -0
- package/dist/agent/cleanSlateAgentExecutionPhase.js +474 -0
- package/dist/agent/cleanSlateAgentExecutionPhase.js.map +1 -0
- package/dist/agent/cleanSlateAgentExecutionSupport.d.ts +22 -0
- package/dist/agent/cleanSlateAgentExecutionSupport.d.ts.map +1 -0
- package/dist/agent/cleanSlateAgentExecutionSupport.js +205 -0
- package/dist/agent/cleanSlateAgentExecutionSupport.js.map +1 -0
- package/dist/agent/cleanSlateAgentParsing.d.ts +21 -0
- package/dist/agent/cleanSlateAgentParsing.d.ts.map +1 -0
- package/dist/agent/cleanSlateAgentParsing.js +106 -0
- package/dist/agent/cleanSlateAgentParsing.js.map +1 -0
- package/dist/agent/cleanSlateAgentSession.d.ts +44 -0
- package/dist/agent/cleanSlateAgentSession.d.ts.map +1 -0
- package/dist/agent/cleanSlateAgentSession.js +205 -0
- package/dist/agent/cleanSlateAgentSession.js.map +1 -0
- package/dist/agent/cleanSlateAgentTypes.d.ts +91 -0
- package/dist/agent/cleanSlateAgentTypes.d.ts.map +1 -0
- package/dist/agent/cleanSlateAgentTypes.js +27 -0
- package/dist/agent/cleanSlateAgentTypes.js.map +1 -0
- package/dist/agent/cleanSlateCommandPolicy.d.ts +12 -0
- package/dist/agent/cleanSlateCommandPolicy.d.ts.map +1 -0
- package/dist/agent/cleanSlateCommandPolicy.js +30 -0
- package/dist/agent/cleanSlateCommandPolicy.js.map +1 -0
- package/dist/agent/cleanSlateContextBudgetManager.d.ts +82 -0
- package/dist/agent/cleanSlateContextBudgetManager.d.ts.map +1 -0
- package/dist/agent/cleanSlateContextBudgetManager.js +419 -0
- package/dist/agent/cleanSlateContextBudgetManager.js.map +1 -0
- package/dist/agent/cleanSlateDomainProfile.d.ts +71 -0
- package/dist/agent/cleanSlateDomainProfile.d.ts.map +1 -0
- package/dist/agent/cleanSlateDomainProfile.js +124 -0
- package/dist/agent/cleanSlateDomainProfile.js.map +1 -0
- package/dist/agent/cleanSlateExecutionBudget.d.ts +19 -0
- package/dist/agent/cleanSlateExecutionBudget.d.ts.map +1 -0
- package/dist/agent/cleanSlateExecutionBudget.js +28 -0
- package/dist/agent/cleanSlateExecutionBudget.js.map +1 -0
- package/dist/agent/cleanSlateExecutionEditPolicy.d.ts +15 -0
- package/dist/agent/cleanSlateExecutionEditPolicy.d.ts.map +1 -0
- package/dist/agent/cleanSlateExecutionEditPolicy.js +148 -0
- package/dist/agent/cleanSlateExecutionEditPolicy.js.map +1 -0
- package/dist/agent/cleanSlateExecutionEvidenceLedger.d.ts +23 -0
- package/dist/agent/cleanSlateExecutionEvidenceLedger.d.ts.map +1 -0
- package/dist/agent/cleanSlateExecutionEvidenceLedger.js +121 -0
- package/dist/agent/cleanSlateExecutionEvidenceLedger.js.map +1 -0
- package/dist/agent/cleanSlateExecutionLoopPrompts.d.ts +5 -0
- package/dist/agent/cleanSlateExecutionLoopPrompts.d.ts.map +1 -0
- package/dist/agent/cleanSlateExecutionLoopPrompts.js +41 -0
- package/dist/agent/cleanSlateExecutionLoopPrompts.js.map +1 -0
- package/dist/agent/cleanSlateExecutionQuery.d.ts +162 -0
- package/dist/agent/cleanSlateExecutionQuery.d.ts.map +1 -0
- package/dist/agent/cleanSlateExecutionQuery.js +1448 -0
- package/dist/agent/cleanSlateExecutionQuery.js.map +1 -0
- package/dist/agent/cleanSlateFilesModifiedService.d.ts +96 -0
- package/dist/agent/cleanSlateFilesModifiedService.d.ts.map +1 -0
- package/dist/agent/cleanSlateFilesModifiedService.js +581 -0
- package/dist/agent/cleanSlateFilesModifiedService.js.map +1 -0
- package/dist/agent/cleanSlateNativeToolTranscript.d.ts +22 -0
- package/dist/agent/cleanSlateNativeToolTranscript.d.ts.map +1 -0
- package/dist/agent/cleanSlateNativeToolTranscript.js +77 -0
- package/dist/agent/cleanSlateNativeToolTranscript.js.map +1 -0
- package/dist/agent/cleanSlatePrompts.d.ts +30 -0
- package/dist/agent/cleanSlatePrompts.d.ts.map +1 -0
- package/dist/agent/cleanSlatePrompts.js +65 -0
- package/dist/agent/cleanSlatePrompts.js.map +1 -0
- package/dist/agent/cleanSlateQueryRunner.d.ts +56 -0
- package/dist/agent/cleanSlateQueryRunner.d.ts.map +1 -0
- package/dist/agent/cleanSlateQueryRunner.js +69 -0
- package/dist/agent/cleanSlateQueryRunner.js.map +1 -0
- package/dist/agent/cleanSlateRuntimePromptBuilder.d.ts +30 -0
- package/dist/agent/cleanSlateRuntimePromptBuilder.d.ts.map +1 -0
- package/dist/agent/cleanSlateRuntimePromptBuilder.js +99 -0
- package/dist/agent/cleanSlateRuntimePromptBuilder.js.map +1 -0
- package/dist/agent/cleanSlateStreamingToolExecutor.d.ts +55 -0
- package/dist/agent/cleanSlateStreamingToolExecutor.d.ts.map +1 -0
- package/dist/agent/cleanSlateStreamingToolExecutor.js +214 -0
- package/dist/agent/cleanSlateStreamingToolExecutor.js.map +1 -0
- package/dist/agent/cleanSlateToolCallLedger.d.ts +32 -0
- package/dist/agent/cleanSlateToolCallLedger.d.ts.map +1 -0
- package/dist/agent/cleanSlateToolCallLedger.js +164 -0
- package/dist/agent/cleanSlateToolCallLedger.js.map +1 -0
- package/dist/agent/cleanSlateToolResultPromptSerializer.d.ts +9 -0
- package/dist/agent/cleanSlateToolResultPromptSerializer.d.ts.map +1 -0
- package/dist/agent/cleanSlateToolResultPromptSerializer.js +184 -0
- package/dist/agent/cleanSlateToolResultPromptSerializer.js.map +1 -0
- package/dist/composer/commands/slashCommands.d.ts +8 -0
- package/dist/composer/commands/slashCommands.d.ts.map +1 -0
- package/dist/composer/commands/slashCommands.js +46 -0
- package/dist/composer/commands/slashCommands.js.map +1 -0
- package/dist/composer/instructions/baseInstructions.d.ts +3 -0
- package/dist/composer/instructions/baseInstructions.d.ts.map +1 -0
- package/dist/composer/instructions/baseInstructions.js +35 -0
- package/dist/composer/instructions/baseInstructions.js.map +1 -0
- package/dist/composer/instructions/runtimeInstructions.d.ts +11 -0
- package/dist/composer/instructions/runtimeInstructions.d.ts.map +1 -0
- package/dist/composer/instructions/runtimeInstructions.js +31 -0
- package/dist/composer/instructions/runtimeInstructions.js.map +1 -0
- package/dist/composer/kernel/coreKernel.d.ts +3 -0
- package/dist/composer/kernel/coreKernel.d.ts.map +1 -0
- package/dist/composer/kernel/coreKernel.js +11 -0
- package/dist/composer/kernel/coreKernel.js.map +1 -0
- package/dist/composer/kernel/editingRules.d.ts +3 -0
- package/dist/composer/kernel/editingRules.d.ts.map +1 -0
- package/dist/composer/kernel/editingRules.js +24 -0
- package/dist/composer/kernel/editingRules.js.map +1 -0
- package/dist/composer/kernel/toolProtocols.d.ts +2 -0
- package/dist/composer/kernel/toolProtocols.d.ts.map +1 -0
- package/dist/composer/kernel/toolProtocols.js +32 -0
- package/dist/composer/kernel/toolProtocols.js.map +1 -0
- package/dist/composer/modes/execution.mode.d.ts +2 -0
- package/dist/composer/modes/execution.mode.d.ts.map +1 -0
- package/dist/composer/modes/execution.mode.js +21 -0
- package/dist/composer/modes/execution.mode.js.map +1 -0
- package/dist/composer/modes/planning.mode.d.ts +2 -0
- package/dist/composer/modes/planning.mode.d.ts.map +1 -0
- package/dist/composer/modes/planning.mode.js +23 -0
- package/dist/composer/modes/planning.mode.js.map +1 -0
- package/dist/composer/promptComposer.d.ts +22 -0
- package/dist/composer/promptComposer.d.ts.map +1 -0
- package/dist/composer/promptComposer.js +62 -0
- package/dist/composer/promptComposer.js.map +1 -0
- package/dist/composer/registry/agentSchema.d.ts +16 -0
- package/dist/composer/registry/agentSchema.d.ts.map +1 -0
- package/dist/composer/registry/agentSchema.js +6 -0
- package/dist/composer/registry/agentSchema.js.map +1 -0
- package/dist/core/arrays.d.ts +311 -0
- package/dist/core/arrays.d.ts.map +1 -0
- package/dist/core/arrays.js +811 -0
- package/dist/core/arrays.js.map +1 -0
- package/dist/core/arraysFind.d.ts +72 -0
- package/dist/core/arraysFind.d.ts.map +1 -0
- package/dist/core/arraysFind.js +200 -0
- package/dist/core/arraysFind.js.map +1 -0
- package/dist/core/assert.d.ts +36 -0
- package/dist/core/assert.d.ts.map +1 -0
- package/dist/core/assert.js +84 -0
- package/dist/core/assert.js.map +1 -0
- package/dist/core/async.d.ts +11 -0
- package/dist/core/async.d.ts.map +1 -0
- package/dist/core/async.js +6 -0
- package/dist/core/async.js.map +1 -0
- package/dist/core/buffer.d.ts +23 -0
- package/dist/core/buffer.d.ts.map +1 -0
- package/dist/core/buffer.js +40 -0
- package/dist/core/buffer.js.map +1 -0
- package/dist/core/cancellation.d.ts +52 -0
- package/dist/core/cancellation.d.ts.map +1 -0
- package/dist/core/cancellation.js +169 -0
- package/dist/core/cancellation.js.map +1 -0
- package/dist/core/charCode.d.ts +428 -0
- package/dist/core/charCode.d.ts.map +1 -0
- package/dist/core/charCode.js +439 -0
- package/dist/core/charCode.js.map +1 -0
- package/dist/core/collections.d.ts +49 -0
- package/dist/core/collections.d.ts.map +1 -0
- package/dist/core/collections.js +132 -0
- package/dist/core/collections.js.map +1 -0
- package/dist/core/diff/diff.d.ts +151 -0
- package/dist/core/diff/diff.d.ts.map +1 -0
- package/dist/core/diff/diff.js +1076 -0
- package/dist/core/diff/diff.js.map +1 -0
- package/dist/core/diff/diffChange.d.ts +39 -0
- package/dist/core/diff/diffChange.d.ts.map +1 -0
- package/dist/core/diff/diffChange.js +37 -0
- package/dist/core/diff/diffChange.js.map +1 -0
- package/dist/core/errors.d.ts +114 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +258 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/event.d.ts +595 -0
- package/dist/core/event.d.ts.map +1 -0
- package/dist/core/event.js +1479 -0
- package/dist/core/event.js.map +1 -0
- package/dist/core/functional.d.ts +5 -0
- package/dist/core/functional.d.ts.map +1 -0
- package/dist/core/functional.js +35 -0
- package/dist/core/functional.js.map +1 -0
- package/dist/core/hash.d.ts +15 -0
- package/dist/core/hash.d.ts.map +1 -0
- package/dist/core/hash.js +27 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/iterator.d.ts +33 -0
- package/dist/core/iterator.d.ts.map +1 -0
- package/dist/core/iterator.js +188 -0
- package/dist/core/iterator.js.map +1 -0
- package/dist/core/lifecycle.d.ts +313 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +789 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/linkedList.d.ts +17 -0
- package/dist/core/linkedList.d.ts.map +1 -0
- package/dist/core/linkedList.js +138 -0
- package/dist/core/linkedList.js.map +1 -0
- package/dist/core/map.d.ts +175 -0
- package/dist/core/map.d.ts.map +1 -0
- package/dist/core/map.js +796 -0
- package/dist/core/map.js.map +1 -0
- package/dist/core/marshallingIds.d.ts +29 -0
- package/dist/core/marshallingIds.d.ts.map +1 -0
- package/dist/core/marshallingIds.js +38 -0
- package/dist/core/marshallingIds.js.map +1 -0
- package/dist/core/observable.d.ts +28 -0
- package/dist/core/observable.d.ts.map +1 -0
- package/dist/core/observable.js +6 -0
- package/dist/core/observable.js.map +1 -0
- package/dist/core/platform.d.ts +4 -0
- package/dist/core/platform.d.ts.map +1 -0
- package/dist/core/platform.js +17 -0
- package/dist/core/platform.js.map +1 -0
- package/dist/core/position.d.ts +91 -0
- package/dist/core/position.d.ts.map +1 -0
- package/dist/core/position.js +145 -0
- package/dist/core/position.js.map +1 -0
- package/dist/core/range.d.ts +198 -0
- package/dist/core/range.d.ts.map +1 -0
- package/dist/core/range.js +426 -0
- package/dist/core/range.js.map +1 -0
- package/dist/core/resources.d.ts +10 -0
- package/dist/core/resources.d.ts.map +1 -0
- package/dist/core/resources.js +126 -0
- package/dist/core/resources.js.map +1 -0
- package/dist/core/sequence.d.ts +20 -0
- package/dist/core/sequence.d.ts.map +1 -0
- package/dist/core/sequence.js +21 -0
- package/dist/core/sequence.js.map +1 -0
- package/dist/core/stopwatch.d.ts +11 -0
- package/dist/core/stopwatch.d.ts.map +1 -0
- package/dist/core/stopwatch.js +33 -0
- package/dist/core/stopwatch.js.map +1 -0
- package/dist/core/symbols.d.ts +5 -0
- package/dist/core/symbols.d.ts.map +1 -0
- package/dist/core/symbols.js +13 -0
- package/dist/core/symbols.js.map +1 -0
- package/dist/core/types.d.ts +229 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +278 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/uint.d.ts +32 -0
- package/dist/core/uint.d.ts.map +1 -0
- package/dist/core/uint.js +57 -0
- package/dist/core/uint.js.map +1 -0
- package/dist/core/uri.d.ts +172 -0
- package/dist/core/uri.d.ts.map +1 -0
- package/dist/core/uri.js +623 -0
- package/dist/core/uri.js.map +1 -0
- package/dist/host/browserAutomation.d.ts +276 -0
- package/dist/host/browserAutomation.d.ts.map +1 -0
- package/dist/host/browserAutomation.js +6 -0
- package/dist/host/browserAutomation.js.map +1 -0
- package/dist/host/diagnostics.d.ts +68 -0
- package/dist/host/diagnostics.d.ts.map +1 -0
- package/dist/host/diagnostics.js +41 -0
- package/dist/host/diagnostics.js.map +1 -0
- package/dist/host/files.d.ts +70 -0
- package/dist/host/files.d.ts.map +1 -0
- package/dist/host/files.js +54 -0
- package/dist/host/files.js.map +1 -0
- package/dist/host/services.d.ts +106 -0
- package/dist/host/services.d.ts.map +1 -0
- package/dist/host/services.js +6 -0
- package/dist/host/services.js.map +1 -0
- package/dist/host/symbols.d.ts +45 -0
- package/dist/host/symbols.d.ts.map +1 -0
- package/dist/host/symbols.js +43 -0
- package/dist/host/symbols.js.map +1 -0
- package/dist/host/textModel.d.ts +83 -0
- package/dist/host/textModel.d.ts.map +1 -0
- package/dist/host/textModel.js +6 -0
- package/dist/host/textModel.js.map +1 -0
- package/dist/host/workspace.d.ts +123 -0
- package/dist/host/workspace.d.ts.map +1 -0
- package/dist/host/workspace.js +32 -0
- package/dist/host/workspace.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/node/cleanSlateAnthropicMessageAdapter.d.ts +12 -0
- package/dist/node/cleanSlateAnthropicMessageAdapter.d.ts.map +1 -0
- package/dist/node/cleanSlateAnthropicMessageAdapter.js +130 -0
- package/dist/node/cleanSlateAnthropicMessageAdapter.js.map +1 -0
- package/dist/node/cleanSlateHeadlessRunner.d.ts +63 -0
- package/dist/node/cleanSlateHeadlessRunner.d.ts.map +1 -0
- package/dist/node/cleanSlateHeadlessRunner.js +84 -0
- package/dist/node/cleanSlateHeadlessRunner.js.map +1 -0
- package/dist/node/cleanSlateNodeAgentRuntime.d.ts +94 -0
- package/dist/node/cleanSlateNodeAgentRuntime.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeAgentRuntime.js +339 -0
- package/dist/node/cleanSlateNodeAgentRuntime.js.map +1 -0
- package/dist/node/cleanSlateNodeBrowserAutomation.d.ts +279 -0
- package/dist/node/cleanSlateNodeBrowserAutomation.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeBrowserAutomation.js +470 -0
- package/dist/node/cleanSlateNodeBrowserAutomation.js.map +1 -0
- package/dist/node/cleanSlateNodeCommandService.d.ts +40 -0
- package/dist/node/cleanSlateNodeCommandService.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeCommandService.js +435 -0
- package/dist/node/cleanSlateNodeCommandService.js.map +1 -0
- package/dist/node/cleanSlateNodeFileServices.d.ts +68 -0
- package/dist/node/cleanSlateNodeFileServices.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeFileServices.js +138 -0
- package/dist/node/cleanSlateNodeFileServices.js.map +1 -0
- package/dist/node/cleanSlateNodeIndexService.d.ts +17 -0
- package/dist/node/cleanSlateNodeIndexService.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeIndexService.js +128 -0
- package/dist/node/cleanSlateNodeIndexService.js.map +1 -0
- package/dist/node/cleanSlateNodeLanguageCommands.d.ts +11 -0
- package/dist/node/cleanSlateNodeLanguageCommands.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeLanguageCommands.js +146 -0
- package/dist/node/cleanSlateNodeLanguageCommands.js.map +1 -0
- package/dist/node/cleanSlateNodeMainService.d.ts +87 -0
- package/dist/node/cleanSlateNodeMainService.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeMainService.js +1304 -0
- package/dist/node/cleanSlateNodeMainService.js.map +1 -0
- package/dist/node/cleanSlateNodeMcpClient.d.ts +20 -0
- package/dist/node/cleanSlateNodeMcpClient.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeMcpClient.js +184 -0
- package/dist/node/cleanSlateNodeMcpClient.js.map +1 -0
- package/dist/node/cleanSlateNodeSearchService.d.ts +14 -0
- package/dist/node/cleanSlateNodeSearchService.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeSearchService.js +180 -0
- package/dist/node/cleanSlateNodeSearchService.js.map +1 -0
- package/dist/node/cleanSlateNodeTextModel.d.ts +56 -0
- package/dist/node/cleanSlateNodeTextModel.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeTextModel.js +127 -0
- package/dist/node/cleanSlateNodeTextModel.js.map +1 -0
- package/dist/node/cleanSlateNodeToolContext.d.ts +50 -0
- package/dist/node/cleanSlateNodeToolContext.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeToolContext.js +134 -0
- package/dist/node/cleanSlateNodeToolContext.js.map +1 -0
- package/dist/node/cleanSlateNodeWebRetrieval.d.ts +20 -0
- package/dist/node/cleanSlateNodeWebRetrieval.d.ts.map +1 -0
- package/dist/node/cleanSlateNodeWebRetrieval.js +379 -0
- package/dist/node/cleanSlateNodeWebRetrieval.js.map +1 -0
- package/dist/node/cleanSlateOpenAIMessageAdapter.d.ts +8 -0
- package/dist/node/cleanSlateOpenAIMessageAdapter.d.ts.map +1 -0
- package/dist/node/cleanSlateOpenAIMessageAdapter.js +111 -0
- package/dist/node/cleanSlateOpenAIMessageAdapter.js.map +1 -0
- package/dist/node/cleanSlateProviderSchemaNormalizer.d.ts +18 -0
- package/dist/node/cleanSlateProviderSchemaNormalizer.d.ts.map +1 -0
- package/dist/node/cleanSlateProviderSchemaNormalizer.js +175 -0
- package/dist/node/cleanSlateProviderSchemaNormalizer.js.map +1 -0
- package/dist/node/index.d.ts +25 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +28 -0
- package/dist/node/index.js.map +1 -0
- package/dist/protocol/cleanSlateAI.d.ts +964 -0
- package/dist/protocol/cleanSlateAI.d.ts.map +1 -0
- package/dist/protocol/cleanSlateAI.js +35 -0
- package/dist/protocol/cleanSlateAI.js.map +1 -0
- package/dist/protocol/cleanSlateModelCapabilities.d.ts +86 -0
- package/dist/protocol/cleanSlateModelCapabilities.d.ts.map +1 -0
- package/dist/protocol/cleanSlateModelCapabilities.js +1104 -0
- package/dist/protocol/cleanSlateModelCapabilities.js.map +1 -0
- package/dist/protocol/cleanSlateProviderMessageTransforms.d.ts +11 -0
- package/dist/protocol/cleanSlateProviderMessageTransforms.d.ts.map +1 -0
- package/dist/protocol/cleanSlateProviderMessageTransforms.js +178 -0
- package/dist/protocol/cleanSlateProviderMessageTransforms.js.map +1 -0
- package/dist/protocol/cleanSlateService.d.ts +68 -0
- package/dist/protocol/cleanSlateService.d.ts.map +1 -0
- package/dist/protocol/cleanSlateService.js +1149 -0
- package/dist/protocol/cleanSlateService.js.map +1 -0
- package/dist/services/cleanSlateCancellation.d.ts +7 -0
- package/dist/services/cleanSlateCancellation.d.ts.map +1 -0
- package/dist/services/cleanSlateCancellation.js +56 -0
- package/dist/services/cleanSlateCancellation.js.map +1 -0
- package/dist/services/cleanSlateCommandExecutionService.d.ts +25 -0
- package/dist/services/cleanSlateCommandExecutionService.d.ts.map +1 -0
- package/dist/services/cleanSlateCommandExecutionService.js +31 -0
- package/dist/services/cleanSlateCommandExecutionService.js.map +1 -0
- package/dist/services/cleanSlateDiffService.d.ts +62 -0
- package/dist/services/cleanSlateDiffService.d.ts.map +1 -0
- package/dist/services/cleanSlateDiffService.js +428 -0
- package/dist/services/cleanSlateDiffService.js.map +1 -0
- package/dist/services/cleanSlateEditMatchValidator.d.ts +63 -0
- package/dist/services/cleanSlateEditMatchValidator.d.ts.map +1 -0
- package/dist/services/cleanSlateEditMatchValidator.js +341 -0
- package/dist/services/cleanSlateEditMatchValidator.js.map +1 -0
- package/dist/services/cleanSlateEditService.d.ts +155 -0
- package/dist/services/cleanSlateEditService.d.ts.map +1 -0
- package/dist/services/cleanSlateEditService.js +848 -0
- package/dist/services/cleanSlateEditService.js.map +1 -0
- package/dist/services/cleanSlateFileHistory.d.ts +56 -0
- package/dist/services/cleanSlateFileHistory.d.ts.map +1 -0
- package/dist/services/cleanSlateFileHistory.js +157 -0
- package/dist/services/cleanSlateFileHistory.js.map +1 -0
- package/dist/services/cleanSlateTaskEvidenceCodec.d.ts +15 -0
- package/dist/services/cleanSlateTaskEvidenceCodec.d.ts.map +1 -0
- package/dist/services/cleanSlateTaskEvidenceCodec.js +151 -0
- package/dist/services/cleanSlateTaskEvidenceCodec.js.map +1 -0
- package/dist/services/cleanSlateTaskSessionService.d.ts +258 -0
- package/dist/services/cleanSlateTaskSessionService.d.ts.map +1 -0
- package/dist/services/cleanSlateTaskSessionService.js +1079 -0
- package/dist/services/cleanSlateTaskSessionService.js.map +1 -0
- package/dist/services/cleanSlateTaskState.d.ts +32 -0
- package/dist/services/cleanSlateTaskState.d.ts.map +1 -0
- package/dist/services/cleanSlateTaskState.js +40 -0
- package/dist/services/cleanSlateTaskState.js.map +1 -0
- package/dist/services/cleanSlateThreadService.d.ts +64 -0
- package/dist/services/cleanSlateThreadService.d.ts.map +1 -0
- package/dist/services/cleanSlateThreadService.js +188 -0
- package/dist/services/cleanSlateThreadService.js.map +1 -0
- package/dist/services/cleanSlateTools.d.ts +29 -0
- package/dist/services/cleanSlateTools.d.ts.map +1 -0
- package/dist/services/cleanSlateTools.js +38 -0
- package/dist/services/cleanSlateTools.js.map +1 -0
- package/dist/services/cleanSlateVerificationTargetTracker.d.ts +23 -0
- package/dist/services/cleanSlateVerificationTargetTracker.d.ts.map +1 -0
- package/dist/services/cleanSlateVerificationTargetTracker.js +214 -0
- package/dist/services/cleanSlateVerificationTargetTracker.js.map +1 -0
- package/dist/skills/cleanSlateSkillCatalog.d.ts +29 -0
- package/dist/skills/cleanSlateSkillCatalog.d.ts.map +1 -0
- package/dist/skills/cleanSlateSkillCatalog.js +225 -0
- package/dist/skills/cleanSlateSkillCatalog.js.map +1 -0
- package/dist/tools/ApplyEditTool.d.ts +73 -0
- package/dist/tools/ApplyEditTool.d.ts.map +1 -0
- package/dist/tools/ApplyEditTool.js +741 -0
- package/dist/tools/ApplyEditTool.js.map +1 -0
- package/dist/tools/AskQuestionTool.d.ts +3 -0
- package/dist/tools/AskQuestionTool.d.ts.map +1 -0
- package/dist/tools/AskQuestionTool.js +113 -0
- package/dist/tools/AskQuestionTool.js.map +1 -0
- package/dist/tools/BrowserAutomationTools.d.ts +28 -0
- package/dist/tools/BrowserAutomationTools.d.ts.map +1 -0
- package/dist/tools/BrowserAutomationTools.js +639 -0
- package/dist/tools/BrowserAutomationTools.js.map +1 -0
- package/dist/tools/CreateMultipleFilesTool.d.ts +6 -0
- package/dist/tools/CreateMultipleFilesTool.d.ts.map +1 -0
- package/dist/tools/CreateMultipleFilesTool.js +115 -0
- package/dist/tools/CreateMultipleFilesTool.js.map +1 -0
- package/dist/tools/ExecuteCommandTool.d.ts +12 -0
- package/dist/tools/ExecuteCommandTool.d.ts.map +1 -0
- package/dist/tools/ExecuteCommandTool.js +378 -0
- package/dist/tools/ExecuteCommandTool.js.map +1 -0
- package/dist/tools/FileHistoryRewindTool.d.ts +3 -0
- package/dist/tools/FileHistoryRewindTool.d.ts.map +1 -0
- package/dist/tools/FileHistoryRewindTool.js +45 -0
- package/dist/tools/FileHistoryRewindTool.js.map +1 -0
- package/dist/tools/FindByNameTool.d.ts +6 -0
- package/dist/tools/FindByNameTool.d.ts.map +1 -0
- package/dist/tools/FindByNameTool.js +80 -0
- package/dist/tools/FindByNameTool.js.map +1 -0
- package/dist/tools/FindReferencesTool.d.ts +3 -0
- package/dist/tools/FindReferencesTool.d.ts.map +1 -0
- package/dist/tools/FindReferencesTool.js +128 -0
- package/dist/tools/FindReferencesTool.js.map +1 -0
- package/dist/tools/GetDefinitionsTool.d.ts +3 -0
- package/dist/tools/GetDefinitionsTool.d.ts.map +1 -0
- package/dist/tools/GetDefinitionsTool.js +136 -0
- package/dist/tools/GetDefinitionsTool.js.map +1 -0
- package/dist/tools/GetOpenFilesTool.d.ts +6 -0
- package/dist/tools/GetOpenFilesTool.d.ts.map +1 -0
- package/dist/tools/GetOpenFilesTool.js +21 -0
- package/dist/tools/GetOpenFilesTool.js.map +1 -0
- package/dist/tools/GrepSearchTool.d.ts +7 -0
- package/dist/tools/GrepSearchTool.d.ts.map +1 -0
- package/dist/tools/GrepSearchTool.js +95 -0
- package/dist/tools/GrepSearchTool.js.map +1 -0
- package/dist/tools/ListDirTool.d.ts +6 -0
- package/dist/tools/ListDirTool.d.ts.map +1 -0
- package/dist/tools/ListDirTool.js +39 -0
- package/dist/tools/ListDirTool.js.map +1 -0
- package/dist/tools/MCPTools.d.ts +6 -0
- package/dist/tools/MCPTools.d.ts.map +1 -0
- package/dist/tools/MCPTools.js +103 -0
- package/dist/tools/MCPTools.js.map +1 -0
- package/dist/tools/MultiFileReplaceTool.d.ts +6 -0
- package/dist/tools/MultiFileReplaceTool.d.ts.map +1 -0
- package/dist/tools/MultiFileReplaceTool.js +345 -0
- package/dist/tools/MultiFileReplaceTool.js.map +1 -0
- package/dist/tools/ReadFileRangeTool.d.ts +6 -0
- package/dist/tools/ReadFileRangeTool.d.ts.map +1 -0
- package/dist/tools/ReadFileRangeTool.js +150 -0
- package/dist/tools/ReadFileRangeTool.js.map +1 -0
- package/dist/tools/ReadFileTool.d.ts +6 -0
- package/dist/tools/ReadFileTool.d.ts.map +1 -0
- package/dist/tools/ReadFileTool.js +183 -0
- package/dist/tools/ReadFileTool.js.map +1 -0
- package/dist/tools/ReadLintsTool.d.ts +6 -0
- package/dist/tools/ReadLintsTool.d.ts.map +1 -0
- package/dist/tools/ReadLintsTool.js +83 -0
- package/dist/tools/ReadLintsTool.js.map +1 -0
- package/dist/tools/ReadReferenceTool.d.ts +6 -0
- package/dist/tools/ReadReferenceTool.d.ts.map +1 -0
- package/dist/tools/ReadReferenceTool.js +24 -0
- package/dist/tools/ReadReferenceTool.js.map +1 -0
- package/dist/tools/ReadSymbolsTool.d.ts +3 -0
- package/dist/tools/ReadSymbolsTool.d.ts.map +1 -0
- package/dist/tools/ReadSymbolsTool.js +100 -0
- package/dist/tools/ReadSymbolsTool.js.map +1 -0
- package/dist/tools/SearchCodebaseTool.d.ts +6 -0
- package/dist/tools/SearchCodebaseTool.d.ts.map +1 -0
- package/dist/tools/SearchCodebaseTool.js +30 -0
- package/dist/tools/SearchCodebaseTool.js.map +1 -0
- package/dist/tools/SearchWorkspaceTool.d.ts +7 -0
- package/dist/tools/SearchWorkspaceTool.d.ts.map +1 -0
- package/dist/tools/SearchWorkspaceTool.js +21 -0
- package/dist/tools/SearchWorkspaceTool.js.map +1 -0
- package/dist/tools/SemanticSearchTool.d.ts +12 -0
- package/dist/tools/SemanticSearchTool.d.ts.map +1 -0
- package/dist/tools/SemanticSearchTool.js +46 -0
- package/dist/tools/SemanticSearchTool.js.map +1 -0
- package/dist/tools/SkillTools.d.ts +3 -0
- package/dist/tools/SkillTools.d.ts.map +1 -0
- package/dist/tools/SkillTools.js +108 -0
- package/dist/tools/SkillTools.js.map +1 -0
- package/dist/tools/SpawnWorkerTool.d.ts +6 -0
- package/dist/tools/SpawnWorkerTool.d.ts.map +1 -0
- package/dist/tools/SpawnWorkerTool.js +28 -0
- package/dist/tools/SpawnWorkerTool.js.map +1 -0
- package/dist/tools/SubmitArtifactTool.d.ts +3 -0
- package/dist/tools/SubmitArtifactTool.d.ts.map +1 -0
- package/dist/tools/SubmitArtifactTool.js +121 -0
- package/dist/tools/SubmitArtifactTool.js.map +1 -0
- package/dist/tools/UndoEditTool.d.ts +3 -0
- package/dist/tools/UndoEditTool.d.ts.map +1 -0
- package/dist/tools/UndoEditTool.js +66 -0
- package/dist/tools/UndoEditTool.js.map +1 -0
- package/dist/tools/UpdateTodoTool.d.ts +6 -0
- package/dist/tools/UpdateTodoTool.d.ts.map +1 -0
- package/dist/tools/UpdateTodoTool.js +116 -0
- package/dist/tools/UpdateTodoTool.js.map +1 -0
- package/dist/tools/WebRetrievalTools.d.ts +4 -0
- package/dist/tools/WebRetrievalTools.d.ts.map +1 -0
- package/dist/tools/WebRetrievalTools.js +169 -0
- package/dist/tools/WebRetrievalTools.js.map +1 -0
- package/dist/tools/WriteFileTool.d.ts +6 -0
- package/dist/tools/WriteFileTool.d.ts.map +1 -0
- package/dist/tools/WriteFileTool.js +145 -0
- package/dist/tools/WriteFileTool.js.map +1 -0
- package/dist/tools/cleanSlateFileReadPolicy.d.ts +33 -0
- package/dist/tools/cleanSlateFileReadPolicy.d.ts.map +1 -0
- package/dist/tools/cleanSlateFileReadPolicy.js +84 -0
- package/dist/tools/cleanSlateFileReadPolicy.js.map +1 -0
- package/dist/tools/cleanSlateHostTypes.d.ts +100 -0
- package/dist/tools/cleanSlateHostTypes.d.ts.map +1 -0
- package/dist/tools/cleanSlateHostTypes.js +6 -0
- package/dist/tools/cleanSlateHostTypes.js.map +1 -0
- package/dist/tools/cleanSlatePlanArtifactPolicy.d.ts +47 -0
- package/dist/tools/cleanSlatePlanArtifactPolicy.d.ts.map +1 -0
- package/dist/tools/cleanSlatePlanArtifactPolicy.js +126 -0
- package/dist/tools/cleanSlatePlanArtifactPolicy.js.map +1 -0
- package/dist/tools/cleanSlateStaleDiagnosticPolicy.d.ts +3 -0
- package/dist/tools/cleanSlateStaleDiagnosticPolicy.d.ts.map +1 -0
- package/dist/tools/cleanSlateStaleDiagnosticPolicy.js +13 -0
- package/dist/tools/cleanSlateStaleDiagnosticPolicy.js.map +1 -0
- package/dist/tools/languageFeatureActivation.d.ts +13 -0
- package/dist/tools/languageFeatureActivation.d.ts.map +1 -0
- package/dist/tools/languageFeatureActivation.js +95 -0
- package/dist/tools/languageFeatureActivation.js.map +1 -0
- package/dist/tools/registry.d.ts +5 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +104 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/structuredEditCanonicalizer.d.ts +11 -0
- package/dist/tools/structuredEditCanonicalizer.d.ts.map +1 -0
- package/dist/tools/structuredEditCanonicalizer.js +44 -0
- package/dist/tools/structuredEditCanonicalizer.js.map +1 -0
- package/dist/tools/symbolContext.d.ts +36 -0
- package/dist/tools/symbolContext.d.ts.map +1 -0
- package/dist/tools/symbolContext.js +146 -0
- package/dist/tools/symbolContext.js.map +1 -0
- package/dist/tools/symbolEditResolver.d.ts +11 -0
- package/dist/tools/symbolEditResolver.d.ts.map +1 -0
- package/dist/tools/symbolEditResolver.js +259 -0
- package/dist/tools/symbolEditResolver.js.map +1 -0
- package/dist/tools/symbolIndex.d.ts +18 -0
- package/dist/tools/symbolIndex.d.ts.map +1 -0
- package/dist/tools/symbolIndex.js +235 -0
- package/dist/tools/symbolIndex.js.map +1 -0
- package/dist/tools/types.d.ts +108 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +6 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/utils.d.ts +56 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +205 -0
- package/dist/tools/utils.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,1448 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) CleanSlate. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import { CLEANSLATE_FALLBACK_CONTEXT_WINDOW_TOKENS } from '../protocol/cleanSlateAI.js';
|
|
6
|
+
import { AgentPhase } from './cleanSlatePrompts.js';
|
|
7
|
+
import { PHASE_CONCLUSION_SIGNAL_PLAN_CREATED } from './cleanSlateAgentTypes.js';
|
|
8
|
+
import { CleanSlateAgentExecutionPhase } from './cleanSlateAgentExecutionPhase.js';
|
|
9
|
+
import { CleanSlateExecutionEvidenceLedger } from './cleanSlateExecutionEvidenceLedger.js';
|
|
10
|
+
import { CleanSlateFilesModifiedService } from './cleanSlateFilesModifiedService.js';
|
|
11
|
+
import { ALL_TOOLS } from '../tools/registry.js';
|
|
12
|
+
import { serializeToolResultForPrompt } from './cleanSlateToolResultPromptSerializer.js';
|
|
13
|
+
import { CleanSlateNativeToolTranscript } from './cleanSlateNativeToolTranscript.js';
|
|
14
|
+
import { CleanSlateToolCallLedger } from './cleanSlateToolCallLedger.js';
|
|
15
|
+
import { CleanSlateContextBudgetManager } from './cleanSlateContextBudgetManager.js';
|
|
16
|
+
import { buildExecutionNoProgressStopMessage, buildExecutionNoToolRecoveryPrompt, buildSerializedToolCallRecoveryPrompt, detectSerializedToolCallSyntax } from './cleanSlateExecutionLoopPrompts.js';
|
|
17
|
+
import { CLEANSLATE_CODING_PROFILE } from './cleanSlateDomainProfile.js';
|
|
18
|
+
import { extractPlanFileEntries, planEntryTargetToPath } from '../tools/cleanSlatePlanArtifactPolicy.js';
|
|
19
|
+
import { evaluateExecutionCommandPolicy } from './cleanSlateCommandPolicy.js';
|
|
20
|
+
import { getWebResearchFinalAnswerPrompt } from './cleanSlateRuntimePromptBuilder.js';
|
|
21
|
+
import { CleanSlateStreamingToolExecutor } from './cleanSlateStreamingToolExecutor.js';
|
|
22
|
+
import { CleanSlateExecutionEditPolicy } from './cleanSlateExecutionEditPolicy.js';
|
|
23
|
+
import { cancellationTokenFromAbortSignal } from '../services/cleanSlateCancellation.js';
|
|
24
|
+
import { estimateCleanSlateFileReadTokens } from '../tools/cleanSlateFileReadPolicy.js';
|
|
25
|
+
export class CleanSlateExecutionQueryEngine {
|
|
26
|
+
/** The check the loop runs itself after mutations. */
|
|
27
|
+
get verificationToolName() {
|
|
28
|
+
return this.profile.deterministicVerificationTool ?? '';
|
|
29
|
+
}
|
|
30
|
+
static { this.DEFAULT_MODEL_TURN_INTERVAL_MS = 0; }
|
|
31
|
+
static { this.NORMAL_MODEL_TURN_INTERVAL_MS = 0; }
|
|
32
|
+
static { this.PLANNING_MODEL_TURN_INTERVAL_MS = 0; }
|
|
33
|
+
/** Summaries are brief continuation state, not another agent turn. */
|
|
34
|
+
static { this.COMPACTION_MAX_OUTPUT_TOKENS = 2_000; }
|
|
35
|
+
/** Stop retrying a failed automatic compaction instead of burning quota repeatedly. */
|
|
36
|
+
static { this.MAX_CONSECUTIVE_COMPACTION_FAILURES = 3; }
|
|
37
|
+
/** A summary must earn back meaningful context before another automatic summary is useful. */
|
|
38
|
+
static { this.AUTO_COMPACTION_REGROWTH_RATIO = 1.25; }
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.options = options;
|
|
41
|
+
/**
|
|
42
|
+
* Describes what the tools in play do to the workspace, so the loop can
|
|
43
|
+
* reason about mutation, verification and concurrency without knowing any
|
|
44
|
+
* individual tool by name.
|
|
45
|
+
*/
|
|
46
|
+
this.profile = CLEANSLATE_CODING_PROFILE;
|
|
47
|
+
this.filesModifiedService = new CleanSlateFilesModifiedService();
|
|
48
|
+
this.nativeToolTranscript = new CleanSlateNativeToolTranscript('execution');
|
|
49
|
+
this.contextBudgetManager = new CleanSlateContextBudgetManager();
|
|
50
|
+
this.editPolicy = new CleanSlateExecutionEditPolicy();
|
|
51
|
+
this.consecutiveCompactionFailures = 0;
|
|
52
|
+
this.executionPhase = new CleanSlateAgentExecutionPhase(options);
|
|
53
|
+
}
|
|
54
|
+
getExecutionLoopSettings() {
|
|
55
|
+
return this.options.parsingSupport.getExecutionLoopSettings();
|
|
56
|
+
}
|
|
57
|
+
async *run(messages, originalUserMessage, uiMode, initialContext, mentionedFiles, activeThreadService, activeTaskSessionService, signal, runOptions = {}) {
|
|
58
|
+
const runPhase = runOptions.phase === AgentPhase.PLANNING ? AgentPhase.PLANNING : AgentPhase.EXECUTION;
|
|
59
|
+
const planMode = runPhase === AgentPhase.PLANNING;
|
|
60
|
+
const promptMode = planMode
|
|
61
|
+
? (typeof uiMode === 'string' && uiMode.trim().length > 0 ? uiMode : 'Planning')
|
|
62
|
+
: 'Execution';
|
|
63
|
+
const logLabel = runOptions.logLabel || (planMode ? 'PLANNING' : 'EXECUTION');
|
|
64
|
+
const markCompletedOnFinish = !runOptions.stopOnPhaseTransition;
|
|
65
|
+
const queryState = {
|
|
66
|
+
objective: originalUserMessage,
|
|
67
|
+
planMode,
|
|
68
|
+
plannedFileTargets: planMode ? [] : this.extractPlannedFileTargets(messages),
|
|
69
|
+
turnCount: 1,
|
|
70
|
+
recoveryNoToolTurns: 0,
|
|
71
|
+
noToolTurns: 0
|
|
72
|
+
};
|
|
73
|
+
const persistedPendingRecovery = planMode ? undefined : activeTaskSessionService.getPendingRecovery();
|
|
74
|
+
if (persistedPendingRecovery?.prompt) {
|
|
75
|
+
queryState.pendingRecoveryPrompt = persistedPendingRecovery.prompt;
|
|
76
|
+
}
|
|
77
|
+
const nativeTools = this.getNativeToolDefinitions();
|
|
78
|
+
const settings = this.options.parsingSupport.getExecutionLoopSettings();
|
|
79
|
+
const executionFlow = runOptions.executionFlow || settings.executionFlow;
|
|
80
|
+
const toolCallLedger = new CleanSlateToolCallLedger({
|
|
81
|
+
availableToolNames: nativeTools.map(tool => tool.name),
|
|
82
|
+
validateToolCall: toolCall => this.executionPhase.validateToolCallForPhase(AgentPhase.EXECUTION, toolCall.toolName, toolCall.input)
|
|
83
|
+
});
|
|
84
|
+
const guardState = {
|
|
85
|
+
touchedPaths: new Set(),
|
|
86
|
+
mutatedPaths: new Set(),
|
|
87
|
+
pendingVerificationPaths: new Set(),
|
|
88
|
+
executionEvidenceLedger: new CleanSlateExecutionEvidenceLedger(),
|
|
89
|
+
mutationSummaries: [],
|
|
90
|
+
verificationSummaries: [],
|
|
91
|
+
terminalSummaries: [],
|
|
92
|
+
markerBaseline: this.options.executionSupport.createMarkerBaseline(settings.failOnWarnings),
|
|
93
|
+
currentTurnIndex: 1,
|
|
94
|
+
successfulToolResultsInPhase: 0,
|
|
95
|
+
successfulMutationsInPhase: 0,
|
|
96
|
+
failOnWarnings: settings.failOnWarnings,
|
|
97
|
+
postEditCommandVerified: false,
|
|
98
|
+
postEditCommandIssues: []
|
|
99
|
+
};
|
|
100
|
+
if (activeTaskSessionService.getPhase() !== runPhase) {
|
|
101
|
+
activeTaskSessionService.setPhase(runPhase);
|
|
102
|
+
}
|
|
103
|
+
while (true) {
|
|
104
|
+
if (signal?.aborted) {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
const budgetDecision = runOptions.executionBudget?.consumeModelTurn(runPhase);
|
|
108
|
+
if (budgetDecision && !budgetDecision.allowed) {
|
|
109
|
+
const stopMessage = budgetDecision.message;
|
|
110
|
+
yield { type: 'chat_text', content: stopMessage, kind: 'model_terminated_pause' };
|
|
111
|
+
activeThreadService.addMessage('assistant', stopMessage);
|
|
112
|
+
activeTaskSessionService.recordAssistantSummary(stopMessage);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const visibleTurnIndex = queryState.turnCount;
|
|
116
|
+
guardState.currentTurnIndex = visibleTurnIndex;
|
|
117
|
+
toolCallLedger.beginTurn();
|
|
118
|
+
await this.waitForNextModelTurn(signal, executionFlow);
|
|
119
|
+
console.log(`[CleanSlateAgent] [${logLabel}] Starting query turn ${visibleTurnIndex}...`);
|
|
120
|
+
if (this.shouldRefreshContextForTurn(visibleTurnIndex)) {
|
|
121
|
+
await this.prepareContext({
|
|
122
|
+
messages,
|
|
123
|
+
objective: originalUserMessage,
|
|
124
|
+
mode: promptMode,
|
|
125
|
+
planMode,
|
|
126
|
+
initialContext,
|
|
127
|
+
mentionedFiles,
|
|
128
|
+
deferredSemanticContext: runOptions.deferredSemanticContext,
|
|
129
|
+
signal
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const turnId = `${runPhase}-${visibleTurnIndex}`;
|
|
133
|
+
let currentResponse = '';
|
|
134
|
+
const streamedToolCalls = [];
|
|
135
|
+
const streamedToolCallKeys = new Set();
|
|
136
|
+
const yieldedStreamingExecutions = [];
|
|
137
|
+
let finishedDuringModelStream = false;
|
|
138
|
+
let concludedWithPlanSignal = false;
|
|
139
|
+
let completedBlockingToolDuringModelStream = false;
|
|
140
|
+
let nextToolIndex = 0;
|
|
141
|
+
const streamingToolExecutor = new CleanSlateStreamingToolExecutor({
|
|
142
|
+
isConcurrencySafe: toolCall => this.isParallelToolCall(toolCall),
|
|
143
|
+
executeTool: (toolCall, signal) => this.streamToolExecutionParts(toolCall, signal, queryState, guardState, executionFlow, toolCallLedger, activeTaskSessionService),
|
|
144
|
+
signal,
|
|
145
|
+
emitAbortedResults: true
|
|
146
|
+
});
|
|
147
|
+
const turnNativeTools = this.getNativeToolDefinitionsForTurn(nativeTools, queryState);
|
|
148
|
+
const pruneResult = this.contextBudgetManager.pruneOldToolOutputs(messages);
|
|
149
|
+
if (pruneResult.pruned) {
|
|
150
|
+
console.info(`[CleanSlateAgent] [${logLabel}] Proactively pruned old tool output before turn ${visibleTurnIndex}: ${pruneResult.beforeChars} -> ${pruneResult.afterChars} chars; reclaimed=${pruneResult.reclaimedChars}; toolResults=${pruneResult.compactedToolResults}; assistantTurns=${pruneResult.compactedAssistantTurns}.`);
|
|
151
|
+
}
|
|
152
|
+
const toolDefinitionChars = this.getToolDefinitionChars(turnNativeTools);
|
|
153
|
+
if (this.shouldAttemptConversationCompaction(messages, toolDefinitionChars)) {
|
|
154
|
+
yield { type: 'context_compaction_start', turnId };
|
|
155
|
+
const compacted = await this.compactMessagesBeforeProviderCall(messages, visibleTurnIndex, logLabel, toolDefinitionChars, signal);
|
|
156
|
+
yield { type: 'context_compaction_complete', turnId, compacted };
|
|
157
|
+
}
|
|
158
|
+
const providerMessages = this.buildMessagesForProvider(messages, visibleTurnIndex, logLabel, toolDefinitionChars);
|
|
159
|
+
const contextUsage = this.getEstimatedContextUsage(providerMessages, toolDefinitionChars);
|
|
160
|
+
yield { type: 'assistant_turn_start', phase: runPhase, turnId, turnIndex: visibleTurnIndex };
|
|
161
|
+
yield { type: 'context_usage', turnId, ...contextUsage };
|
|
162
|
+
this.refreshFileReadBudget(providerMessages, turnNativeTools);
|
|
163
|
+
const response = await this.options.cleanSlateService.chat(providerMessages, {
|
|
164
|
+
tools: turnNativeTools,
|
|
165
|
+
sessionId: this.options.getSessionId?.(),
|
|
166
|
+
cancellationToken: cancellationTokenFromAbortSignal(signal)
|
|
167
|
+
});
|
|
168
|
+
const responseIterator = response[Symbol.asyncIterator]();
|
|
169
|
+
let nextModelPart = responseIterator.next();
|
|
170
|
+
let nextToolEvent;
|
|
171
|
+
const collectToolEventParts = (event) => {
|
|
172
|
+
if (!event) {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
if (event.type === 'parts') {
|
|
176
|
+
return event.batch.parts;
|
|
177
|
+
}
|
|
178
|
+
yieldedStreamingExecutions.push(event.execution);
|
|
179
|
+
if (!this.isParallelToolCall(event.execution.toolCall)) {
|
|
180
|
+
completedBlockingToolDuringModelStream = true;
|
|
181
|
+
}
|
|
182
|
+
return event.execution.parts;
|
|
183
|
+
};
|
|
184
|
+
while (!signal?.aborted) {
|
|
185
|
+
if (!nextToolEvent && streamingToolExecutor.hasUnfinishedWork()) {
|
|
186
|
+
nextToolEvent = streamingToolExecutor.nextEvent();
|
|
187
|
+
}
|
|
188
|
+
const next = await Promise.race([
|
|
189
|
+
nextModelPart.then(result => ({ type: 'model', result })),
|
|
190
|
+
...(nextToolEvent ? [nextToolEvent.then(event => ({ type: 'tool', event }))] : [])
|
|
191
|
+
]);
|
|
192
|
+
if (next.type === 'tool') {
|
|
193
|
+
nextToolEvent = undefined;
|
|
194
|
+
for (const executionPart of collectToolEventParts(next.event)) {
|
|
195
|
+
yield executionPart;
|
|
196
|
+
if (executionPart.type === 'task_complete' || (executionPart.type === 'tool_result' && executionPart.toolName === PHASE_CONCLUSION_SIGNAL_PLAN_CREATED)) {
|
|
197
|
+
finishedDuringModelStream = true;
|
|
198
|
+
concludedWithPlanSignal = concludedWithPlanSignal || (executionPart.type === 'tool_result' && executionPart.toolName === PHASE_CONCLUSION_SIGNAL_PLAN_CREATED);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (finishedDuringModelStream || completedBlockingToolDuringModelStream) {
|
|
202
|
+
if (typeof responseIterator.return === 'function') {
|
|
203
|
+
await responseIterator.return();
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const modelResult = next.result;
|
|
210
|
+
if (modelResult.done) {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
const part = modelResult.value;
|
|
214
|
+
nextModelPart = responseIterator.next();
|
|
215
|
+
if (signal?.aborted) {
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
if (part.type === 'transport_status') {
|
|
219
|
+
yield part;
|
|
220
|
+
}
|
|
221
|
+
else if (part.type === 'reasoning') {
|
|
222
|
+
yield { type: 'reasoning', content: part.content };
|
|
223
|
+
}
|
|
224
|
+
else if (part.type === 'text') {
|
|
225
|
+
currentResponse += part.content;
|
|
226
|
+
// Every normal text block renders, even when a tool call
|
|
227
|
+
// follows it. Phase is presentation metadata, never
|
|
228
|
+
// permission for the host to discard assistant text.
|
|
229
|
+
yield {
|
|
230
|
+
type: 'chat_text',
|
|
231
|
+
content: part.content,
|
|
232
|
+
kind: part.phase === 'commentary'
|
|
233
|
+
? 'commentary'
|
|
234
|
+
: part.phase === 'final_answer' ? 'final_answer' : 'assistant'
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
else if (part.type === 'tool_call') {
|
|
238
|
+
const streamedToolCall = this.parseStreamedToolCall(part.call, toolCallLedger);
|
|
239
|
+
if (streamedToolCall) {
|
|
240
|
+
const key = toolCallLedger.getTurnKey(streamedToolCall);
|
|
241
|
+
if (!streamedToolCallKeys.has(key) && toolCallLedger.shouldAcceptInCurrentTurn(streamedToolCall)) {
|
|
242
|
+
streamedToolCallKeys.add(key);
|
|
243
|
+
streamedToolCalls.push(streamedToolCall);
|
|
244
|
+
streamingToolExecutor.addTool(streamedToolCall, nextToolIndex++);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (finishedDuringModelStream) {
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (!finishedDuringModelStream && nextToolEvent) {
|
|
253
|
+
for (const executionPart of collectToolEventParts(await nextToolEvent)) {
|
|
254
|
+
yield executionPart;
|
|
255
|
+
if (executionPart.type === 'task_complete' || (executionPart.type === 'tool_result' && executionPart.toolName === PHASE_CONCLUSION_SIGNAL_PLAN_CREATED)) {
|
|
256
|
+
finishedDuringModelStream = true;
|
|
257
|
+
concludedWithPlanSignal = concludedWithPlanSignal || (executionPart.type === 'tool_result' && executionPart.toolName === PHASE_CONCLUSION_SIGNAL_PLAN_CREATED);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
yield { type: 'assistant_turn_complete', phase: runPhase, turnId, turnIndex: visibleTurnIndex };
|
|
262
|
+
this.recordModelTurnCompleted();
|
|
263
|
+
if (finishedDuringModelStream) {
|
|
264
|
+
if (markCompletedOnFinish && !concludedWithPlanSignal) {
|
|
265
|
+
activeTaskSessionService.markCompleted();
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const assistantTurn = this.parseAssistantTurn(currentResponse);
|
|
270
|
+
const toolCalls = this.mergeToolCalls(assistantTurn.toolCalls, streamedToolCalls);
|
|
271
|
+
for (const toolCall of assistantTurn.toolCalls) {
|
|
272
|
+
const normalizedToolCall = toolCallLedger.normalizeToolCall(toolCall);
|
|
273
|
+
const key = toolCallLedger.getTurnKey(normalizedToolCall);
|
|
274
|
+
if (streamedToolCallKeys.has(key)) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (!toolCallLedger.shouldAcceptInCurrentTurn(normalizedToolCall)) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
streamingToolExecutor.addTool(normalizedToolCall, nextToolIndex++);
|
|
281
|
+
}
|
|
282
|
+
const assistantMemoryContent = () => this.options.parsingSupport.buildLoopAssistantMemory(currentResponse, runPhase, assistantTurn.toDoList, toolCalls);
|
|
283
|
+
if (toolCalls.length > 0) {
|
|
284
|
+
queryState.noToolTurns = 0;
|
|
285
|
+
messages.push(this.nativeToolTranscript.buildAssistantToolCallMessage(assistantMemoryContent(), toolCalls));
|
|
286
|
+
let shouldRestartAfterMutation = false;
|
|
287
|
+
let sawConfirmedMutation = false;
|
|
288
|
+
let sawUserCancelledCommand = false;
|
|
289
|
+
let sawToolCallLoop = false;
|
|
290
|
+
const recoveryPrompts = [];
|
|
291
|
+
for (const execution of yieldedStreamingExecutions) {
|
|
292
|
+
if (this.pauseForQuestion(execution.toolCall, execution.result, activeTaskSessionService)) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
messages.push(this.nativeToolTranscript.buildToolResultMessage(execution.toolCall, execution.result));
|
|
296
|
+
if (this.editPolicy.isUserCancelledCommandResult(execution.toolCall, execution.result)) {
|
|
297
|
+
sawUserCancelledCommand = true;
|
|
298
|
+
}
|
|
299
|
+
if (this.isToolCallLoopResult(execution.result)) {
|
|
300
|
+
sawToolCallLoop = true;
|
|
301
|
+
}
|
|
302
|
+
if (this.shouldVerifyAfterToolResult(execution.toolCall, execution.result)) {
|
|
303
|
+
shouldRestartAfterMutation = true;
|
|
304
|
+
sawConfirmedMutation = true;
|
|
305
|
+
}
|
|
306
|
+
const recoveryPrompt = this.editPolicy.buildFailedEditRecoveryPrompt(execution.toolCall, execution.result);
|
|
307
|
+
if (recoveryPrompt) {
|
|
308
|
+
recoveryPrompts.push(recoveryPrompt);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
for await (const event of streamingToolExecutor.getRemainingEvents()) {
|
|
312
|
+
if (event.type === 'parts') {
|
|
313
|
+
for (const part of event.batch.parts) {
|
|
314
|
+
yield part;
|
|
315
|
+
if (part.type === 'tool_result' && part.toolName === PHASE_CONCLUSION_SIGNAL_PLAN_CREATED) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (part.type === 'task_complete') {
|
|
319
|
+
if (markCompletedOnFinish) {
|
|
320
|
+
activeTaskSessionService.markCompleted();
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (part.type === 'tool_result' && this.pauseForQuestion(event.batch.toolCall, part.result, activeTaskSessionService)) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
const execution = event.execution;
|
|
331
|
+
for (const part of execution.parts) {
|
|
332
|
+
yield part;
|
|
333
|
+
if (part.type === 'tool_result' && part.toolName === PHASE_CONCLUSION_SIGNAL_PLAN_CREATED) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (part.type === 'task_complete') {
|
|
337
|
+
if (markCompletedOnFinish) {
|
|
338
|
+
activeTaskSessionService.markCompleted();
|
|
339
|
+
}
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (this.pauseForQuestion(execution.toolCall, execution.result, activeTaskSessionService)) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
messages.push(this.nativeToolTranscript.buildToolResultMessage(execution.toolCall, execution.result));
|
|
347
|
+
if (this.editPolicy.isUserCancelledCommandResult(execution.toolCall, execution.result)) {
|
|
348
|
+
sawUserCancelledCommand = true;
|
|
349
|
+
}
|
|
350
|
+
if (this.isToolCallLoopResult(execution.result)) {
|
|
351
|
+
sawToolCallLoop = true;
|
|
352
|
+
}
|
|
353
|
+
if (this.shouldVerifyAfterToolResult(execution.toolCall, execution.result)) {
|
|
354
|
+
shouldRestartAfterMutation = true;
|
|
355
|
+
sawConfirmedMutation = true;
|
|
356
|
+
}
|
|
357
|
+
const recoveryPrompt = this.editPolicy.buildFailedEditRecoveryPrompt(execution.toolCall, execution.result);
|
|
358
|
+
if (recoveryPrompt) {
|
|
359
|
+
recoveryPrompts.push(recoveryPrompt);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (sawUserCancelledCommand) {
|
|
364
|
+
const stopMessage = 'Command cancelled. I will not run it again unless you explicitly ask me to.';
|
|
365
|
+
activeTaskSessionService.markCancelled();
|
|
366
|
+
yield { type: 'chat_text', content: stopMessage };
|
|
367
|
+
yield { type: 'assistant_turn_complete', phase: runPhase, turnId, turnIndex: visibleTurnIndex };
|
|
368
|
+
activeThreadService.addMessage('assistant', stopMessage);
|
|
369
|
+
activeTaskSessionService.recordAssistantSummary(stopMessage);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (sawToolCallLoop) {
|
|
373
|
+
const stopMessage = 'Paused after the same tool call was repeated three times. Change the tool or its arguments before continuing; the workspace was not declared complete.';
|
|
374
|
+
yield { type: 'chat_text', content: stopMessage, kind: 'model_terminated_pause' };
|
|
375
|
+
activeThreadService.addMessage('assistant', stopMessage);
|
|
376
|
+
activeTaskSessionService.recordAssistantSummary(stopMessage);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (shouldRestartAfterMutation) {
|
|
380
|
+
if (sawConfirmedMutation && recoveryPrompts.length === 0) {
|
|
381
|
+
queryState.pendingRecoveryPrompt = undefined;
|
|
382
|
+
queryState.recoveryNoToolTurns = 0;
|
|
383
|
+
activeTaskSessionService.clearPendingRecovery();
|
|
384
|
+
}
|
|
385
|
+
const verificationResult = yield* this.streamPostMutationVerificationParts(signal, guardState);
|
|
386
|
+
if (verificationResult.result) {
|
|
387
|
+
messages.push({
|
|
388
|
+
role: 'system',
|
|
389
|
+
content: `Deterministic ${this.verificationToolName} verification result:\n${serializeToolResultForPrompt(this.verificationToolName, verificationResult.result)}`
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
const verificationFailed = verificationResult.result?.success === false;
|
|
393
|
+
const verificationIssues = verificationFailed
|
|
394
|
+
? [String(verificationResult.result?.message ?? verificationResult.result?.error ?? 'read_lints failed.')]
|
|
395
|
+
: verificationResult.issues;
|
|
396
|
+
guardState.postEditCommandVerified = verificationIssues.length === 0;
|
|
397
|
+
guardState.postEditCommandIssues = verificationIssues;
|
|
398
|
+
if (verificationIssues.length > 0) {
|
|
399
|
+
messages.push({
|
|
400
|
+
role: 'system',
|
|
401
|
+
content: this.buildPostMutationVerificationPrompt(verificationIssues)
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
else if (recoveryPrompts.length === 0 && !queryState.pendingRecoveryPrompt) {
|
|
405
|
+
const finalVerificationScope = guardState.mutatedPaths.size > 0
|
|
406
|
+
? guardState.mutatedPaths
|
|
407
|
+
: guardState.touchedPaths;
|
|
408
|
+
const finalIssues = await this.options.executionSupport.collectNewMarkerIssues(guardState.markerBaseline, finalVerificationScope, guardState.failOnWarnings, 40);
|
|
409
|
+
if (finalIssues.length === 0) {
|
|
410
|
+
messages.push({
|
|
411
|
+
role: 'system',
|
|
412
|
+
content: this.buildVerifiedFinishPrompt(guardState)
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
guardState.postEditCommandVerified = false;
|
|
417
|
+
guardState.postEditCommandIssues = finalIssues;
|
|
418
|
+
messages.push({
|
|
419
|
+
role: 'system',
|
|
420
|
+
content: this.buildPostMutationVerificationPrompt(finalIssues)
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// No re-read demand after mutations:
|
|
425
|
+
// apply_edit updates the host read-state with post-write
|
|
426
|
+
// content, and string anchors resolve against current
|
|
427
|
+
// content — the model's own edits never go stale on it.
|
|
428
|
+
}
|
|
429
|
+
if (recoveryPrompts.length > 0) {
|
|
430
|
+
for (const recoveryPrompt of recoveryPrompts) {
|
|
431
|
+
this.appendPendingRecoveryPrompt(queryState, recoveryPrompt);
|
|
432
|
+
}
|
|
433
|
+
activeTaskSessionService.setPendingRecovery(queryState.pendingRecoveryPrompt, { toolName: this.profile.recoveryMutationTool ?? '', code: 'recovery_required' });
|
|
434
|
+
messages.push({
|
|
435
|
+
role: 'system',
|
|
436
|
+
content: queryState.pendingRecoveryPrompt ?? recoveryPrompts.join('\n\n')
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
else if (sawConfirmedMutation) {
|
|
440
|
+
queryState.pendingRecoveryPrompt = undefined;
|
|
441
|
+
queryState.recoveryNoToolTurns = 0;
|
|
442
|
+
activeTaskSessionService.clearPendingRecovery();
|
|
443
|
+
}
|
|
444
|
+
queryState.turnCount++;
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (planMode) {
|
|
448
|
+
// Plan-mode stop semantics: a turn with no tool calls means the
|
|
449
|
+
// model stopped to talk to the user — a clarifying question, an
|
|
450
|
+
// intermediate report, or an answer. The turn simply ends; none
|
|
451
|
+
// of the execution completion machinery below applies in plan
|
|
452
|
+
// mode.
|
|
453
|
+
if (currentResponse.trim().length > 0) {
|
|
454
|
+
messages.push({ role: 'assistant', content: currentResponse });
|
|
455
|
+
activeThreadService.addMessage('assistant', currentResponse);
|
|
456
|
+
activeTaskSessionService.recordAssistantTurn(currentResponse);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
// A truly empty response falls through to the generic
|
|
460
|
+
// no-tool retry nudge — that is transport-glitch recovery,
|
|
461
|
+
// not completion pressure.
|
|
462
|
+
}
|
|
463
|
+
// Stop semantics:
|
|
464
|
+
// tool calls keep the loop alive; a non-empty assistant response
|
|
465
|
+
// with no tool call is the final model turn. Completion itself is
|
|
466
|
+
// a host lifecycle event, never a model-facing tool call.
|
|
467
|
+
if (!planMode && await this.canHostFinalizeProseStop(currentResponse, queryState, guardState)) {
|
|
468
|
+
if (markCompletedOnFinish) {
|
|
469
|
+
activeTaskSessionService.markCompleted();
|
|
470
|
+
}
|
|
471
|
+
messages.push({ role: 'assistant', content: currentResponse });
|
|
472
|
+
yield {
|
|
473
|
+
type: 'task_complete',
|
|
474
|
+
result: {
|
|
475
|
+
phase: AgentPhase.EXECUTION,
|
|
476
|
+
executionFlow,
|
|
477
|
+
verified: true,
|
|
478
|
+
completionSource: 'host_finalized',
|
|
479
|
+
completionState: this.buildCompletionState(guardState, currentResponse, queryState.plannedFileTargets)
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (!planMode && currentResponse.trim().length > 0) {
|
|
485
|
+
messages.push({ role: 'assistant', content: currentResponse });
|
|
486
|
+
activeThreadService.addMessage('assistant', currentResponse);
|
|
487
|
+
activeTaskSessionService.recordAssistantTurn(currentResponse);
|
|
488
|
+
activeTaskSessionService.recordAssistantSummary(currentResponse);
|
|
489
|
+
activeTaskSessionService.markInterrupted();
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (queryState.pendingRecoveryPrompt) {
|
|
493
|
+
queryState.recoveryNoToolTurns++;
|
|
494
|
+
const recoveryNudge = [
|
|
495
|
+
'RECOVERY STILL REQUIRED: the previous edit failed and no recovery tool call was returned.',
|
|
496
|
+
queryState.pendingRecoveryPrompt,
|
|
497
|
+
'Return corrected tool_calls only. Re-read only if the result reports stale content or you need more current context, then retry apply_edit with file_path, a corrected unique old_string, and new_string. Do not return a final answer until the failed edit is fixed or verified unnecessary.'
|
|
498
|
+
].join('\n\n');
|
|
499
|
+
activeThreadService.addMessage('assistant', assistantMemoryContent(), true);
|
|
500
|
+
messages.push({ role: 'assistant', content: assistantMemoryContent() });
|
|
501
|
+
messages.push({ role: 'system', content: recoveryNudge });
|
|
502
|
+
if (queryState.recoveryNoToolTurns >= 4) {
|
|
503
|
+
const stopMessage = 'Paused execution after repeated edit-failure recovery turns returned no tool calls. The workspace was not declared complete.';
|
|
504
|
+
yield { type: 'chat_text', content: stopMessage, kind: 'model_terminated_pause' };
|
|
505
|
+
activeThreadService.addMessage('assistant', stopMessage);
|
|
506
|
+
activeTaskSessionService.recordAssistantSummary(stopMessage);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
queryState.turnCount++;
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
queryState.noToolTurns++;
|
|
513
|
+
const maxNoToolTurns = this.getNoProgressTurnLimit(AgentPhase.EXECUTION, settings.maxNoToolTurns, {
|
|
514
|
+
hasPhaseProgress: guardState.successfulToolResultsInPhase > 0,
|
|
515
|
+
hasAssistantOutput: currentResponse.trim().length > 0
|
|
516
|
+
});
|
|
517
|
+
const noToolStopLimit = executionFlow === 'normal'
|
|
518
|
+
? maxNoToolTurns
|
|
519
|
+
: Math.max(maxNoToolTurns, 3);
|
|
520
|
+
if (queryState.noToolTurns >= noToolStopLimit) {
|
|
521
|
+
const stopMessage = this.buildNoProgressStopMessage(queryState.noToolTurns, 'the provider returned neither an executable tool call nor a final assistant answer');
|
|
522
|
+
yield { type: 'chat_text', content: stopMessage, kind: 'model_terminated_pause' };
|
|
523
|
+
activeThreadService.addMessage('assistant', stopMessage);
|
|
524
|
+
activeTaskSessionService.recordAssistantSummary(stopMessage);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
// A turn that serialized tool syntax into text is a specific failure
|
|
528
|
+
// with a specific correction — the generic "return tool calls"
|
|
529
|
+
// nudge leaves the model believing its call ran.
|
|
530
|
+
const noToolPrompt = detectSerializedToolCallSyntax(currentResponse)
|
|
531
|
+
? buildSerializedToolCallRecoveryPrompt()
|
|
532
|
+
: this.buildNoToolRecoveryPrompt(guardState.successfulToolResultsInPhase > 0);
|
|
533
|
+
messages.push({ role: 'assistant', content: assistantMemoryContent() });
|
|
534
|
+
messages.push({ role: 'system', content: noToolPrompt });
|
|
535
|
+
activeThreadService.addMessage('assistant', assistantMemoryContent(), true);
|
|
536
|
+
activeThreadService.addMessage('system', noToolPrompt, true);
|
|
537
|
+
queryState.turnCount++;
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
shouldPauseForQuestionResult(toolName, result, inputSummary, activeTaskSessionService) {
|
|
542
|
+
if (toolName !== this.profile.questionTool || result?.success === false || !result?.planning_question) {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
const summary = typeof result?.summary === 'string' && result.summary.trim().length > 0
|
|
546
|
+
? result.summary.trim()
|
|
547
|
+
: typeof inputSummary === 'string' && inputSummary.trim().length > 0
|
|
548
|
+
? inputSummary.trim()
|
|
549
|
+
: undefined;
|
|
550
|
+
activeTaskSessionService.recordAssistantSummary(summary);
|
|
551
|
+
return true;
|
|
552
|
+
}
|
|
553
|
+
pauseForQuestion(toolCall, result, activeTaskSessionService) {
|
|
554
|
+
if (!this.shouldPauseForQuestionResult(toolCall.toolName, result, toolCall.input?.summary, activeTaskSessionService)) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
this.options.onQuestionPaused?.(toolCall, result);
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
async waitForNextModelTurn(signal, executionFlow) {
|
|
561
|
+
const now = Date.now();
|
|
562
|
+
if (this.lastModelTurnStartedAt === undefined) {
|
|
563
|
+
this.lastModelTurnStartedAt = now;
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
const elapsedMs = now - this.lastModelTurnStartedAt;
|
|
567
|
+
const intervalMs = executionFlow === 'normal'
|
|
568
|
+
? CleanSlateExecutionQueryEngine.NORMAL_MODEL_TURN_INTERVAL_MS
|
|
569
|
+
: executionFlow === 'planning'
|
|
570
|
+
? CleanSlateExecutionQueryEngine.PLANNING_MODEL_TURN_INTERVAL_MS
|
|
571
|
+
: CleanSlateExecutionQueryEngine.DEFAULT_MODEL_TURN_INTERVAL_MS;
|
|
572
|
+
const waitMs = Math.max(0, intervalMs - elapsedMs);
|
|
573
|
+
if (waitMs > 0) {
|
|
574
|
+
await this.delay(waitMs, signal);
|
|
575
|
+
}
|
|
576
|
+
this.lastModelTurnStartedAt = Date.now();
|
|
577
|
+
}
|
|
578
|
+
recordModelTurnCompleted() {
|
|
579
|
+
// The native loop only needs a cadence boundary; waitForNextModelTurn tracks starts.
|
|
580
|
+
}
|
|
581
|
+
async compactMessagesBeforeProviderCall(messages, visibleTurnIndex, logLabel, promptOverheadChars, signal) {
|
|
582
|
+
const thresholdChars = this.getConversationMessageThresholdChars(promptOverheadChars);
|
|
583
|
+
if (!this.contextBudgetManager.shouldCompactMessages(messages, thresholdChars)) {
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
const keepStart = this.getCompactionKeepStart(messages);
|
|
587
|
+
if (keepStart <= 2) {
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
const beforeChars = this.contextBudgetManager.getMessagesCharCount(messages);
|
|
591
|
+
const compactedHistory = messages.slice(1, keepStart);
|
|
592
|
+
const previousSummary = compactedHistory.find(message => this.isCompactionSummaryMessage(message));
|
|
593
|
+
const preservedUserMessages = compactedHistory.filter(message => message.role === 'user');
|
|
594
|
+
const summaryPrompt = [
|
|
595
|
+
{
|
|
596
|
+
role: 'system',
|
|
597
|
+
content: [
|
|
598
|
+
previousSummary
|
|
599
|
+
? 'Update the prior continuation summary with the newer conversation history.'
|
|
600
|
+
: 'Create a continuation summary for the older portion of this coding-agent conversation.',
|
|
601
|
+
'Use exactly these terse Markdown sections: Goal; Constraints & Preferences; Progress (Done, In Progress, Blocked); Key Decisions; Next Steps; Critical Context; Relevant Files.',
|
|
602
|
+
'Preserve exact file paths, symbols, commands, error strings, edits, test outcomes, unresolved work, and unanswered user questions. Do not invent facts.',
|
|
603
|
+
'Completed tool calls already ran. Record their durable outcomes so the agent does not repeat work blindly.',
|
|
604
|
+
previousSummary ? `Prior summary to update:\n${this.messageContentToText(previousSummary)}` : ''
|
|
605
|
+
].join('\n')
|
|
606
|
+
},
|
|
607
|
+
...compactedHistory.filter(message => !this.isCompactionSummaryMessage(message))
|
|
608
|
+
];
|
|
609
|
+
const summaryBudget = Math.max(12_000, thresholdChars);
|
|
610
|
+
const projected = this.contextBudgetManager.projectMessagesForProvider(summaryPrompt, summaryBudget).messages;
|
|
611
|
+
try {
|
|
612
|
+
const response = await this.options.cleanSlateService.chat(projected, {
|
|
613
|
+
cancellationToken: cancellationTokenFromAbortSignal(signal),
|
|
614
|
+
maxOutputTokens: CleanSlateExecutionQueryEngine.COMPACTION_MAX_OUTPUT_TOKENS
|
|
615
|
+
});
|
|
616
|
+
let summary = '';
|
|
617
|
+
for await (const part of response) {
|
|
618
|
+
if (part.type === 'text') {
|
|
619
|
+
summary += part.content;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
const normalizedSummary = summary.trim();
|
|
623
|
+
if (!normalizedSummary || signal?.aborted) {
|
|
624
|
+
if (!signal?.aborted) {
|
|
625
|
+
this.consecutiveCompactionFailures++;
|
|
626
|
+
}
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
// Replacement-history behavior: keep actual user turns intact and
|
|
630
|
+
// replace only older model/tool transcript with one summary.
|
|
631
|
+
// Recent messages (including the latest tool groups) remain untouched.
|
|
632
|
+
messages.splice(1, keepStart - 1, ...preservedUserMessages, {
|
|
633
|
+
role: 'system',
|
|
634
|
+
content: `[COMPACTED CONVERSATION SUMMARY]\n${normalizedSummary}`
|
|
635
|
+
});
|
|
636
|
+
this.consecutiveCompactionFailures = 0;
|
|
637
|
+
const afterChars = this.contextBudgetManager.getMessagesCharCount(messages);
|
|
638
|
+
this.lastSuccessfulCompactionChars = afterChars;
|
|
639
|
+
console.info(`[CleanSlateAgent] [${logLabel}] Model-compacted conversation before turn ${visibleTurnIndex}: ${beforeChars} -> ${afterChars} chars; threshold=${thresholdChars}.`);
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
this.consecutiveCompactionFailures++;
|
|
644
|
+
if (!signal?.aborted) {
|
|
645
|
+
console.warn('[CleanSlateAgent] Conversation compaction failed; using a non-mutating provider projection for this turn.', error);
|
|
646
|
+
}
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
shouldAttemptConversationCompaction(messages, promptOverheadChars) {
|
|
651
|
+
if (this.consecutiveCompactionFailures >= CleanSlateExecutionQueryEngine.MAX_CONSECUTIVE_COMPACTION_FAILURES) {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
const currentChars = this.contextBudgetManager.getMessagesCharCount(messages);
|
|
655
|
+
if (this.lastSuccessfulCompactionChars !== undefined
|
|
656
|
+
&& currentChars < Math.ceil(this.lastSuccessfulCompactionChars * CleanSlateExecutionQueryEngine.AUTO_COMPACTION_REGROWTH_RATIO)) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
return this.contextBudgetManager.shouldCompactMessages(messages, this.getConversationMessageThresholdChars(promptOverheadChars)) && this.getCompactionKeepStart(messages) > 2;
|
|
660
|
+
}
|
|
661
|
+
getConversationMessageThresholdChars(promptOverheadChars) {
|
|
662
|
+
return Math.max(12_000, this.options.parsingSupport.getExecutionAutoCompactThresholdChars() - Math.max(0, promptOverheadChars));
|
|
663
|
+
}
|
|
664
|
+
isCompactionSummaryMessage(message) {
|
|
665
|
+
return message.role === 'system'
|
|
666
|
+
&& this.messageContentToText(message).startsWith('[COMPACTED CONVERSATION SUMMARY]');
|
|
667
|
+
}
|
|
668
|
+
messageContentToText(message) {
|
|
669
|
+
return typeof message.content === 'string'
|
|
670
|
+
? message.content
|
|
671
|
+
: message.content.map(part => part.type === 'text' ? part.text ?? '' : '').join('\n');
|
|
672
|
+
}
|
|
673
|
+
getCompactionKeepStart(messages) {
|
|
674
|
+
let keepStart = Math.max(1, messages.length - 18);
|
|
675
|
+
while (keepStart > 1 && messages[keepStart]?.role === 'tool') {
|
|
676
|
+
keepStart--;
|
|
677
|
+
}
|
|
678
|
+
return keepStart;
|
|
679
|
+
}
|
|
680
|
+
buildMessagesForProvider(messages, visibleTurnIndex, logLabel, promptOverheadChars) {
|
|
681
|
+
const budgetChars = Math.max(12_000, this.options.parsingSupport.getExecutionContextBudgetChars() - Math.max(0, promptOverheadChars));
|
|
682
|
+
const projection = this.contextBudgetManager.projectMessagesForProvider(messages, budgetChars);
|
|
683
|
+
if (projection.result.compacted) {
|
|
684
|
+
console.debug(`[CleanSlateAgent] [${logLabel}] Context budget projected for turn ${visibleTurnIndex}: ${projection.result.beforeChars} -> ${projection.result.afterChars} chars; clampedToolResults=${projection.result.clampedToolResults}; clampedAssistantTurns=${projection.result.clampedAssistantTurns}; droppedTool=${projection.result.droppedToolMessages}; droppedSystem=${projection.result.droppedSystemMessages}; droppedHistory=${projection.result.droppedHistoryMessages}`);
|
|
685
|
+
}
|
|
686
|
+
return projection.messages;
|
|
687
|
+
}
|
|
688
|
+
getEstimatedContextUsage(messages, promptOverheadChars) {
|
|
689
|
+
const estimatedInputTokens = Math.ceil((this.contextBudgetManager.getMessagesCharCount(messages) + Math.max(0, promptOverheadChars)) / 4);
|
|
690
|
+
const contextWindowTokens = Math.max(1, Math.floor(this.options.parsingSupport.getExecutionContextBudgetChars() / 4));
|
|
691
|
+
const autoCompactThresholdTokens = Math.max(1, Math.floor(this.options.parsingSupport.getExecutionAutoCompactThresholdChars() / 4));
|
|
692
|
+
return {
|
|
693
|
+
estimatedInputTokens,
|
|
694
|
+
contextWindowTokens,
|
|
695
|
+
autoCompactThresholdTokens,
|
|
696
|
+
percentage: Math.min(100, Math.round((estimatedInputTokens / contextWindowTokens) * 100))
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
getToolDefinitionChars(tools) {
|
|
700
|
+
try {
|
|
701
|
+
return JSON.stringify(tools).length;
|
|
702
|
+
}
|
|
703
|
+
catch {
|
|
704
|
+
return 0;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
shouldRefreshContextForTurn(visibleTurnIndex) {
|
|
708
|
+
return visibleTurnIndex <= 1;
|
|
709
|
+
}
|
|
710
|
+
async prepareContext({ messages, objective, mode, planMode, initialContext, mentionedFiles, deferredSemanticContext, signal }) {
|
|
711
|
+
const freshContext = await this.options.cleanSlateContextService.getContext();
|
|
712
|
+
const promptContext = await (this.options.buildPromptContextForMode
|
|
713
|
+
? this.options.buildPromptContextForMode(freshContext, mode, signal)
|
|
714
|
+
: this.options.buildPromptContext(freshContext, signal));
|
|
715
|
+
void initialContext;
|
|
716
|
+
const systemDirective = planMode
|
|
717
|
+
? this.buildPlanModeDirective()
|
|
718
|
+
: this.buildSystemDirective();
|
|
719
|
+
if (systemDirective.trim().length > 0) {
|
|
720
|
+
messages.push({ role: 'system', content: systemDirective.trim() });
|
|
721
|
+
}
|
|
722
|
+
// Consume the warmed semantic retrieval only if it has already settled by
|
|
723
|
+
// this point (just before the model call) — never block the turn on it.
|
|
724
|
+
// If it isn't ready, the model retrieves via the semantic_search tool.
|
|
725
|
+
const semanticContext = deferredSemanticContext?.tryConsume() ?? '';
|
|
726
|
+
this.refreshContextMessage(messages, promptContext, `${semanticContext}${mentionedFiles}`, objective);
|
|
727
|
+
}
|
|
728
|
+
buildPlanModeDirective() {
|
|
729
|
+
return [
|
|
730
|
+
'',
|
|
731
|
+
'',
|
|
732
|
+
'PLAN MODE:',
|
|
733
|
+
'You are in plan mode. Your tools are read-only: research the workspace, read the relevant code, and design the change. You cannot edit files or run commands in this mode.',
|
|
734
|
+
'Investigate with concrete read/search tool calls. Use assistant text only when you need a user decision or when presenting the completed plan.',
|
|
735
|
+
'When an implementation plan is ready, call submit_artifact with the concise final plan only so it can be reviewed. The artifact is not a research log: omit deliberation, progress narration, files-inspected inventories, and repeated repo facts.',
|
|
736
|
+
'Prefer a clear title plus 3-5 compact sections: Summary, grouped Implementation Changes, Test Plan, and Assumptions only when meaningful. Keep bullets short, avoid unnecessary nesting, and keep straightforward plans under roughly 40 lines.',
|
|
737
|
+
'Group by behavior or subsystem instead of exhaustive file-by-file notes. Mention exact paths only where they prevent ambiguity, normally no more than three unless the task genuinely requires more.',
|
|
738
|
+
'For an informational request, answer in normal assistant text and stop.',
|
|
739
|
+
'If a decision genuinely belongs to the user (competing approaches with real trade-offs, missing requirements), call ask_question. If you simply need to say something to the user, write it as assistant text and stop — the turn ends and the user replies.',
|
|
740
|
+
'Match the plan to the request: for changes to an existing codebase, name the exact files and changes discovered through research; for a greenfield/empty workspace, a scaffold-first plan is correct; for a broad request, scope it explicitly or ask.'
|
|
741
|
+
].join('\n');
|
|
742
|
+
}
|
|
743
|
+
buildSystemDirective() {
|
|
744
|
+
const cliPolicy = [
|
|
745
|
+
'VERIFICATION POLICY:',
|
|
746
|
+
'Use host diagnostics after edits. When diagnostics do not prove the requested behavior, run a finite, scoped execute_command with an accurate intent and writesToWorkspace value.',
|
|
747
|
+
'Prefer targeted tests or builds over broad project commands. Recover from a failed verification when useful, otherwise report it truthfully; partial output is not proof.',
|
|
748
|
+
'Do not create walkthrough artifacts as a completion ritual. When the work is complete, write the visible final answer as normal assistant text and stop without calling a completion tool.'
|
|
749
|
+
].join('\n');
|
|
750
|
+
return [
|
|
751
|
+
'',
|
|
752
|
+
'',
|
|
753
|
+
'WEB RETRIEVAL RULE:',
|
|
754
|
+
'Use web_search for internet discovery and web_fetch for specific URLs. Cite returned source URLs when relying on web evidence; do not use browser_* tools as a search-engine substitute.',
|
|
755
|
+
'For explicit web research/current-information requests, do not answer from search snippets alone. Fetch the most relevant reliable result pages first, then synthesize the fetched evidence into the visible answer with citations.',
|
|
756
|
+
'WEB ANSWER QUALITY:',
|
|
757
|
+
getWebResearchFinalAnswerPrompt(),
|
|
758
|
+
'BROWSER TOOL OPT-IN:',
|
|
759
|
+
'Use browser_* tools only when the current user request explicitly asks you to open a browser, preview a page, inspect DOM, capture screenshots, or perform visual/browser verification.',
|
|
760
|
+
'Do not open localhost, collect browser evidence, or require browser verification only because UI files changed.',
|
|
761
|
+
'When browser verification was not explicitly requested, rely on code inspection, diagnostics, tests, and concise completion reporting instead.',
|
|
762
|
+
'When browser work is requested, operate the one bound live browser session: observe with browser_snapshot, choose a unique semantic locator, act, then observe the resulting URL/DOM/screenshot or diagnostics. Prefer role/name, label, placeholder, text, or testId over coordinates; use coordinates only as a visual fallback.',
|
|
763
|
+
'browser_snapshot is semantic DOM text, not an image. When the user asks to inspect, test, preview, or visually verify a site, call browser_screenshot on the key page states; do not claim visual inspection from browser_snapshot alone.',
|
|
764
|
+
'The visible mouse belongs only to real pointer actions such as browser_click, browser_hover, and browser_scroll. Direct navigation, DOM snapshots, and screenshots must not fabricate mouse movement.',
|
|
765
|
+
'Do not reuse an elementId after navigation or material DOM change. Take a new snapshot and recover from strict-locator ambiguity by choosing a more specific locator instead of guessing.',
|
|
766
|
+
cliPolicy,
|
|
767
|
+
'COMPLETION CONTRACT:',
|
|
768
|
+
'Continue while tool calls are needed. When no more tool calls are needed, return one non-empty user-facing final assistant answer. The host emits task completion only after that natural assistant stop; reasoning, progress narration, mutations, and command output are not completion signals.'
|
|
769
|
+
].join('\n');
|
|
770
|
+
}
|
|
771
|
+
parseAssistantTurn(rawResponse) {
|
|
772
|
+
void rawResponse;
|
|
773
|
+
return {
|
|
774
|
+
toolCalls: [],
|
|
775
|
+
toDoList: []
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Detects arguments that must not execute: the transport's JSON parse
|
|
780
|
+
* failure marker, or serialized tool-call debris that a degenerate model
|
|
781
|
+
* merged into locator argument values. Content-bearing fields (file
|
|
782
|
+
* content, edit text, commands) are deliberately NOT scanned — they can
|
|
783
|
+
* legitimately contain these tokens when the user's code mentions them.
|
|
784
|
+
*/
|
|
785
|
+
getMalformedToolArgumentsError(toolCall) {
|
|
786
|
+
const input = toolCall.input;
|
|
787
|
+
if (!input || typeof input !== 'object') {
|
|
788
|
+
return undefined;
|
|
789
|
+
}
|
|
790
|
+
if (typeof input.__cleanSlateArgumentsParseError === 'string') {
|
|
791
|
+
return input.__cleanSlateArgumentsParseError;
|
|
792
|
+
}
|
|
793
|
+
const locatorValues = [];
|
|
794
|
+
for (const field of ['path', 'file_path', 'pattern', 'query', 'symbol', 'directory']) {
|
|
795
|
+
if (typeof input[field] === 'string') {
|
|
796
|
+
locatorValues.push(input[field]);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (Array.isArray(input.paths)) {
|
|
800
|
+
for (const entry of input.paths) {
|
|
801
|
+
if (typeof entry === 'string') {
|
|
802
|
+
locatorValues.push(entry);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
for (const value of locatorValues) {
|
|
807
|
+
if (detectSerializedToolCallSyntax(value)) {
|
|
808
|
+
return `failed to parse function arguments: a locator argument contains serialized tool-call syntax ("${value.slice(0, 120)}").`;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return undefined;
|
|
812
|
+
}
|
|
813
|
+
parseStreamedToolCall(call, toolCallLedger) {
|
|
814
|
+
const toolCall = this.nativeToolTranscript.parseToolCall(call);
|
|
815
|
+
return toolCall ? toolCallLedger.normalizeToolCall(toolCall) : undefined;
|
|
816
|
+
}
|
|
817
|
+
mergeToolCalls(parsedToolCalls, streamedToolCalls) {
|
|
818
|
+
void parsedToolCalls;
|
|
819
|
+
const seen = new Set();
|
|
820
|
+
const merged = [];
|
|
821
|
+
for (const toolCall of streamedToolCalls) {
|
|
822
|
+
const key = this.getToolCallKey(toolCall);
|
|
823
|
+
if (!seen.has(key)) {
|
|
824
|
+
seen.add(key);
|
|
825
|
+
merged.push(toolCall);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return merged;
|
|
829
|
+
}
|
|
830
|
+
async *executeToolWithTracking(toolName, input, { signal, toolCallId } = {}) {
|
|
831
|
+
for await (const part of this.options.executeTool(toolName, input, toolCallId, signal)) {
|
|
832
|
+
if (signal?.aborted) {
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
if (part.type === 'tool_result' && this.options.executionSupport.didToolSucceed(part.result)) {
|
|
836
|
+
try {
|
|
837
|
+
this.options.recordSemanticToolResult?.(toolName, input, part.result);
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
console.warn('[CleanSlateAgent] Semantic graph ingestion failed:', error);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
yield part;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
getNoProgressTurnLimit(_phase, configuredMaxNoToolTurns, options = {}) {
|
|
847
|
+
const configuredLimit = Number.isFinite(configuredMaxNoToolTurns)
|
|
848
|
+
? Math.max(1, Math.floor(configuredMaxNoToolTurns))
|
|
849
|
+
: 4;
|
|
850
|
+
const floor = options.hasPhaseProgress
|
|
851
|
+
? (options.hasAssistantOutput ? 8 : 6)
|
|
852
|
+
: (options.hasAssistantOutput ? 6 : 4);
|
|
853
|
+
return Math.min(Math.max(configuredLimit, floor), 12);
|
|
854
|
+
}
|
|
855
|
+
refreshContextMessage(messages, promptContext, mentionedFiles, objective) {
|
|
856
|
+
messages.push({
|
|
857
|
+
role: 'system',
|
|
858
|
+
content: `[RUNTIME CONTEXT REMINDER]\n${promptContext}${mentionedFiles}\n\nCurrent objective: ${objective}`
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
getNativeToolDefinitions() {
|
|
862
|
+
return (this.options.getTools?.() ?? ALL_TOOLS).map(tool => ({
|
|
863
|
+
name: tool.name,
|
|
864
|
+
description: tool.description,
|
|
865
|
+
parametersSchema: tool.parametersSchema || { type: 'object', properties: {} }
|
|
866
|
+
}));
|
|
867
|
+
}
|
|
868
|
+
refreshFileReadBudget(messages, tools) {
|
|
869
|
+
const config = this.options.toolContext.configService.getConfiguration();
|
|
870
|
+
const contextWindowTokens = Math.max(1, Math.floor(config.contextWindow
|
|
871
|
+
?? config.maxInputTokens
|
|
872
|
+
?? CLEANSLATE_FALLBACK_CONTEXT_WINDOW_TOKENS));
|
|
873
|
+
// Provider tokenizers are not uniformly available. UTF-8 bytes / 3 is
|
|
874
|
+
// deliberately conservative for source code and works across models.
|
|
875
|
+
const estimatedPromptTokens = estimateCleanSlateFileReadTokens(JSON.stringify({ messages, tools }) ?? '');
|
|
876
|
+
this.options.toolContext.fileReadBudget = {
|
|
877
|
+
contextWindowTokens,
|
|
878
|
+
availableInputTokens: Math.max(1, contextWindowTokens - estimatedPromptTokens)
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
getNativeToolDefinitionsForTurn(nativeTools, queryState) {
|
|
882
|
+
if (!queryState.planMode) {
|
|
883
|
+
// The loop stops when an assistant turn contains no tool calls, and
|
|
884
|
+
// task-finished is emitted host-side. No model-facing completion
|
|
885
|
+
// tool is exposed, so normal mode receives every enabled tool.
|
|
886
|
+
return nativeTools;
|
|
887
|
+
}
|
|
888
|
+
return nativeTools.filter(tool => this.profile.planModeTools.has(tool.name));
|
|
889
|
+
}
|
|
890
|
+
isParallelToolCall(toolCall) {
|
|
891
|
+
return this.options.getToolCategory(toolCall.toolName) === 'discovery'
|
|
892
|
+
|| this.profile.parallelSafeTools.has(toolCall.toolName);
|
|
893
|
+
}
|
|
894
|
+
async *streamToolExecutionParts(toolCall, signal, queryState, guardState, executionFlow, toolCallLedger, activeTaskSessionService) {
|
|
895
|
+
// A tool call with unparseable or corrupted arguments is answered with
|
|
896
|
+
// the parse error, never executed. This catches both the
|
|
897
|
+
// transport-level JSON parse failure marker and serialized-call debris
|
|
898
|
+
// that leaked into locator argument values (the A/B run executed
|
|
899
|
+
// find_by_name with "to=multi_tool_use.parallel..." merged into path).
|
|
900
|
+
const malformedArgumentsError = this.getMalformedToolArgumentsError(toolCall);
|
|
901
|
+
if (malformedArgumentsError) {
|
|
902
|
+
const result = {
|
|
903
|
+
success: false,
|
|
904
|
+
code: 'malformed_tool_arguments',
|
|
905
|
+
message: malformedArgumentsError,
|
|
906
|
+
recoveryHint: 'Re-issue this as a single native tool call with valid JSON arguments. Never serialize tool syntax (to=functions.*, multi_tool_use.parallel) into text or argument values.'
|
|
907
|
+
};
|
|
908
|
+
toolCallLedger.recordResult(toolCall, result);
|
|
909
|
+
yield this.nativeToolTranscript.attachToolCallId({
|
|
910
|
+
type: 'tool_result',
|
|
911
|
+
toolName: toolCall.toolName,
|
|
912
|
+
result
|
|
913
|
+
}, toolCall.id);
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
// Plan-mode write barrier. The provider
|
|
917
|
+
// only sees the read-only tool list, but tool calls parsed from text
|
|
918
|
+
// bypass that filter — this is the hard guarantee that plan mode
|
|
919
|
+
// cannot mutate the workspace or run commands.
|
|
920
|
+
if (queryState.planMode && !this.profile.planModeTools.has(toolCall.toolName)) {
|
|
921
|
+
const result = {
|
|
922
|
+
success: false,
|
|
923
|
+
code: 'plan_mode_tool_blocked',
|
|
924
|
+
message: `Tool "${toolCall.toolName}" is not available in plan mode.`,
|
|
925
|
+
recoveryHint: 'Plan mode is read-only: research with discovery tools, ask_question for decisions you cannot make, and submit the plan with submit_artifact when it is ready. Implementation happens after the user approves the plan.'
|
|
926
|
+
};
|
|
927
|
+
toolCallLedger.recordResult(toolCall, result);
|
|
928
|
+
yield this.nativeToolTranscript.attachToolCallId({
|
|
929
|
+
type: 'tool_result',
|
|
930
|
+
toolName: toolCall.toolName,
|
|
931
|
+
result
|
|
932
|
+
}, toolCall.id);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
const decision = toolCallLedger.prepareForExecution(toolCall);
|
|
936
|
+
toolCall = decision.toolCall;
|
|
937
|
+
if (!decision.accepted) {
|
|
938
|
+
const result = decision.result ?? {
|
|
939
|
+
success: false,
|
|
940
|
+
code: 'tool_call_rejected',
|
|
941
|
+
message: `Tool call "${toolCall.toolName}" was rejected by the execution ledger.`
|
|
942
|
+
};
|
|
943
|
+
toolCallLedger.recordResult(toolCall, result);
|
|
944
|
+
const recoveryPrompt = this.editPolicy.buildFailedEditRecoveryPrompt(toolCall, result);
|
|
945
|
+
if (recoveryPrompt) {
|
|
946
|
+
this.appendPendingRecoveryPrompt(queryState, recoveryPrompt);
|
|
947
|
+
}
|
|
948
|
+
yield this.nativeToolTranscript.attachToolCallId({
|
|
949
|
+
type: 'tool_result',
|
|
950
|
+
toolName: toolCall.toolName,
|
|
951
|
+
result
|
|
952
|
+
}, toolCall.id);
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
if (toolCall.toolName === this.profile.primaryCommandTool) {
|
|
956
|
+
const commandPolicy = evaluateExecutionCommandPolicy(toolCall.input);
|
|
957
|
+
if (!commandPolicy.allowed) {
|
|
958
|
+
const result = {
|
|
959
|
+
success: false,
|
|
960
|
+
code: commandPolicy.code,
|
|
961
|
+
message: commandPolicy.message,
|
|
962
|
+
recoveryHint: commandPolicy.recoveryHint
|
|
963
|
+
};
|
|
964
|
+
toolCallLedger.recordResult(toolCall, result);
|
|
965
|
+
yield this.nativeToolTranscript.attachToolCallId({
|
|
966
|
+
type: 'tool_result',
|
|
967
|
+
toolName: toolCall.toolName,
|
|
968
|
+
result
|
|
969
|
+
}, toolCall.id);
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
if (queryState.pendingRecoveryPrompt
|
|
974
|
+
&& this.profile.structuredEditTools.has(toolCall.toolName)
|
|
975
|
+
&& this.editPolicy.countStructuredEdits(toolCall) !== 1) {
|
|
976
|
+
const result = {
|
|
977
|
+
success: false,
|
|
978
|
+
code: 'recovery_requires_single_edit',
|
|
979
|
+
message: 'A failed edit recovery is pending. Retry exactly one failed edit instead of resubmitting a batch.',
|
|
980
|
+
recoveryHint: queryState.pendingRecoveryPrompt
|
|
981
|
+
};
|
|
982
|
+
toolCallLedger.recordResult(toolCall, result);
|
|
983
|
+
yield this.nativeToolTranscript.attachToolCallId({
|
|
984
|
+
type: 'tool_result',
|
|
985
|
+
toolName: toolCall.toolName,
|
|
986
|
+
result
|
|
987
|
+
}, toolCall.id);
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
const executableToolCall = this.editPolicy.withScopedReadLintsInput(toolCall, guardState);
|
|
991
|
+
let lastToolResult;
|
|
992
|
+
for await (const part of this.executeToolWithTracking(executableToolCall.toolName, executableToolCall.input, { signal, toolCallId: executableToolCall.id })) {
|
|
993
|
+
if (part.type === 'tool_result') {
|
|
994
|
+
lastToolResult = part.result;
|
|
995
|
+
toolCallLedger.recordResult(executableToolCall, part.result);
|
|
996
|
+
this.recordToolResultForGuardrails(executableToolCall, part.result, guardState);
|
|
997
|
+
const recoveryPrompt = this.editPolicy.buildFailedEditRecoveryPrompt(executableToolCall, part.result);
|
|
998
|
+
if (recoveryPrompt) {
|
|
999
|
+
this.appendPendingRecoveryPrompt(queryState, recoveryPrompt);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
yield this.nativeToolTranscript.attachToolCallId(part, executableToolCall.id);
|
|
1003
|
+
}
|
|
1004
|
+
if (queryState.planMode && executableToolCall.toolName === this.profile.completionTool) {
|
|
1005
|
+
const conclusion = this.resolvePlanModeConclusion(executableToolCall, lastToolResult, activeTaskSessionService);
|
|
1006
|
+
if (conclusion) {
|
|
1007
|
+
yield conclusion;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Plan-mode ExitPlanMode analog: a successful submit_artifact concludes
|
|
1013
|
+
* the plan-mode run. An implementation plan pauses the task for user
|
|
1014
|
+
* approval; an explicitly requested analysis artifact finishes it.
|
|
1015
|
+
*/
|
|
1016
|
+
resolvePlanModeConclusion(toolCall, result, activeTaskSessionService) {
|
|
1017
|
+
if (result?.success === false) {
|
|
1018
|
+
return undefined;
|
|
1019
|
+
}
|
|
1020
|
+
const inputType = typeof toolCall.input?.type === 'string' ? toolCall.input.type : '';
|
|
1021
|
+
const artifactType = typeof toolCall.input?.artifactType === 'string' ? toolCall.input.artifactType : '';
|
|
1022
|
+
const inputPath = typeof toolCall.input?.path === 'string' ? toolCall.input.path : '';
|
|
1023
|
+
const resultPath = typeof result?.path === 'string' ? result.path : '';
|
|
1024
|
+
const artifactPath = inputPath || resultPath;
|
|
1025
|
+
const normalizedArtifactPath = artifactPath.toLowerCase();
|
|
1026
|
+
const hasSubmittedContent = typeof toolCall.input?.content === 'string' && toolCall.input.content.trim().length > 0;
|
|
1027
|
+
const isAnalysisArtifact = inputType === 'analysis'
|
|
1028
|
+
|| artifactType === 'analysis'
|
|
1029
|
+
|| normalizedArtifactPath.includes('analysis');
|
|
1030
|
+
const isImplementationPlanArtifact = inputType === 'implementation_plan'
|
|
1031
|
+
|| artifactType === 'implementation_plan'
|
|
1032
|
+
|| normalizedArtifactPath.includes('implementation_plan')
|
|
1033
|
+
|| (hasSubmittedContent && !isAnalysisArtifact);
|
|
1034
|
+
if (isImplementationPlanArtifact) {
|
|
1035
|
+
activeTaskSessionService.markAwaitingApproval();
|
|
1036
|
+
return {
|
|
1037
|
+
type: 'tool_result',
|
|
1038
|
+
toolName: PHASE_CONCLUSION_SIGNAL_PLAN_CREATED,
|
|
1039
|
+
result: {
|
|
1040
|
+
planCreated: true,
|
|
1041
|
+
artifactPath: artifactPath || 'implementation_plan.md',
|
|
1042
|
+
summary: typeof result?.summary === 'string' ? result.summary : 'Planning artifact submitted.'
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
if (isAnalysisArtifact) {
|
|
1047
|
+
activeTaskSessionService.setAwaitingApproval(false);
|
|
1048
|
+
const summary = typeof result?.summary === 'string' && result.summary.trim().length > 0
|
|
1049
|
+
? result.summary.trim()
|
|
1050
|
+
: 'Analysis report submitted.';
|
|
1051
|
+
return {
|
|
1052
|
+
type: 'task_complete',
|
|
1053
|
+
result: {
|
|
1054
|
+
phase: AgentPhase.PLANNING,
|
|
1055
|
+
analysisSubmitted: true,
|
|
1056
|
+
artifactPath: artifactPath || 'analysis.md',
|
|
1057
|
+
completionSummary: {
|
|
1058
|
+
status: 'completed_analysis',
|
|
1059
|
+
summary
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
return undefined;
|
|
1065
|
+
}
|
|
1066
|
+
async *streamPostMutationVerificationParts(signal, guardState) {
|
|
1067
|
+
const scopedPaths = Array.from(guardState.pendingVerificationPaths.size > 0
|
|
1068
|
+
? guardState.pendingVerificationPaths
|
|
1069
|
+
: guardState.mutatedPaths.size > 0
|
|
1070
|
+
? guardState.mutatedPaths
|
|
1071
|
+
: guardState.touchedPaths);
|
|
1072
|
+
if (scopedPaths.length === 0) {
|
|
1073
|
+
return { issues: [] };
|
|
1074
|
+
}
|
|
1075
|
+
const input = { paths: scopedPaths };
|
|
1076
|
+
let lastResult;
|
|
1077
|
+
for await (const part of this.executeToolWithTracking(this.verificationToolName, input, { signal })) {
|
|
1078
|
+
if (part.type === 'tool_result') {
|
|
1079
|
+
lastResult = part.result;
|
|
1080
|
+
this.recordToolResultForGuardrails({ toolName: this.verificationToolName, input }, part.result, guardState);
|
|
1081
|
+
}
|
|
1082
|
+
yield part;
|
|
1083
|
+
}
|
|
1084
|
+
const markerIssues = await this.options.executionSupport.collectNewMarkerIssues(guardState.markerBaseline, new Set(scopedPaths), guardState.failOnWarnings, 40);
|
|
1085
|
+
const lintIssueCount = this.countLintIssues(lastResult);
|
|
1086
|
+
if (markerIssues.length === 0 && lastResult?.success !== false) {
|
|
1087
|
+
guardState.pendingVerificationPaths.clear();
|
|
1088
|
+
}
|
|
1089
|
+
guardState.verificationSummaries.push({
|
|
1090
|
+
toolName: this.verificationToolName,
|
|
1091
|
+
paths: scopedPaths,
|
|
1092
|
+
passed: markerIssues.length === 0 && lastResult?.success !== false,
|
|
1093
|
+
lintIssueCount,
|
|
1094
|
+
markerIssueCount: markerIssues.length,
|
|
1095
|
+
message: typeof lastResult?.message === 'string' ? lastResult.message : undefined
|
|
1096
|
+
});
|
|
1097
|
+
return { result: lastResult, issues: markerIssues };
|
|
1098
|
+
}
|
|
1099
|
+
buildPostMutationVerificationPrompt(issues) {
|
|
1100
|
+
return [
|
|
1101
|
+
'POST-MUTATION VERIFICATION FAILED: the last edit changed the workspace but diagnostics are still present.',
|
|
1102
|
+
...issues.map(issue => `- ${issue}`),
|
|
1103
|
+
'Fix these issues before returning the final answer. Use read_file_range/read_lints and small targeted edits.'
|
|
1104
|
+
].join('\n');
|
|
1105
|
+
}
|
|
1106
|
+
buildVerifiedFinishPrompt(guardState) {
|
|
1107
|
+
const targetCount = guardState.mutatedPaths.size || guardState.touchedPaths.size;
|
|
1108
|
+
return [
|
|
1109
|
+
'EXECUTION VERIFICATION COMPLETE: post-mutation verification passed.',
|
|
1110
|
+
`Verified target files: ${targetCount}.`,
|
|
1111
|
+
'Do not stop merely because this one edit verified.',
|
|
1112
|
+
'If the full user request is implemented, write the visible final answer as normal assistant text and stop without a completion tool.',
|
|
1113
|
+
'If any planned work remains, continue with concrete tool_calls only.'
|
|
1114
|
+
].join('\n');
|
|
1115
|
+
}
|
|
1116
|
+
async canHostFinalizeProseStop(currentResponse, queryState, guardState) {
|
|
1117
|
+
if (queryState.pendingRecoveryPrompt) {
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
// A reasoning-only or empty provider stop is not completion. Refs emit
|
|
1121
|
+
// their task-finished lifecycle only after a non-empty assistant answer.
|
|
1122
|
+
if (this.normalizeCompletionSummary(currentResponse) === undefined) {
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
if (guardState.pendingVerificationPaths.size > 0
|
|
1126
|
+
|| guardState.postEditCommandIssues.length > 0
|
|
1127
|
+
|| this.getUnresolvedFailedGoalCommand(guardState)
|
|
1128
|
+
|| this.hasFailedUserRequestedOrVerificationCommand(guardState)) {
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
if (guardState.mutatedPaths.size > 0 && !guardState.postEditCommandVerified) {
|
|
1132
|
+
return false;
|
|
1133
|
+
}
|
|
1134
|
+
const finalVerificationScope = guardState.mutatedPaths.size > 0
|
|
1135
|
+
? guardState.mutatedPaths
|
|
1136
|
+
: guardState.touchedPaths;
|
|
1137
|
+
if (finalVerificationScope.size > 0) {
|
|
1138
|
+
const markerIssues = await this.options.executionSupport.collectNewMarkerIssues(guardState.markerBaseline, finalVerificationScope, guardState.failOnWarnings, 40);
|
|
1139
|
+
if (markerIssues.length > 0) {
|
|
1140
|
+
return false;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
return true;
|
|
1144
|
+
}
|
|
1145
|
+
hasFailedUserRequestedOrVerificationCommand(guardState) {
|
|
1146
|
+
return guardState.terminalSummaries.some(summary => summary.toolName === this.profile.primaryCommandTool
|
|
1147
|
+
&& summary.success === false
|
|
1148
|
+
&& (summary.intent === 'verification' || summary.intent === 'user_requested'));
|
|
1149
|
+
}
|
|
1150
|
+
isToolCallLoopResult(result) {
|
|
1151
|
+
return result?.code === 'tool_call_loop_detected';
|
|
1152
|
+
}
|
|
1153
|
+
buildCompletionState(guardState, finalAnswer, plannedFileTargets) {
|
|
1154
|
+
const proofSummaries = this.buildHostProofSummaries(guardState);
|
|
1155
|
+
return {
|
|
1156
|
+
touchedPaths: Array.from(guardState.touchedPaths),
|
|
1157
|
+
mutatedPaths: Array.from(guardState.mutatedPaths),
|
|
1158
|
+
mutationSummaries: guardState.mutationSummaries,
|
|
1159
|
+
terminalSummaries: guardState.terminalSummaries.slice(-4),
|
|
1160
|
+
proofSummaries,
|
|
1161
|
+
completionSource: 'host_finalized',
|
|
1162
|
+
verificationIssueCount: guardState.verificationSummaries.reduce((sum, summary) => sum + summary.markerIssueCount, 0),
|
|
1163
|
+
successfulMutationsInPhase: guardState.successfulMutationsInPhase,
|
|
1164
|
+
summary: this.normalizeCompletionSummary(finalAnswer),
|
|
1165
|
+
...(plannedFileTargets?.length ? {
|
|
1166
|
+
plannedFileTargets: [...plannedFileTargets],
|
|
1167
|
+
unmutatedPlannedFiles: this.getUnmutatedPlannedFiles(plannedFileTargets, guardState.mutatedPaths)
|
|
1168
|
+
} : {})
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* File targets named by the approved implementation plan handed off to this
|
|
1173
|
+
* run. Used as audit evidence so plan-to-execution fidelity is judged (and
|
|
1174
|
+
* deviations must be disclosed) instead of silently forgotten.
|
|
1175
|
+
*/
|
|
1176
|
+
extractPlannedFileTargets(messages) {
|
|
1177
|
+
for (const message of messages) {
|
|
1178
|
+
const text = typeof message.content === 'string' ? message.content : '';
|
|
1179
|
+
if (!text.includes('[APPROVED IMPLEMENTATION PLAN]')) {
|
|
1180
|
+
continue;
|
|
1181
|
+
}
|
|
1182
|
+
const targets = extractPlanFileEntries(text)
|
|
1183
|
+
.filter(entry => typeof entry.target === 'string' && entry.target.length > 0)
|
|
1184
|
+
.map(entry => planEntryTargetToPath(entry.target).replace(/\\/g, '/'));
|
|
1185
|
+
return Array.from(new Set(targets)).slice(0, 24);
|
|
1186
|
+
}
|
|
1187
|
+
return [];
|
|
1188
|
+
}
|
|
1189
|
+
getUnmutatedPlannedFiles(plannedFileTargets, mutatedPaths) {
|
|
1190
|
+
const mutatedBasenames = new Set(Array.from(mutatedPaths).map(path => path.replace(/\\/g, '/').toLowerCase().split('/').pop() ?? ''));
|
|
1191
|
+
return plannedFileTargets.filter(target => {
|
|
1192
|
+
const basename = target.toLowerCase().split('/').pop() ?? target.toLowerCase();
|
|
1193
|
+
return !mutatedBasenames.has(basename);
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
buildHostProofSummaries(guardState) {
|
|
1197
|
+
const proofSummaries = [];
|
|
1198
|
+
for (const summary of guardState.verificationSummaries.slice(-4)) {
|
|
1199
|
+
const status = summary.passed ? 'passed' : 'failed';
|
|
1200
|
+
const paths = summary.paths.length > 0 ? ` for ${summary.paths.join(', ')}` : '';
|
|
1201
|
+
proofSummaries.push(`${summary.toolName} ${status}${paths}`);
|
|
1202
|
+
}
|
|
1203
|
+
for (const summary of guardState.terminalSummaries.slice(-4)) {
|
|
1204
|
+
if (summary.success !== true) {
|
|
1205
|
+
continue;
|
|
1206
|
+
}
|
|
1207
|
+
const command = summary.command ? `"${summary.command}"` : (this.profile.primaryCommandTool ?? 'the command');
|
|
1208
|
+
const intent = summary.intent ? ` (${summary.intent})` : '';
|
|
1209
|
+
proofSummaries.push(`${command} succeeded${intent}`);
|
|
1210
|
+
}
|
|
1211
|
+
return Array.from(new Set(proofSummaries));
|
|
1212
|
+
}
|
|
1213
|
+
normalizeCompletionSummary(summary) {
|
|
1214
|
+
if (typeof summary !== 'string') {
|
|
1215
|
+
return undefined;
|
|
1216
|
+
}
|
|
1217
|
+
const trimmed = summary.trim();
|
|
1218
|
+
if (!trimmed) {
|
|
1219
|
+
return undefined;
|
|
1220
|
+
}
|
|
1221
|
+
return trimmed.length > 4000 ? trimmed.slice(0, 4000) : trimmed;
|
|
1222
|
+
}
|
|
1223
|
+
getToolCallKey(toolCall) {
|
|
1224
|
+
return this.nativeToolTranscript.getToolCallKey(toolCall);
|
|
1225
|
+
}
|
|
1226
|
+
shouldVerifyAfterToolResult(toolCall, result) {
|
|
1227
|
+
return this.options.executionSupport.isConfirmedMutationResult(toolCall.toolName, toolCall.input, result)
|
|
1228
|
+
|| this.editPolicy.isSettledEditNoOp(toolCall, result);
|
|
1229
|
+
}
|
|
1230
|
+
buildMutationSummary(toolCall, result, mutationPaths, turnIndex) {
|
|
1231
|
+
return {
|
|
1232
|
+
toolName: toolCall.toolName,
|
|
1233
|
+
turnIndex,
|
|
1234
|
+
paths: mutationPaths.length > 0 ? mutationPaths : this.editPolicy.collectMutationPaths(toolCall, result),
|
|
1235
|
+
fileChanges: this.filesModifiedService.buildMutationFileChanges(toolCall.toolName, toolCall.input, result),
|
|
1236
|
+
appliedBlocks: this.firstNumericValue(result?.appliedBlocks, result?.totalAppliedBlocks, this.sumResultField(result, 'appliedBlocks')),
|
|
1237
|
+
added: this.firstNumericValue(result?.added, this.sumResultField(result, 'added')),
|
|
1238
|
+
deleted: this.firstNumericValue(result?.deleted, this.sumResultField(result, 'deleted')),
|
|
1239
|
+
totalLinesChanged: this.firstNumericValue(result?.totalLinesChanged, this.sumResultField(result, 'totalLinesChanged')),
|
|
1240
|
+
diagnosticsCount: this.countEditDiagnostics(result),
|
|
1241
|
+
strategies: this.collectStrategies(result),
|
|
1242
|
+
message: typeof result?.message === 'string' ? result.message : undefined
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
firstNumericValue(...values) {
|
|
1246
|
+
for (const value of values) {
|
|
1247
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1248
|
+
return value;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return undefined;
|
|
1252
|
+
}
|
|
1253
|
+
sumResultField(result, field) {
|
|
1254
|
+
if (!Array.isArray(result?.results)) {
|
|
1255
|
+
return undefined;
|
|
1256
|
+
}
|
|
1257
|
+
let sum = 0;
|
|
1258
|
+
let found = false;
|
|
1259
|
+
for (const entry of result.results) {
|
|
1260
|
+
const value = entry?.[field];
|
|
1261
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1262
|
+
sum += value;
|
|
1263
|
+
found = true;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return found ? sum : undefined;
|
|
1267
|
+
}
|
|
1268
|
+
countEditDiagnostics(result) {
|
|
1269
|
+
let count = 0;
|
|
1270
|
+
const countArray = (candidate) => {
|
|
1271
|
+
if (Array.isArray(candidate)) {
|
|
1272
|
+
count += candidate.length;
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
countArray(result?.diagnostics);
|
|
1276
|
+
countArray(result?.preflightDiagnostics);
|
|
1277
|
+
countArray(result?.postApplyDiagnostics);
|
|
1278
|
+
if (Array.isArray(result?.validationDiagnostics)) {
|
|
1279
|
+
for (const entry of result.validationDiagnostics) {
|
|
1280
|
+
countArray(entry?.diagnostics);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
if (Array.isArray(result?.results)) {
|
|
1284
|
+
for (const entry of result.results) {
|
|
1285
|
+
countArray(entry?.diagnostics);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return count;
|
|
1289
|
+
}
|
|
1290
|
+
countLintIssues(result) {
|
|
1291
|
+
if (Array.isArray(result?.errors)) {
|
|
1292
|
+
return result.errors.length;
|
|
1293
|
+
}
|
|
1294
|
+
if (Array.isArray(result?.diagnostics)) {
|
|
1295
|
+
return result.diagnostics.length;
|
|
1296
|
+
}
|
|
1297
|
+
return 0;
|
|
1298
|
+
}
|
|
1299
|
+
collectStrategies(result) {
|
|
1300
|
+
const strategies = [];
|
|
1301
|
+
const addStrategy = (candidate) => {
|
|
1302
|
+
if (typeof candidate !== 'string') {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
const strategy = candidate.trim();
|
|
1306
|
+
if (strategy.length === 0 || strategies.includes(strategy)) {
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
strategies.push(strategy);
|
|
1310
|
+
};
|
|
1311
|
+
for (const strategy of Array.isArray(result?.strategies) ? result.strategies : []) {
|
|
1312
|
+
addStrategy(strategy);
|
|
1313
|
+
}
|
|
1314
|
+
for (const entry of Array.isArray(result?.results) ? result.results : []) {
|
|
1315
|
+
for (const strategy of Array.isArray(entry?.strategies) ? entry.strategies : []) {
|
|
1316
|
+
addStrategy(strategy);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
return strategies.length > 0 ? strategies : undefined;
|
|
1320
|
+
}
|
|
1321
|
+
appendPendingRecoveryPrompt(queryState, recoveryPrompt) {
|
|
1322
|
+
if (!queryState.pendingRecoveryPrompt) {
|
|
1323
|
+
queryState.pendingRecoveryPrompt = recoveryPrompt;
|
|
1324
|
+
queryState.recoveryNoToolTurns = 0;
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
if (!queryState.pendingRecoveryPrompt.includes(recoveryPrompt)) {
|
|
1328
|
+
queryState.pendingRecoveryPrompt = `${queryState.pendingRecoveryPrompt}\n\n${recoveryPrompt}`;
|
|
1329
|
+
}
|
|
1330
|
+
queryState.recoveryNoToolTurns = 0;
|
|
1331
|
+
}
|
|
1332
|
+
recordToolResultForGuardrails(toolCall, result, guardState) {
|
|
1333
|
+
this.options.executionSupport.trackTouchedPaths(toolCall.toolName, toolCall.input, result, guardState.touchedPaths);
|
|
1334
|
+
this.recordTerminalSummary(toolCall, result, guardState);
|
|
1335
|
+
const didSucceed = this.options.executionSupport.didToolSucceed(result);
|
|
1336
|
+
if (didSucceed) {
|
|
1337
|
+
guardState.successfulToolResultsInPhase++;
|
|
1338
|
+
}
|
|
1339
|
+
if (didSucceed) {
|
|
1340
|
+
this.executionPhase.updateExecutionEvidenceLedgerFromToolResult(guardState.executionEvidenceLedger, toolCall.toolName, toolCall.input, result);
|
|
1341
|
+
}
|
|
1342
|
+
const isConfirmedMutation = this.options.executionSupport.isConfirmedMutationResult(toolCall.toolName, toolCall.input, result);
|
|
1343
|
+
const isSettledNoOp = this.editPolicy.isSettledEditNoOp(toolCall, result);
|
|
1344
|
+
if (isConfirmedMutation || isSettledNoOp) {
|
|
1345
|
+
const mutationPaths = this.editPolicy.collectMutationPaths(toolCall, result);
|
|
1346
|
+
if (isConfirmedMutation) {
|
|
1347
|
+
guardState.successfulMutationsInPhase++;
|
|
1348
|
+
}
|
|
1349
|
+
guardState.postEditCommandVerified = false;
|
|
1350
|
+
guardState.postEditCommandIssues = [];
|
|
1351
|
+
guardState.mutationSummaries.push(this.buildMutationSummary(toolCall, result, mutationPaths, guardState.currentTurnIndex));
|
|
1352
|
+
this.executionPhase.registerPostMutationEvidence(guardState.executionEvidenceLedger, toolCall.toolName, toolCall.input);
|
|
1353
|
+
if (isConfirmedMutation) {
|
|
1354
|
+
for (const path of mutationPaths) {
|
|
1355
|
+
guardState.mutatedPaths.add(path);
|
|
1356
|
+
guardState.pendingVerificationPaths.add(path);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
recordTerminalSummary(toolCall, result, guardState) {
|
|
1362
|
+
if (!this.profile.commandTools.has(toolCall.toolName)) {
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
const command = typeof toolCall.input?.command === 'string'
|
|
1366
|
+
? toolCall.input.command
|
|
1367
|
+
: undefined;
|
|
1368
|
+
const toolName = toolCall.toolName;
|
|
1369
|
+
const intent = typeof toolCall.input?.intent === 'string' ? toolCall.input.intent : undefined;
|
|
1370
|
+
const writesToWorkspace = typeof toolCall.input?.writesToWorkspace === 'boolean' ? toolCall.input.writesToWorkspace : undefined;
|
|
1371
|
+
const success = typeof result?.success === 'boolean'
|
|
1372
|
+
? result.success
|
|
1373
|
+
: typeof result?.exitCode === 'number'
|
|
1374
|
+
? result.exitCode === 0
|
|
1375
|
+
: undefined;
|
|
1376
|
+
const sessionId = typeof result?.processId === 'string' ? result.processId : undefined;
|
|
1377
|
+
const status = typeof result?.status === 'string' ? result.status : undefined;
|
|
1378
|
+
const exitCode = typeof result?.exitCode === 'number' ? result.exitCode : undefined;
|
|
1379
|
+
const output = typeof result?.output === 'string' ? result.output : undefined;
|
|
1380
|
+
const error = typeof result?.error === 'string' ? result.error : undefined;
|
|
1381
|
+
const existing = sessionId
|
|
1382
|
+
? guardState.terminalSummaries.find(summary => summary.sessionId === sessionId)
|
|
1383
|
+
: undefined;
|
|
1384
|
+
const update = {
|
|
1385
|
+
toolName: toolName ?? existing?.toolName,
|
|
1386
|
+
turnIndex: guardState.currentTurnIndex,
|
|
1387
|
+
command: command ?? existing?.command,
|
|
1388
|
+
sessionId: sessionId ?? existing?.sessionId,
|
|
1389
|
+
intent: intent ?? existing?.intent,
|
|
1390
|
+
writesToWorkspace: writesToWorkspace ?? existing?.writesToWorkspace,
|
|
1391
|
+
success: success ?? existing?.success,
|
|
1392
|
+
status: status ?? existing?.status,
|
|
1393
|
+
exitCode: exitCode ?? existing?.exitCode,
|
|
1394
|
+
output: output ?? existing?.output,
|
|
1395
|
+
error: error ?? existing?.error
|
|
1396
|
+
};
|
|
1397
|
+
if (existing) {
|
|
1398
|
+
Object.assign(existing, update);
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
guardState.terminalSummaries.push(update);
|
|
1402
|
+
}
|
|
1403
|
+
getUnresolvedFailedGoalCommand(guardState) {
|
|
1404
|
+
const failedCommand = [...guardState.terminalSummaries].reverse().find(summary => summary.toolName === this.profile.primaryCommandTool
|
|
1405
|
+
&& summary.success === false
|
|
1406
|
+
&& this.isFailedGoalCommand(summary));
|
|
1407
|
+
if (!failedCommand) {
|
|
1408
|
+
return undefined;
|
|
1409
|
+
}
|
|
1410
|
+
return this.hasSuccessfulRecoveryAfterCommandFailure(guardState, failedCommand) ? undefined : failedCommand;
|
|
1411
|
+
}
|
|
1412
|
+
isFailedGoalCommand(summary) {
|
|
1413
|
+
return summary.intent === 'implementation' || summary.writesToWorkspace === true;
|
|
1414
|
+
}
|
|
1415
|
+
hasSuccessfulRecoveryAfterCommandFailure(guardState, failedCommand) {
|
|
1416
|
+
const failedTurnIndex = failedCommand.turnIndex ?? -1;
|
|
1417
|
+
const hasLaterSuccessfulCommand = guardState.terminalSummaries.some(summary => summary !== failedCommand
|
|
1418
|
+
&& summary.success === true
|
|
1419
|
+
&& (summary.turnIndex ?? -1) > failedTurnIndex
|
|
1420
|
+
&& (summary.intent === failedCommand.intent
|
|
1421
|
+
|| summary.intent === 'implementation'
|
|
1422
|
+
|| (failedCommand.writesToWorkspace === true && summary.writesToWorkspace === true)));
|
|
1423
|
+
if (hasLaterSuccessfulCommand) {
|
|
1424
|
+
return true;
|
|
1425
|
+
}
|
|
1426
|
+
return guardState.mutationSummaries.some(summary => typeof summary.turnIndex === 'number'
|
|
1427
|
+
&& summary.turnIndex > failedTurnIndex);
|
|
1428
|
+
}
|
|
1429
|
+
buildNoToolRecoveryPrompt(hasTechnicalProgress) {
|
|
1430
|
+
return buildExecutionNoToolRecoveryPrompt(hasTechnicalProgress);
|
|
1431
|
+
}
|
|
1432
|
+
buildNoProgressStopMessage(attempts, reason) {
|
|
1433
|
+
return buildExecutionNoProgressStopMessage(attempts, reason);
|
|
1434
|
+
}
|
|
1435
|
+
delay(milliseconds, signal) {
|
|
1436
|
+
if (milliseconds <= 0 || signal?.aborted) {
|
|
1437
|
+
return Promise.resolve();
|
|
1438
|
+
}
|
|
1439
|
+
return new Promise(resolve => {
|
|
1440
|
+
const timeout = setTimeout(resolve, milliseconds);
|
|
1441
|
+
signal?.addEventListener('abort', () => {
|
|
1442
|
+
clearTimeout(timeout);
|
|
1443
|
+
resolve();
|
|
1444
|
+
}, { once: true });
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
//# sourceMappingURL=cleanSlateExecutionQuery.js.map
|