VS Code Treatment Assignment Service (TAS) Client
The `vscode-tas-client` package facilitates A/B experimentation within Visual Studio Code extensions by providing an interface to query and store experiment information from the Microsoft Treatment Assignment Service (TAS). As of version 0.1.86, it is specifically designed for integration with VS Code's extension host environment, leveraging `vscode.Memento` for caching experiment data and `IExperimentationTelemetry` for structured telemetry reporting, including GDPR-classified counterfactual logging. The package manages background refreshes of treatment variables every 30 minutes and offers both synchronous and asynchronous methods for service initialization and variable retrieval, allowing extensions to control data freshness and startup performance. Its core differentiation lies in its tight integration with the VS Code ecosystem, handling aspects like user population targeting, telemetry, and persistence seamlessly for extension developers. The release cadence is typically tied to internal Microsoft development cycles, often aligning with VS Code's own updates.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'globalState')
cause The `memento` argument passed to `getExperimentationService` or `getExperimentationServiceAsync` was `undefined` or not a valid `vscode.Memento` instance. This typically occurs when the package is used outside of a VS Code extension's `activate` context or `context.globalState` is not properly provided.fixEnsure your extension's `activate` function correctly receives `vscode.ExtensionContext` and that `context.globalState` is passed as the `memento` argument to the experimentation service initialization function. -
TypeError: experimentationService.getTreatmentVariableAsync is not a function
cause Attempting to call `getTreatmentVariableAsync` on an `IExperimentationService` instance that was not properly awaited during its acquisition, or attempting to use `getTreatmentVariableAsync` on an outdated version of the service.fixAlways use `await getExperimentationServiceAsync(...)` to get the service instance. Ensure you are calling `getTreatmentVariableAsync` on the `IExperimentationService` instance, not a raw promise or an uninitialized object. Verify your package version supports the async method. -
Telemetry Event: query-expfeature {...} (but no expected experiment data)cause The telemetry event `query-expfeature` is sent, but the associated common properties (`vscode.abexp.features` or `abexp.assignmentcontext`) or the expected treatment variable values are missing or are default values, indicating the experiment data was not successfully loaded.fixVerify that `getExperimentationServiceAsync` was used for initialization. Check network connectivity to TAS and ensure your `extensionName`, `extensionVersion`, and `targetPopulation` are correctly configured, as these are used for traffic filtering.
Warnings
- gotcha Using `getExperimentationService` (synchronous) instead of `getExperimentationServiceAsync` for initial service acquisition might lead to experiment values not being immediately available from cache, potentially serving default values until a background refresh or manual initialization completion. This can result in users not being assigned to the correct experiment group on first run.
- gotcha Subsequent calls to `experimentationService.getTreatmentVariable(configId, name)` within the same user session will consistently return the *cached* value obtained during the first call or initialization. This design choice prevents unexpected mid-session user experience changes, even if a background refresh has occurred and new values are available in the cache.
- gotcha The `vscode-tas-client` package makes HTTP requests to the TAS server initially upon service acquisition and then periodically every 30 minutes for background refreshes. Extensions operating in environments with strict network policies, offline modes, or limited connectivity should account for this network activity.
- gotcha This package is specifically designed for use within the VS Code extension host environment. It relies heavily on VS Code API objects like `vscode.Memento` (via `context.globalState`) and expects an `IExperimentationTelemetry` implementation. Attempting to use it in a standalone Node.js application, browser, or other non-VS Code contexts will lead to runtime errors.
Install
-
npm install vscode-tas-client -
yarn add vscode-tas-client -
pnpm add vscode-tas-client
Imports
- getExperimentationService
const getExperimentationService = require('vscode-tas-client').getExperimentationService;import { getExperimentationService } from 'vscode-tas-client'; - getExperimentationServiceAsync
const getExperimentationServiceAsync = require('vscode-tas-client').getExperimentationServiceAsync;import { getExperimentationServiceAsync } from 'vscode-tas-client'; - IExperimentationService
import IExperimentationService from 'vscode-tas-client';
import { IExperimentationService } from 'vscode-tas-client'; - TargetPopulation
const TargetPopulation = require('vscode-tas-client').TargetPopulation;import { TargetPopulation } from 'vscode-tas-client'; - IExperimentationTelemetry
type IExperimentationTelemetry = any;
import { IExperimentationTelemetry } from 'vscode-tas-client';
Quickstart
import * as vscode from 'vscode';
import {
getExperimentationServiceAsync,
TargetPopulation,
IExperimentationService,
IExperimentationTelemetry,
} from 'vscode-tas-client';
// A mock implementation for IExperimentationTelemetry to satisfy the interface.
// In a real extension, you would likely use VS Code's built-in telemetry reporter.
class MockTelemetry implements IExperimentationTelemetry {
public commonProperties: Record<string, string> = {};
setCommonProperties(properties: Record<string, string>): void {
this.commonProperties = { ...this.commonProperties, ...properties };
}
postEvent(eventName: string, props?: Record<string, any>): void {
console.log(`Telemetry Event: ${eventName}`, { ...this.commonProperties, ...props });
}
dispose(): void {
// No-op for mock telemetry
}
}
export async function activate(context: vscode.ExtensionContext) {
console.log('Extension "my-experiment-extension" is active!');
const extensionName = 'my-experiment-extension';
const extensionVersion = '1.0.0';
// Determine the target population based on user settings or environment
const targetPopulation = process.env.VSCODE_INSIDERS === 'true' ? TargetPopulation.Insiders : TargetPopulation.Public;
const telemetry = new MockTelemetry();
const memento = context.globalState;
let experimentationService: IExperimentationService;
try {
// Initialize the experimentation service asynchronously to ensure cached data is loaded.
experimentationService = await getExperimentationServiceAsync(
extensionName,
extensionVersion,
targetPopulation,
telemetry,
memento
);
console.log('Experimentation service initialized.');
// Query a treatment variable. 'vscode' is the standard configId.
const myFeatureToggleValue = experimentationService.getTreatmentVariable('vscode', 'myFeatureToggle');
console.log(`Value for 'myFeatureToggle': ${myFeatureToggleValue}`);
// If you need to force a refresh and get the very latest value from TAS,
// use getTreatmentVariableAsync. This will trigger a network request.
const latestMyFeatureToggleValue = await experimentationService.getTreatmentVariableAsync('vscode', 'myFeatureToggle');
console.log(`Latest value for 'myFeatureToggle' after refresh: ${latestMyFeatureToggleValue}`);
} catch (error) {
console.error('Failed to initialize experimentation service:', error);
}
}
// Standard VS Code extension deactivate function.
export function deactivate() {
console.log('Extension "my-experiment-extension" is deactivating!');
}