Skip to content

Commit 50ea415

Browse files
authored
Merge branch 'main' into font-aliasing
2 parents 64ba027 + 923e391 commit 50ea415

File tree

153 files changed

+3997
-3269
lines changed

Some content is hidden

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

153 files changed

+3997
-3269
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# Roo Code Changelog
22

3+
## [3.12.0] - 2025-04-15
4+
5+
- Add xAI provider and expose reasoning effort options for Grok on OpenRouter (thanks Cline!)
6+
- Make diff editing config per-profile and improve pre-diff string normalization
7+
- Make checkpoints faster and more reliable
8+
- Add a search bar to mode and profile select dropdowns (thanks @samhvw8!)
9+
- Add telemetry for code action usage, prompt enhancement usage, and consecutive mistake errors
10+
- Suppress zero cost values in the task header (thanks @do-it!)
11+
- Make JSON parsing safer to avoid crashing the webview on bad input
12+
- Allow users to bind a keyboard shortcut for accepting suggestions or input in the chat view (thanks @axkirillov!)
13+
14+
## [3.11.17] - 2025-04-14
15+
16+
- Improvements to OpenAI cache reporting and cost estimates (thanks @monotykamary and Cline!)
17+
- Visual improvements to the auto-approve toggles (thanks @sachasayan!)
18+
- Bugfix to diff apply logic (thanks @avtc for the test case!) and telemetry to track errors going forward
19+
- Fix race condition in capturing short-running terminal commands (thanks @KJ7LNW!)
20+
- Fix eslint error (thanks @nobu007!)
21+
22+
## [3.11.16] - 2025-04-14
23+
24+
- Add gpt-4.1, gpt-4.1-mini, and gpt-4.1-nano to the OpenAI provider
25+
- Include model ID in environment details and when exporting tasks (thanks @feifei325!)
26+
327
## [3.11.15] - 2025-04-13
428

529
- Add ability to filter task history by workspace (thanks @samhvw8!)

README.md

Lines changed: 28 additions & 30 deletions
Large diffs are not rendered by default.

e2e/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
6-
"lint": "eslint src --ext ts",
6+
"lint": "eslint src/**/*.ts",
77
"check-types": "tsc --noEmit",
88
"test": "npm run build && npx dotenvx run -f .env.local -- node ./out/runTest.js",
99
"ci": "npm run vscode-test && npm run test",

