@theia/ai-chat 1.55.0-next.4 → 1.55.0-next.70

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 (57) hide show
  1. package/lib/browser/ai-chat-frontend-module.d.ts.map +1 -1
  2. package/lib/browser/ai-chat-frontend-module.js +25 -2
  3. package/lib/browser/ai-chat-frontend-module.js.map +1 -1
  4. package/lib/browser/custom-agent-factory.d.ts +4 -0
  5. package/lib/browser/custom-agent-factory.d.ts.map +1 -0
  6. package/lib/browser/custom-agent-factory.js +20 -0
  7. package/lib/browser/custom-agent-factory.js.map +1 -0
  8. package/lib/browser/custom-agent-frontend-application-contribution.d.ts +13 -0
  9. package/lib/browser/custom-agent-frontend-application-contribution.d.ts.map +1 -0
  10. package/lib/browser/custom-agent-frontend-application-contribution.js +82 -0
  11. package/lib/browser/custom-agent-frontend-application-contribution.js.map +1 -0
  12. package/lib/common/chat-agent-service.d.ts +11 -0
  13. package/lib/common/chat-agent-service.d.ts.map +1 -1
  14. package/lib/common/chat-agent-service.js +3 -0
  15. package/lib/common/chat-agent-service.js.map +1 -1
  16. package/lib/common/chat-agents-variable-contribution.d.ts +1 -1
  17. package/lib/common/chat-agents-variable-contribution.d.ts.map +1 -1
  18. package/lib/common/chat-agents.d.ts +8 -1
  19. package/lib/common/chat-agents.d.ts.map +1 -1
  20. package/lib/common/chat-agents.js +28 -32
  21. package/lib/common/chat-agents.js.map +1 -1
  22. package/lib/common/chat-history-entry.d.ts +7 -0
  23. package/lib/common/chat-history-entry.d.ts.map +1 -0
  24. package/lib/common/chat-history-entry.js +42 -0
  25. package/lib/common/chat-history-entry.js.map +1 -0
  26. package/lib/common/chat-model.d.ts +14 -1
  27. package/lib/common/chat-model.d.ts.map +1 -1
  28. package/lib/common/chat-model.js +11 -1
  29. package/lib/common/chat-model.js.map +1 -1
  30. package/lib/common/custom-chat-agent.d.ts +14 -0
  31. package/lib/common/custom-chat-agent.d.ts.map +1 -0
  32. package/lib/common/custom-chat-agent.js +43 -0
  33. package/lib/common/custom-chat-agent.js.map +1 -0
  34. package/lib/common/index.d.ts +4 -3
  35. package/lib/common/index.d.ts.map +1 -1
  36. package/lib/common/index.js +4 -3
  37. package/lib/common/index.js.map +1 -1
  38. package/lib/common/o1-chat-agent.d.ts +13 -0
  39. package/lib/common/o1-chat-agent.d.ts.map +1 -0
  40. package/lib/common/o1-chat-agent.js +45 -0
  41. package/lib/common/o1-chat-agent.js.map +1 -0
  42. package/lib/common/orchestrator-chat-agent.d.ts.map +1 -1
  43. package/lib/common/orchestrator-chat-agent.js +28 -3
  44. package/lib/common/orchestrator-chat-agent.js.map +1 -1
  45. package/package.json +8 -8
  46. package/src/browser/ai-chat-frontend-module.ts +30 -4
  47. package/src/browser/custom-agent-factory.ts +20 -0
  48. package/src/browser/custom-agent-frontend-application-contribution.ts +73 -0
  49. package/src/common/chat-agent-service.ts +15 -0
  50. package/src/common/chat-agents-variable-contribution.ts +1 -1
  51. package/src/common/chat-agents.ts +32 -31
  52. package/src/common/chat-history-entry.ts +47 -0
  53. package/src/common/chat-model.ts +17 -1
  54. package/src/common/custom-chat-agent.ts +44 -0
  55. package/src/common/index.ts +4 -3
  56. package/src/common/o1-chat-agent.ts +51 -0
  57. package/src/common/orchestrator-chat-agent.ts +30 -4
