fix(voice): validate Codex OAuth and report unknown usage

This commit is contained in:
devv-shayan committed 2026-09-27 21:09:26 +05:00
1 parent 881e24485c
commit a398a25934
8 files changed
+265 -19

No files matched your search

+14 -3
View File
@@ -3194,18 +3194,29 @@ test('F1: the toggle still records the next-session preference while live', () =
assert.match(ui.tierButton.title, /this session stays on/i);
});
test('OAuth cloud sessions hide API spend and do not trip the API spend guard', () => {
test('OAuth cloud sessions report unknown cost and usage without tripping the API spend guard', () => {
const { controller, ui } = costControllerHarness();
controller.status = 'listening';
controller._cost.cloudVoiceAuth = 'oauth';
controller._cost.sessionCloudVoiceAuth = 'oauth';
controller.syncCostUi();
const before = controller.costTracker.state();
assert.equal(ui.costValue.hidden, true);
assert.equal(controller.recordUsage(usdUsage(100)), null);
assert.equal(ui.costValue.hidden, false);
assert.equal(ui.costValue.textContent, 'COST UNKNOWN');
assert.deepEqual(controller.recordUsage(usdUsage(100)), {
responses: 1,
input: 0,
output: 1562500,
costKnown: false,
});
const after = controller.costTracker.state();
assert.equal(after.totalUsd, before.totalUsd);
assert.equal(controller.costCapStopped, false);
assert.match(ui.costValue.title, /1 response\(s\).*1562500 output tokens/);
controller.dc = {};
controller.responseActive = true;
controller.stop();
assert.match(ui.costValue.title, /Usage is incomplete/);
});
test('F1: when idle, toggling does re-price the preview meter', () => {
+4 -1
View File
@@ -239,7 +239,10 @@ export class GevRealtimeController extends RealtimeFacade {
status: this.status,
connection: this.connectionDiagnostics(),
});
if (this.dc && this.responseActive) this.costTracker.markIncomplete();
if (this.dc && this.responseActive) {
this.costTracker.markIncomplete();
this.syncCostUi();
}
this._connection.closeTransport();
this.stopVoiceVisualizer();
this._connection.releaseMedia();
+25 -2
View File
@@ -19,6 +19,7 @@ export class RealtimeCost {
this.voiceLimits = readStoredVoiceLimits();
this.cloudVoiceAuth = readStoredCloudVoiceAuthMode();
this.sessionCloudVoiceAuth = null;
this.oauthUsage = { responses: 0, input: 0, output: 0 };
this.costTracker = createVoiceCostTracker({
tier: this.voiceTier,
limits: this.voiceLimits,
@@ -60,7 +61,20 @@ export class RealtimeCost {
}
if (this.ui?.costValue) {
const liveAuth = this.sessionCloudVoiceAuth || this.cloudVoiceAuth;
this.ui.costValue.hidden = liveAuth === 'oauth';
if (liveAuth === 'oauth') {
const { responses, input, output } = this.oauthUsage;
this.ui.costValue.hidden = false;
this.ui.costValue.textContent = 'COST UNKNOWN';
this.ui.costValue.dataset.level = 'unknown';
this.ui.costValue.title =
`ChatGPT OAuth session: ${responses} response(s), ${input} input and ${output} output tokens reported. ` +
'USD cost and the API spend cap are unavailable for this auth mode.' +
(state.incomplete
? ' Usage is incomplete because a response was still in flight when the session ended.'
: '');
return;
}
this.ui.costValue.hidden = false;
this.ui.costValue.textContent = state.display;
this.ui.costValue.dataset.level = state.level;
this.ui.costValue.title =
@@ -141,7 +155,15 @@ export class RealtimeCost {
*/
recordUsage(usage) {
if (!usage) return null;
if (this.sessionCloudVoiceAuth === 'oauth') return null;
if (this.sessionCloudVoiceAuth === 'oauth') {
const count = (value) =>
Number.isFinite(value) && value > 0 ? value : 0;
this.oauthUsage.responses += 1;
this.oauthUsage.input += count(usage.input_tokens);
this.oauthUsage.output += count(usage.output_tokens);
this.syncCostUi();
return { ...this.oauthUsage, costKnown: false };
}
const state = this.costTracker.record(usage);
this.syncCostUi();
if (state.warnCrossed) {
@@ -198,6 +220,7 @@ export class RealtimeCost {
this.voiceLimits = readStoredVoiceLimits();
this.cloudVoiceAuth = readStoredCloudVoiceAuthMode();
this.sessionCloudVoiceAuth = this.cloudVoiceAuth;
this.oauthUsage = { responses: 0, input: 0, output: 0 };
this.costCapStopped = false;
// Provisional meter (tier-priced) so the readout shows $0.00 while
// connecting. It is REPLACED below with one bound to the model the server