@theia/ai-core 1.55.0-next.4 → 1.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/lib/browser/ai-configuration/agent-configuration-widget.d.ts +1 -0
  2. package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +1 -1
  3. package/lib/browser/ai-configuration/agent-configuration-widget.js +7 -1
  4. package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
  5. package/lib/browser/ai-configuration/template-settings-renderer.js +1 -1
  6. package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -1
  7. package/lib/browser/ai-core-frontend-application-contribution.d.ts +3 -1
  8. package/lib/browser/ai-core-frontend-application-contribution.d.ts.map +1 -1
  9. package/lib/browser/ai-core-frontend-application-contribution.js +6 -6
  10. package/lib/browser/ai-core-frontend-application-contribution.js.map +1 -1
  11. package/lib/browser/frontend-prompt-customization-service.d.ts +6 -5
  12. package/lib/browser/frontend-prompt-customization-service.d.ts.map +1 -1
  13. package/lib/browser/frontend-prompt-customization-service.js +72 -35
  14. package/lib/browser/frontend-prompt-customization-service.js.map +1 -1
  15. package/lib/browser/prompttemplate-contribution.d.ts +1 -0
  16. package/lib/browser/prompttemplate-contribution.d.ts.map +1 -1
  17. package/lib/browser/prompttemplate-contribution.js +3 -2
  18. package/lib/browser/prompttemplate-contribution.js.map +1 -1
  19. package/lib/common/agent-service.d.ts +21 -3
  20. package/lib/common/agent-service.d.ts.map +1 -1
  21. package/lib/common/agent-service.js +17 -13
  22. package/lib/common/agent-service.js.map +1 -1
  23. package/lib/common/communication-recording-service.d.ts +3 -0
  24. package/lib/common/communication-recording-service.d.ts.map +1 -1
  25. package/lib/common/language-model-util.d.ts +11 -0
  26. package/lib/common/language-model-util.d.ts.map +1 -1
  27. package/lib/common/language-model-util.js +19 -2
  28. package/lib/common/language-model-util.js.map +1 -1
  29. package/lib/common/prompt-service.d.ts +33 -3
  30. package/lib/common/prompt-service.d.ts.map +1 -1
  31. package/lib/common/prompt-service.js +23 -1
  32. package/lib/common/prompt-service.js.map +1 -1
  33. package/package.json +12 -10
  34. package/src/browser/ai-configuration/agent-configuration-widget.tsx +8 -0
  35. package/src/browser/ai-configuration/template-settings-renderer.tsx +1 -1
  36. package/src/browser/ai-core-frontend-application-contribution.ts +7 -8
  37. package/src/browser/frontend-prompt-customization-service.ts +73 -35
  38. package/src/browser/prompttemplate-contribution.ts +3 -1
  39. package/src/browser/style/index.css +5 -0
  40. package/src/common/agent-service.ts +42 -13
  41. package/src/common/communication-recording-service.ts +5 -0
  42. package/src/common/language-model-util.ts +18 -1
  43. package/src/common/prompt-service.ts +51 -3
@@ -17,13 +17,22 @@
17
17
  import { DisposableCollection, URI, Event, Emitter } from '@theia/core';
18
18
  import { OpenerService } from '@theia/core/lib/browser';
19
19
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
20
- import { PromptCustomizationService, PromptTemplate } from '../common';
20
+ import { PromptCustomizationService, CustomAgentDescription } from '../common';
21
21
  import { BinaryBuffer } from '@theia/core/lib/common/buffer';
22
22
  import { FileService } from '@theia/filesystem/lib/browser/file-service';
23
23
  import { FileChangesEvent } from '@theia/filesystem/lib/common/files';
24
24
  import { AICorePreferences, PREFERENCE_NAME_PROMPT_TEMPLATES } from './ai-core-preferences';
25
- import { AgentService } from '../common/agent-service';
26
25
  import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
26
+ import { load, dump } from 'js-yaml';
27
+ import { PROMPT_TEMPLATE_EXTENSION } from './prompttemplate-contribution';
28
+
29
+ const templateEntry = {
30
+ id: 'my_agent',
31
+ name: 'My Agent',
32
+ description: 'This is an example agent. Please adapt the properties to fit your needs.',
33
+ prompt: 'You are an example agent. Be nice and helpful to the user.',
34
+ defaultLLM: 'openai/gpt-4o'
35
+ };
27
36
 
