Files
anomalyco_opencode/packages/opencode/script/bench-session-usage-migration.ts
T
2026-05-10 23:09:33 -04:00

141 lines
4.9 KiB
TypeScript

#!/usr/bin/env bun
import { rmSync } from "fs"
import path from "path"
import { Effect, ManagedRuntime } from "effect"
import { eq } from "drizzle-orm"
const args = new Map(
Bun.argv.slice(2).flatMap((arg) => {
const match = /^--([^=]+)=(.*)$/.exec(arg)
return match ? [[match[1], match[2]] as const] : []
}),
)
const sessions = Number(args.get("sessions") ?? 10_000)
const messages = Number(args.get("messages") ?? 20)
const batch = Number(args.get("batch") ?? 1_000)
const dbPath = path.resolve(args.get("db") ?? path.join("/tmp", "opencode-session-usage-bench.db"))
const keep = args.get("keep") === "true"
if (!keep) rmSync(dbPath, { force: true })
process.env.OPENCODE_DB = dbPath
const started = performance.now()
const [{ Database }, { SessionTable, MessageTable }] = await Promise.all([
import("../src/storage/db"),
import("../src/session/session.sql"),
])
const now = Date.now()
const expectedCost = sessions * messages * 0.001
const db = Database.Client().$client
console.log(`database: ${dbPath}`)
console.log(`seed: ${sessions.toLocaleString()} sessions x ${messages.toLocaleString()} assistant messages`)
db.transaction(() => {
db.query(
`INSERT INTO project (id, worktree, vcs, name, icon_url, icon_url_override, icon_color, time_created, time_updated, time_initialized, sandboxes, commands)
VALUES ($id, $worktree, NULL, $name, NULL, NULL, NULL, $time, $time, $time, $sandboxes, NULL)`,
).run({
$id: "global",
$worktree: process.cwd(),
$name: "bench",
$time: now,
$sandboxes: JSON.stringify([]),
})
})()
const insertSession = db.query(
`INSERT INTO session (
id, project_id, workspace_id, parent_id, slug, directory, path, title, version, share_url,
summary_additions, summary_deletions, summary_files, summary_diffs, cost,
tokens_input, tokens_output, tokens_reasoning, tokens_cache_read, tokens_cache_write,
revert, permission, agent, model, time_created, time_updated, time_compacting, time_archived
) VALUES (
$id, 'global', NULL, NULL, $slug, $directory, $path, $title, 'bench', NULL,
NULL, NULL, NULL, NULL, 0,
0, 0, 0, 0, 0,
NULL, NULL, NULL, NULL, $time, $time, NULL, NULL
)`,
)
const insertMessage = db.query(
`INSERT INTO message (id, session_id, time_created, time_updated, data)
VALUES ($id, $session, $time, $time, $data)`,
)
for (let offset = 0; offset < sessions; offset += batch) {
const end = Math.min(offset + batch, sessions)
db.transaction(() => {
for (let i = offset; i < end; i++) {
const sessionID = `ses_bench_${i.toString().padStart(8, "0")}`
insertSession.run({
$id: sessionID,
$slug: `bench-${i}`,
$directory: process.cwd(),
$path: ".",
$title: `Bench ${i}`,
$time: now + i,
})
for (let j = 0; j < messages; j++) {
insertMessage.run({
$id: `msg_bench_${i.toString().padStart(8, "0")}_${j.toString().padStart(4, "0")}`,
$session: sessionID,
$time: now + i + j,
$data: JSON.stringify({
role: "assistant",
time: { created: now + i + j, completed: now + i + j + 1 },
parentID: `msg_parent_${i.toString().padStart(8, "0")}_${j.toString().padStart(4, "0")}`,
modelID: "bench-model",
providerID: "bench-provider",
mode: "build",
agent: "bench",
path: { cwd: process.cwd(), root: process.cwd() },
cost: 0.001,
tokens: { input: 100, output: 50, reasoning: 10, cache: { read: 5, write: 2 } },
}),
})
}
}
})()
console.log(`seeded ${end.toLocaleString()} sessions`)
}
console.log(`seed time: ${Math.round(performance.now() - started).toLocaleString()}ms`)
const [{ DataMigration }, { DataMigrationTable }] = await Promise.all([
import("../src/data-migration"),
import("../src/data-migration.sql"),
])
const runtime = ManagedRuntime.make(DataMigration.defaultLayer)
const migrationStarted = performance.now()
await runtime.runPromise(Effect.gen(function* () {
return yield* DataMigration.Service
}))
for (;;) {
const completed = Database.use((db) =>
db
.select({ name: DataMigrationTable.name })
.from(DataMigrationTable)
.where(eq(DataMigrationTable.name, "session_usage_from_messages"))
.get(),
)
if (completed) break
await Bun.sleep(100)
}
const migrationMs = performance.now() - migrationStarted
const totals = db
.query(`SELECT COUNT(*) AS sessions, SUM(cost) AS cost, SUM(tokens_input) AS input FROM session`)
.get() as { sessions: number; cost: number; input: number }
await runtime.dispose()
Database.close()
console.log(`migration time: ${Math.round(migrationMs).toLocaleString()}ms`)
console.log(`total time: ${Math.round(performance.now() - started).toLocaleString()}ms`)
console.log(`result: ${totals.sessions.toLocaleString()} sessions, cost=${totals.cost}, input=${totals.input}`)
console.log(`expected: cost=${expectedCost}, input=${sessions * messages * 100}`)