Skip to content

Commit 4543d29

Browse files
authored
supportFileAttachment in new coding agent editor (#7744)
* initial approach to attaching file context * make prompt rendering prettier
1 parent 5a8a050 commit 4543d29

3 files changed

Lines changed: 48 additions & 7 deletions

File tree

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@
7777
"name": "copilot",
7878
"displayName": "GitHub Copilot coding agent",
7979
"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.",
80-
"when": "config.chat.agentSessionsViewLocation && config.chat.agentSessionsViewLocation != 'disabled'"
80+
"when": "config.chat.agentSessionsViewLocation && config.chat.agentSessionsViewLocation != 'disabled'",
81+
"capabilities": {
82+
"supportsFileAttachments": true
83+
}
8184
}
8285
],
8386
"remoteCodingAgents": [

src/github/copilotRemoteAgent.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as pathLib from 'path';
77
import * as marked from 'marked';
8-
import vscode from 'vscode';
8+
import vscode, { ChatPromptReference } from 'vscode';
99
import { parseSessionLogs, parseToolCallDetails, StrReplaceEditorToolData } from '../../common/sessionParsing';
1010
import { COPILOT_ACCOUNTS } from '../common/comment';
1111
import { CopilotRemoteAgentConfig } from '../common/config';
@@ -573,7 +573,7 @@ export class CopilotRemoteAgentManager extends Disposable {
573573
return `${header}\n\n${collapsedContext}`;
574574
};
575575

576-
const problemStatement: string = `${prompt} ${problemContext ? `: ${problemContext}` : ''}`;
576+
const problemStatement: string = `${prompt}\n${problemContext ?? ''}`;
577577
const payload: RemoteAgentJobPayload = {
578578
problem_statement: problemStatement,
579579
event_type: 'visual_studio_code_remote_agent_tool_invoked',
@@ -751,12 +751,42 @@ export class CopilotRemoteAgentManager extends Disposable {
751751
return fullText;
752752
}
753753

754-
public async provideNewChatSessionItem(options: { prompt?: string; history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>; metadata?: any; }, token: vscode.CancellationToken): Promise<ChatSessionWithPR | ChatSessionFromSummarizedChat> {
755-
const { prompt, history } = options;
756-
if (!prompt) {
754+
extractFileReferences(references: readonly ChatPromptReference[] | undefined): string | undefined {
755+
if (!references || references.length === 0) {
756+
return;
757+
}
758+
// 'file:///Users/jospicer/dev/joshbot/.github/workflows/build-vsix.yml' -> '.github/workflows/build-vsix.yml'
759+
const parts: string[] = [];
760+
for (const ref of references) {
761+
if (ref.value instanceof vscode.Uri && ref.value.scheme === 'file') { // TODO: Add support for more kinds of references
762+
const workspaceFolder = vscode.workspace.getWorkspaceFolder(ref.value);
763+
if (workspaceFolder) {
764+
const relativePath = pathLib.relative(workspaceFolder.uri.fsPath, ref.value.fsPath);
765+
parts.push(` - ${relativePath}`);
766+
}
767+
}
768+
}
769+
770+
if (!parts.length) {
771+
return;
772+
}
773+
774+
parts.unshift('The user has attached the following files as relevant context:');
775+
return parts.join('\n');
776+
}
777+
778+
cleanPrompt(prompt: string): string {
779+
// Remove #file:xxxx from the prompt
780+
return prompt.replace(/#file:\S+/g, '').trim();
781+
}
782+
783+
public async provideNewChatSessionItem(options: { request: vscode.ChatRequest; prompt?: string; history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>; metadata?: any; }, token: vscode.CancellationToken): Promise<ChatSessionWithPR | ChatSessionFromSummarizedChat> {
784+
const { request, history } = options;
785+
if (!options.prompt) {
757786
throw new Error(`Prompt is expected to provide a new chat session item`);
758787
}
759788

789+
const prompt = this.cleanPrompt(options.prompt);
760790
const { source, summary } = options.metadata || {};
761791

762792
// Ephemeral session for new session creation flow
@@ -775,7 +805,10 @@ export class CopilotRemoteAgentManager extends Disposable {
775805

776806
const result = await this.invokeRemoteAgent(
777807
prompt,
778-
(await this.extractHistory(history)),
808+
[
809+
this.extractFileReferences(request.references),
810+
await this.extractHistory(history)
811+
].join('\n\n').trim(),
779812
false,
780813
);
781814
if (result.state !== 'success') {

src/github/copilotRemoteAgent/chatSessionContentBuilder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@ export class ChatSessionContentBuilder {
248248
const titleMatch = jobInfo.problem_statement.match(/TITLE: \s*(.*)/i);
249249
if (titleMatch && titleMatch[1]) {
250250
prompt = titleMatch[1].trim();
251+
} else {
252+
const split = jobInfo.problem_statement.split('\n');
253+
if (split.length > 0) {
254+
prompt = split[0].trim();
255+
}
251256
}
252257
Logger.appendLine(`Session 0: Found problem_statement from Jobs API: ${prompt}`, this.loggerId);
253258
return prompt;

0 commit comments

Comments
 (0)