Skip to content
Open
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
63 changes: 63 additions & 0 deletions src/vs/workbench/contrib/agent/browser/agentService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { IAgentService, IAgent, AgentRole } from 'vs/workbench/contrib/agent/common/agentService';
import { ITaskService } from 'vs/workbench/contrib/agent/common/taskService';
import { IContextService } from 'vs/workbench/contrib/agent/common/contextService';
import { IModelService } from 'vs/workbench/contrib/agent/common/modelService';
import { ICodeIndexService } from 'vs/workbench/contrib/agent/common/codeIndexService';
import { IKnowledgeGraphService } from 'vs/workbench/contrib/agent/common/knowledgeGraphService';
import { ITask } from 'vs/workbench/contrib/agent/common/task';
import { Task } from 'vs/workbench/contrib/agent/browser/task';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';

class Agent implements IAgent {
constructor(
public readonly role: AgentRole,
private readonly taskService: ITaskService,
private readonly instantiationService: IInstantiationService
) {}

startTask(text: string, images?: string[]): Promise<ITask> {
const task = this.instantiationService.createInstance(Task, this, this.role, text, images);
// In a real implementation, we would manage the task lifecycle here.
(task as Task).run();
return Promise.resolve(task);
}
}

export class AgentService implements IAgentService {
_serviceBrand: undefined;

private readonly agents: Map<AgentRole, IAgent> = new Map();

constructor(
@ITaskService private readonly taskService: ITaskService,
@IContextService private readonly contextService: IContextService,
@IModelService private readonly modelService: IModelService,
@ICodeIndexService private readonly codeIndexService: ICodeIndexService,
@IKnowledgeGraphService private readonly knowledgeGraphService: IKnowledgeGraphService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
) {
this.agents.set('architect', new Agent('architect', this.taskService, this.instantiationService));
this.agents.set('developer', new Agent('developer', this.taskService, this.instantiationService));
this.agents.set('tester', new Agent('tester', this.taskService, this.instantiationService));
}

getAgent(role: AgentRole): IAgent | undefined {
return this.agents.get(role);
}

async startTask(role: AgentRole, text: string, images?: string[]): Promise<ITask> {
const agent = this.getAgent(role);
if (!agent) {
throw new Error(`Agent with role '${role}' not found.`);
}
return agent.startTask(text, images);
}

async cancelTask(taskId: string): Promise<void> {
await this.taskService.cancelTask();
}

getCurrentTask(): ITask | undefined {
return this.taskService.getCurrentTask();
}
}
107 changes: 107 additions & 0 deletions src/vs/workbench/contrib/agent/browser/agentView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWebviewViewService, IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { URI } from 'vs/base/common/uri';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IAgentService } from 'vs/workbench/contrib/agent/common/agentService';

export class AgentView extends ViewPane {
private webviewViewService: IWebviewViewService;
private webview?: IWebviewService;
private environmentService: IEnvironmentService;
private agentService: IAgentService;

constructor(
options: IViewPaneOptions,
@IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService,
@IConfigurationService configurationService: IConfigurationService,
@IInstantiationService instantiationService: IInstantiationService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IOpenerService openerService: IOpenerService,
@IThemeService themeService: IThemeService,
@ITelemetryService telemetryService: ITelemetryService,
@IWebviewViewService webviewViewService: IWebviewViewService,
@IContextKeyService contextKeyService: IContextKeyService,
@IStorageService storageService: IStorageService,
@IEnvironmentService environmentService: IEnvironmentService,
@IAgentService agentService: IAgentService,
) {
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, instantiationService, viewDescriptorService, themeService, telemetryService, openerService);
this.webviewViewService = webviewViewService;
this.environmentService = environmentService;
this.agentService = agentService;
}

protected override renderBody(container: HTMLElement): void {
super.renderBody(container);

const webviewView = this.webviewViewService.createWebviewView(this.id, {
title: this.title,
icon: this.icon,
});

this.webview = webviewView.webview;
webviewView.webview.html = this.getHtmlForWebview();

webviewView.webview.onDidReceiveMessage(message => {
switch (message.type) {
case 'startTask':
this.agentService.startTask('developer', message.text, message.images);
break;
}
});

// Post initial state
this.postStateToWebview();
}

private async postStateToWebview() {
if (!this.webview) {
return;
}

const state = {
// This will be populated with the actual state from the services
};

this.webview.postMessage({ type: 'state', state });
}

