@theia/ai-chat 1.66.0-next.67 → 1.66.0-next.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/lib/browser/agent-delegation-tool.d.ts.map +1 -1
  2. package/lib/browser/agent-delegation-tool.js +4 -2
  3. package/lib/browser/agent-delegation-tool.js.map +1 -1
  4. package/lib/browser/ai-chat-frontend-module.d.ts.map +1 -1
  5. package/lib/browser/ai-chat-frontend-module.js +15 -0
  6. package/lib/browser/ai-chat-frontend-module.js.map +1 -1
  7. package/lib/browser/change-set-file-element-deserializer.d.ts +7 -0
  8. package/lib/browser/change-set-file-element-deserializer.d.ts.map +1 -0
  9. package/lib/browser/change-set-file-element-deserializer.js +61 -0
  10. package/lib/browser/change-set-file-element-deserializer.js.map +1 -0
  11. package/lib/browser/change-set-file-element.d.ts +2 -0
  12. package/lib/browser/change-set-file-element.d.ts.map +1 -1
  13. package/lib/browser/change-set-file-element.js +17 -0
  14. package/lib/browser/change-set-file-element.js.map +1 -1
  15. package/lib/browser/chat-session-store-impl.d.ts +36 -0
  16. package/lib/browser/chat-session-store-impl.d.ts.map +1 -0
  17. package/lib/browser/chat-session-store-impl.js +287 -0
  18. package/lib/browser/chat-session-store-impl.js.map +1 -0
  19. package/lib/common/change-set-element-deserializer.d.ts +30 -0
  20. package/lib/common/change-set-element-deserializer.d.ts.map +1 -0
  21. package/lib/common/change-set-element-deserializer.js +81 -0
  22. package/lib/common/change-set-element-deserializer.js.map +1 -0
  23. package/lib/common/change-set.d.ts +7 -0
  24. package/lib/common/change-set.d.ts.map +1 -1
  25. package/lib/common/change-set.js.map +1 -1
  26. package/lib/common/chat-auto-save.spec.d.ts +2 -0
  27. package/lib/common/chat-auto-save.spec.d.ts.map +1 -0
  28. package/lib/common/chat-auto-save.spec.js +304 -0
  29. package/lib/common/chat-auto-save.spec.js.map +1 -0
  30. package/lib/common/chat-content-deserializer.d.ts +161 -0
  31. package/lib/common/chat-content-deserializer.d.ts.map +1 -0
  32. package/lib/common/chat-content-deserializer.js +166 -0
  33. package/lib/common/chat-content-deserializer.js.map +1 -0
  34. package/lib/common/chat-content-deserializer.spec.d.ts +2 -0
  35. package/lib/common/chat-content-deserializer.spec.d.ts.map +1 -0
  36. package/lib/common/chat-content-deserializer.spec.js +307 -0
  37. package/lib/common/chat-content-deserializer.spec.js.map +1 -0
  38. package/lib/common/chat-model-serialization.d.ts +110 -0
  39. package/lib/common/chat-model-serialization.d.ts.map +1 -0
  40. package/lib/common/chat-model-serialization.js +20 -0
  41. package/lib/common/chat-model-serialization.js.map +1 -0
  42. package/lib/common/chat-model-serialization.spec.d.ts +2 -0
  43. package/lib/common/chat-model-serialization.spec.d.ts.map +1 -0
  44. package/lib/common/chat-model-serialization.spec.js +278 -0
  45. package/lib/common/chat-model-serialization.spec.js.map +1 -0
  46. package/lib/common/chat-model.d.ts +163 -14
  47. package/lib/common/chat-model.d.ts.map +1 -1
  48. package/lib/common/chat-model.js +444 -36
  49. package/lib/common/chat-model.js.map +1 -1
  50. package/lib/common/chat-service-deletion.spec.d.ts +2 -0
  51. package/lib/common/chat-service-deletion.spec.d.ts.map +1 -0
  52. package/lib/common/chat-service-deletion.spec.js +221 -0
  53. package/lib/common/chat-service-deletion.spec.js.map +1 -0
  54. package/lib/common/chat-service.d.ts +30 -2
  55. package/lib/common/chat-service.d.ts.map +1 -1
  56. package/lib/common/chat-service.js +182 -10
  57. package/lib/common/chat-service.js.map +1 -1
  58. package/lib/common/chat-session-store.d.ts +43 -0
  59. package/lib/common/chat-session-store.d.ts.map +1 -0
  60. package/lib/common/chat-session-store.js +20 -0
  61. package/lib/common/chat-session-store.js.map +1 -0
  62. package/lib/common/index.d.ts +3 -0
  63. package/lib/common/index.d.ts.map +1 -1
  64. package/lib/common/index.js +3 -0
  65. package/lib/common/index.js.map +1 -1
  66. package/package.json +9 -9
  67. package/src/browser/agent-delegation-tool.ts +4 -2
  68. package/src/browser/ai-chat-frontend-module.ts +27 -0
  69. package/src/browser/change-set-file-element-deserializer.ts +62 -0
  70. package/src/browser/change-set-file-element.ts +19 -0
  71. package/src/browser/chat-session-store-impl.ts +326 -0
  72. package/src/common/change-set-element-deserializer.ts +90 -0
  73. package/src/common/change-set.ts +8 -0
  74. package/src/common/chat-auto-save.spec.ts +372 -0
  75. package/src/common/chat-content-deserializer.spec.ts +375 -0
  76. package/src/common/chat-content-deserializer.ts +327 -0
  77. package/src/common/chat-model-serialization.spec.ts +343 -0
  78. package/src/common/chat-model-serialization.ts +133 -0
  79. package/src/common/chat-model.ts +644 -41
  80. package/src/common/chat-service-deletion.spec.ts +269 -0
  81. package/src/common/chat-service.ts +227 -10
  82. package/src/common/chat-session-store.ts +63 -0
  83. package/src/common/index.ts +3 -0
