Path: blob/main/extensions/copilot/src/extension/prompts/node/panel/notebookVariables.tsx
13405 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 { BasePromptElementProps, PromptElement, PromptElementProps, PromptSizing, TextChunk, TokenLimit } from '@vscode/prompt-tsx';6import type * as vscode from 'vscode';7import { ILogService } from '../../../../platform/log/common/logService';8import { parseAndCleanStack } from '../../../../platform/notebook/common/helpers';9import { INotebookService, VariablesResult } from '../../../../platform/notebook/common/notebookService';10import { IPromptPathRepresentationService } from '../../../../platform/prompts/common/promptPathRepresentationService';11import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';12import { getNotebookCellOutput, isJupyterNotebookUri } from '../../../../util/common/notebooks';13import { URI } from '../../../../util/vs/base/common/uri';14import { IPromptEndpoint } from '../base/promptRenderer';15import { Tag } from '../base/tag';16import { getCharLimit } from '../inline/summarizedDocument/summarizeDocumentHelpers';17import { Image } from './image';1819type NotebookVariablesPromptProps = PromptElementProps<{20notebook: vscode.NotebookDocument;21}>;2223interface InlineChatNotebookRuntimeState {24variables: VariablesResult[];25}2627export class NotebookVariables extends PromptElement<NotebookVariablesPromptProps, InlineChatNotebookRuntimeState> {28constructor(29props: NotebookVariablesPromptProps,30@INotebookService private readonly notebookService: INotebookService,31@IPromptPathRepresentationService private readonly _promptPathRepresentationService: IPromptPathRepresentationService,32@ILogService private readonly logger: ILogService,33) {34super(props);35}3637override async prepare(): Promise<InlineChatNotebookRuntimeState> {38try {39this.logger.trace(`Fetching notebook variables for ${this.props.notebook.uri.toString()}`);40const variables = await this.notebookService.getVariables(this.props.notebook.uri);41return { variables };42} catch (error) {43this.logger.error(`Failed to get notebook variables for ${this.props.notebook.uri.toString()}: ${error}`);44return { variables: [] };45}46}4748render(state: InlineChatNotebookRuntimeState) {49const filePath = this._promptPathRepresentationService.getFilePath(this.props.notebook.uri);50const isJupyterNotebook = isJupyterNotebookUri(this.props.notebook.uri);51const notebookType = isJupyterNotebook ? 'Jupyter Notebook' : 'Notebook';52if (state.variables.length === 0) {53return (<></>);54}5556return (57<TokenLimit max={16384}>58<notebook-kernel-variables><br />59{state.variables.length !== 0 &&60<>61The following variables are present in the {notebookType} {filePath}:62{63state.variables.map((variable) => (64<>65<TextChunk>66Name: {variable.variable.name}<br />67{variable.variable.type && <>Type: {variable.variable.type}</>}<br />68</TextChunk>69</>70))7172}73</>}74</notebook-kernel-variables><br />75</TokenLimit>76);77}78}798081export interface INotebookCellOutputProps extends BasePromptElementProps {82outputUri: URI;83}848586export class NotebookCellOutputVariable extends PromptElement<INotebookCellOutputProps> {87constructor(88props: PromptElementProps<INotebookCellOutputProps>,89@IWorkspaceService private readonly workspaceService: IWorkspaceService,90@IPromptPathRepresentationService private readonly promptPathRepresentationService: IPromptPathRepresentationService,91@IPromptEndpoint private readonly promptEndpoint: IPromptEndpoint92) {93super(props);94}9596render(state: void, sizing: PromptSizing) {97const outputUri = this.props.outputUri;98const outputInfo = getNotebookCellOutput(outputUri, this.workspaceService.notebookDocuments);99if (!outputInfo) {100return;101}102const [notebook, cell, notebookCellOutput] = outputInfo;103const outputIndex = cell.outputs.indexOf(notebookCellOutput);104105const allowedTextMimeTypes = ['text/plain', 'text/html', 'text/markdown', 'application/vnd.code.notebook.stdout', 'application/vnd.code.notebook.error', 'application/vnd.code.notebook.stderr'];106const item = notebookCellOutput.items.length ? notebookCellOutput.items[0] : undefined;107if (!item || (!allowedTextMimeTypes.includes(item.mime) && !item.mime.startsWith('image/'))) {108return <></>;109}110let text;111const cellIndex = cell.index;112const notebookPath = this.promptPathRepresentationService.getFilePath(notebook.uri);113if (item.mime === 'image/png') {114if (this.promptEndpoint.supportsVision) {115text = (116<>117<br />118<Tag name={`cell-output`} attrs={{ mimeType: item.mime, outputIndex, cellIndex, notebookPath }}>119<Image variableName={`cell-output-image-${outputIndex}`} variableValue={item.data} />120</Tag>121122</>123);124} else {125text = (<>126<br />127The user attempted to attach an image which is the output from the cell with index: {cellIndex} of the notebook {notebookPath} but128images cannot be sent to this endpoint at this time and is therefore not attached. <br />129<br />130</>);131}132} else {133// force 1/4 of the token budget for text134const textSize = getCharLimit(sizing.tokenBudget / 4);135let textChunk = item.data.toString();136if (item.mime === 'application/vnd.code.notebook.stderr' || item.mime === 'application/vnd.code.notebook.error') {137textChunk = parseAndCleanStack(textChunk);138}139if (textChunk.length > textSize) {140textChunk = textChunk.substring(0, textSize);141}142text = (143<>144<br />145<Tag name={`notebook-cell-output`} attrs={{ mimeType: item.mime, outputIndex, cellIndex, notebookPath }}>146{textChunk}147</Tag>148</>149);150}151return text;152}153}154155//#endregion156157158