@theia/ai-chat 1.55.1 → 1.57.0-next.112
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.
- package/README.md +2 -1
- package/lib/browser/ai-chat-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-chat-frontend-module.js +14 -4
- package/lib/browser/ai-chat-frontend-module.js.map +1 -1
- package/lib/browser/change-set-file-element.d.ts +44 -0
- package/lib/browser/change-set-file-element.d.ts.map +1 -0
- package/lib/browser/change-set-file-element.js +113 -0
- package/lib/browser/change-set-file-element.js.map +1 -0
- package/lib/browser/change-set-file-resource.d.ts +13 -0
- package/lib/browser/change-set-file-resource.d.ts.map +1 -0
- package/lib/browser/change-set-file-resource.js +73 -0
- package/lib/browser/change-set-file-resource.js.map +1 -0
- package/lib/browser/change-set-file-service.d.ts +26 -0
- package/lib/browser/change-set-file-service.d.ts.map +1 -0
- package/lib/browser/change-set-file-service.js +139 -0
- package/lib/browser/change-set-file-service.js.map +1 -0
- package/lib/common/chat-agents.d.ts +16 -9
- package/lib/common/chat-agents.d.ts.map +1 -1
- package/lib/common/chat-agents.js +51 -67
- package/lib/common/chat-agents.js.map +1 -1
- package/lib/common/chat-history-entry.d.ts +7 -0
- package/lib/common/chat-history-entry.d.ts.map +1 -0
- package/lib/common/chat-history-entry.js +42 -0
- package/lib/common/chat-history-entry.js.map +1 -0
- package/lib/common/chat-model-util.d.ts +7 -0
- package/lib/common/chat-model-util.d.ts.map +1 -0
- package/lib/common/chat-model-util.js +50 -0
- package/lib/common/chat-model-util.js.map +1 -0
- package/lib/common/chat-model.d.ts +176 -7
- package/lib/common/chat-model.d.ts.map +1 -1
- package/lib/common/chat-model.js +193 -9
- package/lib/common/chat-model.js.map +1 -1
- package/lib/common/chat-service.d.ts +6 -0
- package/lib/common/chat-service.d.ts.map +1 -1
- package/lib/common/chat-service.js +12 -0
- package/lib/common/chat-service.js.map +1 -1
- package/lib/common/chat-tool-request-service.d.ts +17 -0
- package/lib/common/chat-tool-request-service.d.ts.map +1 -0
- package/lib/common/chat-tool-request-service.js +52 -0
- package/lib/common/chat-tool-request-service.js.map +1 -0
- package/lib/common/command-chat-agents.d.ts.map +1 -1
- package/lib/common/command-chat-agents.js +4 -2
- package/lib/common/command-chat-agents.js.map +1 -1
- package/lib/common/index.d.ts +1 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +1 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/orchestrator-chat-agent.d.ts.map +1 -1
- package/lib/common/orchestrator-chat-agent.js +16 -14
- package/lib/common/orchestrator-chat-agent.js.map +1 -1
- package/lib/common/parse-contents.d.ts +2 -2
- package/lib/common/parse-contents.d.ts.map +1 -1
- package/lib/common/parse-contents.js +4 -4
- package/lib/common/parse-contents.js.map +1 -1
- package/lib/common/parse-contents.spec.d.ts.map +1 -1
- package/lib/common/parse-contents.spec.js +14 -13
- package/lib/common/parse-contents.spec.js.map +1 -1
- package/lib/common/response-content-matcher.d.ts +3 -3
- package/lib/common/response-content-matcher.d.ts.map +1 -1
- package/lib/common/response-content-matcher.js +2 -2
- package/lib/common/response-content-matcher.js.map +1 -1
- package/lib/common/universal-chat-agent.d.ts +1 -0
- package/lib/common/universal-chat-agent.d.ts.map +1 -1
- package/lib/common/universal-chat-agent.js +10 -3
- package/lib/common/universal-chat-agent.js.map +1 -1
- package/package.json +10 -8
- package/src/browser/ai-chat-frontend-module.ts +17 -6
- package/src/browser/change-set-file-element.ts +137 -0
- package/src/browser/change-set-file-resource.ts +74 -0
- package/src/browser/change-set-file-service.ts +136 -0
- package/src/common/chat-agents.ts +56 -78
- package/src/common/chat-history-entry.ts +47 -0
- package/src/common/chat-model-util.ts +44 -0
- package/src/common/chat-model.ts +325 -14
- package/src/common/chat-service.ts +17 -0
- package/src/common/chat-tool-request-service.ts +59 -0
- package/src/common/command-chat-agents.ts +4 -2
- package/src/common/index.ts +1 -0
- package/src/common/orchestrator-chat-agent.ts +17 -14
- package/src/common/parse-contents.spec.ts +16 -14
- package/src/common/parse-contents.ts +5 -4
- package/src/common/response-content-matcher.ts +4 -3
- package/src/common/universal-chat-agent.ts +10 -2
- package/lib/common/o1-chat-agent.d.ts +0 -13
- package/lib/common/o1-chat-agent.d.ts.map +0 -1
- package/lib/common/o1-chat-agent.js +0 -45
- package/lib/common/o1-chat-agent.js.map +0 -1
- package/src/common/o1-chat-agent.ts +0 -51
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 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 { ILogger, UNTITLED_SCHEME, URI } from '@theia/core';
|
|
18
|
+
import { DiffUris, LabelProvider, OpenerService, open } from '@theia/core/lib/browser';
|
|
19
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
20
|
+
import { EditorManager } from '@theia/editor/lib/browser';
|
|
21
|
+
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
22
|
+
import { MonacoWorkspace } from '@theia/monaco/lib/browser/monaco-workspace';
|
|
23
|
+
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
|
24
|
+
import { ChangeSetFileElement } from './change-set-file-element';
|
|
25
|
+
|
|
26
|
+
@injectable()
|
|
27
|
+
export class ChangeSetFileService {
|
|
28
|
+
@inject(ILogger)
|
|
29
|
+
protected readonly logger: ILogger;
|
|
30
|
+
|
|
31
|
+
@inject(WorkspaceService)
|
|
32
|
+
protected readonly wsService: WorkspaceService;
|
|
33
|
+
|
|
34
|
+
@inject(LabelProvider)
|
|
35
|
+
protected readonly labelProvider: LabelProvider;
|
|
36
|
+
|
|
37
|
+
@inject(OpenerService)
|
|
38
|
+
protected readonly openerService: OpenerService;
|
|
39
|
+
|
|
40
|
+
@inject(EditorManager)
|
|
41
|
+
protected readonly editorManager: EditorManager;
|
|
42
|
+
|
|
43
|
+
@inject(MonacoWorkspace)
|
|
44
|
+
protected readonly monacoWorkspace: MonacoWorkspace;
|
|
45
|
+
|
|
46
|
+
@inject(FileService)
|
|
47
|
+
protected readonly fileService: FileService;
|
|
48
|
+
|
|
49
|
+
async read(uri: URI): Promise<string | undefined> {
|
|
50
|
+
const exists = await this.fileService.exists(uri);
|
|
51
|
+
if (!exists) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const document = this.monacoWorkspace.getTextDocument(uri.toString());
|
|
56
|
+
if (document) {
|
|
57
|
+
return document.getText();
|
|
58
|
+
}
|
|
59
|
+
return (await this.fileService.readFile(uri)).value.toString();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
this.logger.error('Failed to read original content of change set file element.', error);
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getName(uri: URI): string {
|
|
67
|
+
return this.labelProvider.getName(uri);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getIcon(uri: URI): string | undefined {
|
|
71
|
+
return this.labelProvider.getIcon(uri);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getAdditionalInfo(uri: URI): string | undefined {
|
|
75
|
+
const wsUri = this.wsService.getWorkspaceRootUri(uri);
|
|
76
|
+
if (wsUri) {
|
|
77
|
+
const wsRelative = wsUri.relative(uri);
|
|
78
|
+
if (wsRelative?.hasDir) {
|
|
79
|
+
return `${wsRelative.dir.toString()}`;
|
|
80
|
+
}
|
|
81
|
+
return '';
|
|
82
|
+
}
|
|
83
|
+
return this.labelProvider.getLongName(uri.parent);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async open(element: ChangeSetFileElement): Promise<void> {
|
|
87
|
+
const exists = await this.fileService.exists(element.uri);
|
|
88
|
+
if (exists) {
|
|
89
|
+
await open(this.openerService, element.uri);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
await this.editorManager.open(element.changedUri, {
|
|
93
|
+
mode: 'reveal'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async openDiff(originalUri: URI, suggestedUri: URI): Promise<void> {
|
|
98
|
+
const exists = await this.fileService.exists(originalUri);
|
|
99
|
+
const openedUri = exists ? originalUri : originalUri.withScheme(UNTITLED_SCHEME);
|
|
100
|
+
// Currently we don't have a great way to show the suggestions in a diff editor with accept/reject buttons
|
|
101
|
+
// So we just use plain diffs with the suggestions as original and the current state as modified, so users can apply changes in their current state
|
|
102
|
+
// But this leads to wrong colors and wrong label (revert change instead of accept change)
|
|
103
|
+
const diffUri = DiffUris.encode(openedUri, suggestedUri,
|
|
104
|
+
`AI Changes: ${this.labelProvider.getName(originalUri)}`,
|
|
105
|
+
);
|
|
106
|
+
open(this.openerService, diffUri);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async delete(uri: URI): Promise<void> {
|
|
110
|
+
const exists = await this.fileService.exists(uri);
|
|
111
|
+
if (exists) {
|
|
112
|
+
await this.fileService.delete(uri);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async write(uri: URI, targetState: string): Promise<void> {
|
|
117
|
+
const exists = await this.fileService.exists(uri);
|
|
118
|
+
if (!exists) {
|
|
119
|
+
await this.fileService.create(uri, targetState);
|
|
120
|
+
}
|
|
121
|
+
await this.doWrite(uri, targetState);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
protected async doWrite(uri: URI, text: string): Promise<void> {
|
|
125
|
+
const document = this.monacoWorkspace.getTextDocument(uri.toString());
|
|
126
|
+
if (document) {
|
|
127
|
+
await this.monacoWorkspace.applyBackgroundEdit(document, [{
|
|
128
|
+
range: document.textEditorModel.getFullModelRange(),
|
|
129
|
+
text
|
|
130
|
+
}], (editor, wasDirty) => editor === undefined || !wasDirty);
|
|
131
|
+
} else {
|
|
132
|
+
await this.fileService.write(uri, text);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
}
|
|
@@ -38,12 +38,11 @@ import {
|
|
|
38
38
|
LanguageModelStreamResponsePart,
|
|
39
39
|
MessageActor,
|
|
40
40
|
} from '@theia/ai-core/lib/common';
|
|
41
|
-
import { CancellationToken,
|
|
42
|
-
import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
|
|
41
|
+
import { CancellationToken, ContributionProvider, ILogger, isArray } from '@theia/core';
|
|
42
|
+
import { inject, injectable, named, postConstruct, unmanaged } from '@theia/core/shared/inversify';
|
|
43
43
|
import { ChatAgentService } from './chat-agent-service';
|
|
44
44
|
import {
|
|
45
45
|
ChatModel,
|
|
46
|
-
ChatRequestModel,
|
|
47
46
|
ChatRequestModelImpl,
|
|
48
47
|
ChatResponseContent,
|
|
49
48
|
ErrorChatResponseContentImpl,
|
|
@@ -52,6 +51,8 @@ import {
|
|
|
52
51
|
} from './chat-model';
|
|
53
52
|
import { findFirstMatch, parseContents } from './parse-contents';
|
|
54
53
|
import { DefaultResponseContentFactory, ResponseContentMatcher, ResponseContentMatcherProvider } from './response-content-matcher';
|
|
54
|
+
import { ChatHistoryEntry } from './chat-history-entry';
|
|
55
|
+
import { ChatToolRequestService } from './chat-tool-request-service';
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* A conversation consists of a sequence of ChatMessages.
|
|
@@ -122,28 +123,35 @@ export abstract class AbstractChatAgent {
|
|
|
122
123
|
@inject(LanguageModelRegistry) protected languageModelRegistry: LanguageModelRegistry;
|
|
123
124
|
@inject(ILogger) protected logger: ILogger;
|
|
124
125
|
@inject(CommunicationRecordingService) protected recordingService: CommunicationRecordingService;
|
|
126
|
+
@inject(ChatToolRequestService) protected chatToolRequestService: ChatToolRequestService;
|
|
125
127
|
@inject(PromptService) protected promptService: PromptService;
|
|
126
128
|
|
|
127
129
|
@inject(ContributionProvider) @named(ResponseContentMatcherProvider)
|
|
128
130
|
protected contentMatcherProviders: ContributionProvider<ResponseContentMatcherProvider>;
|
|
131
|
+
protected additionalToolRequests: ToolRequest[] = [];
|
|
129
132
|
protected contentMatchers: ResponseContentMatcher[] = [];
|
|
130
133
|
|
|
131
134
|
@inject(DefaultResponseContentFactory)
|
|
132
135
|
protected defaultContentFactory: DefaultResponseContentFactory;
|
|
133
136
|
|
|
134
137
|
constructor(
|
|
135
|
-
public id: string,
|
|
136
|
-
public languageModelRequirements: LanguageModelRequirement[],
|
|
137
|
-
protected defaultLanguageModelPurpose: string,
|
|
138
|
-
public iconClass: string = 'codicon codicon-copilot',
|
|
139
|
-
public locations: ChatAgentLocation[] = ChatAgentLocation.ALL,
|
|
140
|
-
public tags:
|
|
141
|
-
public defaultLogging: boolean = true) {
|
|
138
|
+
@unmanaged() public id: string,
|
|
139
|
+
@unmanaged() public languageModelRequirements: LanguageModelRequirement[],
|
|
140
|
+
@unmanaged() protected defaultLanguageModelPurpose: string,
|
|
141
|
+
@unmanaged() public iconClass: string = 'codicon codicon-copilot',
|
|
142
|
+
@unmanaged() public locations: ChatAgentLocation[] = ChatAgentLocation.ALL,
|
|
143
|
+
@unmanaged() public tags: string[] = ['Chat'],
|
|
144
|
+
@unmanaged() public defaultLogging: boolean = true) {
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
@postConstruct()
|
|
145
148
|
init(): void {
|
|
146
|
-
this.
|
|
149
|
+
this.initializeContentMatchers();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
protected initializeContentMatchers(): void {
|
|
153
|
+
const contributedContentMatchers = this.contentMatcherProviders.getContributions().flatMap(provider => provider.matchers);
|
|
154
|
+
this.contentMatchers.push(...contributedContentMatchers);
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
async invoke(request: ChatRequestModelImpl): Promise<void> {
|
|
@@ -152,20 +160,19 @@ export abstract class AbstractChatAgent {
|
|
|
152
160
|
if (!languageModel) {
|
|
153
161
|
throw new Error('Couldn\'t find a matching language model. Please check your setup!');
|
|
154
162
|
}
|
|
163
|
+
|
|
164
|
+
const systemMessageDescription = await this.getSystemMessageDescription();
|
|
155
165
|
const messages = await this.getMessages(request.session);
|
|
156
166
|
if (this.defaultLogging) {
|
|
157
|
-
this.recordingService.recordRequest(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
});
|
|
167
|
+
this.recordingService.recordRequest(
|
|
168
|
+
ChatHistoryEntry.fromRequest(
|
|
169
|
+
this.id, request, {
|
|
170
|
+
messages,
|
|
171
|
+
systemMessage: systemMessageDescription?.text
|
|
172
|
+
})
|
|
173
|
+
);
|
|
165
174
|
}
|
|
166
175
|
|
|
167
|
-
const systemMessageDescription = await this.getSystemMessageDescription();
|
|
168
|
-
const tools: Map<string, ToolRequest> = new Map();
|
|
169
176
|
if (systemMessageDescription) {
|
|
170
177
|
const systemMsg: ChatMessage = {
|
|
171
178
|
actor: 'system',
|
|
@@ -174,44 +181,35 @@ export abstract class AbstractChatAgent {
|
|
|
174
181
|
};
|
|
175
182
|
// insert system message at the beginning of the request messages
|
|
176
183
|
messages.unshift(systemMsg);
|
|
177
|
-
systemMessageDescription.functionDescriptions?.forEach((tool, id) => {
|
|
178
|
-
tools.set(id, tool);
|
|
179
|
-
});
|
|
180
184
|
}
|
|
181
|
-
this.getTools(request)?.forEach(tool => tools.set(tool.id, tool));
|
|
182
185
|
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
const systemMessageToolRequests = systemMessageDescription?.functionDescriptions?.values();
|
|
187
|
+
const tools = [
|
|
188
|
+
...this.chatToolRequestService.getChatToolRequests(request),
|
|
189
|
+
...this.chatToolRequestService.toChatToolRequests(systemMessageToolRequests ? Array.from(systemMessageToolRequests) : [], request),
|
|
190
|
+
...this.chatToolRequestService.toChatToolRequests(this.additionalToolRequests, request)
|
|
191
|
+
];
|
|
189
192
|
|
|
190
193
|
const languageModelResponse = await this.callLlm(
|
|
191
194
|
languageModel,
|
|
192
195
|
messages,
|
|
193
|
-
tools.
|
|
194
|
-
cancellationToken
|
|
196
|
+
tools.length > 0 ? tools : undefined,
|
|
197
|
+
request.response.cancellationToken
|
|
195
198
|
);
|
|
196
199
|
await this.addContentsToResponse(languageModelResponse, request);
|
|
197
|
-
|
|
200
|
+
await this.onResponseComplete(request);
|
|
198
201
|
if (this.defaultLogging) {
|
|
199
|
-
this.recordingService.recordResponse(
|
|
200
|
-
agentId: this.id,
|
|
201
|
-
sessionId: request.session.id,
|
|
202
|
-
timestamp: Date.now(),
|
|
203
|
-
requestId: request.response.requestId,
|
|
204
|
-
response: request.response.response.asString()
|
|
205
|
-
});
|
|
202
|
+
this.recordingService.recordResponse(ChatHistoryEntry.fromResponse(this.id, request));
|
|
206
203
|
}
|
|
207
204
|
} catch (e) {
|
|
208
205
|
this.handleError(request, e);
|
|
209
206
|
}
|
|
210
207
|
}
|
|
211
208
|
|
|
212
|
-
protected parseContents(text: string): ChatResponseContent[] {
|
|
209
|
+
protected parseContents(text: string, request: ChatRequestModelImpl): ChatResponseContent[] {
|
|
213
210
|
return parseContents(
|
|
214
211
|
text,
|
|
212
|
+
request,
|
|
215
213
|
this.contentMatchers,
|
|
216
214
|
this.defaultContentFactory?.create.bind(this.defaultContentFactory)
|
|
217
215
|
);
|
|
@@ -264,15 +262,6 @@ export abstract class AbstractChatAgent {
|
|
|
264
262
|
return requestMessages;
|
|
265
263
|
}
|
|
266
264
|
|
|
267
|
-
/**
|
|
268
|
-
* @returns the list of tools used by this agent, or undefined if none is needed.
|
|
269
|
-
*/
|
|
270
|
-
protected getTools(request: ChatRequestModel): ToolRequest[] | undefined {
|
|
271
|
-
return request.message.toolRequests.size > 0
|
|
272
|
-
? [...request.message.toolRequests.values()]
|
|
273
|
-
: undefined;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
265
|
protected async callLlm(
|
|
277
266
|
languageModel: LanguageModel,
|
|
278
267
|
messages: ChatMessage[],
|
|
@@ -295,6 +284,16 @@ export abstract class AbstractChatAgent {
|
|
|
295
284
|
return undefined;
|
|
296
285
|
}
|
|
297
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Invoked after the response by the LLM completed successfully.
|
|
289
|
+
*
|
|
290
|
+
* The default implementation sets the state of the response to `complete`.
|
|
291
|
+
* Subclasses may override this method to perform additional actions or keep the response open for processing further requests.
|
|
292
|
+
*/
|
|
293
|
+
protected async onResponseComplete(request: ChatRequestModelImpl): Promise<void> {
|
|
294
|
+
return request.response.complete();
|
|
295
|
+
}
|
|
296
|
+
|
|
298
297
|
protected abstract addContentsToResponse(languageModelResponse: LanguageModelResponse, request: ChatRequestModelImpl): Promise<void>;
|
|
299
298
|
}
|
|
300
299
|
|
|
@@ -318,33 +317,12 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
|
|
|
318
317
|
|
|
319
318
|
protected override async addContentsToResponse(languageModelResponse: LanguageModelResponse, request: ChatRequestModelImpl): Promise<void> {
|
|
320
319
|
if (isLanguageModelTextResponse(languageModelResponse)) {
|
|
321
|
-
const contents = this.parseContents(languageModelResponse.text);
|
|
320
|
+
const contents = this.parseContents(languageModelResponse.text, request);
|
|
322
321
|
request.response.response.addContents(contents);
|
|
323
|
-
request.response.complete();
|
|
324
|
-
if (this.defaultLogging) {
|
|
325
|
-
this.recordingService.recordResponse({
|
|
326
|
-
agentId: this.id,
|
|
327
|
-
sessionId: request.session.id,
|
|
328
|
-
timestamp: Date.now(),
|
|
329
|
-
requestId: request.response.requestId,
|
|
330
|
-
response: request.response.response.asString()
|
|
331
|
-
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
322
|
return;
|
|
335
323
|
}
|
|
336
324
|
if (isLanguageModelStreamResponse(languageModelResponse)) {
|
|
337
325
|
await this.addStreamResponse(languageModelResponse, request);
|
|
338
|
-
request.response.complete();
|
|
339
|
-
if (this.defaultLogging) {
|
|
340
|
-
this.recordingService.recordResponse({
|
|
341
|
-
agentId: this.id,
|
|
342
|
-
sessionId: request.session.id,
|
|
343
|
-
timestamp: Date.now(),
|
|
344
|
-
requestId: request.response.requestId,
|
|
345
|
-
response: request.response.response.asString()
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
326
|
return;
|
|
349
327
|
}
|
|
350
328
|
this.logger.error(
|
|
@@ -359,7 +337,7 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
|
|
|
359
337
|
|
|
360
338
|
protected async addStreamResponse(languageModelResponse: LanguageModelStreamResponse, request: ChatRequestModelImpl): Promise<void> {
|
|
361
339
|
for await (const token of languageModelResponse.stream) {
|
|
362
|
-
const newContents = this.parse(token, request
|
|
340
|
+
const newContents = this.parse(token, request);
|
|
363
341
|
if (isArray(newContents)) {
|
|
364
342
|
request.response.response.addContents(newContents);
|
|
365
343
|
} else {
|
|
@@ -375,7 +353,7 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
|
|
|
375
353
|
return;
|
|
376
354
|
}
|
|
377
355
|
|
|
378
|
-
const result: ChatResponseContent[] = findFirstMatch(this.contentMatchers, text) ? this.parseContents(text) : [];
|
|
356
|
+
const result: ChatResponseContent[] = findFirstMatch(this.contentMatchers, text) ? this.parseContents(text, request) : [];
|
|
379
357
|
if (result.length > 0) {
|
|
380
358
|
request.response.response.addContents(result);
|
|
381
359
|
} else {
|
|
@@ -384,11 +362,11 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
|
|
|
384
362
|
}
|
|
385
363
|
}
|
|
386
364
|
|
|
387
|
-
protected parse(token: LanguageModelStreamResponsePart,
|
|
365
|
+
protected parse(token: LanguageModelStreamResponsePart, request: ChatRequestModelImpl): ChatResponseContent | ChatResponseContent[] {
|
|
388
366
|
const content = token.content;
|
|
389
367
|
// eslint-disable-next-line no-null/no-null
|
|
390
368
|
if (content !== undefined && content !== null) {
|
|
391
|
-
return this.defaultContentFactory.create(content);
|
|
369
|
+
return this.defaultContentFactory.create(content, request);
|
|
392
370
|
}
|
|
393
371
|
const toolCalls = token.tool_calls;
|
|
394
372
|
if (toolCalls !== undefined) {
|
|
@@ -396,7 +374,7 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
|
|
|
396
374
|
new ToolCallChatResponseContentImpl(toolCall.id, toolCall.function?.name, toolCall.function?.arguments, toolCall.finished, toolCall.result));
|
|
397
375
|
return toolCallContents;
|
|
398
376
|
}
|
|
399
|
-
return this.defaultContentFactory.create('');
|
|
377
|
+
return this.defaultContentFactory.create('', request);
|
|
400
378
|
}
|
|
401
379
|
|
|
402
380
|
}
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
import { ChatProgressMessage, ChatRequestModel, ChatResponse, ChatResponseContent, ChatResponseModel, QuestionResponseContent } from './chat-model';
|
|
17
|
+
|
|
18
|
+
export function lastResponseContent(request: ChatRequestModel): ChatResponseContent | undefined {
|
|
19
|
+
return lastContentOfResponse(request.response?.response);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function lastContentOfResponse(response: ChatResponse | undefined): ChatResponseContent | undefined {
|
|
23
|
+
const content = response?.content;
|
|
24
|
+
return content && content.length > 0 ? content[content.length - 1] : undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function lastProgressMessage(request: ChatRequestModel): ChatProgressMessage | undefined {
|
|
28
|
+
return lastProgressMessageOfResponse(request.response);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function lastProgressMessageOfResponse(response: ChatResponseModel | undefined): ChatProgressMessage | undefined {
|
|
32
|
+
const progressMessages = response?.progressMessages;
|
|
33
|
+
return progressMessages && progressMessages.length > 0 ? progressMessages[progressMessages.length - 1] : undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function unansweredQuestions(request: ChatRequestModel): QuestionResponseContent[] {
|
|
37
|
+
const response = request.response;
|
|
38
|
+
return unansweredQuestionsOfResponse(response);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function unansweredQuestionsOfResponse(response: ChatResponseModel | undefined): QuestionResponseContent[] {
|
|
42
|
+
if (!response || !response.response) { return []; }
|
|
43
|
+
return response.response.content.filter((c): c is QuestionResponseContent => QuestionResponseContent.is(c) && c.selectedOption === undefined);
|
|
44
|
+
}
|