evals/apps/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"private": true,
44
"type": "module",
55
"scripts": {
6-
"lint": "eslint src --ext ts --max-warnings=0",
6+
"lint": "eslint src/**/*.ts --max-warnings=0",
77
"check-types": "tsc --noEmit",
88
"format": "prettier --write src",
99
"dev": "dotenvx run -f ../../.env -- tsx src/index.ts"

evals/apps/cli/src/index.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
IpcMessageType,
1717
TaskCommandName,
1818
rooCodeDefaults,
19+
EvalEventName,
1920
} from "@evals/types"
2021
import {
2122
type Run,
@@ -34,7 +35,7 @@ import { IpcServer, IpcClient } from "@evals/ipc"
3435
import { __dirname, extensionDevelopmentPath, exercisesPath } from "./paths.js"
3536
import { getExercises } from "./exercises.js"
3637

37-
type TaskResult = { success: boolean; retry: boolean }
38+
type TaskResult = { success: boolean }
3839
type TaskPromise = Promise<TaskResult>
3940

4041
const TASK_START_DELAY = 10 * 1_000
@@ -116,24 +117,25 @@ const run = async (toolbox: GluegunToolbox) => {
116117

117118
const runningPromises: TaskPromise[] = []
118119

119-
// Retries aren't implemented yet, but the return values are set up to
120-
// support them.
121120
const processTask = async (task: Task, delay = 0) => {
122121
if (task.finishedAt === null) {
123122
await new Promise((resolve) => setTimeout(resolve, delay))
124-
const { retry } = await runExercise({ run, task, server })
125-
126-
if (retry) {
127-
return { success: false, retry: true }
128-
}
123+
await runExercise({ run, task, server })
129124
}
130125

131126
if (task.passed === null) {
132127
const passed = await runUnitTest({ task })
133128
await updateTask(task.id, { passed })
134-
return { success: passed, retry: false }
129+
130+
server.broadcast({
131+
type: IpcMessageType.TaskEvent,
132+
origin: IpcOrigin.Server,
133+
data: { eventName: passed ? EvalEventName.Pass : EvalEventName.Fail, taskId: task.id },
134+
})
135+
136+
return { success: passed }
135137
} else {
136-
return { success: task.passed, retry: false }
138+
return { success: task.passed }
137139
}
138140
}
139141

@@ -200,7 +202,7 @@ const runExercise = async ({ run, task, server }: { run: Run; task: Task; server
200202
} catch (error) {
201203
console.log(`${Date.now()} [cli#runExercise | ${language} / ${exercise}] unable to connect`)
202204
client.disconnect()
203-
return { success: false, retry: false }
205+
return { success: false }
204206
}
205207

206208
let taskStartedAt = Date.now()
@@ -209,16 +211,15 @@ const runExercise = async ({ run, task, server }: { run: Run; task: Task; server
209211
let rooTaskId: string | undefined
210212
let isClientDisconnected = false
211213

212-
const ignoreEvents: RooCodeEventName[] = [
213-
RooCodeEventName.Message,
214-
RooCodeEventName.TaskTokenUsageUpdated,
215-
RooCodeEventName.TaskAskResponded,
216-
]
214+
const ignoreEvents: Record<"broadcast" | "log", (RooCodeEventName | EvalEventName)[]> = {
215+
broadcast: [RooCodeEventName.Message],
216+
log: [RooCodeEventName.Message, RooCodeEventName.TaskTokenUsageUpdated, RooCodeEventName.TaskAskResponded],
217+
}
217218

218219
client.on(IpcMessageType.TaskEvent, async (taskEvent) => {
219220
const { eventName, payload } = taskEvent
220221

221-
if (taskEvent.eventName !== RooCodeEventName.Message) {
222+
if (!ignoreEvents.broadcast.includes(eventName)) {
222223
server.broadcast({
223224
type: IpcMessageType.TaskEvent,
224225
origin: IpcOrigin.Server,
@@ -227,7 +228,7 @@ const runExercise = async ({ run, task, server }: { run: Run; task: Task; server
227228
})
228229
}
229230

230-
if (!ignoreEvents.includes(eventName)) {
231+
if (!ignoreEvents.log.includes(eventName)) {
231232
console.log(
232233
`${Date.now()} [cli#runExercise | ${language} / ${exercise}] taskEvent -> ${eventName}`,
233234
payload,
@@ -320,11 +321,10 @@ const runExercise = async ({ run, task, server }: { run: Run; task: Task; server
320321
data: { commandName: TaskCommandName.CancelTask, data: rooTaskId },
321322
})
322323

323-
// Give the server some time to cancel the task.
324+
// Allow some time for the task to cancel.
324325
await new Promise((resolve) => setTimeout(resolve, 5_000))
325326
}
326327

327-
// TODO: Notify clients that the task timed out.
328328
await updateTask(task.id, { finishedAt: new Date() })
329329
}
330330

@@ -336,12 +336,15 @@ const runExercise = async ({ run, task, server }: { run: Run; task: Task; server
336336
clientId: client.clientId!,
337337
data: { commandName: TaskCommandName.CloseTask, data: rooTaskId },
338338
})
339+
340+
// Allow some time for the window to close.
341+
await new Promise((resolve) => setTimeout(resolve, 2_000))
339342
}
340343

341344
client.disconnect()
342345
}
343346

344-
return { success: !!taskFinishedAt, retry: false }
347+
return { success: !!taskFinishedAt }
345348
}
346349

347350
const runUnitTest = async ({ task }: { task: Task }) => {
@@ -372,7 +375,7 @@ const runUnitTest = async ({ task }: { task: Task }) => {
372375
})
373376

374377
console.log(
375-
`${Date.now()} [cli#runUnitTest | ${task.language} / ${task.exercise}] "${command.join(" ")}": ${subprocess.pid} -> ${JSON.stringify(descendants)}`,
378+
`${Date.now()} [cli#runUnitTest | ${task.language} / ${task.exercise}] "${command.join(" ")}": unit tests timed out, killing ${subprocess.pid} + ${JSON.stringify(descendants)}`,
376379
)
377380

378381
if (descendants.length > 0) {
@@ -384,7 +387,10 @@ const runUnitTest = async ({ task }: { task: Task }) => {
384387

385388
await execa`kill -9 ${descendant}`
386389
} catch (error) {
387-
console.error("Error killing descendant processes:", error)
390+
console.error(
391+
`${Date.now()} [cli#runUnitTest | ${task.language} / ${task.exercise}] Error killing descendant processes:`,
392+
error,
393+
)
388394
}
389395
}
390396
}
@@ -396,7 +402,10 @@ const runUnitTest = async ({ task }: { task: Task }) => {
396402
try {
397403
await execa`kill -9 ${subprocess.pid!}`
398404
} catch (error) {
399-
console.error("Error killing process:", error)
405+
console.error(
406+
`${Date.now()} [cli#runUnitTest | ${task.language} / ${task.exercise}] Error killing process:`,
407+
error,
408+
)
400409
}
401410
}, UNIT_TEST_TIMEOUT)
402411

evals/apps/web/src/hooks/use-run-status.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useState, useCallback, useRef } from "react"
22
import { useQuery, keepPreviousData } from "@tanstack/react-query"
33

4-
import { RooCodeEventName, taskEventSchema, TokenUsage } from "@evals/types"
4+
import { TokenUsage, taskEventSchema, RooCodeEventName, EvalEventName } from "@evals/types"
55
import { Run } from "@evals/db"
66

77
import { getTasks } from "@/lib/server/tasks"
@@ -51,17 +51,17 @@ export const useRunStatus = (run: Run) => {
5151
case RooCodeEventName.TaskStarted:
5252
startTimes.current.set(taskId, Date.now())
5353
break
54-
case RooCodeEventName.TaskCompleted:
55-
case RooCodeEventName.TaskAborted:
56-
setTasksUpdatedAt(Date.now())
57-
break
5854
case RooCodeEventName.TaskTokenUsageUpdated: {
5955
const startTime = startTimes.current.get(taskId)
6056
const duration = startTime ? Date.now() - startTime : undefined
6157
tokenUsage.current.set(taskId, { ...payload[1], duration })
6258
setUsageUpdatedAt(Date.now())
6359
break
6460
}
61+
case EvalEventName.Pass:
62+
case EvalEventName.Fail:
63+
setTasksUpdatedAt(Date.now())
64+
break
6565
}
6666
}, [])
6767

evals/packages/db/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"type": "module",
55
"exports": "./src/index.ts",
66
"scripts": {
7-
"lint": "eslint src --ext ts --max-warnings=0",
7+
"lint": "eslint src/**/*.ts --max-warnings=0",
88
"check-types": "tsc --noEmit",
99
"format": "prettier --write src",
1010
"drizzle-kit": "dotenvx run -f ../../.env -- tsx node_modules/drizzle-kit/bin.cjs",
@@ -23,6 +23,7 @@
2323
"@libsql/client": "^0.14.0",
2424
"drizzle-orm": "^0.40.0",
2525
"drizzle-zod": "^0.7.0",
26+
"p-map": "^7.0.3",
2627
"zod": "^3.24.2"
2728
},
2829
"devDependencies": {

evals/packages/db/scripts/copy-run.mts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { drizzle } from "drizzle-orm/libsql"
22
import { eq } from "drizzle-orm"
3+
import pMap from "p-map"
34

45
import { db as sourceDb } from "../src/db.js"
56
import { schema } from "../src/schema.js"
@@ -52,29 +53,33 @@ const copyRun = async (runId: number) => {
5253

5354
console.log(`Copying ${tasks.length} tasks`)
5455

55-
for (const task of tasks) {
56-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
57-
const { id: _, ...newTaskMetricsValues } = task.taskMetrics!
58-
const [newTaskMetrics] = await destDb.insert(schema.taskMetrics).values(newTaskMetricsValues).returning()
59-
60-
if (!newTaskMetrics) {
61-
throw new Error(`Failed to insert taskMetrics for task ${task.id}`)
62-
}
63-
64-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
65-
const { id: __, ...newTaskValues } = task
66-
67-
const [newTask] = await destDb
68-
.insert(schema.tasks)
69-
.values({ ...newTaskValues, runId: newRun.id, taskMetricsId: newTaskMetrics.id })
70-
.returning()
71-
72-
if (!newTask) {
73-
throw new Error(`Failed to insert task ${task.id}`)
74-
}
75-
}
76-
77-
console.log(`Successfully copied run ${runId} with ${tasks.length} tasks`)
56+
await pMap(
57+
tasks,
58+
async (task) => {
59+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
60+
const { id: _, ...newTaskMetricsValues } = task.taskMetrics!
61+
const [newTaskMetrics] = await destDb.insert(schema.taskMetrics).values(newTaskMetricsValues).returning()
62+
63+
if (!newTaskMetrics) {
64+
throw new Error(`Failed to insert taskMetrics for task ${task.id}`)
65+
}
66+
67+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
68+
const { id: __, ...newTaskValues } = task
69+
70+
const [newTask] = await destDb
71+
.insert(schema.tasks)
72+
.values({ ...newTaskValues, runId: newRun.id, taskMetricsId: newTaskMetrics.id })
73+
.returning()
74+
75+
if (!newTask) {
76+
throw new Error(`Failed to insert task ${task.id}`)
77+
}
78+
},
79+
{ concurrency: 25 },
80+
)
81+
82+
console.log(`\nSuccessfully copied run ${runId} with ${tasks.length} tasks`)
7883
}
7984

8085
const main = async () => {

evals/packages/ipc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"type": "module",
55
"exports": "./src/index.ts",
66
"scripts": {
7-
"lint": "eslint src --ext ts --max-warnings=0",
7+
"lint": "eslint src/**/*.ts --max-warnings=0",
88
"check-types": "tsc --noEmit",
99
"format": "prettier --write src"
1010
},

evals/packages/lib/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"type": "module",
55
"exports": "./src/index.ts",
66
"scripts": {
7-
"lint": "eslint src --ext ts --max-warnings=0",
7+
"lint": "eslint src/**/*.ts --max-warnings=0",
88
"check-types": "tsc --noEmit",
99
"test": "vitest --globals --run",
1010
"format": "prettier --write src"

0 commit comments

Comments
 (0)