Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export function getUserPrompt(promptPieces: PromptPieces): UserPromptResult {
case PromptingStrategy.PatchBased02:
case PromptingStrategy.PatchBased02WithRecentLineNumbers:
case PromptingStrategy.PatchBased02Unified:
case PromptingStrategy.PatchBased02UnifiedEagerness:
case PromptingStrategy.PatchBased02WithoutRecentLineNumbers: {
const currentDocument = promptPieces.currentDocument;
const cursorLine = currentDocument.lineWithCursor();
Expand Down Expand Up @@ -177,6 +178,7 @@ export function getUserPrompt(promptPieces: PromptPieces): UserPromptResult {
opts.promptingStrategy !== PromptingStrategy.PatchBased02 &&
opts.promptingStrategy !== PromptingStrategy.PatchBased02WithRecentLineNumbers &&
opts.promptingStrategy !== PromptingStrategy.PatchBased02Unified &&
opts.promptingStrategy !== PromptingStrategy.PatchBased02UnifiedEagerness &&
opts.promptingStrategy !== PromptingStrategy.PatchBased02WithoutRecentLineNumbers;

const packagedPrompt = includeBackticks ? wrapInBackticks(mainPrompt) : mainPrompt;
Expand Down Expand Up @@ -382,6 +384,7 @@ function getPostScript(options: PromptOptions, currentFilePath: string, aggressi
case PromptingStrategy.PatchBased02:
case PromptingStrategy.PatchBased02WithRecentLineNumbers:
case PromptingStrategy.PatchBased02Unified:
case PromptingStrategy.PatchBased02UnifiedEagerness:
case PromptingStrategy.PatchBased02WithoutRecentLineNumbers:
postScript = eagernessPrompt === 'aggressionHighLow'
? aggressivenessLevel === AggressivenessLevel.Medium
Expand Down
1 change: 1 addition & 0 deletions extensions/copilot/src/extension/xtab/node/xtabProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,7 @@ export function pickSystemPrompt(promptingStrategy: xtabPromptOptions.PromptingS
case xtabPromptOptions.PromptingStrategy.PatchBased02:
case xtabPromptOptions.PromptingStrategy.PatchBased02WithRecentLineNumbers:
case xtabPromptOptions.PromptingStrategy.PatchBased02Unified:
case xtabPromptOptions.PromptingStrategy.PatchBased02UnifiedEagerness:
case xtabPromptOptions.PromptingStrategy.PatchBased02WithoutRecentLineNumbers:
case xtabPromptOptions.PromptingStrategy.Xtab275:
case xtabPromptOptions.PromptingStrategy.XtabAggressiveness:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,32 @@ describe('getUserPrompt', () => {
}
});

test.each([
[AggressivenessLevel.Medium, ''],
[AggressivenessLevel.High, '<|aggression|>high<|/aggression|>'],
[AggressivenessLevel.Low, '<|aggression|>low<|/aggression|>'],
])('PatchBased02UnifiedEagerness places the %s eagerness tag before the postscript', (aggressivenessLevel, eagernessTag) => {
const pieces = createTestPromptPieces({
cursorLine: 2,
cursorColumn: 9,
strategy: PromptingStrategy.PatchBased02UnifiedEagerness,
eagernessPrompt: 'aggressionHighLow',
aggressivenessLevel,
});
const { prompt } = getUserPrompt(pieces);

const cursorLocation = `${PromptTags.CURSOR_LOCATION.start}\n const ${PromptTags.CURSOR}x = 1;\n${PromptTags.CURSOR_LOCATION.end}`;
const postScript = 'The developer was working on a section of code within the `current_file_content`';
expect(prompt).toContain(cursorLocation);
expect(prompt.indexOf(cursorLocation)).toBeLessThan(prompt.indexOf(postScript));
if (aggressivenessLevel === AggressivenessLevel.Medium) {
expect(prompt).not.toContain('<|aggression|>');
expect(prompt).toContain(`${PromptTags.CURSOR_LOCATION.end}\n\n${postScript}`);
} else {
expect(prompt).toContain(`${PromptTags.CURSOR_LOCATION.end}\n\n${eagernessTag}\n\n${postScript}`);
}
});

describe('Xtab275AggressivenessHighLow', () => {
test('medium level does not include aggressive tag', () => {
const pieces = createTestPromptPieces({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ describe('pickSystemPrompt', () => {
PromptingStrategy.PatchBased02,
PromptingStrategy.PatchBased02WithRecentLineNumbers,
PromptingStrategy.PatchBased02Unified,
PromptingStrategy.PatchBased02UnifiedEagerness,
PromptingStrategy.PatchBased02WithoutRecentLineNumbers,
PromptingStrategy.Xtab275,
PromptingStrategy.XtabAggressiveness,
Expand Down Expand Up @@ -275,6 +276,18 @@ describe('overrideModelConfig', () => {
expect(result.diffHistory).toEqual(base.diffHistory);
});

it('propagates the eagerness prompt from model configuration', () => {
const result = overrideModelConfig(makeBaseModelConfig(), {
modelName: 'four-in-one-model',
promptingStrategy: PromptingStrategy.PatchBased02UnifiedEagerness,
eagernessPrompt: 'aggressionHighLow',
includeTagsInCurrentFile: false,
lintOptions: undefined,
});

expect(result.eagernessPrompt).toBe('aggressionHighLow');
});

it('merges lintOptions when overridingConfig has lintOptions', () => {
const testLintOptions = { tagName: 'lint', warnings: LintOptionWarning.YES, showCode: LintOptionShowCode.YES, maxLints: 5, maxLineDistance: 10, nRecentFiles: 0 };
const base: ModelConfig = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,8 @@ export enum PromptingStrategy {
* completions itself: it bakes in the client and latency knobs that treatment was tuned for.
*/
PatchBased02Unified = 'patchBased02Unified',
/** PatchBased02 unified variant trained for eagerness prompting. */
PatchBased02UnifiedEagerness = 'patchBased02UnifiedEagerness',
/** PatchBased02 variant: no line numbers on recent docs. */
PatchBased02WithoutRecentLineNumbers = 'patchBased02WithoutRecentLineNumbers',
/**
Expand Down Expand Up @@ -574,6 +576,8 @@ export function isEagernessPrompt(options: PromptOptions): boolean {
return (options.eagernessPrompt !== undefined && [
PromptingStrategy.PatchBased02,
PromptingStrategy.PatchBased02WithRecentLineNumbers,
PromptingStrategy.PatchBased02Unified,
PromptingStrategy.PatchBased02UnifiedEagerness,
PromptingStrategy.PatchBased02WithoutRecentLineNumbers,
].includes(options.promptingStrategy)) // eagerness prompt option is only supported for patch-based strategies
|| [PromptingStrategy.XtabAggressiveness,
Expand Down Expand Up @@ -614,6 +618,7 @@ export namespace ResponseFormat {
case PromptingStrategy.PatchBased02:
case PromptingStrategy.PatchBased02WithRecentLineNumbers:
case PromptingStrategy.PatchBased02Unified:
case PromptingStrategy.PatchBased02UnifiedEagerness:
case PromptingStrategy.PatchBased02WithoutRecentLineNumbers:
return ResponseFormat.CustomDiffPatch;
case PromptingStrategy.Xtab275EditIntent:
Expand Down Expand Up @@ -803,6 +808,19 @@ const PATCH_BASED_02_WITH_RECENT_LINE_NUMBERS_CONFIG: Partial<ModelConfiguration
allowImportChanges: ImportChanges.All,
};

const PATCH_BASED_02_UNIFIED_CONFIG: Partial<ModelConfiguration> = {
...PATCH_BASED_02_WITH_RECENT_LINE_NUMBERS_CONFIG,
patchModelPredictionKind: PatchModelPrediction.CurrentLineCompleted,
splitPatchOnDiff: true,
patchFastYieldLineWithCursor: true,
extraDebounceEndOfLine: 0,
nesMimicGhostTextBehavior: true,
cacheDelay: 200,
rebasedCacheDelay: 0,
debounce: 0,
supportsUnifiedCompletions: true,
};

const STRATEGY_CONFIG: Partial<Record<PromptingStrategy, Partial<ModelConfiguration>>> = {
// proxy /models doesn't know about includeTagsInCurrentFile field as of now, so hard-code it for CopilotNesXtab
[PromptingStrategy.CopilotNesXtab]: {
Expand All @@ -811,18 +829,7 @@ const STRATEGY_CONFIG: Partial<Record<PromptingStrategy, Partial<ModelConfigurat
[PromptingStrategy.PatchBased02WithRecentLineNumbers]: PATCH_BASED_02_WITH_RECENT_LINE_NUMBERS_CONFIG,
// Inherits everything from PatchBased02WithRecentLineNumbers and additionally bakes in the
// client/latency knobs that this unified model was tuned to run with.
[PromptingStrategy.PatchBased02Unified]: {
...PATCH_BASED_02_WITH_RECENT_LINE_NUMBERS_CONFIG,
patchModelPredictionKind: PatchModelPrediction.CurrentLineCompleted,
splitPatchOnDiff: true,
patchFastYieldLineWithCursor: true,
extraDebounceEndOfLine: 0,
nesMimicGhostTextBehavior: true,
cacheDelay: 200,
rebasedCacheDelay: 0,
debounce: 0,
supportsUnifiedCompletions: true,
},
[PromptingStrategy.PatchBased02Unified]: PATCH_BASED_02_UNIFIED_CONFIG,
[PromptingStrategy.PatchBased02WithoutRecentLineNumbers]: {
includeTagsInCurrentFile: false,
includePostScript: true,
Expand All @@ -831,6 +838,10 @@ const STRATEGY_CONFIG: Partial<Record<PromptingStrategy, Partial<ModelConfigurat
supportsNextCursorLinePrediction: false,
allowImportChanges: ImportChanges.All,
},
[PromptingStrategy.PatchBased02UnifiedEagerness]: {
...PATCH_BASED_02_UNIFIED_CONFIG,
eagernessPrompt: 'aggressionHighLow',
},
};

/** Apply per-strategy baked-in config; strategy values override `config`. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ describe('applyStrategyConfig', () => {
expect(result.currentFile?.includeLineNumbers).toBe(IncludeLineNumbersOption.WithoutSpace);
});

it('matches PatchBased02Unified config except for the eagerness prompt', () => {
const unified = applyStrategyConfig(baseConfig({
promptingStrategy: PromptingStrategy.PatchBased02Unified,
}));
const eagerness = applyStrategyConfig(baseConfig({
promptingStrategy: PromptingStrategy.PatchBased02UnifiedEagerness,
}));

expect(eagerness).toEqual({
...unified,
promptingStrategy: PromptingStrategy.PatchBased02UnifiedEagerness,
eagernessPrompt: 'aggressionHighLow',
});
});

it('preserves undefined for option bags neither side specifies', () => {
const result = applyStrategyConfig(baseConfig({
promptingStrategy: PromptingStrategy.CopilotNesXtab,
Expand Down Expand Up @@ -159,6 +174,27 @@ describe('isEagernessPrompt', () => {
expect(isEagernessPrompt({ ...DEFAULT_OPTIONS, promptingStrategy: PromptingStrategy.PatchBased02, eagernessPrompt: 'aggressionHighLow' })).toBe(true);
expect(isEagernessPrompt({ ...DEFAULT_OPTIONS, promptingStrategy: PromptingStrategy.PatchBased02 })).toBe(false);
});

it('recognizes the optimized PatchBased02 aggression prompt option', () => {
expect(isEagernessPrompt({ ...DEFAULT_OPTIONS, promptingStrategy: PromptingStrategy.PatchBased02Unified, eagernessPrompt: 'aggressionHighLow' })).toBe(true);
expect(isEagernessPrompt({ ...DEFAULT_OPTIONS, promptingStrategy: PromptingStrategy.PatchBased02Unified })).toBe(false);
});

it('does not recognize eagerness for an unrelated strategy', () => {
expect(isEagernessPrompt({ ...DEFAULT_OPTIONS, promptingStrategy: PromptingStrategy.CopilotNesXtab, eagernessPrompt: 'aggressionHighLow' })).toBe(false);
});

it('recognizes the standalone eagerness strategy after strategy config is applied', () => {
const config = applyStrategyConfig(baseConfig({
promptingStrategy: PromptingStrategy.PatchBased02UnifiedEagerness,
}));
const options = {
...DEFAULT_OPTIONS,
promptingStrategy: config.promptingStrategy,
eagernessPrompt: config.eagernessPrompt,
};
expect(isEagernessPrompt(options)).toBe(true);
});
});

describe('GlobalBudgetOptions', () => {
Expand Down
Loading