@theia/ai-chat 1.71.0-next.8 → 1.71.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/agent-delegation-tool.d.ts +4 -10
- package/lib/browser/agent-delegation-tool.d.ts.map +1 -1
- package/lib/browser/agent-delegation-tool.js +31 -22
- package/lib/browser/agent-delegation-tool.js.map +1 -1
- package/lib/browser/agent-delegation-tool.spec.js +3 -2
- package/lib/browser/agent-delegation-tool.spec.js.map +1 -1
- package/lib/browser/chat-tool-preference-bindings.d.ts +3 -2
- package/lib/browser/chat-tool-preference-bindings.d.ts.map +1 -1
- package/lib/browser/chat-tool-preference-bindings.js +9 -8
- package/lib/browser/chat-tool-preference-bindings.js.map +1 -1
- package/lib/browser/chat-tool-preference-bindings.spec.js +72 -21
- package/lib/browser/chat-tool-preference-bindings.spec.js.map +1 -1
- package/lib/browser/chat-tool-request-service.d.ts.map +1 -1
- package/lib/browser/chat-tool-request-service.js +3 -1
- package/lib/browser/chat-tool-request-service.js.map +1 -1
- package/lib/common/chat-agents.d.ts +5 -2
- package/lib/common/chat-agents.d.ts.map +1 -1
- package/lib/common/chat-agents.js +54 -1
- package/lib/common/chat-agents.js.map +1 -1
- package/lib/common/chat-agents.spec.d.ts +2 -0
- package/lib/common/chat-agents.spec.d.ts.map +1 -0
- package/lib/common/chat-agents.spec.js +100 -0
- package/lib/common/chat-agents.spec.js.map +1 -0
- package/lib/common/chat-model-serialization.d.ts +2 -0
- package/lib/common/chat-model-serialization.d.ts.map +1 -1
- package/lib/common/chat-model-serialization.js.map +1 -1
- package/lib/common/chat-model.d.ts +59 -11
- package/lib/common/chat-model.d.ts.map +1 -1
- package/lib/common/chat-model.js +82 -2
- package/lib/common/chat-model.js.map +1 -1
- package/lib/common/chat-request-parser.spec.js +5 -2
- package/lib/common/chat-request-parser.spec.js.map +1 -1
- package/lib/common/chat-response-model.spec.d.ts +2 -0
- package/lib/common/chat-response-model.spec.d.ts.map +1 -0
- package/lib/common/chat-response-model.spec.js +43 -0
- package/lib/common/chat-response-model.spec.js.map +1 -0
- package/package.json +11 -11
- package/src/browser/agent-delegation-tool.spec.ts +4 -2
- package/src/browser/agent-delegation-tool.ts +40 -29
- package/src/browser/chat-tool-preference-bindings.spec.ts +83 -23
- package/src/browser/chat-tool-preference-bindings.ts +17 -8
- package/src/browser/chat-tool-request-service.ts +3 -2
- package/src/common/chat-agents.spec.ts +124 -0
- package/src/common/chat-agents.ts +59 -2
- package/src/common/chat-model-serialization.ts +2 -0
- package/src/common/chat-model.ts +136 -12
- package/src/common/chat-request-parser.spec.ts +6 -2
- package/src/common/chat-response-model.spec.ts +47 -0
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { GenericCapabilitySelections } from '@theia/ai-core';
|
|
18
18
|
import { ChatAgentLocation } from './chat-agents';
|
|
19
|
+
import { ResponseTokenUsage } from './chat-model';
|
|
19
20
|
|
|
20
21
|
export interface SerializableChangeSetElement {
|
|
21
22
|
kind?: string;
|
|
@@ -129,6 +130,7 @@ export interface SerializableChatResponseData {
|
|
|
129
130
|
errorMessage?: string;
|
|
130
131
|
promptVariantId?: string;
|
|
131
132
|
isPromptVariantEdited?: boolean;
|
|
133
|
+
tokenUsage?: ResponseTokenUsage;
|
|
132
134
|
content: SerializableChatResponseContentData[];
|
|
133
135
|
}
|
|
134
136
|
|
package/src/common/chat-model.ts
CHANGED
|
@@ -23,11 +23,11 @@ import {
|
|
|
23
23
|
AIVariableResolutionRequest,
|
|
24
24
|
GenericCapabilitySelections,
|
|
25
25
|
LanguageModelMessage,
|
|
26
|
+
ReasoningSettings,
|
|
26
27
|
ResolvedAIContextVariable,
|
|
27
28
|
ResolvedAIVariable,
|
|
28
29
|
TextMessage,
|
|
29
30
|
ThinkingMessage,
|
|
30
|
-
ThinkingModeSettings,
|
|
31
31
|
ToolCallResult,
|
|
32
32
|
ToolRequest,
|
|
33
33
|
ToolResultMessage,
|
|
@@ -78,7 +78,8 @@ export type ChatChangeEvent =
|
|
|
78
78
|
| ChatEditCancelEvent
|
|
79
79
|
| ChatEditSubmitEvent
|
|
80
80
|
| ChatResponseChangedEvent
|
|
81
|
-
| ChatChangeHierarchyBranchEvent
|
|
81
|
+
| ChatChangeHierarchyBranchEvent
|
|
82
|
+
| ChatInteractionNeededEvent;
|
|
82
83
|
|
|
83
84
|
export interface ChatAddRequestEvent {
|
|
84
85
|
kind: 'addRequest';
|
|
@@ -135,10 +136,18 @@ export interface ChatResponseChangedEvent {
|
|
|
135
136
|
kind: 'responseChanged';
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
export interface ChatInteractionNeededEvent {
|
|
140
|
+
kind: 'interactionNeeded';
|
|
141
|
+
contentPart: InteractiveContent & ChatResponseContent;
|
|
142
|
+
}
|
|
143
|
+
|
|
138
144
|
export namespace ChatChangeEvent {
|
|
139
145
|
export function isChangeSetEvent(event: ChatChangeEvent): event is ChatUpdateChangeSetEvent {
|
|
140
146
|
return event.kind === 'updateChangeSet';
|
|
141
147
|
}
|
|
148
|
+
export function isInteractionNeededEvent(event: ChatChangeEvent): event is ChatInteractionNeededEvent {
|
|
149
|
+
return event.kind === 'interactionNeeded';
|
|
150
|
+
}
|
|
142
151
|
}
|
|
143
152
|
|
|
144
153
|
export type ChatRequestRemovalReason = 'removal' | 'resend' | 'adoption';
|
|
@@ -212,11 +221,8 @@ export interface ChatHierarchyBranchItem<TRequest extends ChatRequestModel = Cha
|
|
|
212
221
|
}
|
|
213
222
|
|
|
214
223
|
export interface CommonChatSessionSettings {
|
|
215
|
-
/**
|
|
216
|
-
|
|
217
|
-
* These are processed by Theia and converted to provider-specific formats.
|
|
218
|
-
*/
|
|
219
|
-
thinkingMode?: ThinkingModeSettings;
|
|
224
|
+
/** Reasoning configuration for this session; applied to reasoning-capable models. */
|
|
225
|
+
reasoning?: ReasoningSettings;
|
|
220
226
|
/** Per-session tool confirmation timeout in seconds. Overrides the global preference when set. */
|
|
221
227
|
confirmationTimeout?: number;
|
|
222
228
|
}
|
|
@@ -382,6 +388,29 @@ export interface ChatProgressMessage {
|
|
|
382
388
|
content: string;
|
|
383
389
|
}
|
|
384
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Interface for ChatResponseContent parts that require user interaction.
|
|
393
|
+
* Content parts that implement this interface can be tracked by the delegation
|
|
394
|
+
* renderer without content-type-specific checks.
|
|
395
|
+
*/
|
|
396
|
+
export interface InteractiveContent {
|
|
397
|
+
/** Stable identifier for deduplication in pending interaction tracking. */
|
|
398
|
+
readonly interactionId: string | undefined;
|
|
399
|
+
/** Whether the interaction has been resolved (e.g., confirmed/denied, option selected). */
|
|
400
|
+
readonly isResolved: boolean;
|
|
401
|
+
/** Resolves when the interaction is resolved. Used for cleanup in delegation chains. */
|
|
402
|
+
readonly whenResolved: Promise<void>;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export namespace InteractiveContent {
|
|
406
|
+
export function is(content: unknown): content is InteractiveContent {
|
|
407
|
+
return typeof content === 'object' && !!content
|
|
408
|
+
&& 'interactionId' in content
|
|
409
|
+
&& 'isResolved' in content
|
|
410
|
+
&& 'whenResolved' in content;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
385
414
|
export interface ChatResponseContent {
|
|
386
415
|
kind: string;
|
|
387
416
|
/**
|
|
@@ -526,7 +555,7 @@ export interface HorizontalLayoutChatResponseContent extends ChatResponseContent
|
|
|
526
555
|
content: ChatResponseContent[];
|
|
527
556
|
}
|
|
528
557
|
|
|
529
|
-
export interface ToolCallChatResponseContent extends Required<ChatResponseContent
|
|
558
|
+
export interface ToolCallChatResponseContent extends Required<ChatResponseContent>, InteractiveContent {
|
|
530
559
|
kind: 'toolCall';
|
|
531
560
|
id?: string;
|
|
532
561
|
name?: string;
|
|
@@ -803,7 +832,7 @@ export type MultiSelectQuestionResponseHandler = (
|
|
|
803
832
|
selectedOptions: { text: string, value?: string }[],
|
|
804
833
|
) => void;
|
|
805
834
|
|
|
806
|
-
export interface QuestionResponseContent extends ChatResponseContent {
|
|
835
|
+
export interface QuestionResponseContent extends ChatResponseContent, InteractiveContent {
|
|
807
836
|
kind: 'question';
|
|
808
837
|
question: string;
|
|
809
838
|
header?: string;
|
|
@@ -844,6 +873,13 @@ export namespace QuestionResponseContent {
|
|
|
844
873
|
}
|
|
845
874
|
}
|
|
846
875
|
|
|
876
|
+
export interface ResponseTokenUsage {
|
|
877
|
+
readonly inputTokens: number;
|
|
878
|
+
readonly outputTokens: number;
|
|
879
|
+
readonly cacheCreationInputTokens?: number;
|
|
880
|
+
readonly cacheReadInputTokens?: number;
|
|
881
|
+
}
|
|
882
|
+
|
|
847
883
|
export interface ChatResponse {
|
|
848
884
|
readonly content: ChatResponseContent[];
|
|
849
885
|
asString(): string;
|
|
@@ -858,6 +894,11 @@ export interface ChatResponseModel {
|
|
|
858
894
|
* Use this to be notified for any change in the response model
|
|
859
895
|
*/
|
|
860
896
|
readonly onDidChange: Event<void>;
|
|
897
|
+
/**
|
|
898
|
+
* Fires when this response requires user interaction (e.g., tool confirmation, question response).
|
|
899
|
+
* The content part that needs interaction is provided as the event payload.
|
|
900
|
+
*/
|
|
901
|
+
readonly onInteractionNeeded: Event<InteractiveContent & ChatResponseContent>;
|
|
861
902
|
/**
|
|
862
903
|
* The unique identifier of the response model
|
|
863
904
|
*/
|
|
@@ -911,6 +952,7 @@ export interface ChatResponseModel {
|
|
|
911
952
|
* Indicates whether the prompt variant was customized/edited
|
|
912
953
|
*/
|
|
913
954
|
readonly isPromptVariantEdited?: boolean;
|
|
955
|
+
readonly tokenUsage?: ResponseTokenUsage;
|
|
914
956
|
toSerializable(): SerializableChatResponseData;
|
|
915
957
|
}
|
|
916
958
|
|
|
@@ -1052,6 +1094,17 @@ export class MutableChatModel implements ChatModel, Disposable {
|
|
|
1052
1094
|
this._settings = settings;
|
|
1053
1095
|
}
|
|
1054
1096
|
|
|
1097
|
+
addChildModel(child: MutableChatModel): Disposable {
|
|
1098
|
+
const disposable = new DisposableCollection();
|
|
1099
|
+
disposable.push(child.onDidChange(event => {
|
|
1100
|
+
if (ChatChangeEvent.isInteractionNeededEvent(event)) {
|
|
1101
|
+
this._onDidChangeEmitter.fire(event);
|
|
1102
|
+
}
|
|
1103
|
+
}));
|
|
1104
|
+
this.toDispose.push(disposable);
|
|
1105
|
+
return disposable;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1055
1108
|
addRequest(parsedChatRequest: ParsedChatRequest, agentId?: string, context: ChatContext = { variables: [] }): MutableChatRequestModel {
|
|
1056
1109
|
const add = this.getTargetForRequestAddition(parsedChatRequest);
|
|
1057
1110
|
const requestModel = new MutableChatRequestModel(
|
|
@@ -1680,10 +1733,14 @@ export class MutableChatRequestModel implements ChatRequestModel, EditableChatRe
|
|
|
1680
1733
|
|
|
1681
1734
|
// Wire response changes to propagate through request to session
|
|
1682
1735
|
this._response.onDidChange(() => {
|
|
1683
|
-
// Fire a generic addVariable event to propagate response changes
|
|
1684
1736
|
this._onDidChangeEmitter.fire({ kind: 'responseChanged' });
|
|
1685
1737
|
}, this, this.toDispose);
|
|
1686
1738
|
|
|
1739
|
+
// Wire interaction needed events to propagate through request to session
|
|
1740
|
+
this._response.onInteractionNeeded(contentPart => {
|
|
1741
|
+
this._onDidChangeEmitter.fire({ kind: 'interactionNeeded', contentPart });
|
|
1742
|
+
}, this, this.toDispose);
|
|
1743
|
+
|
|
1687
1744
|
this.toDispose.push(this._onDidChangeEmitter);
|
|
1688
1745
|
}
|
|
1689
1746
|
|
|
@@ -2236,7 +2293,7 @@ export class CodeChatResponseContentImpl implements CodeChatResponseContent {
|
|
|
2236
2293
|
}
|
|
2237
2294
|
}
|
|
2238
2295
|
|
|
2239
|
-
export class ToolCallChatResponseContentImpl implements ToolCallChatResponseContent {
|
|
2296
|
+
export class ToolCallChatResponseContentImpl implements ToolCallChatResponseContent, InteractiveContent {
|
|
2240
2297
|
readonly kind = 'toolCall';
|
|
2241
2298
|
protected _id?: string;
|
|
2242
2299
|
protected _name?: string;
|
|
@@ -2298,6 +2355,14 @@ export class ToolCallChatResponseContentImpl implements ToolCallChatResponseCont
|
|
|
2298
2355
|
this._confirmationTimeout = value;
|
|
2299
2356
|
}
|
|
2300
2357
|
|
|
2358
|
+
get interactionId(): string | undefined {
|
|
2359
|
+
return this._id;
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
get isResolved(): boolean {
|
|
2363
|
+
return this.finished;
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2301
2366
|
get confirmed(): Promise<boolean> {
|
|
2302
2367
|
return this._confirmed;
|
|
2303
2368
|
}
|
|
@@ -2310,6 +2375,10 @@ export class ToolCallChatResponseContentImpl implements ToolCallChatResponseCont
|
|
|
2310
2375
|
return this._whenFinished;
|
|
2311
2376
|
}
|
|
2312
2377
|
|
|
2378
|
+
get whenResolved(): Promise<void> {
|
|
2379
|
+
return this._whenFinished;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2313
2382
|
createConfirmationPromise(): Promise<boolean> {
|
|
2314
2383
|
if (!this._confirmationResolver) {
|
|
2315
2384
|
this._confirmed = new Promise<boolean>((resolve, reject) => {
|
|
@@ -2563,12 +2632,14 @@ export interface QuestionResponseContentOptions {
|
|
|
2563
2632
|
* Default implementation for the QuestionResponseContent.
|
|
2564
2633
|
* Can be created with or without handler/request for read-only (restored) mode.
|
|
2565
2634
|
*/
|
|
2566
|
-
export class QuestionResponseContentImpl implements QuestionResponseContent {
|
|
2635
|
+
export class QuestionResponseContentImpl implements QuestionResponseContent, InteractiveContent {
|
|
2567
2636
|
readonly kind = 'question';
|
|
2568
2637
|
public multiSelect?: boolean;
|
|
2569
2638
|
public header?: string;
|
|
2570
2639
|
public onSkip?: () => void;
|
|
2571
2640
|
protected _selectedOptions: { text: string; value?: string }[] | undefined;
|
|
2641
|
+
protected _resolvedResolver?: () => void;
|
|
2642
|
+
readonly whenResolved: Promise<void>;
|
|
2572
2643
|
|
|
2573
2644
|
constructor(
|
|
2574
2645
|
question: string,
|
|
@@ -2596,14 +2667,33 @@ export class QuestionResponseContentImpl implements QuestionResponseContent {
|
|
|
2596
2667
|
this.onSkip = questionOptions?.onSkip;
|
|
2597
2668
|
this._selectedOptions = questionOptions?.selectedOptions ??
|
|
2598
2669
|
(questionOptions?.selectedOption ? [questionOptions.selectedOption] : undefined);
|
|
2670
|
+
if (this._selectedOptions) {
|
|
2671
|
+
this.whenResolved = Promise.resolve();
|
|
2672
|
+
} else {
|
|
2673
|
+
this.whenResolved = new Promise<void>(resolve => {
|
|
2674
|
+
this._resolvedResolver = resolve;
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
if (!this.isReadOnly && this.request) {
|
|
2678
|
+
this.request.response.fireInteractionNeeded(this);
|
|
2679
|
+
}
|
|
2599
2680
|
}
|
|
2600
2681
|
|
|
2601
2682
|
get isReadOnly(): boolean {
|
|
2602
2683
|
return !this.handler || !this.request;
|
|
2603
2684
|
}
|
|
2604
2685
|
|
|
2686
|
+
get interactionId(): string | undefined {
|
|
2687
|
+
return `question-${this.question}`;
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
get isResolved(): boolean {
|
|
2691
|
+
return this.selectedOption !== undefined;
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2605
2694
|
set selectedOption(option: { text: string; value?: string } | undefined) {
|
|
2606
2695
|
this._selectedOptions = option ? [option] : undefined;
|
|
2696
|
+
this._resolvedResolver?.();
|
|
2607
2697
|
if (this.request) {
|
|
2608
2698
|
this.request.response.response.responseContentChanged();
|
|
2609
2699
|
}
|
|
@@ -2614,6 +2704,7 @@ export class QuestionResponseContentImpl implements QuestionResponseContent {
|
|
|
2614
2704
|
|
|
2615
2705
|
set selectedOptions(options: { text: string; value?: string }[] | undefined) {
|
|
2616
2706
|
this._selectedOptions = options;
|
|
2707
|
+
this._resolvedResolver?.();
|
|
2617
2708
|
if (this.request) {
|
|
2618
2709
|
this.request.response.response.responseContentChanged();
|
|
2619
2710
|
}
|
|
@@ -2766,6 +2857,9 @@ export class MutableChatResponseModel implements ChatResponseModel {
|
|
|
2766
2857
|
protected readonly _onDidChangeEmitter = new Emitter<void>();
|
|
2767
2858
|
onDidChange: Event<void> = this._onDidChangeEmitter.event;
|
|
2768
2859
|
|
|
2860
|
+
protected readonly _onInteractionNeededEmitter = new Emitter<InteractiveContent & ChatResponseContent>();
|
|
2861
|
+
readonly onInteractionNeeded: Event<InteractiveContent & ChatResponseContent> = this._onInteractionNeededEmitter.event;
|
|
2862
|
+
|
|
2769
2863
|
data = {};
|
|
2770
2864
|
|
|
2771
2865
|
protected _id: string;
|
|
@@ -2780,6 +2874,8 @@ export class MutableChatResponseModel implements ChatResponseModel {
|
|
|
2780
2874
|
protected _cancellationToken: CancellationTokenSource;
|
|
2781
2875
|
protected _promptVariantId?: string;
|
|
2782
2876
|
protected _isPromptVariantEdited?: boolean;
|
|
2877
|
+
protected _tokenUsage?: ResponseTokenUsage;
|
|
2878
|
+
protected _tokenUsageEntries: ResponseTokenUsage[] = [];
|
|
2783
2879
|
|
|
2784
2880
|
constructor(
|
|
2785
2881
|
requestId: string,
|
|
@@ -2823,6 +2919,7 @@ export class MutableChatResponseModel implements ChatResponseModel {
|
|
|
2823
2919
|
this._progressMessages = [];
|
|
2824
2920
|
this._promptVariantId = data.promptVariantId;
|
|
2825
2921
|
this._isPromptVariantEdited = data.isPromptVariantEdited ?? false;
|
|
2922
|
+
this._tokenUsage = data.tokenUsage;
|
|
2826
2923
|
|
|
2827
2924
|
if (data.errorMessage) {
|
|
2828
2925
|
this._errorObject = new Error(data.errorMessage);
|
|
@@ -2902,6 +2999,24 @@ export class MutableChatResponseModel implements ChatResponseModel {
|
|
|
2902
2999
|
return this._isPromptVariantEdited ?? false;
|
|
2903
3000
|
}
|
|
2904
3001
|
|
|
3002
|
+
get tokenUsage(): ResponseTokenUsage | undefined {
|
|
3003
|
+
return this._tokenUsage;
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
setTokenUsage(usage: ResponseTokenUsage): void {
|
|
3007
|
+
this._tokenUsage = usage;
|
|
3008
|
+
this.addTokenUsageEntry(usage);
|
|
3009
|
+
this._onDidChangeEmitter.fire();
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
addTokenUsageEntry(usage: ResponseTokenUsage): void {
|
|
3013
|
+
this._tokenUsageEntries.push(usage);
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
get tokenUsageEntries(): readonly ResponseTokenUsage[] {
|
|
3017
|
+
return this._tokenUsageEntries;
|
|
3018
|
+
}
|
|
3019
|
+
|
|
2905
3020
|
setPromptVariantInfo(variantId: string | undefined, isEdited: boolean): void {
|
|
2906
3021
|
this._promptVariantId = variantId;
|
|
2907
3022
|
this._isPromptVariantEdited = isEdited;
|
|
@@ -2952,6 +3067,14 @@ export class MutableChatResponseModel implements ChatResponseModel {
|
|
|
2952
3067
|
this._onDidChangeEmitter.fire();
|
|
2953
3068
|
}
|
|
2954
3069
|
|
|
3070
|
+
fireInteractionNeeded(contentPart: InteractiveContent & ChatResponseContent): void {
|
|
3071
|
+
this._onInteractionNeededEmitter.fire(contentPart);
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
notifyChanged(): void {
|
|
3075
|
+
this._onDidChangeEmitter.fire();
|
|
3076
|
+
}
|
|
3077
|
+
|
|
2955
3078
|
error(error: Error): void {
|
|
2956
3079
|
this._isComplete = true;
|
|
2957
3080
|
this._isWaitingForInput = false;
|
|
@@ -2975,6 +3098,7 @@ export class MutableChatResponseModel implements ChatResponseModel {
|
|
|
2975
3098
|
errorMessage: this.errorObject?.message,
|
|
2976
3099
|
promptVariantId: this._promptVariantId,
|
|
2977
3100
|
isPromptVariantEdited: this._isPromptVariantEdited,
|
|
3101
|
+
tokenUsage: this._tokenUsage,
|
|
2978
3102
|
content: this.response.content.map(c => {
|
|
2979
3103
|
const serialized = c.toSerializable?.();
|
|
2980
3104
|
if (!serialized) {
|
|
@@ -323,6 +323,9 @@ describe('ChatRequestParserImpl', () => {
|
|
|
323
323
|
invoke: async () => undefined,
|
|
324
324
|
});
|
|
325
325
|
|
|
326
|
+
// Set up the parser's agent service so it can recognise agents during parsing
|
|
327
|
+
chatAgentService.getAgents.returns([createAgent('agentA'), createAgent('agentB')]);
|
|
328
|
+
|
|
326
329
|
const tool = new AgentDelegationTool();
|
|
327
330
|
(tool as unknown as { getChatAgentService: () => unknown }).getChatAgentService = () => ({
|
|
328
331
|
getAgent: sinon.stub().withArgs('agentA').returns(createAgent('agentA')),
|
|
@@ -348,11 +351,12 @@ describe('ChatRequestParserImpl', () => {
|
|
|
348
351
|
id: 'session-1',
|
|
349
352
|
model: {
|
|
350
353
|
changeSet: {
|
|
351
|
-
onDidChange: sinon.stub().returns({}),
|
|
354
|
+
onDidChange: sinon.stub().returns({ dispose: sinon.stub() }),
|
|
352
355
|
getElements: sinon.stub().returns([]),
|
|
353
356
|
setTitle: sinon.stub(),
|
|
354
357
|
addElements: sinon.stub(),
|
|
355
|
-
}
|
|
358
|
+
},
|
|
359
|
+
onDidChange: sinon.stub().returns({ dispose: sinon.stub() })
|
|
356
360
|
}
|
|
357
361
|
}),
|
|
358
362
|
sendRequest,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 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 { expect } from 'chai';
|
|
18
|
+
import { MutableChatResponseModel } from './chat-model';
|
|
19
|
+
|
|
20
|
+
describe('MutableChatResponseModel', () => {
|
|
21
|
+
describe('setTokenUsage', () => {
|
|
22
|
+
it('should also add a token usage entry', () => {
|
|
23
|
+
const response = new MutableChatResponseModel('req-1');
|
|
24
|
+
const usage = { inputTokens: 100, outputTokens: 50 };
|
|
25
|
+
|
|
26
|
+
response.setTokenUsage(usage);
|
|
27
|
+
|
|
28
|
+
expect(response.tokenUsage).to.deep.equal(usage);
|
|
29
|
+
expect(response.tokenUsageEntries).to.have.lengthOf(1);
|
|
30
|
+
expect(response.tokenUsageEntries[0]).to.deep.equal(usage);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should accumulate entries across multiple setTokenUsage calls', () => {
|
|
34
|
+
const response = new MutableChatResponseModel('req-1');
|
|
35
|
+
const usage1 = { inputTokens: 100, outputTokens: 50 };
|
|
36
|
+
const usage2 = { inputTokens: 200, outputTokens: 80 };
|
|
37
|
+
|
|
38
|
+
response.setTokenUsage(usage1);
|
|
39
|
+
response.setTokenUsage(usage2);
|
|
40
|
+
|
|
41
|
+
expect(response.tokenUsage).to.deep.equal(usage2);
|
|
42
|
+
expect(response.tokenUsageEntries).to.have.lengthOf(2);
|
|
43
|
+
expect(response.tokenUsageEntries[0]).to.deep.equal(usage1);
|
|
44
|
+
expect(response.tokenUsageEntries[1]).to.deep.equal(usage2);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|