Skip to content

Commit cd1487b

Browse files
authored
nes: refactor prompt construction for extensibility (#1241)
* nes: refactor: get config from within computeEditWindowLinesRange * nes: refactor: tagging * nes: refactor: extract tagging current file into its own method * nes: refactor: keep active document props in a single object * nes: refactor: extract cursorLineOffset * nes: refactor: more refactoring * nes: extract language context computation side effect that we now always await not when language context is enabled * nes: refactor: move CurrentDocument to common/ * nes: refactor: abstract constructing messages * nes: fix off by one
1 parent dccb635 commit cd1487b

File tree

5 files changed

+273
-121
lines changed

5 files changed

+273
-121
lines changed

src/extension/xtab/common/promptCrafting.ts

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,29 @@ import { StringText } from '../../../util/vs/editor/common/core/text/abstractTex
2020
export namespace PromptTags {
2121
export const CURSOR = "<|cursor|>";
2222

23-
export const EDIT_WINDOW = {
24-
start: "<|code_to_edit|>",
25-
end: "<|/code_to_edit|>"
23+
type Tag = {
24+
start: string;
25+
end: string;
2626
};
2727

28-
export const AREA_AROUND = {
29-
start: "<|area_around_code_to_edit|>",
30-
end: "<|/area_around_code_to_edit|>"
31-
};
28+
function createTag(key: string): Tag {
29+
return {
30+
start: `<|${key}|>`,
31+
end: `<|/${key}|>`
32+
};
33+
}
3234

33-
export const CURRENT_FILE = {
34-
start: "<|current_file_content|>",
35-
end: "<|/current_file_content|>"
36-
};
35+
export const EDIT_WINDOW = createTag("code_to_edit");
3736

38-
export const EDIT_HISTORY = {
39-
start: "<|edit_diff_history|>",
40-
end: "<|/edit_diff_history|>"
41-
};
37+
export const AREA_AROUND = createTag("area_around_code_to_edit");
4238

43-
export const RECENT_FILES = {
44-
start: "<|recently_viewed_code_snippets|>",
45-
end: "<|/recently_viewed_code_snippets|>"
46-
};
39+
export const CURRENT_FILE = createTag("current_file_content");
4740

48-
export const RECENT_FILE = {
49-
start: "<|recently_viewed_code_snippet|>",
50-
end: "<|/recently_viewed_code_snippet|>"
51-
};
41+
export const EDIT_HISTORY = createTag("edit_diff_history");
42+
43+
export const RECENT_FILES = createTag("recently_viewed_code_snippets");
44+
45+
export const RECENT_FILE = createTag("recently_viewed_code_snippet");
5246
}
5347

5448
export const systemPromptTemplate = `Your role as an AI assistant is to help developers complete their code tasks by assisting in editing specific sections of code marked by the ${PromptTags.EDIT_WINDOW.start} and ${PromptTags.EDIT_WINDOW.end} tags, while adhering to Microsoft's content policies and avoiding the creation of content that violates copyrights.
@@ -671,40 +665,62 @@ function expandRangeToPageRange(
671665
return { firstPageIdx, lastPageIdx, budgetLeft: tokenBudget };
672666
}
673667

674-
/**
675-
* @remark exported for testing
676-
*/
677-
export function createTaggedCurrentFileContentUsingPagedClipping(
678-
currentDocLines: string[],
679-
areaAroundCodeToEdit: string,
680-
areaAroundEditWindowLinesRange: OffsetRange,
668+
export function clipPreservingRange(
669+
docLines: string[],
670+
rangeToPreserve: OffsetRange,
681671
computeTokens: (s: string) => number,
682672
pageSize: number,
683-
opts: CurrentFileOptions
684-
): Result<{ taggedCurrentFileContent: string; nLines: number }, 'outOfBudget'> {
673+
opts: CurrentFileOptions,
674+
): Result<OffsetRange, 'outOfBudget'> {
685675

686-
// subtract budget consumed by areaAroundCodeToEdit
687-
const availableTokenBudget = opts.maxTokens - countTokensForLines(areaAroundCodeToEdit.split(/\r?\n/), computeTokens);
676+
// subtract budget consumed by rangeToPreserve
677+
const availableTokenBudget = opts.maxTokens - countTokensForLines(docLines.slice(rangeToPreserve.start, rangeToPreserve.endExclusive), computeTokens);
688678
if (availableTokenBudget < 0) {
689679
return Result.error('outOfBudget');
690680
}
691681

692682
const { firstPageIdx, lastPageIdx } = expandRangeToPageRange(
693-
currentDocLines,
694-
areaAroundEditWindowLinesRange,
683+
docLines,
684+
rangeToPreserve,
695685
pageSize,
696686
availableTokenBudget,
697687
computeTokens,
698688
opts.prioritizeAboveCursor,
699689
);
700690

701691
const linesOffsetStart = firstPageIdx * pageSize;
702-
const linesOffsetEnd = lastPageIdx * pageSize + pageSize;
692+
const linesOffsetEndExcl = lastPageIdx * pageSize + pageSize;
693+
694+
return Result.ok(new OffsetRange(linesOffsetStart, linesOffsetEndExcl));
695+
}
696+
697+
export function createTaggedCurrentFileContentUsingPagedClipping(
698+
currentDocLines: string[],
699+
areaAroundCodeToEdit: string,
700+
areaAroundEditWindowLinesRange: OffsetRange,
701+
computeTokens: (s: string) => number,
702+
pageSize: number,
703+
opts: CurrentFileOptions
704+
): Result<{ taggedCurrentFileContent: string; nLines: number }, 'outOfBudget'> {
705+
706+
const r = clipPreservingRange(
707+
currentDocLines,
708+
areaAroundEditWindowLinesRange,
709+
computeTokens,
710+
pageSize,
711+
opts
712+
);
713+
714+
if (r.isError()) {
715+
return Result.error('outOfBudget');
716+
}
717+
718+
const clippedRange = r.val;
703719

704720
const taggedCurrentFileContent = [
705-
...currentDocLines.slice(linesOffsetStart, areaAroundEditWindowLinesRange.start),
721+
...currentDocLines.slice(clippedRange.start, areaAroundEditWindowLinesRange.start),
706722
areaAroundCodeToEdit,
707-
...currentDocLines.slice(areaAroundEditWindowLinesRange.endExclusive, linesOffsetEnd),
723+
...currentDocLines.slice(areaAroundEditWindowLinesRange.endExclusive, clippedRange.endExclusive),
708724
];
709725

710726
return Result.ok({ taggedCurrentFileContent: taggedCurrentFileContent.join('\n'), nLines: taggedCurrentFileContent.length });
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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 { Position } from '../../../util/vs/editor/common/core/position';
7+
import { StringText } from '../../../util/vs/editor/common/core/text/abstractText';
8+
import { PositionOffsetTransformer } from '../../../util/vs/editor/common/core/text/positionToOffsetImpl';
9+
10+
export class CurrentDocument {
11+
12+
public readonly lines: string[];
13+
public readonly cursorOffset: number;
14+
15+
public readonly transformer: PositionOffsetTransformer;
16+
17+
/**
18+
* The 0-based line number of the cursor.
19+
*/
20+
public readonly cursorLineOffset: number;
21+
22+
constructor(
23+
public readonly content: StringText,
24+
public readonly cursorPosition: Position,
25+
) {
26+
this.lines = content.getLines();
27+
this.transformer = content.getTransformer();
28+
this.cursorOffset = this.transformer.getOffset(cursorPosition);
29+
this.cursorLineOffset = this.cursorPosition.lineNumber - 1;
30+
}
31+
}

0 commit comments

Comments
 (0)