Skip to content
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased]

### Fixes

- Refactor timeline event polling to use timeout-based approach for Copilot sessions. Prevents indefinite waiting by enforcing appropriate timeouts (1 minute for timeline events, 1 hour for coding sessions) to improve user experience.

## 0.114.2

### Fixes
Expand Down
61 changes: 60 additions & 1 deletion src/@types/vscode.proposed.chatParticipantAdditions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ declare module 'vscode' {
* Optional URI to navigate to when clicking on the file.
*/
goToFileUri?: Uri;

/**
* Added data (e.g. line numbers) to show in the UI
*/
added?: number;

/**
* Removed data (e.g. line numbers) to show in the UI
*/
removed?: number;
}

/**
Expand All @@ -149,7 +159,7 @@ declare module 'vscode' {
constructor(value: ChatResponseDiffEntry[], title: string);
}

export type ExtendedChatResponsePart = ChatResponsePart | ChatResponseTextEditPart | ChatResponseNotebookEditPart | ChatResponseConfirmationPart | ChatResponseCodeCitationPart | ChatResponseReferencePart2 | ChatResponseMovePart | ChatResponseExtensionsPart | ChatResponsePullRequestPart | ChatPrepareToolInvocationPart | ChatToolInvocationPart | ChatResponseMultiDiffPart;
export type ExtendedChatResponsePart = ChatResponsePart | ChatResponseTextEditPart | ChatResponseNotebookEditPart | ChatResponseConfirmationPart | ChatResponseCodeCitationPart | ChatResponseReferencePart2 | ChatResponseMovePart | ChatResponseExtensionsPart | ChatResponsePullRequestPart | ChatPrepareToolInvocationPart | ChatToolInvocationPart | ChatResponseMultiDiffPart | ChatResponseThinkingProgressPart;
export class ChatResponseWarningPart {
value: MarkdownString;
constructor(value: string | MarkdownString);
Expand All @@ -161,6 +171,23 @@ declare module 'vscode' {
constructor(value: string, task?: (progress: Progress<ChatResponseWarningPart | ChatResponseReferencePart>) => Thenable<string | void>);
}

/**
* A specialized progress part for displaying thinking/reasoning steps.
*/
export class ChatResponseThinkingProgressPart {
value: string | string[];
id?: string;
metadata?: { readonly [key: string]: any };
task?: (progress: Progress<LanguageModelThinkingPart>) => Thenable<string | void>;

/**
* Creates a new thinking progress part.
* @param value An initial progress message
* @param task A task that will emit thinking parts during its execution
*/
constructor(value: string | string[], id?: string, metadata?: { readonly [key: string]: any }, task?: (progress: Progress<LanguageModelThinkingPart>) => Thenable<string | void>);
}

