Skip to content

Commit 1be76b3

Browse files
committed
Fix response toString for inline refs
Fixes microsoft#236655
1 parent 41793c2 commit 1be76b3

File tree

3 files changed

+78
-33
lines changed

3 files changed

+78
-33
lines changed

src/vs/workbench/contrib/chat/common/chatModel.ts

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Emitter, Event } from '../../../../base/common/event.js';
99
import { IMarkdownString, MarkdownString, isMarkdownString } from '../../../../base/common/htmlContent.js';
1010
import { Disposable } from '../../../../base/common/lifecycle.js';
1111
import { revive } from '../../../../base/common/marshalling.js';
12+
import { Schemas } from '../../../../base/common/network.js';
1213
import { equals } from '../../../../base/common/objects.js';
1314
import { basename, isEqual } from '../../../../base/common/resources.js';
1415
import { ThemeIcon } from '../../../../base/common/themables.js';
@@ -397,38 +398,12 @@ export class Response extends Disposable implements IResponse {
397398
}
398399

399400
private _updateRepr(quiet?: boolean) {
400-
const inlineRefToRepr = (part: IChatContentInlineReference) =>
401-
'uri' in part.inlineReference
402-
? basename(part.inlineReference.uri)
403-
: 'name' in part.inlineReference
404-
? part.inlineReference.name
405-
: basename(part.inlineReference);
406-
407-
this._responseRepr = this._responseParts.map(part => {
408-
if (part.kind === 'treeData') {
409-
return '';
410-
} else if (part.kind === 'inlineReference') {
411-
return inlineRefToRepr(part);
412-
} else if (part.kind === 'command') {
413-
return part.command.title;
414-
} else if (part.kind === 'textEditGroup') {
415-
return localize('editsSummary', "Made changes.");
416-
} else if (part.kind === 'progressMessage' || part.kind === 'codeblockUri' || part.kind === 'toolInvocation' || part.kind === 'toolInvocationSerialized') {
417-
return '';
418-
} else if (part.kind === 'confirmation') {
419-
return `${part.title}\n${part.message}`;
420-
} else {
421-
return part.content.value;
422-
}
423-
})
424-
.filter(s => s.length > 0)
425-
.join('\n\n');
426-
401+
this._responseRepr = this.partsToRepr(this._responseParts);
427402
this._responseRepr += this._citations.length ? '\n\n' + getCodeCitationsMessage(this._citations) : '';
428403

429404
this._markdownContent = this._responseParts.map(part => {
430405
if (part.kind === 'inlineReference') {
431-
return inlineRefToRepr(part);
406+
return this.inlineRefToRepr(part);
432407
} else if (part.kind === 'markdownContent' || part.kind === 'markdownVuln') {
433408
return part.content.value;
434409
} else {
@@ -442,6 +417,73 @@ export class Response extends Disposable implements IResponse {
442417
this._onDidChangeValue.fire();
443418
}
444419
}
420+
421+
private partsToRepr(parts: readonly IChatProgressResponseContent[]): string {
422+
const blocks: string[] = [];
423+
let currentBlockSegments: string[] = [];
424+
425+
for (const part of parts) {
426+
let segment: { text: string; isBlock?: boolean } | undefined;
427+
switch (part.kind) {
428+
case 'treeData':
429+
case 'progressMessage':
430+
case 'codeblockUri':
431+
case 'toolInvocation':
432+
case 'toolInvocationSerialized':
433+
// Ignore
434+
continue;
435+
case 'inlineReference':
436+
segment = { text: this.inlineRefToRepr(part) };
437+
break;
438+
case 'command':
439+
segment = { text: part.command.title, isBlock: true };
440+
break;
441+
case 'textEditGroup':
442+
segment = { text: localize('editsSummary', "Made changes."), isBlock: true };
443+
break;
444+
case 'confirmation':
445+
segment = { text: `${part.title}\n${part.message}`, isBlock: true };
446+
break;
447+
default:
448+
segment = { text: part.content.value };
449+
break;
450+
}
451+
452+
if (segment.isBlock) {
453+
if (currentBlockSegments.length) {
454+
blocks.push(currentBlockSegments.join(''));
455+
currentBlockSegments = [];
456+
}
457+
blocks.push(segment.text);
458+
} else {
459+
currentBlockSegments.push(segment.text);
460+
}
461+
}
462+
463+
if (currentBlockSegments.length) {
464+
blocks.push(currentBlockSegments.join(''));
465+
}
466+
467+
return blocks.join('\n\n');
468+
}
469+
470+
private inlineRefToRepr(part: IChatContentInlineReference) {
471+
if ('uri' in part.inlineReference) {
472+
return this.uriToRepr(part.inlineReference.uri);
473+
}
474+
475+
return 'name' in part.inlineReference
476+
? '`' + part.inlineReference.name + '`'
477+
: this.uriToRepr(part.inlineReference);
478+
}
479+
480+
private uriToRepr(uri: URI): string {
481+
if (uri.scheme === Schemas.http || uri.scheme === Schemas.https) {
482+
return uri.toString(false);
483+
}
484+
485+
return basename(uri);
486+
}
445487
}
446488

447489
export class ChatResponseModel extends Disposable implements IChatResponseModel {

src/vs/workbench/contrib/chat/test/common/__snapshots__/Response_inline_reference.0.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
content: {
4-
value: "text before",
4+
value: "text before ",
55
isTrusted: false,
66
supportThemeIcons: false,
77
supportHtml: false
@@ -14,7 +14,7 @@
1414
},
1515
{
1616
content: {
17-
value: "text after",
17+
value: " text after",
1818
isTrusted: false,
1919
supportThemeIcons: false,
2020
supportHtml: false

src/vs/workbench/contrib/chat/test/common/chatModel.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,13 @@ suite('Response', () => {
191191

192192
test('inline reference', async () => {
193193
const response = store.add(new Response([]));
194-
response.updateContent({ content: new MarkdownString('text before'), kind: 'markdownContent' });
195-
response.updateContent({ inlineReference: URI.parse('https://microsoft.com'), kind: 'inlineReference' });
196-
response.updateContent({ content: new MarkdownString('text after'), kind: 'markdownContent' });
194+
response.updateContent({ content: new MarkdownString('text before '), kind: 'markdownContent' });
195+
response.updateContent({ inlineReference: URI.parse('https://microsoft.com/'), kind: 'inlineReference' });
196+
response.updateContent({ content: new MarkdownString(' text after'), kind: 'markdownContent' });
197197
await assertSnapshot(response.value);
198+
199+
assert.strictEqual(response.toString(), 'text before https://microsoft.com/ text after');
200+
198201
});
199202
});
200203

0 commit comments

Comments
 (0)