agentHost: Respect telemetry disablement from process launch (#330929) · microsoft/vscode@6f50f21 · GitHub
Skip to content

Commit 6f50f21

Browse files
authored
agentHost: Respect telemetry disablement from process launch (#330929)
* agentHost: Respect telemetry disablement during initialization Send each client's effective telemetry level with initialize and reconnect so the host applies consent before connection telemetry or queued actions. Keep the host disabled until a client level arrives, and propagate process-level restrictions to generic remote telemetry.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: Preserve telemetry wrapper defaults for direct callers Keep fail-closed startup explicit to the production factory while preserving the established constructor behavior used by isolated Agent Host components and tests.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: Gate telemetry on client consent Keep seeded root configuration from enabling telemetry before initialize or reconnect provides a client telemetry level. Preserve existing direct-construction defaults for isolated callers and tests.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: Propagate telemetry level at process launch Start controlled Agent Host processes with the launcher's effective telemetry level so opted-in clients retain early diagnostics while opted-out clients disable telemetry before startup. Keep initialize and reconnect updates as a monotonic multi-client clamp across local, remote-server, SSH, WSL, and CLI-supervised hosts.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update generated extension point cache Include the link presentation provider extension point generated by hygiene after merging origin/main.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: Derive SSH telemetry in shared process Use the shared process telemetry service when launching SSH and WSL Agent Hosts instead of threading the telemetry level through renderer IPC contracts.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6450636 commit 6f50f21

26 files changed

Lines changed: 561 additions & 89 deletions

cli/src/commands/agent_host.rs

Lines changed: 6 additions & 0 deletions

cli/src/tunnels/agent_host.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::async_pipe::{
3131
use crate::constants::VSCODE_CLI_QUALITY;
3232
use crate::download_cache::DownloadCache;
3333
use crate::log;
34-
use crate::options::Quality;
34+
use crate::options::{Quality, TelemetryLevel};
3535
use crate::state::LauncherPaths;
3636
use crate::update_service::{
3737
unzip_downloaded_release, Platform, Release, TargetKind, UpdateService,
@@ -98,6 +98,7 @@ const UPGRADE_KILL_DELAY: Duration = Duration::from_secs(3);
9898
#[derive(Clone, Debug)]
9999
pub struct AgentHostConfig {
100100
pub server_data_dir: Option<String>,
101+
pub telemetry_level: Option<TelemetryLevel>,
101102
pub without_connection_token: bool,
102103
pub connection_token: Option<String>,
103104
pub connection_token_file: Option<String>,
@@ -262,6 +263,10 @@ impl AgentHostManager {
262263
cmd.arg("--server-data-dir");
263264
cmd.arg(a);
264265
}
266+
if let Some(level) = self.config.telemetry_level {
267+
cmd.arg("--telemetry-level");
268+
cmd.arg(level.to_string());
269+
}
265270
if self.config.without_connection_token {
266271
cmd.arg("--without-connection-token");
267272
}
@@ -2255,6 +2260,7 @@ mod tests {
22552260
Arc::new(ReqwestSimpleHttp::new()),
22562261
AgentHostConfig {
22572262
server_data_dir: None,
2263+
telemetry_level: None,
22582264
without_connection_token: true,
22592265
connection_token: None,
22602266
connection_token_file: None,

src/vs/platform/agentHost/browser/remoteAgentHostProtocolClient.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ import { ChatSourceKind, ContentEncoding, ResourceRequestParams, type Completion
3737
import type { InvokeChangesetOperationParams, InvokeChangesetOperationResult } from '../common/state/protocol/channels-changeset/commands.js';
3838
import { encodeBase64 } from '../../../base/common/buffer.js';
3939
import { ILoadEstimator, LoadEstimator } from '../../../base/parts/ipc/common/ipc.net.js';
40-
import { ITelemetryService, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID, TelemetryLevel, telemetryLevelEnabled } from '../../telemetry/common/telemetry.js';
40+
import { ITelemetryService, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from '../../telemetry/common/telemetry.js';
4141
import { getTelemetryLevel } from '../../telemetry/common/telemetryUtils.js';
4242
import { AgentHostTelemetryLevelConfigKey, AgentHostTerminalAutoApproveEnabledConfigKey, AgentHostTerminalAutoApproveRulesConfigKey, AgentHostDisableRepoInfoTelemetryConfigKey, getAgentHostTerminalAutoApproveRulesConfig, TERMINAL_AUTO_APPROVE_ENABLED_SETTING_ID, TERMINAL_AUTO_APPROVE_SETTING_ID, TERMINAL_IGNORE_DEFAULT_AUTO_APPROVE_RULES_SETTING_ID, DISABLE_REPO_INFO_TELEMETRY_SETTING_ID, telemetryLevelToAgentHostConfigValue } from '../common/agentHostSchema.js';
4343
import { getAgentHostConfigurationSyncEntries, resolveAgentHostConfigurationSyncPatch, resolveAgentHostConfigurationSyncValue } from '../common/agentHostConfigurationSync.js';
4444
import { managedPermissionsConfigurationIds, resolveManagedSettingsPermissions, type IAgentHostManagedSettingsPermissions } from '../common/agentHostManagedSettings.js';
45-
import { AgentHostClientConnectionKind, toClientTelemetryMeta } from '../common/agentHostTelemetry.js';
45+
import { AgentHostClientConnectionKind, toAgentHostClientMeta } from '../common/agentHostTelemetry.js';
4646
import type { OtlpExportLogsParams } from '../common/state/protocol/channels-otlp/notifications.js';
4747
import type { TelemetryCapabilities } from '../common/state/protocol/channels-otlp/state.js';
4848
import type { Implementation, InitializeResult } from '../common/state/protocol/common/commands.js';
@@ -455,7 +455,7 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
455455
protocolVersions: [...SUPPORTED_PROTOCOL_VERSIONS],
456456
clientId: this._clientId,
457457
clientInfo: this._clientInfo,
458-
...this._clientConnectionTelemetryMeta(),
458+
_meta: this._clientMeta(),
459459
initialSubscriptions: [ROOT_STATE_URI],
460460
}, { bypassInitializeQueue: true });
461461
this._applyInitializeResult(result);
@@ -705,7 +705,7 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
705705
clientId: this._clientId,
706706
lastSeenServerSeq,
707707
subscriptions,
708-
...this._clientConnectionTelemetryMeta(),
708+
_meta: this._clientMeta(),
709709
}, { bypassReconnectGate: true });
710710
return { result, freshInitialize: false };
711711
} catch (error) {
@@ -720,7 +720,7 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
720720
protocolVersions: [...SUPPORTED_PROTOCOL_VERSIONS],
721721
clientId: this._clientId,
722722
clientInfo: this._clientInfo,
723-
...this._clientConnectionTelemetryMeta(),
723+
_meta: this._clientMeta(),
724724
initialSubscriptions: subscriptions,
725725
}, { bypassReconnectGate: true });
726726
this._applyInitializeResult(initializeResult, false);
@@ -774,12 +774,15 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
774774
}, { bypassReconnectGate: true })));
775775
}
776776

