Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/common/widget/chatResponseResourceFileSystemProvider.ts
5252 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 { decodeBase64, VSBuffer } from '../../../../../base/common/buffer.js';
7
import { Event } from '../../../../../base/common/event.js';
8
import { Disposable, IDisposable } from '../../../../../base/common/lifecycle.js';
9
import { newWriteableStream, ReadableStreamEvents } from '../../../../../base/common/stream.js';
10
import { URI } from '../../../../../base/common/uri.js';
11
import { createFileSystemProviderError, FileSystemProviderCapabilities, FileSystemProviderErrorCode, FileType, IFileService, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileReadWriteCapability, IStat } from '../../../../../platform/files/common/files.js';
12
import { IWorkbenchContribution } from '../../../../common/contributions.js';
13
import { ChatResponseResource } from '../model/chatModel.js';
14
import { IChatService, IChatToolInvocation, IChatToolInvocationSerialized } from '../chatService/chatService.js';
15
import { isToolResultInputOutputDetails } from '../tools/languageModelToolsService.js';
16
17
export class ChatResponseResourceFileSystemProvider extends Disposable implements
18
IWorkbenchContribution,
19
IFileSystemProviderWithFileReadWriteCapability,
20
IFileSystemProviderWithFileAtomicReadCapability,
21
IFileSystemProviderWithFileReadStreamCapability {
22
23
public static readonly ID = 'workbench.contrib.chatResponseResourceFileSystemProvider';
24
25
public readonly onDidChangeCapabilities = Event.None;
26
public readonly onDidChangeFile = Event.None;
27
28
public readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.None
29
| FileSystemProviderCapabilities.Readonly
30
| FileSystemProviderCapabilities.PathCaseSensitive
31
| FileSystemProviderCapabilities.FileReadStream
32
| FileSystemProviderCapabilities.FileAtomicRead
33
| FileSystemProviderCapabilities.FileReadWrite;
34
35
constructor(
36
@IChatService private readonly chatService: IChatService,
37
@IFileService private readonly _fileService: IFileService
38
) {
39
super();
40
this._register(this._fileService.registerProvider(ChatResponseResource.scheme, this));
41
}
42
43
readFile(resource: URI): Promise<Uint8Array> {
44
return Promise.resolve(this.lookupURI(resource));
45
}
46
47
readFileStream(resource: URI): ReadableStreamEvents<Uint8Array> {
48
const stream = newWriteableStream<Uint8Array>(data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer);
49
Promise.resolve(this.lookupURI(resource)).then(v => stream.end(v));
50
return stream;
51
}
52
53
async stat(resource: URI): Promise<IStat> {
54
const r = await this.lookupURI(resource);
55
return {
56
type: FileType.File,
57
ctime: 0,
58
mtime: 0,
59
size: r.length,
60
};
61
}
62
63
delete(): Promise<void> {
64
throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);
65
}
66
67
watch(): IDisposable {
68
return Disposable.None;
69
}
70
71
mkdir(): Promise<void> {
72
throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);
73
}
74
75
readdir(): Promise<[string, FileType][]> {
76
return Promise.resolve([]);
77
}
78
79
rename(): Promise<void> {
80
throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);
81
}
82
83
writeFile(): Promise<void> {
84
throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);
85
}
86
87
private findMatchingInvocation(uri: URI) {
88
const parsed = ChatResponseResource.parseUri(uri);
89
if (!parsed) {
90
throw createFileSystemProviderError(`File not found`, FileSystemProviderErrorCode.FileNotFound);
91
}
92
const { sessionResource, toolCallId, index } = parsed;
93
const session = this.chatService.getSession(sessionResource);
94
if (!session) {
95
throw createFileSystemProviderError(`File not found`, FileSystemProviderErrorCode.FileNotFound);
96
}
97
98
const requests = session.getRequests();
99
for (let k = requests.length - 1; k >= 0; k--) {
100
const req = requests[k];
101
const tc = req.response?.entireResponse.value.find((r): r is IChatToolInvocation | IChatToolInvocationSerialized => (r.kind === 'toolInvocation' || r.kind === 'toolInvocationSerialized') && r.toolCallId === toolCallId);
102
if (tc) {
103
return { result: tc, index };
104
}
105
}
106
107
throw createFileSystemProviderError(`File not found`, FileSystemProviderErrorCode.FileNotFound);
108
}
109
110
private lookupURI(uri: URI): Uint8Array | Promise<Uint8Array> {
111
const { result, index } = this.findMatchingInvocation(uri);
112
const details = IChatToolInvocation.resultDetails(result);
113
if (!isToolResultInputOutputDetails(details)) {
114
throw createFileSystemProviderError(`Tool does not have I/O`, FileSystemProviderErrorCode.FileNotFound);
115
}
116
117
const part = details.output.at(index);
118
if (!part) {
119
throw createFileSystemProviderError(`Tool does not have part`, FileSystemProviderErrorCode.FileNotFound);
120
}
121
122
if (part.type === 'ref') {
123
return this._fileService.readFile(part.uri).then(r => r.value.buffer);
124
}
125
126
return part.isText ? new TextEncoder().encode(part.value) : decodeBase64(part.value).buffer;
127
}
128
}
129
130