More progress

This commit is contained in:
cte 2025-03-20 20:01:53 -07:00
parent e8db2fb252
commit 9466f0511e
17 changed files with 121 additions and 132 deletions

View file

@ -37,6 +37,3 @@ yarn-error.log*
# Misc
.DS_Store
*.pem
# Roo-Code-Benchmark
exercises

View file

@ -9,9 +9,9 @@ import { runTests } from "@vscode/test-electron"
import { type Language, languages, type Run, findRun, createRun, getTask } from "@benchmark/db"
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const extensionDevelopmentPath = path.resolve(__dirname, "../../../..")
const extensionDevelopmentPath = path.resolve(__dirname, "..", "..", "..", "..")
const extensionTestsPath = path.resolve(extensionDevelopmentPath, "benchmark/packages/runner/dist")
const exercisesPath = path.resolve(extensionDevelopmentPath, "benchmark/exercises")
const exercisesPath = path.resolve(extensionDevelopmentPath, "..", "exercises")
export const isLanguage = (language: string): language is Language => languages.includes(language as Language)
@ -87,10 +87,12 @@ const runExercise = async ({ run, language, exercise }: { run: Run; language: La
extensionTestsPath,
launchArgs: [workspacePath, "--disable-extensions"],
extensionTestsEnv: {
RUN_ID: run.id.toString(),
LANGUAGE: language,
EXERCISE: exercise,
PROMPT_PATH: promptPath,
WORKSPACE_PATH: workspacePath,
OPENROUTER_MODEL_ID: run.model,
RUN_ID: run.id.toString(),
},
})

View file