export class ChatResponseReferencePart2 {
/**
* The reference target.
Expand Down Expand Up @@ -256,6 +283,8 @@ declare module 'vscode' {
*/
progress(value: string, task?: (progress: Progress<ChatResponseWarningPart | ChatResponseReferencePart>) => Thenable<string | void>): void;

thinkingProgress(thinkingDelta: ThinkingDelta): void;

textEdit(target: Uri, edits: TextEdit | TextEdit[]): void;

textEdit(target: Uri, isDone: true): void;
Expand Down Expand Up @@ -298,6 +327,8 @@ declare module 'vscode' {
prepareToolInvocation(toolName: string): void;

push(part: ExtendedChatResponsePart): void;

clearToPreviousToolInvocation(reason: ChatResponseClearToPreviousToolInvocationReason): void;
}

export enum ChatResponseReferencePartStatusKind {
Expand All @@ -306,6 +337,26 @@ declare module 'vscode' {
Omitted = 3
}

export type ThinkingDelta = {
text?: string | string[];
id: string;
metadata?: { readonly [key: string]: any };
} | {
text?: string | string[];
id?: string;
metadata: { readonly [key: string]: any };
} |
{
text: string | string[];
id?: string;
metadata?: { readonly [key: string]: any };
};

export enum ChatResponseClearToPreviousToolInvocationReason {
NoReason = 0,
FilteredContentRetry = 1,
CopyrightContentRetry = 2,
}

/**
* Does this piggy-back on the existing ChatRequest, or is it a different type of request entirely?
Expand Down Expand Up @@ -527,6 +578,8 @@ declare module 'vscode' {
kind: 'chatEditingHunkAction';
uri: Uri;
lineCount: number;
linesAdded: number;
linesRemoved: number;
outcome: ChatEditingSessionActionOutcome;
hasRemainingEdits: boolean;
}
Expand All @@ -547,6 +600,11 @@ declare module 'vscode' {
* TODO Needed for now to drive the variableName-type reference, but probably both of these should go away in the future.
*/
readonly name: string;

/**
* The list of tools were referenced in the value of the reference
*/
readonly toolReferences?: readonly ChatLanguageModelToolReference[];
}

export interface ChatResultFeedback {
Expand Down Expand Up @@ -589,5 +647,6 @@ declare module 'vscode' {

export interface ChatRequest {
modeInstructions?: string;
modeInstructionsToolReferences?: readonly ChatLanguageModelToolReference[];
}
}
4 changes: 3 additions & 1 deletion src/@types/vscode.proposed.chatParticipantPrivate.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// version: 9
// version: 10

declare module 'vscode' {

Expand Down Expand Up @@ -183,6 +183,8 @@ declare module 'vscode' {
isQuotaExceeded?: boolean;

level?: ChatErrorLevel;

code?: string;
}

export namespace chat {
Expand Down
113 changes: 101 additions & 12 deletions src/@types/vscode.proposed.chatSessionsProvider.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {
/**
* Represents the status of a chat session.
*/
export enum ChatSessionStatus {
/**
* The chat session failed to complete.
*/
Failed = 0,

/**
* The chat session completed successfully.
*/
Completed = 1,

/**
* The chat session is currently in progress.
*/
InProgress = 2
}

/**
* Provides a list of information about chat sessions.
*/
Expand All @@ -13,16 +33,34 @@ declare module 'vscode' {
*/
readonly onDidChangeChatSessionItems: Event<void>;

// /**
// * Create a new chat session item
// */
// provideNewChatSessionItem(context: {
// // This interface should be extracted
// readonly triggerChat?: {
// readonly prompt: string;
// readonly history: ReadonlyArray<ChatRequestTurn | ChatResponseTurn>;
// };
// }, token: CancellationToken): Thenable<ChatSessionItem> | ChatSessionItem;
/**
* Creates a new chat session.
*
* @param options Options for the new session including an optional initial prompt and history
* @param token A cancellation token
* @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
*/
readonly prompt?: string;

/**
* History to initialize the session with
*/
readonly history?: ReadonlyArray<ChatRequestTurn | ChatResponseTurn>;

/**
* Additional metadata to use for session creation
*/
metadata?: any;
}, token: CancellationToken): ProviderResult<ChatSessionItem>;

/**
* Provides a list of chat sessions.
Expand All @@ -46,10 +84,53 @@ declare module 'vscode' {
* An icon for the participant shown in UI.
*/
iconPath?: IconPath;

/**
* An optional description that provides additional context about the chat session.
*/
description?: string | MarkdownString;

/**
* An optional status indicating the current state of the session.
*/
status?: ChatSessionStatus;

/**
* The tooltip text when you hover over this item.
*/
tooltip?: string | MarkdownString;

/**
* The times at which session started and ended
*/
timing?: {
/**
* Session start timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
*/
startTime: number;
/**
* Session end timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
*/
endTime?: number;
};

/**
* Statistics about the chat session.
*/
statistics?: {
/**
* Number of insertions made during the session.
*/
insertions: number;

/**
* Number of deletions made during the session.
*/
deletions: number;
};
}

export interface ChatSession {

/**
* The full history of the session
*
Expand All @@ -74,6 +155,7 @@ declare module 'vscode' {
* If not set, then the session will be considered read-only and no requests can be made.
*/
// TODO: Should we introduce our own type for `ChatRequestHandler` since not all field apply to chat sessions?
// TODO: Revisit this to align with code.
readonly requestHandler: ChatRequestHandler | undefined;
}

Expand Down Expand Up @@ -108,7 +190,14 @@ declare module 'vscode' {
*
* @returns A disposable that unregisters the provider when disposed.
*/
export function registerChatSessionContentProvider(chatSessionType: string, provider: ChatSessionContentProvider): Disposable;
export function registerChatSessionContentProvider(chatSessionType: string, provider: ChatSessionContentProvider, capabilities?: ChatSessionCapabilities): Disposable;
}

export interface ChatSessionCapabilities {
/**
* Whether sessions can be interrupted and resumed without side-effects.
*/
supportsInterruptions?: boolean;
}

export interface ChatSessionShowOptions {
Expand Down
4 changes: 2 additions & 2 deletions src/@types/vscode.proposed.languageModelDataPart.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ declare module 'vscode' {
* A string or heterogeneous array of things that a message can contain as content. Some parts may be message-type
* specific for some models.
*/
content: Array<LanguageModelTextPart | LanguageModelToolResultPart2 | LanguageModelToolCallPart | LanguageModelDataPart>;
content: Array<LanguageModelTextPart | LanguageModelToolResultPart2 | LanguageModelToolCallPart | LanguageModelDataPart | LanguageModelThinkingPart>;

/**
* The optional name of a user for this message.
Expand All @@ -56,7 +56,7 @@ declare module 'vscode' {
* @param content The content of the message.
* @param name The optional name of a user for the message.
*/
constructor(role: LanguageModelChatMessageRole, content: string | Array<LanguageModelTextPart | LanguageModelToolResultPart2 | LanguageModelToolCallPart | LanguageModelDataPart>, name?: string);
constructor(role: LanguageModelChatMessageRole, content: string | Array<LanguageModelTextPart | LanguageModelToolResultPart2 | LanguageModelToolCallPart | LanguageModelDataPart | LanguageModelThinkingPart>, name?: string);
}

/**
Expand Down
21 changes: 16 additions & 5 deletions src/@types/vscode.proposed.languageModelToolResultAudience.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,32 @@

declare module 'vscode' {

export enum ToolResultAudience {
export enum LanguageModelPartAudience {
/**
* The part should be shown to the language model.
*/
Assistant = 0,
/**
* The part should be shown to the user.
*/
User = 1,
/**
* The part should should be retained for internal bookkeeping within
* extensions.
*/
Extension = 2,
}

/**
* A language model response part containing a piece of text, returned from a {@link LanguageModelChatResponse}.
*/
export class LanguageModelTextPart2 extends LanguageModelTextPart {
audience: ToolResultAudience[] | undefined;
constructor(value: string, audience?: ToolResultAudience[]);
audience: LanguageModelPartAudience[] | undefined;
constructor(value: string, audience?: LanguageModelPartAudience[]);
}

export class LanguageModelDataPart2 extends LanguageModelDataPart {
audience: ToolResultAudience[] | undefined;
constructor(data: Uint8Array, mimeType: string, audience?: ToolResultAudience[]);
audience: LanguageModelPartAudience[] | undefined;
constructor(data: Uint8Array, mimeType: string, audience?: LanguageModelPartAudience[]);
}
}
12 changes: 11 additions & 1 deletion src/github/copilotRemoteAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,8 @@ export class CopilotRemoteAgentManager extends Disposable {
let lastProcessedLength = 0;
let hasActiveProgress = false;
const pollingInterval = 3000; // 3 seconds
const maxWaitTime = 60 * 60 * 1000; // 1 hour timeout for long-running sessions
const startTime = Date.now();

return new Promise<void>((resolve, reject) => {
let cancellationListener: vscode.Disposable | undefined;
Expand Down Expand Up @@ -1229,6 +1231,14 @@ export class CopilotRemoteAgentManager extends Disposable {
return;
}

// Check for timeout
if (Date.now() - startTime > maxWaitTime) {
Logger.appendLine(`Session polling timed out after ${maxWaitTime / 1000} seconds`, CopilotRemoteAgentManager.ID);
stream.markdown(vscode.l10n.t('Session polling timed out. The session may still be running.'));
complete();
return;
}

// Get the specific session info
const sessionInfo = await capi.getSessionInfo(sessionId);
if (!sessionInfo || token.isCancellationRequested) {
Expand Down Expand Up @@ -1286,7 +1296,7 @@ export class CopilotRemoteAgentManager extends Disposable {
}
} catch (error) {
Logger.error(`Error polling for session updates: ${error}`, CopilotRemoteAgentManager.ID);
if (!token.isCancellationRequested) {
if (!token.isCancellationRequested && Date.now() - startTime <= maxWaitTime) {
setTimeout(pollForUpdates, pollingInterval);
} else {
reject(error);
Expand Down
Loading