mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-24 01:11:34 +01:00
Display background agent todo tool results (#3400)
* Display background agent tool results * wip tools
This commit is contained in:
@@ -5,11 +5,12 @@
|
||||
|
||||
import type { SessionEvent, ToolExecutionCompleteEvent, ToolExecutionStartEvent } from '@github/copilot/sdk';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import type { ChatPromptReference, ChatTerminalToolInvocationData, ExtendedChatResponsePart } from 'vscode';
|
||||
import type { ChatPromptReference, ChatTerminalToolInvocationData, ChatTodoStatus, ChatTodoToolInvocationData, ExtendedChatResponsePart } from 'vscode';
|
||||
import { ILogger } from '../../../../platform/log/common/logService';
|
||||
import { isLocation } from '../../../../util/common/types';
|
||||
import { decodeBase64 } from '../../../../util/vs/base/common/buffer';
|
||||
import { ResourceSet } from '../../../../util/vs/base/common/map';
|
||||
import { isAbsolutePath } from '../../../../util/vs/base/common/resources';
|
||||
import { URI } from '../../../../util/vs/base/common/uri';
|
||||
import { ChatMcpToolInvocationData, ChatRequestTurn2, ChatResponseCodeblockUriPart, ChatResponseMarkdownPart, ChatResponsePullRequestPart, ChatResponseTextEditPart, ChatResponseThinkingProgressPart, ChatResponseTurn2, ChatToolInvocationPart, Location, MarkdownString, McpToolInvocationContentData, Range, Uri } from '../../../../vscodeTypes';
|
||||
import type { MCP } from '../../../common/modelContextProtocol';
|
||||
@@ -309,7 +310,7 @@ function extractPRMetadata(content: string): { cleanedContent: string; prPart?:
|
||||
* Build chat history from SDK events for VS Code chat session
|
||||
* Converts SDKEvents into ChatRequestTurn2 and ChatResponseTurn2 objects
|
||||
*/
|
||||
export function buildChatHistoryFromEvents(sessionId: string, events: readonly SessionEvent[], getVSCodeRequestId: (sdkRequestId: string) => { requestId: string; toolIdEditMap: Record<string, string> } | undefined, delegationSummaryService: IChatDelegationSummaryService, logger: ILogger): (ChatRequestTurn2 | ChatResponseTurn2)[] {
|
||||
export function buildChatHistoryFromEvents(sessionId: string, events: readonly SessionEvent[], getVSCodeRequestId: (sdkRequestId: string) => { requestId: string; toolIdEditMap: Record<string, string> } | undefined, delegationSummaryService: IChatDelegationSummaryService, logger: ILogger, workingDirectory?: URI): (ChatRequestTurn2 | ChatResponseTurn2)[] {
|
||||
const turns: (ChatRequestTurn2 | ChatResponseTurn2)[] = [];
|
||||
let currentResponseParts: ExtendedChatResponsePart[] = [];
|
||||
const pendingToolInvocations = new Map<string, [ChatToolInvocationPart, toolData: ToolCall]>();
|
||||
@@ -431,7 +432,7 @@ export function buildChatHistoryFromEvents(sessionId: string, events: readonly S
|
||||
break;
|
||||
}
|
||||
case 'tool.execution_complete': {
|
||||
const [responsePart, toolCall] = processToolExecutionComplete(event, pendingToolInvocations, logger) ?? [undefined, undefined];
|
||||
const [responsePart, toolCall] = processToolExecutionComplete(event, pendingToolInvocations, logger, workingDirectory) ?? [undefined, undefined];
|
||||
if (responsePart && toolCall && !(responsePart instanceof ChatResponseThinkingProgressPart)) {
|
||||
const editId = details?.toolIdEditMap ? details.toolIdEditMap[toolCall.toolCallId] : undefined;
|
||||
const editedUris = getAffectedUrisForEditTool(toolCall);
|
||||
@@ -563,7 +564,7 @@ export function processToolExecutionStart(event: ToolExecutionStartEvent, pendin
|
||||
return toolInvocation;
|
||||
}
|
||||
|
||||
export function processToolExecutionComplete(event: ToolExecutionCompleteEvent, pendingToolInvocations: Map<string, [ChatToolInvocationPart | ChatResponseThinkingProgressPart, toolData: ToolCall]>, logger: ILogger): [ChatToolInvocationPart | ChatResponseThinkingProgressPart, toolData: ToolCall] | undefined {
|
||||
export function processToolExecutionComplete(event: ToolExecutionCompleteEvent, pendingToolInvocations: Map<string, [ChatToolInvocationPart | ChatResponseThinkingProgressPart, toolData: ToolCall]>, logger: ILogger, workingDirectory?: URI): [ChatToolInvocationPart | ChatResponseThinkingProgressPart, toolData: ToolCall] | undefined {
|
||||
const invocation = pendingToolInvocations.get(event.data.toolCallId);
|
||||
pendingToolInvocations.delete(event.data.toolCallId);
|
||||
|
||||
@@ -594,26 +595,9 @@ export function processToolExecutionComplete(event: ToolExecutionCompleteEvent,
|
||||
}
|
||||
}
|
||||
|
||||
if (toolCall.toolName === 'bash' || toolCall.toolName === 'powershell') {
|
||||
const result = event.data.result?.content || '';
|
||||
// Exit code will be at the end of the result in the last line in the form of `<exited with exit code ${output.exitCode}>`,
|
||||
const exitCodeStr = result ? /<exited with exit code (\d+)>$/.exec(result)?.[1] : undefined;
|
||||
const exitCode = exitCodeStr ? parseInt(exitCodeStr, 10) : undefined;
|
||||
// Lets remove the last line containing the exit code from the output.
|
||||
const text = (exitCode !== undefined ? result.replace(/<exited with exit code \d+>$/, '').trimEnd() : result).replace(/\n/g, '\r\n');
|
||||
const toolSpecificData: ChatTerminalToolInvocationData = {
|
||||
commandLine: {
|
||||
original: toolCall.arguments.command,
|
||||
},
|
||||
language: toolCall.toolName === 'bash' ? 'bash' : 'powershell',
|
||||
state: {
|
||||
exitCode
|
||||
},
|
||||
output: {
|
||||
text
|
||||
}
|
||||
};
|
||||
invocation[0].toolSpecificData = toolSpecificData;
|
||||
if (Object.hasOwn(ToolFriendlyNameAndHandlers, toolCall.toolName)) {
|
||||
const [, , postFormatter] = ToolFriendlyNameAndHandlers[toolCall.toolName];
|
||||
(postFormatter as PostInvocationFormatter)(invocation[0], toolCall, event.data, workingDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,37 +639,40 @@ export function createCopilotCLIToolInvocation(data: { toolCallId: string; toolN
|
||||
}
|
||||
|
||||
type Formatter = (invocation: ChatToolInvocationPart, toolCall: ToolCall, editId?: string) => void;
|
||||
type PostInvocationFormatter = (invocation: ChatToolInvocationPart, toolCall: ToolCall, result: ToolCallResult, workingDirectory?: URI) => void;
|
||||
type ToolCallFor<T extends ToolCall['toolName']> = Extract<ToolCall, { toolName: T }>;
|
||||
type ToolCallResult = ToolExecutionCompleteEvent['data'];
|
||||
|
||||
const ToolFriendlyNameAndHandlers: { [K in ToolCall['toolName']]: [string, (invocation: ChatToolInvocationPart, toolCall: ToolCallFor<K>) => void] } = {
|
||||
'str_replace_editor': [l10n.t('Edit File'), formatStrReplaceEditorInvocation],
|
||||
'edit': [l10n.t('Edit File'), formatEditToolInvocation],
|
||||
'str_replace': [l10n.t('Edit File'), formatEditToolInvocation],
|
||||
'create': [l10n.t('Create File'), formatCreateToolInvocation],
|
||||
'insert': [l10n.t('Edit File'), formatInsertToolInvocation],
|
||||
'undo_edit': [l10n.t('Edit File'), formatUndoEdit],
|
||||
'view': [l10n.t('Read'), formatViewToolInvocation],
|
||||
'bash': [l10n.t('Run Shell Command'), formatShellInvocation],
|
||||
'powershell': [l10n.t('Run Shell Command'), formatShellInvocation],
|
||||
'write_bash': [l10n.t('Write to Bash'), emptyInvocation],
|
||||
'write_powershell': [l10n.t('Write to PowerShell'), emptyInvocation],
|
||||
'read_bash': [l10n.t('Read Terminal'), emptyInvocation],
|
||||
'read_powershell': [l10n.t('Read Terminal'), emptyInvocation],
|
||||
'stop_bash': [l10n.t('Stop Terminal Session'), emptyInvocation],
|
||||
'stop_powershell': [l10n.t('Stop Terminal Session'), emptyInvocation],
|
||||
'search': [l10n.t('Search'), formatSearchToolInvocation],
|
||||
'grep': [l10n.t('Search'), formatSearchToolInvocation],
|
||||
'glob': [l10n.t('Search'), formatSearchToolInvocation],
|
||||
'search_bash': [l10n.t('Search'), formatSearchToolInvocation],
|
||||
'semantic_code_search': [l10n.t('Search'), formatSearchToolInvocation],
|
||||
'reply_to_comment': [l10n.t('Reply to Comment'), formatReplyToCommentInvocation],
|
||||
'code_review': [l10n.t('Code Review'), formatCodeReviewInvocation],
|
||||
'report_intent': [l10n.t('Report Intent'), emptyInvocation],
|
||||
'think': [l10n.t('Thinking'), emptyInvocation],
|
||||
'report_progress': [l10n.t('Progress update'), formatProgressToolInvocation],
|
||||
'web_fetch': [l10n.t('Fetch Web Content'), emptyInvocation],
|
||||
'web_search': [l10n.t('Web Search'), emptyInvocation],
|
||||
'update_todo': [l10n.t('Update Todo'), emptyInvocation],
|
||||
|
||||
const ToolFriendlyNameAndHandlers: { [K in ToolCall['toolName']]: [title: string, pre: (invocation: ChatToolInvocationPart, toolCall: ToolCallFor<K>) => void, post: (invocation: ChatToolInvocationPart, toolCall: ToolCallFor<K>, result: ToolCallResult) => void] } = {
|
||||
'str_replace_editor': [l10n.t('Edit File'), formatStrReplaceEditorInvocation, emptyInvocation],
|
||||
'edit': [l10n.t('Edit File'), formatEditToolInvocation, emptyInvocation],
|
||||
'str_replace': [l10n.t('Edit File'), formatEditToolInvocation, emptyInvocation],
|
||||
'create': [l10n.t('Create File'), formatCreateToolInvocation, emptyInvocation],
|
||||
'insert': [l10n.t('Edit File'), formatInsertToolInvocation, emptyInvocation],
|
||||
'undo_edit': [l10n.t('Edit File'), formatUndoEdit, emptyInvocation],
|
||||
'view': [l10n.t('Read'), formatViewToolInvocation, emptyInvocation],
|
||||
'bash': [l10n.t('Run Shell Command'), formatShellInvocation, formatShellInvocationCompleted],
|
||||
'powershell': [l10n.t('Run Shell Command'), formatShellInvocation, formatShellInvocationCompleted],
|
||||
'write_bash': [l10n.t('Write to Bash'), emptyInvocation, emptyInvocation],
|
||||
'write_powershell': [l10n.t('Write to PowerShell'), emptyInvocation, emptyInvocation],
|
||||
'read_bash': [l10n.t('Read Terminal'), emptyInvocation, emptyInvocation],
|
||||
'read_powershell': [l10n.t('Read Terminal'), emptyInvocation, emptyInvocation],
|
||||
'stop_bash': [l10n.t('Stop Terminal Session'), emptyInvocation, emptyInvocation],
|
||||
'stop_powershell': [l10n.t('Stop Terminal Session'), emptyInvocation, emptyInvocation],
|
||||
'search': [l10n.t('Search'), formatSearchToolInvocation, genericToolInvocationCompleted],
|
||||
'grep': [l10n.t('Search'), formatSearchToolInvocation, formatSearchToolInvocationCompleted],
|
||||
'glob': [l10n.t('Search'), formatSearchToolInvocation, formatSearchToolInvocationCompleted],
|
||||
'search_bash': [l10n.t('Search'), formatSearchToolInvocation, genericToolInvocationCompleted],
|
||||
'semantic_code_search': [l10n.t('Search'), formatSearchToolInvocation, genericToolInvocationCompleted],
|
||||
'reply_to_comment': [l10n.t('Reply to Comment'), formatReplyToCommentInvocation, genericToolInvocationCompleted],
|
||||
'code_review': [l10n.t('Code Review'), formatCodeReviewInvocation, genericToolInvocationCompleted],
|
||||
'report_intent': [l10n.t('Report Intent'), emptyInvocation, emptyInvocation],
|
||||
'think': [l10n.t('Thinking'), emptyInvocation, emptyInvocation],
|
||||
'report_progress': [l10n.t('Progress update'), formatProgressToolInvocation, genericToolInvocationCompleted],
|
||||
'web_fetch': [l10n.t('Fetch Web Content'), emptyInvocation, genericToolInvocationCompleted],
|
||||
'web_search': [l10n.t('Web Search'), emptyInvocation, genericToolInvocationCompleted],
|
||||
'update_todo': [l10n.t('Update Todo'), formatUpdateTodoInvocation, formatUpdateTodoInvocationCompleted],
|
||||
};
|
||||
|
||||
|
||||
@@ -810,6 +797,28 @@ function formatShellInvocation(invocation: ChatToolInvocationPart, toolCall: She
|
||||
language: toolCall.toolName === 'bash' ? 'bash' : 'powershell'
|
||||
} as ChatTerminalToolInvocationData;
|
||||
}
|
||||
function formatShellInvocationCompleted(invocation: ChatToolInvocationPart, toolCall: ShellTool, result: ToolCallResult): void {
|
||||
const resultContent = result.result?.content || '';
|
||||
// Exit code will be at the end of the result in the last line in the form of `<exited with exit code ${output.exitCode}>`,
|
||||
const exitCodeStr = resultContent ? /<exited with exit code (\d+)>$/.exec(resultContent)?.[1] : undefined;
|
||||
const exitCode = exitCodeStr ? parseInt(exitCodeStr, 10) : undefined;
|
||||
// Lets remove the last line containing the exit code from the output.
|
||||
const text = (exitCode !== undefined ? resultContent.replace(/<exited with exit code \d+>$/, '').trimEnd() : resultContent).replace(/\n/g, '\r\n');
|
||||
const toolSpecificData: ChatTerminalToolInvocationData = {
|
||||
commandLine: {
|
||||
original: toolCall.arguments.command,
|
||||
},
|
||||
language: toolCall.toolName === 'bash' ? 'bash' : 'powershell',
|
||||
state: {
|
||||
exitCode
|
||||
},
|
||||
output: {
|
||||
text
|
||||
}
|
||||
};
|
||||
invocation.toolSpecificData = toolSpecificData;
|
||||
|
||||
}
|
||||
function formatSearchToolInvocation(invocation: ChatToolInvocationPart, toolCall: SearchTool | GLobTool | GrepTool | SearchBashTool | SemanticCodeSearchTool): void {
|
||||
if (toolCall.toolName === 'search') {
|
||||
invocation.invocationMessage = `Criteria: ${toolCall.arguments.question} \nReason: ${toolCall.arguments.reason}`;
|
||||
@@ -819,10 +828,40 @@ function formatSearchToolInvocation(invocation: ChatToolInvocationPart, toolCall
|
||||
invocation.invocationMessage = `Command: \`${toolCall.arguments.command}\``;
|
||||
} else if (toolCall.toolName === 'glob') {
|
||||
const searchInPath = toolCall.arguments.path ? ` in \`${toolCall.arguments.path}\`` : '';
|
||||
invocation.invocationMessage = `Search: \`${toolCall.arguments.pattern}\`${searchInPath}`;
|
||||
invocation.invocationMessage = `Search for files matching \`${toolCall.arguments.pattern}\`${searchInPath}`;
|
||||
invocation.pastTenseMessage = `Searched for files matching \`${toolCall.arguments.pattern}\`${searchInPath}`;
|
||||
} else if (toolCall.toolName === 'grep') {
|
||||
const searchInPath = toolCall.arguments.path ? ` in \`${toolCall.arguments.path}\`` : '';
|
||||
invocation.invocationMessage = `Search: \`${toolCall.arguments.pattern}\`${searchInPath}`;
|
||||
invocation.invocationMessage = `Search for files matching \`${toolCall.arguments.pattern}\`${searchInPath}`;
|
||||
invocation.pastTenseMessage = `Searched for files matching \`${toolCall.arguments.pattern}\`${searchInPath}`;
|
||||
}
|
||||
}
|
||||
|
||||
function formatSearchToolInvocationCompleted(invocation: ChatToolInvocationPart, toolCall: SearchTool | GLobTool | GrepTool | SearchBashTool | SemanticCodeSearchTool, result: ToolCallResult, workingDirectory?: URI): void {
|
||||
if (toolCall.toolName === 'search') {
|
||||
// invocation.invocationMessage = `Criteria: ${toolCall.arguments.question} \nReason: ${toolCall.arguments.reason}`;
|
||||
} else if (toolCall.toolName === 'semantic_code_search') {
|
||||
// invocation.invocationMessage = `Criteria: ${toolCall.arguments.question}`;
|
||||
} else if (toolCall.toolName === 'search_bash') {
|
||||
// invocation.invocationMessage = `Command: \`${toolCall.arguments.command}\``;
|
||||
} else if (toolCall.toolName === 'glob' || toolCall.toolName === 'grep') {
|
||||
const noMatches = (result.result?.content || '').toLowerCase().includes('no matches found') || (result.result?.content || '').toLowerCase().includes('no files matched the pattern');
|
||||
const searchInPath = toolCall.arguments.path ? ` in \`${toolCall.arguments.path}\`` : '';
|
||||
const files = !noMatches && result.success && typeof result.result?.content === 'string' ? result.result.content.split('\n') : [];
|
||||
const successMessage = files.length ? `, ${files.length} result${files.length > 1 ? 's' : ''}` : '.';
|
||||
invocation.pastTenseMessage = `Searched for files matching \`${toolCall.arguments.pattern}\`${searchInPath}${successMessage}`;
|
||||
let searchPath = toolCall.arguments.path ? Uri.file(toolCall.arguments.path) : workingDirectory;
|
||||
if (toolCall.arguments.path && workingDirectory && searchPath && !isAbsolutePath(searchPath)) {
|
||||
searchPath = Uri.joinPath(workingDirectory, toolCall.arguments.path);
|
||||
}
|
||||
invocation.toolSpecificData = {
|
||||
values: files.map(file => {
|
||||
if (!file.startsWith('./') || !searchPath) {
|
||||
return Uri.file(file);
|
||||
}
|
||||
return Uri.joinPath(searchPath, file.substring(2));
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -840,10 +879,127 @@ function formatGenericInvocation(invocation: ChatToolInvocationPart, toolCall: U
|
||||
invocation.invocationMessage = l10n.t("Used tool: {0}", toolCall.toolName ?? 'unknown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse markdown todo list into structured ChatTodoToolInvocationData.
|
||||
* Extracts title from first non-empty line (strips leading #), parses checklist items,
|
||||
* and generates sequential numeric IDs.
|
||||
*/
|
||||
function parseTodoMarkdown(markdown: string): { title: string; todoList: Array<{ id: string; title: string; status: ChatTodoStatus }> } {
|
||||
const lines = markdown.split('\n');
|
||||
const todoList: Array<{ id: string; title: string; status: ChatTodoStatus }> = [];
|
||||
let title = 'Updated todo list';
|
||||
let inCodeBlock = false;
|
||||
let currentItem: { title: string; status: ChatTodoStatus } | null = null;
|
||||
|
||||
for (const line of lines) {
|
||||
// Track code fences
|
||||
if (line.trim().startsWith('```') || line.trim().startsWith('~~~')) {
|
||||
inCodeBlock = !inCodeBlock;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip lines inside code blocks
|
||||
if (inCodeBlock) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract title from first non-empty line
|
||||
if (title === 'Updated todo list' && line.trim()) {
|
||||
const trimmed = line.trim();
|
||||
// Check if it's not a list item
|
||||
if (!trimmed.match(/^[-*+]\s+\[.\]/) && !trimmed.match(/^\d+[.)]\s+\[.\]/)) {
|
||||
// Strip leading # for headings
|
||||
title = trimmed.replace(/^#+\s*/, '');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse checklist items (unordered and ordered lists)
|
||||
const unorderedMatch = line.match(/^\s*[-*+]\s+\[(.?)\]\s*(.*)$/);
|
||||
const orderedMatch = line.match(/^\s*\d+[.)]\s+\[(.?)\]\s*(.*)$/);
|
||||
const match = unorderedMatch || orderedMatch;
|
||||
|
||||
if (match) {
|
||||
// Save previous item if exists
|
||||
if (currentItem && currentItem.title.trim()) {
|
||||
todoList.push({
|
||||
id: String(todoList.length + 1),
|
||||
title: currentItem.title.trim(),
|
||||
status: currentItem.status
|
||||
});
|
||||
}
|
||||
|
||||
const checkboxChar = match[1];
|
||||
const itemTitle = match[2];
|
||||
|
||||
// Map checkbox character to status
|
||||
let status: ChatTodoStatus;
|
||||
if (checkboxChar === 'x' || checkboxChar === 'X') {
|
||||
status = 3; // ChatTodoStatus.Completed
|
||||
} else if (checkboxChar === '>' || checkboxChar === '~') {
|
||||
status = 2; // ChatTodoStatus.InProgress
|
||||
} else {
|
||||
status = 1; // ChatTodoStatus.NotStarted
|
||||
}
|
||||
|
||||
currentItem = { title: itemTitle, status };
|
||||
} else if (currentItem && line.trim() && (line.startsWith(' ') || line.startsWith('\t'))) {
|
||||
// Continuation line - append to current item
|
||||
currentItem.title += ' ' + line.trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last item
|
||||
if (currentItem && currentItem.title.trim()) {
|
||||
todoList.push({
|
||||
id: String(todoList.length + 1),
|
||||
title: currentItem.title.trim(),
|
||||
status: currentItem.status
|
||||
});
|
||||
}
|
||||
|
||||
return { title, todoList };
|
||||
}
|
||||
|
||||
function formatUpdateTodoInvocation(invocation: ChatToolInvocationPart, toolCall: UpdateTodoTool): void {
|
||||
const args = toolCall.arguments;
|
||||
const parsed = args.todos ? parseTodoMarkdown(args.todos) : { title: '', todoList: [] };
|
||||
if (!args.todos || !parsed) {
|
||||
invocation.invocationMessage = 'Updated todo list';
|
||||
return;
|
||||
}
|
||||
|
||||
invocation.invocationMessage = parsed.title;
|
||||
invocation.toolSpecificData = {
|
||||
todoList: parsed.todoList
|
||||
} as ChatTodoToolInvocationData;
|
||||
}
|
||||
|
||||
function formatUpdateTodoInvocationCompleted(invocation: ChatToolInvocationPart, toolCall: UpdateTodoTool, result: ToolCallResult): void {
|
||||
const parsed = toolCall.arguments.todos ? parseTodoMarkdown(toolCall.arguments.todos) : { title: '', todoList: [] };
|
||||
// Re-parse todo markdown on completion to ensure UI has final state
|
||||
if (parsed.todoList.length > 0) {
|
||||
invocation.invocationMessage = parsed.title;
|
||||
invocation.toolSpecificData = {
|
||||
todoList: parsed.todoList
|
||||
} as ChatTodoToolInvocationData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* No-op formatter for tool invocations that do not require custom formatting.
|
||||
* The `toolCall` parameter is unused and present for interface consistency.
|
||||
*/
|
||||
function emptyInvocation(_invocation: ChatToolInvocationPart, _toolCall: UnknownToolCall): void {
|
||||
//
|
||||
// No custom formatting needed
|
||||
}
|
||||
|
||||
function genericToolInvocationCompleted(_invocation: ChatToolInvocationPart, toolCall: UnknownToolCall, result: ToolCallResult): void {
|
||||
if (result.success && result.result?.content && typeof result.result.content === 'string') {
|
||||
_invocation.toolSpecificData = {
|
||||
output: new MarkdownString(result.result.content),
|
||||
input: toolCall.arguments ? `\`\`\`json\n${JSON.stringify(toolCall.arguments, null, 2)}\n\`\`\`` : ''
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ export class CopilotCLISession extends DisposableStore implements ICopilotCLISes
|
||||
return;
|
||||
}
|
||||
|
||||
const [responsePart,] = processToolExecutionComplete(event, pendingToolInvocations, this.logService) ?? [];
|
||||
const [responsePart,] = processToolExecutionComplete(event, pendingToolInvocations, this.logService, this.options.workingDirectory) ?? [];
|
||||
if (responsePart && !(responsePart instanceof ChatResponseThinkingProgressPart)) {
|
||||
this._stream?.push(responsePart);
|
||||
}
|
||||
@@ -400,7 +400,7 @@ export class CopilotCLISession extends DisposableStore implements ICopilotCLISes
|
||||
const getVSCodeRequestId = (sdkRequestId: string) => {
|
||||
return this.copilotCLISDK.getRequestId(sdkRequestId);
|
||||
};
|
||||
return buildChatHistoryFromEvents(this.sessionId, events, getVSCodeRequestId, this._delegationSummaryService, this.logService);
|
||||
return buildChatHistoryFromEvents(this.sessionId, events, getVSCodeRequestId, this._delegationSummaryService, this.logService, this.options.workingDirectory);
|
||||
}
|
||||
|
||||
private async requestPermission(
|
||||
|
||||
+37
-1
@@ -266,6 +266,42 @@ declare module 'vscode' {
|
||||
output: McpToolInvocationContentData[];
|
||||
}
|
||||
|
||||
export enum ChatTodoStatus {
|
||||
NotStarted = 1,
|
||||
InProgress = 2,
|
||||
Completed = 3
|
||||
}
|
||||
|
||||
export interface ChatTodoToolInvocationData {
|
||||
todoList: Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
status: ChatTodoStatus;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic tool result data that displays input and output in collapsible sections.
|
||||
* Use plain strings for unformatted text or MarkdownString for formatted markdown.
|
||||
*/
|
||||
export interface ChatGenericToolResultData {
|
||||
/**
|
||||
* The input to display. Can be a plain string (renders as text) or MarkdownString (renders with markdown formatting).
|
||||
*/
|
||||
input: string | MarkdownString;
|
||||
/**
|
||||
* The output to display. Can be a plain string (renders as text) or MarkdownString (renders with markdown formatting).
|
||||
*/
|
||||
output: string | MarkdownString;
|
||||
}
|
||||
|
||||
export interface ChatToolResourcesInvocationData {
|
||||
/**
|
||||
* Array of file URIs or locations to display as a collapsible list
|
||||
*/
|
||||
values: Array<Uri | Location>;
|
||||
}
|
||||
|
||||
export class ChatToolInvocationPart {
|
||||
toolName: string;
|
||||
toolCallId: string;
|
||||
@@ -275,7 +311,7 @@ declare module 'vscode' {
|
||||
pastTenseMessage?: string | MarkdownString;
|
||||
isConfirmed?: boolean;
|
||||
isComplete?: boolean;
|
||||
toolSpecificData?: ChatTerminalToolInvocationData | ChatMcpToolInvocationData;
|
||||
toolSpecificData?: ChatTerminalToolInvocationData | ChatMcpToolInvocationData | ChatTodoToolInvocationData | ChatGenericToolResultData | ChatToolResourcesInvocationData;
|
||||
subAgentInvocationId?: string;
|
||||
presentation?: 'hidden' | 'hiddenAfterComplete' | undefined;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user