@theia/ai-chat 1.59.0-next.62 → 1.59.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.
- package/lib/browser/ai-chat-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-chat-frontend-module.js +6 -0
- package/lib/browser/ai-chat-frontend-module.js.map +1 -1
- package/lib/browser/change-set-file-element.d.ts +7 -0
- package/lib/browser/change-set-file-element.d.ts.map +1 -1
- package/lib/browser/change-set-file-element.js +3 -0
- package/lib/browser/change-set-file-element.js.map +1 -1
- package/lib/browser/change-set-variable.d.ts +11 -0
- package/lib/browser/change-set-variable.d.ts.map +1 -0
- package/lib/browser/change-set-variable.js +56 -0
- package/lib/browser/change-set-variable.js.map +1 -0
- package/lib/common/chat-agents.d.ts +10 -3
- package/lib/common/chat-agents.d.ts.map +1 -1
- package/lib/common/chat-agents.js +11 -4
- package/lib/common/chat-agents.js.map +1 -1
- package/lib/common/chat-model.d.ts +28 -3
- package/lib/common/chat-model.d.ts.map +1 -1
- package/lib/common/chat-model.js +50 -2
- package/lib/common/chat-model.js.map +1 -1
- package/lib/common/chat-service.d.ts +4 -7
- package/lib/common/chat-service.d.ts.map +1 -1
- package/lib/common/chat-service.js +10 -8
- package/lib/common/chat-service.js.map +1 -1
- package/lib/common/chat-string-utils.d.ts +3 -0
- package/lib/common/chat-string-utils.d.ts.map +1 -0
- package/lib/common/chat-string-utils.js +27 -0
- package/lib/common/chat-string-utils.js.map +1 -0
- package/lib/common/context-details-variable.d.ts +9 -0
- package/lib/common/context-details-variable.d.ts.map +1 -0
- package/lib/common/context-details-variable.js +57 -0
- package/lib/common/context-details-variable.js.map +1 -0
- package/lib/common/context-summary-variable.d.ts +9 -0
- package/lib/common/context-summary-variable.d.ts.map +1 -0
- package/lib/common/context-summary-variable.js +57 -0
- package/lib/common/context-summary-variable.js.map +1 -0
- package/lib/common/context-variables.d.ts +4 -0
- package/lib/common/context-variables.d.ts.map +1 -0
- package/lib/common/context-variables.js +22 -0
- package/lib/common/context-variables.js.map +1 -0
- package/lib/common/custom-chat-agent.d.ts +0 -1
- package/lib/common/custom-chat-agent.d.ts.map +1 -1
- package/lib/common/custom-chat-agent.js +2 -1
- package/lib/common/custom-chat-agent.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/package.json +11 -11
- package/src/browser/ai-chat-frontend-module.ts +6 -0
- package/src/browser/change-set-file-element.ts +10 -0
- package/src/browser/change-set-variable.ts +54 -0
- package/src/common/chat-agents.ts +17 -5
- package/src/common/chat-model.ts +73 -3
- package/src/common/chat-service.ts +12 -17
- package/src/common/chat-string-utils.ts +23 -0
- package/src/common/context-details-variable.ts +53 -0
- package/src/common/context-summary-variable.ts +53 -0
- package/src/common/context-variables.ts +19 -0
- package/src/common/custom-chat-agent.ts +2 -1
- package/src/common/index.ts +1 -0
|
@@ -42,6 +42,9 @@ import { ChangeSetFileService } from './change-set-file-service';
|
|
|
42
42
|
import { ContextVariableLabelProvider } from './context-variable-label-provider';
|
|
43
43
|
import { ContextFileVariableLabelProvider } from './context-file-variable-label-provider';
|
|
44
44
|
import { FileChatVariableContribution } from './file-chat-variable-contribution';
|
|
45
|
+
import { ContextSummaryVariableContribution } from '../common/context-summary-variable';
|
|
46
|
+
import { ContextDetailsVariableContribution } from '../common/context-details-variable';
|
|
47
|
+
import { ChangeSetVariableContribution } from './change-set-variable';
|
|
45
48
|
|
|
46
49
|
export default new ContainerModule(bind => {
|
|
47
50
|
bindContributionProvider(bind, Agent);
|
|
@@ -102,4 +105,7 @@ export default new ContainerModule(bind => {
|
|
|
102
105
|
bind(ResourceResolver).toService(ChangeSetFileResourceResolver);
|
|
103
106
|
bind(ToolCallChatResponseContentFactory).toSelf().inSingletonScope();
|
|
104
107
|
bind(AIVariableContribution).to(FileChatVariableContribution).inSingletonScope();
|
|
108
|
+
bind(AIVariableContribution).to(ContextSummaryVariableContribution).inSingletonScope();
|
|
109
|
+
bind(AIVariableContribution).to(ContextDetailsVariableContribution).inSingletonScope();
|
|
110
|
+
bind(AIVariableContribution).to(ChangeSetVariableContribution).inSingletonScope();
|
|
105
111
|
});
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { DisposableCollection, Emitter, URI } from '@theia/core';
|
|
18
18
|
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
|
|
19
|
+
import { Replacement } from '@theia/core/lib/common/content-replacer';
|
|
19
20
|
import { ChangeSetElement, ChangeSetImpl } from '../common';
|
|
20
21
|
import { ChangeSetFileResourceResolver, createChangeSetFileUri, UpdatableReferenceResource } from './change-set-file-resource';
|
|
21
22
|
import { ChangeSetFileService } from './change-set-file-service';
|
|
@@ -39,6 +40,11 @@ export interface ChangeSetElementArgs extends Partial<ChangeSetElement> {
|
|
|
39
40
|
* If `undefined`, there is no change.
|
|
40
41
|
*/
|
|
41
42
|
targetState?: string;
|
|
43
|
+
/**
|
|
44
|
+
* An array of replacements used to create the new content for the targetState.
|
|
45
|
+
* This is only available if the agent was able to provide replacements and we were able to apply them.
|
|
46
|
+
*/
|
|
47
|
+
replacements?: Replacement[];
|
|
42
48
|
};
|
|
43
49
|
|
|
44
50
|
@injectable()
|
|
@@ -149,6 +155,10 @@ export class ChangeSetFileElement implements ChangeSetElement {
|
|
|
149
155
|
}
|
|
150
156
|
}
|
|
151
157
|
|
|
158
|
+
get replacements(): Replacement[] | undefined {
|
|
159
|
+
return this.elementProps.replacements;
|
|
160
|
+
}
|
|
161
|
+
|
|
152
162
|
get type(): 'add' | 'modify' | 'delete' | undefined {
|
|
153
163
|
return this.elementProps.type;
|
|
154
164
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 EclipseSource GmbH and others.
|
|
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 { MaybePromise, nls } from '@theia/core';
|
|
18
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
19
|
+
import { AIVariable, ResolvedAIVariable, AIVariableContribution, AIVariableResolver, AIVariableService, AIVariableResolutionRequest, AIVariableContext } from '@theia/ai-core';
|
|
20
|
+
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
|
21
|
+
import { ChatSessionContext } from '../common';
|
|
22
|
+
|
|
23
|
+
export const CHANGE_SET_SUMMARY_VARIABLE: AIVariable = {
|
|
24
|
+
id: 'changeSetSummary',
|
|
25
|
+
description: nls.localize('theia/ai/core/changeSetSummaryVariable/description', 'Provides a summary of the files in a change set and their contents.'),
|
|
26
|
+
|
|
27
|
+
name: 'changeSetSummary',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
@injectable()
|
|
31
|
+
export class ChangeSetVariableContribution implements AIVariableContribution, AIVariableResolver {
|
|
32
|
+
@inject(WorkspaceService)
|
|
33
|
+
protected readonly workspaceService: WorkspaceService;
|
|
34
|
+
|
|
35
|
+
registerVariables(service: AIVariableService): void {
|
|
36
|
+
service.registerResolver(CHANGE_SET_SUMMARY_VARIABLE, this);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
canResolve(request: AIVariableResolutionRequest, context: AIVariableContext): MaybePromise<number> {
|
|
40
|
+
return request.variable.name === CHANGE_SET_SUMMARY_VARIABLE.name ? 50 : 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async resolve(request: AIVariableResolutionRequest, context: AIVariableContext): Promise<ResolvedAIVariable | undefined> {
|
|
44
|
+
if (!ChatSessionContext.is(context) || request.variable.name !== CHANGE_SET_SUMMARY_VARIABLE.name || !context.model.changeSet?.getElements().length) { return undefined; }
|
|
45
|
+
const entries = await Promise.all(
|
|
46
|
+
context.model.changeSet.getElements().map(async element => `- file: ${await this.workspaceService.getWorkspaceRelativePath(element.uri)}, status: ${element.state}`)
|
|
47
|
+
);
|
|
48
|
+
return {
|
|
49
|
+
variable: CHANGE_SET_SUMMARY_VARIABLE,
|
|
50
|
+
value: entries.join('\n')
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import {
|
|
23
23
|
AgentSpecificVariables,
|
|
24
|
+
AIVariableContext,
|
|
24
25
|
CommunicationRecordingService,
|
|
25
26
|
getTextOfResponse,
|
|
26
27
|
LanguageModel,
|
|
@@ -50,7 +51,8 @@ import {
|
|
|
50
51
|
ChatResponseContent,
|
|
51
52
|
ErrorChatResponseContentImpl,
|
|
52
53
|
MarkdownChatResponseContentImpl,
|
|
53
|
-
ToolCallChatResponseContentImpl
|
|
54
|
+
ToolCallChatResponseContentImpl,
|
|
55
|
+
ChatRequestModel
|
|
54
56
|
} from './chat-model';
|
|
55
57
|
import { findFirstMatch, parseContents } from './parse-contents';
|
|
56
58
|
import { DefaultResponseContentFactory, ResponseContentMatcher, ResponseContentMatcherProvider } from './response-content-matcher';
|
|
@@ -86,6 +88,17 @@ export namespace SystemMessageDescription {
|
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
|
|
91
|
+
export interface ChatSessionContext extends AIVariableContext {
|
|
92
|
+
request?: ChatRequestModel;
|
|
93
|
+
model: ChatModel;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export namespace ChatSessionContext {
|
|
97
|
+
export function is(candidate: unknown): candidate is ChatSessionContext {
|
|
98
|
+
return typeof candidate === 'object' && !!candidate && 'model' in candidate;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
89
102
|
/**
|
|
90
103
|
* The location from where an chat agent may be invoked.
|
|
91
104
|
* Based on the location, a different context may be available.
|
|
@@ -168,8 +181,7 @@ export abstract class AbstractChatAgent implements ChatAgent {
|
|
|
168
181
|
if (!languageModel) {
|
|
169
182
|
throw new Error('Couldn\'t find a matching language model. Please check your setup!');
|
|
170
183
|
}
|
|
171
|
-
|
|
172
|
-
const systemMessageDescription = await this.getSystemMessageDescription();
|
|
184
|
+
const systemMessageDescription = await this.getSystemMessageDescription({ model: request.session, request } satisfies ChatSessionContext);
|
|
173
185
|
const messages = await this.getMessages(request.session);
|
|
174
186
|
if (this.defaultLogging) {
|
|
175
187
|
this.recordingService.recordRequest(
|
|
@@ -244,11 +256,11 @@ export abstract class AbstractChatAgent implements ChatAgent {
|
|
|
244
256
|
return languageModel;
|
|
245
257
|
}
|
|
246
258
|
|
|
247
|
-
protected async getSystemMessageDescription(): Promise<SystemMessageDescription | undefined> {
|
|
259
|
+
protected async getSystemMessageDescription(context: AIVariableContext): Promise<SystemMessageDescription | undefined> {
|
|
248
260
|
if (this.systemPromptId === undefined) {
|
|
249
261
|
return undefined;
|
|
250
262
|
}
|
|
251
|
-
const resolvedPrompt = await this.promptService.getPrompt(this.systemPromptId);
|
|
263
|
+
const resolvedPrompt = await this.promptService.getPrompt(this.systemPromptId, undefined, context);
|
|
252
264
|
return resolvedPrompt ? SystemMessageDescription.fromResolvedPromptTemplate(resolvedPrompt) : undefined;
|
|
253
265
|
}
|
|
254
266
|
|
package/src/common/chat-model.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { MarkdownString, MarkdownStringImpl } from '@theia/core/lib/common/markd
|
|
|
24
24
|
import { Position } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
25
25
|
import { ChatAgentLocation } from './chat-agents';
|
|
26
26
|
import { ParsedChatRequest } from './parsed-chat-request';
|
|
27
|
-
import { ResolvedAIContextVariable } from '@theia/ai-core';
|
|
27
|
+
import { AIVariableResolutionRequest, ResolvedAIContextVariable } from '@theia/ai-core';
|
|
28
28
|
|
|
29
29
|
/**********************
|
|
30
30
|
* INTERFACES AND TYPE GUARDS
|
|
@@ -33,6 +33,8 @@ import { ResolvedAIContextVariable } from '@theia/ai-core';
|
|
|
33
33
|
export type ChatChangeEvent =
|
|
34
34
|
| ChatAddRequestEvent
|
|
35
35
|
| ChatAddResponseEvent
|
|
36
|
+
| ChatAddVariableEvent
|
|
37
|
+
| ChatRemoveVariableEvent
|
|
36
38
|
| ChatRemoveRequestEvent
|
|
37
39
|
| ChatSetChangeSetEvent
|
|
38
40
|
| ChatUpdateChangeSetEvent
|
|
@@ -64,6 +66,14 @@ export interface ChatRemoveChangeSetEvent {
|
|
|
64
66
|
changeSet: ChangeSet;
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
export interface ChatAddVariableEvent {
|
|
70
|
+
kind: 'addVariable';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ChatRemoveVariableEvent {
|
|
74
|
+
kind: 'removeVariable';
|
|
75
|
+
}
|
|
76
|
+
|
|
67
77
|
export namespace ChatChangeEvent {
|
|
68
78
|
export function isChangeSetEvent(event: ChatChangeEvent): event is ChatSetChangeSetEvent | ChatUpdateChangeSetEvent | ChatRemoveChangeSetEvent {
|
|
69
79
|
return event.kind === 'setChangeSet' || event.kind === 'removeChangeSet' || event.kind === 'updateChangeSet';
|
|
@@ -84,17 +94,26 @@ export interface ChatModel {
|
|
|
84
94
|
readonly id: string;
|
|
85
95
|
readonly location: ChatAgentLocation;
|
|
86
96
|
readonly changeSet?: ChangeSet;
|
|
97
|
+
readonly context: ChatContextManager;
|
|
87
98
|
getRequests(): ChatRequestModel[];
|
|
88
99
|
isEmpty(): boolean;
|
|
89
100
|
}
|
|
90
101
|
|
|
91
|
-
export interface ChangeSet {
|
|
102
|
+
export interface ChangeSet extends Disposable {
|
|
92
103
|
onDidChange: Event<ChangeSetChangeEvent>;
|
|
93
104
|
readonly title: string;
|
|
94
105
|
getElements(): ChangeSetElement[];
|
|
95
106
|
dispose(): void;
|
|
96
107
|
}
|
|
97
108
|
|
|
109
|
+
export interface ChatContextManager {
|
|
110
|
+
onDidChange: Event<ChatAddVariableEvent | ChatRemoveVariableEvent>;
|
|
111
|
+
getVariables(): readonly AIVariableResolutionRequest[]
|
|
112
|
+
addVariables(...variables: AIVariableResolutionRequest[]): void;
|
|
113
|
+
deleteVariables(...indices: number[]): void;
|
|
114
|
+
clear(): void;
|
|
115
|
+
}
|
|
116
|
+
|
|
98
117
|
export interface ChangeSetElement {
|
|
99
118
|
readonly uri: URI;
|
|
100
119
|
|
|
@@ -478,11 +497,13 @@ export class MutableChatModel implements ChatModel, Disposable {
|
|
|
478
497
|
protected _requests: MutableChatRequestModel[];
|
|
479
498
|
protected _id: string;
|
|
480
499
|
protected _changeSet?: ChangeSetImpl;
|
|
500
|
+
protected readonly _contextManager = new ChatContextManagerImpl();
|
|
481
501
|
|
|
482
502
|
constructor(public readonly location = ChatAgentLocation.Panel) {
|
|
483
503
|
// TODO accept serialized data as a parameter to restore a previously saved ChatModel
|
|
484
504
|
this._requests = [];
|
|
485
505
|
this._id = generateUuid();
|
|
506
|
+
this._contextManager.onDidChange(e => this._onDidChangeEmitter.fire(e));
|
|
486
507
|
}
|
|
487
508
|
|
|
488
509
|
getRequests(): MutableChatRequestModel[] {
|
|
@@ -501,6 +522,10 @@ export class MutableChatModel implements ChatModel, Disposable {
|
|
|
501
522
|
return this._changeSet;
|
|
502
523
|
}
|
|
503
524
|
|
|
525
|
+
get context(): ChatContextManager {
|
|
526
|
+
return this._contextManager;
|
|
527
|
+
}
|
|
528
|
+
|
|
504
529
|
setChangeSet(changeSet: ChangeSetImpl | undefined): void {
|
|
505
530
|
if (!changeSet) {
|
|
506
531
|
return this.removeChangeSet();
|
|
@@ -610,8 +635,53 @@ export class ChangeSetImpl implements ChangeSet {
|
|
|
610
635
|
}
|
|
611
636
|
|
|
612
637
|
dispose(): void {
|
|
613
|
-
this._elements.forEach(element => element.dispose?.());
|
|
614
638
|
this._onDidChangeEmitter.dispose();
|
|
639
|
+
this._elements.forEach(element => element.dispose?.());
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
export class ChatContextManagerImpl implements ChatContextManager {
|
|
644
|
+
protected readonly variables = new Array<AIVariableResolutionRequest>();
|
|
645
|
+
protected readonly onDidChangeEmitter = new Emitter<ChatAddVariableEvent | ChatRemoveVariableEvent>();
|
|
646
|
+
get onDidChange(): Event<ChatAddVariableEvent | ChatRemoveVariableEvent> {
|
|
647
|
+
return this.onDidChangeEmitter.event;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
getVariables(): readonly AIVariableResolutionRequest[] {
|
|
651
|
+
const result = this.variables.slice();
|
|
652
|
+
Object.freeze(result);
|
|
653
|
+
return result;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
addVariables(...variables: AIVariableResolutionRequest[]): void {
|
|
657
|
+
let modified = false;
|
|
658
|
+
variables.forEach(variable => {
|
|
659
|
+
if (this.variables.some(existing => existing.variable.id === variable.variable.id && existing.arg === variable.arg)) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
this.variables.push(variable);
|
|
663
|
+
modified = true;
|
|
664
|
+
});
|
|
665
|
+
if (modified) {
|
|
666
|
+
this.onDidChangeEmitter.fire({ kind: 'addVariable' });
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
deleteVariables(...indices: number[]): void {
|
|
671
|
+
const toDelete = indices.filter(candidate => candidate <= this.variables.length).sort((left, right) => right - left);
|
|
672
|
+
if (toDelete.length) {
|
|
673
|
+
toDelete.forEach(index => {
|
|
674
|
+
this.variables.splice(index, 1);
|
|
675
|
+
});
|
|
676
|
+
this.onDidChangeEmitter.fire({ kind: 'removeVariable' });
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
clear(): void {
|
|
681
|
+
if (this.variables.length) {
|
|
682
|
+
this.variables.length = 0;
|
|
683
|
+
this.onDidChangeEmitter.fire({ kind: 'removeVariable' });
|
|
684
|
+
}
|
|
615
685
|
}
|
|
616
686
|
}
|
|
617
687
|
|
|
@@ -24,7 +24,7 @@ import { Emitter, ILogger, generateUuid } from '@theia/core';
|
|
|
24
24
|
import { inject, injectable, optional } from '@theia/core/shared/inversify';
|
|
25
25
|
import { Event } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
26
26
|
import { ChatAgentService } from './chat-agent-service';
|
|
27
|
-
import { ChatAgent, ChatAgentLocation } from './chat-agents';
|
|
27
|
+
import { ChatAgent, ChatAgentLocation, ChatSessionContext } from './chat-agents';
|
|
28
28
|
import {
|
|
29
29
|
ChatModel,
|
|
30
30
|
MutableChatModel,
|
|
@@ -60,10 +60,6 @@ export interface ChatSession {
|
|
|
60
60
|
pinnedAgent?: ChatAgent;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export interface ChatContextRequest {
|
|
64
|
-
variableRequests: AIVariableResolutionRequest[]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
63
|
export interface ActiveSessionChangedEvent {
|
|
68
64
|
sessionId: string | undefined;
|
|
69
65
|
focus?: boolean;
|
|
@@ -104,8 +100,7 @@ export interface ChatService {
|
|
|
104
100
|
|
|
105
101
|
sendRequest(
|
|
106
102
|
sessionId: string,
|
|
107
|
-
request: ChatRequest
|
|
108
|
-
requestedContext?: ChatContextRequest
|
|
103
|
+
request: ChatRequest
|
|
109
104
|
): Promise<ChatRequestInvocation | undefined>;
|
|
110
105
|
|
|
111
106
|
deleteChangeSet(sessionId: string): void;
|
|
@@ -169,7 +164,7 @@ export class ChatServiceImpl implements ChatService {
|
|
|
169
164
|
|
|
170
165
|
deleteSession(sessionId: string): void {
|
|
171
166
|
const sessionIndex = this._sessions.findIndex(candidate => candidate.id === sessionId);
|
|
172
|
-
if (
|
|
167
|
+
if (sessionIndex === -1) { return; }
|
|
173
168
|
const session = this._sessions[sessionIndex];
|
|
174
169
|
// If the removed session is the active one, set the newest one as active
|
|
175
170
|
if (session.isActive) {
|
|
@@ -189,7 +184,6 @@ export class ChatServiceImpl implements ChatService {
|
|
|
189
184
|
async sendRequest(
|
|
190
185
|
sessionId: string,
|
|
191
186
|
request: ChatRequest,
|
|
192
|
-
requestedContext: ChatContextRequest = { variableRequests: [] }
|
|
193
187
|
): Promise<ChatRequestInvocation | undefined> {
|
|
194
188
|
const session = this.getSession(sessionId);
|
|
195
189
|
if (!session) {
|
|
@@ -211,14 +205,16 @@ export class ChatServiceImpl implements ChatService {
|
|
|
211
205
|
};
|
|
212
206
|
}
|
|
213
207
|
|
|
214
|
-
const
|
|
208
|
+
const resolutionContext: ChatSessionContext = { model: session.model };
|
|
209
|
+
const resolvedContext = await this.resolveChatContext(session.model.context.getVariables(), resolutionContext);
|
|
215
210
|
const requestModel = session.model.addRequest(parsedRequest, agent?.id, resolvedContext);
|
|
211
|
+
resolutionContext.request = requestModel;
|
|
216
212
|
|
|
217
213
|
for (const part of parsedRequest.parts) {
|
|
218
214
|
if (part instanceof ParsedChatRequestVariablePart) {
|
|
219
215
|
const resolvedVariable = await this.variableService.resolveVariable(
|
|
220
216
|
{ variable: part.variableName, arg: part.variableArg },
|
|
221
|
-
|
|
217
|
+
resolutionContext
|
|
222
218
|
);
|
|
223
219
|
if (resolvedVariable) {
|
|
224
220
|
part.resolution = resolvedVariable;
|
|
@@ -260,13 +256,12 @@ export class ChatServiceImpl implements ChatService {
|
|
|
260
256
|
}
|
|
261
257
|
|
|
262
258
|
protected async resolveChatContext(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
session: ChatSessionInternal
|
|
259
|
+
resolutionRequests: readonly AIVariableResolutionRequest[],
|
|
260
|
+
context: ChatSessionContext,
|
|
266
261
|
): Promise<ChatContext> {
|
|
267
262
|
const resolvedVariables = await Promise.all(
|
|
268
|
-
|
|
269
|
-
const resolvedVariable = await this.variableService.resolveVariable(contextVariable,
|
|
263
|
+
resolutionRequests.map(async contextVariable => {
|
|
264
|
+
const resolvedVariable = await this.variableService.resolveVariable(contextVariable, context);
|
|
270
265
|
if (ResolvedAIContextVariable.is(resolvedVariable)) {
|
|
271
266
|
return resolvedVariable;
|
|
272
267
|
}
|
|
@@ -317,7 +312,7 @@ export class ChatServiceImpl implements ChatService {
|
|
|
317
312
|
}
|
|
318
313
|
|
|
319
314
|
deleteChangeSet(sessionId: string): void {
|
|
320
|
-
this.getSession(sessionId)?.model.
|
|
315
|
+
this.getSession(sessionId)?.model.removeChangeSet();
|
|
321
316
|
}
|
|
322
317
|
|
|
323
318
|
deleteChangeSetElement(sessionId: string, index: number): void {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 EclipseSource GmbH and others.
|
|
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
|
+
export function stringJsonCodeBlock(input: string): string {
|
|
18
|
+
return `\`\`\`json\n${input}\n\`\`\``;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function dataToJsonCodeBlock(input: unknown): string {
|
|
22
|
+
return stringJsonCodeBlock(JSON.stringify(input, undefined, 2));
|
|
23
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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 { MaybePromise, nls } from '@theia/core';
|
|
18
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
19
|
+
import { AIVariable, ResolvedAIVariable, AIVariableContribution, AIVariableResolver, AIVariableService, AIVariableResolutionRequest, AIVariableContext } from '@theia/ai-core';
|
|
20
|
+
import { dataToJsonCodeBlock } from './chat-string-utils';
|
|
21
|
+
import { ChatSessionContext } from './chat-agents';
|
|
22
|
+
import { CHAT_CONTEXT_DETAILS_VARIABLE_ID } from './context-variables';
|
|
23
|
+
|
|
24
|
+
export const CONTEXT_DETAILS_VARIABLE: AIVariable = {
|
|
25
|
+
id: CHAT_CONTEXT_DETAILS_VARIABLE_ID,
|
|
26
|
+
description: nls.localize('theia/ai/core/contextDetailsVariable/description', 'Provides full text values and descriptions for all context elements.'),
|
|
27
|
+
name: CHAT_CONTEXT_DETAILS_VARIABLE_ID,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
@injectable()
|
|
31
|
+
export class ContextDetailsVariableContribution implements AIVariableContribution, AIVariableResolver {
|
|
32
|
+
registerVariables(service: AIVariableService): void {
|
|
33
|
+
service.registerResolver(CONTEXT_DETAILS_VARIABLE, this);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
canResolve(request: AIVariableResolutionRequest, context: AIVariableContext): MaybePromise<number> {
|
|
37
|
+
return request.variable.name === CONTEXT_DETAILS_VARIABLE.name ? 50 : 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async resolve(request: AIVariableResolutionRequest, context: AIVariableContext): Promise<ResolvedAIVariable | undefined> {
|
|
41
|
+
/** By expecting context.request, we're assuming that this variable will not be resolved until the context has been resolved. */
|
|
42
|
+
if (!ChatSessionContext.is(context) || request.variable.name !== CONTEXT_DETAILS_VARIABLE.name || !context.request) { return undefined; }
|
|
43
|
+
const data = context.request.context.variables.map(variable => ({
|
|
44
|
+
type: variable.variable.name,
|
|
45
|
+
ref: variable.value,
|
|
46
|
+
content: variable.contextValue
|
|
47
|
+
}));
|
|
48
|
+
return {
|
|
49
|
+
variable: CONTEXT_DETAILS_VARIABLE,
|
|
50
|
+
value: dataToJsonCodeBlock(data)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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 { MaybePromise, nls } from '@theia/core';
|
|
18
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
19
|
+
import { AIVariable, ResolvedAIVariable, AIVariableContribution, AIVariableResolver, AIVariableService, AIVariableResolutionRequest, AIVariableContext } from '@theia/ai-core';
|
|
20
|
+
import { dataToJsonCodeBlock } from './chat-string-utils';
|
|
21
|
+
import { ChatSessionContext } from './chat-agents';
|
|
22
|
+
|
|
23
|
+
export const CONTEXT_SUMMARY_VARIABLE: AIVariable = {
|
|
24
|
+
id: 'contextSummary',
|
|
25
|
+
description: nls.localize('theia/ai/core/contextSummaryVariable/description', 'Describes files in the context for a given session.'),
|
|
26
|
+
name: 'contextSummary',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
@injectable()
|
|
30
|
+
export class ContextSummaryVariableContribution implements AIVariableContribution, AIVariableResolver {
|
|
31
|
+
registerVariables(service: AIVariableService): void {
|
|
32
|
+
service.registerResolver(CONTEXT_SUMMARY_VARIABLE, this);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
canResolve(request: AIVariableResolutionRequest, context: AIVariableContext): MaybePromise<number> {
|
|
36
|
+
return request.variable.name === CONTEXT_SUMMARY_VARIABLE.name ? 50 : 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async resolve(request: AIVariableResolutionRequest, context: AIVariableContext): Promise<ResolvedAIVariable | undefined> {
|
|
40
|
+
if (!ChatSessionContext.is(context) || request.variable.name !== CONTEXT_SUMMARY_VARIABLE.name) { return undefined; }
|
|
41
|
+
const data = context.model.context.getVariables().filter(variable => variable.variable.isContextVariable)
|
|
42
|
+
.map(variable => ({
|
|
43
|
+
type: variable.variable.name,
|
|
44
|
+
// eslint-disable-next-line no-null/no-null
|
|
45
|
+
instanceData: variable.arg || null,
|
|
46
|
+
contextElementId: variable.variable.id + variable.arg
|
|
47
|
+
}));
|
|
48
|
+
return {
|
|
49
|
+
variable: CONTEXT_SUMMARY_VARIABLE,
|
|
50
|
+
value: dataToJsonCodeBlock(data)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
export const CHAT_CONTEXT_VARIABLE_ID = 'contextSummary';
|
|
18
|
+
export const CHAT_CONTEXT_DETAILS_VARIABLE_ID = 'contextDetails';
|
|
19
|
+
export const CHANGE_SET_SUMMARY_VARIABLE_ID = 'changeSetSummary';
|
|
@@ -24,9 +24,10 @@ export class CustomChatAgent extends AbstractStreamParsingChatAgent {
|
|
|
24
24
|
name: string = 'CustomChatAgent';
|
|
25
25
|
languageModelRequirements: LanguageModelRequirement[] = [{ purpose: 'chat' }];
|
|
26
26
|
protected defaultLanguageModelPurpose: string = 'chat';
|
|
27
|
-
protected override systemPromptId: string = `${this.name}_prompt`;
|
|
28
27
|
|
|
29
28
|
set prompt(prompt: string) {
|
|
29
|
+
// the name is dynamic, so we set the propmptId here
|
|
30
|
+
this.systemPromptId = `${this.name}_prompt`;
|
|
30
31
|
this.promptTemplates.push({ id: `${this.name}_prompt`, template: prompt });
|
|
31
32
|
}
|
|
32
33
|
}
|
package/src/common/index.ts
CHANGED