3640
3641
this._register(wrapper.onUsage(e => {
3643
>
// `agentId`. Such an event is reported twice:
3644
>
// 1. Folded into the parent turn (scope `''`) so the parent turn's
3645
>
// reported cost stays the full turn aggregate (parent + every
3646
>
// subagent), and
3647
>
// 2. Emitted to the subagent's own child session (via
3648
>
// `parentToolCallId`) carrying just that subagent's running
3649
>
// component total, so the subagent tool can show its own cost.
3650
>
// Main-agent (or unmapped subagent) events only contribute to the
3651
>
// parent aggregate.
3652
>
const parentToolCallId = this._parentToolCallIdForSubagentEvent(e);
3653
>
if (!parentToolCallId && !e.agentId && !e.data.parentToolCallId && e.data.model) {
3654
>
this._setPromptCacheState(e.data.cacheExpiresAt ? { modelId: e.data.model, cacheExpiresAt: e.data.cacheExpiresAt } : undefined);
3655
>
}
3656
>
// TODO: `copilotUsage` is marked `asInternal` in the SDK schema so it is not exposed on the generated
3657
>
// `AssistantUsageData` type, but it is present at runtime. Read it dynamically.
3658
>
const copilotUsage = (e.data as unknown as Record<string, unknown>).copilotUsage as { totalNanoAiu?: number } | undefined;
3659
>
// `quotaSnapshots` is likewise `asInternal` in the SDK schema (not on the generated type) but is
3660
>
// present at runtime. Forward the per-category snapshots on `_meta` so the client can keep the
3661
>
// account quota UI current. Mirrors the extension-host CLI path, which feeds these into its quota service.
3662
>
const quotaSnapshots = normalizeQuotaSnapshots((e.data as unknown as Record<string, unknown>).quotaSnapshots);
3663
>
const turn = this._currentTurn;
3664
>
3665
>
if (typeof e.data.model === 'string' && e.data.model) {
3666
>
this._lastSeenModelId = e.data.model;
3667
>
}
3668
>
3669
>
// This event's own context usage (the model call that produced it).
3670
>
const eventContext = {
3671
>
inputTokens: e.data.inputTokens,
3672
>
outputTokens: e.data.outputTokens,
3673
>
model: e.data.model,
3674
>
cacheReadTokens: e.data.cacheReadTokens,
3675
>
...(typeof e.data.cost === 'number' ? { cost: e.data.cost } : {}),
3676
>
};
3677
>
3678
>
// Record the parent agent's own context usage so subagent events
3679
>
// don't overwrite the model/context tokens shown for the parent turn.
3680
>
if (!parentToolCallId && turn) {
3681
turn.parentContextUsage = eventContext;
3682
}
3684
>
// Builds a usage object carrying the given context's tokens/model
3685
>
// and the running credit total for the given scope.
3686
>
const buildUsage = (scope: string, context: UsageContext): UsageInfo => {
3687
>
const metadata: UsageInfoMeta = {};
3688
>
if (typeof context.cost === 'number') {
3689
metadata.cost = context.cost;
3690
}
3692
metadata.autoModeResolved = autoModeResolved.data;
3693
}
3695
const scopedTotal = (turn.copilotUsageTotalNanoAiuByScope.get(scope) ?? 0) + copilotUsage.totalNanoAiu;
3696
turn.copilotUsageTotalNanoAiuByScope.set(scope, scopedTotal);