Skip to content
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
19 changes: 19 additions & 0 deletions .github/instructions/kusto.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
description: Kusto exploration and telemetry analysis instructions
---

# Kusto Exploration Instructions

When performing Kusto queries, telemetry analysis, or data exploration tasks for VS Code, consult the comprehensive Kusto instructions located at:

**[kusto-vscode-instructions.md](../../../vscode-internalbacklog/instructions/kusto/kusto-vscode-instructions.md)**

These instructions contain valuable information about:
- Available Kusto clusters and databases for VS Code telemetry
- Common query patterns and best practices
- Schema information and table structures
- Tips for effective data exploration

Reading these instructions before writing Kusto queries will help you write more accurate and efficient queries, avoid common pitfalls, and leverage existing knowledge about VS Code's telemetry infrastructure.

(Make sure to have the main branch of vscode-internalbacklog up to date in case there are problems).
2 changes: 1 addition & 1 deletion src/vs/platform/update/electron-main/updateService.snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export class SnapUpdateService extends AbstractUpdateService {
const onDebouncedCurrentChange = Event.debounce(onCurrentChange, (_, e) => e, 2000);
const listener = onDebouncedCurrentChange(() => this.checkForUpdates(false));

lifecycleMainService.onWillShutdown(() => {
Event.once(lifecycleMainService.onWillShutdown)(() => {
listener.dispose();
watcher.close();
});
Expand Down
21 changes: 18 additions & 3 deletions src/vs/workbench/api/common/extHostTypeConverters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2843,14 +2843,29 @@ export namespace ChatResponseExtensionsPart {
}

export namespace ChatResponsePullRequestPart {
export function from(part: vscode.ChatResponsePullRequestPart): Dto<IChatPullRequestContent> {
export function from(part: Omit<vscode.ChatResponsePullRequestPart, 'command'> & { command?: vscode.Command }, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): Dto<IChatPullRequestContent> {
// If the command isn't in the converter, then this session may have been restored, and the command args don't exist anymore
let command: extHostProtocol.ICommandDto;
if (!part.command) {
if (!part.uri) {
throw new Error('Pull request part must have a command if URI is provided');
}
command = {
title: 'Open Pull Request',
id: 'vscode.open',
arguments: [part.uri]
};
} else {
command = commandsConverter.toInternal(part.command, commandDisposables);
}
return {
kind: 'pullRequest',
author: part.author,
title: part.title,
description: part.description,
uri: part.uri,
linkTag: part.linkTag
linkTag: part.linkTag,
command
};
}
}
Expand Down Expand Up @@ -3296,7 +3311,7 @@ export namespace ChatResponsePart {
} else if (part instanceof types.ChatResponseExtensionsPart) {
return ChatResponseExtensionsPart.from(part);
} else if (part instanceof types.ChatResponsePullRequestPart) {
return ChatResponsePullRequestPart.from(part);
return ChatResponsePullRequestPart.from(part, commandsConverter, commandDisposables);
} else if (part instanceof types.ChatToolInvocationPart) {
return ChatToolInvocationPart.from(part);
} else if (part instanceof types.ChatResponseWorkspaceEditPart) {
Expand Down
17 changes: 15 additions & 2 deletions src/vs/workbench/api/common/extHostTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { MarshalledId } from '../../../base/common/marshallingIds.js';
import { Mimes } from '../../../base/common/mime.js';
import { nextCharLength } from '../../../base/common/strings.js';
import { isNumber, isObject, isString, isStringArray } from '../../../base/common/types.js';
import { URI } from '../../../base/common/uri.js';
import { isUriComponents, URI } from '../../../base/common/uri.js';
import { generateUuid } from '../../../base/common/uuid.js';
import { TextEditorSelectionSource } from '../../../platform/editor/common/editor.js';
import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
Expand Down Expand Up @@ -3298,13 +3298,26 @@ export class ChatResponseExtensionsPart {
}

export class ChatResponsePullRequestPart {
public readonly uri?: vscode.Uri;
public readonly command: vscode.Command;

constructor(
public readonly uri: vscode.Uri,
uriOrCommand: vscode.Uri | vscode.Command,
public readonly title: string,
public readonly description: string,
public readonly author: string,
public readonly linkTag: string
) {
if (isUriComponents(uriOrCommand)) {
this.uri = uriOrCommand as vscode.Uri;
this.command = {
title: 'Open Pull Request',
command: 'vscode.open',
arguments: [uriOrCommand]
};
} else {
this.command = uriOrCommand;
}
}

toJSON() {
Expand Down
16 changes: 10 additions & 6 deletions src/vs/workbench/browser/parts/editor/media/modalEditorPart.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

/** Modal Editor Part: Shadow Container */
.monaco-modal-editor-block .modal-editor-shadow {
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
box-shadow: 0 4px 32px var(--vscode-widget-shadow, rgba(0, 0, 0, 0.2));
border-radius: 8px;
overflow: hidden;
}
Expand All @@ -49,21 +49,21 @@
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
height: 24px;
min-height: 24px;
padding: 0 8px;
height: 32px;
min-height: 32px;
padding: 0 8px 0 16px;
background-color: var(--vscode-titleBar-activeBackground);
border-bottom: 1px solid var(--vscode-titleBar-border, transparent);
}

.monaco-modal-editor-block .modal-editor-title {
grid-column: 2;
grid-column: 1;
font-size: 12px;
font-weight: 500;
color: var(--vscode-titleBar-activeForeground);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center;
}

.monaco-modal-editor-block .modal-editor-action-container {
Expand All @@ -73,6 +73,10 @@
justify-content: flex-end;
}

.monaco-modal-editor-block .modal-editor-action-container .actions-container {
gap: 4px;
}

/** Modal Editor Part: Ensure proper sizing */
.monaco-modal-editor-block .modal-editor-part .content {
flex: 1;
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/browser/parts/editor/modalEditorPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class ModalEditorPart {
editorPartContainer.style.height = `${height}px`;

const borderSize = 2; // Account for 1px border on all sides and modal header height
const headerHeight = 24 + 1 /* border bottom */;
const headerHeight = 32 + 1 /* border bottom */;
editorPart.layout(width - borderSize, height - borderSize - headerHeight, 0, 0);
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ import { IChatContentPart } from './chatContentParts.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { ThemeIcon } from '../../../../../../base/common/themables.js';
import { addDisposableListener } from '../../../../../../base/browser/dom.js';
import { IOpenerService } from '../../../../../../platform/opener/common/opener.js';
import { ICommandService } from '../../../../../../platform/commands/common/commands.js';

export class ChatPullRequestContentPart extends Disposable implements IChatContentPart {
public readonly domNode: HTMLElement;

constructor(
private readonly pullRequestContent: IChatPullRequestContent,
@IOpenerService private readonly openerService: IOpenerService
) {
@ICommandService private readonly commandService: ICommandService) {
super();

this.domNode = dom.$('.chat-pull-request-content-part');
Expand All @@ -33,11 +32,13 @@ export class ChatPullRequestContentPart extends Disposable implements IChatConte
icon.classList.add(...ThemeIcon.asClassNameArray(Codicon.gitPullRequest));
const titleLink: HTMLAnchorElement = dom.append(titleContainer, dom.$('a.title'));
titleLink.textContent = `${this.pullRequestContent.title} - ${this.pullRequestContent.author}`;
titleLink.href = this.pullRequestContent.uri.toString();
if (this.pullRequestContent.uri) {
titleLink.href = this.pullRequestContent.uri?.toString();
}
this._register(addDisposableListener(titleLink, 'click', (e) => {
e.preventDefault();
e.stopPropagation();
this.openerService.open(this.pullRequestContent.uri, { allowCommands: true });
this.commandService.executeCommand(this.pullRequestContent.command.id, ...(this.pullRequestContent.command.arguments ?? []));
}));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2007,8 +2007,9 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
return part;
}

// Render the active carousel in the input part (above the input box)
const part = widget?.input.renderQuestionCarousel(carousel, context, {
// Render the active carousel in the input part (above the input box, not while editing)
const isEditing = !!this.viewModel?.editing;
const part = isEditing ? undefined : widget?.input.renderQuestionCarousel(carousel, context, {
shouldAutoFocus,
onSubmit: async (answers) => handleSubmit(answers, part!)
});
Expand Down
26 changes: 21 additions & 5 deletions src/vs/workbench/contrib/chat/browser/widget/chatListWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ export class ChatListWidget extends Disposable {
private _lastItem: ChatTreeItem | undefined;
private _mostRecentlyFocusedItemIndex: number = -1;
private _scrollLock: boolean = true;
private _suppressAutoScroll: boolean = false;
private _settingChangeCounter: number = 0;
private _visibleChangeCount: number = 0;

Expand Down Expand Up @@ -525,7 +526,6 @@ export class ChatListWidget extends Disposable {
}));

const editing = this._viewModel.editing;
const checkpoint = this._viewModel.model?.checkpoint;

this._withPersistedAutoScroll(() => {
this._tree.setChildren(null, treeItems, {
Expand All @@ -534,6 +534,9 @@ export class ChatListWidget extends Disposable {
// Pending types only have 'id', request/response have 'dataId'
const baseId = (isRequestVM(element) || isResponseVM(element)) ? element.dataId : element.id;
const disablement = (isRequestVM(element) || isResponseVM(element)) ? element.shouldBeRemovedOnSend : undefined;
// Per-element editing state: only re-render items whose editing role changed
const isEditTarget = isRequestVM(element) && editing?.id === element.id;
const isBlocked = (isRequestVM(element) || isResponseVM(element)) ? element.shouldBeBlocked.get() : false;
return baseId +
// If a response is in the process of progressive rendering, we need to ensure that it will
// be re-rendered so progressive rendering is restarted, even if the model wasn't updated.
Expand All @@ -542,10 +545,11 @@ export class ChatListWidget extends Disposable {
(isResponseVM(element) ? `_${element.contentReferences.length}` : '') +
// Re-render if element becomes hidden due to undo/redo
`_${disablement ? `${disablement.afterUndoStop || '1'}` : '0'}` +
// Re-render if we have an element currently being edited
`_${editing ? '1' : '0'}` +
// Re-render if we have an element currently being checkpointed
`_${checkpoint ? '1' : '0'}` +
// Re-render the request being edited and requests whose blocked state changed
`_${isEditTarget ? 'edit' : ''}` +
`_${isBlocked ? 'blocked' : ''}` +
// Re-render requests when editing starts/stops (for hover button visibility, click handlers)
(isRequestVM(element) ? `_${editing ? '1' : '0'}` : '') +
// Re-render all if invoked by setting change
`_setting${this._settingChangeCounter}` +
// Rerender request if we got new content references in the response
Expand Down Expand Up @@ -706,7 +710,19 @@ export class ChatListWidget extends Disposable {
}
}

/**
* Suppress auto-scroll behavior temporarily. While suppressed,
* _withPersistedAutoScroll will not scroll to bottom after operations.
*/
set suppressAutoScroll(value: boolean) {
this._suppressAutoScroll = value;
}

private _withPersistedAutoScroll(fn: () => void): void {
if (this._suppressAutoScroll) {
fn();
return;
}
const wasScrolledToBottom = this.isScrolledToBottom;
fn();
if (wasScrolledToBottom) {
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
this.inputPart.dnd.setDisabledOverlay(!isInput);
this.input.renderAttachedContext();
this.input.setValue(currentElement.messageText, false);
this.listWidget.suppressAutoScroll = true;
this.onDidChangeItems();
this.input.inputEditor.focus();

Expand Down Expand Up @@ -1586,6 +1587,7 @@ export class ChatWidget extends Disposable implements IChatWidget {

finishedEditing(completedEdit?: boolean): void {
// reset states
this.listWidget.suppressAutoScroll = false;
const editedRequest = this.listWidget.getTemplateDataForRequestId(this.viewModel?.editing?.id);
if (this.recentlyRestoredCheckpoint) {
this.recentlyRestoredCheckpoint = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ export interface ILegacyChatTerminalToolInvocationData {
}

export function isLegacyChatTerminalToolInvocationData(data: unknown): data is ILegacyChatTerminalToolInvocationData {
return !!data && typeof data === 'object' && 'command' in data;
return !!data && typeof data === 'object' && 'command' in data && 'language' in data;
}

export interface IChatToolInputInvocationData {
Expand Down Expand Up @@ -817,7 +817,11 @@ export interface IChatExtensionsContent {
}

export interface IChatPullRequestContent {
uri: URI;
/**
* @deprecated use `command` instead
*/
uri?: URI;
command: Command;
title: string;
description: string;
author: string;
Expand Down
9 changes: 9 additions & 0 deletions src/vs/workbench/contrib/chat/common/model/chatModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2305,6 +2305,9 @@ export class ChatModel extends Disposable implements IChatModel {
resetCheckpoint(): void {
for (const request of this._requests) {
request.setShouldBeBlocked(false);
if (request.response) {
request.response.setBlockedState(false);
}
}
}

Expand All @@ -2329,13 +2332,19 @@ export class ChatModel extends Disposable implements IChatModel {
const request = this._requests[i];
if (this._checkpoint && !checkpoint) {
request.setShouldBeBlocked(false);
if (request.response) {
request.response.setBlockedState(false);
}
} else if (checkpoint && i >= checkpointIndex) {
request.setShouldBeBlocked(true);
if (request.response) {
request.response.setBlockedState(true);
}
} else if (checkpoint && i < checkpointIndex) {
request.setShouldBeBlocked(false);
if (request.response) {
request.response.setBlockedState(false);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const HOOK_TYPES = [
{
id: HookType.PreToolUse,
label: nls.localize('hookType.preToolUse.label', "Pre-Tool Use"),
description: nls.localize('hookType.preToolUse.description', "Executed before the agent uses any tool (such as bash, edit, view).")
description: nls.localize('hookType.preToolUse.description', "Executed before the agent uses any tool.")
},
{
id: HookType.PostToolUse,
Expand Down Expand Up @@ -181,7 +181,7 @@ export const hookFileSchema: IJSONSchema = {
},
PreToolUse: {
...hookArraySchema,
description: nls.localize('hookFile.preToolUse', 'Executed before the agent uses any tool (such as bash, edit, view). This is the most powerful hook as it can approve or deny tool executions. Use to block dangerous commands, enforce security policies, require approval for sensitive operations, or log tool usage.')
description: nls.localize('hookFile.preToolUse', 'Executed before the agent uses any tool. This is the most powerful hook as it can approve or deny tool executions. Use to block dangerous commands, enforce security policies, require approval for sensitive operations, or log tool usage.')
},
PostToolUse: {
...hookArraySchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ suite('ChatResponseAccessibleView', () => {
const prData: IChatPullRequestContent = {
kind: 'pullRequest',
uri: URI.file('/test'),
command: { id: 'vscode.open', title: 'Open Pull Request', arguments: [URI.file('/test')] },
title: 'Add new feature',
description: 'This PR adds a great feature',
author: 'testuser',
Expand Down
Loading
Loading