Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chronicle/common/test/extractAssistantResponse.spec.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { describe, expect, it } from 'vitest';
7
import { extractAssistantResponse } from '../sessionStoreTracking';
8
9
describe('extractAssistantResponse', () => {
10
it('returns assistant text from valid JSON', () => {
11
const raw = JSON.stringify([
12
{ role: 'assistant', parts: [{ type: 'text', content: 'Hello, world!' }] },
13
]);
14
15
expect(extractAssistantResponse(raw)).toBe('Hello, world!');
16
});
17
18
it('returns undefined when input is undefined', () => {
19
expect(extractAssistantResponse(undefined)).toBeUndefined();
20
});
21
22
it('returns undefined for empty string', () => {
23
expect(extractAssistantResponse('')).toBeUndefined();
24
});
25
26
it('joins multiple text parts with newline', () => {
27
const raw = JSON.stringify([
28
{
29
role: 'assistant',
30
parts: [
31
{ type: 'text', content: 'Part one.' },
32
{ type: 'text', content: 'Part two.' },
33
],
34
},
35
]);
36
37
expect(extractAssistantResponse(raw)).toBe('Part one.\nPart two.');
38
});
39
40
it('ignores non-assistant roles', () => {
41
const raw = JSON.stringify([
42
{ role: 'system', parts: [{ type: 'text', content: 'System message' }] },
43
{ role: 'assistant', parts: [{ type: 'text', content: 'Assistant reply' }] },
44
]);
45
46
expect(extractAssistantResponse(raw)).toBe('Assistant reply');
47
});
48
49
it('ignores non-text parts (tool_call)', () => {
50
const raw = JSON.stringify([
51
{
52
role: 'assistant',
53
parts: [
54
{ type: 'tool_call', id: 'tc-1', name: 'some_tool', arguments: '{}' },
55
{ type: 'text', content: 'After tool call.' },
56
],
57
},
58
]);
59
60
expect(extractAssistantResponse(raw)).toBe('After tool call.');
61
});
62
63
it('returns undefined for empty parts array', () => {
64
const raw = JSON.stringify([
65
{ role: 'assistant', parts: [] },
66
]);
67
68
expect(extractAssistantResponse(raw)).toBeUndefined();
69
});
70
71
it('handles truncated JSON from truncateForOTel', () => {
72
// Simulate what truncateForOTel does: slices JSON mid-string and appends suffix
73
const longContent = 'A'.repeat(100_000);
74
const fullJson = JSON.stringify([
75
{ role: 'assistant', parts: [{ type: 'text', content: longContent }] },
76
]);
77
const truncated = fullJson.substring(0, 500) + '...[truncated, original 100123 chars]';
78
79
const result = extractAssistantResponse(truncated);
80
expect(result).toBeDefined();
81
expect(result!.startsWith('AAAA')).toBe(true);
82
expect(result!).not.toContain('...[truncated');
83
});
84
85
it('unescapes JSON escapes in truncated fallback path', () => {
86
// Content with characters that get JSON-escaped: newlines, quotes, backslashes
87
const content = 'Hello "world"\nLine two\tTabbed\\end';
88
const fullJson = JSON.stringify([
89
{ role: 'assistant', parts: [{ type: 'text', content: content + 'A'.repeat(100_000) }] },
90
]);
91
const truncated = fullJson.substring(0, 200) + '...[truncated, original 100050 chars]';
92
93
const result = extractAssistantResponse(truncated);
94
expect(result).toBeDefined();
95
// Should be unescaped — actual newlines and quotes, not \\n and \\"
96
expect(result!).toContain('Hello "world"');
97
expect(result!).toContain('\n');
98
});
99
100
it('returns undefined for malformed non-truncated JSON', () => {
101
expect(extractAssistantResponse('{not valid json at all}')).toBeUndefined();
102
});
103
104
it('skips tool_call content and extracts text part in truncated JSON', () => {
105
// Simulate JSON with a tool_call part (which has a "content" field) before the text part
106
const fullJson = JSON.stringify([
107
{
108
role: 'assistant',
109
parts: [
110
{ type: 'tool_call', id: 'tc-1', content: 'should be skipped' },
111
{ type: 'text', content: 'The real answer' + 'B'.repeat(100_000) },
112
],
113
},
114
]);
115
const truncated = fullJson.substring(0, 500) + '...[truncated, original 100050 chars]';
116
117
const result = extractAssistantResponse(truncated);
118
expect(result).toBeDefined();
119
expect(result!).toContain('The real answer');
120
expect(result!).not.toContain('should be skipped');
121
});
122
});
123
124