Skip to content

add session ID to terminal, send with suggest, quickfix, and creation events #252003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/vs/workbench/contrib/terminal/browser/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,11 @@ export interface ITerminalInstance extends IBaseTerminalInstance {
*/
readonly hasFocus: boolean;

/**
* The ID of the session that this terminal is connected to
*/
readonly sessionId: string;

/**
* Get or set the behavior of the terminal when it closes. This was indented only to be called
* after reconnecting to a terminal.
Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import { IContextMenuService } from '../../../../platform/contextview/browser/co
import { TerminalContribCommandId } from '../terminalContribExports.js';
import type { IProgressState } from '@xterm/addon-progress';
import { refreshShellIntegrationInfoStatus } from './terminalTooltip.js';
import { generateUuid } from '../../../../base/common/uuid.js';

const enum Constants {
/**
Expand Down Expand Up @@ -361,6 +362,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}));
readonly onLineData = this._onLineData.event;

readonly sessionId = generateUuid();

constructor(
private readonly _terminalShellTypeContextKey: IContextKey<string>,
private _shellLaunchConfig: IShellLaunchConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export class TerminalTelemetryContribution extends Disposable implements IWorkbe
shellIntegrationQuality: number;
shellIntegrationInjected: boolean;
shellIntegrationInjectionFailureReason: ShellIntegrationInjectionFailureReason | undefined;

sessionId: string;
};
type TerminalCreationTelemetryClassification = {
owner: 'tyriar';
Expand All @@ -77,6 +79,8 @@ export class TerminalTelemetryContribution extends Disposable implements IWorkbe
shellIntegrationQuality: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The shell integration quality (rich=2, basic=1 or none=0).' };
shellIntegrationInjected: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the shell integration script was injected.' };
shellIntegrationInjectionFailureReason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Info about shell integration injection.' };

sessionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The session ID of the terminal instance.' };
};
this._telemetryService.publicLog2<TerminalCreationTelemetryData, TerminalCreationTelemetryClassification>('terminal/createInstance', {
shellType: getSanitizedShellType(slc),
Expand All @@ -90,6 +94,7 @@ export class TerminalTelemetryContribution extends Disposable implements IWorkbe
shellIntegrationQuality: commandDetection?.hasRichCommandDetection ? 2 : commandDetection ? 1 : 0,
shellIntegrationInjected: instance.usedShellIntegrationInjection,
shellIntegrationInjectionFailureReason: instance.shellIntegrationInjectionFailureReason,
sessionId: instance.sessionId,
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
readonly onDidUpdateQuickFixes = this._onDidUpdateQuickFixes.event;

constructor(
private readonly _sessionId: string,
private readonly _aliases: string[][] | undefined,
private readonly _capabilities: ITerminalCapabilityStore,
@IAccessibilitySignalService private readonly _accessibilitySignalService: IAccessibilitySignalService,
Expand Down Expand Up @@ -224,16 +225,19 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
type QuickFixResultTelemetryEvent = {
quickFixId: string;
ranQuickFix: boolean;
sessionId: string;
};
type QuickFixClassification = {
owner: 'meganrogge';
quickFixId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The quick fix ID' };
ranQuickFix: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the quick fix was run' };
sessionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The terminal session ID' };
comment: 'Terminal quick fixes';
};
this._telemetryService?.publicLog2<QuickFixResultTelemetryEvent, QuickFixClassification>('terminal/quick-fix', {
quickFixId: id,
ranQuickFix: this._didRun
ranQuickFix: this._didRun,
sessionId: this._sessionId
});
this._decoration.clear();
this._decorationDisposables.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class TerminalQuickFixContribution extends DisposableStore implements ITerminalC

xtermReady(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void {
// Create addon
this._addon = this._instantiationService.createInstance(TerminalQuickFixAddon, undefined, this._ctx.instance.capabilities);
this._addon = this._instantiationService.createInstance(TerminalQuickFixAddon, this._ctx.instance.sessionId, undefined, this._ctx.instance.capabilities);
xterm.raw.loadAddon(this._addon);

// Hook up listeners
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { ITerminalQuickFixService } from '../../browser/quickFix.js';
import { getQuickFixesForCommand, TerminalQuickFixAddon } from '../../browser/quickFixAddon.js';
import { freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, gitFastForwardPull, GitFastForwardPullOutputRegex, GitPushOutputRegex, gitPushSetUpstream, gitSimilar, GitSimilarOutputRegex, gitTwoDashes, GitTwoDashesRegex, pwshGeneralError, PwshGeneralErrorOutputRegex, pwshUnixCommandNotFoundError, PwshUnixCommandNotFoundErrorOutputRegex } from '../../browser/terminalQuickFixBuiltinActions.js';
import { TestStorageService } from '../../../../../test/common/workbenchTestServices.js';
import { generateUuid } from '../../../../../../base/common/uuid.js';

suite('QuickFixAddon', () => {
const store = ensureNoDisposablesAreLeakedInTestSuite();
Expand Down Expand Up @@ -66,7 +67,7 @@ suite('QuickFixAddon', () => {
openerService = instantiationService.stub(IOpenerService, {} as Partial<IOpenerService>);
commandService = new TestCommandService(instantiationService);

quickFixAddon = instantiationService.createInstance(TerminalQuickFixAddon, [], capabilities);
quickFixAddon = instantiationService.createInstance(TerminalQuickFixAddon, generateUuid(), [], capabilities);
terminal.loadAddon(quickFixAddon);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class TerminalSuggestContribution extends DisposableStore implements ITerminalCo
return;
}

const addon = this._addon.value = this._instantiationService.createInstance(SuggestAddon, this._ctx.instance.shellType, this._ctx.instance.capabilities, this._terminalSuggestWidgetVisibleContextKey);
const addon = this._addon.value = this._instantiationService.createInstance(SuggestAddon, this._ctx.instance.sessionId, this._ctx.instance.shellType, this._ctx.instance.capabilities, this._terminalSuggestWidgetVisibleContextKey);
xterm.loadAddon(addon);
this._loadPwshCompletionAddon(xterm);
this._loadLspCompletionAddon(xterm);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest
private _suggestTelemetry: TerminalSuggestTelemetry | undefined;

constructor(
private readonly _sessionId: string,
shellType: TerminalShellType | undefined,
private readonly _capabilities: ITerminalCapabilityStore,
private readonly _terminalSuggestWidgetVisibleContextKey: IContextKey<boolean>,
Expand Down Expand Up @@ -753,7 +754,7 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest
}
const initialPromptInputState = this._mostRecentPromptInputState;
if (!suggestion || !initialPromptInputState || this._leadingLineContent === undefined || !this._model) {
this._suggestTelemetry?.acceptCompletion(undefined, this._mostRecentPromptInputState?.value);
this._suggestTelemetry?.acceptCompletion(this._sessionId, undefined, this._mostRecentPromptInputState?.value);
return;
}
SuggestAddon.lastAcceptedCompletionTimestamp = Date.now();
Expand Down Expand Up @@ -839,7 +840,7 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest

// Send the completion
this._onAcceptedCompletion.fire(resultSequence);
this._suggestTelemetry?.acceptCompletion(completion, this._mostRecentPromptInputState?.value);
this._suggestTelemetry?.acceptCompletion(this._sessionId, completion, this._mostRecentPromptInputState?.value);
this.hideSuggestWidget(true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { IPromptInputModel } from '../../../../../platform/terminal/common/capab
import { ITerminalCompletion, TerminalCompletionItemKind } from './terminalCompletionItem.js';

export class TerminalSuggestTelemetry extends Disposable {
private _acceptedCompletions: Array<{ label: string; kind?: string }> | undefined;
private _acceptedCompletions: Array<{ label: string; kind?: string; sessionId: string }> | undefined;

private _kindMap = new Map<number, string>([
[TerminalCompletionItemKind.File, 'File'],
Expand Down Expand Up @@ -40,13 +40,13 @@ export class TerminalSuggestTelemetry extends Disposable {
this._acceptedCompletions = undefined;
}));
}
acceptCompletion(completion: ITerminalCompletion | undefined, commandLine?: string): void {
acceptCompletion(sessionId: string, completion: ITerminalCompletion | undefined, commandLine?: string): void {
if (!completion || !commandLine) {
this._acceptedCompletions = undefined;
return;
}
this._acceptedCompletions = this._acceptedCompletions || [];
this._acceptedCompletions.push({ label: typeof completion.label === 'string' ? completion.label : completion.label.label, kind: this._kindMap.get(completion.kind!) });
this._acceptedCompletions.push({ label: typeof completion.label === 'string' ? completion.label : completion.label.label, kind: this._kindMap.get(completion.kind!), sessionId });
}
private _sendTelemetryInfo(fromInterrupt?: boolean, exitCode?: number): void {
const commandLine = this._promptInputModel?.value;
Expand All @@ -72,6 +72,7 @@ export class TerminalSuggestTelemetry extends Disposable {
kind: string | undefined;
outcome: string;
exitCode: number | undefined;
sessionId: string;
}, {
owner: 'meganrogge';
comment: 'This data is collected to understand the outcome of a terminal completion acceptance.';
Expand All @@ -90,10 +91,16 @@ export class TerminalSuggestTelemetry extends Disposable {
purpose: 'FeatureInsight';
comment: 'The exit code from the command';
};
sessionId: {
classification: 'SystemMetaData';
purpose: 'FeatureInsight';
comment: 'The session ID of the terminal session where the completion was accepted';
};
}>('terminal.suggest.acceptedCompletion', {
kind,
outcome,
exitCode
exitCode,
sessionId: completion.sessionId
});
}
}
Expand Down
Loading