Replace requestKind literal strings with RequestKind constant

Collapse the four IBackgroundRequestOptions / ISubagentRequestOptions /
ISummarizationRequestOptions / IMainAgentRequestOptions interfaces into
a single 'as const' object + derived type, matching the existing
ToolName / ContributedToolName pattern in this codebase. Call sites now
use RequestKind.MainAgent etc. instead of hand-typing 'mainagent', so a
future rename only has to update the RequestKind definition.

Compile-time safety is unchanged — IRequestKindOptions.kind is still
typed as the union of literals.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Kevin Kent
2026-04-30 13:51:26 -07:00
co-authored by Copilot
parent 450d3c6d31
commit 26f1db756d
10 changed files with 46 additions and 51 deletions
@@ -17,7 +17,7 @@ import { IOctoKitService } from '../../../platform/github/common/githubService';
import { IIgnoreService } from '../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../platform/log/common/logService';
import { Prediction } from '../../../platform/networking/common/fetch';
import { IChatEndpoint, IMakeChatRequestOptions } from '../../../platform/networking/common/networking';
import { IChatEndpoint, IMakeChatRequestOptions, RequestKind } from '../../../platform/networking/common/networking';
import { IParserService } from '../../../platform/parser/node/parserService';
import { getWasmLanguage } from '../../../platform/parser/node/treeSitterLanguages';
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
@@ -468,7 +468,7 @@ class InlineChatEditToolsStrategy implements IInlineChatEditStrategy {
conversationId: telemetry.sessionId,
messageSource: this._intent.id
},
requestKindOptions: { kind: 'mainagent' },
requestKindOptions: { kind: RequestKind.MainAgent },
finishedCb: async (_text, _index, delta) => {
telemetry.markReceivedToken();
@@ -668,7 +668,7 @@ class InlineChatEditHeuristicStrategy implements IInlineChatEditStrategy {
conversationId: telemetry.sessionId,
messageSource: this._intent.id
},
requestKindOptions: { kind: 'mainagent' },
requestKindOptions: { kind: RequestKind.MainAgent },
requestOptions: {
stream: true,
prediction
@@ -19,7 +19,7 @@ import { IEnvService } from '../../../platform/env/common/envService';
import { ILogService } from '../../../platform/log/common/logService';
import { IEditLogService } from '../../../platform/multiFileEdit/common/editLogService';
import { CUSTOM_TOOL_SEARCH_NAME, isAnthropicContextEditingEnabled } from '../../../platform/networking/common/anthropic';
import { IChatEndpoint } from '../../../platform/networking/common/networking';
import { IChatEndpoint, RequestKind } from '../../../platform/networking/common/networking';
import { modelsWithoutResponsesContextManagement } from '../../../platform/networking/common/openai';
import { INotebookService } from '../../../platform/notebook/common/notebookService';
import { GenAiMetrics } from '../../../platform/otel/common/genAiMetrics';
@@ -864,7 +864,7 @@ export class AgentIntentInvocation extends EditCodeIntentInvocation implements I
modelCapabilities,
telemetryProperties: associatedRequestId ? { associatedRequestId } : undefined,
enableRetryOnFilter: true,
requestKindOptions: { kind: 'summarization' },
requestKindOptions: { kind: RequestKind.Summarization },
}, bgToken);
if (response.type !== ChatFetchResponseType.Success) {
throw new Error(`Background inline summarization request failed: ${response.type}`);
@@ -21,7 +21,7 @@ import { getResponsesApiCompactionThresholdFromBody, OpenAIResponsesProcessor, r
import { collectSingleLineErrorMessage, ILogService } from '../../../platform/log/common/logService';
import { FinishedCallback, getRequestId, IResponseDelta, OptionalChatRequestParams, RequestId } from '../../../platform/networking/common/fetch';
import { FetcherId, IFetcherService, Response } from '../../../platform/networking/common/fetcherService';
import { IChatEndpoint, IEndpointBody, IRequestKindOptions, postRequest, stringifyUrlOrRequestMetadata } from '../../../platform/networking/common/networking';
import { IChatEndpoint, IEndpointBody, IRequestKindOptions, postRequest, RequestKind, stringifyUrlOrRequestMetadata } from '../../../platform/networking/common/networking';
import { CAPIChatMessage, ChatCompletion, FilterReason, FinishedCompletionReason, rawMessageToCAPI } from '../../../platform/networking/common/openai';
import { sendEngineMessagesTelemetry } from '../../../platform/networking/node/chatStream';
import { CAPIWebSocketErrorEvent, IChatWebSocketManager, isCAPIWebSocketError } from '../../../platform/networking/node/chatWebSocketManager';
@@ -142,7 +142,7 @@ export class ChatMLFetcherImpl extends AbstractChatMLFetcher {
// explicitly opt in to 'mainagent'. This way new utility callers get classified
// correctly without each one having to remember to opt in.
if (!requestKindOptions) {
requestKindOptions = { kind: 'background' };
requestKindOptions = { kind: RequestKind.Background };
}
if (useWebSocket && this._consecutiveWebSocketRetryFallbacks >= ChatMLFetcherImpl._maxConsecutiveWebSocketFallbacks) {
this._logService.debug(`[ChatWebSocketManager] Disabling WebSocket for request due to ${this._consecutiveWebSocketRetryFallbacks} consecutive WebSocket failures with successful HTTP fallback.`);
@@ -1076,9 +1076,9 @@ export class ChatMLFetcherImpl extends AbstractChatMLFetcher {
summarizedAtRoundId: string | undefined,
): Promise<{ result: ChatResults | ChatRequestFailed | ChatRequestCanceled }> {
const intent = locationToIntent(location);
const agentInteractionType = requestKindOptions?.kind === 'subagent' ?
const agentInteractionType = requestKindOptions?.kind === RequestKind.Subagent ?
'conversation-subagent' :
requestKindOptions?.kind === 'background' ?
requestKindOptions?.kind === RequestKind.Background ?
'conversation-background' :
intent === 'conversation-agent' ? intent : undefined;
const additionalHeaders: Record<string, string> = {
@@ -6,7 +6,7 @@
import { ChatFetchError } from '../../../platform/chat/common/commonTypes';
import { isAutoModel } from '../../../platform/endpoint/node/autoChatEndpoint';
import { FetcherId } from '../../../platform/networking/common/fetcherService';
import { IChatEndpoint, IChatRequestTelemetryProperties, IEndpointBody, IRequestKindOptions } from '../../../platform/networking/common/networking';
import { IChatEndpoint, IChatRequestTelemetryProperties, IEndpointBody, IRequestKindOptions, RequestKind } from '../../../platform/networking/common/networking';
import { ChatCompletion } from '../../../platform/networking/common/openai';
import { ITelemetryService } from '../../../platform/telemetry/common/telemetry';
import { TelemetryData } from '../../../platform/telemetry/common/telemetryData';
@@ -160,7 +160,7 @@ export class ChatMLFetcherTelemetrySender {
filterReason: chatCompletion.filterReason,
source: baseTelemetry?.properties.messageSource ?? 'unknown',
initiatorType: userInitiatedRequest ? 'user' : 'agent',
requestKind: requestKindOptions?.kind ?? 'mainagent',
requestKind: requestKindOptions?.kind ?? RequestKind.MainAgent,
conversationId: baseTelemetry?.properties.conversationId,
model: chatEndpointInfo?.model,
modelInvoked: chatCompletion.model,
@@ -277,7 +277,7 @@ export class ChatMLFetcherTelemetrySender {
source,
requestId,
model,
requestKind: requestKindOptions?.kind ?? 'mainagent',
requestKind: requestKindOptions?.kind ?? RequestKind.MainAgent,
conversationId,
associatedRequestId,
parentRequestId,
@@ -371,7 +371,7 @@ export class ChatMLFetcherTelemetrySender {
type: processed.type,
reason: processed.reasonDetail || processed.reason,
source: telemetryProperties?.messageSource ?? 'unknown',
requestKind: requestKindOptions?.kind ?? 'mainagent',
requestKind: requestKindOptions?.kind ?? RequestKind.MainAgent,
conversationId: telemetryProperties?.conversationId,
requestId: processed.requestId,
gitHubRequestId: processed.serverRequestId,
@@ -23,6 +23,7 @@ import { HAS_IGNORED_FILES_MESSAGE } from '../../../platform/ignore/common/ignor
import { ILogService } from '../../../platform/log/common/logService';
import { isAnthropicContextEditingEnabled } from '../../../platform/networking/common/anthropic';
import { FilterReason } from '../../../platform/networking/common/openai';
import { RequestKind } from '../../../platform/networking/common/networking';
import { IOTelService } from '../../../platform/otel/common/otelService';
import { CapturingToken } from '../../../platform/requestLogger/common/capturingToken';
import { IRequestLogger } from '../../../platform/requestLogger/common/requestLogger';
@@ -731,8 +732,8 @@ class DefaultToolCallingLoop extends ToolCallingLoop<IDefaultToolLoopOptions> {
parentRequestId: this.options.request.parentRequestId,
},
requestKindOptions: this.options.request.subAgentInvocationId
? { kind: 'subagent' }
: { kind: 'mainagent' },
? { kind: RequestKind.Subagent }
: { kind: RequestKind.MainAgent },
enableRetryOnFilter: true
}, token);
}
@@ -13,6 +13,7 @@ import { ConfigKey, IConfigurationService } from '../../../platform/configuratio
import { ChatEndpointFamily, IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
import { ProxyAgenticEndpoint } from '../../../platform/endpoint/node/proxyAgenticEndpoint';
import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService';
import { RequestKind } from '../../../platform/networking/common/networking';
import { IGitService } from '../../../platform/git/common/gitService';
import { ILogService } from '../../../platform/log/common/logService';
import { IOTelService } from '../../../platform/otel/common/otelService';
@@ -154,7 +155,7 @@ export class ExecutionSubagentToolCallingLoop extends ToolCallingLoop<IExecution
},
// This loop is inside a tool called from another request, so never user initiated
userInitiatedRequest: false,
requestKindOptions: { kind: 'subagent' },
requestKindOptions: { kind: RequestKind.Subagent },
telemetryProperties: {
requestId: this.options.subAgentInvocationId,
messageId: randomUUID(),
@@ -13,6 +13,7 @@ import { ConfigKey, IConfigurationService } from '../../../platform/configuratio
import { ChatEndpointFamily, IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
import { ProxyAgenticEndpoint } from '../../../platform/endpoint/node/proxyAgenticEndpoint';
import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService';
import { RequestKind } from '../../../platform/networking/common/networking';
import { IGitService } from '../../../platform/git/common/gitService';
import { ILogService } from '../../../platform/log/common/logService';
import { IOTelService } from '../../../platform/otel/common/otelService';
@@ -165,7 +166,7 @@ export class SearchSubagentToolCallingLoop extends ToolCallingLoop<ISearchSubage
conversationId: this.options.conversation.sessionId,
parentToolCallId: this.options.parentToolCallId,
},
requestKindOptions: { kind: 'subagent' }
requestKindOptions: { kind: RequestKind.Subagent }
}, token);
}
}
@@ -12,6 +12,7 @@ import { CapturingToken } from '../../../platform/requestLogger/common/capturing
import { IRequestLogger } from '../../../platform/requestLogger/common/requestLogger';
import { URI } from '../../../util/vs/base/common/uri';
import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';
import { RequestKind } from '../../../platform/networking/common/networking';
import { ConversationHistorySummarizationPrompt } from '../../prompts/node/agent/summarizedConversationHistory';
import { renderPromptElement } from '../../prompts/node/base/promptRenderer';
import { ChatVariablesCollection } from '../common/chatVariablesCollection';
@@ -96,7 +97,7 @@ export class ChatSummarizerProvider implements vscode.ChatSummarizer {
finishedCb: undefined,
location: ChatLocation.Panel,
userInitiatedRequest: false,
requestKindOptions: { kind: 'summarization' },
requestKindOptions: { kind: RequestKind.Summarization },
}, token));
if (token.isCancellationRequested) {
@@ -16,7 +16,7 @@ import { ConfigKey, IConfigurationService } from '../../../../platform/configura
import { isAnthropicFamily, isGeminiFamily } from '../../../../platform/endpoint/common/chatModelCapabilities';
import { ILogService } from '../../../../platform/log/common/logService';
import { CUSTOM_TOOL_SEARCH_NAME } from '../../../../platform/networking/common/anthropic';
import { IChatEndpoint } from '../../../../platform/networking/common/networking';
import { IChatEndpoint, RequestKind } from '../../../../platform/networking/common/networking';
import { APIUsage } from '../../../../platform/networking/common/openai';
import { IPromptPathRepresentationService } from '../../../../platform/prompts/common/promptPathRepresentationService';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry';
@@ -750,7 +750,7 @@ class ConversationHistorySummarizer {
},
telemetryProperties: associatedRequestId ? { associatedRequestId } : undefined,
enableRetryOnFilter: true,
requestKindOptions: { kind: 'summarization' }
requestKindOptions: { kind: RequestKind.Summarization }
}, this.token ?? CancellationToken.None);
} catch (e) {
this.logInfo(`Error from summarization request. ${e.message}`, mode);
@@ -355,39 +355,30 @@ export interface INetworkRequestOptions {
}
/**
* A background request is one that is not associated with a user request.
* Classifies a chat request for telemetry (`requestKind` on response events) and the
* `X-Interaction-Type` header sent to CAPI.
*
* - `Background`: out-of-band utility request not directly tied to a user turn (default).
* - `Subagent`: a request made by a subagent loop (search/execution); also indicated to
* the server with `X-Interaction-Type: conversation-subagent`.
* - `Summarization`: conversation-history compaction in the critical path of a user turn.
* - `MainAgent`: a primary user-initiated chat turn (panel chat, inline chat).
*
* Callers opt in to a non-default kind via `RequestKind.<Member>`. Anything that doesn't
* set `requestKindOptions` is classified as `RequestKind.Background` by `chatMLFetcher`.
*/
export interface IBackgroundRequestOptions {
readonly kind: 'background';
}
export const RequestKind = {
Background: 'background',
Subagent: 'subagent',
Summarization: 'summarization',
MainAgent: 'mainagent',
} as const;
export type RequestKind = typeof RequestKind[keyof typeof RequestKind];
/**
* A subagent request is a request made by a subagent, indicated with a subAgentInvocationId included in the request from VS Code.
*/
export interface ISubagentRequestOptions {
readonly kind: 'subagent';
export interface IRequestKindOptions {
readonly kind: RequestKind;
}
/**
* A summarization request used for compacting conversation history (both
* inline mid-turn and post-turn). Distinct from 'background' because it's
* directly in the critical path of a user turn.
*/
export interface ISummarizationRequestOptions {
readonly kind: 'summarization';
}
/**
* A normal request is a primary user-initiated chat turn (e.g. driven by the
* default intent request handler or inline chat). Callers explicitly opt in to
* 'mainagent' so the chat ML fetcher can default unmarked requests to 'background'.
*/
export interface IMainAgentRequestOptions {
readonly kind: 'mainagent';
}
export type IRequestKindOptions = IBackgroundRequestOptions | ISubagentRequestOptions | ISummarizationRequestOptions | IMainAgentRequestOptions;
function networkRequest(
accessor: ServicesAccessor,
options: INetworkRequestOptions,
@@ -409,9 +400,9 @@ function networkRequest(
name: '',
version: '',
} satisfies IEndpoint : endpointOrUrl;
const agentInteractionType = options.requestKindOptions?.kind === 'subagent' ?
const agentInteractionType = options.requestKindOptions?.kind === RequestKind.Subagent ?
'conversation-subagent' :
options.requestKindOptions?.kind === 'background' ?
options.requestKindOptions?.kind === RequestKind.Background ?
'conversation-background' :
intent === 'conversation-agent' ? intent :
intent;