Skip to content

Implement follow-up detection for active coding agent PRs #7180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
140 changes: 135 additions & 5 deletions src/@types/vscode.proposed.chatParticipantAdditions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ declare module 'vscode' {

export class ChatResponseConfirmationPart {
title: string;
message: string;
message: string | MarkdownString;
data: any;
buttons?: string[];
constructor(title: string, message: string, data: any, buttons?: string[]);
constructor(title: string, message: string | MarkdownString, data: any, buttons?: string[]);
}

export class ChatResponseCodeCitationPart {
Expand All @@ -84,8 +84,72 @@ declare module 'vscode' {
constructor(toolName: string);
}

export type ExtendedChatResponsePart = ChatResponsePart | ChatResponseTextEditPart | ChatResponseNotebookEditPart | ChatResponseConfirmationPart | ChatResponseCodeCitationPart | ChatResponseReferencePart2 | ChatResponseMovePart | ChatResponseExtensionsPart | ChatPrepareToolInvocationPart;
export interface ChatTerminalToolInvocationData {
commandLine: {
original: string;
userEdited?: string;
toolEdited?: string;
};
language: string;
}

export class ChatToolInvocationPart {
toolName: string;
toolCallId: string;
isError?: boolean;
invocationMessage?: string | MarkdownString;
originMessage?: string | MarkdownString;
pastTenseMessage?: string | MarkdownString;
isConfirmed?: boolean;
isComplete?: boolean;
toolSpecificData?: ChatTerminalToolInvocationData;

constructor(toolName: string, toolCallId: string, isError?: boolean);
}

/**
* Represents a single file diff entry in a multi diff view.
*/
export interface ChatResponseDiffEntry {
/**
* The original file URI (undefined for new files).
*/
originalUri?: Uri;

/**
* The modified file URI (undefined for deleted files).
*/
modifiedUri?: Uri;

/**
* Optional URI to navigate to when clicking on the file.
*/
goToFileUri?: Uri;
}

/**
* Represents a part of a chat response that shows multiple file diffs.
*/
export class ChatResponseMultiDiffPart {
/**
* Array of file diff entries to display.
*/
value: ChatResponseDiffEntry[];

/**
* The title for the multi diff editor.
*/
title: string;

/**
* Create a new ChatResponseMultiDiffPart.
* @param value Array of file diff entries.
* @param title The title for the multi diff editor.
*/
constructor(value: ChatResponseDiffEntry[], title: string);
}

export type ExtendedChatResponsePart = ChatResponsePart | ChatResponseTextEditPart | ChatResponseNotebookEditPart | ChatResponseConfirmationPart | ChatResponseCodeCitationPart | ChatResponseReferencePart2 | ChatResponseMovePart | ChatResponseExtensionsPart | ChatResponsePullRequestPart | ChatPrepareToolInvocationPart | ChatToolInvocationPart | ChatResponseMultiDiffPart;
export class ChatResponseWarningPart {
value: MarkdownString;
constructor(value: string | MarkdownString);
Expand Down Expand Up @@ -171,6 +235,15 @@ declare module 'vscode' {
constructor(extensions: string[]);
}

export class ChatResponsePullRequestPart {
readonly uri: Uri;
readonly linkTag: string;
readonly title: string;
readonly description: string;
readonly author: string;
constructor(uri: Uri, title: string, description: string, author: string, linkTag: string);
}

export interface ChatResponseStream {

/**
Expand Down Expand Up @@ -205,7 +278,7 @@ declare module 'vscode' {
* TODO@API should this be MarkdownString?
* TODO@API should actually be a more generic function that takes an array of buttons
*/
confirmation(title: string, message: string, data: any, buttons?: string[]): void;
confirmation(title: string, message: string | MarkdownString, data: any, buttons?: string[]): void;

/**
* Push a warning to this stream. Short-hand for
Expand Down Expand Up @@ -258,6 +331,50 @@ declare module 'vscode' {
readonly tools: Map<string, boolean>;
}

export namespace lm {
/**
* Fired when the set of tools on a chat request changes.
*/
export const onDidChangeChatRequestTools: Event<ChatRequest>;
}

export class LanguageModelToolExtensionSource {
/**
* ID of the extension that published the tool.
*/
readonly id: string;

/**
* Label of the extension that published the tool.
*/
readonly label: string;

private constructor(id: string, label: string);
}

export class LanguageModelToolMCPSource {
/**
* Editor-configured label of the MCP server that published the tool.
*/
readonly label: string;

/**
* Server-defined name of the MCP server.
*/
readonly name: string;

/**
* Server-defined instructions for MCP tool use.
*/
readonly instructions?: string;

private constructor(label: string, name: string, instructions?: string);
}

export interface LanguageModelToolInformation {
source: LanguageModelToolExtensionSource | LanguageModelToolMCPSource | undefined;
}

// TODO@API fit this into the stream
export interface ChatUsedContext {
documents: ChatDocumentContext[];
Expand Down Expand Up @@ -307,6 +424,10 @@ declare module 'vscode' {
participant?: string;
command?: string;
};
/**
* An optional detail string that will be rendered at the end of the response in certain UI contexts.
*/
details?: string;
}

export namespace chat {
Expand Down Expand Up @@ -401,6 +522,15 @@ declare module 'vscode' {
outcome: ChatEditingSessionActionOutcome;
}

export interface ChatEditingHunkAction {
// eslint-disable-next-line local/vscode-dts-string-type-literals
kind: 'chatEditingHunkAction';
uri: Uri;
lineCount: number;
outcome: ChatEditingSessionActionOutcome;
hasRemainingEdits: boolean;
}

export enum ChatEditingSessionActionOutcome {
Accepted = 1,
Rejected = 2,
Expand All @@ -409,7 +539,7 @@ declare module 'vscode' {

export interface ChatUserActionEvent {
readonly result: ChatResult;
readonly action: ChatCopyAction | ChatInsertAction | ChatApplyAction | ChatTerminalAction | ChatCommandAction | ChatFollowupAction | ChatBugReportAction | ChatEditorAction | ChatEditingSessionAction;
readonly action: ChatCopyAction | ChatInsertAction | ChatApplyAction | ChatTerminalAction | ChatCommandAction | ChatFollowupAction | ChatBugReportAction | ChatEditorAction | ChatEditingSessionAction | ChatEditingHunkAction;
}

export interface ChatPromptReference {
Expand Down
44 changes: 25 additions & 19 deletions src/@types/vscode.proposed.chatParticipantPrivate.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,31 @@ declare module 'vscode' {
/**
* @hidden
*/
private constructor(prompt: string, command: string | undefined, references: ChatPromptReference[], participant: string, toolReferences: ChatLanguageModelToolReference[], editedFileEvents: ChatRequestEditedFileEvent[] | undefined);
constructor(prompt: string, command: string | undefined, references: ChatPromptReference[], participant: string, toolReferences: ChatLanguageModelToolReference[], editedFileEvents: ChatRequestEditedFileEvent[] | undefined);
}

export class ChatResponseTurn2 {
/**
* The content that was received from the chat participant. Only the stream parts that represent actual content (not metadata) are represented.
*/
readonly response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart | ExtendedChatResponsePart | ChatToolInvocationPart>;

/**
* The result that was received from the chat participant.
*/
readonly result: ChatResult;

/**
* The id of the chat participant that this response came from.
*/
readonly participant: string;

/**
* The name of the command that this response came from.
*/
readonly command?: string;

constructor(response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart | ExtendedChatResponsePart>, result: ChatResult, participant: string);
}

export interface ChatParticipant {
Expand Down Expand Up @@ -205,24 +229,6 @@ declare module 'vscode' {
presentation?: 'hidden' | undefined;
}

export interface LanguageModelTool<T> {
prepareInvocation2?(options: LanguageModelToolInvocationPrepareOptions<T>, token: CancellationToken): ProviderResult<PreparedTerminalToolInvocation>;
}

export class PreparedTerminalToolInvocation {
readonly command: string;
readonly language: string;
readonly confirmationMessages?: LanguageModelToolConfirmationMessages;
readonly presentation?: 'hidden' | undefined;

constructor(
command: string,
language: string,
confirmationMessages?: LanguageModelToolConfirmationMessages,
presentation?: 'hidden'
);
}

export class ExtendedLanguageModelToolResult extends LanguageModelToolResult {
toolResultMessage?: string | MarkdownString;
toolResultDetails?: Array<Uri | Location>;
Expand Down
9 changes: 9 additions & 0 deletions src/github/copilotRemoteAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,15 @@ export class CopilotRemoteAgentManager extends Disposable {
// Group 2 is this, url-encoded:
// {"owner":"monalisa","repo":"app","pullRequestNumber":18}
let followUpPR: number | undefined = this.parseFollowup(followup, repoInfo);

// Check if the currently active PR is a coding agent PR
if (!followUpPR) {
const activePR = repoInfo.fm.activePullRequest;
if (activePR && this._stateModel.get(owner, repo, activePR.number)) {
followUpPR = activePR.number;
}
}

if (followUpPR) {
return this.addFollowUpToExistingPR(followUpPR, userPrompt, summary);
}
Expand Down
2 changes: 1 addition & 1 deletion src/github/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';

import * as OctokitTypes from '@octokit/types';
import * as crypto from 'crypto';
import * as OctokitTypes from '@octokit/types';
import * as vscode from 'vscode';
import { Repository } from '../api/api';
import { GitApiImpl } from '../api/api1';
Expand Down
Loading