28
37
  @injectable()
29
38
  export class FrontendPromptCustomizationServiceImpl implements PromptCustomizationService {
@@ -40,9 +49,6 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
40
49
  @inject(OpenerService)
41
50
  protected readonly openerService: OpenerService;
42
51
 
43
- @inject(AgentService)
44
- protected readonly agentService: AgentService;
45
-
46
52
  protected readonly trackedTemplateURIs = new Set<string>();
47
53
  protected templates = new Map<string, string>();
48
54
 
@@ -51,6 +57,9 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
51
57
  private readonly onDidChangePromptEmitter = new Emitter<string>();
52
58
  readonly onDidChangePrompt: Event<string> = this.onDidChangePromptEmitter.event;
53
59
 
60
+ private readonly onDidChangeCustomAgentsEmitter = new Emitter<void>();
61
+ readonly onDidChangeCustomAgents = this.onDidChangeCustomAgentsEmitter.event;
62
+
54
63
  @postConstruct()
55
64
  protected init(): void {
56
65
  this.preferences.onPreferenceChanged(event => {
@@ -72,6 +81,9 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
72
81
 
73
82
  this.toDispose.push(this.fileService.watch(templateURI, { recursive: true, excludes: [] }));
74
83
  this.toDispose.push(this.fileService.onDidFilesChange(async (event: FileChangesEvent) => {
84
+ if (event.changes.some(change => change.resource.toString().endsWith('customAgents.yml'))) {
85
+ this.onDidChangeCustomAgentsEmitter.fire();
86
+ }
75
87
  // check deleted templates
76
88
  for (const deletedFile of event.getDeleted()) {
77
89
  if (this.trackedTemplateURIs.has(deletedFile.resource.toString())) {
@@ -84,25 +96,26 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
84
96
  // check updated templates
85
97
  for (const updatedFile of event.getUpdated()) {
86
98
  if (this.trackedTemplateURIs.has(updatedFile.resource.toString())) {
87
- const filecontent = await this.fileService.read(updatedFile.resource);
99
+ const fileContent = await this.fileService.read(updatedFile.resource);
88
100
  const templateId = this.removePromptTemplateSuffix(updatedFile.resource.path.name);
89
- _templates.set(templateId, filecontent.value);
101
+ _templates.set(templateId, fileContent.value);
90
102
  this.onDidChangePromptEmitter.fire(templateId);
91
103
  }
92
104
  }
93
105
  // check new templates
94
106
  for (const addedFile of event.getAdded()) {
95
- if (addedFile.resource.parent.toString() === templateURI.toString() && addedFile.resource.path.ext === '.prompttemplate') {
107
+ if (addedFile.resource.parent.toString() === templateURI.toString() && addedFile.resource.path.ext === PROMPT_TEMPLATE_EXTENSION) {
96
108
  this.trackedTemplateURIs.add(addedFile.resource.toString());
97
- const filecontent = await this.fileService.read(addedFile.resource);
109
+ const fileContent = await this.fileService.read(addedFile.resource);
98
110
  const templateId = this.removePromptTemplateSuffix(addedFile.resource.path.name);
99
- _templates.set(templateId, filecontent.value);
111
+ _templates.set(templateId, fileContent.value);
100
112
  this.onDidChangePromptEmitter.fire(templateId);
101
113
  }
102
114
  }
103
115
 
104
116
  }));
105
117
 
118
+ this.onDidChangeCustomAgentsEmitter.fire();
106
119
  const stat = await this.fileService.resolve(templateURI);
107
120
  if (stat.children === undefined) {
108
121
  return;
@@ -113,11 +126,11 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
113
126
  continue;
114
127
  }
115
128
  const fileURI = file.resource;
116
- if (fileURI.path.ext === '.prompttemplate') {
129
+ if (fileURI.path.ext === PROMPT_TEMPLATE_EXTENSION) {
117
130
  this.trackedTemplateURIs.add(fileURI.toString());
118
- const filecontent = await this.fileService.read(fileURI);
131
+ const fileContent = await this.fileService.read(fileURI);
119
132
  const templateId = this.removePromptTemplateSuffix(file.name);
120
- _templates.set(templateId, filecontent.value);
133
+ _templates.set(templateId, fileContent.value);
121
134
  this.onDidChangePromptEmitter.fire(templateId);
122
135
  }
123
136
  }
@@ -133,11 +146,11 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
133
146
  }
134
147
 
135
148
  protected async getTemplateURI(templateId: string): Promise<URI> {
136
- return (await this.getTemplatesDirectoryURI()).resolve(`${templateId}.prompttemplate`);
149
+ return (await this.getTemplatesDirectoryURI()).resolve(`${templateId}${PROMPT_TEMPLATE_EXTENSION}`);
137
150
  }
138
151
 
139
152
  protected removePromptTemplateSuffix(filename: string): string {
140
- const suffix = '.prompttemplate';
153
+ const suffix = PROMPT_TEMPLATE_EXTENSION;
141
154
  if (filename.endsWith(suffix)) {
142
155
  return filename.slice(0, -suffix.length);
143
156
  }
@@ -152,17 +165,10 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
152
165
  return this.templates.get(id);
153
166
  }
154
167
 
155
- async editTemplate(id: string, content?: string): Promise<void> {
156
- const template = this.getOriginalTemplate(id);
157
- if (template === undefined) {
158
- throw new Error(`Unable to edit template ${id}: template not found.`);
159
- }
168
+ async editTemplate(id: string, defaultContent?: string): Promise<void> {
160
169
  const editorUri = await this.getTemplateURI(id);
161
170
  if (! await this.fileService.exists(editorUri)) {
162
- await this.fileService.createFile(editorUri, BinaryBuffer.fromString(content ?? template.template));
163
- } else if (content) {
164
- // Write content to the file before opening it
165
- await this.fileService.writeFile(editorUri, BinaryBuffer.fromString(content));
171
+ await this.fileService.createFile(editorUri, BinaryBuffer.fromString(defaultContent ?? ''));
166
172
  }
167
173
  const openHandler = await this.openerService.getOpener(editorUri);
168
174
  openHandler.open(editorUri);
@@ -175,17 +181,6 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
175
181
  }
176
182
  }
177
183
 
178
- getOriginalTemplate(id: string): PromptTemplate | undefined {
179
- for (const agent of this.agentService.getAllAgents()) {
180
- for (const template of agent.promptTemplates) {
181
- if (template.id === id) {
182
- return template;
183
- }
184
- }
185
- }
186
- return undefined;
187
- }
188
-
189
184
  getTemplateIDFromURI(uri: URI): string | undefined {
190
185
  const id = this.removePromptTemplateSuffix(uri.path.name);
191
186
  if (this.templates.has(id)) {
@@ -194,4 +189,47 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
194
189
  return undefined;
195
190
  }
196
191
 
192
+ async getCustomAgents(): Promise<CustomAgentDescription[]> {
193
+ const customAgentYamlUri = (await this.getTemplatesDirectoryURI()).resolve('customAgents.yml');
194
+ const yamlExists = await this.fileService.exists(customAgentYamlUri);
195
+ if (!yamlExists) {
196
+ return [];
197
+ }
198
+ const fileContent = await this.fileService.read(customAgentYamlUri, { encoding: 'utf-8' });
199
+ try {
200
+ const doc = load(fileContent.value);
201
+ if (!Array.isArray(doc) || !doc.every(entry => CustomAgentDescription.is(entry))) {
202
+ console.debug('Invalid customAgents.yml file content');
203
+ return [];
204
+ }
205
+ const readAgents = doc as CustomAgentDescription[];
206
+ // make sure all agents are unique (id and name)
207
+ const uniqueAgentIds = new Set<string>();
208
+ const uniqueAgents: CustomAgentDescription[] = [];
209
+ readAgents.forEach(agent => {
210
+ if (uniqueAgentIds.has(agent.id)) {
211
+ return;
212
+ }
213
+ uniqueAgentIds.add(agent.id);
214
+ uniqueAgents.push(agent);
215
+ });
216
+ return uniqueAgents;
217
+ } catch (e) {
218
+ console.debug(e.message, e);
219
+ return [];
220
+ }
221
+ }
222
+
223
+ async openCustomAgentYaml(): Promise<void> {
224
+ const customAgentYamlUri = (await this.getTemplatesDirectoryURI()).resolve('customAgents.yml');
225
+ const content = dump([templateEntry]);
226
+ if (! await this.fileService.exists(customAgentYamlUri)) {
227
+ await this.fileService.createFile(customAgentYamlUri, BinaryBuffer.fromString(content));
228
+ } else {
229
+ const fileContent = (await this.fileService.readFile(customAgentYamlUri)).value;
230
+ await this.fileService.writeFile(customAgentYamlUri, BinaryBuffer.concat([fileContent, BinaryBuffer.fromString(content)]));
231
+ }
232
+ const openHandler = await this.openerService.getOpener(customAgentYamlUri);
233
+ openHandler.open(customAgentYamlUri);
234
+ }
197
235
  }
@@ -28,6 +28,8 @@ import { ProviderResult } from '@theia/monaco-editor-core/esm/vs/editor/common/l
28
28
  const PROMPT_TEMPLATE_LANGUAGE_ID = 'theia-ai-prompt-template';
29
29
  const PROMPT_TEMPLATE_TEXTMATE_SCOPE = 'source.prompttemplate';
30
30
 
31
+ export const PROMPT_TEMPLATE_EXTENSION = '.prompttemplate';
32
+
31
33
  export const DISCARD_PROMPT_TEMPLATE_CUSTOMIZATIONS: Command = {
32
34
  id: 'theia-ai-prompt-template:discard',
33
35
  iconClass: codicon('discard'),
@@ -81,7 +83,7 @@ export class PromptTemplateContribution implements LanguageGrammarDefinitionCont
81
83
  'Theia AI Prompt Templates'
82
84
  ],
83
85
  'extensions': [
84
- '.prompttemplate',
86
+ PROMPT_TEMPLATE_EXTENSION,
85
87
  ],
86
88
  'filenames': []
87
89
  });
@@ -88,3 +88,8 @@
88
88
  border-radius: calc(var(--theia-ui-padding) * 2 / 3);
89
89
  background: hsla(0, 0%, 68%, 0.31);
90
90
  }
91
+
92
+ .configuration-agents-add {
93
+ margin-top: 3em;
94
+ margin-left: 0;
95
+ }
@@ -13,10 +13,11 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
- import { inject, injectable, named, optional, postConstruct } from '@theia/core/shared/inversify';
17
- import { ContributionProvider } from '@theia/core';
16
+ import { inject, injectable, optional, postConstruct } from '@theia/core/shared/inversify';
17
+ import { Emitter, Event } from '@theia/core';
18
18
  import { Agent } from './agent';
19
19
  import { AISettingsService } from './settings-service';
20
+ import { PromptService } from './prompt-service';
20
21
 
21
22
  export const AgentService = Symbol('AgentService');
22
23
 
@@ -48,21 +49,42 @@ export interface AgentService {
48
49
  * @return true if the agent is enabled, false otherwise.
49
50
  */
50
51
  isEnabled(agentId: string): boolean;
52
+
53
+ /**
54
+ * Allows to register an agent programmatically.
55
+ * @param agent the agent to register
56
+ */
57
+ registerAgent(agent: Agent): void;
58
+
59
+ /**
60
+ * Allows to unregister an agent programmatically.
61
+ * @param agentId the agent id to unregister
62
+ */
63
+ unregisterAgent(agentId: string): void;
64
+
65
+ /**
66
+ * Emitted when the list of agents changes.
67
+ * This can be used to update the UI when agents are added or removed.
68
+ */
69
+ onDidChangeAgents: Event<void>;
51
70
  }
52
71
 
53
72
  @injectable()
54
73
  export class AgentServiceImpl implements AgentService {
55
74
 
56
- @inject(ContributionProvider) @named(Agent)
57
- protected readonly agentsProvider: ContributionProvider<Agent>;
58
-
59
75
  @inject(AISettingsService) @optional()
60
76
  protected readonly aiSettingsService: AISettingsService | undefined;
61
77
 
78
+ @inject(PromptService)
79
+ protected readonly promptService: PromptService;
80
+
62
81
  protected disabledAgents = new Set<string>();
63
82
 
64
83
  protected _agents: Agent[] = [];
65
84
 
85
+ private readonly onDidChangeAgentsEmitter = new Emitter<void>();
86
+ readonly onDidChangeAgents = this.onDidChangeAgentsEmitter.event;
87
+
66
88
  @postConstruct()
67
89
  protected init(): void {
68
90
  this.aiSettingsService?.getSettings().then(settings => {
@@ -74,22 +96,29 @@ export class AgentServiceImpl implements AgentService {
74
96
  });
75
97
  }
76
98
 
77
- private get agents(): Agent[] {
78
- // We can't collect the contributions at @postConstruct because this will lead to a circular dependency
79
- // with agents reusing the chat agent service (e.g. orchestrator) which in turn injects the agent service
80
- return [...this.agentsProvider.getContributions(), ...this._agents];
81
- }
82
-
83
99
  registerAgent(agent: Agent): void {
84
100
  this._agents.push(agent);
101
+ agent.promptTemplates.forEach(
102
+ template => this.promptService.storePrompt(template.id, template.template)
103
+ );
104
+ this.onDidChangeAgentsEmitter.fire();
105
+ }
106
+
107
+ unregisterAgent(agentId: string): void {
108
+ const agent = this._agents.find(a => a.id === agentId);
109
+ this._agents = this._agents.filter(a => a.id !== agentId);
110
+ this.onDidChangeAgentsEmitter.fire();
111
+ agent?.promptTemplates.forEach(
112
+ template => this.promptService.removePrompt(template.id)
113
+ );
85
114
  }
86
115
 
87
116
  getAgents(): Agent[] {
88
- return this.agents.filter(agent => this.isEnabled(agent.id));
117
+ return this._agents.filter(agent => this.isEnabled(agent.id));
89
118
  }
90
119
 
91
120
  getAllAgents(): Agent[] {
92
- return this.agents;
121
+ return this._agents;
93
122
  }
94
123
 
95
124
  enableAgent(agentId: string): void {
@@ -41,4 +41,9 @@ export interface CommunicationRecordingService {
41
41
  readonly onDidRecordResponse: Event<CommunicationResponseEntry>;
42
42
 
43
43
  getHistory(agentId: string): CommunicationHistory;
44
+
45
+ getSessionHistory(sessionId: string): CommunicationHistory;
46
+
47
+ clearHistory(): void;
48
+ readonly onStructuralChange: Event<void>;
44
49
  }
@@ -14,8 +14,18 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { isLanguageModelStreamResponse, isLanguageModelTextResponse, LanguageModelResponse, ToolRequest } from './language-model';
17
+ import { isLanguageModelParsedResponse, isLanguageModelStreamResponse, isLanguageModelTextResponse, LanguageModelResponse, ToolRequest } from './language-model';
18
18
 
19
+ /**
20
+ * Retrieves the text content from a `LanguageModelResponse` object.
21
+ *
22
+ * **Important:** For stream responses, the stream can only be consumed once. Calling this function multiple times on the same stream response will return an empty string (`''`)
23
+ * on subsequent calls, as the stream will have already been consumed.
24
+ *
25
+ * @param {LanguageModelResponse} response - The response object, which may contain a text, stream, or parsed response.
26
+ * @returns {Promise<string>} - A promise that resolves to the text content of the response.
27
+ * @throws {Error} - Throws an error if the response type is not supported or does not contain valid text content.
28
+ */
19
29
  export const getTextOfResponse = async (response: LanguageModelResponse): Promise<string> => {
20
30
  if (isLanguageModelTextResponse(response)) {
21
31
  return response.text;
@@ -25,12 +35,18 @@ export const getTextOfResponse = async (response: LanguageModelResponse): Promis
25
35
  result += chunk.content ?? '';
26
36
  }
27
37
  return result;
38
+ } else if (isLanguageModelParsedResponse(response)) {
39
+ return response.content;
28
40
  }
29
41
  throw new Error(`Invalid response type ${response}`);
30
42
  };
31
43
 
32
44
  export const getJsonOfResponse = async (response: LanguageModelResponse): Promise<unknown> => {
33
45
  const text = await getTextOfResponse(response);
46
+ return getJsonOfText(text);
47
+ };
48
+
49
+ export const getJsonOfText = (text: string): unknown => {
34
50
  if (text.startsWith('```json')) {
35
51
  const regex = /```json\s*([\s\S]*?)\s*```/g;
36
52
  let match;
@@ -47,6 +63,7 @@ export const getJsonOfResponse = async (response: LanguageModelResponse): Promis
47
63
  }
48
64
  throw new Error('Invalid response format');
49
65
  };
66
+
50
67
  export const toolRequestToPromptText = (toolRequest: ToolRequest): string => {
51
68
  const parameters = toolRequest.parameters;
52
69
  let paramsText = '';
@@ -58,17 +58,46 @@ export interface PromptService {
58
58
  */
59
59
  getPrompt(id: string, args?: { [key: string]: unknown }): Promise<ResolvedPromptTemplate | undefined>;
60
60
  /**
61
- * Manually add a prompt to the list of prompts.
61
+ * Adds a prompt to the list of prompts.
62
62
  * @param id the id of the prompt
63
63
  * @param prompt the prompt template to store
64
64
  */
65
65
  storePrompt(id: string, prompt: string): void;
66
+ /**
67
+ * Removes a prompt from the list of prompts.
68
+ * @param id the id of the prompt
69
+ */
70
+ removePrompt(id: string): void;
66
71
  /**
67
72
  * Return all known prompts as a {@link PromptMap map}.
68
73
  */
69
74
  getAllPrompts(): PromptMap;
70
75
  }
71
76
 
77
+ export interface CustomAgentDescription {
78
+ id: string;
79
+ name: string;
80
+ description: string;
81
+ prompt: string;
82
+ defaultLLM: string;
83
+ }
84
+ export namespace CustomAgentDescription {
85
+ export function is(entry: unknown): entry is CustomAgentDescription {
86
+ // eslint-disable-next-line no-null/no-null
87
+ return typeof entry === 'object' && entry !== null
88
+ && 'id' in entry && typeof entry.id === 'string'
89
+ && 'name' in entry && typeof entry.name === 'string'
90
+ && 'description' in entry && typeof entry.description === 'string'
91
+ && 'prompt' in entry
92
+ && typeof entry.prompt === 'string'
93
+ && 'defaultLLM' in entry
94
+ && typeof entry.defaultLLM === 'string';
95
+ }
96
+ export function equals(a: CustomAgentDescription, b: CustomAgentDescription): boolean {
97
+ return a.id === b.id && a.name === b.name && a.description === b.description && a.prompt === b.prompt && a.defaultLLM === b.defaultLLM;
98
+ }
99
+ }
100
+
72
101
  export const PromptCustomizationService = Symbol('PromptCustomizationService');
73
102
  export interface PromptCustomizationService {
74
103
  /**
@@ -89,9 +118,9 @@ export interface PromptCustomizationService {
89
118
  * on the implementation. Implementation may for example decide to
90
119
  * open an editor, or request more information from the user, ...
91
120
  * @param id the template id.
92
- * @param content optional content to customize the template.
121
+ * @param content optional default content to initialize the template
93
122
  */
94
- editTemplate(id: string, content?: string): void;
123
+ editTemplate(id: string, defaultContent?: string): void;
95
124
 
96
125
  /**
97
126
  * Reset the template to its default value.
@@ -109,6 +138,22 @@ export interface PromptCustomizationService {
109
138
  * Event which is fired when the prompt template is changed.
110
139
  */
111
140
  readonly onDidChangePrompt: Event<string>;
141
+
142
+ /**
143
+ * Return all custom agents.
144
+ * @returns all custom agents
145
+ */
146
+ getCustomAgents(): Promise<CustomAgentDescription[]>;
147
+
148
+ /**
149
+ * Event which is fired when custom agents are modified.
150
+ */
151
+ readonly onDidChangeCustomAgents: Event<void>;
152
+
153
+ /**
154
+ * Open the custom agent yaml file.
155
+ */
156
+ openCustomAgentYaml(): void;
112
157
  }
113
158
 
114
159
  @injectable()
@@ -210,4 +255,7 @@ export class PromptServiceImpl implements PromptService {
210
255
  storePrompt(id: string, prompt: string): void {
211
256
  this._prompts[id] = { id, template: prompt };
212
257
  }
258
+ removePrompt(id: string): void {
259
+ delete this._prompts[id];
260
+ }
213
261
  }