Skip to content

Commit b2b7780

Browse files
hannesrudolphroomote-v0[bot]roomotedaniel-lxsmrubens
authored
Reapply Batch 1: 22 clean non-AI-SDK cherry-picks (#11473)
* fix: add image content support to MCP tool responses (#10874) Co-authored-by: Roo Code <roomote@roocode.com> * fix: transform tool blocks to text before condensing (EXT-624) (#10975) * refactor(read_file): Codex-inspired read_file refactor EXT-617 (#10981) * feat: allow import settings in initial welcome screen (#10994) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix(code-index): remove deprecated text-embedding-004 and migrate to gemini-embedding-001 (#11038) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Hannes Rudolph <hrudolph@gmail.com> * chore: treat extension .env as optional (#11116) * fix: sanitize tool_use_id in tool_result blocks to match API history (#11131) Tool IDs from providers like Gemini/OpenRouter contain special characters (e.g., 'functions.read_file:0') that are sanitized when saving tool_use blocks to API history. However, tool_result blocks were using the original unsanitized IDs, causing ToolResultIdMismatchError. This fix ensures tool_result blocks use sanitizeToolUseId() to match the sanitized tool_use IDs in conversation history. Fixes EXT-711 * fix: queue messages during command execution instead of losing them (#11140) * IPC fixes for task cancellation and queued messages (#11162) * feat: add support for AGENTS.local.md personal override files (#11183) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * fix(cli): resolve race condition causing provider switch during mode changes (#11205) When using slash commands with `mode:` frontmatter (e.g., `/cli-release` with `mode: code`), the CLI would fail with "Could not resolve authentication method" from the Anthropic SDK, even when using a non-Anthropic provider like `--provider roo`. Root cause: In `markWebviewReady()`, the `webviewDidLaunch` message was sent before `updateSettings`, creating a race condition. The `webviewDidLaunch` handler's "first-time init" sync would read `getState()` before CLI-provided settings were applied to the context proxy. Since `getState()` defaults `apiProvider` to "anthropic" when unset, this default was saved to the provider profile. When a slash command triggered `handleModeSwitch()`, it found this corrupted profile with `apiProvider: "anthropic"` (but no API key) and activated it, overwriting the CLI's working roo provider configuration. Fix: 1. Reorder `markWebviewReady()` to send `updateSettings` before `webviewDidLaunch`, ensuring the context proxy has CLI-provided values when the initialization handler runs. 2. Guard the first-time init sync with `checkExistKey(apiConfiguration)` to prevent saving a profile with only the default "anthropic" fallback and no actual API keys configured. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove dead toolFormat code from getEnvironmentDetails (#11207) Remove the toolFormat constant and <tool_format> line from environment details output. Native tool calling is now the only supported protocol, making this code unnecessary. Fixes #11206 Co-authored-by: Roo Code <roomote@roocode.com> * feat: extract translation and merge resolver modes into reusable skills (#11215) * feat: extract translation and merge resolver modes into reusable skills - Add roo-translation skill with comprehensive i18n guidelines - Add roo-conflict-resolution skill for intelligent merge conflict resolution - Add /roo-translate slash command as shortcut for translation skill - Add /roo-resolve-conflicts slash command as shortcut for conflict resolution skill The existing translate and merge-resolver modes are preserved. These new skills and commands provide reusable access to the same functionality. Closes CLO-722 * feat: add guidances directory with translator guidance file - Add .roo/guidances/roo-translator.md for brand voice, tone, and word choice guidance - Update roo-translation skill to reference the guidance file The guidance file serves as a placeholder for translation style guidelines that will be interpolated at runtime. * fix: rename guidances directory to guidance (singular) * fix: remove language-specific section from translator guidance The guidance file should focus on brand voice, tone, and word choice only. * fix: remove language-specific guidelines section from skill file * Update .roo/skills/roo-translation/SKILL.md Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> --------- Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Bruno Bergher <bruno@roocode.com> Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * feat: add Claude Opus 4.6 support across all providers (#11224) * feat: add Claude Opus 4.6 support across all providers Add Claude Opus 4.6 (claude-opus-4-6) model definitions and 1M context support across Anthropic, Bedrock, Vertex AI, OpenRouter, and Vercel AI Gateway providers. - Anthropic: 128K max output, /5 pricing, 1M context tiers - Bedrock: anthropic.claude-opus-4-6-v1:0 with 1M context + global inference - Vertex: claude-opus-4-6 with 1M context tiers - OpenRouter: prompt caching + reasoning budget sets - Vercel AI Gateway: Opus 4.5 and 4.6 added to capability sets - UI: 1M context checkbox for Opus 4.6 on all providers - i18n: Updated 1M context descriptions across 18 locales Also adds Opus 4.5 to Vercel AI Gateway (previously missing) and OpenRouter maxTokens overrides for Opus 4.5/4.6. Closes #11223 * fix: apply tier pricing when 1M context is enabled on Bedrock When awsBedrock1MContext is enabled for tiered models like Opus 4.6, also apply the 1M tier pricing (inputPrice, outputPrice, cache prices) instead of only updating contextWindow. This ensures cost calculations and UI display use the correct >200K rates. * feat: add gpt-5.3-codex model to OpenAI Codex provider (#11225) feat: add gpt-5.3-codex model and make it default for OpenAI Codex provider Co-authored-by: Roo Code <roomote@roocode.com> * fix: prevent parent task state loss during orchestrator delegation (#11281) * fix: make removeClineFromStack() delegation-aware to prevent orphaned parent tasks (#11302) * fix: make removeClineFromStack() delegation-aware to prevent orphaned parent tasks When a delegated child task is removed via removeClineFromStack() (e.g., Clear Task, navigate to history, start new task), the parent task was left orphaned in "delegated" status with a stale awaitingChildId. This made the parent unresumable without manual history repair. This fix captures parentTaskId and childTaskId before abort/dispose, then repairs the parent metadata (status -> active, clear awaitingChildId) when the popped task is a delegated child and awaitingChildId matches. Parent lookup + updateTaskHistory are wrapped in try/catch so failures are non-fatal (logged but do not block the pop). Closes #11301 * fix: add skipDelegationRepair opt-out to removeClineFromStack() for nested delegation --------- Co-authored-by: Roo Code <roomote@roocode.com> * fix(reliability): prevent webview postMessage crashes and make dispose idempotent (#11313) * fix(reliability): prevent webview postMessage crashes and make dispose idempotent Closes: #11311 1. postMessageToWebview() now catches rejections from webview.postMessage() so that messages sent after the webview is disposed do not surface as unhandled promise rejections. 2. dispose() is guarded by a _disposed flag so that repeated calls (e.g. during rapid extension deactivation) are no-ops. 3. CloudService mock in ClineProvider.spec.ts updated to include off() — a pre-existing gap exposed by the new dispose test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add early _disposed check in postMessageToWebview Skip the postMessage call entirely when the provider is already disposed, avoiding unnecessary try/catch execution. Added test coverage for this path. * chore: trigger CI --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * fix: resolve race condition in new_task delegation that loses parent task history (#11331) * fix: resolve race condition in new_task delegation that loses parent task history When delegateParentAndOpenChild creates a child task via createTask(), the Task constructor fires startTask() as a fire-and-forget async call. The child immediately begins its task loop and eventually calls saveClineMessages() → updateTaskHistory(), which reads globalState, modifies it, and writes back. Meanwhile, delegateParentAndOpenChild persists the parent's delegation metadata (status: 'delegated', delegatedToId, awaitingChildId, childIds) via a separate updateTaskHistory() call AFTER createTask() returns. These two concurrent read-modify-write operations on globalState race: the last writer wins, overwriting the other's changes. When the child's write lands last, the parent's delegation fields are lost, making the parent task unresumable when the child finishes. Fix: create the child task with startTask: false, persist the parent's delegation metadata first, then manually call child.start(). This ensures the parent metadata is safely in globalState before the child begins writing. * docs: clarify Task.start() only handles new tasks, not history resume * fix: serialize taskHistory writes and fix delegation status overwrite race (#11335) Add a promise-chain mutex (withTaskHistoryLock) to serialize all read-modify-write operations on taskHistory, preventing concurrent interleaving from silently dropping entries. Reorder reopenParentFromDelegation to close the child instance before marking it completed, so the abort path's stale 'active' status write no longer overwrites the 'completed' state. Covered by new tests: RPD-04/05/06, UTH-02/04, and a full mutex concurrency suite. * Fix task resumption in the API module (#11369) * chore: clean up repo-facing mode rules (#11410) * fix: add maxReadFileLine to ExtensionState type for webview compatibility --------- Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> Co-authored-by: Chris Estreich <cestreich@gmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Bruno Bergher <bruno@roocode.com> Co-authored-by: 0xMink <dennis@dennismink.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>
1 parent d52b683 commit b2b7780

130 files changed

Lines changed: 6590 additions & 4722 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ bin/
1818

1919
# Local prompts and rules
2020
/local-prompts
21+
AGENTS.local.md
2122

2223
# Test environment
2324
.test_env

apps/cli/src/agent/extension-host.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,12 +428,16 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
428428
public markWebviewReady(): void {
429429
this.isReady = true
430430

431-
// Send initial webview messages to trigger proper extension initialization.
432-
// This is critical for the extension to start sending state updates properly.
433-
this.sendToExtension({ type: "webviewDidLaunch" })
434-
431+
// Apply CLI settings to the runtime config and context proxy BEFORE
432+
// sending webviewDidLaunch. This prevents a race condition where the
433+
// webviewDidLaunch handler's first-time init sync reads default state
434+
// (apiProvider: "anthropic") instead of the CLI-provided settings.
435435
setRuntimeConfigValues("roo-cline", this.initialSettings as Record<string, unknown>)
436436
this.sendToExtension({ type: "updateSettings", updatedSettings: this.initialSettings })
437+
438+
// Now trigger extension initialization. The context proxy should already
439+
// have CLI-provided values when the webviewDidLaunch handler runs.
440+
this.sendToExtension({ type: "webviewDidLaunch" })
437441
}
438442

439443
public isInInitialSetup(): boolean {

apps/vscode-e2e/src/suite/tools/read-file.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ suite.skip("Roo Code read_file Tool", function () {
376376
}
377377
})
378378

379-
test("Should read file with line range", async function () {
379+
test("Should read file with slice offset/limit", async function () {
380380
const api = globalThis.api
381381
const messages: ClineMessage[] = []
382382
let taskCompleted = false
@@ -446,7 +446,7 @@ suite.skip("Roo Code read_file Tool", function () {
446446
alwaysAllowReadOnly: true,
447447
alwaysAllowReadOnlyOutsideWorkspace: true,
448448
},
449-
text: `Use the read_file tool to read the file "${fileName}" and show me what's on lines 2, 3, and 4. The file contains lines like "Line 1", "Line 2", etc. Assume the file exists and you can read it directly.`,
449+
text: `Use the read_file tool to read the file "${fileName}" using slice mode with offset=2 and limit=3 (1-based offset). The file contains lines like "Line 1", "Line 2", etc. After reading, show me the three lines you read.`,
450450
})
451451

452452
// Wait for task completion
@@ -455,9 +455,8 @@ suite.skip("Roo Code read_file Tool", function () {
455455
// Verify tool was executed
456456
assert.ok(toolExecuted, "The read_file tool should have been executed")
457457

458-
// Verify the tool returned the correct lines (when line range is used)
458+
// Verify the tool returned the correct lines (offset=2, limit=3 -> lines 2-4)
459459
if (toolResult && (toolResult as string).includes(" | ")) {
460-
// The result includes line numbers
461460
assert.ok(
462461
(toolResult as string).includes("2 | Line 2"),
463462
"Tool result should include line 2 with line number",

packages/cloud/src/__tests__/CloudSettingsService.parsing.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ describe("CloudSettingsService - Response Parsing", () => {
8181
version: 2,
8282
defaultSettings: {
8383
maxOpenTabsContext: 10,
84-
maxReadFileLine: 1000,
8584
},
8685
allowList: {
8786
allowAll: false,

packages/evals/src/cli/runTaskInCli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export const runTaskWithCli = async ({ run, task, publish, logger, jobToken }: R
263263

264264
if (rooTaskId && !isClientDisconnected) {
265265
logger.info("cancelling task")
266-
client.sendCommand({ commandName: TaskCommandName.CancelTask, data: rooTaskId })
266+
client.sendCommand({ commandName: TaskCommandName.CancelTask })
267267
await new Promise((resolve) => setTimeout(resolve, 5_000))
268268
}
269269

@@ -288,7 +288,7 @@ export const runTaskWithCli = async ({ run, task, publish, logger, jobToken }: R
288288

289289
if (rooTaskId && !isClientDisconnected) {
290290
logger.info("closing task")
291-
client.sendCommand({ commandName: TaskCommandName.CloseTask, data: rooTaskId })
291+
client.sendCommand({ commandName: TaskCommandName.CloseTask })
292292
await new Promise((resolve) => setTimeout(resolve, 2_000))
293293
}
294294

packages/evals/src/cli/runTaskInVscode.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ export const runTaskInVscode = async ({ run, task, publish, logger, jobToken }:
270270

271271
if (rooTaskId && !isClientDisconnected) {
272272
logger.info("cancelling task")
273-
client.sendCommand({ commandName: TaskCommandName.CancelTask, data: rooTaskId })
273+
client.sendCommand({ commandName: TaskCommandName.CancelTask })
274274
await new Promise((resolve) => setTimeout(resolve, 5_000)) // Allow some time for the task to cancel.
275275
}
276276

@@ -289,7 +289,7 @@ export const runTaskInVscode = async ({ run, task, publish, logger, jobToken }:
289289

290290
if (rooTaskId && !isClientDisconnected) {
291291
logger.info("closing task")
292-
client.sendCommand({ commandName: TaskCommandName.CloseTask, data: rooTaskId })
292+
client.sendCommand({ commandName: TaskCommandName.CloseTask })
293293
await new Promise((resolve) => setTimeout(resolve, 2_000)) // Allow some time for the window to close.
294294
}
295295

packages/types/src/__tests__/ipc.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe("IPC Types", () => {
2727
const result = taskCommandSchema.safeParse(resumeTaskCommand)
2828
expect(result.success).toBe(true)
2929

30-
if (result.success) {
30+
if (result.success && result.data.commandName === TaskCommandName.ResumeTask) {
3131
expect(result.data.commandName).toBe("ResumeTask")
3232
expect(result.data.data).toBe("non-existent-task-id")
3333
}
@@ -45,7 +45,7 @@ describe("IPC Types", () => {
4545
const result = taskCommandSchema.safeParse(resumeTaskCommand)
4646
expect(result.success).toBe(true)
4747

48-
if (result.success) {
48+
if (result.success && result.data.commandName === TaskCommandName.ResumeTask) {
4949
expect(result.data.commandName).toBe("ResumeTask")
5050
expect(result.data.data).toBe("task-123")
5151
}

packages/types/src/cloud.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ export const organizationDefaultSettingsSchema = globalSettingsSchema
9595
.pick({
9696
enableCheckpoints: true,
9797
maxOpenTabsContext: true,
98-
maxReadFileLine: true,
9998
maxWorkspaceFiles: true,
10099
showRooIgnoredFiles: true,
101100
terminalCommandDelay: true,
@@ -108,7 +107,6 @@ export const organizationDefaultSettingsSchema = globalSettingsSchema
108107
.merge(
109108
z.object({
110109
maxOpenTabsContext: z.number().int().nonnegative().optional(),
111-
maxReadFileLine: z.number().int().gte(-1).optional(),
112110
maxWorkspaceFiles: z.number().int().nonnegative().optional(),
113111
terminalCommandDelay: z.number().int().nonnegative().optional(),
114112
terminalShellIntegrationTimeout: z.number().int().nonnegative().optional(),

packages/types/src/events.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { z } from "zod"
22

3-
import { clineMessageSchema, tokenUsageSchema } from "./message.js"
3+
import { clineMessageSchema, queuedMessageSchema, tokenUsageSchema } from "./message.js"
44
import { toolNamesSchema, toolUsageSchema } from "./tool.js"
55

66
/**
@@ -35,6 +35,7 @@ export enum RooCodeEventName {
3535
TaskModeSwitched = "taskModeSwitched",
3636
TaskAskResponded = "taskAskResponded",
3737
TaskUserMessage = "taskUserMessage",
38+
QueuedMessagesUpdated = "queuedMessagesUpdated",
3839

3940
// Task Analytics
4041
TaskTokenUsageUpdated = "taskTokenUsageUpdated",
@@ -100,6 +101,7 @@ export const rooCodeEventsSchema = z.object({
100101
[RooCodeEventName.TaskModeSwitched]: z.tuple([z.string(), z.string()]),
101102
[RooCodeEventName.TaskAskResponded]: z.tuple([z.string()]),
102103
[RooCodeEventName.TaskUserMessage]: z.tuple([z.string()]),
104+
[RooCodeEventName.QueuedMessagesUpdated]: z.tuple([z.string(), z.array(queuedMessageSchema)]),
103105

104106
[RooCodeEventName.TaskToolFailed]: z.tuple([z.string(), toolNamesSchema, z.string()]),
105107
[RooCodeEventName.TaskTokenUsageUpdated]: z.tuple([z.string(), tokenUsageSchema, toolUsageSchema]),
@@ -217,6 +219,11 @@ export const taskEventSchema = z.discriminatedUnion("eventName", [
217219
payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskAskResponded],
218220
taskId: z.number().optional(),
219221
}),
222+
z.object({
223+
eventName: z.literal(RooCodeEventName.QueuedMessagesUpdated),
224+
payload: rooCodeEventsSchema.shape[RooCodeEventName.QueuedMessagesUpdated],
225+
taskId: z.number().optional(),
226+
}),
220227

221228
// Task Analytics
222229
z.object({

packages/types/src/global-settings.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ export const globalSettingsSchema = z.object({
119119
allowedMaxCost: z.number().nullish(),
120120
autoCondenseContext: z.boolean().optional(),
121121
autoCondenseContextPercent: z.number().optional(),
122-
maxConcurrentFileReads: z.number().optional(),
123122

124123
/**
125124
* Whether to include current time in the environment details
@@ -173,7 +172,6 @@ export const globalSettingsSchema = z.object({
173172
maxWorkspaceFiles: z.number().optional(),
174173
showRooIgnoredFiles: z.boolean().optional(),
175174
enableSubfolderRules: z.boolean().optional(),
176-
maxReadFileLine: z.number().optional(),
177175
maxImageFileSize: z.number().optional(),
178176
maxTotalImageSize: z.number().optional(),
179177

@@ -389,7 +387,6 @@ export const EVALS_SETTINGS: RooCodeSettings = {
389387
maxWorkspaceFiles: 200,
390388
maxGitStatusFiles: 20,
391389
showRooIgnoredFiles: true,
392-
maxReadFileLine: -1, // -1 to enable full file reading.
393390

394391
includeDiagnosticMessages: true,
395392
maxDiagnosticMessages: 50,

0 commit comments

Comments
 (0)