@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
package/src/common/chat-model.ts
CHANGED
|
@@ -19,11 +19,12 @@
|
|
|
19
19
|
*--------------------------------------------------------------------------------------------*/
|
|
20
20
|
// Partially copied from https://github.com/microsoft/vscode/blob/a2cab7255c0df424027be05d58e1b7b941f4ea60/src/vs/workbench/contrib/chat/common/chatModel.ts
|
|
21
21
|
|
|
22
|
-
import { Command, Emitter, Event, generateUuid, URI } from '@theia/core';
|
|
22
|
+
import { CancellationToken, CancellationTokenSource, Command, Disposable, Emitter, Event, generateUuid, URI } from '@theia/core';
|
|
23
23
|
import { MarkdownString, MarkdownStringImpl } from '@theia/core/lib/common/markdown-rendering';
|
|
24
24
|
import { Position } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
25
25
|
import { ChatAgentLocation } from './chat-agents';
|
|
26
|
-
import { ParsedChatRequest } from './parsed-chat-request';
|
|
26
|
+
import { ParsedChatRequest, ParsedChatRequestVariablePart } from './parsed-chat-request';
|
|
27
|
+
import { ResolvedAIVariable } from '@theia/ai-core';
|
|
27
28
|
|
|
28
29
|
/**********************
|
|
29
30
|
* INTERFACES AND TYPE GUARDS
|
|
@@ -32,7 +33,11 @@ import { ParsedChatRequest } from './parsed-chat-request';
|
|
|
32
33
|
export type ChatChangeEvent =
|
|
33
34
|
| ChatAddRequestEvent
|
|
34
35
|
| ChatAddResponseEvent
|
|
35
|
-
| ChatRemoveRequestEvent
|
|
36
|
+
| ChatRemoveRequestEvent
|
|
37
|
+
| ChatSetChangeSetEvent
|
|
38
|
+
| ChatSetChangeDeleteEvent
|
|
39
|
+
| ChatUpdateChangeSetEvent
|
|
40
|
+
| ChatRemoveChangeSetEvent;
|
|
36
41
|
|
|
37
42
|
export interface ChatAddRequestEvent {
|
|
38
43
|
kind: 'addRequest';
|
|
@@ -44,6 +49,31 @@ export interface ChatAddResponseEvent {
|
|
|
44
49
|
response: ChatResponseModel;
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
export interface ChatSetChangeSetEvent {
|
|
53
|
+
kind: 'setChangeSet';
|
|
54
|
+
changeSet: ChangeSet;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ChatSetChangeDeleteEvent {
|
|
58
|
+
kind: 'deleteChangeSet';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface ChatUpdateChangeSetEvent {
|
|
62
|
+
kind: 'updateChangeSet';
|
|
63
|
+
changeSet: ChangeSet;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ChatRemoveChangeSetEvent {
|
|
67
|
+
kind: 'removeChangeSet';
|
|
68
|
+
changeSet: ChangeSet;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export namespace ChatChangeEvent {
|
|
72
|
+
export function isChangeSetEvent(event: ChatChangeEvent): event is ChatSetChangeSetEvent | ChatUpdateChangeSetEvent | ChatRemoveChangeSetEvent {
|
|
73
|
+
return event.kind === 'setChangeSet' || event.kind === 'deleteChangeSet' || event.kind === 'removeChangeSet' || event.kind === 'updateChangeSet';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
47
77
|
export type ChatRequestRemovalReason = 'removal' | 'resend' | 'adoption';
|
|
48
78
|
|
|
49
79
|
export interface ChatRemoveRequestEvent {
|
|
@@ -57,10 +87,33 @@ export interface ChatModel {
|
|
|
57
87
|
readonly onDidChange: Event<ChatChangeEvent>;
|
|
58
88
|
readonly id: string;
|
|
59
89
|
readonly location: ChatAgentLocation;
|
|
90
|
+
readonly changeSet?: ChangeSet;
|
|
60
91
|
getRequests(): ChatRequestModel[];
|
|
61
92
|
isEmpty(): boolean;
|
|
62
93
|
}
|
|
63
94
|
|
|
95
|
+
export interface ChangeSet {
|
|
96
|
+
readonly title: string;
|
|
97
|
+
getElements(): ChangeSetElement[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface ChangeSetElement {
|
|
101
|
+
readonly uri: URI;
|
|
102
|
+
|
|
103
|
+
readonly name?: string;
|
|
104
|
+
readonly icon?: string;
|
|
105
|
+
readonly additionalInfo?: string;
|
|
106
|
+
|
|
107
|
+
readonly state?: 'pending' | 'applied' | 'discarded';
|
|
108
|
+
readonly type?: 'add' | 'modify' | 'delete';
|
|
109
|
+
readonly data?: { [key: string]: unknown };
|
|
110
|
+
|
|
111
|
+
open?(): Promise<void>;
|
|
112
|
+
openChange?(): Promise<void>;
|
|
113
|
+
accept?(): Promise<void>;
|
|
114
|
+
discard?(): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
|
|
64
117
|
export interface ChatRequest {
|
|
65
118
|
readonly text: string;
|
|
66
119
|
readonly displayText?: string;
|
|
@@ -76,10 +129,37 @@ export interface ChatRequestModel {
|
|
|
76
129
|
readonly data?: { [key: string]: unknown };
|
|
77
130
|
}
|
|
78
131
|
|
|
132
|
+
export namespace ChatRequestModel {
|
|
133
|
+
export function is(request: unknown): request is ChatRequestModel {
|
|
134
|
+
return !!(
|
|
135
|
+
request &&
|
|
136
|
+
typeof request === 'object' &&
|
|
137
|
+
'id' in request &&
|
|
138
|
+
typeof (request as { id: unknown }).id === 'string' &&
|
|
139
|
+
'session' in request &&
|
|
140
|
+
'request' in request &&
|
|
141
|
+
'response' in request &&
|
|
142
|
+
'message' in request
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
export function isInProgress(request: ChatRequestModel | undefined): boolean {
|
|
146
|
+
if (!request) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
const response = request.response;
|
|
150
|
+
return !(
|
|
151
|
+
response.isComplete ||
|
|
152
|
+
response.isCanceled ||
|
|
153
|
+
response.isError
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
79
158
|
export interface ChatProgressMessage {
|
|
80
159
|
kind: 'progressMessage';
|
|
81
160
|
id: string;
|
|
82
161
|
status: 'inProgress' | 'completed' | 'failed';
|
|
162
|
+
show: 'untilFirstContent' | 'whileIncomplete' | 'forever';
|
|
83
163
|
content: string;
|
|
84
164
|
}
|
|
85
165
|
|
|
@@ -279,22 +359,100 @@ export namespace ErrorChatResponseContent {
|
|
|
279
359
|
}
|
|
280
360
|
}
|
|
281
361
|
|
|
362
|
+
export type QuestionResponseHandler = (
|
|
363
|
+
selectedOption: { text: string, value?: string },
|
|
364
|
+
) => void;
|
|
365
|
+
|
|
366
|
+
export interface QuestionResponseContent extends ChatResponseContent {
|
|
367
|
+
kind: 'question';
|
|
368
|
+
question: string;
|
|
369
|
+
options: { text: string, value?: string }[];
|
|
370
|
+
selectedOption?: { text: string, value?: string };
|
|
371
|
+
handler: QuestionResponseHandler;
|
|
372
|
+
request: ChatRequestModelImpl;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export namespace QuestionResponseContent {
|
|
376
|
+
export function is(obj: unknown): obj is QuestionResponseContent {
|
|
377
|
+
return (
|
|
378
|
+
ChatResponseContent.is(obj) &&
|
|
379
|
+
obj.kind === 'question' &&
|
|
380
|
+
'question' in obj &&
|
|
381
|
+
typeof (obj as { question: unknown }).question === 'string' &&
|
|
382
|
+
'options' in obj &&
|
|
383
|
+
Array.isArray((obj as { options: unknown }).options) &&
|
|
384
|
+
(obj as { options: unknown[] }).options.every(option =>
|
|
385
|
+
typeof option === 'object' &&
|
|
386
|
+
option && 'text' in option &&
|
|
387
|
+
typeof (option as { text: unknown }).text === 'string' &&
|
|
388
|
+
('value' in option ? typeof (option as { value: unknown }).value === 'string' || typeof (option as { value: unknown }).value === 'undefined' : true)
|
|
389
|
+
) &&
|
|
390
|
+
'handler' in obj &&
|
|
391
|
+
typeof (obj as { handler: unknown }).handler === 'function' &&
|
|
392
|
+
'request' in obj &&
|
|
393
|
+
obj.request instanceof ChatRequestModelImpl
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
282
398
|
export interface ChatResponse {
|
|
283
399
|
readonly content: ChatResponseContent[];
|
|
284
400
|
asString(): string;
|
|
285
401
|
}
|
|
286
402
|
|
|
403
|
+
/**
|
|
404
|
+
* The ChatResponseModel wraps the actual ChatResponse with additional information like the current state, progress messages, a unique id etc.
|
|
405
|
+
*/
|
|
287
406
|
export interface ChatResponseModel {
|
|
407
|
+
/**
|
|
408
|
+
* Use this to be notified for any change in the response model
|
|
409
|
+
*/
|
|
288
410
|
readonly onDidChange: Event<void>;
|
|
411
|
+
/**
|
|
412
|
+
* The unique identifier of the response model
|
|
413
|
+
*/
|
|
289
414
|
readonly id: string;
|
|
415
|
+
/**
|
|
416
|
+
* The unique identifier of the request model this response is associated with
|
|
417
|
+
*/
|
|
290
418
|
readonly requestId: string;
|
|
419
|
+
/**
|
|
420
|
+
* In case there are progress messages, then they will be stored here
|
|
421
|
+
*/
|
|
291
422
|
readonly progressMessages: ChatProgressMessage[];
|
|
423
|
+
/**
|
|
424
|
+
* The actual response content
|
|
425
|
+
*/
|
|
292
426
|
readonly response: ChatResponse;
|
|
427
|
+
/**
|
|
428
|
+
* Indicates whether this response is complete. No further changes are expected if 'true'.
|
|
429
|
+
*/
|
|
293
430
|
readonly isComplete: boolean;
|
|
431
|
+
/**
|
|
432
|
+
* Indicates whether this response is canceled. No further changes are expected if 'true'.
|
|
433
|
+
*/
|
|
294
434
|
readonly isCanceled: boolean;
|
|
435
|
+
/**
|
|
436
|
+
* Some agents might need to wait for user input to continue. This flag indicates that.
|
|
437
|
+
*/
|
|
438
|
+
readonly isWaitingForInput: boolean;
|
|
439
|
+
/**
|
|
440
|
+
* Indicates whether an error occurred when processing the response. No further changes are expected if 'true'.
|
|
441
|
+
*/
|
|
295
442
|
readonly isError: boolean;
|
|
443
|
+
/**
|
|
444
|
+
* The agent who produced the response content, if there is one.
|
|
445
|
+
*/
|
|
296
446
|
readonly agentId?: string
|
|
447
|
+
/**
|
|
448
|
+
* An optional error object that caused the response to be in an error state.
|
|
449
|
+
*/
|
|
297
450
|
readonly errorObject?: Error;
|
|
451
|
+
/**
|
|
452
|
+
* Some functionality might want to store some data associated with the response.
|
|
453
|
+
* This can be used to store and retrieve such data.
|
|
454
|
+
*/
|
|
455
|
+
readonly data: { [key: string]: unknown };
|
|
298
456
|
}
|
|
299
457
|
|
|
300
458
|
/**********************
|
|
@@ -307,6 +465,8 @@ export class ChatModelImpl implements ChatModel {
|
|
|
307
465
|
|
|
308
466
|
protected _requests: ChatRequestModelImpl[];
|
|
309
467
|
protected _id: string;
|
|
468
|
+
protected _changeSetListener?: Disposable;
|
|
469
|
+
protected _changeSet?: ChangeSetImpl;
|
|
310
470
|
|
|
311
471
|
constructor(public readonly location = ChatAgentLocation.Panel) {
|
|
312
472
|
// TODO accept serialized data as a parameter to restore a previously saved ChatModel
|
|
@@ -318,12 +478,52 @@ export class ChatModelImpl implements ChatModel {
|
|
|
318
478
|
return this._requests;
|
|
319
479
|
}
|
|
320
480
|
|
|
481
|
+
getRequest(id: string): ChatRequestModelImpl | undefined {
|
|
482
|
+
return this._requests.find(request => request.id === id);
|
|
483
|
+
}
|
|
484
|
+
|
|
321
485
|
get id(): string {
|
|
322
486
|
return this._id;
|
|
323
487
|
}
|
|
324
488
|
|
|
325
|
-
|
|
326
|
-
|
|
489
|
+
get changeSet(): ChangeSetImpl | undefined {
|
|
490
|
+
return this._changeSet;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
setChangeSet(changeSet: ChangeSetImpl | undefined): void {
|
|
494
|
+
this._changeSet = changeSet;
|
|
495
|
+
if (this._changeSet === undefined) {
|
|
496
|
+
this._changeSetListener?.dispose();
|
|
497
|
+
this._onDidChangeEmitter.fire({
|
|
498
|
+
kind: 'deleteChangeSet',
|
|
499
|
+
});
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
this._onDidChangeEmitter.fire({
|
|
503
|
+
kind: 'setChangeSet',
|
|
504
|
+
changeSet: this._changeSet,
|
|
505
|
+
});
|
|
506
|
+
this._changeSetListener = this._changeSet.onDidChange(() => {
|
|
507
|
+
this._onDidChangeEmitter.fire({
|
|
508
|
+
kind: 'updateChangeSet',
|
|
509
|
+
changeSet: this._changeSet!,
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
removeChangeSet(): void {
|
|
515
|
+
if (this._changeSet) {
|
|
516
|
+
const oldChangeSet = this._changeSet;
|
|
517
|
+
this._changeSet = undefined;
|
|
518
|
+
this._onDidChangeEmitter.fire({
|
|
519
|
+
kind: 'removeChangeSet',
|
|
520
|
+
changeSet: oldChangeSet,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
addRequest(parsedChatRequest: ParsedChatRequest, agentId?: string, context: ResolvedAIVariable[] = []): ChatRequestModelImpl {
|
|
526
|
+
const requestModel = new ChatRequestModelImpl(this, parsedChatRequest, agentId, context);
|
|
327
527
|
this._requests.push(requestModel);
|
|
328
528
|
this._onDidChangeEmitter.fire({
|
|
329
529
|
kind: 'addRequest',
|
|
@@ -337,21 +537,72 @@ export class ChatModelImpl implements ChatModel {
|
|
|
337
537
|
}
|
|
338
538
|
}
|
|
339
539
|
|
|
540
|
+
export class ChangeSetImpl implements ChangeSet {
|
|
541
|
+
protected readonly _onDidChangeEmitter = new Emitter<void>();
|
|
542
|
+
onDidChange: Event<void> = this._onDidChangeEmitter.event;
|
|
543
|
+
|
|
544
|
+
protected _elements: ChangeSetElement[] = [];
|
|
545
|
+
|
|
546
|
+
constructor(public readonly title: string, elements: ChangeSetElement[] = []) {
|
|
547
|
+
this.addElements(elements);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
getElements(): ChangeSetElement[] {
|
|
551
|
+
return this._elements;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
addElement(element: ChangeSetElement): void {
|
|
555
|
+
this.addElements([element]);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
addElements(elements: ChangeSetElement[]): void {
|
|
559
|
+
this._elements.push(...elements);
|
|
560
|
+
this.notifyChange();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
replaceElement(element: ChangeSetElement): boolean {
|
|
564
|
+
const index = this._elements.findIndex(e => e.uri.toString() === element.uri.toString());
|
|
565
|
+
if (index < 0) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
this._elements[index] = element;
|
|
569
|
+
this.notifyChange();
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
addOrReplaceElement(element: ChangeSetElement): void {
|
|
574
|
+
if (!this.replaceElement(element)) {
|
|
575
|
+
this.addElement(element);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
removeElement(index: number): void {
|
|
580
|
+
this._elements.splice(index, 1);
|
|
581
|
+
this.notifyChange();
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
notifyChange(): void {
|
|
585
|
+
this._onDidChangeEmitter.fire();
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
340
589
|
export class ChatRequestModelImpl implements ChatRequestModel {
|
|
341
590
|
protected readonly _id: string;
|
|
342
|
-
protected _session:
|
|
591
|
+
protected _session: ChatModelImpl;
|
|
343
592
|
protected _request: ChatRequest;
|
|
344
593
|
protected _response: ChatResponseModelImpl;
|
|
594
|
+
protected _context: ResolvedAIVariable[];
|
|
345
595
|
protected _agentId?: string;
|
|
346
596
|
protected _data: { [key: string]: unknown };
|
|
347
597
|
|
|
348
|
-
constructor(session:
|
|
349
|
-
data: { [key: string]: unknown } = {}) {
|
|
598
|
+
constructor(session: ChatModelImpl, public readonly message: ParsedChatRequest, agentId?: string,
|
|
599
|
+
context: ResolvedAIVariable[] = [], data: { [key: string]: unknown } = {}) {
|
|
350
600
|
// TODO accept serialized data as a parameter to restore a previously saved ChatRequestModel
|
|
351
601
|
this._request = message.request;
|
|
352
602
|
this._id = generateUuid();
|
|
353
603
|
this._session = session;
|
|
354
604
|
this._response = new ChatResponseModelImpl(this._id, agentId);
|
|
605
|
+
this._context = context.concat(message.parts.filter(part => part.kind === 'var').map(part => (part as ParsedChatRequestVariablePart).resolution));
|
|
355
606
|
this._agentId = agentId;
|
|
356
607
|
this._data = data;
|
|
357
608
|
}
|
|
@@ -372,7 +623,7 @@ export class ChatRequestModelImpl implements ChatRequestModel {
|
|
|
372
623
|
return this._id;
|
|
373
624
|
}
|
|
374
625
|
|
|
375
|
-
get session():
|
|
626
|
+
get session(): ChatModelImpl {
|
|
376
627
|
return this._session;
|
|
377
628
|
}
|
|
378
629
|
|
|
@@ -387,6 +638,10 @@ export class ChatRequestModelImpl implements ChatRequestModel {
|
|
|
387
638
|
get agentId(): string | undefined {
|
|
388
639
|
return this._agentId;
|
|
389
640
|
}
|
|
641
|
+
|
|
642
|
+
cancel(): void {
|
|
643
|
+
this.response.cancel();
|
|
644
|
+
}
|
|
390
645
|
}
|
|
391
646
|
|
|
392
647
|
export class ErrorChatResponseContentImpl implements ErrorChatResponseContent {
|
|
@@ -602,6 +857,31 @@ export class HorizontalLayoutChatResponseContentImpl implements HorizontalLayout
|
|
|
602
857
|
}
|
|
603
858
|
}
|
|
604
859
|
|
|
860
|
+
/**
|
|
861
|
+
* Default implementation for the QuestionResponseContent.
|
|
862
|
+
*/
|
|
863
|
+
export class QuestionResponseContentImpl implements QuestionResponseContent {
|
|
864
|
+
readonly kind = 'question';
|
|
865
|
+
protected _selectedOption: { text: string; value?: string } | undefined;
|
|
866
|
+
constructor(public question: string, public options: { text: string, value?: string }[],
|
|
867
|
+
public request: ChatRequestModelImpl, public handler: QuestionResponseHandler) {
|
|
868
|
+
}
|
|
869
|
+
set selectedOption(option: { text: string; value?: string; } | undefined) {
|
|
870
|
+
this._selectedOption = option;
|
|
871
|
+
this.request.response.response.responseContentChanged();
|
|
872
|
+
}
|
|
873
|
+
get selectedOption(): { text: string; value?: string; } | undefined {
|
|
874
|
+
return this._selectedOption;
|
|
875
|
+
}
|
|
876
|
+
asString?(): string | undefined {
|
|
877
|
+
return `Question: ${this.question}
|
|
878
|
+
${this.selectedOption ? `Answer: ${this.selectedOption?.text}` : 'No answer'}`;
|
|
879
|
+
}
|
|
880
|
+
merge?(): boolean {
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
605
885
|
class ChatResponseImpl implements ChatResponse {
|
|
606
886
|
protected readonly _onDidChangeEmitter = new Emitter<void>();
|
|
607
887
|
onDidChange: Event<void> = this._onDidChangeEmitter.event;
|
|
@@ -654,6 +934,11 @@ class ChatResponseImpl implements ChatResponse {
|
|
|
654
934
|
this._updateResponseRepresentation();
|
|
655
935
|
}
|
|
656
936
|
|
|
937
|
+
responseContentChanged(): void {
|
|
938
|
+
this._updateResponseRepresentation();
|
|
939
|
+
this._onDidChangeEmitter.fire();
|
|
940
|
+
}
|
|
941
|
+
|
|
657
942
|
protected _updateResponseRepresentation(): void {
|
|
658
943
|
this._responseRepresentation = this._content
|
|
659
944
|
.map(responseContent => {
|
|
@@ -682,15 +967,18 @@ class ChatResponseModelImpl implements ChatResponseModel {
|
|
|
682
967
|
protected readonly _onDidChangeEmitter = new Emitter<void>();
|
|
683
968
|
onDidChange: Event<void> = this._onDidChangeEmitter.event;
|
|
684
969
|
|
|
970
|
+
data = {};
|
|
971
|
+
|
|
685
972
|
protected _id: string;
|
|
686
973
|
protected _requestId: string;
|
|
687
974
|
protected _progressMessages: ChatProgressMessage[];
|
|
688
975
|
protected _response: ChatResponseImpl;
|
|
689
976
|
protected _isComplete: boolean;
|
|
690
|
-
protected
|
|
977
|
+
protected _isWaitingForInput: boolean;
|
|
691
978
|
protected _agentId?: string;
|
|
692
979
|
protected _isError: boolean;
|
|
693
980
|
protected _errorObject: Error | undefined;
|
|
981
|
+
protected _cancellationToken: CancellationTokenSource;
|
|
694
982
|
|
|
695
983
|
constructor(requestId: string, agentId?: string) {
|
|
696
984
|
// TODO accept serialized data as a parameter to restore a previously saved ChatResponseModel
|
|
@@ -701,8 +989,9 @@ class ChatResponseModelImpl implements ChatResponseModel {
|
|
|
701
989
|
response.onDidChange(() => this._onDidChangeEmitter.fire());
|
|
702
990
|
this._response = response;
|
|
703
991
|
this._isComplete = false;
|
|
704
|
-
this.
|
|
992
|
+
this._isWaitingForInput = false;
|
|
705
993
|
this._agentId = agentId;
|
|
994
|
+
this._cancellationToken = new CancellationTokenSource();
|
|
706
995
|
}
|
|
707
996
|
|
|
708
997
|
get id(): string {
|
|
@@ -728,6 +1017,7 @@ class ChatResponseModelImpl implements ChatResponseModel {
|
|
|
728
1017
|
kind: 'progressMessage',
|
|
729
1018
|
id,
|
|
730
1019
|
status: message.status ?? 'inProgress',
|
|
1020
|
+
show: message.show ?? 'untilFirstContent',
|
|
731
1021
|
...message,
|
|
732
1022
|
};
|
|
733
1023
|
this._progressMessages.push(newMessage);
|
|
@@ -756,7 +1046,11 @@ class ChatResponseModelImpl implements ChatResponseModel {
|
|
|
756
1046
|
}
|
|
757
1047
|
|
|
758
1048
|
get isCanceled(): boolean {
|
|
759
|
-
return this.
|
|
1049
|
+
return this._cancellationToken.token.isCancellationRequested;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
get isWaitingForInput(): boolean {
|
|
1053
|
+
return this._isWaitingForInput;
|
|
760
1054
|
}
|
|
761
1055
|
|
|
762
1056
|
get agentId(): string | undefined {
|
|
@@ -769,17 +1063,34 @@ class ChatResponseModelImpl implements ChatResponseModel {
|
|
|
769
1063
|
|
|
770
1064
|
complete(): void {
|
|
771
1065
|
this._isComplete = true;
|
|
1066
|
+
this._isWaitingForInput = false;
|
|
772
1067
|
this._onDidChangeEmitter.fire();
|
|
773
1068
|
}
|
|
774
1069
|
|
|
775
1070
|
cancel(): void {
|
|
1071
|
+
this._cancellationToken.cancel();
|
|
776
1072
|
this._isComplete = true;
|
|
777
|
-
this.
|
|
1073
|
+
this._isWaitingForInput = false;
|
|
1074
|
+
this._onDidChangeEmitter.fire();
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
get cancellationToken(): CancellationToken {
|
|
1078
|
+
return this._cancellationToken.token;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
waitForInput(): void {
|
|
1082
|
+
this._isWaitingForInput = true;
|
|
778
1083
|
this._onDidChangeEmitter.fire();
|
|
779
1084
|
}
|
|
1085
|
+
|
|
1086
|
+
stopWaitingForInput(): void {
|
|
1087
|
+
this._isWaitingForInput = false;
|
|
1088
|
+
this._onDidChangeEmitter.fire();
|
|
1089
|
+
}
|
|
1090
|
+
|
|
780
1091
|
error(error: Error): void {
|
|
781
1092
|
this._isComplete = true;
|
|
782
|
-
this.
|
|
1093
|
+
this._isWaitingForInput = false;
|
|
783
1094
|
this._isError = true;
|
|
784
1095
|
this._errorObject = error;
|
|
785
1096
|
this._onDidChangeEmitter.fire();
|
|
@@ -86,6 +86,11 @@ export interface ChatService {
|
|
|
86
86
|
sessionId: string,
|
|
87
87
|
request: ChatRequest
|
|
88
88
|
): Promise<ChatRequestInvocation | undefined>;
|
|
89
|
+
|
|
90
|
+
deleteChangeSet(sessionId: string): void;
|
|
91
|
+
deleteChangeSetElement(sessionId: string, index: number): void;
|
|
92
|
+
|
|
93
|
+
cancelRequest(sessionId: string, requestId: string): Promise<void>;
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
interface ChatSessionInternal extends ChatSession {
|
|
@@ -219,6 +224,10 @@ export class ChatServiceImpl implements ChatService {
|
|
|
219
224
|
return invocation;
|
|
220
225
|
}
|
|
221
226
|
|
|
227
|
+
async cancelRequest(sessionId: string, requestId: string): Promise<void> {
|
|
228
|
+
return this.getSession(sessionId)?.model.getRequest(requestId)?.response.cancel();
|
|
229
|
+
}
|
|
230
|
+
|
|
222
231
|
protected getAgent(parsedRequest: ParsedChatRequest): ChatAgent | undefined {
|
|
223
232
|
const agentPart = this.getMentionedAgent(parsedRequest);
|
|
224
233
|
if (agentPart) {
|
|
@@ -233,4 +242,12 @@ export class ChatServiceImpl implements ChatService {
|
|
|
233
242
|
protected getMentionedAgent(parsedRequest: ParsedChatRequest): ParsedChatRequestAgentPart | undefined {
|
|
234
243
|
return parsedRequest.parts.find(p => p instanceof ParsedChatRequestAgentPart) as ParsedChatRequestAgentPart | undefined;
|
|
235
244
|
}
|
|
245
|
+
|
|
246
|
+
deleteChangeSet(sessionId: string): void {
|
|
247
|
+
this.getSession(sessionId)?.model.setChangeSet(undefined);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
deleteChangeSetElement(sessionId: string, index: number): void {
|
|
251
|
+
this.getSession(sessionId)?.model.changeSet?.removeElement(index);
|
|
252
|
+
}
|
|
236
253
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
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 { ToolRequest } from '@theia/ai-core';
|
|
18
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
19
|
+
import { ChatRequestModelImpl } from './chat-model';
|
|
20
|
+
|
|
21
|
+
export interface ChatToolRequest extends ToolRequest {
|
|
22
|
+
handler: (
|
|
23
|
+
arg_string: string,
|
|
24
|
+
context: ChatRequestModelImpl,
|
|
25
|
+
) => Promise<unknown>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Wraps tool requests in a chat context.
|
|
30
|
+
*
|
|
31
|
+
* This service extracts tool requests from a given chat request model and wraps their
|
|
32
|
+
* handler functions to provide additional context, such as the chat request model.
|
|
33
|
+
*/
|
|
34
|
+
@injectable()
|
|
35
|
+
export class ChatToolRequestService {
|
|
36
|
+
|
|
37
|
+
getChatToolRequests(request: ChatRequestModelImpl): ChatToolRequest[] {
|
|
38
|
+
const toolRequests = request.message.toolRequests.size > 0 ? [...request.message.toolRequests.values()] : undefined;
|
|
39
|
+
if (!toolRequests) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
return this.toChatToolRequests(toolRequests, request);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
toChatToolRequests(toolRequests: ToolRequest[] | undefined, request: ChatRequestModelImpl): ChatToolRequest[] {
|
|
46
|
+
if (!toolRequests) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
return toolRequests.map(toolRequest => this.toChatToolRequest(toolRequest, request));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
protected toChatToolRequest(toolRequest: ToolRequest, request: ChatRequestModelImpl): ChatToolRequest {
|
|
53
|
+
return {
|
|
54
|
+
...toolRequest,
|
|
55
|
+
handler: async (arg_string: string) => toolRequest.handler(arg_string, request)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
}
|
|
@@ -36,7 +36,9 @@ import {
|
|
|
36
36
|
|
|
37
37
|
export const commandTemplate: PromptTemplate = {
|
|
38
38
|
id: 'command-system',
|
|
39
|
-
template:
|
|
39
|
+
template: `{{!-- Made improvements or adaptations to this prompt template? We’d love for you to share it with the community! Contribute back here:
|
|
40
|
+
https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}
|
|
41
|
+
# System Prompt
|
|
40
42
|
|
|
41
43
|
You are a service that helps users find commands to execute in an IDE.
|
|
42
44
|
You reply with stringified JSON Objects that tell the user which command to execute and its arguments, if any.
|
|
@@ -313,7 +315,7 @@ export class CommandChatAgent extends AbstractTextToModelParsingChatAgent<Parsed
|
|
|
313
315
|
const theiaCommand = this.commandRegistry.getCommand(parsedCommand.commandId);
|
|
314
316
|
if (theiaCommand === undefined) {
|
|
315
317
|
console.error(`No Theia Command with id ${parsedCommand.commandId}`);
|
|
316
|
-
request.
|
|
318
|
+
request.cancel();
|
|
317
319
|
}
|
|
318
320
|
const args = parsedCommand.arguments !== undefined &&
|
|
319
321
|
parsedCommand.arguments.length > 0
|
package/src/common/index.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
export * from './chat-agents';
|
|
17
17
|
export * from './chat-agent-service';
|
|
18
18
|
export * from './chat-model';
|
|
19
|
+
export * from './chat-model-util';
|
|
19
20
|
export * from './chat-request-parser';
|
|
20
21
|
export * from './chat-service';
|
|
21
22
|
export * from './command-chat-agents';
|