chatSlashCommands.ts ×10

Frontier kind: Code frontier

unlabeled · c_4138ae1cb564

111 tests · 40990 LOC · 185 files · introduces 0 tests · 243 LOC · 5 files

Introduces — evidence that enters the hierarchy at this concept

Code
27 ranges243 lines · 5 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
3616 ranges40990 lines · 185 files · Browse complete extent
All tests (intent)
111 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.

5 files ranked by introduced lines: 243 introduced LOC across 27 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/contrib/chat/common/participants/chatSlashCommands.ts 104 introduced LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatSlashCommands.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 { CancellationToken } from '../../../../../base/common/cancellation.js';
7 > import { Emitter, Event } from '../../../../../base/common/event.js';
8 > import { Disposable, IDisposable, toDisposable } from '../../../../../base/common/lifecycle.js';
9 > import { ContextKeyExpression } from '../../../../../platform/contextkey/common/contextkey.js';
10 > import { createDecorator } from '../../../../../platform/instantiation/common/instantiation.js';
11 > import { IProgress } from '../../../../../platform/progress/common/progress.js';
12 > import { IChatMessage } from '../languageModels.js';
13 > import { IChatFollowup, IChatProgress, IChatResponseProgressFileTreeData, IChatSendRequestOptions } from '../chatService/chatService.js';
14 > import { IExtensionService } from '../../../../services/extensions/common/extensions.js';
15 > import { ChatAgentLocation, ChatModeKind } from '../constants.js';
16 > import { URI } from '../../../../../base/common/uri.js';
17 > import { getChatSessionType } from '../model/chatUri.js';
18 > import { matchesSessionType } from '../promptSyntax/service/promptsService.js';
19 >
20 > //#region slash service, commands etc
21 >
22 > export interface IChatSlashData {
23 > command: string;
24 > detail: string;
25 > sortText?: string;
26 > /**
27 > * Whether the command should execute as soon
28 > * as it is entered. Defaults to `false`.
29 > */
30 > executeImmediately?: boolean;
31 >
32 > /**
33 > * Whether a silent command can execute independently while the chat has a request in progress.
34 > */
35 > executeDuringRequest?: boolean;
36 >
37 > /**
38 > * Whether the command should be added as a request/response
39 > * turn to the chat history. Defaults to `false`.
40 > *
41 > * For instance, the `/save` command opens an untitled document
42 > * to the side hence does not contain any chatbot responses.
43 > */
44 > silent?: boolean;
45 >
46 > locations: ChatAgentLocation[];
47 > modes?: ChatModeKind[];
48 > sessionTypes?: string[];
49 >
50 > /**
51 > * Optional context key expression that controls visibility of this command.
52 > * When set, the command is only shown if the expression evaluates to true.
53 > */
54 > when?: ContextKeyExpression;
55 > }
56 >
57 > export interface IChatSlashFragment {
58 > content: string | { treeData: IChatResponseProgressFileTreeData };
59 > }
60 > export type IChatSlashCallback = { (prompt: string, progress: IProgress<IChatProgress>, history: IChatMessage[], location: ChatAgentLocation, sessionResource: URI, token: CancellationToken, options?: IChatSendRequestOptions): Promise<{ followUp: IChatFollowup[] } | void> };
61 >
62 > export const IChatSlashCommandService = createDecorator<IChatSlashCommandService>('chatSlashCommandService');
63 >
64 > /**
65 > * This currently only exists to drive /clear and /help
66 > */
67 > export interface IChatSlashCommandService {
68 > _serviceBrand: undefined;
69 > readonly onDidChangeCommands: Event<void>;
70 > registerSlashCommand(data: IChatSlashData, command: IChatSlashCallback): IDisposable;
71 > executeCommand(id: string, prompt: string, progress: IProgress<IChatProgress>, history: IChatMessage[], location: ChatAgentLocation, sessionResource: URI, token: CancellationToken, options?: IChatSendRequestOptions): Promise<{ followUp: IChatFollowup[] } | void>;
72 > getCommands(location: ChatAgentLocation, mode: ChatModeKind): Array<IChatSlashData>;
73 > hasCommand(id: string, sessionType: string): boolean;
74 > }
75 >
76 > type RegisteredSlashCommand = { data: IChatSlashData; command?: IChatSlashCallback };
77 >
78 > export class ChatSlashCommandService extends Disposable implements IChatSlashCommandService {
79 >
80 > declare _serviceBrand: undefined;
81 >
82 > private readonly _commands = new Map<string, RegisteredSlashCommand[]>();
83 >
84 > private readonly _onDidChangeCommands = this._register(new Emitter<void>());
85 > readonly onDidChangeCommands: Event<void> = this._onDidChangeCommands.event;
86 >
87 > constructor(@IExtensionService private readonly _extensionService: IExtensionService) {
88 super();
89 }
91 > override dispose(): void {
92 super.dispose();
93 this._commands.clear();
94 }
96 > private getSessionScopedCommands(id: string): RegisteredSlashCommand[] {
97 return this._commands.get(id) ?? [];
98 }
100 > private commandsOverlap(dataA: IChatSlashData, dataB: IChatSlashData): boolean {
101 if (dataA.sessionTypes === undefined || dataB.sessionTypes === undefined) {
102 return true;
105 return dataA.sessionTypes.some(sessionType => dataB.sessionTypes?.includes(sessionType));
106 }
108 > private getCommand(id: string, sessionType: string | undefined): RegisteredSlashCommand | undefined {
109 return this.getSessionScopedCommands(id).find(candidate => matchesSessionType(candidate.data.sessionTypes, sessionType));
110 }
112 > registerSlashCommand(data: IChatSlashData, command: IChatSlashCallback): IDisposable {
113 const commandsForId = this.getSessionScopedCommands(data.command);
114 if (commandsForId.some(candidate => this.commandsOverlap(candidate.data, data))) {
140 });
141 }
143 > getCommands(location: ChatAgentLocation, mode: ChatModeKind): Array<IChatSlashData> {
144 return Array
145 .from(this._commands.values())
147 .filter(c => c.locations.includes(location) && (!c.modes || c.modes.includes(mode)));
148 }
150 > hasCommand(id: string, sessionType: string): boolean {
151 return !!this.getCommand(id, sessionType);
152 }
154 > async executeCommand(id: string, prompt: string, progress: IProgress<IChatProgress>, history: IChatMessage[], location: ChatAgentLocation, sessionResource: URI, token: CancellationToken, options?: IChatSendRequestOptions): Promise<{ followUp: IChatFollowup[] } | void> {
155 const data = this.getCommand(id, getChatSessionType(sessionResource));
156 if (!data) {
166 return await data.command(prompt, progress, history, location, sessionResource, token, options);
167 }
src/vs/workbench/contrib/chat/common/attachments/chatVariables.ts 71 introduced LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatVariables.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 { CancellationToken } from '../../../../../base/common/cancellation.js';
7 > import { ThemeIcon } from '../../../../../base/common/themables.js';
8 > import { URI } from '../../../../../base/common/uri.js';
9 > import { IRange } from '../../../../../editor/common/core/range.js';
10 > import { Location } from '../../../../../editor/common/languages.js';
11 > import { createDecorator } from '../../../../../platform/instantiation/common/instantiation.js';
12 > import { IChatModel } from '../model/chatModel.js';
13 > import { IChatContentReference, IChatProgressMessage } from '../chatService/chatService.js';
14 > import { IDiagnosticVariableEntryFilterData, StringChatContextValue, type IChatRequestVariableEntry } from './chatVariableEntries.js';
15 > import { ToolAndToolSetEnablementMap } from '../tools/languageModelToolsService.js';
16 >
17 > export interface IChatVariableData {
18 > id: string;
19 > name: string;
20 > icon?: ThemeIcon;
21 > fullName?: string;
22 > description: string;
23 > modelDescription?: string;
24 > canTakeArgument?: boolean;
25 > }
26 >
27 > export interface IChatRequestProblemsVariable {
28 > id: 'vscode.problems';
29 > filter: IDiagnosticVariableEntryFilterData;
30 > }
31 >
32 > export const isIChatRequestProblemsVariable = (obj: unknown): obj is IChatRequestProblemsVariable =>
33 typeof obj === 'object' && obj !== null && 'id' in obj && (obj as IChatRequestProblemsVariable).id === 'vscode.problems';
35 > export type IChatRequestVariableValue = string | URI | Location | Uint8Array | IChatRequestProblemsVariable | StringChatContextValue | unknown;
36 >
37 > export type IChatVariableResolverProgress =
38 > | IChatContentReference
39 > | IChatProgressMessage;
40 >
41 > export interface IChatVariableResolver {
42 > (messageText: string, arg: string | undefined, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise<IChatRequestVariableValue | undefined>;
43 > }
44 >
45 > export const IChatVariablesService = createDecorator<IChatVariablesService>('IChatVariablesService');
46 >
47 > export interface IChatVariablesService {
48 > _serviceBrand: undefined;
49 > getDynamicVariables(sessionResource: URI): ReadonlyArray<IDynamicVariable>;
50 > getSelectedToolAndToolSets(sessionResource: URI): ToolAndToolSetEnablementMap;
51 > }
52 >
53 > export interface IDynamicVariable {
54 > range: IRange;
55 > id: string;
56 > fullName?: string;
57 > icon?: ThemeIcon;
58 > modelDescription?: string;
59 > isFile?: boolean;
60 > isDirectory?: boolean;
61 > isAttachmentReference?: boolean;
62 > data: IChatRequestVariableValue;
63 > /**
64 > * Implementation-defined metadata that flows through to the resulting
65 > * {@link IChatRequestVariableEntry} and any {@link MessageAttachment}
66 > * derived from it. Used to round-trip provider-specific data attached
67 > * to chat input completions.
68 > */
69 > _meta?: Record<string, unknown>;
70 > }
71 >
72 > export function toAttachedContextDynamicVariable(entry: IChatRequestVariableEntry, range: IRange): IDynamicVariable {
73 return {
74 id: entry.id,
src/vs/workbench/contrib/chat/common/requestParser/chatRequestParser.ts 47 introduced LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatRequestParser.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 { URI } from '../../../../../base/common/uri.js';
7 > import { IPosition, Position } from '../../../../../editor/common/core/position.js';
8 > import { Range } from '../../../../../editor/common/core/range.js';
9 > import { OffsetRange } from '../../../../../editor/common/core/ranges/offsetRange.js';
10 > import { IChatVariablesService, IDynamicVariable } from '../attachments/chatVariables.js';
11 > import { ChatAgentLocation, ChatModeKind } from '../constants.js';
12 > import { getChatSessionType } from '../model/chatUri.js';
13 > import { IChatAgentAttachmentCapabilities, IChatAgentData, IChatAgentService } from '../participants/chatAgents.js';
14 > import { IChatSlashCommandService } from '../participants/chatSlashCommands.js';
15 > import { IPromptsService, matchesSessionType } from '../promptSyntax/service/promptsService.js';
16 > import { ToolAndToolSetEnablementMap, IToolData, IToolSet, isToolSet } from '../tools/languageModelToolsService.js';
17 > import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicVariablePart, ChatRequestSlashCommandPart, ChatRequestSlashPromptPart, ChatRequestTextPart, ChatRequestToolPart, ChatRequestToolSetPart, IParsedChatRequest, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from './chatParserTypes.js';
18 >
19 > export const agentReg = /^@([\w_\-\.]+)(?=(\s|$|\b))/i; // An @-agent
20 > export const variableReg = /^#([\w_\-]+)(:\d+)?(?=(\s|$|\b))/i; // A #-variable with an optional numeric : arg (@response:2)
21 > export const slashReg = /^\/([\p{L}\d_\-\.:]+)(?=(\s|$|\b))/iu; // A / command
22 >
23 > export interface IChatParserContext {
24 > /** Used only as a disambiguator, when the query references an agent that has a duplicate with the same name. */
25 > selectedAgent?: IChatAgentData;
26 > mode?: ChatModeKind;
27 > /** Parse as this agent, even when it does not appear in the query text */
28 > forcedAgent?: IChatAgentData;
29 > attachmentCapabilities?: IChatAgentAttachmentCapabilities;
30 > sessionType?: string;
31 > }
32 >
33 > export class ChatRequestParser {
34 > constructor(
35 @IChatAgentService private readonly agentService: IChatAgentService,
36 @IChatVariablesService private readonly variableService: IChatVariablesService,
38 @IPromptsService private readonly promptsService: IPromptsService,
39 ) { }
41 > parseChatRequest(sessionResource: URI, message: string, location: ChatAgentLocation = ChatAgentLocation.Chat, context: IChatParserContext = {}): IParsedChatRequest {
42 const references = this.variableService.getDynamicVariables(sessionResource); // must access this list before any async calls
43 const selectedToolAndToolSets = this.variableService.getSelectedToolAndToolSets(sessionResource);
47 return this.parseChatRequestWithReferences(references, selectedToolAndToolSets, message, location, context);
48 }
50 > parseChatRequestWithReferences(references: ReadonlyArray<IDynamicVariable>, selectedToolAndToolSets: ToolAndToolSetEnablementMap, message: string, location: ChatAgentLocation = ChatAgentLocation.Chat, context?: IChatParserContext): IParsedChatRequest {
51 const parts: IParsedChatRequestPart[] = [];
52 const toolsByName = new Map<string, IToolData>();
120 };
121 }
123 > private tryToParseAgent(message: string, fullMessage: string, offset: number, position: IPosition, parts: Array<IParsedChatRequestPart>, location: ChatAgentLocation, context: IChatParserContext | undefined): ChatRequestAgentPart | undefined {
124 const nextAgentMatch = message.match(agentReg);
125 if (!nextAgentMatch) {
171 return new ChatRequestAgentPart(agentRange, agentEditorRange, agent);
172 }
174 > private tryToParseVariable(message: string, offset: number, position: IPosition, parts: ReadonlyArray<IParsedChatRequestPart>, toolsByName: ReadonlyMap<string, IToolData>, toolSetsByName: ReadonlyMap<string, IToolSet>): ChatRequestToolPart | ChatRequestToolSetPart | undefined {
175 const nextVariableMatch = message.match(variableReg);
176 if (!nextVariableMatch) {
195 return;
196 }
198 > private tryToParseSlashCommand(remainingMessage: string, fullMessage: string, offset: number, position: IPosition, parts: ReadonlyArray<IParsedChatRequestPart>, location: ChatAgentLocation, context?: IChatParserContext): ChatRequestSlashCommandPart | ChatRequestAgentSubcommandPart | ChatRequestSlashPromptPart | undefined {
199 const nextSlashMatch = remainingMessage.match(slashReg);
200 if (!nextSlashMatch) {
276 return;
277 }
279 > private tryToParseDynamicVariable(message: string, offset: number, position: IPosition, references: ReadonlyArray<IDynamicVariable>): ChatRequestDynamicVariablePart | undefined {
280 const refAtThisPosition = references.find(r =>
281 r.range.startLineNumber === position.lineNumber &&
src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts 20 introduced LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mockChatVariables.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 { ResourceMap } from '../../../../../base/common/map.js';
7 > import { URI } from '../../../../../base/common/uri.js';
8 > import { IChatVariablesService, IDynamicVariable } from '../../common/attachments/chatVariables.js';
9 > import { ToolAndToolSetEnablementMap } from '../../common/tools/languageModelToolsService.js';
10 >
11 > export class MockChatVariablesService implements IChatVariablesService {
12 _serviceBrand: undefined;
13
14 private _dynamicVariables = new ResourceMap<readonly IDynamicVariable[]>();
15 private _selectedToolAndToolSets = new ResourceMap<ToolAndToolSetEnablementMap>();
17 > getDynamicVariables(sessionResource: URI): readonly IDynamicVariable[] {
18 return this._dynamicVariables.get(sessionResource) ?? [];
19 }
21 > getSelectedToolAndToolSets(sessionResource: URI): ToolAndToolSetEnablementMap {
22 return this._selectedToolAndToolSets.get(sessionResource) ?? ToolAndToolSetEnablementMap.fromEntries([]);
23 }
25 > setDynamicVariables(sessionResource: URI, variables: readonly IDynamicVariable[]): void {
26 this._dynamicVariables.set(sessionResource, variables);
27 }
29 > setSelectedToolAndToolSets(sessionResource: URI, tools: ToolAndToolSetEnablementMap): void {
30 this._selectedToolAndToolSets.set(sessionResource, tools);
31 }
src/vs/workbench/contrib/chat/common/tools/languageModelToolsService.ts 1 introduced LOC · 1 range

Open complete file

461
462 private constructor(private readonly _map: Map<IToolData | IToolSet, boolean>) {
464
465 [Symbol.iterator](): IterableIterator<[IToolData | IToolSet, boolean]> {