From 9692ac387e47af5f4b2674bbc10e9efdcb2bd540 Mon Sep 17 00:00:00 2001 From: Eugen Neufeld Date: Fri, 18 Oct 2024 12:25:28 +0200 Subject: [PATCH] incorporate review comments --- .../src/browser/ai-chat-frontend-module.ts | 10 +++++++--- .../src/browser/custom-agent-factory.ts | 4 ++-- ...agent-frontend-application-contribution.ts | 10 +++++----- .../frontend-prompt-customization-service.ts | 20 +++++++++++++------ packages/ai-core/src/common/prompt-service.ts | 7 +++++-- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/packages/ai-chat/src/browser/ai-chat-frontend-module.ts b/packages/ai-chat/src/browser/ai-chat-frontend-module.ts index cd84c076f6c5f..396bcb7331a06 100644 --- a/packages/ai-chat/src/browser/ai-chat-frontend-module.ts +++ b/packages/ai-chat/src/browser/ai-chat-frontend-module.ts @@ -36,7 +36,7 @@ import { UniversalChatAgent } from '../common/universal-chat-agent'; import { aiChatPreferences } from './ai-chat-preferences'; import { AICustomAgentsFrontendApplicationContribution } from './custom-agent-frontend-application-contribution'; import { FrontendChatServiceImpl } from './frontend-chat-service'; -import { FactoryOfCustomAgents } from './custom-agent-factory'; +import { CustomAgentFactory } from './custom-agent-factory'; export default new ContainerModule(bind => { bindContributionProvider(bind, Agent); @@ -74,13 +74,17 @@ export default new ContainerModule(bind => { bind(PreferenceContribution).toConstantValue({ schema: aiChatPreferences }); bind(CustomChatAgent).toSelf(); - bind(FactoryOfCustomAgents).toFactory( - ctx => (id: string, name: string, description: string, prompt: string) => { + bind(CustomAgentFactory).toFactory( + ctx => (id: string, name: string, description: string, prompt: string, defaultLLM: string) => { const agent = ctx.container.get(CustomChatAgent); agent.id = id; agent.name = name; agent.description = description; agent.prompt = prompt; + agent.languageModelRequirements = [{ + purpose: 'chat', + identifier: defaultLLM, + }]; ctx.container.get(ChatAgentService).registerChatAgent(agent); ctx.container.get(AgentService).registerAgent(agent); return agent; diff --git a/packages/ai-chat/src/browser/custom-agent-factory.ts b/packages/ai-chat/src/browser/custom-agent-factory.ts index dbf94cfa49c2e..9fe67f88e723e 100644 --- a/packages/ai-chat/src/browser/custom-agent-factory.ts +++ b/packages/ai-chat/src/browser/custom-agent-factory.ts @@ -16,5 +16,5 @@ import { CustomChatAgent } from '../common'; -export const FactoryOfCustomAgents = Symbol('FactoryOfCustomAgents'); -export type FactoryOfCustomAgents = (id: string, name: string, description: string, prompt: string) => CustomChatAgent; +export const CustomAgentFactory = Symbol('CustomAgentFactory'); +export type CustomAgentFactory = (id: string, name: string, description: string, prompt: string, defaultLLM: string) => CustomChatAgent; diff --git a/packages/ai-chat/src/browser/custom-agent-frontend-application-contribution.ts b/packages/ai-chat/src/browser/custom-agent-frontend-application-contribution.ts index e6cea408e2866..4c67a14ab508c 100644 --- a/packages/ai-chat/src/browser/custom-agent-frontend-application-contribution.ts +++ b/packages/ai-chat/src/browser/custom-agent-frontend-application-contribution.ts @@ -18,12 +18,12 @@ import { AgentService, CustomAgentDescription, PromptCustomizationService } from import { FrontendApplicationContribution } from '@theia/core/lib/browser'; import { inject, injectable } from '@theia/core/shared/inversify'; import { ChatAgentService } from '../common'; -import { FactoryOfCustomAgents } from './custom-agent-factory'; +import { CustomAgentFactory } from './custom-agent-factory'; @injectable() export class AICustomAgentsFrontendApplicationContribution implements FrontendApplicationContribution { - @inject(FactoryOfCustomAgents) - protected readonly customAgentFactory: FactoryOfCustomAgents; + @inject(CustomAgentFactory) + protected readonly customAgentFactory: CustomAgentFactory; @inject(PromptCustomizationService) protected readonly customizationService: PromptCustomizationService; @@ -38,7 +38,7 @@ export class AICustomAgentsFrontendApplicationContribution implements FrontendAp onStart(): void { this.customizationService?.getCustomAgents().then(customAgents => { customAgents.forEach(agent => { - this.customAgentFactory(agent.id, agent.name, agent.description, agent.prompt); + this.customAgentFactory(agent.id, agent.name, agent.description, agent.prompt, agent.defaultLLM); this.knownCustomAgents.set(agent.id, agent); }); }).catch(e => { @@ -59,7 +59,7 @@ export class AICustomAgentsFrontendApplicationContribution implements FrontendAp }); customAgentsToAdd .forEach(agent => { - this.customAgentFactory(agent.id, agent.name, agent.description, agent.prompt); + this.customAgentFactory(agent.id, agent.name, agent.description, agent.prompt, agent.defaultLLM); this.knownCustomAgents.set(agent.id, agent); }); }).catch(e => { diff --git a/packages/ai-core/src/browser/frontend-prompt-customization-service.ts b/packages/ai-core/src/browser/frontend-prompt-customization-service.ts index 7866519d4fd8c..782d9112e8e16 100644 --- a/packages/ai-core/src/browser/frontend-prompt-customization-service.ts +++ b/packages/ai-core/src/browser/frontend-prompt-customization-service.ts @@ -24,12 +24,15 @@ import { FileChangesEvent } from '@theia/filesystem/lib/common/files'; import { AICorePreferences, PREFERENCE_NAME_PROMPT_TEMPLATES } from './ai-core-preferences'; import { AgentService } from '../common/agent-service'; import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; -import { load } from 'js-yaml'; +import { load, dump } from 'js-yaml'; -const templateEntry = `-id: my_agent -name: My Agent -description: This is an example agent. Please adapt the properties to fit your needs. -prompt: You are an example agent. Be nice and helpful to the user.`; +const templateEntry = { + id: 'my_agent', + name: 'My Agent', + description: 'This is an example agent. Please adapt the properties to fit your needs.', + prompt: 'You are an example agent. Be nice and helpful to the user.', + defaultLLM: 'openai/gpt-4o' +}; @injectable() export class FrontendPromptCustomizationServiceImpl implements PromptCustomizationService { @@ -115,6 +118,7 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati })); + this.onDidChangeCustomAgentsEmitter.fire(); const stat = await this.fileService.resolve(templateURI); if (stat.children === undefined) { return; @@ -228,8 +232,12 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati async openCustomAgentYaml(): Promise { const customAgentYamlUri = (await this.getTemplatesDirectoryURI()).resolve('customAgents.yml'); + const content = dump([templateEntry]); if (! await this.fileService.exists(customAgentYamlUri)) { - await this.fileService.createFile(customAgentYamlUri, BinaryBuffer.fromString(templateEntry)); + await this.fileService.createFile(customAgentYamlUri, BinaryBuffer.fromString(content)); + } else { + const fileContent = (await this.fileService.readFile(customAgentYamlUri)).value; + await this.fileService.writeFile(customAgentYamlUri, BinaryBuffer.concat([fileContent, BinaryBuffer.fromString(content)])); } const openHandler = await this.openerService.getOpener(customAgentYamlUri); openHandler.open(customAgentYamlUri); diff --git a/packages/ai-core/src/common/prompt-service.ts b/packages/ai-core/src/common/prompt-service.ts index de6f4446b94ca..44d8fb0622d66 100644 --- a/packages/ai-core/src/common/prompt-service.ts +++ b/packages/ai-core/src/common/prompt-service.ts @@ -74,6 +74,7 @@ export interface CustomAgentDescription { name: string; description: string; prompt: string; + defaultLLM: string; } export namespace CustomAgentDescription { export function is(entry: unknown): entry is CustomAgentDescription { @@ -83,10 +84,12 @@ export namespace CustomAgentDescription { && 'name' in entry && typeof entry.name === 'string' && 'description' in entry && typeof entry.description === 'string' && 'prompt' in entry - && typeof entry.prompt === 'string'; + && typeof entry.prompt === 'string' + && 'defaultLLM' in entry + && typeof entry.defaultLLM === 'string'; } export function equals(a: CustomAgentDescription, b: CustomAgentDescription): boolean { - return a.id === b.id && a.name === b.name && a.description === b.description && a.prompt === b.prompt; + return a.id === b.id && a.name === b.name && a.description === b.description && a.prompt === b.prompt && a.defaultLLM === b.defaultLLM; } }