Path: blob/main/extensions/copilot/src/extension/prompts/node/test/summarizeDocumentPlayground.ts
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 { OverlayNode } from '../../../../platform/parser/node/nodes';6import { DisposableStore } from '../../../../util/vs/base/common/lifecycle';7import { autorun, derived, IObservable, observableFromPromise, observableValue, transaction } from '../../../../util/vs/base/common/observable';8import { isDefined } from '../../../../util/vs/base/common/types';9import { Range } from '../../../../vscodeTypes';10import { IProjectedDocumentDebugInfo } from '../inline/summarizedDocument/implementation';1112export class SummarizeDocumentPlayground {13private readonly _text = observableValue<string>(this, '');14private readonly _range = observableValue<Range>(this, new Range(0, 0, 0, 0));15private readonly _charLimit = observableValue<number>(this, 10);1617private readonly _initialResult = observableValue<IProjectedDocumentDebugInfo | undefined>(this, undefined);1819constructor(20result: IProjectedDocumentDebugInfo,21initialRange: Range,22initialCharLimit: number,23private readonly _getUpdatedStructure: (text: string) => Promise<OverlayNode | undefined>,24private readonly _getUpdatedResult: (text: string, charLimit: number, selection: Range, structure: OverlayNode) => IProjectedDocumentDebugInfo,2526) {27transaction(tx => {28this._initialResult.set(result, tx);29this._text.set(result.originalText, tx);30this._range.set(initialRange, tx);31this._charLimit.set(initialCharLimit, tx);32});33}3435get inputDocument(): ITextRangeDoc {36return {37...{ $fileExtension: 'textRange.w' },38text: this._text.get(),39range: {40start: { lineNumber: this._range.get().start.line + 1, column: this._range.get().start.character + 1 },41end: { lineNumber: this._range.get().end.line + 1, column: this._range.get().end.character + 1 },42}43};44}4546set inputDocument(value: ITextRangeDoc) {47transaction(tx => {48this._initialResult.set(undefined, tx);49this._text.set(value.text, tx);50this._range.set(new Range(value.range.start.lineNumber - 1, value.range.start.column - 1, value.range.end.lineNumber - 1, value.range.end.column - 1), tx);51});52}5354get inputOptions(): IJsonUiDoc<{ charLimit: number }> {55return {56...{ $fileExtension: 'jsonUi.w' },57value: { charLimit: this._charLimit.get() },58'schema': {59'title': 'data',60'type': 'object',61'properties': {62'charLimit': {63'type': 'number',64'format': 'range',65'default': 500,66'minimum': 0,67'maximum': 10000,68'step': 169}70}71},72};73}7475set inputOptions(value: IJsonUiDoc<{ charLimit: number }>) {76transaction(tx => {77this._initialResult.set(undefined, tx);78this._charLimit.set(value.value.charLimit, tx);79});80}8182private readonly _structure = derived(this, reader => {83return observableFromPromise(this._getUpdatedStructure(this._text.read(reader)));84});8586private readonly _store = new DisposableStore();8788private readonly _result = derived(this, reader => {89const r = this._initialResult.read(reader);90if (r) { return r; }9192const structure = this._structure.read(reader).read(reader).value;93if (!structure) { return undefined; }94return this._getUpdatedResult(this._text.read(reader), this._charLimit.read(reader), this._range.read(reader), structure);95}).keepObserved(this._store);9697getAst() {98return waitForStateOrReturn(this._result.map(r => !r ? undefined : r.getVisualization?.()), isDefined);99}100101getSummarizedText() {102return waitForStateOrReturn(this._result.map(r => !r ? undefined : r.text), isDefined);103}104}105106/**107* If the value is ready, returns the value directly (without a promise).108* If the value is not ready, returns a promise of the value.109*110* This allows consumers to use the value synchronously if it is already available.111*/112export function waitForStateOrReturn<T, TState extends T>(observable: IObservable<T>, predicate: (state: T) => state is TState): Promise<TState> | TState;113export function waitForStateOrReturn<T>(observable: IObservable<T>, predicate: (state: T) => boolean): Promise<T> | T;114export function waitForStateOrReturn<T>(observable: IObservable<T>, predicate: (state: T) => boolean): Promise<T> | T {115let result: T | undefined;116let didRunImmediately = false;117118const p = new Promise<T>(resolve => {119let shouldDispose = false;120const stateObs = observable.map(state => ({ isFinished: predicate(state), state }));121let didRun = false;122const d = autorun(reader => {123/** @description waitForState */124const { isFinished, state } = stateObs.read(reader);125if (isFinished) {126if (!didRun) {127shouldDispose = true;128} else {129d.dispose();130}131result = state;132didRunImmediately = true;133resolve(state);134}135});136didRun = true;137if (shouldDispose) {138d.dispose();139}140});141142if (didRunImmediately) {143return result!;144} else {145return p;146}147}148149interface IJsonUiDoc<T = unknown> {150value: T;151schema: unknown;152}153154interface ITextRangeDoc {155text: string;156range: { start: IPosition; end: IPosition };157}158159interface IPosition {160lineNumber: number;161column: number;162}163164165