mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-22 22:01:18 +00:00
feat: add cache-aware token usage dashboard (#1338)
* feat: add cache-aware token usage dashboard Track normalized Claude, Codex, and ACP usage with incremental SQLite backfill. Exclude imported transcript history, rebuild usage after history rewrites, and expose an owner-only dashboard with cache-aware totals and breakdowns. via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix: preserve usage model and local dates via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix: normalize cached usage and timezone buckets via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> --------- Co-authored-by: HAPI <noreply@hapi.run>
This commit is contained in:
@@ -36,6 +36,16 @@ function extractTurnContextReasoningEffort(event: CodexSessionEvent): ReasoningE
|
||||
return effort.trim().toLowerCase();
|
||||
}
|
||||
|
||||
function extractTurnContextModel(event: CodexSessionEvent): string | null | undefined {
|
||||
if (event.type !== 'turn_context' || !event.payload || typeof event.payload !== 'object') {
|
||||
return undefined;
|
||||
}
|
||||
const model = (event.payload as Record<string, unknown>).model;
|
||||
if (model === null) return null;
|
||||
if (typeof model !== 'string' || !model.trim()) return undefined;
|
||||
return model.trim();
|
||||
}
|
||||
|
||||
export async function codexLocalLauncher(session: CodexSession): Promise<'switch' | 'exit'> {
|
||||
const resumeSessionId = session.sessionId;
|
||||
let primarySessionId = resumeSessionId;
|
||||
@@ -47,6 +57,7 @@ export async function codexLocalLauncher(session: CodexSession): Promise<'switch
|
||||
let transcriptLocator: CodexTranscriptLocator | null = null;
|
||||
let scannerTranscriptPath: string | null = null;
|
||||
let scannerReplayedExistingHistory = false;
|
||||
let transcriptModel: string | null = null;
|
||||
const pendingPlansByTurnId = new Map<string, ProposedPlanMessage>();
|
||||
const pendingExecWrappers = new Map<string, PendingExecWrapper>();
|
||||
const toolHookBridge = new CodexToolHookBridge();
|
||||
@@ -202,7 +213,11 @@ export async function codexLocalLauncher(session: CodexSession): Promise<'switch
|
||||
}
|
||||
session.onSessionFound(sessionId);
|
||||
},
|
||||
onEvent: (event) => {
|
||||
onEvent: (event, context) => {
|
||||
const observedModel = extractTurnContextModel(event);
|
||||
if (observedModel !== undefined) {
|
||||
transcriptModel = observedModel;
|
||||
}
|
||||
const observedReasoningEffort = extractTurnContextReasoningEffort(event);
|
||||
if (observedReasoningEffort !== undefined) {
|
||||
session.setModelReasoningEffort(observedReasoningEffort);
|
||||
@@ -242,7 +257,20 @@ export async function codexLocalLauncher(session: CodexSession): Promise<'switch
|
||||
flushPendingExecWrapper(message.callId, message);
|
||||
}
|
||||
} else {
|
||||
session.sendAgentMessage(message);
|
||||
const scopedMessage = message.type !== 'token_count'
|
||||
? message
|
||||
: context.replayedHistory
|
||||
? { ...message, model: transcriptModel, hapiUsageScope: 'imported-history' }
|
||||
: primarySessionId
|
||||
? {
|
||||
...message,
|
||||
model: transcriptModel,
|
||||
threadId: primarySessionId,
|
||||
thread_id: primarySessionId,
|
||||
hapiUsageScope: 'managed'
|
||||
}
|
||||
: { ...message, model: transcriptModel };
|
||||
session.sendAgentMessage(scopedMessage);
|
||||
}
|
||||
}
|
||||
if (converted?.finishedTurnId) {
|
||||
|
||||
Reference in New Issue
Block a user