agentHostRestrictedTelemetry.ts ×13

Frontier kind: Code frontier

unlabeled · c_eb02be2af888

937 tests · 3535 LOC · 20 files · introduces 0 tests · 132 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
13 ranges132 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
496 ranges3535 lines · 20 files · Browse complete extent
All tests (intent)
937 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.

1 file ranked by introduced lines: 132 introduced LOC across 13 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/node/agentHostRestrictedTelemetry.ts 132 introduced LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentHostRestrictedTelemetry.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 { generateUuid } from '../../../base/common/uuid.js';
7 > import { ILogService } from '../../log/common/log.js';
8 > import { ICommonProperties } from '../../telemetry/common/telemetry.js';
9 >
10 > /**
11 > * Public GitHub Copilot telemetry ingestion keys. These are instrumentation keys, not
12 > * secrets; the iKey selects the destination hydro table:
13 > * - standard -> `copilot_v0_copilot_event`
14 > * - enhanced -> `copilot_v0_restricted_copilot_event`
15 > */
16 > const GH_STANDARD_IKEY = '7d7048df-6dd0-4048-bb23-b716c1461f8f';
17 > const GH_ENHANCED_IKEY = '3fdd7f28-937a-48c8-9a21-ba337db23bd1';
18 >
19 > /**
20 > * Fallback Copilot telemetry endpoint (the dotcom value of the CAPI token's
21 > * `endpoints.telemetry`, with the `/telemetry` path the Copilot CLI/runtime appends).
22 > * Used until {@link IAgentHostRestrictedTelemetry.setRestrictedTelemetryEndpoint} supplies
23 > * the user's discovered endpoint (dotcom, GHE, or proxy). Accepts unauthenticated POSTs.
24 > */
25 > const GH_TELEMETRY_URL = 'https://copilot-telemetry.githubusercontent.com/telemetry';
26 >
27 > /** Event names are namespaced by client category; the CTS name filter requires this. */
28 > const NAMESPACE = 'copilot-chat';
29 >
30 > export type TelemetryProps = Record<string, string | undefined>;
31 > export type TelemetryMeasurements = Record<string, number | undefined>;
32 >
33 > export interface IAgentHostInternalTelemetryContext {
34 > readonly isInternal: boolean;
35 > readonly trackingId: string | undefined;
36 > readonly userName: string | undefined;
37 > readonly isVscodeTeamMember: boolean;
38 > }
39 >
40 > export interface IAgentHostRestrictedTelemetryContext extends IAgentHostInternalTelemetryContext {
41 > readonly restrictedTelemetryEnabled: boolean;
42 > readonly telemetryEndpoint: string | undefined;
43 > /** Whether content exclusion is enabled; undefined when account discovery could not determine it. */
44 > readonly copilotIgnoreEnabled?: boolean;
45 > }
46 >
47 > export interface IAgentHostInternalTelemetrySink {
48 > setContext(context: IAgentHostInternalTelemetryContext | undefined): void;
49 > send(eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void;
50 > sendForContext(context: IAgentHostInternalTelemetryContext, eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void;
51 > }
52 >
53 > /** The subset of the global `fetch` used to POST envelopes; injectable so tests avoid live network calls. */
54 > export type FetchFn = typeof globalThis.fetch;
55 >
56 > /**
57 > * App Insights caps a single property value at ~8192 chars. Long values are split across
58 > * numbered keys (`key`, `key_02`, `key_03`, …) so the Copilot Telemetry Service reassembles
59 > * them, mirroring the Copilot extension's `multiplexProperties` so events look identical on the
60 > * wire and downstream.
61 > */
62 > const MAX_PROPERTY_LENGTH = 8192;
63 > const MAX_CONCATENATED_PROPERTIES = 50;
64 >
65 > export function multiplexProperties(properties: TelemetryProps): TelemetryProps {
66 const newProperties: TelemetryProps = { ...properties };
67 for (const key in properties) {
89 return newProperties;
90 }
92 > /**
93 > * The restricted telemetry surface the agent host exposes, mirroring the Copilot extension's
94 > * `ITelemetryService` restricted methods so agent-host code can emit the same GH/MSFT events.
95 > */
96 > export interface IAgentHostRestrictedTelemetry {
97 > /** GH standard (non-restricted) telemetry -> `copilot_v0_copilot_event`. */
98 > sendGHTelemetryEvent(eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void;
99 > /** GH enhanced/restricted telemetry (prompts, tools, etc.) -> `copilot_v0_restricted_copilot_event`. */
100 > sendEnhancedGHTelemetryEvent(eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void;
101 > /** GH enhanced telemetry attributed and routed using an immutable per-session context. */
102 > sendEnhancedGHTelemetryEventForContext(context: IAgentHostRestrictedTelemetryContext, eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void;
103 > /** MSFT-internal telemetry -> Aria/Collector++ (internal-only table). No-op without an internal key. */
104 > sendInternalMSFTTelemetryEvent(eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void;
105 > /** MSFT-internal telemetry attributed using an immutable per-session context. */
106 > sendInternalMSFTTelemetryEventForContext(context: IAgentHostInternalTelemetryContext, eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void;
107 > /** Sets the Copilot user tracking id (`copilot_trackingId`) carried on every subsequent event. */
108 > setCopilotTrackingId(trackingId: string | undefined): void;
109 > /** Overrides the POST endpoint with the user's CAPI `endpoints.telemetry`; falsy restores the default. */
110 > setRestrictedTelemetryEndpoint(endpointUrl: string | undefined): void;
111 > /** Enables enhanced GH telemetry once the token opts in (`rt=1`); off by default and on flip/logout. */
112 > setRestrictedTelemetryEnabled(enabled: boolean): void;
113 > /** Sets the internal-user identity and enables the internal sink only for staff accounts. */
114 > setInternalTelemetryContext(context: IAgentHostInternalTelemetryContext | undefined): void;
115 > }
116 >
117 > /**
118 > * Emits GitHub Copilot restricted/enhanced telemetry from the agent-host process by POSTing
119 > * Application-Insights envelopes to the Copilot telemetry endpoint (the same wire format the
120 > * Copilot extension uses). Fire-and-forget; failures are logged, never thrown.
121 > */
122 > export class AgentHostRestrictedTelemetrySender implements IAgentHostRestrictedTelemetry {
123 >
124 > private readonly _commonProps: TelemetryProps;
125 >
126 > /**
127 > * Whether the current Copilot token opts into enhanced/restricted telemetry (`rt=1`). Off by
128 > * default so the sole writer to the restricted table never emits for public users — a hard
129 > * safety boundary that holds even if the enclosing service's gate is bypassed. Mirrors the
130 > * Copilot extension, which only creates the restricted reporter for opted-in users.
131 > */
132 > private _restrictedTelemetryEnabled = false;
133 > private _internalTelemetryEnabled = false;
134 >
135 > constructor(
136 commonProperties: ICommonProperties,
137 private readonly _logService: ILogService,
149 };
150 }
152 > sendGHTelemetryEvent(eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void {
153 this._post(GH_STANDARD_IKEY, eventName, properties, measurements);
154 }
156 > sendEnhancedGHTelemetryEvent(eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void {
157 // Hard safety boundary: enhanced/restricted telemetry is the pipeline that may carry prompt
158 // and tool content, so the only writer to the restricted table refuses to emit unless the
164 this._post(GH_ENHANCED_IKEY, eventName, properties, measurements);
165 }
167 > sendEnhancedGHTelemetryEventForContext(context: IAgentHostRestrictedTelemetryContext, eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void {
168 if (!context.restrictedTelemetryEnabled) {
169 return;
174 });
175 }
177 > sendInternalMSFTTelemetryEvent(eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void {
178 if (!this._internalTelemetryEnabled) {
179 return;
185 this._logService.trace(`[ahp-restricted] internal MSFT event (not sent, no internal key): ${eventName}`);
186 }
188 > sendInternalMSFTTelemetryEventForContext(context: IAgentHostInternalTelemetryContext, eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements): void {
189 if (!context.isInternal) {
190 return;
196 this._logService.trace(`[ahp-restricted] internal MSFT event (not sent, no internal key): ${eventName}`);
197 }
199 > setCopilotTrackingId(trackingId: string | undefined): void {
200 // `copilot_trackingId` is the current account's Copilot token `tid` claim. Exact runtime
201 // targets use their immutable per-session context instead; this mutable value remains for
203 this._commonProps.copilot_trackingId = trackingId || undefined;
204 }
206 > setRestrictedTelemetryEndpoint(endpointUrl: string | undefined): void {
207 // The user's telemetry host comes from the CAPI `endpoints.telemetry` discovery; fall back
208 // to the dotcom default when it is unknown so events are never sent to an empty URL.
209 this._endpointUrl = endpointUrl || GH_TELEMETRY_URL;
210 }
212 > setRestrictedTelemetryEnabled(enabled: boolean): void {
213 this._restrictedTelemetryEnabled = enabled;
214 }
216 > setInternalTelemetryContext(context: IAgentHostInternalTelemetryContext | undefined): void {
217 this._internalTelemetryEnabled = context?.isInternal === true;
218 this._internalSink?.setContext(context);
219 }
221 > private _post(iKey: string, eventName: string, properties?: TelemetryProps, measurements?: TelemetryMeasurements, context?: { readonly endpointUrl: string | undefined; readonly trackingId: string | undefined }): void {
222 const name = eventName.includes('/') ? eventName : `${NAMESPACE}/${eventName}`;
223 const commonProps = context
270 });
271 }
273 >
274 function asString(value: string | boolean | undefined): string | undefined {
275 return typeof value === 'string' ? value : value === undefined ? undefined : String(value);