@@ -0,0 +1,375 @@
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 { expect } from 'chai';
18
+ import { URI } from '@theia/core';
19
+ import { Position } from '@theia/core/shared/vscode-languageserver-protocol';
20
+ import { ILogger } from '@theia/core/lib/common';
21
+ import {
22
+ ChatContentDeserializerRegistryImpl,
23
+ DefaultChatContentDeserializerContribution
24
+ } from './chat-content-deserializer';
25
+ import {
26
+ CodeChatResponseContentImpl,
27
+ ErrorChatResponseContentImpl,
28
+ HorizontalLayoutChatResponseContentImpl,
29
+ InformationalChatResponseContentImpl,
30
+ MarkdownChatResponseContentImpl,
31
+ ProgressChatResponseContentImpl,
32
+ QuestionResponseContentImpl,
33
+ TextChatResponseContentImpl,
34
+ ThinkingChatResponseContentImpl,
35
+ ToolCallChatResponseContentImpl
36
+ } from './chat-model';
37
+
38
+ class MockLogger {
39
+ error(): void { }
40
+ warn(): void { }
41
+ info(): void { }
42
+ debug(): void { }
43
+ }
44
+
45
+ describe('Chat Content Serialization', () => {
46
+
47
+ let registry: ChatContentDeserializerRegistryImpl;
48
+
49
+ beforeEach(() => {
50
+ registry = new ChatContentDeserializerRegistryImpl();
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ (registry as any).logger = new MockLogger() as unknown as ILogger;
53
+ const contribution = new DefaultChatContentDeserializerContribution();
54
+ contribution.registerDeserializers(registry);
55
+ });
56
+
57
+ describe('TextChatResponseContentImpl', () => {
58
+ it('should serialize and deserialize correctly', async () => {
59
+ const original = new TextChatResponseContentImpl('Hello, World!');
60
+ const serialized = original.toSerializable?.();
61
+
62
+ expect(serialized).to.not.be.undefined;
63
+ expect(serialized!.kind).to.equal('text');
64
+ expect(serialized!.data).to.deep.equal({ content: 'Hello, World!' });
65
+
66
+ // Simulate caller populating fallbackMessage
67
+ const withFallback = {
68
+ ...serialized!,
69
+ fallbackMessage: original.asString?.() || original.toString()
70
+ };
71
+
72
+ const deserialized = await registry.deserialize(withFallback);
73
+ expect(deserialized.kind).to.equal('text');
74
+ expect(deserialized.asString?.()).to.equal('Hello, World!');
75
+ });
76
+ });
77
+
78
+ describe('ThinkingChatResponseContentImpl', () => {
79
+ it('should serialize and deserialize correctly', async () => {
80
+ const original = new ThinkingChatResponseContentImpl('Thinking...', 'sig123');
81
+ const serialized = original.toSerializable?.();
82
+
83
+ expect(serialized).to.not.be.undefined;
84
+ expect(serialized!.kind).to.equal('thinking');
85
+ expect(serialized!.data).to.deep.equal({
86
+ content: 'Thinking...',
87
+ signature: 'sig123'
88
+ });
89
+
90
+ // Simulate caller populating fallbackMessage
91
+ const withFallback = {
92
+ ...serialized!,
93
+ fallbackMessage: original.asString?.() || original.toString()
94
+ };
95
+
96
+ const deserialized = await registry.deserialize(withFallback);
97
+ expect(deserialized.kind).to.equal('thinking');
98
+ });
99
+ });
100
+
101
+ describe('MarkdownChatResponseContentImpl', () => {
102
+ it('should serialize and deserialize correctly', async () => {
103
+ const original = new MarkdownChatResponseContentImpl('# Title\n\nContent');
104
+ const serialized = original.toSerializable?.();
105
+
106
+ expect(serialized).to.not.be.undefined;
107
+ expect(serialized!.kind).to.equal('markdownContent');
108
+ expect(serialized!.data).to.deep.equal({ content: '# Title\n\nContent' });
109
+
110
+ // Simulate caller populating fallbackMessage
111
+ const withFallback = {
112
+ ...serialized!,
113
+ fallbackMessage: original.asString?.() || original.toString()
114
+ };
115
+
116
+ const deserialized = await registry.deserialize(withFallback);
117
+ expect(deserialized.kind).to.equal('markdownContent');
118
+ expect(deserialized.asString?.()).to.equal('# Title\n\nContent');
119
+ });
120
+ });
121
+
122
+ describe('InformationalChatResponseContentImpl', () => {
123
+ it('should serialize and deserialize correctly', async () => {
124
+ const original = new InformationalChatResponseContentImpl('Info message');
125
+ const serialized = original.toSerializable?.();
126
+
127
+ expect(serialized).to.not.be.undefined;
128
+ expect(serialized!.kind).to.equal('informational');
129
+ expect(serialized!.data).to.deep.equal({ content: 'Info message' });
130
+
131
+ // Simulate caller populating fallbackMessage
132
+ const withFallback = {
133
+ ...serialized!,
134
+ fallbackMessage: original.asString?.() || original.toString()
135
+ };
136
+
137
+ const deserialized = await registry.deserialize(withFallback);
138
+ expect(deserialized.kind).to.equal('informational');
139
+ });
140
+ });
141
+
142
+ describe('CodeChatResponseContentImpl', () => {
143
+ it('should serialize and deserialize code without location', async () => {
144
+ const original = new CodeChatResponseContentImpl('console.log("test")', 'typescript');
145
+ const serialized = original.toSerializable?.();
146
+
147
+ expect(serialized).to.not.be.undefined;
148
+ expect(serialized!.kind).to.equal('code');
149
+ expect(serialized!.data).to.deep.equal({
150
+ code: 'console.log("test")',
151
+ language: 'typescript',
152
+ location: undefined
153
+ });
154
+
155
+ // Simulate caller populating fallbackMessage
156
+ const withFallback = {
157
+ ...serialized!,
158
+ fallbackMessage: original.asString?.() || original.toString()
159
+ };
160
+
161
+ const deserialized = await registry.deserialize(withFallback);
162
+ expect(deserialized.kind).to.equal('code');
163
+ });
164
+
165
+ it('should serialize and deserialize code with location', async () => {
166
+ const location = {
167
+ uri: new URI('file:///test.ts'),
168
+ position: Position.create(1, 0)
169
+ };
170
+ const original = new CodeChatResponseContentImpl('code', 'typescript', location);
171
+ const serialized = original.toSerializable?.();
172
+
173
+ expect(serialized).to.not.be.undefined;
174
+ expect(serialized!.kind).to.equal('code');
175
+
176
+ // Simulate caller populating fallbackMessage
177
+ const withFallback = {
178
+ ...serialized!,
179
+ fallbackMessage: original.asString?.() || original.toString()
180
+ };
181
+
182
+ const deserialized = await registry.deserialize(withFallback);
183
+ expect(deserialized.kind).to.equal('code');
184
+ });
185
+ });
186
+
187
+ describe('ToolCallChatResponseContentImpl', () => {
188
+ it('should serialize and deserialize correctly', async () => {
189
+ const original = new ToolCallChatResponseContentImpl(
190
+ 'id123',
191
+ 'toolName',
192
+ '{"arg": "value"}',
193
+ true,
194
+ 'result'
195
+ );
196
+ const serialized = original.toSerializable?.();
197
+
198
+ expect(serialized).to.not.be.undefined;
199
+ expect(serialized!.kind).to.equal('toolCall');
200
+ expect(serialized!.data).to.deep.equal({
201
+ id: 'id123',
202
+ name: 'toolName',
203
+ arguments: '{"arg": "value"}',
204
+ finished: true,
205
+ result: 'result'
206
+ });
207
+
208
+ // Simulate caller populating fallbackMessage
209
+ const withFallback = {
210
+ ...serialized!,
211
+ fallbackMessage: original.asString?.() || original.toString()
212
+ };
213
+
214
+ const deserialized = await registry.deserialize(withFallback);
215
+ expect(deserialized.kind).to.equal('toolCall');
216
+ });
217
+ });
218
+
219
+ describe('ErrorChatResponseContentImpl', () => {
220
+ it('should serialize and deserialize correctly', async () => {
221
+ const error = new Error('Test error');
222
+ const original = new ErrorChatResponseContentImpl(error);
223
+ const serialized = original.toSerializable?.();
224
+
225
+ expect(serialized).to.not.be.undefined;
226
+ expect(serialized!.kind).to.equal('error');
227
+ expect(serialized!.data).to.have.property('message', 'Test error');
228
+
229
+ // Simulate caller populating fallbackMessage
230
+ const withFallback = {
231
+ ...serialized!,
232
+ fallbackMessage: original.asString?.() || original.toString()
233
+ };
234
+
235
+ const deserialized = await registry.deserialize(withFallback);
236
+ expect(deserialized.kind).to.equal('error');
237
+ });
238
+ });
239
+
240
+ describe('ProgressChatResponseContentImpl', () => {
241
+ it('should serialize and deserialize correctly', async () => {
242
+ const original = new ProgressChatResponseContentImpl('Processing...');
243
+ const serialized = original.toSerializable?.();
244
+
245
+ expect(serialized).to.not.be.undefined;
246
+ expect(serialized!.kind).to.equal('progress');
247
+ expect(serialized!.data).to.deep.equal({ message: 'Processing...' });
248
+
249
+ // Simulate caller populating fallbackMessage
250
+ const withFallback = {
251
+ ...serialized!,
252
+ fallbackMessage: original.asString?.() || original.toString()
253
+ };
254
+
255
+ const deserialized = await registry.deserialize(withFallback);
256
+ expect(deserialized.kind).to.equal('progress');
257
+ });
258
+ });
259
+
260
+ describe('HorizontalLayoutChatResponseContentImpl', () => {
261
+ it('should serialize and deserialize nested content', async () => {
262
+ const child1 = new TextChatResponseContentImpl('Text 1');
263
+ const child2 = new TextChatResponseContentImpl('Text 2');
264
+ const original = new HorizontalLayoutChatResponseContentImpl([child1, child2]);
265
+ const serialized = original.toSerializable?.();
266
+
267
+ expect(serialized).to.not.be.undefined;
268
+ expect(serialized!.kind).to.equal('horizontal');
269
+ expect(serialized!.data).to.have.property('content');
270
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
271
+ expect((serialized!.data as any).content).to.be.an('array').with.length(2);
272
+
273
+ // Simulate caller populating fallbackMessage
274
+ const withFallback = {
275
+ ...serialized!,
276
+ fallbackMessage: original.asString?.() || original.toString()
277
+ };
278
+
279
+ const deserialized = await registry.deserialize(withFallback);
280
+ expect(deserialized.kind).to.equal('horizontal');
281
+ });
282
+ });
283
+
284
+ describe('QuestionResponseContentImpl', () => {
285
+ it('should serialize and deserialize question with selected option', async () => {
286
+ const options = [
287
+ { text: 'Blue' },
288
+ { text: 'Green' },
289
+ { text: 'Lavender' }
290
+ ];
291
+ const original = new QuestionResponseContentImpl(
292
+ 'Which color do you find most calming?',
293
+ options,
294
+ undefined, // request
295
+ undefined, // handler
296
+ { text: 'Blue' } // selectedOption
297
+ );
298
+ const serialized = original.toSerializable?.();
299
+
300
+ expect(serialized).to.not.be.undefined;
301
+ expect(serialized!.kind).to.equal('question');
302
+ expect(serialized!.data).to.deep.equal({
303
+ question: 'Which color do you find most calming?',
304
+ options: options,
305
+ selectedOption: { text: 'Blue' }
306
+ });
307
+
308
+ // Simulate caller populating fallbackMessage
309
+ const withFallback = {
310
+ ...serialized!,
311
+ fallbackMessage: original.asString?.() || original.toString()
312
+ };
313
+
314
+ const deserialized = await registry.deserialize(withFallback);
315
+ expect(deserialized.kind).to.equal('question');
316
+ expect(deserialized.asString?.()).to.include('Question: Which color do you find most calming?');
317
+ expect(deserialized.asString?.()).to.include('Answer: Blue');
318
+ });
319
+
320
+ it('should serialize and deserialize question without selected option', async () => {
321
+ const options = [
322
+ { text: 'Option 1' },
323
+ { text: 'Option 2' }
324
+ ];
325
+ const original = new QuestionResponseContentImpl(
326
+ 'What is your choice?',
327
+ options,
328
+ undefined, // request
329
+ undefined // handler
330
+ // no selectedOption
331
+ );
332
+ const serialized = original.toSerializable?.();
333
+
334
+ expect(serialized).to.not.be.undefined;
335
+ expect(serialized!.kind).to.equal('question');
336
+
337
+ // Simulate caller populating fallbackMessage
338
+ const withFallback = {
339
+ ...serialized!,
340
+ fallbackMessage: original.asString?.() || original.toString()
341
+ };
342
+
343
+ const deserialized = await registry.deserialize(withFallback);
344
+ expect(deserialized.kind).to.equal('question');
345
+ expect(deserialized.asString?.()).to.include('Question: What is your choice?');
346
+ expect(deserialized.asString?.()).to.include('No answer');
347
+ });
348
+ });
349
+
350
+ describe('ChatContentDeserializerRegistry', () => {
351
+ it('should handle unknown content types with fallback', async () => {
352
+ const unknownContent = {
353
+ kind: 'unknown-type',
354
+ fallbackMessage: 'Fallback text',
355
+ data: { some: 'data' }
356
+ };
357
+
358
+ const deserialized = await registry.deserialize(unknownContent);
359
+ expect(deserialized.kind).to.equal('unknown');
360
+ expect(deserialized.asString?.()).to.equal('Fallback text');
361
+ });
362
+
363
+ it('should use fallback message when deserializer not found', async () => {
364
+ const unknownContent = {
365
+ kind: 'custom-extension-type',
366
+ fallbackMessage: 'Custom content not available',
367
+ data: undefined
368
+ };
369
+
370
+ const deserialized = await registry.deserialize(unknownContent);
371
+ expect(deserialized.asString?.()).to.equal('Custom content not available');
372
+ });
373
+ });
374
+
375
+ });