copilotAgentSession.ts ×15

Frontier kind: Code frontier

unlabeled · c_a0044a646196

7 tests · 43868 LOC · 243 files · introduces 0 tests · 112 LOC · 3 files

Introduces — evidence that enters the hierarchy at this concept

Code
19 ranges112 lines · 3 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
4030 ranges43868 lines · 243 files · Browse complete extent
All tests (intent)
7 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

3 files ranked by introduced lines: 112 introduced LOC across 19 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts 105 introduced LOC · 15 ranges

Open complete file

1314
1315 private _setPromptCacheState(promptCache: { readonly modelId: string; readonly cacheExpiresAt: string } | undefined): void {
1316 > const currentMeta = this._stateManager.getSessionSummary(this.sessionUri.toString())?._meta; copilotAgentSession.ts
1317 > this._stateManager.setSessionMeta(this.sessionUri.toString(), withSessionPromptCacheState(currentMeta, promptCache));
1318 > }
1319
1320 private _createRuntimeAdapter(): ICopilotSessionRuntime {
3640
3641 this._register(wrapper.onUsage(e => {
3642 > // Usage events for a subagent's model calls carry the subagent's copilotAgentSession.ts
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 }
3691 > if (scope === '' && autoModeResolved?.turnId === this._turnId) { copilotAgentSession.ts
3692 metadata.autoModeResolved = autoModeResolved.data;
3693 }
3694 > if (turn && typeof copilotUsage?.totalNanoAiu === 'number') { copilotAgentSession.ts
3695 const scopedTotal = (turn.copilotUsageTotalNanoAiuByScope.get(scope) ?? 0) + copilotUsage.totalNanoAiu;
3696 turn.copilotUsageTotalNanoAiuByScope.set(scope, scopedTotal);
3700 };
3701 }
3702 > if (quotaSnapshots) { copilotAgentSession.ts
3703 metadata.quotaSnapshots = quotaSnapshots;
3704 }
3705 > return { copilotAgentSession.ts
3706 > inputTokens: context.inputTokens,
3707 > outputTokens: context.outputTokens,
3708 > model: context.model,
3709 > cacheReadTokens: context.cacheReadTokens,
3710 > ...(Object.keys(metadata).length > 0 ? { _meta: metadata } : {}),
3711 > };
3712 > };
3713 >
3714 > // Parent turn aggregate (scope `''`): every model call contributes
3715 > // its credits, but a subagent event must not replace the parent
3716 > // turn's own model/context-token usage. Fold subagent credits into
3717 > // the parent aggregate while preserving the parent's context.
3718 > const parentContext = parentToolCallId ? (turn?.parentContextUsage ?? {}) : eventContext;
3719 > const parentUsage = buildUsage('', parentContext);
3720 > lastParentUsage = parentUsage;
3721 > lastParentUsageTurnId = this._turnId;
3722 > this._emitAction({
3723 > type: ActionType.ChatUsage,
3724 > turnId: this._turnId,
3725 > usage: parentUsage,
3726 > });
3727 >
3728 > // Subagent component: additionally report the subagent's own running
3729 > // total to its child session.
3730 > if (parentToolCallId) {
3731 this._emitAction({
3732 type: ActionType.ChatUsage,
3742 // the widget picks up the detailed breakdown on the next render cycle.
3743 this._register(wrapper.onUsage(async e => {
3744 > // Only enrich the parent-turn aggregate (not subagent scopes). copilotAgentSession.ts
3745 > if (this._parentToolCallIdForSubagentEvent(e)) {
3746 return;
3747 }
3748 > const turnId = this._turnId; copilotAgentSession.ts
3749 > // Capture the base usage before the await boundary so concurrent
3750 > // usage events don't overwrite what we merge into.
3751 > const baseUsage = lastParentUsageTurnId === turnId ? lastParentUsage : undefined;
3752 > const usage: UsageInfo = baseUsage ?? {
3753 inputTokens: e.data.inputTokens,
3754 outputTokens: e.data.outputTokens,
3756 cacheReadTokens: e.data.cacheReadTokens,
3757 };
3758 > try { copilotAgentSession.ts
3759 > const result = await this._wrapper.session.rpc.metadata.getContextAttribution();
3760 const attribution = result?.contextAttribution;
3761 > if (!attribution || !turnId) { copilotAgentSession.ts
3762 this._logService.trace(`[Copilot:${sessionId}] contextAttribution: null/empty (turnId=${turnId})`);
3763 return;
3770 // Guard against a newer usage event having arrived while we
3771 // were awaiting — only enrich if baseUsage is still current.
3772 > if (usage !== lastParentUsage || lastParentUsageTurnId !== turnId) { copilotAgentSession.ts
3773 return;
3774 }
3782 _meta: {
3783 ...(usage._meta ?? {}),
3784 > contextAttribution: attribution, copilotAgentSession.ts
3785 > },
3786 > };
3787 > lastParentUsage = enriched;
3788 > lastParentUsageTurnId = turnId;
3789 > this._emitAction({
3790 > type: ActionType.ChatUsage,
3791 > turnId,
3792 > usage: enriched,
3793 > });
3794 > } catch (err) {
3795 > this._logService.trace(`[Copilot:${sessionId}] contextAttribution RPC failed: ${(err as Error)?.message ?? err}`);
3796 > }
3797 }));
3798
4632 * carried on {@link UsageInfoMeta.quotaSnapshots}. Returns `undefined` when no usable snapshot is present.
4633 */
4634 > function normalizeQuotaSnapshots(raw: unknown): UsageInfoMeta['quotaSnapshots'] | undefined { copilotAgentSession.ts
4635 > if (!raw || typeof raw !== 'object') {
4636 return undefined;
4637 }
src/vs/platform/agentHost/common/state/sessionState.ts 5 introduced LOC · 3 ranges

Open complete file

1067 /** Returns session metadata with the prompt-cache slot updated or removed. */
1068 export function withSessionPromptCacheState(meta: SessionMeta | undefined, promptCache: ISessionPromptCacheState | undefined): SessionMeta | undefined {
1069 > const next: SessionMeta = { ...meta }; sessionState.ts
1070 > if (promptCache) {
1071 next[SESSION_META_PROMPT_CACHE_KEY] = promptCache;
1072 > } else { sessionState.ts
1073 delete next[SESSION_META_PROMPT_CACHE_KEY];
1074 }
1075 > return Object.keys(next).length > 0 ? next : undefined; sessionState.ts
1076 > }
1077
1078 /**
src/vs/platform/agentHost/node/agentHostStateManager.ts 2 introduced LOC · 1 range

Open complete file

1203 resultingState = newState;
1204 } else if (!isAhpChatChannel(key)) {
1205 > this._logService.warn(`[AgentHostStateManager] Action for unknown session: ${key}, type=${action.type}`); agentHostStateManager.ts
1206 > }
1207 }
1208