From 0851769450856be91b18b94347cd916e3f6813f9 Mon Sep 17 00:00:00 2001 From: Daniel <57051444+daniel-lxs@users.noreply.github.com> Date: Thu, 20 Nov 2025 07:21:48 -0500 Subject: [PATCH 1/8] Improve read_file tool description with examples (#9422) * Improve read_file tool description with examples - Add explicit JSON structure documentation - Include three concrete examples (single file, with line ranges, multiple files) - Clarify that 'path' is required and 'line_ranges' is optional - Better explain line range format (1-based inclusive) This addresses agent confusion by providing clear examples similar to the XML tool definition. * Make read_file tool dynamic based on partialReadsEnabled setting - Convert read_file from static export to createReadFileTool() factory function - Add getNativeTools() function that accepts partialReadsEnabled parameter - Create buildNativeToolsArray() helper to encapsulate tool building logic - Update Task.ts to build native tools dynamically using maxReadFileLine setting - When partialReadsEnabled is false, line_ranges parameter is excluded from schema - Examples and descriptions adjust based on whether line ranges are supported This matches the behavior of the XML tool definition which dynamically adjusts its documentation based on settings, reducing confusion for agents. --- src/core/prompts/tools/native-tools/index.ts | 53 ++++---- .../prompts/tools/native-tools/read_file.ts | 117 ++++++++++++------ src/core/task/Task.ts | 39 ++---- src/core/task/build-tools.ts | 62 ++++++++++ 4 files changed, 183 insertions(+), 88 deletions(-) create mode 100644 src/core/task/build-tools.ts diff --git a/src/core/prompts/tools/native-tools/index.ts b/src/core/prompts/tools/native-tools/index.ts index c12a681704..941fd3fddb 100644 --- a/src/core/prompts/tools/native-tools/index.ts +++ b/src/core/prompts/tools/native-tools/index.ts @@ -10,7 +10,7 @@ import insertContent from "./insert_content" import listCodeDefinitionNames from "./list_code_definition_names" import listFiles from "./list_files" import newTask from "./new_task" -import { read_file } from "./read_file" +import { createReadFileTool } from "./read_file" import runSlashCommand from "./run_slash_command" import searchFiles from "./search_files" import switchMode from "./switch_mode" @@ -21,23 +21,34 @@ import { apply_diff_single_file } from "./apply_diff" export { getMcpServerTools } from "./mcp_server" export { convertOpenAIToolToAnthropic, convertOpenAIToolsToAnthropic } from "./converters" -export const nativeTools = [ - apply_diff_single_file, - askFollowupQuestion, - attemptCompletion, - browserAction, - codebaseSearch, - executeCommand, - fetchInstructions, - generateImage, - insertContent, - listCodeDefinitionNames, - listFiles, - newTask, - read_file, - runSlashCommand, - searchFiles, - switchMode, - updateTodoList, - writeToFile, -] satisfies OpenAI.Chat.ChatCompletionTool[] +/** + * Get native tools array, optionally customizing based on settings. + * + * @param partialReadsEnabled - Whether to include line_ranges support in read_file tool (default: true) + * @returns Array of native tool definitions + */ +export function getNativeTools(partialReadsEnabled: boolean = true): OpenAI.Chat.ChatCompletionTool[] { + return [ + apply_diff_single_file, + askFollowupQuestion, + attemptCompletion, + browserAction, + codebaseSearch, + executeCommand, + fetchInstructions, + generateImage, + insertContent, + listCodeDefinitionNames, + listFiles, + newTask, + createReadFileTool(partialReadsEnabled), + runSlashCommand, + searchFiles, + switchMode, + updateTodoList, + writeToFile, + ] satisfies OpenAI.Chat.ChatCompletionTool[] +} + +// Backward compatibility: export default tools with line ranges enabled +export const nativeTools = getNativeTools(true) diff --git a/src/core/prompts/tools/native-tools/read_file.ts b/src/core/prompts/tools/native-tools/read_file.ts index 6118f58587..81bee82d5e 100644 --- a/src/core/prompts/tools/native-tools/read_file.ts +++ b/src/core/prompts/tools/native-tools/read_file.ts @@ -1,43 +1,80 @@ import type OpenAI from "openai" -export const read_file = { - type: "function", - function: { - name: "read_file", - description: - "Read one or more files and return their contents with line numbers for diffing or discussion. Use line ranges when available to keep reads efficient and combine related files when possible.", - strict: true, - parameters: { - type: "object", - properties: { - files: { - type: "array", - description: "List of files to read; request related files together when allowed", - items: { - type: "object", - properties: { - path: { - type: "string", - description: "Path to the file to read, relative to the workspace", - }, - line_ranges: { - type: ["array", "null"], - description: - "Optional 1-based inclusive ranges to read (format: start-end). Use multiple ranges for non-contiguous sections and keep ranges tight to the needed context.", - items: { - type: "string", - pattern: "^[0-9]+-[0-9]+$", - }, - }, - }, - required: ["path"], - additionalProperties: false, - }, - minItems: 1, - }, - }, - required: ["files"], - additionalProperties: false, +/** + * Creates the read_file tool definition, optionally including line_ranges support + * based on whether partial reads are enabled. + * + * @param partialReadsEnabled - Whether to include line_ranges parameter + * @returns Native tool definition for read_file + */ +export function createReadFileTool(partialReadsEnabled: boolean = true): OpenAI.Chat.ChatCompletionTool { + const baseDescription = + "Read one or more files and return their contents with line numbers for diffing or discussion. " + + "Structure: { files: [{ path: 'relative/path.ts'" + + (partialReadsEnabled ? ", line_ranges: ['1-50', '100-150']" : "") + + " }] }. " + + "The 'path' is required and relative to workspace. " + + const optionalRangesDescription = partialReadsEnabled + ? "The 'line_ranges' is optional for reading specific sections (format: 'start-end', 1-based inclusive). " + : "" + + const examples = partialReadsEnabled + ? "Example single file: { files: [{ path: 'src/app.ts' }] }. " + + "Example with line ranges: { files: [{ path: 'src/app.ts', line_ranges: ['1-50', '100-150'] }] }. " + + "Example multiple files: { files: [{ path: 'file1.ts', line_ranges: ['1-50'] }, { path: 'file2.ts' }] }" + : "Example single file: { files: [{ path: 'src/app.ts' }] }. " + + "Example multiple files: { files: [{ path: 'file1.ts' }, { path: 'file2.ts' }] }" + + const description = baseDescription + optionalRangesDescription + examples + + // Build the properties object conditionally + const fileProperties: Record = { + path: { + type: "string", + description: "Path to the file to read, relative to the workspace", }, - }, -} satisfies OpenAI.Chat.ChatCompletionTool + } + + // Only include line_ranges if partial reads are enabled + if (partialReadsEnabled) { + fileProperties.line_ranges = { + type: ["array", "null"], + description: + "Optional 1-based inclusive ranges to read (format: start-end). Use multiple ranges for non-contiguous sections and keep ranges tight to the needed context.", + items: { + type: "string", + pattern: "^[0-9]+-[0-9]+$", + }, + } + } + + return { + type: "function", + function: { + name: "read_file", + description, + strict: true, + parameters: { + type: "object", + properties: { + files: { + type: "array", + description: "List of files to read; request related files together when allowed", + items: { + type: "object", + properties: fileProperties, + required: ["path"], + additionalProperties: false, + }, + minItems: 1, + }, + }, + required: ["files"], + additionalProperties: false, + }, + }, + } satisfies OpenAI.Chat.ChatCompletionTool +} + +export const read_file = createReadFileTool(false) diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index c7fb7bea79..7c0355e498 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -87,8 +87,7 @@ import { getWorkspacePath } from "../../utils/path" // prompts import { formatResponse } from "../prompts/responses" import { SYSTEM_PROMPT } from "../prompts/system" -import { nativeTools, getMcpServerTools } from "../prompts/tools/native-tools" -import { filterNativeToolsForMode, filterMcpToolsForMode } from "../prompts/tools/filter-tools-for-mode" +import { buildNativeToolsArray } from "./build-tools" // core modules import { ToolRepetitionDetector } from "../tools/ToolRepetitionDetector" @@ -3132,34 +3131,20 @@ export class Task extends EventEmitter implements TaskLike { let allTools: OpenAI.Chat.ChatCompletionTool[] = [] if (shouldIncludeTools) { const provider = this.providerRef.deref() - const mcpHub = provider?.getMcpHub() - - // Get CodeIndexManager for feature checking - const { CodeIndexManager } = await import("../../services/code-index/manager") - const codeIndexManager = CodeIndexManager.getInstance(provider!.context, this.cwd) - - // Build settings object for tool filtering - // Include browserToolEnabled to filter browser_action when disabled by user - const filterSettings = { - todoListEnabled: apiConfiguration?.todoListEnabled ?? true, - browserToolEnabled: state?.browserToolEnabled ?? true, + if (!provider) { + throw new Error("Provider reference lost during tool building") } - // Filter native tools based on mode restrictions (similar to XML tool filtering) - const filteredNativeTools = filterNativeToolsForMode( - nativeTools, + allTools = await buildNativeToolsArray({ + provider, + cwd: this.cwd, mode, - state?.customModes, - state?.experiments, - codeIndexManager, - filterSettings, - ) - - // Filter MCP tools based on mode restrictions - const mcpTools = getMcpServerTools(mcpHub) - const filteredMcpTools = filterMcpToolsForMode(mcpTools, mode, state?.customModes, state?.experiments) - - allTools = [...filteredNativeTools, ...filteredMcpTools] + customModes: state?.customModes, + experiments: state?.experiments, + apiConfiguration, + maxReadFileLine: state?.maxReadFileLine ?? -1, + browserToolEnabled: state?.browserToolEnabled ?? true, + }) } const metadata: ApiHandlerCreateMessageMetadata = { diff --git a/src/core/task/build-tools.ts b/src/core/task/build-tools.ts new file mode 100644 index 0000000000..4708a462d6 --- /dev/null +++ b/src/core/task/build-tools.ts @@ -0,0 +1,62 @@ +import type OpenAI from "openai" +import type { ProviderSettings, ModeConfig } from "@roo-code/types" +import type { ClineProvider } from "../webview/ClineProvider" +import { getNativeTools, getMcpServerTools } from "../prompts/tools/native-tools" +import { filterNativeToolsForMode, filterMcpToolsForMode } from "../prompts/tools/filter-tools-for-mode" + +interface BuildToolsOptions { + provider: ClineProvider + cwd: string + mode: string | undefined + customModes: ModeConfig[] | undefined + experiments: Record | undefined + apiConfiguration: ProviderSettings | undefined + maxReadFileLine: number + browserToolEnabled: boolean +} + +/** + * Builds the complete tools array for native protocol requests. + * Combines native tools and MCP tools, filtered by mode restrictions. + * + * @param options - Configuration options for building the tools + * @returns Array of filtered native and MCP tools + */ +export async function buildNativeToolsArray(options: BuildToolsOptions): Promise { + const { provider, cwd, mode, customModes, experiments, apiConfiguration, maxReadFileLine, browserToolEnabled } = + options + + const mcpHub = provider.getMcpHub() + + // Get CodeIndexManager for feature checking + const { CodeIndexManager } = await import("../../services/code-index/manager") + const codeIndexManager = CodeIndexManager.getInstance(provider.context, cwd) + + // Build settings object for tool filtering + const filterSettings = { + todoListEnabled: apiConfiguration?.todoListEnabled ?? true, + browserToolEnabled: browserToolEnabled ?? true, + } + + // Determine if partial reads are enabled based on maxReadFileLine setting + const partialReadsEnabled = maxReadFileLine !== -1 + + // Build native tools with dynamic read_file tool based on partialReadsEnabled + const nativeTools = getNativeTools(partialReadsEnabled) + + // Filter native tools based on mode restrictions + const filteredNativeTools = filterNativeToolsForMode( + nativeTools, + mode, + customModes, + experiments, + codeIndexManager, + filterSettings, + ) + + // Filter MCP tools based on mode restrictions + const mcpTools = getMcpServerTools(mcpHub) + const filteredMcpTools = filterMcpToolsForMode(mcpTools, mode, customModes, experiments) + + return [...filteredNativeTools, ...filteredMcpTools] +} From 6a98ffb81735b71447b60e16c6ef555ba66f5feb Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Thu, 20 Nov 2025 08:29:07 -0700 Subject: [PATCH 2/8] Fix Marketplace crash by removing wildcard activation event (#9423) --- src/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/package.json b/src/package.json index a93caab32d..82f4e34d0b 100644 --- a/src/package.json +++ b/src/package.json @@ -46,7 +46,6 @@ "roocode" ], "activationEvents": [ - "onLanguage", "onStartupFinished" ], "main": "./dist/extension.js", From 1201b0fd8d16a3438a43a37816986a17a474843c Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Thu, 20 Nov 2025 10:49:41 -0500 Subject: [PATCH 3/8] Revert "Fix Marketplace crash by removing wildcard activation event" (#9432) --- src/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/package.json b/src/package.json index 82f4e34d0b..a93caab32d 100644 --- a/src/package.json +++ b/src/package.json @@ -46,6 +46,7 @@ "roocode" ], "activationEvents": [ + "onLanguage", "onStartupFinished" ], "main": "./dist/extension.js", From f7d6daedff23a52101870f085b7f925581bf916a Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Thu, 20 Nov 2025 09:38:33 -0700 Subject: [PATCH 4/8] Fix OpenAI Native parallel tool calls for native protocol (#9433) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes an issue where using the OpenAI Native provider together with Native Tool Calling could cause OpenAI’s Responses API to fail with errors like: --- src/api/providers/openai-native.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 6926e4d624..74ba621c43 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -244,6 +244,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio strict?: boolean }> tool_choice?: any + parallel_tool_calls?: boolean } // Validate requested tier against model support; if not supported, omit. @@ -302,6 +303,12 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio ...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }), } + // For native tool protocol, explicitly disable parallel tool calls. + // For XML or when protocol is unset, omit the field entirely so the API default applies. + if (metadata?.toolProtocol === "native") { + body.parallel_tool_calls = false + } + // Include text.verbosity only when the model explicitly supports it if (model.info.supportsVerbosity === true) { body.text = { verbosity: (verbosity || "medium") as VerbosityLevel } From 1589cc1849dc94e776015066d406c400a4e7f4bd Mon Sep 17 00:00:00 2001 From: "roomote[bot]" <219738659+roomote[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:19:37 -0500 Subject: [PATCH 5/8] feat: add Google Gemini 3 Pro Image Preview to image generation models (#9440) Co-authored-by: Roo Code Co-authored-by: Matt Rubens --- packages/types/src/image-generation.ts | 20 +++++++++++++++++++ packages/types/src/index.ts | 1 + src/core/tools/GenerateImageTool.ts | 6 ++---- .../settings/ImageGenerationSettings.tsx | 9 +-------- 4 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 packages/types/src/image-generation.ts diff --git a/packages/types/src/image-generation.ts b/packages/types/src/image-generation.ts new file mode 100644 index 0000000000..2acd281031 --- /dev/null +++ b/packages/types/src/image-generation.ts @@ -0,0 +1,20 @@ +/** + * Image generation model constants + */ + +export interface ImageGenerationModel { + value: string + label: string +} + +export const IMAGE_GENERATION_MODELS: ImageGenerationModel[] = [ + { value: "google/gemini-2.5-flash-image", label: "Gemini 2.5 Flash Image" }, + { value: "google/gemini-3-pro-image-preview", label: "Gemini 3 Pro Image Preview" }, + { value: "openai/gpt-5-image", label: "GPT-5 Image" }, + { value: "openai/gpt-5-image-mini", label: "GPT-5 Image Mini" }, +] + +/** + * Get array of model values only (for backend validation) + */ +export const IMAGE_GENERATION_MODEL_IDS = IMAGE_GENERATION_MODELS.map((m) => m.value) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index ebebb72313..32505ede7b 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -7,6 +7,7 @@ export * from "./experiment.js" export * from "./followup.js" export * from "./global-settings.js" export * from "./history.js" +export * from "./image-generation.js" export * from "./ipc.js" export * from "./marketplace.js" export * from "./mcp.js" diff --git a/src/core/tools/GenerateImageTool.ts b/src/core/tools/GenerateImageTool.ts index 60914a86a7..18e8882754 100644 --- a/src/core/tools/GenerateImageTool.ts +++ b/src/core/tools/GenerateImageTool.ts @@ -1,7 +1,7 @@ import path from "path" import fs from "fs/promises" import * as vscode from "vscode" -import type { GenerateImageParams } from "@roo-code/types" +import { GenerateImageParams, IMAGE_GENERATION_MODEL_IDS } from "@roo-code/types" import { Task } from "../task/Task" import { formatResponse } from "../prompts/responses" import { fileExistsAtPath } from "../../utils/fs" @@ -12,8 +12,6 @@ import { OpenRouterHandler } from "../../api/providers/openrouter" import { BaseTool, ToolCallbacks } from "./BaseTool" import type { ToolUse } from "../../shared/tools" -const IMAGE_GENERATION_MODELS = ["google/gemini-2.5-flash-image", "openai/gpt-5-image", "openai/gpt-5-image-mini"] - export class GenerateImageTool extends BaseTool<"generate_image"> { readonly name = "generate_image" as const @@ -137,7 +135,7 @@ export class GenerateImageTool extends BaseTool<"generate_image"> { return } - const selectedModel = state?.openRouterImageGenerationSelectedModel || IMAGE_GENERATION_MODELS[0] + const selectedModel = state?.openRouterImageGenerationSelectedModel || IMAGE_GENERATION_MODEL_IDS[0] const fullPath = path.resolve(task.cwd, removeClosingTag("path", relPath)) const isOutsideWorkspace = isPathOutsideWorkspace(fullPath) diff --git a/webview-ui/src/components/settings/ImageGenerationSettings.tsx b/webview-ui/src/components/settings/ImageGenerationSettings.tsx index 2f0f21f74d..3baa2a9e8b 100644 --- a/webview-ui/src/components/settings/ImageGenerationSettings.tsx +++ b/webview-ui/src/components/settings/ImageGenerationSettings.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from "react" import { VSCodeCheckbox, VSCodeTextField, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react" +import { IMAGE_GENERATION_MODELS } from "@roo-code/types" import { useAppTranslation } from "@/i18n/TranslationContext" interface ImageGenerationSettingsProps { @@ -11,14 +12,6 @@ interface ImageGenerationSettingsProps { setImageGenerationSelectedModel: (model: string) => void } -// Hardcoded list of image generation models -const IMAGE_GENERATION_MODELS = [ - { value: "google/gemini-2.5-flash-image", label: "Gemini 2.5 Flash Image" }, - { value: "openai/gpt-5-image", label: "GPT-5 Image" }, - { value: "openai/gpt-5-image-mini", label: "GPT-5 Image Mini" }, - // Add more models as they become available -] - export const ImageGenerationSettings = ({ enabled, onChange, From 97cdc419374811aa11b8ca2bec382a9e22e2e6b9 Mon Sep 17 00:00:00 2001 From: Daniel <57051444+daniel-lxs@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:03:02 -0500 Subject: [PATCH 6/8] fix: prevent duplicate environment_details when resuming cancelled tasks (#9442) - Filter out complete environment_details blocks before appending fresh ones - Check for both opening and closing tags to ensure we're matching complete blocks - Prevents stale environment data from being kept during task resume - Add tests to verify deduplication logic and edge cases --- src/core/task/Task.ts | 19 ++- .../task/__tests__/task-tool-history.spec.ts | 121 ++++++++++++++++++ 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 7c0355e498..b340091dde 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2024,9 +2024,26 @@ export class Task extends EventEmitter implements TaskLike { const environmentDetails = await getEnvironmentDetails(this, currentIncludeFileDetails) + // Remove any existing environment_details blocks before adding fresh ones. + // This prevents duplicate environment details when resuming tasks with XML tool calls, + // where the old user message content may already contain environment details from the previous session. + // We check for both opening and closing tags to ensure we're matching complete environment detail blocks, + // not just mentions of the tag in regular content. + const contentWithoutEnvDetails = parsedUserContent.filter((block) => { + if (block.type === "text" && typeof block.text === "string") { + // Check if this text block is a complete environment_details block + // by verifying it starts with the opening tag and ends with the closing tag + const isEnvironmentDetailsBlock = + block.text.trim().startsWith("") && + block.text.trim().endsWith("") + return !isEnvironmentDetailsBlock + } + return true + }) + // Add environment details as its own text block, separate from tool // results. - const finalUserContent = [...parsedUserContent, { type: "text" as const, text: environmentDetails }] + const finalUserContent = [...contentWithoutEnvDetails, { type: "text" as const, text: environmentDetails }] // Only add user message to conversation history if: // 1. This is the first attempt (retryAttempt === 0), OR diff --git a/src/core/task/__tests__/task-tool-history.spec.ts b/src/core/task/__tests__/task-tool-history.spec.ts index 0ab087c7a2..832e81c37b 100644 --- a/src/core/task/__tests__/task-tool-history.spec.ts +++ b/src/core/task/__tests__/task-tool-history.spec.ts @@ -196,5 +196,126 @@ describe("Task Tool History Handling", () => { content: '{"setting": "value"}', }) }) + + describe("environment details deduplication", () => { + it("should filter out existing environment_details blocks before adding new ones", () => { + // Simulate user content that already contains environment details from a previous session + const userContentWithOldEnvDetails = [ + { + type: "text" as const, + text: "Some user message", + }, + { + type: "text" as const, + text: "\n# Old Environment Details\nCurrent time: 2024-01-01\n", + }, + ] + + // Filter out existing environment_details blocks using the same logic as Task.ts + const contentWithoutEnvDetails = userContentWithOldEnvDetails.filter((block) => { + if (block.type === "text" && typeof block.text === "string") { + // Check if this text block is a complete environment_details block + const isEnvironmentDetailsBlock = + block.text.trim().startsWith("") && + block.text.trim().endsWith("") + return !isEnvironmentDetailsBlock + } + return true + }) + + // Verify old environment details were removed + expect(contentWithoutEnvDetails).toHaveLength(1) + expect(contentWithoutEnvDetails[0].text).toBe("Some user message") + + // Simulate adding fresh environment details + const newEnvironmentDetails = + "\n# Fresh Environment Details\nCurrent time: 2024-01-02\n" + const finalUserContent = [ + ...contentWithoutEnvDetails, + { type: "text" as const, text: newEnvironmentDetails }, + ] + + // Verify we have exactly one environment_details block (the new one) + const envDetailsBlocks = finalUserContent.filter((block) => { + if (block.type === "text" && typeof block.text === "string") { + return ( + block.text.trim().startsWith("") && + block.text.trim().endsWith("") + ) + } + return false + }) + expect(envDetailsBlocks).toHaveLength(1) + expect(envDetailsBlocks[0].text).toContain("2024-01-02") + expect(envDetailsBlocks[0].text).not.toContain("2024-01-01") + }) + + it("should not filter out text that mentions environment_details tags in content", () => { + // User content that mentions the tags but isn't an environment_details block + const userContent = [ + { + type: "text" as const, + text: "Let me explain how work in this system", + }, + { + type: "text" as const, + text: "The closing tag is ", + }, + { + type: "text" as const, + text: "Regular message", + }, + ] + + // Filter using the same logic as Task.ts + const contentWithoutEnvDetails = userContent.filter((block) => { + if (block.type === "text" && typeof block.text === "string") { + const isEnvironmentDetailsBlock = + block.text.trim().startsWith("") && + block.text.trim().endsWith("") + return !isEnvironmentDetailsBlock + } + return true + }) + + // All blocks should be preserved since none are complete environment_details blocks + expect(contentWithoutEnvDetails).toHaveLength(3) + expect(contentWithoutEnvDetails).toEqual(userContent) + }) + + it("should not filter out regular text blocks", () => { + // User content with various blocks but no environment details + const userContent = [ + { + type: "text" as const, + text: "Regular message", + }, + { + type: "text" as const, + text: "Another message with tags", + }, + { + type: "tool_result" as const, + tool_use_id: "tool_123", + content: "Tool result", + }, + ] + + // Filter using the same logic as Task.ts + const contentWithoutEnvDetails = userContent.filter((block) => { + if (block.type === "text" && typeof block.text === "string") { + const isEnvironmentDetailsBlock = + block.text.trim().startsWith("") && + block.text.trim().endsWith("") + return !isEnvironmentDetailsBlock + } + return true + }) + + // All blocks should be preserved + expect(contentWithoutEnvDetails).toHaveLength(3) + expect(contentWithoutEnvDetails).toEqual(userContent) + }) + }) }) }) From 341863f8cd5108f7bbd0a64113ed4e77a36d3bb5 Mon Sep 17 00:00:00 2001 From: John Richmond <5629+jr@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:45:02 -0800 Subject: [PATCH 7/8] Update glob to ^11.1.0 (#9449) --- apps/vscode-e2e/package.json | 2 +- package.json | 5 +- pnpm-lock.yaml | 118 ++++++++--------------------------- src/package.json | 2 +- 4 files changed, 32 insertions(+), 95 deletions(-) diff --git a/apps/vscode-e2e/package.json b/apps/vscode-e2e/package.json index 1d19ffebf2..d366f72a2d 100644 --- a/apps/vscode-e2e/package.json +++ b/apps/vscode-e2e/package.json @@ -18,7 +18,7 @@ "@types/vscode": "^1.95.0", "@vscode/test-cli": "^0.0.11", "@vscode/test-electron": "^2.4.0", - "glob": "^11.0.1", + "glob": "^11.1.0", "mocha": "^11.1.0", "rimraf": "^6.0.1", "typescript": "5.8.3" diff --git a/package.json b/package.json index badfdef578..eccdc916bc 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@vscode/vsce": "3.3.2", "esbuild": "^0.25.0", "eslint": "^9.27.0", - "glob": "^11.0.3", + "glob": "^11.1.0", "husky": "^9.1.7", "knip": "^5.44.4", "lint-staged": "^16.0.0", @@ -59,7 +59,8 @@ "undici": ">=5.29.0", "brace-expansion": ">=2.0.2", "form-data": ">=4.0.4", - "bluebird": ">=3.7.2" + "bluebird": ">=3.7.2", + "glob": ">=11.1.0" } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb94763a83..984e48a614 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,7 @@ overrides: brace-expansion: '>=2.0.2' form-data: '>=4.0.4' bluebird: '>=3.7.2' + glob: '>=11.1.0' importers: @@ -41,8 +42,8 @@ importers: specifier: ^9.27.0 version: 9.28.0(jiti@2.4.2) glob: - specifier: ^11.0.3 - version: 11.0.3 + specifier: '>=11.1.0' + version: 11.1.0 husky: specifier: ^9.1.7 version: 9.1.7 @@ -104,8 +105,8 @@ importers: specifier: ^2.4.0 version: 2.5.2 glob: - specifier: ^11.0.1 - version: 11.0.3 + specifier: '>=11.1.0' + version: 11.1.0 mocha: specifier: ^11.1.0 version: 11.2.2 @@ -916,8 +917,8 @@ importers: specifier: ^9.5.2 version: 9.5.3 glob: - specifier: ^11.0.1 - version: 11.0.3 + specifier: '>=11.1.0' + version: 11.1.0 mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -2494,10 +2495,6 @@ packages: '@petamoriken/float16@3.9.3': resolution: {integrity: sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==} - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} @@ -6176,9 +6173,6 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -6301,19 +6295,11 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true - - glob@11.0.3: - resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} hasBin: true - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -6592,10 +6578,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -6900,9 +6882,6 @@ packages: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jackspeak@4.1.1: resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} engines: {node: 20 || >=22} @@ -7680,8 +7659,8 @@ packages: resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} engines: {node: 20 || >=22} - minimatch@10.0.3: - resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} minimatch@3.1.2: @@ -8153,10 +8132,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.0: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} @@ -12038,9 +12013,6 @@ snapshots: '@petamoriken/float16@3.9.3': optional: true - '@pkgjs/parseargs@0.11.0': - optional: true - '@polka/url@1.0.0-next.29': {} '@puppeteer/browsers@2.10.5': @@ -13751,7 +13723,7 @@ snapshots: '@types/glob@9.0.0': dependencies: - glob: 11.0.3 + glob: 11.1.0 '@types/hast@3.0.4': dependencies: @@ -14073,7 +14045,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.14 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.50)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) '@vitest/utils@3.2.4': dependencies: @@ -14089,7 +14061,7 @@ snapshots: c8: 9.1.0 chokidar: 3.6.0 enhanced-resolve: 5.18.1 - glob: 10.4.5 + glob: 11.1.0 minimatch: 9.0.5 mocha: 11.2.2 supports-color: 9.4.0 @@ -14154,7 +14126,7 @@ snapshots: cockatiel: 3.2.1 commander: 12.1.0 form-data: 4.0.4 - glob: 11.0.3 + glob: 11.1.0 hosted-git-info: 4.1.0 jsonc-parser: 3.3.1 leven: 3.1.0 @@ -14259,7 +14231,7 @@ snapshots: archiver-utils@2.1.0: dependencies: - glob: 7.2.3 + glob: 11.1.0 graceful-fs: 4.2.11 lazystream: 1.0.1 lodash.defaults: 4.2.0 @@ -14272,7 +14244,7 @@ snapshots: archiver-utils@3.0.4: dependencies: - glob: 7.2.3 + glob: 11.1.0 graceful-fs: 4.2.11 lazystream: 1.0.1 lodash.defaults: 4.2.0 @@ -14870,7 +14842,7 @@ snapshots: copyfiles@2.4.1: dependencies: - glob: 7.2.3 + glob: 11.1.0 minimatch: 3.1.2 mkdirp: 1.0.4 noms: 0.0.0 @@ -16148,8 +16120,6 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true @@ -16311,33 +16281,15 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@10.4.5: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - glob@11.0.3: + glob@11.1.0: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 - minimatch: 10.0.3 + minimatch: 10.1.1 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.0 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - globals@11.12.0: {} globals@14.0.0: {} @@ -16692,11 +16644,6 @@ snapshots: indent-string@4.0.0: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} ini@1.3.8: @@ -16976,12 +16923,6 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - jackspeak@4.1.1: dependencies: '@isaacs/cliui': 8.0.2 @@ -18020,7 +17961,7 @@ snapshots: dependencies: brace-expansion: 4.0.1 - minimatch@10.0.3: + minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -18072,7 +18013,7 @@ snapshots: diff: 5.2.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 - glob: 10.4.5 + glob: 11.1.0 he: 1.2.0 js-yaml: 4.1.0 log-symbols: 4.1.0 @@ -18550,11 +18491,6 @@ snapshots: path-parse@1.0.7: {} - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - path-scurry@2.0.0: dependencies: lru-cache: 11.2.2 @@ -19275,15 +19211,15 @@ snapshots: rimraf@2.7.1: dependencies: - glob: 7.2.3 + glob: 11.1.0 rimraf@5.0.10: dependencies: - glob: 10.4.5 + glob: 11.1.0 rimraf@6.0.1: dependencies: - glob: 11.0.3 + glob: 11.1.0 package-json-from-dist: 1.0.1 robust-predicates@3.0.2: {} @@ -19910,7 +19846,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.8 commander: 4.1.1 - glob: 10.4.5 + glob: 11.1.0 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.7 @@ -20017,7 +19953,7 @@ snapshots: test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 + glob: 11.1.0 minimatch: 3.1.2 text-decoder@1.2.3: diff --git a/src/package.json b/src/package.json index a93caab32d..a7846c4350 100644 --- a/src/package.json +++ b/src/package.json @@ -558,7 +558,7 @@ "@vscode/vsce": "3.3.2", "esbuild": "^0.25.0", "execa": "^9.5.2", - "glob": "^11.0.1", + "glob": "^11.1.0", "mkdirp": "^3.0.1", "nock": "^14.0.4", "npm-run-all2": "^8.0.1", From d389771d754372cfe0dd80a63c5d89207fe85d68 Mon Sep 17 00:00:00 2001 From: "roomote[bot]" <219738659+roomote[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:16:30 -0800 Subject: [PATCH 8/8] chore: update tar-fs to 3.1.1 via pnpm override (#9450) Co-authored-by: Roo Code --- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index eccdc916bc..793658b459 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ }, "pnpm": { "overrides": { - "tar-fs": ">=2.1.3", + "tar-fs": ">=3.1.1", "esbuild": ">=0.25.0", "undici": ">=5.29.0", "brace-expansion": ">=2.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 984e48a614..92719c266b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - tar-fs: '>=2.1.3' + tar-fs: '>=3.1.1' esbuild: '>=0.25.0' undici: '>=5.29.0' brace-expansion: '>=2.0.2' @@ -9331,8 +9331,8 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - tar-fs@3.0.9: - resolution: {integrity: sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==} + tar-fs@3.1.1: + resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==} tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} @@ -12022,7 +12022,7 @@ snapshots: progress: 2.0.3 proxy-agent: 6.5.0 semver: 7.7.3 - tar-fs: 3.0.9 + tar-fs: 3.1.1 yargs: 17.7.2 transitivePeerDependencies: - bare-buffer @@ -12035,7 +12035,7 @@ snapshots: progress: 2.0.3 proxy-agent: 6.5.0 semver: 7.7.3 - tar-fs: 3.0.9 + tar-fs: 3.1.1 unbzip2-stream: 1.4.3 yargs: 17.7.2 transitivePeerDependencies: @@ -18651,7 +18651,7 @@ snapshots: pump: 3.0.2 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 3.0.9 + tar-fs: 3.1.1 tunnel-agent: 0.6.0 transitivePeerDependencies: - bare-buffer @@ -19915,7 +19915,7 @@ snapshots: tapable@2.2.1: {} - tar-fs@3.0.9: + tar-fs@3.1.1: dependencies: pump: 3.0.2 tar-stream: 3.1.7