diff --git a/package.json b/package.json index dfaf24d013..49f399d9f3 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/github/copilotRemoteAgent.ts b/src/github/copilotRemoteAgent.ts index 280bfcfb24..23a0691857 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'; @@ -573,7 +573,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', @@ -751,12 +751,42 @@ 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; - if (!prompt) { + 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'); + } + + 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, 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 @@ -775,7 +805,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') { diff --git a/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts b/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts index cc3ea9fc2a..11cd61bca2 100644 --- a/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts +++ b/src/github/copilotRemoteAgent/chatSessionContentBuilder.ts @@ -248,6 +248,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;