src/vs/platform/assignment/common/assignment.ts
200 LOC · 135 covered · 65 uncovered · 6 ranges · 198 concepts · 1 introducers · 76 tests
File neighbourhood
The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.
Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file
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 related-file, concept, and source links on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.
/*---------------------------------------------------------------------------------------------
chatServiceImpl.ts ×75
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from '../../../base/common/event.js';
import * as platform from '../../../base/common/platform.js';
import type { IExperimentationFilterProvider } from 'tas-client';
export const ASSIGNMENT_STORAGE_KEY = 'VSCode.ABExp.FeatureData';
export const ASSIGNMENT_REFETCH_INTERVAL = 60 * 60 * 1000; // 1 hour
export interface IAssignmentService {
readonly _serviceBrand: undefined;
readonly onDidRefetchAssignments: Event<void>;
getTreatment<T extends string | number | boolean>(name: string): Promise<T | undefined>;
}
export enum TargetPopulation {
Insiders = 'insider',
Public = 'public',
Exploration = 'exploration'
}
/*
Based upon the official VSCode currently existing filters in the
ExP backend for the VSCode cluster.
https://experimentation.visualstudio.com/Analysis%20and%20Experimentation/_git/AnE.ExP.TAS.TachyonHost.Configuration?path=%2FConfigurations%2Fvscode%2Fvscode.json&version=GBmaster
"X-MSEdge-Market": "detection.market",
"X-FD-Corpnet": "detection.corpnet",
"X-VSCode-AppVersion": "appversion",
"X-VSCode-Build": "build",
"X-MSEdge-ClientId": "clientid",
"X-VSCode-ExtensionName": "extensionname",
"X-VSCode-ExtensionVersion": "extensionversion",
"X-VSCode-TargetPopulation": "targetpopulation",
"X-VSCode-Language": "language",
"X-VSCode-Platform": "platform",
"X-VSCode-ReleaseDate": "releasedate",
"X-VSCode-WindowKind": "windowkind"
*/
export enum Filters {
/**
* The market in which the extension is distributed.
*/
Market = 'X-MSEdge-Market',
/**
* The corporation network.
*/
CorpNet = 'X-FD-Corpnet',
/**
* Version of the application which uses experimentation service.
*/
ApplicationVersion = 'X-VSCode-AppVersion',
/**
* Insiders vs Stable.
*/
Build = 'X-VSCode-Build',
/**
* Client Id which is used as primary unit for the experimentation.
*/
ClientId = 'X-MSEdge-ClientId',
/**
* Developer Device Id which can be used as an alternate unit for experimentation.
*/
DeveloperDeviceId = 'X-VSCode-DevDeviceId',
/**
* Extension header.
*/
ExtensionName = 'X-VSCode-ExtensionName',
/**
* The version of the extension.
*/
ExtensionVersion = 'X-VSCode-ExtensionVersion',
/**
* The language in use by VS Code
*/
Language = 'X-VSCode-Language',
/**
* The target population.
* This is used to separate internal, early preview, GA, etc.
*/
TargetPopulation = 'X-VSCode-TargetPopulation',
/**
* The platform (OS) on which VS Code is running.
*/
Platform = 'X-VSCode-Platform',
/**
* The release/build date of VS Code (UTC) in the format yyyymmddHH.
*/
ReleaseDate = 'X-VSCode-ReleaseDate',
/**
* The kind of window VS Code is running in (`editor` or `agents`).
*/
WindowKind = 'X-VSCode-WindowKind',
}
export const enum WindowKind {
Editor = 'editor',
Agents = 'agents',
}
export class AssignmentFilterProvider implements IExperimentationFilterProvider {
constructor(
private version: string,
private appName: string,
private machineId: string,
private devDeviceId: string,
private targetPopulation: TargetPopulation,
private releaseDate: string,
private windowKind: WindowKind
) { }
/**
* Returns a version string that can be parsed by the TAS client.
* The tas client cannot handle suffixes lke "-insider"
* Ref: https://github.com/microsoft/tas-client/blob/30340d5e1da37c2789049fcf45928b954680606f/vscode-tas-client/src/vscode-tas-client/VSCodeFilterProvider.ts#L35
*
* @param version Version string to be trimmed.
*/
private static trimVersionSuffix(version: string): string {
const regex = /\-[a-zA-Z0-9]+$/;
const result = version.split(regex);
return result[0];
}
getFilterValue(filter: string): string | null {
switch (filter) {
case Filters.ApplicationVersion:
return AssignmentFilterProvider.trimVersionSuffix(this.version); // productService.version
case Filters.Build:
return this.appName; // productService.nameLong
case Filters.ClientId:
return this.machineId;
case Filters.DeveloperDeviceId:
return this.devDeviceId;
case Filters.Language:
return platform.language;
case Filters.ExtensionName:
return 'vscode-core'; // always return vscode-core for exp service
case Filters.ExtensionVersion:
return '999999.0'; // always return a very large number for cross-extension experimentation
case Filters.TargetPopulation:
return this.targetPopulation;
case Filters.Platform:
return platform.PlatformToString(platform.platform);
case Filters.ReleaseDate:
return AssignmentFilterProvider.formatReleaseDate(this.releaseDate);
case Filters.WindowKind:
return this.windowKind;
default:
return '';
}
}
private static formatReleaseDate(iso: string): string {
// Expect ISO format, fall back to empty string if not provided
if (!iso) {
return '';
}
// Remove separators and milliseconds: YYYY-MM-DDTHH:MM:SS.sssZ -> YYYYMMDDHH
// Trimmed to 10 digits to fit within int32 bounds (ExP requirement)
const match = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2})/.exec(iso);
if (!match) {
return '';
}
return match.slice(1, 5).join('');
}
getFilters(): Map<string, unknown> {
const filters: Map<string, unknown> = new Map<string, unknown>();
const filterValues = Object.values(Filters);
for (const value of filterValues) {
filters.set(value, this.getFilterValue(value));
}
return filters;
}
export function getInternalOrg(organisations: string[] | undefined): 'vscode' | 'github' | 'microsoft' | undefined {
const isVSCodeInternal = organisations?.includes('Visual-Studio-Code');
const isGitHubInternal = organisations?.includes('github');
const isMicrosoftInternal = organisations?.includes('microsoft') || organisations?.includes('ms-copilot') || organisations?.includes('MicrosoftCopilot');
return isVSCodeInternal ? 'vscode' : isGitHubInternal ? 'github' : isMicrosoftInternal ? 'microsoft' : undefined;
}