Bläddra i källkod

Revert "chore: remove unused stripAppendedEnvironmentDetails and helpers" (#11255)

Revert "chore: remove unused stripAppendedEnvironmentDetails and helpers (#11…"

This reverts commit 2d5e633781614e611d79f92732c795e5bde79c18.
Matt Rubens 1 vecka sedan
förälder
incheckning
5fd156de7b

+ 99 - 1
src/core/task/__tests__/appendEnvironmentDetails.spec.ts

@@ -1,5 +1,10 @@
 import { Anthropic } from "@anthropic-ai/sdk"
-import { appendEnvironmentDetails, removeEnvironmentDetailsBlocks, UserContentBlock } from "../appendEnvironmentDetails"
+import {
+	appendEnvironmentDetails,
+	removeEnvironmentDetailsBlocks,
+	stripAppendedEnvironmentDetails,
+	UserContentBlock,
+} from "../appendEnvironmentDetails"
 
 describe("appendEnvironmentDetails", () => {
 	const envDetails = "<environment_details>\n# Test\nSome details\n</environment_details>"
@@ -314,3 +319,96 @@ describe("removeEnvironmentDetailsBlocks", () => {
 		expect(result).toHaveLength(0)
 	})
 })
+
+describe("stripAppendedEnvironmentDetails", () => {
+	const envDetails = "<environment_details>\n# Test\nSome details\n</environment_details>"
+
+	it("should strip environment details from the end of a text block", () => {
+		const content: UserContentBlock[] = [{ type: "text", text: "User message\n\n" + envDetails }]
+
+		const result = stripAppendedEnvironmentDetails(content)
+
+		expect(result).toHaveLength(1)
+		expect((result[0] as Anthropic.Messages.TextBlockParam).text).toBe("User message")
+	})
+
+	it("should strip environment details from tool_result string content", () => {
+		const content: UserContentBlock[] = [
+			{
+				type: "tool_result",
+				tool_use_id: "tool-123",
+				content: "Tool result\n\n" + envDetails,
+			},
+		]
+
+		const result = stripAppendedEnvironmentDetails(content)
+
+		expect(result).toHaveLength(1)
+		expect((result[0] as Anthropic.Messages.ToolResultBlockParam).content).toBe("Tool result")
+	})
+
+	it("should strip environment details from tool_result array content", () => {
+		const content: UserContentBlock[] = [
+			{
+				type: "tool_result",
+				tool_use_id: "tool-123",
+				content: [{ type: "text", text: "Result text\n\n" + envDetails }],
+			},
+		]
+
+		const result = stripAppendedEnvironmentDetails(content)
+
+		const toolResult = result[0] as Anthropic.Messages.ToolResultBlockParam
+		const contentArray = toolResult.content as Anthropic.Messages.TextBlockParam[]
+		expect(contentArray[0].text).toBe("Result text")
+	})
+
+	it("should also remove standalone environment_details blocks", () => {
+		const content: UserContentBlock[] = [
+			{ type: "text", text: "User message" },
+			{ type: "text", text: envDetails },
+		]
+
+		const result = stripAppendedEnvironmentDetails(content)
+
+		expect(result).toHaveLength(1)
+		expect((result[0] as Anthropic.Messages.TextBlockParam).text).toBe("User message")
+	})
+
+	it("should handle content without environment details", () => {
+		const content: UserContentBlock[] = [
+			{ type: "text", text: "User message" },
+			{
+				type: "tool_result",
+				tool_use_id: "tool-123",
+				content: "Tool result",
+			},
+		]
+
+		const result = stripAppendedEnvironmentDetails(content)
+
+		expect(result).toEqual(content)
+	})
+
+	it("should handle empty content", () => {
+		const result = stripAppendedEnvironmentDetails([])
+		expect(result).toHaveLength(0)
+	})
+
+	it("should preserve is_error flag when stripping from tool_result", () => {
+		const content: UserContentBlock[] = [
+			{
+				type: "tool_result",
+				tool_use_id: "tool-123",
+				content: "Error\n\n" + envDetails,
+				is_error: true,
+			},
+		]
+
+		const result = stripAppendedEnvironmentDetails(content)
+
+		const toolResult = result[0] as Anthropic.Messages.ToolResultBlockParam
+		expect(toolResult.is_error).toBe(true)
+		expect(toolResult.content).toBe("Error")
+	})
+})

+ 93 - 0
src/core/task/appendEnvironmentDetails.ts

@@ -143,3 +143,96 @@ export function removeEnvironmentDetailsBlocks(content: UserContentBlock[]): Use
 		return true
 	})
 }
+
+/**
+ * Strips environment details from the last text block or tool_result in the content.
+ * This handles the case where environment details were appended to an existing block
+ * rather than added as a standalone block.
+ *
+ * @param content - Array of content blocks
+ * @returns New array with environment details stripped from the last suitable block
+ */
+export function stripAppendedEnvironmentDetails(content: UserContentBlock[]): UserContentBlock[] {
+	if (content.length === 0) {
+		return content
+	}
+
+	// First, remove any standalone environment_details blocks
+	let result = removeEnvironmentDetailsBlocks(content)
+
+	if (result.length === 0) {
+		return result
+	}
+
+	// Then, strip appended environment details from the last block
+	const lastIndex = result.length - 1
+	const lastBlock = result[lastIndex]
+
+	if (lastBlock.type === "text") {
+		const strippedText = stripEnvDetailsFromText(lastBlock.text)
+		if (strippedText !== lastBlock.text) {
+			result = [...result]
+			result[lastIndex] = { type: "text" as const, text: strippedText }
+		}
+	} else if (lastBlock.type === "tool_result") {
+		const strippedToolResult = stripEnvDetailsFromToolResult(lastBlock)
+		if (strippedToolResult !== lastBlock) {
+			result = [...result]
+			result[lastIndex] = strippedToolResult
+		}
+	}
+
+	return result
+}
+
+/**
+ * Strips environment details from the end of a text string.
+ */
+function stripEnvDetailsFromText(text: string): string {
+	// Match environment details at the end of the string, with optional preceding newlines
+	const envDetailsPattern = /\n*<environment_details>[\s\S]*<\/environment_details>\s*$/
+	return text.replace(envDetailsPattern, "")
+}
+
+/**
+ * Strips environment details from a tool_result block's content.
+ */
+function stripEnvDetailsFromToolResult(
+	toolResult: Anthropic.Messages.ToolResultBlockParam,
+): Anthropic.Messages.ToolResultBlockParam {
+	const { content, ...rest } = toolResult
+
+	if (content === undefined || content === null) {
+		return toolResult
+	}
+
+	if (typeof content === "string") {
+		const strippedContent = stripEnvDetailsFromText(content)
+		if (strippedContent === content) {
+			return toolResult
+		}
+		return { ...rest, content: strippedContent }
+	}
+
+	if (Array.isArray(content)) {
+		let changed = false
+		const newContent = content.map((block) => {
+			if (block.type === "text") {
+				const strippedText = stripEnvDetailsFromText(block.text)
+				if (strippedText !== block.text) {
+					changed = true
+					return { type: "text" as const, text: strippedText }
+				}
+			}
+			return block
+		})
+
+		if (!changed) {
+			return toolResult
+		}
+
+		return { ...rest, content: newContent }
+	}
+
+	return toolResult
+}