Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
45 changes: 39 additions & 6 deletions src/github/copilotRemoteAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -751,12 +751,42 @@ export class CopilotRemoteAgentManager extends Disposable {
return fullText;
}

public async provideNewChatSessionItem(options: { prompt?: string; history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>; metadata?: any; }, token: vscode.CancellationToken): Promise<ChatSessionWithPR | ChatSessionFromSummarizedChat> {
const { prompt, history } = options;
if (!prompt) {
extractFileReferences(references: readonly ChatPromptReference[] | undefined): string | undefined {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be private

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}`);
}
Comment on lines +762 to +766
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be relative to the workspace folder, not the git repo. Instead, you should use getRepositoryForFile:

export function getRepositoryForFile(gitAPI: GitApiImpl, file: vscode.Uri): Repository | undefined {
const foundRepos: Repository[] = [];

}
}

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();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to keep the file name (or relative file path) in the prompt, for example, user might write add tests to #file:x.ts, if we replace it completely and include multiple files as relevant files, the prompt itself might be ambiguous as it reads as add tests to.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

public async provideNewChatSessionItem(options: { request: vscode.ChatRequest; prompt?: string; history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>; metadata?: any; }, token: vscode.CancellationToken): Promise<ChatSessionWithPR | ChatSessionFromSummarizedChat> {
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
Expand All @@ -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') {
Expand Down
5 changes: 5 additions & 0 deletions src/github/copilotRemoteAgent/chatSessionContentBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down