777-
private _clientConnectionTelemetryMeta(): { _meta: Record<string, unknown> } | Record<string, never> {
778-
const sendIdentity = telemetryLevelEnabled(this._telemetryService, TelemetryLevel.USAGE);
779-
const machineId = sendIdentity ? this._telemetryService.machineId : undefined;
780-
const devDeviceId = sendIdentity ? this._telemetryService.devDeviceId : undefined;
781-
const meta = toClientTelemetryMeta(this._transport.clientConnectionKind, machineId, devDeviceId);
782-
return meta ? { _meta: meta } : {};
777+
private _clientMeta(): Record<string, unknown> {
778+
const telemetryLevel = this._effectiveTelemetryLevel();
779+
const sendIdentity = telemetryLevel >= TelemetryLevel.USAGE;
780+
return toAgentHostClientMeta(
781+
this._transport.clientConnectionKind,
782+
telemetryLevel,
783+
sendIdentity ? this._telemetryService.machineId : undefined,
784+
sendIdentity ? this._telemetryService.devDeviceId : undefined,
785+
);
783786
}
784787

785788
private _applyInitializeResult(result: CommandMap['initialize']['result'], forwardClientConfig = true): void {
@@ -1616,7 +1619,11 @@ export class RemoteAgentHostProtocolClient extends Disposable implements IAgentC
16161619
}
16171620

16181621
private _updateTelemetryLevel(): void {
1619-
this._dispatchRootConfig({ [AgentHostTelemetryLevelConfigKey]: telemetryLevelToAgentHostConfigValue(getTelemetryLevel(this._configurationService)) });
1622+
this._dispatchRootConfig({ [AgentHostTelemetryLevelConfigKey]: telemetryLevelToAgentHostConfigValue(this._effectiveTelemetryLevel()) });
1623+
}
1624+
1625+
private _effectiveTelemetryLevel(): TelemetryLevel {
1626+
return Math.min(getTelemetryLevel(this._configurationService), this._telemetryService.telemetryLevel);
16201627
}
16211628

16221629
/** Merge a patch into the agent host's root configuration. */

src/vs/platform/agentHost/common/agentHostSchema.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ConfigurationTarget, type IConfigurationService, type IConfigurationVal
99
import { DEFAULT_EDIT_AUTO_APPROVE_PATTERNS, type ChatEditAutoApprovePatterns } from '../../chat/common/chatSettings.js';
1010
import type { IMcpServerConfiguration } from '../../mcp/common/mcpPlatformTypes.js';
1111
import { TelemetryConfiguration, TelemetryLevel } from '../../telemetry/common/telemetry.js';
12+
import { telemetryLevelToAgentHostValue } from './agentHostTelemetry.js';
1213
import { SessionConfigKey } from './sessionConfigKeys.js';
1314
import type { SessionConfigPropertySchema, SessionConfigSchema } from './state/protocol/commands.js';
1415
import { JsonRpcErrorCodes, ProtocolError } from './state/sessionProtocol.js';
@@ -593,16 +594,7 @@ export const AgentHostMcpServersConfigKey = 'mcpServers';
593594
export type AgentHostMcpServers = Record<string, IMcpServerConfiguration>;
594595

595596
export function telemetryLevelToAgentHostConfigValue(telemetryLevel: TelemetryLevel): TelemetryConfiguration {
596-
switch (telemetryLevel) {
597-
case TelemetryLevel.NONE:
598-
return TelemetryConfiguration.OFF;
599-
case TelemetryLevel.CRASH:
600-
return TelemetryConfiguration.CRASH;
601-
case TelemetryLevel.ERROR:
602-
return TelemetryConfiguration.ERROR;
603-
case TelemetryLevel.USAGE:
604-
return TelemetryConfiguration.ON;
605-
}
597+
return telemetryLevelToAgentHostValue(telemetryLevel);
606598
}
607599

608600
export function agentHostConfigValueToTelemetryLevel(value: unknown): TelemetryLevel | undefined {

src/vs/platform/agentHost/common/agentHostTelemetry.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { TelemetryConfiguration, TelemetryLevel } from '../../telemetry/common/telemetry.js';
67
import type { AgentHostClientType } from './agentHostClientInfo.js';
78

89
export const enum AgentHostLaunchKind {
@@ -49,11 +50,14 @@ export function createUnknownAgentHostClientTelemetryContext(clientType: AgentHo
4950
}
5051

5152
const CLIENT_CONNECTION_KIND_META_KEY = 'vscode.clientConnectionKind';
53+
const CLIENT_TELEMETRY_LEVEL_META_KEY = 'vscode.telemetryLevel';
5254
const CLIENT_MACHINE_ID_META_KEY = 'vscode.clientMachineId';
5355
const CLIENT_DEV_DEVICE_ID_META_KEY = 'vscode.clientDevDeviceId';
5456

55-
export function toClientTelemetryMeta(connectionKind: AgentHostClientConnectionKind | undefined, machineId: string | undefined, devDeviceId: string | undefined): Record<string, unknown> | undefined {
56-
const meta: Record<string, unknown> = {};
57+
export function toAgentHostClientMeta(connectionKind: AgentHostClientConnectionKind | undefined, telemetryLevel: TelemetryLevel, machineId: string | undefined, devDeviceId: string | undefined): Record<string, unknown> {
58+
const meta: Record<string, unknown> = {
59+
[CLIENT_TELEMETRY_LEVEL_META_KEY]: telemetryLevelToAgentHostValue(telemetryLevel),
60+
};
5761
if (connectionKind !== undefined && connectionKind !== AgentHostClientConnectionKind.Unknown) {
5862
meta[CLIENT_CONNECTION_KIND_META_KEY] = connectionKind;
5963
}
@@ -63,7 +67,7 @@ export function toClientTelemetryMeta(connectionKind: AgentHostClientConnectionK
6367
if (devDeviceId) {
6468
meta[CLIENT_DEV_DEVICE_ID_META_KEY] = devDeviceId;
6569
}
66-
return Object.keys(meta).length > 0 ? meta : undefined;
70+
return meta;
6771
}
6872

6973
export function readClientConnectionKind(meta: Record<string, unknown> | undefined): AgentHostClientConnectionKind {
@@ -82,6 +86,35 @@ export function readClientConnectionKind(meta: Record<string, unknown> | undefin
8286
}
8387
}
8488

89+
export function readClientTelemetryLevel(meta: Record<string, unknown> | undefined): TelemetryLevel | undefined {
90+
const value = meta?.[CLIENT_TELEMETRY_LEVEL_META_KEY];
91+
switch (value) {
92+
case TelemetryConfiguration.OFF:
93+
return TelemetryLevel.NONE;
94+
case TelemetryConfiguration.CRASH:
95+
return TelemetryLevel.CRASH;
96+
case TelemetryConfiguration.ERROR:
97+
return TelemetryLevel.ERROR;
98+
case TelemetryConfiguration.ON:
99+
return TelemetryLevel.USAGE;
100+
default:
101+
return value === undefined ? undefined : TelemetryLevel.NONE;
102+
}
103+
}
104+
105+
export function telemetryLevelToAgentHostValue(telemetryLevel: TelemetryLevel): TelemetryConfiguration {
106+
switch (telemetryLevel) {
107+
case TelemetryLevel.NONE:
108+
return TelemetryConfiguration.OFF;
109+
case TelemetryLevel.CRASH:
110+
return TelemetryConfiguration.CRASH;
111+
case TelemetryLevel.ERROR:
112+
return TelemetryConfiguration.ERROR;
113+
case TelemetryLevel.USAGE:
114+
return TelemetryConfiguration.ON;
115+
}
116+
}
117+
85118
export function readClientMachineId(meta: Record<string, unknown> | undefined): string | undefined {
86119
return readClientTelemetryIdentity(meta, CLIENT_MACHINE_ID_META_KEY);
87120
}

src/vs/platform/agentHost/common/agentHostTelemetryEnv.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
export const AgentHostMachineIdEnvKey = 'VSCODE_AGENT_HOST_MACHINE_ID';
2222
export const AgentHostSqmIdEnvKey = 'VSCODE_AGENT_HOST_SQM_ID';
2323
export const AgentHostDevDeviceIdEnvKey = 'VSCODE_AGENT_HOST_DEV_DEVICE_ID';
24+
export const AgentHostTelemetryLevelEnvKey = 'VSCODE_AGENT_HOST_TELEMETRY_LEVEL';
2425

2526
export interface IAgentHostForwardedTelemetryIds {
2627
readonly machineId: string;

src/vs/platform/agentHost/electron-main/electronAgentHostStarter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ import { ILifecycleMainService } from '../../lifecycle/electron-main/lifecycleMa
1717
import { ILogService } from '../../log/common/log.js';
1818
import { Schemas } from '../../../base/common/network.js';
1919
import { getResolvedShellEnv } from '../../shell/node/shellEnv.js';
20+
import { ITelemetryService } from '../../telemetry/common/telemetry.js';
2021
import { NullTelemetryService } from '../../telemetry/common/telemetryUtils.js';
2122
import { UtilityProcess } from '../../utilityProcess/electron-main/utilityProcess.js';
2223
import { AgentHostStartError, IAgentHostConnection, IAgentHostShutdownRequest, IAgentHostStarter, IAgentHostStartRequest } from '../common/agent.js';
2324
import { buildAgentHostTelemetryIdEnv, IAgentHostForwardedTelemetryIds } from '../common/agentHostTelemetryEnv.js';
24-
import { AgentHostLaunchKind, AgentHostLaunchKindEnvVar } from '../common/agentHostTelemetry.js';
25+
import { AgentHostLaunchKind, AgentHostLaunchKindEnvVar, telemetryLevelToAgentHostValue } from '../common/agentHostTelemetry.js';
2526
import { AgentHostByokModelsEnabledSettingId, AgentHostClaudeAgentEnabledSettingId, AgentHostCodexAgentBinaryArgsSettingId, AgentHostCodexAgentEnabledSettingId, AgentHostCodexAgentSdkRootSettingId, AgentHostCodexAgentCodexHomeSettingId, AgentHostIpcChannels, AgentHostOTelCaptureContentSettingId, AgentHostOTelDbSpanExporterEnabledSettingId, AgentHostOTelEnabledSettingId, AgentHostOTelExporterTypeSettingId, AgentHostOTelOtlpEndpointSettingId, AgentHostOTelOtlpProtocolSettingId, AgentHostOTelOutfileSettingId, AgentHostOTelResourceAttributesSettingId, AgentHostOTelServiceNameSettingId, AgentHostOTelPolicyIpcChannel, AgentHostRestartIpcChannel, AgentHostWillRestartIpcChannel, buildAgentHostOTelEnv, buildAgentSdkEnv, IAgentHostManagementService, IAgentHostOTelSettings, sanitizeAgentHostOTelPolicySettings } from '../common/agentService.js';
2627
import { deepClone } from '../../../base/common/objects.js';
2728
import '../common/agentHostStarter.config.contribution.js';
@@ -54,6 +55,7 @@ export class ElectronAgentHostStarter extends Disposable implements IAgentHostSt
5455
@IEnvironmentMainService private readonly _environmentMainService: IEnvironmentMainService,
5556
@ILifecycleMainService private readonly _lifecycleMainService: ILifecycleMainService,
5657
@ILogService private readonly _logService: ILogService,
58+
@ITelemetryService private readonly _telemetryService: ITelemetryService,
5759
) {
5860
super();
5961

@@ -158,10 +160,8 @@ export class ElectronAgentHostStarter extends Disposable implements IAgentHostSt
158160
const args = [
159161
'--logsPath', this._environmentMainService.logsHome.with({ scheme: Schemas.file }).fsPath,
160162
'--user-data-dir', this._environmentMainService.userDataPath,
163+
'--telemetry-level', telemetryLevelToAgentHostValue(this._telemetryService.telemetryLevel),
161164
];
162-
if (this._environmentMainService.disableTelemetry) {
163-
args.push('--disable-telemetry');
164-
}
165165

166166
// Forward the host's resolved telemetry identifiers so the agent host
167167
// reuses the same persisted machineId/sqmId/devDeviceId instead of

src/vs/platform/agentHost/node/agentHostTelemetryService.ts

Lines changed: 16 additions & 3 deletions

0 commit comments

Comments
 (0)