Skip to content

Commit

Permalink
It1: Start moving to async chat messages
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostwriternr committed Sep 24, 2024
1 parent 8c40196 commit bd4d93f
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';

import { getUserId } from '../../utilities/uniqueId';

export class AideAgentSessionProvider implements vscode.Disposable {
private aideAgent: vscode.AideSessionAgent;

private sessionId: string | undefined;
private stream: vscode.ChatResponseStream | undefined;
private eventQueue: vscode.ChatRequest[] = [];
private processingEvents: Map<string, boolean> = new Map();

constructor() {
this.aideAgent = vscode.aideAgent.createChatParticipant('aide', {
newSession: this.newSession.bind(this),
handleEvent: this.handleEvent.bind(this),
});
this.aideAgent.iconPath = vscode.Uri.joinPath(
vscode.extensions.getExtension('codestory-ghost.codestoryai')?.extensionUri ?? vscode.Uri.parse(''),
'assets',
'aide-agent.png'
);
this.aideAgent.requester = {
name: getUserId(),
icon: vscode.Uri.joinPath(
vscode.extensions.getExtension('codestory-ghost.codestoryai')?.extensionUri ?? vscode.Uri.parse(''),
'assets',
'aide-user.png'
)
};
this.aideAgent.supportIssueReporting = false;
this.aideAgent.welcomeMessageProvider = {
provideWelcomeMessage: async () => {
return [
'Hi, I\'m **Aide**, your personal coding assistant! I can find, understand, explain, debug or write code for you.',
];
}
};
}

private newSession(sessionId: string, stream: vscode.ChatResponseStream): void {
this.sessionId = sessionId;
this.stream = stream;
}

private async handleEvent(event: vscode.ChatRequest, token: vscode.CancellationToken): Promise<void> {
this.eventQueue.push(event);
if (this.sessionId && !this.processingEvents.has(this.sessionId)) {
this.processingEvents.set(this.sessionId, true);
this.processEvent(event);
}
}

private async processEvent(event: vscode.ChatRequest): Promise<void> {
await this.generateResponse(event);
if (this.sessionId) {
this.processingEvents.delete(this.sessionId);
}
}

private async generateResponse(event: vscode.ChatRequest) {
// Simulate processing time
await new Promise(resolve => setTimeout(resolve, 1000));
this.stream?.markdown('Hello, world! Thanks for telling me ' + event.prompt);
}

dispose() {
this.aideAgent.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ import { InLineAgentContextSelection } from '../../sidecar/types';
import { getSelectedCodeContextForExplain } from '../../utilities/getSelectionContext';
import { getUserId } from '../../utilities/uniqueId';
import { ProjectContext } from '../../utilities/workspaceContext';
import { registerOpenFiles } from './openFiles';
import { IndentStyleSpaces, IndentationHelper, provideInteractiveEditorResponse } from './editorSessionProvider';
import { AdjustedLineContent, AnswerSplitOnNewLineAccumulator, AnswerStreamContext, AnswerStreamLine, LineContent, LineIndentManager, StateEnum } from './reportEditorSessionAnswerStream';
import { registerTerminalSelection } from './terminalSelection';

class CSChatParticipant implements vscode.ChatRequesterInformation {
name: string;
Expand Down
12 changes: 9 additions & 3 deletions extensions/codestory/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import * as os from 'os';
import { commands, DiagnosticSeverity, env, ExtensionContext, languages, modelSelection, window, workspace, } from 'vscode';

import { createInlineCompletionItemProvider } from './completions/create-inline-completion-item-provider';
import { CSChatAgentProvider } from './completions/providers/chatprovider';
import { AideAgentSessionProvider } from './completions/providers/aideAgentProvider';
import { AideProbeProvider } from './completions/providers/probeProvider';
import { CSEventHandler } from './csEvents/csEventHandler';
import { getGitCurrentHash, getGitRepoName } from './git/helper';
import { aideCommands } from './inlineCompletion/commands';
import { startupStatusBar } from './inlineCompletion/statusBar';
import logger from './logger';
import postHogClient from './posthog/client';
import { AideQuickFix } from './quickActions/fix';
import { RecentEditsRetriever } from './server/editedFiles';
import { RepoRef, RepoRefBackend, SideCarClient } from './sidecar/client';
import { loadOrSaveToStorage } from './storage/types';
import { copySettings } from './utilities/copySettings';
Expand All @@ -25,8 +27,6 @@ import { readCustomSystemInstruction } from './utilities/systemInstruction';
import { CodeSymbolInformationEmbeddings } from './utilities/types';
import { getUniqueId } from './utilities/uniqueId';
import { ProjectContext } from './utilities/workspaceContext';
import { CSEventHandler } from './csEvents/csEventHandler';
import { RecentEditsRetriever } from './server/editedFiles';

export let SIDECAR_CLIENT: SideCarClient | null = null;

Expand Down Expand Up @@ -176,12 +176,18 @@ export async function activate(context: ExtensionContext) {
const aideQuickFix = new AideQuickFix();
languages.registerCodeActionsProvider('*', aideQuickFix);

/*
const chatAgentProvider = new CSChatAgentProvider(
rootPath, repoName, repoHash,
uniqueUserId,
sidecarClient, currentRepo, projectContext
);
context.subscriptions.push(chatAgentProvider);
*/

// Register the agent session provider
const agentSessionProvider = new AideAgentSessionProvider();
context.subscriptions.push(agentSessionProvider);

// add the recent edits retriver to the subscriptions
// so we can grab the recent edits very quickly
Expand Down
29 changes: 9 additions & 20 deletions src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1494,33 +1494,22 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I

// namespace: aideAgent
const aideAgent: typeof vscode.aideAgent = {
registerChatResponseProvider(id: string, provider: vscode.ChatResponseProvider, metadata: vscode.ChatResponseProviderMetadata) {
checkProposedApiEnabled(extension, 'chatProvider');
return extHostLanguageModels.registerLanguageModel(extension, id, provider, metadata);
createChatParticipant(id: string, resolver: vscode.AideSessionParticipant) {
checkProposedApiEnabled(extension, 'aideAgent');
return extHostAideAgentAgents2.createChatAgent(extension, id, resolver);
},
registerChatParticipantDetectionProvider(provider: vscode.ChatParticipantDetectionProvider) {
checkProposedApiEnabled(extension, 'aideAgent');
return extHostAideAgentAgents2.registerChatParticipantDetectionProvider(provider);
},
registerChatVariableResolver(id: string, name: string, userDescription: string, modelDescription: string | undefined, isSlow: boolean | undefined, resolver: vscode.ChatVariableResolver, fullName?: string, icon?: vscode.ThemeIcon) {
checkProposedApiEnabled(extension, 'chatVariableResolver');
checkProposedApiEnabled(extension, 'aideAgent');
return extHostAideAgentVariables.registerVariableResolver(extension, id, name, userDescription, modelDescription, isSlow, resolver, fullName, icon?.id);
},
registerMappedEditsProvider(selector: vscode.DocumentSelector, provider: vscode.MappedEditsProvider) {
checkProposedApiEnabled(extension, 'mappedEditsProvider');
return extHostLanguageFeatures.registerMappedEditsProvider(extension, selector, provider);
},
registerMappedEditsProvider2(provider: vscode.MappedEditsProvider2) {
checkProposedApiEnabled(extension, 'mappedEditsProvider');
checkProposedApiEnabled(extension, 'aideAgent');
return extHostAideAgentCodeMapper.registerMappedEditsProvider(extension, provider);
},
createChatParticipant(id: string, handler: vscode.ChatExtendedRequestHandler) {
return extHostAideAgentAgents2.createChatAgent(extension, id, handler);
},
createDynamicChatParticipant(id: string, dynamicProps: vscode.DynamicChatParticipantProps, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
checkProposedApiEnabled(extension, 'chatParticipantPrivate');
return extHostAideAgentAgents2.createDynamicChatAgent(extension, id, dynamicProps, handler);
},
registerChatParticipantDetectionProvider(provider: vscode.ChatParticipantDetectionProvider) {
checkProposedApiEnabled(extension, 'chatParticipantAdditions');
return extHostAideAgentAgents2.registerChatParticipantDetectionProvider(provider);
},
};

// namespace: lm
Expand Down
49 changes: 24 additions & 25 deletions src/vs/workbench/api/common/extHostAideAgentAgents2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import type * as vscode from 'vscode';
import { coalesce } from '../../../base/common/arrays.js';
import { raceCancellation } from '../../../base/common/async.js';
import { CancellationToken } from '../../../base/common/cancellation.js';
Expand All @@ -18,16 +19,15 @@ import { URI } from '../../../base/common/uri.js';
import { Location } from '../../../editor/common/languages.js';
import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
import { ILogService } from '../../../platform/log/common/log.js';
import { ExtHostChatAgentsShape2, IChatAgentCompletionItem, IChatAgentHistoryEntryDto, IChatProgressDto, IExtensionChatAgentMetadata, IMainContext, MainContext, MainThreadChatAgentsShape2 } from './extHost.protocol.js';
import { CommandsConverter, ExtHostCommands } from './extHostCommands.js';
import { ExtHostDocuments } from './extHostDocuments.js';
import * as typeConvert from './extHostTypeConverters.js';
import * as extHostTypes from './extHostTypes.js';
import { ChatAgentLocation, IChatAgentRequest, IChatAgentResult, IChatAgentResultTimings } from '../../contrib/aideAgent/common/aideAgentAgents.js';
import { ChatAgentVoteDirection, IChatContentReference, IChatFollowup, IChatResponseErrorDetails, IChatUserActionEvent, IChatVoteAction } from '../../contrib/aideAgent/common/aideAgentService.js';
import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
import { Dto } from '../../services/extensions/common/proxyIdentifier.js';
import type * as vscode from 'vscode';
import { ExtHostChatAgentsShape2, IChatAgentCompletionItem, IChatAgentHistoryEntryDto, IChatProgressDto, IMainContext, MainContext, MainThreadChatAgentsShape2 } from './extHost.protocol.js';
import { CommandsConverter, ExtHostCommands } from './extHostCommands.js';
import { ExtHostDocuments } from './extHostDocuments.js';
import * as typeConvert from './extHostTypeConverters.js';
import * as extHostTypes from './extHostTypes.js';

class ChatAgentResponseStream {

Expand Down Expand Up @@ -299,24 +299,15 @@ export class ExtHostAideAgentAgents2 extends Disposable implements ExtHostChatAg
this._proxy.$transferActiveChatSession(newWorkspace);
}

createChatAgent(extension: IExtensionDescription, id: string, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
createChatAgent(extension: IExtensionDescription, id: string, handler: vscode.AideSessionParticipant): vscode.AideSessionAgent {
const handle = ExtHostAideAgentAgents2._idPool++;
const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler.newSession, handler.handleEvent);
this._agents.set(handle, agent);

this._proxy.$registerAgent(handle, extension.identifier, id, {}, undefined);
return agent.apiAgent;
}

createDynamicChatAgent(extension: IExtensionDescription, id: string, dynamicProps: vscode.DynamicChatParticipantProps, handler: vscode.ChatExtendedRequestHandler): vscode.ChatParticipant {
const handle = ExtHostAideAgentAgents2._idPool++;
const agent = new ExtHostChatAgent(extension, id, this._proxy, handle, handler);
this._agents.set(handle, agent);

this._proxy.$registerAgent(handle, extension.identifier, id, { isSticky: true } satisfies IExtensionChatAgentMetadata, dynamicProps);
return agent.apiAgent;
}

registerChatParticipantDetectionProvider(provider: vscode.ChatParticipantDetectionProvider): vscode.Disposable {
const handle = ExtHostAideAgentAgents2._participantDetectionProviderIdPool++;
this._participantDetectionProviders.set(handle, provider);
Expand Down Expand Up @@ -375,24 +366,27 @@ export class ExtHostAideAgentAgents2 extends Disposable implements ExtHostChatAg
let stream: ChatAgentResponseStream | undefined;

try {
const { request, location, history } = await this._createRequest(requestDto, context);
const { request, location } = await this._createRequest(requestDto, context);
if (!isProposedApiEnabled(agent.extension, 'chatParticipantAdditions')) {
delete request.userSelectedModelId;
}

// Init session disposables
let newSession = false;
let sessionDisposables = this._sessionDisposables.get(request.sessionId);
if (!sessionDisposables) {
newSession = true;
sessionDisposables = new DisposableStore();
this._sessionDisposables.set(request.sessionId, sessionDisposables);
}

stream = new ChatAgentResponseStream(agent.extension, request, this._proxy, this._commands.converter, sessionDisposables);
if (newSession) {
agent.createSession(request.sessionId, stream.apiObject);
}

const task = agent.invoke(
typeConvert.ChatAgentRequest.to(request, location),
{ history },
stream.apiObject,
token
);

Expand Down Expand Up @@ -602,9 +596,14 @@ class ExtHostChatAgent {
public readonly id: string,
private readonly _proxy: MainThreadChatAgentsShape2,
private readonly _handle: number,
private _requestHandler: vscode.ChatExtendedRequestHandler,
private _sessionHandler: vscode.AideSessionHandler,
private _requestHandler: vscode.AideSessionEventHandler,
) { }

createSession(sessionId: string, stream: vscode.ChatResponseStream): void {
this._sessionHandler(sessionId, stream);
}

acceptFeedback(feedback: vscode.ChatResultFeedback) {
this._onDidReceiveFeedback.fire(feedback);
}
Expand Down Expand Up @@ -674,7 +673,7 @@ class ExtHostChatAgent {
return content;
}

get apiAgent(): vscode.ChatParticipant {
get apiAgent(): vscode.AideSessionAgent {
let disposed = false;
let updateScheduled = false;
const updateMetadataSoon = () => {
Expand Down Expand Up @@ -843,10 +842,10 @@ class ExtHostChatAgent {
that._onDidReceiveFeedback.dispose();
that._proxy.$unregisterAgent(that._handle);
},
} satisfies vscode.ChatParticipant;
} satisfies vscode.AideSessionAgent;
}

invoke(request: vscode.ChatRequest, context: vscode.ChatContext, response: vscode.ChatResponseStream, token: CancellationToken): vscode.ProviderResult<vscode.ChatResult | void> {
return this._requestHandler(request, context, response, token);
invoke(request: vscode.ChatRequest, token: CancellationToken): vscode.ProviderResult<vscode.ChatResult | void> {
return this._requestHandler(request, token);
}
}
33 changes: 29 additions & 4 deletions src/vscode-dts/vscode.proposed.aideAgent.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,38 @@
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {
export type AideSessionHandler = (id: string, stream: ChatResponseStream) => void;
export type AideSessionEventHandler = (event: ChatRequest, token: CancellationToken) => ProviderResult<ChatResult | void>;

export interface AideSessionParticipant {
newSession: AideSessionHandler;
handleEvent: AideSessionEventHandler;
}

interface AideSessionAgent {
readonly id: string;
followupProvider?: ChatFollowupProvider;
helpTextPostfix?: string | MarkdownString;
helpTextPrefix?: string | MarkdownString;
helpTextVariablesPrefix?: string | MarkdownString;
iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon;
isSecondary?: boolean;
onDidPerformAction: Event<ChatUserActionEvent>;
onDidReceiveFeedback: Event<ChatResultFeedback>;
participantVariableProvider?: { provider: ChatParticipantCompletionItemProvider; triggerCharacters: string[] };
requester?: ChatRequesterInformation;
requestHandler: AideSessionEventHandler;
supportIssueReporting?: boolean;
supportsSlowReferences?: boolean;
titleProvider?: ChatTitleProvider;
welcomeMessageProvider?: ChatWelcomeMessageProvider;
dispose(): void;
}

export namespace aideAgent {
export function createChatParticipant(id: string, handler: ChatExtendedRequestHandler): ChatParticipant;
export function createDynamicChatParticipant(id: string, dynamicProps: DynamicChatParticipantProps, handler: ChatExtendedRequestHandler): ChatParticipant;
export function createChatParticipant(id: string, resolver: AideSessionParticipant): AideSessionAgent;
export function registerChatParticipantDetectionProvider(participantDetectionProvider: ChatParticipantDetectionProvider): Disposable;
export function registerChatResponseProvider(id: string, provider: ChatResponseProvider, metadata: ChatResponseProviderMetadata): Disposable;
export function registerChatVariableResolver(id: string, name: string, userDescription: string, modelDescription: string | undefined, isSlow: boolean | undefined, resolver: ChatVariableResolver, fullName?: string, icon?: ThemeIcon): Disposable;
export function registerMappedEditsProvider(documentSelector: DocumentSelector, provider: MappedEditsProvider): Disposable;
export function registerMappedEditsProvider2(provider: MappedEditsProvider2): Disposable;
}
}

0 comments on commit bd4d93f

Please sign in to comment.