Path: blob/main/extensions/copilot/src/platform/requestLogger/node/requestLogger.ts
13401 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 type { RequestMetadata } from '@vscode/copilot-api';6import { HTMLTracer, IChatEndpointInfo, RenderPromptResult } from '@vscode/prompt-tsx';7import { AsyncLocalStorage } from 'async_hooks';8import type { Event } from 'vscode';9import type { LanguageModelToolResult2 } from '../../../vscodeTypes';10import type { IModelAPIResponse } from '../../endpoint/common/endpointProvider';11import { CapturingToken } from '../common/capturingToken';12import { ILoggedPendingRequest, IRequestLogger, LoggedInfo, LoggedRequest, PendingLoggedChatRequest } from '../common/requestLogger';13import { Disposable } from '../../../util/vs/base/common/lifecycle';14import { IChatEndpoint } from '../../../platform/networking/common/networking';1516const requestLogStorage = new AsyncLocalStorage<CapturingToken>();1718/**19* Correlation map for preserving CapturingToken across IPC boundaries.20*21* When requests cross the VS Code IPC boundary (e.g., BYOK providers),22* AsyncLocalStorage context is lost. This map allows correlating requests23* by storing the token before IPC and retrieving it on the other side.24*/25const capturingTokenCorrelationMap = new Map<string, CapturingToken>();2627/**28* Get the current CapturingToken from AsyncLocalStorage.29* Returns undefined if not within a captureInvocation context.30*/31export function getCurrentCapturingToken(): CapturingToken | undefined {32return requestLogStorage.getStore();33}3435/**36* Store the current CapturingToken with a correlation ID for cross-IPC retrieval.37* Call this before making a request that will cross IPC boundaries.38*/39export function storeCapturingTokenForCorrelation(correlationId: string): void {40const token = requestLogStorage.getStore();41if (token) {42capturingTokenCorrelationMap.set(correlationId, token);43}44}4546/**47* Retrieve and remove a CapturingToken by correlation ID.48* Returns undefined if no token was stored for this ID.49*/50export function retrieveCapturingTokenByCorrelation(correlationId: string): CapturingToken | undefined {51const token = capturingTokenCorrelationMap.get(correlationId);52if (token) {53capturingTokenCorrelationMap.delete(correlationId);54}55return token;56}5758/**59* Run a function within a CapturingToken context without going through IRequestLogger.60* Used to restore context after IPC boundary crossing.61*/62export function runWithCapturingToken<T>(token: CapturingToken, fn: () => T): T {63return requestLogStorage.run(token, fn);64}6566export abstract class AbstractRequestLogger extends Disposable implements IRequestLogger {67declare _serviceBrand: undefined;6869public get promptRendererTracing() {70return false;71}7273public captureInvocation<T>(request: CapturingToken, fn: () => Promise<T>): Promise<T> {74return requestLogStorage.run(request, () => fn());75}7677public abstract logModelListCall(id: string, requestMetadata: RequestMetadata, models: IModelAPIResponse[]): void;78public abstract logToolCall(id: string, name: string | undefined, args: unknown, response: LanguageModelToolResult2): void;7980public logContentExclusionRules(_repos: string[], _rules: { patterns: string[]; ifAnyMatch: string[]; ifNoneMatch: string[] }[], _durationMs: number): void {81// no-op by default; concrete implementations can override82}8384public logChatRequest(debugName: string, chatEndpoint: IChatEndpoint, chatParams: ILoggedPendingRequest): PendingLoggedChatRequest {85return new PendingLoggedChatRequest(this, debugName, chatEndpoint, chatParams);86}8788public abstract addPromptTrace(elementName: string, endpoint: IChatEndpointInfo, result: RenderPromptResult, trace: HTMLTracer): void;89public abstract addEntry(entry: LoggedRequest): void;90public abstract getRequests(): LoggedInfo[];91public abstract getRequestById(id: string): LoggedInfo | undefined;92abstract onDidChangeRequests: Event<void>;9394public enableWorkspaceEditTracing(): void {95// no-op by default; concrete implementations can override96}9798public disableWorkspaceEditTracing(): void {99// no-op by default; concrete implementations can override100}101102/** Current request being made to the LM. */103protected get currentRequest() {104return requestLogStorage.getStore();105}106}107108109