Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/prompts/node/test/summarizeDocumentPlayground.ts
13405 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 { OverlayNode } from '../../../../platform/parser/node/nodes';
7
import { DisposableStore } from '../../../../util/vs/base/common/lifecycle';
8
import { autorun, derived, IObservable, observableFromPromise, observableValue, transaction } from '../../../../util/vs/base/common/observable';
9
import { isDefined } from '../../../../util/vs/base/common/types';
10
import { Range } from '../../../../vscodeTypes';
11
import { IProjectedDocumentDebugInfo } from '../inline/summarizedDocument/implementation';
12
13
export class SummarizeDocumentPlayground {
14
private readonly _text = observableValue<string>(this, '');
15
private readonly _range = observableValue<Range>(this, new Range(0, 0, 0, 0));
16
private readonly _charLimit = observableValue<number>(this, 10);
17
18
private readonly _initialResult = observableValue<IProjectedDocumentDebugInfo | undefined>(this, undefined);
19
20
constructor(
21
result: IProjectedDocumentDebugInfo,
22
initialRange: Range,
23
initialCharLimit: number,
24
private readonly _getUpdatedStructure: (text: string) => Promise<OverlayNode | undefined>,
25
private readonly _getUpdatedResult: (text: string, charLimit: number, selection: Range, structure: OverlayNode) => IProjectedDocumentDebugInfo,
26
27
) {
28
transaction(tx => {
29
this._initialResult.set(result, tx);
30
this._text.set(result.originalText, tx);
31
this._range.set(initialRange, tx);
32
this._charLimit.set(initialCharLimit, tx);
33
});
34
}
35
36
get inputDocument(): ITextRangeDoc {
37
return {
38
...{ $fileExtension: 'textRange.w' },
39
text: this._text.get(),
40
range: {
41
start: { lineNumber: this._range.get().start.line + 1, column: this._range.get().start.character + 1 },
42
end: { lineNumber: this._range.get().end.line + 1, column: this._range.get().end.character + 1 },
43
}
44
};
45
}
46
47
set inputDocument(value: ITextRangeDoc) {
48
transaction(tx => {
49
this._initialResult.set(undefined, tx);
50
this._text.set(value.text, tx);
51
this._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);
52
});
53
}
54
55
get inputOptions(): IJsonUiDoc<{ charLimit: number }> {
56
return {
57
...{ $fileExtension: 'jsonUi.w' },
58
value: { charLimit: this._charLimit.get() },
59
'schema': {
60
'title': 'data',
61
'type': 'object',
62
'properties': {
63
'charLimit': {
64
'type': 'number',
65
'format': 'range',
66
'default': 500,
67
'minimum': 0,
68
'maximum': 10000,
69
'step': 1
70
}
71
}
72
},
73
};
74
}
75
76
set inputOptions(value: IJsonUiDoc<{ charLimit: number }>) {
77
transaction(tx => {
78
this._initialResult.set(undefined, tx);
79
this._charLimit.set(value.value.charLimit, tx);
80
});
81
}
82
83
private readonly _structure = derived(this, reader => {
84
return observableFromPromise(this._getUpdatedStructure(this._text.read(reader)));
85
});
86
87
private readonly _store = new DisposableStore();
88
89
private readonly _result = derived(this, reader => {
90
const r = this._initialResult.read(reader);
91
if (r) { return r; }
92
93
const structure = this._structure.read(reader).read(reader).value;
94
if (!structure) { return undefined; }
95
return this._getUpdatedResult(this._text.read(reader), this._charLimit.read(reader), this._range.read(reader), structure);
96
}).keepObserved(this._store);
97
98
getAst() {
99
return waitForStateOrReturn(this._result.map(r => !r ? undefined : r.getVisualization?.()), isDefined);
100
}
101
102
getSummarizedText() {
103
return waitForStateOrReturn(this._result.map(r => !r ? undefined : r.text), isDefined);
104
}
105
}
106
107
/**
108
* If the value is ready, returns the value directly (without a promise).
109
* If the value is not ready, returns a promise of the value.
110
*
111
* This allows consumers to use the value synchronously if it is already available.
112
*/
113
export function waitForStateOrReturn<T, TState extends T>(observable: IObservable<T>, predicate: (state: T) => state is TState): Promise<TState> | TState;
114
export function waitForStateOrReturn<T>(observable: IObservable<T>, predicate: (state: T) => boolean): Promise<T> | T;
115
export function waitForStateOrReturn<T>(observable: IObservable<T>, predicate: (state: T) => boolean): Promise<T> | T {
116
let result: T | undefined;
117
let didRunImmediately = false;
118
119
const p = new Promise<T>(resolve => {
120
let shouldDispose = false;
121
const stateObs = observable.map(state => ({ isFinished: predicate(state), state }));
122
let didRun = false;
123
const d = autorun(reader => {
124
/** @description waitForState */
125
const { isFinished, state } = stateObs.read(reader);
126
if (isFinished) {
127
if (!didRun) {
128
shouldDispose = true;
129
} else {
130
d.dispose();
131
}
132
result = state;
133
didRunImmediately = true;
134
resolve(state);
135
}
136
});
137
didRun = true;
138
if (shouldDispose) {
139
d.dispose();
140
}
141
});
142
143
if (didRunImmediately) {
144
return result!;
145
} else {
146
return p;
147
}
148
}
149
150
interface IJsonUiDoc<T = unknown> {
151
value: T;
152
schema: unknown;
153
}
154
155
interface ITextRangeDoc {
156
text: string;
157
range: { start: IPosition; end: IPosition };
158
}
159
160
interface IPosition {
161
lineNumber: number;
162
column: number;
163
}
164
165