Path: blob/main/src/vs/workbench/contrib/chat/common/chatResponseResourceFileSystemProvider.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { decodeBase64, VSBuffer } from '../../../../base/common/buffer.js';6import { Event } from '../../../../base/common/event.js';7import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';8import { newWriteableStream, ReadableStreamEvents } from '../../../../base/common/stream.js';9import { URI } from '../../../../base/common/uri.js';10import { createFileSystemProviderError, FileSystemProviderCapabilities, FileSystemProviderErrorCode, FileType, IFileService, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileReadWriteCapability, IStat } from '../../../../platform/files/common/files.js';11import { IWorkbenchContribution } from '../../../common/contributions.js';12import { ChatResponseResource } from './chatModel.js';13import { IChatService, IChatToolInvocation, IChatToolInvocationSerialized } from './chatService.js';14import { isToolResultInputOutputDetails } from './languageModelToolsService.js';1516export class ChatResponseResourceFileSystemProvider extends Disposable implements17IWorkbenchContribution,18IFileSystemProviderWithFileReadWriteCapability,19IFileSystemProviderWithFileAtomicReadCapability,20IFileSystemProviderWithFileReadStreamCapability {2122public static readonly ID = 'workbench.contrib.chatResponseResourceFileSystemProvider';2324public readonly onDidChangeCapabilities = Event.None;25public readonly onDidChangeFile = Event.None;2627public readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.None28| FileSystemProviderCapabilities.Readonly29| FileSystemProviderCapabilities.PathCaseSensitive30| FileSystemProviderCapabilities.FileReadStream31| FileSystemProviderCapabilities.FileAtomicRead32| FileSystemProviderCapabilities.FileReadWrite;3334constructor(35@IChatService private readonly chatService: IChatService,36@IFileService private readonly _fileService: IFileService37) {38super();39this._register(this._fileService.registerProvider(ChatResponseResource.scheme, this));40}4142readFile(resource: URI): Promise<Uint8Array> {43return Promise.resolve(this.lookupURI(resource));44}4546readFileStream(resource: URI): ReadableStreamEvents<Uint8Array> {47const stream = newWriteableStream<Uint8Array>(data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer);48Promise.resolve(this.lookupURI(resource)).then(v => stream.end(v));49return stream;50}5152async stat(resource: URI): Promise<IStat> {53const r = await this.lookupURI(resource);54return {55type: FileType.File,56ctime: 0,57mtime: 0,58size: r.length,59};60}6162delete(): Promise<void> {63throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);64}6566watch(): IDisposable {67return Disposable.None;68}6970mkdir(): Promise<void> {71throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);72}7374readdir(): Promise<[string, FileType][]> {75return Promise.resolve([]);76}7778rename(): Promise<void> {79throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);80}8182writeFile(): Promise<void> {83throw createFileSystemProviderError('fs is readonly', FileSystemProviderErrorCode.NoPermissions);84}8586private lookupURI(uri: URI): Uint8Array | Promise<Uint8Array> {87const parsed = ChatResponseResource.parseUri(uri);88if (!parsed) {89throw createFileSystemProviderError(`File not found`, FileSystemProviderErrorCode.FileNotFound);90}91const { sessionId, requestId, toolCallId } = parsed;92const result = this.chatService.getSession(sessionId)93?.getRequests()94.find(r => r.id === requestId)95?.response?.entireResponse.value96.find((r): r is IChatToolInvocation | IChatToolInvocationSerialized => (r.kind === 'toolInvocation' || r.kind === 'toolInvocationSerialized') && r.toolCallId === toolCallId);9798if (!result) {99throw createFileSystemProviderError(`File not found`, FileSystemProviderErrorCode.FileNotFound);100}101102if (!isToolResultInputOutputDetails(result.resultDetails)) {103throw createFileSystemProviderError(`Tool does not have I/O`, FileSystemProviderErrorCode.FileNotFound);104}105106const part = result.resultDetails.output.at(parsed.index);107if (!part) {108throw createFileSystemProviderError(`Tool does not have part`, FileSystemProviderErrorCode.FileNotFound);109}110111if (part.type === 'ref') {112return this._fileService.readFile(part.uri).then(r => r.value.buffer);113}114115return part.isText ? new TextEncoder().encode(part.value) : decodeBase64(part.value).buffer;116}117}118119120