agentModelPricing.ts ×7

Frontier kind: Code frontier

unlabeled · c_de0ecbde5019

384 tests · 31442 LOC · 165 files · introduces 0 tests · 192 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
8 ranges192 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2700 ranges31442 lines · 165 files · Browse complete extent
All tests (intent)
384 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.

2 files ranked by introduced lines: 192 introduced LOC across 8 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/common/agentModelPricing.ts 137 introduced LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentModelPricing.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import type { SessionModelInfo } from './state/protocol/state.js';
7 > import type { IAgentModelInfo } from './agentService.js';
8 >
9 > /**
10 > * Well-known model picker metadata carried under a model's open `_meta` bag (see {@link IAgentModelInfo._meta} /
11 > * {@link SessionModelInfo._meta}). Agents populate these keys so the chat model picker can render pricing,
12 > * capability categories, and promotions.
13 > *
14 > * All cost values are expressed as credits per 1M tokens — the same unit the model picker hover renders (see
15 > * `getModelHoverContent` in `modelPicker/modelPickerHover.ts`). Fields are optional; agents omit what they don't know.
16 > */
17 > export interface IAgentModelPricingMeta {
18 > /** Request multiplier (e.g. `1.5` rendered as "1.5x"). */
19 > readonly multiplierNumeric?: number;
20 > /** Default-tier input cost in credits per 1M tokens. */
21 > readonly inputCost?: number;
22 > /** Default-tier cached-input (read) cost in credits per 1M tokens. */
23 > readonly cacheCost?: number;
24 > /** Default-tier cache-write cost in credits per 1M tokens. */
25 > readonly cacheWriteCost?: number;
26 > /** Default-tier output cost in credits per 1M tokens. */
27 > readonly outputCost?: number;
28 > /** Long-context-tier input cost in credits per 1M tokens. */
29 > readonly longContextInputCost?: number;
30 > /** Long-context-tier cached-input (read) cost in credits per 1M tokens. */
31 > readonly longContextCacheCost?: number;
32 > /** Long-context-tier cache-write cost in credits per 1M tokens. */
33 > readonly longContextCacheWriteCost?: number;
34 > /** Long-context-tier output cost in credits per 1M tokens. */
35 > readonly longContextOutputCost?: number;
36 > /** Coarse price bucket (e.g. `low`, `medium`, `high`) for an at-a-glance tag. */
37 > readonly priceCategory?: string;
38 > /** Capability category (e.g. `lightweight`, `versatile`, `powerful`) shown in the model picker hover. */
39 > readonly category?: string;
40 > /** Whole-number percentage discount (0-100) for the synthetic `auto` model; shown as a "{n}% discount" detail. */
41 > readonly discountPercent?: number;
42 > /** Promotional information when the model is experiencing a discount. */
43 > readonly promo?: {
44 > readonly id: string;
45 > readonly discountPercent: number;
46 > readonly endsAt: string;
47 > readonly message: string;
48 > };
49 > }
50 >
51 > const NUMBER_KEYS = [
52 > 'multiplierNumeric',
53 > 'inputCost',
54 > 'cacheCost',
55 > 'cacheWriteCost',
56 > 'outputCost',
57 > 'longContextInputCost',
58 > 'longContextCacheCost',
59 > 'longContextCacheWriteCost',
60 > 'longContextOutputCost',
61 > 'discountPercent',
62 > ] as const satisfies readonly (keyof IAgentModelPricingMeta)[];
63 >
64 > /**
65 > * Reads the well-known {@link IAgentModelPricingMeta} keys from a model's open `_meta` bag, ignoring any unrelated
66 > * provider-specific keys and values of the wrong type. Returns an object containing only the keys that were present
67 > * with a valid value.
68 > */
69 > export function readAgentModelPricingMeta(model: IAgentModelInfo | SessionModelInfo): IAgentModelPricingMeta {
70 const meta = model._meta;
71 if (!meta) {
94 return result;
95 }
97 > /**
98 > * Builds a `_meta` payload from {@link IAgentModelPricingMeta}, dropping `undefined` entries. Returns `undefined` when
99 > * no model picker fields are known so callers can avoid attaching an empty `_meta` object.
100 > */
101 > export function createAgentModelPricingMeta(pricing: IAgentModelPricingMeta): Record<string, unknown> | undefined {
102 const entries = Object.entries(pricing).filter(([, value]) => value !== undefined);
103 return entries.length > 0 ? Object.fromEntries(entries) : undefined;
104 }
106 > /**
107 > * Normalizes a raw CAPI or Copilot SDK billing payload into the camelCase
108 > * {@link ICAPIModelBilling} shape that {@link createPricingMetaFromBilling} expects.
109 > * Prices are converted from the payload's billing batch to credits per million tokens.
110 > */
111 > export function normalizeCAPIBilling(raw: unknown): ICAPIModelBilling | undefined {
112 if (!raw || typeof raw !== 'object') {
113 return undefined;
160 return { multiplier, priceCategory, discountPercent, promo: normalizePromo(billing), tokenPrices };
161 }
163 function asNumber(v: unknown): number | undefined {
164 return typeof v === 'number' ? v : undefined;
165 }
167 function normalizePromo(billing: Record<string, unknown>): ICAPIModelBilling['promo'] {
168 const raw = billing.promo as Record<string, unknown> | undefined;
181 return undefined;
182 }
184 > /**
185 > * Normalized model billing shape shared by CAPI-backed agents and the Copilot SDK model list.
186 > * Raw snake_case and current SDK fields are converted at the read boundary by {@link normalizeCAPIBilling}.
187 > */
188 > export interface ICAPIModelBilling {
189 > readonly multiplier?: number;
190 > /** Coarse price bucket surfaced as a tag in the model picker hover. */
191 > readonly priceCategory?: string;
192 > /** Whole-number percentage discount (0-100) for the synthetic `auto` model; rendered as a "{n}% discount" detail. */
193 > readonly discountPercent?: number;
194 > /** Promotional info when the model is experiencing a promotional discount. */
195 > readonly promo?: {
196 > readonly id: string;
197 > readonly discountPercent: number;
198 > readonly endsAt: string;
199 > readonly message: string;
200 > };
201 > readonly tokenPrices?: {
202 > readonly contextMax?: number;
203 > readonly inputPrice?: number;
204 > readonly cachePrice?: number;
205 > readonly cacheWritePrice?: number;
206 > readonly outputPrice?: number;
207 > readonly longContext?: {
208 > readonly contextMax?: number;
209 > readonly inputPrice?: number;
210 > readonly cachePrice?: number;
211 > readonly cacheWritePrice?: number;
212 > readonly outputPrice?: number;
213 > };
214 > };
215 > }
216 >
217 > /**
218 > * Converts a CAPI model's billing payload into an {@link IAgentModelPricingMeta} `_meta` bag. Long-context costs are
219 > * only emitted when there is an actual surcharge (at least one long-context price differs from the default tier).
220 > * When emitting, any missing long-context field falls back to the default-tier value so the hover table renders
221 > * complete rows. See {@link hasLongContextSurcharge} for the surcharge detection logic.
222 > *
223 > * @param billing - The model's billing info, narrowed through {@link ICAPIModelBilling}.
224 > * @param priceCategory - An optional override for the price category (e.g. from `modelPickerPriceCategory` on the
225 > * model object itself). Falls back to `billing.priceCategory` when not provided.
226 > * @param category - The model's capability category from its top-level `modelPickerCategory` field.
227 > */
228 > export function createPricingMetaFromBilling(billing: ICAPIModelBilling | undefined, priceCategory?: string, category?: string): Record<string, unknown> | undefined {
229 const tokenPrices = billing?.tokenPrices;
230 const longContext = tokenPrices?.longContext;
257 });
258 }
260 > /**
261 > * Whether the model's long-context tier has any cost that differs from its default tier.
262 > * Used to decide whether to show a context-size picker (surcharge → user opts in) or to
263 > * silently use the full context window for free.
264 > */
265 > export function hasLongContextSurcharge(billing: ICAPIModelBilling | undefined): boolean {
266 const tokenPrices = billing?.tokenPrices;
267 const longContext = tokenPrices?.longContext;
src/vs/platform/agentHost/common/agentPluginManager.ts 55 introduced LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentPluginManager.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { URI } from '../../../base/common/uri.js';
7 > import { createDecorator } from '../../instantiation/common/instantiation.js';
8 > import type { ClientPluginCustomization, PluginCustomization } from './state/sessionState.js';
9 >
10 > export const IAgentPluginManager = createDecorator<IAgentPluginManager>('agentPluginManager');
11 >
12 > /**
13 > * A synced customization with its local plugin directory (when available).
14 > */
15 > export interface ISyncedCustomization {
16 > /** The session customization with loading/error status. */
17 > readonly customization: PluginCustomization;
18 > /** Local plugin directory URI, defined when the sync was successful. */
19 > readonly pluginDir?: URI;
20 > }
21 >
22 > /**
23 > * Manages Open Plugin directories for agent backends.
24 > *
25 > * Shared across agents and sessions. Syncs client-provided customization
26 > * references to local disk, tracking nonces to avoid redundant copies.
27 > * Concurrent syncs of the same plugin URI are serialized internally.
28 > */
29 > export interface IAgentPluginManager {
30 > readonly _serviceBrand: undefined;
31 >
32 > /**
33 > * Root directory under which all agent plugin data is materialized.
34 > * Exposed so other host-side components can carve out sibling
35 > * directories for their own bundles (e.g. session-discovered
36 > * customizations) without having to thread `userDataPath` separately.
37 > */
38 > readonly basePath: URI;
39 >
40 > /**
41 > * Syncs a set of client-provided plugin customizations to local storage.
42 > *
43 > * Each plugin is copied to a local directory, respecting nonce-based
44 > * caching. The optional {@link progress} callback fires with the single
45 > * customization that completed or failed, allowing callers to publish
46 > * targeted incremental status updates.
47 > *
48 > * Concurrent calls for the same plugin URI are serialized so that
49 > * overlapping syncs do not clobber each other.
50 > *
51 > * @returns Final status for every customization, with `pluginDir`
52 > * defined when the sync was successful.
53 > */
54 > syncCustomizations(clientId: string, customizations: ClientPluginCustomization[], progress?: (status: PluginCustomization) => void): Promise<ISyncedCustomization[]>;
55 > }