@@ -133,7 +133,6 @@ import { AutoApprovalHandler, checkAutoApproval } from "../auto-approval"
133133import { MessageManager } from "../message-manager"
134134import { validateAndFixToolResultIds } from "./validateToolResultIds"
135135import { mergeConsecutiveApiMessages } from "./mergeConsecutiveApiMessages"
136- import { appendEnvironmentDetails , removeEnvironmentDetailsBlocks } from "./appendEnvironmentDetails"
137136
138137const MAX_EXPONENTIAL_BACKOFF_SECONDS = 600 // 10 minutes
139138const DEFAULT_USAGE_COLLECTION_TIMEOUT_MS = 5000 // 5 seconds
@@ -2569,18 +2568,20 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
25692568 if ( lastUserMsgIndex >= 0 ) {
25702569 const lastUserMsg = this . apiConversationHistory [ lastUserMsgIndex ]
25712570 if ( Array . isArray ( lastUserMsg . content ) ) {
2572- // Remove any existing environment_details blocks before adding fresh ones,
2573- // then append env details to the last text or tool_result block.
2574- // This avoids creating standalone trailing text blocks which can break
2575- // interleaved-thinking models like DeepSeek reasoner.
2576- const contentWithoutEnvDetails = removeEnvironmentDetailsBlocks (
2577- lastUserMsg . content as (
2578- | Anthropic . Messages . TextBlockParam
2579- | Anthropic . Messages . ImageBlockParam
2580- | Anthropic . Messages . ToolResultBlockParam
2581- ) [ ] ,
2571+ // Remove any existing environment_details blocks before adding fresh ones
2572+ const contentWithoutEnvDetails = lastUserMsg . content . filter (
2573+ ( block : Anthropic . Messages . ContentBlockParam ) => {
2574+ if ( block . type === "text" && typeof block . text === "string" ) {
2575+ const isEnvironmentDetailsBlock =
2576+ block . text . trim ( ) . startsWith ( "<environment_details>" ) &&
2577+ block . text . trim ( ) . endsWith ( "</environment_details>" )
2578+ return ! isEnvironmentDetailsBlock
2579+ }
2580+ return true
2581+ } ,
25822582 )
2583- lastUserMsg . content = appendEnvironmentDetails ( contentWithoutEnvDetails , environmentDetails )
2583+ // Add fresh environment details
2584+ lastUserMsg . content = [ ...contentWithoutEnvDetails , { type : "text" as const , text : environmentDetails } ]
25842585 }
25852586 }
25862587
@@ -2747,12 +2748,23 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
27472748 // Remove any existing environment_details blocks before adding fresh ones.
27482749 // This prevents duplicate environment details when resuming tasks,
27492750 // where the old user message content may already contain environment details from the previous session.
2750- const contentWithoutEnvDetails = removeEnvironmentDetailsBlocks ( parsedUserContent )
2751+ // We check for both opening and closing tags to ensure we're matching complete environment detail blocks,
2752+ // not just mentions of the tag in regular content.
2753+ const contentWithoutEnvDetails = parsedUserContent . filter ( ( block ) => {
2754+ if ( block . type === "text" && typeof block . text === "string" ) {
2755+ // Check if this text block is a complete environment_details block
2756+ // by verifying it starts with the opening tag and ends with the closing tag
2757+ const isEnvironmentDetailsBlock =
2758+ block . text . trim ( ) . startsWith ( "<environment_details>" ) &&
2759+ block . text . trim ( ) . endsWith ( "</environment_details>" )
2760+ return ! isEnvironmentDetailsBlock
2761+ }
2762+ return true
2763+ } )
27512764
2752- // Append environment details to the last text or tool_result block.
2753- // This avoids creating standalone trailing text blocks which can break
2754- // interleaved-thinking models like DeepSeek reasoner that expect specific message shapes.
2755- let finalUserContent = appendEnvironmentDetails ( contentWithoutEnvDetails , environmentDetails )
2765+ // Add environment details as its own text block, separate from tool
2766+ // results.
2767+ let finalUserContent = [ ...contentWithoutEnvDetails , { type : "text" as const , text : environmentDetails } ]
27562768 // Only add user message to conversation history if:
27572769 // 1. This is the first attempt (retryAttempt === 0), AND
27582770 // 2. The original userContent was not empty (empty signals delegation resume where
0 commit comments