Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
03a4ecc
Initial plan
Copilot Jan 14, 2026
598e8cb
Implement locked optionGroup display - show grayed out and non-clickable
Copilot Jan 14, 2026
572915a
Address code review feedback - improve locked state implementation
Copilot Jan 14, 2026
84ef88d
Refactor updateEnabled to directly compute effective disabled state
Copilot Jan 14, 2026
93fac91
Fix trailing whitespace in modified files
Copilot Jan 14, 2026
bebe212
Remove 'as any' type casts - use proper action.enabled modification
Copilot Jan 14, 2026
fc49714
Remove lock icon - keep chevron and gray out when locked
Copilot Jan 14, 2026
a7de968
Reapply timing and chat session changes
mjbvz Jan 14, 2026
aafd5f9
Add support for custom file link rendering metadata (#286839)
pwang347 Jan 14, 2026
5bef030
Merge pull request #287881 from mjbvz/dev/mjbvz/arbitrary-owl
mjbvz Jan 14, 2026
0d6b648
fix unneeded code
joshspicer Jan 14, 2026
bcb685b
change opacity and color to match 'Set Session Target'
joshspicer Jan 14, 2026
602c17d
refactor searchableOptionPickerActionItem.ts to extend from chatSessi…
joshspicer Jan 14, 2026
586f815
fix chevron disabled opacity
joshspicer Jan 14, 2026
32cdd27
Implement UX for running subagents in parallel (#287687)
roblourens Jan 14, 2026
593782b
Update src/vs/workbench/contrib/chat/browser/chatSessions/media/chatS…
joshspicer Jan 15, 2026
c95fddb
Merge pull request #287808 from microsoft/copilot/fix-locked-optiongr…
joshspicer Jan 15, 2026
1a285a3
Update open chat command behavior for quick chat (#287918)
Copilot Jan 15, 2026
628f19a
Harden handling of old timing info
mjbvz Jan 15, 2026
53460a1
support local sessions in focus view service (#287927)
joshspicer Jan 15, 2026
6cb58a3
Unify agent skills internal architecture (#286860)
pwang347 Jan 15, 2026
5613569
Merge pull request #287932 from mjbvz/dev/mjbvz/youthful-mollusk
mjbvz Jan 15, 2026
97b6da8
Enable agent skills by default (#287930)
pwang347 Jan 15, 2026
4dbed81
Don't have default tool progress message (#287938)
lramos15 Jan 15, 2026
be3d856
use a vscode theme color for focusView (#287891)
joshspicer Jan 15, 2026
daf2ea5
swap around icons and indicators in the title bar agents control (#28…
joshspicer Jan 15, 2026
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
3 changes: 2 additions & 1 deletion build/lib/stylelint/vscode-known-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,8 @@
"--comment-thread-editor-font-weight",
"--comment-thread-state-color",
"--comment-thread-state-background-color",
"--inline-edit-border-radius"
"--inline-edit-border-radius",
"--chat-subagent-last-item-height"
],
"sizes": [
"--vscode-bodyFontSize",
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ export default tseslint.config(
],
'verbs': [
'accept',
'archive',
'change',
'close',
'collapse',
Expand Down
4 changes: 4 additions & 0 deletions src/vs/base/common/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const year = day * 365;
* is less than 30 seconds.
*/
export function fromNow(date: number | Date, appendAgoLabel?: boolean, useFullTimeWords?: boolean, disallowNow?: boolean): string {
if (typeof date === 'undefined') {
return localize('date.fromNow.unknown', 'unknown');
}

if (typeof date !== 'number') {
date = date.getTime();
}
Expand Down
47 changes: 47 additions & 0 deletions src/vs/base/common/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,53 @@ export function lcut(text: string, n: number, prefix = ''): string {
return prefix + trimmed.substring(i).trimStart();
}

/**
* Given a string and a max length returns a shortened version keeping the beginning.
* Shortening happens at favorable positions - such as whitespace or punctuation characters.
* Trailing whitespace is always trimmed.
*/
export function rcut(text: string, n: number, suffix = ''): string {
const trimmed = text.trimEnd();

if (trimmed.length <= n) {
return trimmed;
}

const re = /\b/g;
let lastGoodBreak = 0;
let foundBoundaryAfterN = false;
while (re.test(trimmed)) {
if (re.lastIndex > n) {
foundBoundaryAfterN = true;
break;
}
lastGoodBreak = re.lastIndex;
re.lastIndex += 1;
}

// If no boundary was found after n, return the full trimmed string
// (there's no good place to cut)
if (!foundBoundaryAfterN) {
return trimmed;
}

// If the only boundary <= n is at position 0 (start of string),
// cutting there gives empty string, so just return the suffix
if (lastGoodBreak === 0) {
return suffix;
}

const result = trimmed.substring(0, lastGoodBreak).trimEnd();

// If trimEnd removed more than half of what we cut (meaning we cut
// mostly through whitespace), return the full string instead
if (result.length < lastGoodBreak / 2) {
return trimmed;
}

return result + suffix;
}

// Defacto standard: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
const CSI_SEQUENCE = /(?:\x1b\[|\x9b)[=?>!]?[\d;:]*["$#'* ]?[a-zA-Z@^`{}|~]/;
const OSC_SEQUENCE = /(?:\x1b\]|\x9d).*?(?:\x1b\\|\x07|\x9c)/;
Expand Down
34 changes: 34 additions & 0 deletions src/vs/base/test/common/strings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,40 @@ suite('Strings', () => {
assert.strictEqual(strings.lcut('............a', 10, '…'), '............a');
});

test('rcut', () => {
assert.strictEqual(strings.rcut('foo bar', 0), '');
assert.strictEqual(strings.rcut('foo bar', 1), '');
assert.strictEqual(strings.rcut('foo bar', 3), 'foo');
assert.strictEqual(strings.rcut('foo bar', 4), 'foo'); // Trailing whitespace trimmed
assert.strictEqual(strings.rcut('foo bar', 5), 'foo');
assert.strictEqual(strings.rcut('foo bar', 7), 'foo bar');
assert.strictEqual(strings.rcut('foo bar', 10), 'foo bar');
assert.strictEqual(strings.rcut('test string 0.1.2.3', 6), 'test');

assert.strictEqual(strings.rcut('foo bar', 0, '…'), '…');
assert.strictEqual(strings.rcut('foo bar', 1, '…'), '…');
assert.strictEqual(strings.rcut('foo bar', 3, '…'), 'foo…');
assert.strictEqual(strings.rcut('foo bar', 4, '…'), 'foo…'); // Trailing whitespace trimmed
assert.strictEqual(strings.rcut('foo bar', 5, '…'), 'foo…');
assert.strictEqual(strings.rcut('foo bar', 7, '…'), 'foo bar');
assert.strictEqual(strings.rcut('foo bar', 10, '…'), 'foo bar');
assert.strictEqual(strings.rcut('test string 0.1.2.3', 6, '…'), 'test…');

assert.strictEqual(strings.rcut('', 10), '');
assert.strictEqual(strings.rcut('a', 10), 'a');
assert.strictEqual(strings.rcut('a ', 10), 'a');
assert.strictEqual(strings.rcut('a ', 10), 'a');
assert.strictEqual(strings.rcut('a bbbb ', 10), 'a bbbb');
assert.strictEqual(strings.rcut('a............', 10), 'a............');

assert.strictEqual(strings.rcut('', 10, '…'), '');
assert.strictEqual(strings.rcut('a', 10, '…'), 'a');
assert.strictEqual(strings.rcut('a ', 10, '…'), 'a');
assert.strictEqual(strings.rcut('a ', 10, '…'), 'a');
assert.strictEqual(strings.rcut('a bbbb ', 10, '…'), 'a bbbb');
assert.strictEqual(strings.rcut('a............', 10, '…'), 'a............');
});

test('escape', () => {
assert.strictEqual(strings.escape(''), '');
assert.strictEqual(strings.escape('foo'), 'foo');
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/api/browser/mainThreadChatAgents2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
toolId: progress.toolName,
chatRequestId: requestId,
sessionResource: chatSession?.sessionResource,
subagentInvocationId: progress.subagentInvocationId
});
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/browser/mainThreadChatSessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,6 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
));
}


$onDidChangeChatSessionItems(handle: number): void {
this._itemProvidersRegistrations.get(handle)?.onDidChangeItems.fire();
}
Expand Down Expand Up @@ -491,6 +490,7 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
resource: uri,
iconPath: session.iconPath,
tooltip: session.tooltip ? this._reviveTooltip(session.tooltip) : undefined,
archived: session.archived,
} satisfies IChatSessionItem;
}));
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class MainThreadLanguageModelTools extends Disposable implements MainThre
return fn.countTokens(input, token);
}

$registerTool(id: string): void {
$registerTool(id: string, hasHandleToolStream: boolean): void {
const disposable = this._languageModelToolsService.registerToolImplementation(
id,
{
Expand All @@ -93,7 +93,7 @@ export class MainThreadLanguageModelTools extends Disposable implements MainThre
}
},
prepareToolInvocation: (context, token) => this._proxy.$prepareToolInvocation(id, context, token),
handleToolStream: (context, token) => this._proxy.$handleToolStream(id, context, token),
handleToolStream: hasHandleToolStream ? (context, token) => this._proxy.$handleToolStream(id, context, token) : undefined,
});
this._tools.set(id, disposable);
}
Expand Down
4 changes: 4 additions & 0 deletions src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension, 'chatSessionsProvider');
return extHostChatSessions.registerChatSessionItemProvider(extension, chatSessionType, provider);
},
createChatSessionItemController: (chatSessionType: string, refreshHandler: () => Thenable<void>) => {
checkProposedApiEnabled(extension, 'chatSessionsProvider');
return extHostChatSessions.createChatSessionItemController(extension, chatSessionType, refreshHandler);
},
registerChatSessionContentProvider(scheme: string, provider: vscode.ChatSessionContentProvider, chatParticipant: vscode.ChatParticipant, capabilities?: vscode.ChatSessionCapabilities) {
checkProposedApiEnabled(extension, 'chatSessionsProvider');
return extHostChatSessions.registerChatSessionContentProvider(extension, scheme, chatParticipant, provider, capabilities);
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1498,7 +1498,7 @@ export interface MainThreadLanguageModelToolsShape extends IDisposable {
$acceptToolProgress(callId: string, progress: IToolProgressStep): void;
$invokeTool(dto: Dto<IToolInvocation>, token?: CancellationToken): Promise<Dto<IToolResult> | SerializableObjectWithBuffers<Dto<IToolResult>>>;
$countTokensForInvocation(callId: string, input: string, token: CancellationToken): Promise<number>;
$registerTool(id: string): void;
$registerTool(id: string, hasHandleToolStream: boolean): void;
$unregisterTool(name: string): void;
}

Expand Down Expand Up @@ -2330,6 +2330,7 @@ export interface IChatBeginToolInvocationDto {
streamData?: {
partialInput?: unknown;
};
subagentInvocationId?: string;
}

export interface IChatUpdateToolInvocationDto {
Expand Down
5 changes: 4 additions & 1 deletion src/vs/workbench/api/common/extHostChatAgents2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,8 @@ export class ChatAgentResponseStream {
toolName,
streamData: streamData ? {
partialInput: streamData.partialInput
} : undefined
} : undefined,
subagentInvocationId: streamData?.subagentInvocationId
};
_report(dto);
return this;
Expand Down Expand Up @@ -559,6 +560,8 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS
return await (provider as vscode.InstructionsProvider).provideInstructions(context, token) ?? undefined;
case PromptsType.prompt:
return await (provider as vscode.PromptFileProvider).providePromptFiles(context, token) ?? undefined;
case PromptsType.skill:
throw new Error('Skills prompt file provider not implemented yet');
}
}

Expand Down
Loading
Loading