@@ -41,6 +41,18 @@ export interface ChatAgentService {
41
41
  * Returns all agents, including disabled ones.
42
42
  */
43
43
  getAllAgents(): ChatAgent[];
44
+
45
+ /**
46
+ * Allows to register a chat agent programmatically.
47
+ * @param agent the agent to register
48
+ */
49
+ registerChatAgent(agent: ChatAgent): void;
50
+
51
+ /**
52
+ * Allows to unregister a chat agent programmatically.
53
+ * @param agentId the agent id to unregister
54
+ */
55
+ unregisterChatAgent(agentId: string): void;
44
56
  }
45
57
  @injectable()
46
58
  export class ChatAgentServiceImpl implements ChatAgentService {
@@ -65,6 +77,9 @@ export class ChatAgentServiceImpl implements ChatAgentService {
65
77
  registerChatAgent(agent: ChatAgent): void {
66
78
  this._agents.push(agent);
67
79
  }
80
+ unregisterChatAgent(agentId: string): void {
81
+ this._agents = this._agents.filter(a => a.id !== agentId);
82
+ }
68
83
 
69
84
  getAgent(id: string): ChatAgent | undefined {
70
85
  if (!this._agentIsEnabled(id)) {
@@ -23,7 +23,7 @@ import {
23
23
  AIVariableResolver,
24
24
  AIVariableService,
25
25
  ResolvedAIVariable
26
- } from '../../../ai-core/src/common/variable-service';
26
+ } from '@theia/ai-core';
27
27
  import { ChatAgentService } from './chat-agent-service';
28
28
 
29
29
  export const CHAT_AGENTS_VARIABLE: AIVariable = {
@@ -52,6 +52,7 @@ import {
52
52
  } from './chat-model';
53
53
  import { findFirstMatch, parseContents } from './parse-contents';
54
54
  import { DefaultResponseContentFactory, ResponseContentMatcher, ResponseContentMatcherProvider } from './response-content-matcher';
55
+ import { ChatHistoryEntry } from './chat-history-entry';
55
56
 
56
57
  /**
57
58
  * A conversation consists of a sequence of ChatMessages.
@@ -137,7 +138,8 @@ export abstract class AbstractChatAgent {
137
138
  protected defaultLanguageModelPurpose: string,
138
139
  public iconClass: string = 'codicon codicon-copilot',
139
140
  public locations: ChatAgentLocation[] = ChatAgentLocation.ALL,
140
- public tags: String[] = ['Chat']) {
141
+ public tags: String[] = ['Chat'],
142
+ public defaultLogging: boolean = true) {
141
143
  }
142
144
 
143
145
  @postConstruct()
@@ -151,17 +153,19 @@ export abstract class AbstractChatAgent {
151
153
  if (!languageModel) {
152
154
  throw new Error('Couldn\'t find a matching language model. Please check your setup!');
153
155
  }
154
- const messages = await this.getMessages(request.session);
155
- this.recordingService.recordRequest({
156
- agentId: this.id,
157
- sessionId: request.session.id,
158
- timestamp: Date.now(),
159
- requestId: request.id,
160
- request: request.request.text,
161
- messages
162
- });
163
156
 
164
157
  const systemMessageDescription = await this.getSystemMessageDescription();
158
+ const messages = await this.getMessages(request.session);
159
+ if (this.defaultLogging) {
160
+ this.recordingService.recordRequest(
161
+ ChatHistoryEntry.fromRequest(
162
+ this.id, request, {
163
+ messages,
164
+ systemMessage: systemMessageDescription?.text
165
+ })
166
+ );
167
+ }
168
+
165
169
  const tools: Map<string, ToolRequest> = new Map();
166
170
  if (systemMessageDescription) {
167
171
  const systemMsg: ChatMessage = {
@@ -192,13 +196,9 @@ export abstract class AbstractChatAgent {
192
196
  );
193
197
  await this.addContentsToResponse(languageModelResponse, request);
194
198
  request.response.complete();
195
- this.recordingService.recordResponse({
196
- agentId: this.id,
197
- sessionId: request.session.id,
198
- timestamp: Date.now(),
199
- requestId: request.response.requestId,
200
- response: request.response.response.asString()
201
- });
199
+ if (this.defaultLogging) {
200
+ this.recordingService.recordResponse(ChatHistoryEntry.fromResponse(this.id, request));
201
+ }
202
202
  } catch (e) {
203
203
  this.handleError(request, e);
204
204
  }
@@ -274,13 +274,22 @@ export abstract class AbstractChatAgent {
274
274
  tools: ToolRequest[] | undefined,
275
275
  token: CancellationToken
276
276
  ): Promise<LanguageModelResponse> {
277
+ const settings = this.getLlmSettings();
277
278
  const languageModelResponse = languageModel.request({
278
279
  messages,
279
280
  tools,
281
+ settings,
280
282
  }, token);
281
283
  return languageModelResponse;
282
284
  }
283
285
 
286
+ /**
287
+ * @returns the settings, such as `temperature`, to be used in all language model requests. Returns `undefined` by default.
288
+ */
289
+ protected getLlmSettings(): { [key: string]: unknown; } | undefined {
290
+ return undefined;
291
+ }
292
+
284
293
  protected abstract addContentsToResponse(languageModelResponse: LanguageModelResponse, request: ChatRequestModelImpl): Promise<void>;
285
294
  }
286
295
 
@@ -307,25 +316,17 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
307
316
  const contents = this.parseContents(languageModelResponse.text);
308
317
  request.response.response.addContents(contents);
309
318
  request.response.complete();
310
- this.recordingService.recordResponse({
311
- agentId: this.id,
312
- sessionId: request.session.id,
313
- timestamp: Date.now(),
314
- requestId: request.response.requestId,
315
- response: request.response.response.asString()
316
- });
319
+ if (this.defaultLogging) {
320
+ this.recordingService.recordResponse(ChatHistoryEntry.fromResponse(this.id, request));
321
+ }
317
322
  return;
318
323
  }
319
324
  if (isLanguageModelStreamResponse(languageModelResponse)) {
320
325
  await this.addStreamResponse(languageModelResponse, request);
321
326
  request.response.complete();
322
- this.recordingService.recordResponse({
323
- agentId: this.id,
324
- sessionId: request.session.id,
325
- timestamp: Date.now(),
326
- requestId: request.response.requestId,
327
- response: request.response.response.asString()
328
- });
327
+ if (this.defaultLogging) {
328
+ this.recordingService.recordResponse(ChatHistoryEntry.fromResponse(this.id, request));
329
+ }
329
330
  return;
330
331
  }
331
332
  this.logger.error(
@@ -0,0 +1,47 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { CommunicationRequestEntryParam, CommunicationResponseEntryParam } from '@theia/ai-core/lib/common/communication-recording-service';
18
+ import { ChatRequestModel } from './chat-model';
19
+
20
+ export namespace ChatHistoryEntry {
21
+ export function fromRequest(
22
+ agentId: string,
23
+ request: ChatRequestModel,
24
+ args: Partial<CommunicationRequestEntryParam> = {}
25
+ ): CommunicationRequestEntryParam {
26
+ return {
27
+ agentId: agentId,
28
+ sessionId: request.session.id,
29
+ requestId: request.id,
30
+ request: request.request.text,
31
+ ...args,
32
+ };
33
+ }
34
+ export function fromResponse(
35
+ agentId: string,
36
+ request: ChatRequestModel,
37
+ args: Partial<CommunicationResponseEntryParam> = {}
38
+ ): CommunicationResponseEntryParam {
39
+ return {
40
+ agentId: agentId,
41
+ sessionId: request.session.id,
42
+ requestId: request.id,
43
+ response: request.response.response.asString(),
44
+ ...args,
45
+ };
46
+ }
47
+ }
@@ -73,6 +73,7 @@ export interface ChatRequestModel {
73
73
  readonly response: ChatResponseModel;
74
74
  readonly message: ParsedChatRequest;
75
75
  readonly agentId?: string;
76
+ readonly data?: { [key: string]: unknown };
76
77
  }
77
78
 
78
79
  export interface ChatProgressMessage {
@@ -342,14 +343,29 @@ export class ChatRequestModelImpl implements ChatRequestModel {
342
343
  protected _request: ChatRequest;
343
344
  protected _response: ChatResponseModelImpl;
344
345
  protected _agentId?: string;
346
+ protected _data: { [key: string]: unknown };
345
347
 
346
- constructor(session: ChatModel, public readonly message: ParsedChatRequest, agentId?: string) {
348
+ constructor(session: ChatModel, public readonly message: ParsedChatRequest, agentId?: string,
349
+ data: { [key: string]: unknown } = {}) {
347
350
  // TODO accept serialized data as a parameter to restore a previously saved ChatRequestModel
348
351
  this._request = message.request;
349
352
  this._id = generateUuid();
350
353
  this._session = session;
351
354
  this._response = new ChatResponseModelImpl(this._id, agentId);
352
355
  this._agentId = agentId;
356
+ this._data = data;
357
+ }
358
+
359
+ get data(): { [key: string]: unknown } | undefined {
360
+ return this._data;
361
+ }
362
+
363
+ addData(key: string, value: unknown): void {
364
+ this._data[key] = value;
365
+ }
366
+
367
+ getDataByKey(key: string): unknown {
368
+ return this._data[key];
353
369
  }
354
370
 
355
371
  get id(): string {
@@ -0,0 +1,44 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { AgentSpecificVariables, PromptTemplate } from '@theia/ai-core';
18
+ import { AbstractStreamParsingChatAgent, ChatAgent, SystemMessageDescription } from './chat-agents';
19
+ import { injectable } from '@theia/core/shared/inversify';
20
+
21
+ @injectable()
22
+ export class CustomChatAgent
23
+ extends AbstractStreamParsingChatAgent
24
+ implements ChatAgent {
25
+ name: string;
26
+ description: string;
27
+ readonly variables: string[] = [];
28
+ readonly functions: string[] = [];
29
+ readonly promptTemplates: PromptTemplate[] = [];
30
+ readonly agentSpecificVariables: AgentSpecificVariables[] = [];
31
+
32
+ constructor(
33
+ ) {
34
+ super('CustomChatAgent', [{ purpose: 'chat' }], 'chat');
35
+ }
36
+ protected override async getSystemMessageDescription(): Promise<SystemMessageDescription | undefined> {
37
+ const resolvedPrompt = await this.promptService.getPrompt(`${this.name}_prompt`);
38
+ return resolvedPrompt ? SystemMessageDescription.fromResolvedPromptTemplate(resolvedPrompt) : undefined;
39
+ }
40
+
41
+ set prompt(prompt: string) {
42
+ this.promptTemplates.push({ id: `${this.name}_prompt`, template: prompt });
43
+ }
44
+ }
@@ -13,12 +13,13 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
- export * from './chat-agent-service';
17
16
  export * from './chat-agents';
17
+ export * from './chat-agent-service';
18
18
  export * from './chat-model';
19
- export * from './parsed-chat-request';
20
19
  export * from './chat-request-parser';
21
20
  export * from './chat-service';
22
21
  export * from './command-chat-agents';
23
- export * from './universal-chat-agent';
22
+ export * from './custom-chat-agent';
23
+ export * from './parsed-chat-request';
24
24
  export * from './orchestrator-chat-agent';
25
+ export * from './universal-chat-agent';
@@ -0,0 +1,51 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import {
18
+ ChatAgent,
19
+ AbstractStreamParsingChatAgent,
20
+ SystemMessageDescription
21
+ } from './chat-agents';
22
+
23
+ import { injectable } from '@theia/core/shared/inversify';
24
+ import { AgentSpecificVariables, PromptTemplate } from '@theia/ai-core';
25
+
26
+ @injectable()
27
+ export class O1ChatAgent extends AbstractStreamParsingChatAgent implements ChatAgent {
28
+
29
+ public name = 'O1-Preview';
30
+ public description = 'An agent for interacting with ChatGPT o1-preview';
31
+ public promptTemplates: PromptTemplate[] = [];
32
+ readonly agentSpecificVariables: AgentSpecificVariables[] = [];
33
+ readonly variables: string[] = [];
34
+ readonly functions: string[] = [];
35
+
36
+ constructor() {
37
+ super(
38
+ 'o1-preview',
39
+ [{
40
+ purpose: 'chat',
41
+ identifier: 'openai/o1-preview',
42
+ }],
43
+ 'chat'
44
+ );
45
+ }
46
+
47
+ protected async getSystemMessageDescription(): Promise<SystemMessageDescription | undefined> {
48
+ // O1 currently does not support system prompts
49
+ return undefined;
50
+ }
51
+ }
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { AgentSpecificVariables, getJsonOfResponse, LanguageModelResponse } from '@theia/ai-core';
17
+ import { AgentSpecificVariables, getJsonOfText, getTextOfResponse, LanguageModelResponse } from '@theia/ai-core';
18
18
  import {
19
19
  PromptTemplate
20
20
  } from '@theia/ai-core/lib/common';
@@ -22,6 +22,8 @@ import { inject, injectable } from '@theia/core/shared/inversify';
22
22
  import { ChatAgentService } from './chat-agent-service';
23
23
  import { AbstractStreamParsingChatAgent, ChatAgent, SystemMessageDescription } from './chat-agents';
24
24
  import { ChatRequestModelImpl, InformationalChatResponseContentImpl } from './chat-model';
25
+ import { generateUuid } from '@theia/core';
26
+ import { ChatHistoryEntry } from './chat-history-entry';
25
27
 
26
28
  export const orchestratorTemplate: PromptTemplate = {
27
29
  id: 'orchestrator-system',
@@ -59,6 +61,7 @@ You must only use the \`id\` attribute of the agent, never the name.
59
61
  `};
60
62
 
61
63
  export const OrchestratorChatAgentId = 'Orchestrator';
64
+ const OrchestratorRequestIdKey = 'orchestatorRequestIdKey';
62
65
 
63
66
  @injectable()
64
67
  export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent implements ChatAgent {
@@ -74,7 +77,7 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent implem
74
77
  super(OrchestratorChatAgentId, [{
75
78
  purpose: 'agent-selection',
76
79
  identifier: 'openai/gpt-4o',
77
- }], 'agent-selection', 'codicon codicon-symbol-boolean');
80
+ }], 'agent-selection', 'codicon codicon-symbol-boolean', undefined, undefined, false);
78
81
  this.name = OrchestratorChatAgentId;
79
82
  this.description = 'This agent analyzes the user request against the description of all available chat agents and selects the best fitting agent to answer the request \
80
83
  (by using AI).The user\'s request will be directly delegated to the selected agent without further confirmation.';
@@ -88,8 +91,20 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent implem
88
91
  @inject(ChatAgentService)
89
92
  protected chatAgentService: ChatAgentService;
90
93
 
91
- override invoke(request: ChatRequestModelImpl): Promise<void> {
94
+ override async invoke(request: ChatRequestModelImpl): Promise<void> {
92
95
  request.response.addProgressMessage({ content: 'Determining the most appropriate agent', status: 'inProgress' });
96
+ // We generate a dedicated ID for recording the orchestrator request/response, as we will forward the original request to another agent
97
+ const orchestratorRequestId = generateUuid();
98
+ request.addData(OrchestratorRequestIdKey, orchestratorRequestId);
99
+ const messages = await this.getMessages(request.session);
100
+ const systemMessage = (await this.getSystemMessageDescription())?.text;
101
+ this.recordingService.recordRequest(
102
+ ChatHistoryEntry.fromRequest(this.id, request, {
103
+ requestId: orchestratorRequestId,
104
+ messages,
105
+ systemMessage
106
+ })
107
+ );
93
108
  return super.invoke(request);
94
109
  }
95
110
 
@@ -100,8 +115,19 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent implem
100
115
 
101
116
  protected override async addContentsToResponse(response: LanguageModelResponse, request: ChatRequestModelImpl): Promise<void> {
102
117
  let agentIds: string[] = [];
118
+ const responseText = await getTextOfResponse(response);
119
+ // We use the previously generated, dedicated ID to log the orchestrator response before we forward the original request
120
+ const orchestratorRequestId = request.getDataByKey(OrchestratorRequestIdKey);
121
+ if (typeof orchestratorRequestId === 'string') {
122
+ this.recordingService.recordResponse({
123
+ agentId: this.id,
124
+ sessionId: request.session.id,
125
+ requestId: orchestratorRequestId,
126
+ response: responseText,
127
+ });
128
+ }
103
129
  try {
104
- const jsonResponse = await getJsonOfResponse(response);
130
+ const jsonResponse = await getJsonOfText(responseText);
105
131
  if (Array.isArray(jsonResponse)) {
106
132
  agentIds = jsonResponse.filter((id: string) => id !== this.id);
107
133
  }