private getHtmlForWebview(): string {
if (!this.webview) {
return '';
}

const webviewUiUri = this.webview.asWebviewUri(
URI.joinPath(this.environmentService.appRoot, 'src', 'vs', 'workbench', 'contrib', 'agent', 'webview-ui', 'build', 'assets', 'index.js')
);

return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cortex IDE Agent</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="${webviewUiUri}"></script>
</body>
</html>`;
}

protected override layoutBody(height: number, width: number): void {
super.layoutBody(height, width);
}
}
72 changes: 72 additions & 0 deletions src/vs/workbench/contrib/agent/browser/codeIndexService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ICodeIndexService, ISymbolReference } from 'vs/workbench/contrib/agent/common/codeIndexService';
import { VectorStoreSearchResult } from 'vs/workbench/contrib/agent/common/vectorStore';
import { IContextService } from 'vs/workbench/contrib/agent/common/contextService';
import { IModelService } from 'vs/workbench/contrib/agent/common/modelService';
import { ILogService } from 'vs/platform/log/common/log';
import { URI } from 'vs/base/common/uri';

// This would be a more complex implementation in a real scenario,
// likely involving a language server and a vector database.
class LanguageService {
async findSymbol(query: string): Promise<ISymbolReference[]> { return []; }
async findReferences(symbol: ISymbolReference): Promise<ISymbolReference[]> { return []; }
async insertAfterSymbol(symbol: ISymbolReference, content: string): Promise<void> {}
}

class VectorDB {
async search(query: string): Promise<VectorStoreSearchResult[]> { return []; }
async startIndexing(): Promise<void> {}
async stopIndexing(): Promise<void> {}
async clearIndex(): Promise<void> {}
}

export class CodeIndexService implements ICodeIndexService {
_serviceBrand: undefined;

private languageService: LanguageService;
private vectorDB: VectorDB;

constructor(
@IContextService private readonly contextService: IContextService,
@IModelService private readonly modelService: IModelService,
@ILogService private readonly logService: ILogService
) {
this.languageService = new LanguageService();
this.vectorDB = new VectorDB();
}

async startIndexing(): Promise<void> {
this.logService.info('Starting code indexing...');
await this.vectorDB.startIndexing();
}

stopWatcher(): void {
this.logService.info('Stopping code indexing watcher...');
this.vectorDB.stopIndexing();
}

async clearIndexData(): Promise<void> {
this.logService.info('Clearing code index data...');
await this.vectorDB.clearIndex();
}

async searchIndex(query: string, directoryPrefix?: string): Promise<VectorStoreSearchResult[]> {
this.logService.info(`Searching index for: ${query}`);
return this.vectorDB.search(query);
}

async findSymbol(query: string): Promise<ISymbolReference[]> {
this.logService.info(`Finding symbol: ${query}`);
return this.languageService.findSymbol(query);
}

async findReferences(symbol: ISymbolReference): Promise<ISymbolReference[]> {
this.logService.info(`Finding references for symbol: ${symbol}`);
return this.languageService.findReferences(symbol);
}

async insertAfterSymbol(symbol: ISymbolReference, content: string): Promise<void> {
this.logService.info(`Inserting content after symbol: ${symbol}`);
await this.languageService.insertAfterSymbol(symbol, content);
}
}
62 changes: 62 additions & 0 deletions src/vs/workbench/contrib/agent/browser/contextService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { IContextService } from 'vs/workbench/contrib/agent/common/contextService';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { GlobalState, RooCodeSettings, GLOBAL_STATE_KEYS, SECRET_STATE_KEYS, isSecretStateKey } from '@roo-code/types';
import { ILogService } from 'vs/platform/log/common/log';
import { Memento } from 'vs/workbench/common/memento';

export class ContextService implements IContextService {
_serviceBrand: undefined;

private stateCache: GlobalState = {};
private memento: Memento;

constructor(
@IStorageService private readonly storageService: IStorageService,
@ILogService private readonly logService: ILogService
) {
this.memento = new Memento('cortex-agent', this.storageService);
this.loadState();
}

private loadState(): void {
const state = this.memento.getMemento(StorageScope.APPLICATION, StorageTarget.MACHINE);
for (const key of GLOBAL_STATE_KEYS) {
this.stateCache[key] = state[key];
}
}

private saveState(): void {
const state = this.memento.getMemento(StorageScope.APPLICATION, StorageTarget.MACHINE);
for (const key of GLOBAL_STATE_KEYS) {
state[key] = this.stateCache[key];
}
this.memento.saveMemento();
}

getValue<K extends keyof RooCodeSettings>(key: K): RooCodeSettings[K] {
if (isSecretStateKey(key)) {
this.logService.warn(`Attempted to access secret key '${key}' through non-secret method.`);
return undefined;
}
return this.stateCache[key as keyof GlobalState] as RooCodeSettings[K];
}

async setValue<K extends keyof RooCodeSettings>(key: K, value: RooCodeSettings[K]): Promise<void> {
if (isSecretStateKey(key)) {
this.logService.warn(`Attempted to set secret key '${key}' through non-secret method.`);
return;
}
this.stateCache[key as keyof GlobalState] = value;
this.saveState();
}

getValues(): RooCodeSettings {
return this.stateCache as RooCodeSettings;
}

async setValues(values: RooCodeSettings): Promise<void> {
for (const key in values) {
await this.setValue(key as keyof RooCodeSettings, values[key as keyof RooCodeSettings]);
}
}
}
36 changes: 36 additions & 0 deletions src/vs/workbench/contrib/agent/browser/knowledgeGraphService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { IKnowledgeGraphService } from 'vs/workbench/contrib/agent/common/knowledgeGraphService';
import { ICodeIndexService } from 'vs/workbench/contrib/agent/common/codeIndexService';
import { ILogService } from 'vs/platform/log/common/log';

// This would be a more complex implementation in a real scenario,
// likely involving a graph database and natural language processing.
class GraphDB {
async buildGraph(data: any): Promise<void> {}
async queryGraph(query: string): Promise<any[]> { return []; }
}

export class KnowledgeGraphService implements IKnowledgeGraphService {
_serviceBrand: undefined;

private graphDB: GraphDB;

constructor(
@ICodeIndexService private readonly codeIndexService: ICodeIndexService,
@ILogService private readonly logService: ILogService
) {
this.graphDB = new GraphDB();
}

async buildGraph(): Promise<void> {
this.logService.info('Building knowledge graph...');
// In a real implementation, we would use the code index to get
// information about the codebase and then use that to build the graph.
const symbols = await this.codeIndexService.findSymbol('*');
await this.graphDB.buildGraph(symbols);
}

async queryGraph(query: string): Promise<any[]> {
this.logService.info(`Querying knowledge graph with: ${query}`);
return this.graphDB.queryGraph(query);
}
}
Loading
Loading