From 409d34d44cdd196535dc9701369cd3bbd74d1102 Mon Sep 17 00:00:00 2001 From: Josh Spicer <23246594+joshspicer@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:14:11 -0700 Subject: [PATCH 1/2] initial approach to attaching file context --- package.json | 5 ++- .../vscode.proposed.chatSessionsProvider.d.ts | 7 +++- src/extension.ts | 2 +- src/github/copilotRemoteAgent.ts | 37 +++++++++++++++++-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 760503a6f3..4de61cb46a 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,10 @@ "name": "copilot", "displayName": "GitHub Copilot coding agent", "description": "Delegate tasks to the GitHub Copilot coding agent. The agent works asynchronously to implement changes, iterates via chat, and can create or update pull requests as needed.", - "when": "config.chat.agentSessionsViewLocation && config.chat.agentSessionsViewLocation != 'disabled'" + "when": "config.chat.agentSessionsViewLocation && config.chat.agentSessionsViewLocation != 'disabled'", + "capabilities": { + "supportsFileAttachments": true + } } ], "remoteCodingAgents": [ diff --git a/src/@types/vscode.proposed.chatSessionsProvider.d.ts b/src/@types/vscode.proposed.chatSessionsProvider.d.ts index c758688404..d178031d75 100644 --- a/src/@types/vscode.proposed.chatSessionsProvider.d.ts +++ b/src/@types/vscode.proposed.chatSessionsProvider.d.ts @@ -41,6 +41,11 @@ declare module 'vscode' { * @returns Metadata for the chat session */ provideNewChatSessionItem?(options: { + /** + * The chat request that initiated the session creation + */ + readonly request: ChatRequest; + /** * Initial prompt to initiate the session */ @@ -210,4 +215,4 @@ declare module 'vscode' { */ export function showChatSession(chatSessionType: string, sessionId: string, options: ChatSessionShowOptions): Thenable; } -} \ No newline at end of file +} diff --git a/src/extension.ts b/src/extension.ts index 7a49fa5cad..c1e8a6a4c6 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -433,7 +433,7 @@ async function deferredActivate(context: vscode.ExtensionContext, showPRControll return await copilotRemoteAgentManager.provideChatSessionContent(id, token); }; onDidChangeChatSessionItems = copilotRemoteAgentManager.onDidChangeChatSessions; - provideNewChatSessionItem = async (options: { prompt?: string; history: ReadonlyArray; metadata?: any; }, token: vscode.CancellationToken): Promise => { + provideNewChatSessionItem = async (options: { request: vscode.ChatRequest; prompt?: string; history: ReadonlyArray; metadata?: any; }, token: vscode.CancellationToken): Promise => { return await copilotRemoteAgentManager.provideNewChatSessionItem(options, token); }; }(); diff --git a/src/github/copilotRemoteAgent.ts b/src/github/copilotRemoteAgent.ts index 7a5647f27d..d84372ecea 100644 --- a/src/github/copilotRemoteAgent.ts +++ b/src/github/copilotRemoteAgent.ts @@ -5,7 +5,7 @@ import * as pathLib from 'path'; import * as marked from 'marked'; -import vscode from 'vscode'; +import vscode, { ChatPromptReference } from 'vscode'; import { parseSessionLogs, parseToolCallDetails, StrReplaceEditorToolData } from '../../common/sessionParsing'; import { COPILOT_ACCOUNTS } from '../common/comment'; import { CopilotRemoteAgentConfig } from '../common/config'; @@ -746,12 +746,38 @@ export class CopilotRemoteAgentManager extends Disposable { return fullText; } - public async provideNewChatSessionItem(options: { prompt?: string; history: ReadonlyArray; metadata?: any; }, token: vscode.CancellationToken): Promise { - const { prompt, history } = options; + extractFileReferences(references: readonly ChatPromptReference[] | undefined): string | undefined { + if (!references || references.length === 0) { + return; + } + // 'file:///Users/jospicer/dev/joshbot/.github/workflows/build-vsix.yml' -> '.github/workflows/build-vsix.yml' + const parts: string[] = []; + for (const ref of references) { + if (ref.value instanceof vscode.Uri && ref.value.scheme === 'file') { // TODO: Add support for more kinds of references + const workspaceFolder = vscode.workspace.getWorkspaceFolder(ref.value); + if (workspaceFolder) { + const relativePath = pathLib.relative(workspaceFolder.uri.fsPath, ref.value.fsPath); + parts.push(` - ${relativePath}`); + } + } + } + + if (!parts.length) { + return; + } + + parts.unshift('The user has attached the following files as relevant context:'); + return parts.join('\n'); + } + + public async provideNewChatSessionItem(options: { request: vscode.ChatRequest; prompt?: string; history: ReadonlyArray; metadata?: any; }, token: vscode.CancellationToken): Promise { + const { request, prompt, history } = options; if (!prompt) { throw new Error(`Prompt is expected to provide a new chat session item`); } + + const { source, summary } = options.metadata || {}; // Ephemeral session for new session creation flow @@ -770,7 +796,10 @@ export class CopilotRemoteAgentManager extends Disposable { const result = await this.invokeRemoteAgent( prompt, - (await this.extractHistory(history)), + [ + this.extractFileReferences(request.references), + await this.extractHistory(history) + ].join('\n\n').trim(), false, ); if (result.state !== 'success') { From 3e92f89c2b02afbcfe737f5f3225330df4728147 Mon Sep 17 00:00:00 2001 From: Josh Spicer <23246594+joshspicer@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:37:31 -0700 Subject: [PATCH 2/2] make prompt rendering prettier --- src/github/copilotRemoteAgent.ts | 14 +++++++++----- .../chatSessionContentBuilder.ts | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/github/copilotRemoteAgent.ts b/src/github/copilotRemoteAgent.ts index d84372ecea..10daa06649 100644 --- a/src/github/copilotRemoteAgent.ts +++ b/src/github/copilotRemoteAgent.ts @@ -568,7 +568,7 @@ export class CopilotRemoteAgentManager extends Disposable { return `${header}\n\n${collapsedContext}`; }; - const problemStatement: string = `${prompt} ${problemContext ? `: ${problemContext}` : ''}`; + const problemStatement: string = `${prompt}\n${problemContext ?? ''}`; const payload: RemoteAgentJobPayload = { problem_statement: problemStatement, event_type: 'visual_studio_code_remote_agent_tool_invoked', @@ -770,14 +770,18 @@ export class CopilotRemoteAgentManager extends Disposable { return parts.join('\n'); } + cleanPrompt(prompt: string): string { + // Remove #file:xxxx from the prompt + return prompt.replace(/#file:\S+/g, '').trim(); + } + public async provideNewChatSessionItem(options: { request: vscode.ChatRequest; prompt?: string; history: ReadonlyArray; metadata?: any; }, token: vscode.CancellationToken): Promise { - const { request, prompt, history } = options; - if (!prompt) { + const { request, history } = options; + if (!options.prompt) { throw new Error(`Prompt is expected to provide a new chat session item`); } - - + const prompt = this.cleanPrompt(options.prompt); const { source, summary } = options.metadata || {}; // Ephemeral session for new session creation flow diff --git a/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts b/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts index f77006f8d9..f29cbc6691 100644 --- a/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts +++ b/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts @@ -230,6 +230,11 @@ export class ChatSessionContentBuilder { const titleMatch = jobInfo.problem_statement.match(/TITLE: \s*(.*)/i); if (titleMatch && titleMatch[1]) { prompt = titleMatch[1].trim(); + } else { + const split = jobInfo.problem_statement.split('\n'); + if (split.length > 0) { + prompt = split[0].trim(); + } } Logger.appendLine(`Session 0: Found problem_statement from Jobs API: ${prompt}`, this.loggerId); return prompt;