@ -5,9 +5,9 @@
"lint": "next lint",
"check-types": "tsc -b",
"dev": "dotenvx run -f ../../.env -- next dev --turbopack",
"format": "prettier --write src",
"build": "echo 'NOP' || next build",
"start": "next start",
"format": "prettier --write src"
"start": "next start"
},
"dependencies": {
"@benchmark/db": "workspace:^",

View file

@ -12,6 +12,7 @@
"lint": "eslint src --ext ts --max-warnings=0",
"check-types": "tsc --noEmit",
"format": "prettier --write src",
"build": "tsup",
"drizzle-kit": "dotenvx run -f ../../.env -- tsx node_modules/drizzle-kit/bin.cjs",
"db:generate": "pnpm drizzle-kit generate",
"db:migrate": "pnpm drizzle-kit migrate",
@ -25,7 +26,6 @@
"@libsql/client": "^0.14.0",
"drizzle-orm": "^0.40.0",
"drizzle-zod": "^0.7.0",
"libsql": "^0.5.1",
"zod": "^3.24.2"
},
"devDependencies": {

View file

@ -34,7 +34,13 @@ export const createTask = async (args: InsertTask) => {
return task
}
export const getTask = async ({ runId, language, exercise }: { runId: number; language: Language; exercise: string }) =>
type GetTask = {
runId: number
language: Language
exercise: string
}
export const getTask = async ({ runId, language, exercise }: GetTask) =>
db.query.tasks.findFirst({
where: and(eq(tasks.runId, runId), eq(tasks.language, language), eq(tasks.exercise, exercise)),
})

View file

@ -0,0 +1,8 @@
{
"extends": "@benchmark/typescript-config/cjs.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["src"],
"exclude": ["node_modules"]
}

View file

@ -0,0 +1,11 @@
import { defineConfig } from "tsup"
export default defineConfig({
entry: ["src/index.ts"],
format: ["cjs"],
dts: true,
sourcemap: true,
clean: true,
outExtension: ({ format }) => ({ js: format === "cjs" ? ".cjs" : ".js" }),
tsconfig: "tsconfig.cjs.json",
})

View file

@ -12,9 +12,7 @@
"lint": "eslint src --ext ts --max-warnings=0",
"check-types": "tsc --noEmit",
"format": "prettier --write src",
"build": "tsup",
"test:server": "tsx scripts/server.ts",
"test:client": "tsx scripts/client.ts"
"build": "tsup"
},
"dependencies": {
"node-ipc": "^12.0.0",

View file

@ -1,11 +1,16 @@
import { Socket } from "node:net"
import * as crypto from "node:crypto"
import EventEmitter from "node:events"
import ipc from "node-ipc"
import { ClientMessageType, ServerMessage, ServerMessageType, clientMessageSchema } from "./types.js"
export class IpcServer {
type IpcServerEvents = {
client: [id: string]
}
export class IpcServer extends EventEmitter<IpcServerEvents> {
private readonly _socketPath: string
private readonly _log: (...args: unknown[]) => void
private readonly _clients: Map<string, Socket>
@ -13,6 +18,8 @@ export class IpcServer {
private _isListening = false
constructor(socketPath: string, log = console.log) {
super()
this._socketPath = socketPath
this._log = log
this._clients = new Map()
@ -37,6 +44,7 @@ export class IpcServer {
this._clients.set(clientId, socket)
this.log(`[server#onConnect] clientId = ${clientId}, # clients = ${this._clients.size}`)
this.send(socket, { type: ServerMessageType.Hello, data: { clientId } })
this.emit("client", clientId)
}
private onMessage(data: unknown, socket: Socket) {
@ -88,9 +96,18 @@ export class IpcServer {
ipc.server.broadcast("message", message)
}
public send(socket: Socket, message: ServerMessage) {
public send(client: string | Socket, message: ServerMessage) {
this.log("[server#send] message =", message)
ipc.server.emit(socket, "message", message)
if (typeof client === "string") {
const socket = this._clients.get(client)
if (socket) {
ipc.server.emit(socket, "message", message)
}
} else {
ipc.server.emit(client, "message", message)
}
}
public get socketPath() {

View file

@ -8,5 +8,5 @@ export default defineConfig({
clean: true,
outExtension: ({ format }) => ({ js: format === "cjs" ? ".cjs" : ".js" }),
tsconfig: "tsconfig.cjs.json",
noExternal: ["node-ipc", "zod"],
noExternal: ["node-ipc"],
})

View file

@ -8,6 +8,7 @@
"build": "tsup"
},
"dependencies": {
"@benchmark/db": "workspace:^",
"@benchmark/ipc": "workspace:^"
},
"devDependencies": {

View file

@ -5,8 +5,8 @@ import * as vscode from "vscode"
import { RooCodeAPI } from "../../../../src/exports/roo-code.js"
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { IpcServer, ServerMessageType } = require("@benchmark/ipc")
import { IpcServer, ServerMessageType } from "@benchmark/ipc"
import { Language, createTask } from "@benchmark/db"
import { waitUntilReady, waitUntilCompleted, sleep } from "./utils.js"
@ -15,13 +15,15 @@ export async function run() {
* Validate environment variables.
*/
const runId = process.env.RUN_ID
const openRouterApiKey = process.env.OPENROUTER_API_KEY
const openRouterModelId = process.env.OPENROUTER_MODEL_ID
const runId = process.env.RUN_ID ? parseInt(process.env.RUN_ID) : undefined
const language = process.env.LANGUAGE as Language
const exercise = process.env.EXERCISE
const promptPath = process.env.PROMPT_PATH
const workspacePath = process.env.WORKSPACE_PATH
const openRouterApiKey = process.env.OPENROUTER_API_KEY
const openRouterModelId = process.env.OPENROUTER_MODEL_ID
if (!runId || !openRouterApiKey || !openRouterModelId || !promptPath || !workspacePath) {
if (!runId || !language || !exercise || !promptPath || !workspacePath || !openRouterApiKey || !openRouterModelId) {
throw new Error("ENV not configured.")
}
@ -79,31 +81,33 @@ export async function run() {
* Start the IPC server.
*/
const server = new IpcServer(`/tmp/benchmark-${runId}.sock`)
const server = new IpcServer(`/tmp/benchmark-${runId}.sock`, () => {})
server.listen()
api.on("message", (message) => {
server.broadcast({ type: ServerMessageType.Data, data: message })
server.on("client", (id) => {
server.send(id, {
type: ServerMessageType.Data,
data: {
event: "client",
runId,
language,
exercise,
prompt,
workspacePath,
},
})
})
api.on("taskStarted", (taskId) => {
server.broadcast({ type: ServerMessageType.Data, data: { taskId } })
server.broadcast({ type: ServerMessageType.Data, data: { event: "taskStarted", taskId } })
})
api.on("taskPaused", (taskId) => {
server.broadcast({ type: ServerMessageType.Data, data: { taskId } })
})
api.on("taskUnpaused", (taskId) => {
server.broadcast({ type: ServerMessageType.Data, data: { taskId } })
})
api.on("taskAskResponded", (taskId) => {
server.broadcast({ type: ServerMessageType.Data, data: { taskId } })
api.on("message", ({ taskId, action, message }) => {
server.broadcast({ type: ServerMessageType.Data, data: { event: "message", taskId, action, message } })
})
api.on("taskTokenUsageUpdated", (taskId, usage) => {
server.broadcast({ type: ServerMessageType.Data, data: { taskId, usage } })
server.broadcast({ type: ServerMessageType.Data, data: { event: "taskTokenUsageUpdated", taskId, usage } })
})
/**
@ -115,14 +119,25 @@ export async function run() {
let usage
try {
usage = await waitUntilCompleted({ api, taskId, timeout: 5 * 60 * 1_000 }) // 5m
usage = (await waitUntilCompleted({ api, taskId, timeout: 5 * 60 * 1_000 })) || api.getTokenUsage(taskId)
} catch (e: unknown) {
console.error(e)
usage = api.getTokenUsage(taskId)
console.error(e)
}
if (usage) {
const content = JSON.stringify({ runId: parseInt(runId), ...usage, duration: Date.now() - startTime }, null, 2)
await fs.writeFile(path.resolve(workspacePath, "usage.json"), content)
}
const task = await createTask({
runId,
language,
exercise,
duration: Date.now() - startTime,
tokensIn: usage.totalTokensIn,
tokensOut: usage.totalTokensOut,
tokensContext: usage.contextTokens,
cacheWrites: usage.totalCacheWrites ?? 0,
cacheReads: usage.totalCacheReads ?? 0,
cost: usage.totalCost,
passed: false,
})
await fs.writeFile(path.resolve(workspacePath, "usage.json"), JSON.stringify(task, null, 2))
}

View file

@ -189,9 +189,6 @@ importers:
drizzle-zod:
specifier: ^0.7.0
version: 0.7.0(drizzle-orm@0.40.1(@libsql/client@0.14.0)(gel@2.0.1))(zod@3.24.2)
libsql:
specifier: ^0.5.1
version: 0.5.1
zod:
specifier: ^3.24.2
version: 3.24.2
@ -227,6 +224,9 @@ importers:
packages/runner:
dependencies:
'@benchmark/db':
specifier: workspace:^
version: link:../db
'@benchmark/ipc':
specifier: workspace:^
version: link:../ipc
@ -915,21 +915,11 @@ packages:
cpu: [arm64]
os: [darwin]
'@libsql/darwin-arm64@0.5.1':
resolution: {integrity: sha512-ETWRV8+h2l1P4/BB+ct1yWoBJMokUfCLe8W7TEbGo/9mAqk4NWkacVlAJgRdVIFQsA+3/vrQF7LyaIQOSEELTg==}
cpu: [arm64]
os: [darwin]
'@libsql/darwin-x64@0.4.7':
resolution: {integrity: sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==}
cpu: [x64]
os: [darwin]
'@libsql/darwin-x64@0.5.1':
resolution: {integrity: sha512-zB1Sid7vTBt/PiiLyQmw9AXZZv3MziNRx/rJ6xc/HTUYG7c2QHwOMikVuad1Lafvvf3OyGYSAPHKg9hdvNFP9A==}
cpu: [x64]
os: [darwin]
'@libsql/hrana-client@0.7.0':
resolution: {integrity: sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==}
@ -945,51 +935,26 @@ packages:
cpu: [arm64]
os: [linux]
'@libsql/linux-arm64-gnu@0.5.1':
resolution: {integrity: sha512-RbDc3fcRH5gjg2UUsMTPncSMCqTZ6re59t4jhNFpaLb3n2raD8S3XfvMq9LFqirzK+JDKHhxRPTow0E+QLaLJQ==}
cpu: [arm64]
os: [linux]
'@libsql/linux-arm64-musl@0.4.7':
resolution: {integrity: sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==}
cpu: [arm64]
os: [linux]
'@libsql/linux-arm64-musl@0.5.1':
resolution: {integrity: sha512-JwK6Ne8dmtt+D+0zESwKvrjnylSDHNN7Mt9gb+TbWZZVvmro8n/ApvRVJh8ZO3R7dH32rUJoc2cQmKD6B691sA==}
cpu: [arm64]
os: [linux]
'@libsql/linux-x64-gnu@0.4.7':
resolution: {integrity: sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==}
cpu: [x64]
os: [linux]
'@libsql/linux-x64-gnu@0.5.1':
resolution: {integrity: sha512-9U1yo0H8OaxGsVPQFDm/SrQjhyMFUHinmfPOwQcLjcnWwv1GqfNdYlGnp2ZfdJr2QOx7k5klouJjJgy8KzhY4g==}
cpu: [x64]
os: [linux]
'@libsql/linux-x64-musl@0.4.7':
resolution: {integrity: sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==}
cpu: [x64]
os: [linux]
'@libsql/linux-x64-musl@0.5.1':
resolution: {integrity: sha512-2TEX6SJqi88wPbv1ZHiTHtqaWOf+Mj7L8jOSgQY/aMoPzV5VFtDFF68ApIUNR6L+4eMwlD28NpahwJf8ilWYIw==}
cpu: [x64]
os: [linux]
'@libsql/win32-x64-msvc@0.4.7':
resolution: {integrity: sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==}
cpu: [x64]
os: [win32]
'@libsql/win32-x64-msvc@0.5.1':
resolution: {integrity: sha512-rOtBBJhLuCeSgXBWIRNTLADdSLfwsII6za/ci5+XJKSiSi0STO4bcGEfVKLEJ6HDqdCJ2zdH1WGc9rTwhsUB0g==}
cpu: [x64]
os: [win32]
'@neon-rs/load@0.0.4':
resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==}
@ -2677,10 +2642,6 @@ packages:
resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==}
os: [darwin, linux, win32]
libsql@0.5.1:
resolution: {integrity: sha512-ePnm5zj6T//GKiTY/v5b0a272NX73hqdRORmD8gzz1nUui9051dtTt6t0XCrIqxwJAHSmQiZcfAx3YSASn9Y+A==}
os: [darwin, linux, win32]
lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
@ -4194,15 +4155,9 @@ snapshots:
'@libsql/darwin-arm64@0.4.7':
optional: true
'@libsql/darwin-arm64@0.5.1':
optional: true
'@libsql/darwin-x64@0.4.7':
optional: true
'@libsql/darwin-x64@0.5.1':
optional: true
'@libsql/hrana-client@0.7.0':
dependencies:
'@libsql/isomorphic-fetch': 0.3.1
@ -4226,33 +4181,18 @@ snapshots:
'@libsql/linux-arm64-gnu@0.4.7':
optional: true
'@libsql/linux-arm64-gnu@0.5.1':
optional: true
'@libsql/linux-arm64-musl@0.4.7':
optional: true
'@libsql/linux-arm64-musl@0.5.1':
optional: true
'@libsql/linux-x64-gnu@0.4.7':
optional: true
'@libsql/linux-x64-gnu@0.5.1':
optional: true
'@libsql/linux-x64-musl@0.4.7':
optional: true
'@libsql/linux-x64-musl@0.5.1':
optional: true
'@libsql/win32-x64-msvc@0.4.7':
optional: true
'@libsql/win32-x64-msvc@0.5.1':
optional: true
'@neon-rs/load@0.0.4': {}
'@next/env@15.2.2': {}
@ -6019,19 +5959,6 @@ snapshots:
'@libsql/linux-x64-musl': 0.4.7
'@libsql/win32-x64-msvc': 0.4.7
libsql@0.5.1:
dependencies:
'@neon-rs/load': 0.0.4
detect-libc: 2.0.2
optionalDependencies:
'@libsql/darwin-arm64': 0.5.1
'@libsql/darwin-x64': 0.5.1
'@libsql/linux-arm64-gnu': 0.5.1
'@libsql/linux-arm64-musl': 0.5.1
'@libsql/linux-x64-gnu': 0.5.1
'@libsql/linux-x64-musl': 0.5.1
'@libsql/win32-x64-msvc': 0.5.1
lie@3.3.0:
dependencies:
immediate: 3.0.6

View file

@ -5,6 +5,8 @@
"NODE_ENV",
"NEXT_RUNTIME",
"RUN_ID",
"LANGUAGE",
"EXERCISE",
"OPENROUTER_API_KEY",
"OPENROUTER_MODEL_ID",
"PROMPT_PATH",
@ -22,7 +24,7 @@
},
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"]
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
}
}
}

View file

@ -411,5 +411,6 @@
"webview-ui/**/*.{ts,tsx}": [
"npx eslint -c webview-ui/.eslintrc.json --max-warnings=0 --fix"
]
}
},
"packageManager": "pnpm@10.6.5+sha512.cdf928fca20832cd59ec53826492b7dc25dc524d4370b6b4adbf65803d32efaa6c1c88147c0ae4e8d579a6c9eec715757b50d4fa35eea179d868eada4ed043af"
}

View file

@ -2972,6 +2972,10 @@ export class Cline extends EventEmitter<ClineEvents> {
false,
)
telemetryService.captureTaskCompleted(this.taskId)
this.emit("taskCompleted", this.taskId, this.getTokenUsage())
console.log("TASK COMPLETED | event emitted")
await this.ask(
"command",
removeClosingTag("command", command),
@ -3003,9 +3007,11 @@ export class Cline extends EventEmitter<ClineEvents> {
if (command) {
if (lastMessage && lastMessage.ask !== "command") {
// Haven't sent a command message yet so
// first send completion_result then command.
// Haven't sent a command message yet so first send completion_result then command.
await this.say("completion_result", result, undefined, false)
telemetryService.captureTaskCompleted(this.taskId)
this.emit("taskCompleted", this.taskId, this.getTokenUsage())
console.log("TASK COMPLETED | event emitted")
}
// Complete command message.
@ -3027,11 +3033,11 @@ export class Cline extends EventEmitter<ClineEvents> {
commandResult = execCommandResult
} else {
await this.say("completion_result", result, undefined, false)
telemetryService.captureTaskCompleted(this.taskId)
this.emit("taskCompleted", this.taskId, this.getTokenUsage())
console.log("TASK COMPLETED | event emitted")
}
telemetryService.captureTaskCompleted(this.taskId)
this.emit("taskCompleted", this.taskId, this.getTokenUsage())
if (this.parentTask) {
const didApprove = await askFinishSubTaskApproval()

View file

@ -27,14 +27,12 @@ export class API extends EventEmitter<RooCodeEvents> implements RooCodeAPI {
cline.on("taskUnpaused", () => this.emit("taskUnpaused", cline.taskId))
cline.on("taskAskResponded", () => this.emit("taskAskResponded", cline.taskId))
cline.on("taskAborted", () => this.emit("taskAborted", cline.taskId))
cline.on("taskSpawned", (taskId) => this.emit("taskSpawned", cline.taskId, taskId))
cline.on("taskSpawned", (childTaskId) => this.emit("taskSpawned", cline.taskId, childTaskId))
cline.on("taskCompleted", (_, usage) => this.emit("taskCompleted", cline.taskId, usage))
cline.on("taskTokenUsageUpdated", (_, usage) => this.emit("taskTokenUsageUpdated", cline.taskId, usage))
})
this.on("message", ({ taskId, action, message }) => {
// if (message.type === "say") {
// console.log("message", { taskId, action, message })
// }
if (action === "created") {
this.history.add(taskId, message)
} else if (action === "updated") {