allow speculative requests to be initiated using chat-lib (#2591)

This commit is contained in:
Jeff Hunter
2025-12-16 10:52:05 -05:00
committed by GitHub
parent a2fd2580ef
commit c5285fa9f8
2 changed files with 44 additions and 3 deletions

View File

@@ -28,6 +28,8 @@ import { ChatRequest } from '../src/_internal/vscodeTypes';
import { createInlineCompletionsProvider, IActionItem, IAuthenticationService, ICompletionsStatusChangedEvent, ICompletionsTextDocumentManager, IEndpointProvider, ILogTarget, ITelemetrySender, LogLevel } from '../src/main';
class TestFetcher implements IFetcher {
private _fetched = new Map<string, number>();
constructor(private readonly responses: Record<string, string>) { }
getUserAgentLibrary(): string {
@@ -36,6 +38,7 @@ class TestFetcher implements IFetcher {
async fetch(url: string, options: FetchOptions): Promise<Response> {
const uri = URI.parse(url);
this._markFetched(uri.path);
const responseText = this.responses[uri.path];
const headers = new class implements IHeaders {
@@ -59,6 +62,15 @@ class TestFetcher implements IFetcher {
);
}
private _markFetched(urlPath: string): void {
const count = this.fetchCount(urlPath);
this._fetched.set(urlPath, count + 1);
}
fetchCount(urlPath: string): number {
return this._fetched.get(urlPath) || 0;
}
fetchWithPagination<T>(baseUrl: string, options: PaginationOptions<T>): Promise<T[]> {
throw new Error('Method not implemented.');
}
@@ -195,9 +207,14 @@ class NullLogTarget implements ILogTarget {
}
describe('getInlineCompletions', () => {
it('should return completions for a document and position', async () => {
const provider = createInlineCompletionsProvider({
fetcher: new TestFetcher({ '/v1/engines/gpt-41-copilot/completions': await readFile(join(__dirname, 'getInlineCompletions.reply.txt'), 'utf8') }),
const completionsPath = '/v1/engines/gpt-41-copilot/completions';
let fetcher: TestFetcher;
async function getCompletionsProvider() {
fetcher = new TestFetcher({ [completionsPath]: await readFile(join(__dirname, 'getInlineCompletions.reply.txt'), 'utf8') });
return createInlineCompletionsProvider({
fetcher,
authService: new TestAuthService(),
telemetrySender: new TestTelemetrySender(),
logTarget: new NullLogTarget(),
@@ -221,6 +238,10 @@ describe('getInlineCompletions', () => {
},
endpointProvider: new TestEndpointProvider(),
});
}
it('should return completions for a document and position', async () => {
const provider = await getCompletionsProvider();
const doc = createTextDocument('file:///test.txt', 'javascript', 1, 'function main() {\n\n}\n');
const result = await provider.getInlineCompletions(doc, { line: 1, character: 0 });
@@ -230,4 +251,18 @@ describe('getInlineCompletions', () => {
expect(result[0].resultType).toBe(ResultType.Async);
expect(result[0].displayText).toBe(' console.log("Hello, World!");');
});
it('makes any pending speculative requests when a completion is shown', async () => {
const provider = await getCompletionsProvider();
const doc = createTextDocument('file:///test.txt', 'javascript', 1, 'function main() {\n\n}\n');
const result = await provider.getInlineCompletions(doc, { line: 1, character: 0 });
assert(result);
expect(result.length).toBe(1);
await provider.inlineCompletionShown(result[0].clientCompletionId);
expect(fetcher.fetchCount(completionsPath)).toBe(2);
});
});

View File

@@ -628,6 +628,7 @@ export type IGetInlineCompletionsOptions = Exclude<Partial<GetGhostTextOptions>,
export interface IInlineCompletionsProvider {
updateTreatmentVariables(variables: Record<string, boolean | number | string>): void;
getInlineCompletions(textDocument: ITextDocument, position: Position, token?: CancellationToken, options?: IGetInlineCompletionsOptions): Promise<CopilotCompletion[] | undefined>;
inlineCompletionShown(completionId: string): Promise<void>;
dispose(): void;
}
@@ -643,6 +644,7 @@ class InlineCompletionsProvider extends Disposable implements IInlineCompletions
constructor(
@IInstantiationService private _insta: IInstantiationService,
@IExperimentationService private readonly _expService: IExperimentationService,
@ICompletionsSpeculativeRequestCache private readonly _speculativeRequestCache: ICompletionsSpeculativeRequestCache,
) {
super();
@@ -659,6 +661,10 @@ class InlineCompletionsProvider extends Disposable implements IInlineCompletions
async getInlineCompletions(textDocument: ITextDocument, position: Position, token?: CancellationToken, options?: IGetInlineCompletionsOptions): Promise<CopilotCompletion[] | undefined> {
return await this.ghostText.getInlineCompletions(textDocument, position, token, options);
}
async inlineCompletionShown(completionId: string): Promise<void> {
return await this._speculativeRequestCache.request(completionId);
}
}
class UnwrappingTelemetrySender implements ITelemetrySender {