mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-31 09:25:32 +08:00
fix: refine token usage reporting (#807)
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
import { spawn } from 'child_process';
|
||||
import fsSync from 'node:fs';
|
||||
|
||||
import crossSpawn from 'cross-spawn';
|
||||
import Database from 'better-sqlite3';
|
||||
|
||||
import { sessionsService } from './modules/providers/services/sessions.service.js';
|
||||
import { providerAuthService } from './modules/providers/services/provider-auth.service.js';
|
||||
import { providerModelsService } from './modules/providers/services/provider-models.service.js';
|
||||
import { notifyRunFailed, notifyRunStopped } from './services/notification-orchestrator.js';
|
||||
import { createNormalizedMessage } from './shared/utils.js';
|
||||
import { createNormalizedMessage, getOpenCodeDatabasePath } from './shared/utils.js';
|
||||
|
||||
const spawnFunction = process.platform === 'win32' ? crossSpawn : spawn;
|
||||
|
||||
@@ -20,6 +22,66 @@ function readOpenCodeSessionId(event) {
|
||||
return event.sessionID || event.sessionId || null;
|
||||
}
|
||||
|
||||
function readOpenCodeTokenUsage(sessionId) {
|
||||
const dbPath = getOpenCodeDatabasePath();
|
||||
if (!sessionId || !fsSync.existsSync(dbPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let db = null;
|
||||
try {
|
||||
db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
||||
const columns = db.prepare('PRAGMA table_info(session)').all();
|
||||
const columnNames = new Set(columns.map((column) => column.name));
|
||||
const requiredColumns = ['tokens_input', 'tokens_output', 'tokens_reasoning', 'tokens_cache_read', 'tokens_cache_write'];
|
||||
if (!requiredColumns.every((column) => columnNames.has(column))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const row = db.prepare(`
|
||||
SELECT
|
||||
tokens_input AS inputTokens,
|
||||
tokens_output AS outputTokens,
|
||||
tokens_reasoning AS reasoningTokens,
|
||||
tokens_cache_read AS cacheReadTokens,
|
||||
tokens_cache_write AS cacheWriteTokens
|
||||
FROM session
|
||||
WHERE id = ?
|
||||
`).get(sessionId);
|
||||
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const inputTokens = Number(row.inputTokens || 0) + Number(row.cacheReadTokens || 0);
|
||||
const outputTokens = Number(row.outputTokens || 0);
|
||||
const used = Number(row.inputTokens || 0)
|
||||
+ outputTokens
|
||||
+ Number(row.reasoningTokens || 0)
|
||||
+ Number(row.cacheReadTokens || 0)
|
||||
+ Number(row.cacheWriteTokens || 0);
|
||||
if (used <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
used,
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
breakdown: {
|
||||
input: inputTokens,
|
||||
output: outputTokens,
|
||||
},
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
} finally {
|
||||
if (db) {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function spawnOpenCode(command, options = {}, ws) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { sessionId, projectPath, cwd, model, sessionSummary } = options;
|
||||
@@ -183,6 +245,17 @@ async function spawnOpenCode(command, options = {}, ws) {
|
||||
stdoutLineBuffer = '';
|
||||
}
|
||||
|
||||
const tokenBudget = readOpenCodeTokenUsage(finalSessionId);
|
||||
if (tokenBudget) {
|
||||
ws.send(createNormalizedMessage({
|
||||
kind: 'status',
|
||||
text: 'token_budget',
|
||||
tokenBudget,
|
||||
sessionId: finalSessionId,
|
||||
provider: 'opencode',
|
||||
}));
|
||||
}
|
||||
|
||||
ws.send(createNormalizedMessage({
|
||||
kind: 'complete',
|
||||
exitCode: code,
|
||||
|
||||
Reference in New Issue
Block a user