Path: blob/main/extensions/copilot/src/platform/networking/common/fetch.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 { EncryptedThinkingDelta, ThinkingData, ThinkingDelta } from '../../thinking/common/thinking';6import { AnthropicMessagesTool, ContextManagementResponse } from './anthropic';7import { IHeaders } from './fetcherService';8import { ChoiceLogProbs, FilterReason, openAIContextManagementCompactionType, OpenAIContextManagementResponse } from './openai';91011// Request helpers1213export interface RequestId {14headerRequestId: string;15gitHubRequestId: string;16completionId: string;17created: number;18serverExperiments: string;19deploymentId: string;20}2122export function getRequestId(headers: IHeaders, json?: any): RequestId {23const serverExperiments = headers.get('X-Copilot-Experiment') || '';24const capiExpAssignmentContext = headers.get('x-copilot-api-exp-assignment-context') || '';25return {26headerRequestId: headers.get('x-request-id') || '',27gitHubRequestId: headers.get('x-github-request-id') || '',28completionId: json && json.id ? json.id : '',29created: json && json.created ? json.created : 0,30serverExperiments: serverExperiments && capiExpAssignmentContext31? `${serverExperiments};${capiExpAssignmentContext}`32: serverExperiments || capiExpAssignmentContext,33deploymentId: headers.get('azureml-model-deployment') || '',34};35}3637// Request methods3839export interface ICodeVulnerabilityAnnotation {40details: {41type: string;42description: string;43};44}4546export interface IIPCodeCitation {47citations: {48url: string;49license: string;50snippet: string;51};52}5354export function isCopilotAnnotation(thing: unknown): thing is ICodeVulnerabilityAnnotation {55if (typeof thing !== 'object' || thing === null || !('details' in thing)) {56return false;57}5859const { details } = thing as ICodeVulnerabilityAnnotation;60return typeof details === 'object' && details !== null &&61'type' in details && 'description' in details && typeof details.type === 'string' && typeof details.description === 'string';62}6364export function isCodeCitationAnnotation(thing: unknown): thing is IIPCodeCitation {65if (typeof thing !== 'object' || thing === null || !('citations' in thing)) {66return false;67}6869const { citations } = thing as IIPCodeCitation;70return typeof citations === 'object' && citations !== null &&71'url' in citations && 'license' in citations && typeof citations.url === 'string' && typeof citations.license === 'string';72}7374export interface ICopilotReference {75type: string;76id: string;77data: Record<string, unknown>;78metadata?: {79display_name: string;80display_icon?: string;81display_url?: string;82};83}8485export interface ICopilotToolCall {86name: string;87arguments: string;88id: string;89}9091export interface ICopilotToolCallStreamUpdate {92name: string;93arguments: string;94id?: string;95}9697export interface ICopilotBeginToolCall {98name: string;99id?: string;100}101102/**103* @deprecated104*/105export interface ICopilotFunctionCall {106name: string;107arguments: string;108}109110export interface ICopilotError {111type: string;112code: string;113message: string;114agent: string;115identifier?: string;116}117118export function isCopilotWebReference(reference: unknown) {119return typeof reference === 'object' && !!reference && 'title' in reference && 'excerpt' in reference && 'url' in reference;120}121122export interface ICopilotWebReference {123title: string;124excerpt: string;125url: string;126}127128export interface ICopilotConfirmation {129title: string;130message: string;131confirmation: any;132}133134export interface IResponseDelta {135text: string;136logprobs?: ChoiceLogProbs;137codeVulnAnnotations?: ICodeVulnerabilityAnnotation[];138ipCitations?: IIPCodeCitation[];139copilotReferences?: ICopilotReference[];140copilotErrors?: ICopilotError[];141copilotToolCalls?: ICopilotToolCall[];142copilotToolCallStreamUpdates?: ICopilotToolCallStreamUpdate[];143beginToolCalls?: ICopilotBeginToolCall[];144_deprecatedCopilotFunctionCalls?: ICopilotFunctionCall[];145copilotConfirmation?: ICopilotConfirmation;146thinking?: ThinkingDelta | EncryptedThinkingDelta;147phase?: string;148retryReason?: FilterReason | 'network_error' | 'server_error';149/** Marker for the current response, which should be presented in `IMakeChatRequestOptions` on the next call */150statefulMarker?: string;151/** Context management information from Anthropic Messages API */152contextManagement?: ContextManagementResponse | OpenAIContextManagementResponse;153}154155export function isOpenAIContextManagementResponse(value: ContextManagementResponse | OpenAIContextManagementResponse): value is OpenAIContextManagementResponse {156return 'type' in value && value.type === openAIContextManagementCompactionType;157}158159export function isAnthropicContextManagementResponse(value: ContextManagementResponse | OpenAIContextManagementResponse): value is ContextManagementResponse {160return 'applied_edits' in value;161}162163export const enum ResponsePartKind {164ContentDelta,165Content,166ToolCallDelta,167ToolCall,168Annotation,169Confirmation,170Error,171Thinking,172ThinkingDelta,173}174175/** Part that contains incremental data added to the output */176export interface IContentDeltaResponsePart {177kind: ResponsePartKind.ContentDelta;178/** Part ID corresponds to the later IContentResponsePart */179partId: string;180/** Incremental content chunk */181delta: string;182}183184/** Part that is emitted once the content is finished */185export interface IContentResponsePart {186kind: ResponsePartKind.Content;187/** Part ID of the IContentDeltaResponsePart */188partId: string;189/** Finalized content */190content: string;191/** Log probabilities, if requested */192logProbs?: ChoiceLogProbs;193}194195/** Part that contains incremental data for a tool call that's being generated */196export interface IToolCallDeltaResponsePart {197kind: ResponsePartKind.ToolCallDelta;198/** Part ID corresponds to the later IToolCallResponsePart */199partId: string;200/** Name of the function being called */201name: string;202/** Arguments delta */203delta: string;204}205206/** Part that is emitted once a tool call is ready. */207export interface IToolCallResponsePart extends ICopilotToolCall {208kind: ResponsePartKind.ToolCall;209/** Part ID of the IToolCallDeltaResponsePart */210partId: string;211}212213/** Part that is emitted when the model wants to ask the user for confirmation. */214export interface IConfirmationResponsePart extends ICopilotConfirmation {215kind: ResponsePartKind.Confirmation;216}217218/** Part that is emitted when the model want to add annotations to a response. */219export interface IAnnotationResponsePart {220kind: ResponsePartKind.Annotation;221codeVulnAnnotations?: ICodeVulnerabilityAnnotation[];222ipCitations?: IIPCodeCitation[];223copilotReferences?: ICopilotReference[];224}225226/** Part that is emitted when the model begins thinking. */227export interface IThinkingResponseDeltaPart {228kind: ResponsePartKind.ThinkingDelta;229/** Part ID of the IThinkingResponsePart */230partId: string;231/** Delta of the thinking process */232delta: ThinkingDelta;233}234235/**236* Part that is emitted when the model finishes thinking.237* WARN: currently CAPI never signals the end of thinking.238*/239export interface IThinkingResponsePart {240kind: ResponsePartKind.Thinking;241/** Part ID of IThinkingResponseDeltaPart */242partId: string;243/** Summary text shown to the user. */244data: ThinkingData;245}246247/** Part that is emitted when the model encounters an error. */248export interface IErrorResponsePart {249kind: ResponsePartKind.Error;250error: ICopilotError;251}252253export type ResponsePart =254| IContentDeltaResponsePart255| IContentResponsePart256| IToolCallDeltaResponsePart257| IToolCallResponsePart258| IAnnotationResponsePart259| IThinkingResponseDeltaPart260| IThinkingResponsePart261| IConfirmationResponsePart262| IErrorResponsePart;263264265export interface FinishedCallback {266/**267* @param text The full concatenated text of the response268* @param index The index of the choice to which the completion chunk belongs269* @param delta A delta for the latest chunk270* @returns A number to stop reading data from the server, `undefined` to continue271*/272(text: string, index: number, delta: IResponseDelta): Promise<number | undefined>;273}274275export interface OpenAiFunctionDef {276name: string;277description: string;278parameters?: object;279}280281export interface OpenAiFunctionTool {282function: OpenAiFunctionDef;283type: 'function';284}285286export interface OpenAiResponsesFunctionTool extends OpenAiFunctionDef {287type: 'function';288}289290/** OpenAI Responses API client-executed tool_search tool declaration. See https://developers.openai.com/api/docs/guides/tools-tool-search */291export interface OpenAiToolSearchTool {292type: 'tool_search';293execution: 'client';294/** Description for client-executed tool search. */295description?: string;296/** Parameters schema for client-executed tool search. */297parameters?: Record<string, unknown>;298}299300export function isOpenAiFunctionTool(tool: OpenAiResponsesFunctionTool | OpenAiFunctionTool | AnthropicMessagesTool | OpenAiToolSearchTool): tool is OpenAiFunctionTool {301return (tool as OpenAiFunctionTool).function !== undefined;302}303304/**305* Options for streaming response. Only set this when you set stream: true.306*307* @remarks Proxy has `include_usage` hard-coded to true.308*/309export type StreamOptions = {310/**311* If set, an additional chunk will be streamed before the data: [DONE] message. The usage field on this chunk shows the token usage statistics for the entire request, and the choices field will always be an empty array.312*313* All other chunks will also include a usage field, but with a null value. NOTE: If the stream is interrupted, you may not receive the final usage chunk which contains the total token usage for the request.314*/315include_usage?: boolean;316};317318export type Prediction = {319type: 'content';320content: string | { type: string; text: string }[];321};322323/** based on https://platform.openai.com/docs/api-reference/chat/create324*325* 'stream' param is not respected because we don't yet support non-streamed responses326*/327export interface OptionalChatRequestParams {328329/** Non-negative temperature sampling parameter (default 1). */330temperature?: number;331332/** Non-negative temperature sampling parameter (default 1). */333top_p?: number;334335/** How many parallel completions the model should generate (default 1). */336n?: number;337338/** Whether to stream back a response in SSE format. */339stream?: boolean;340341/** Options for streaming response. Only set this when you set stream: true. */342stream_options?: StreamOptions;343344/** Strings that will cause the model to stop generating text. */345stop?: string[];346347/** The maximum number of tokens to return for a completion request */348max_tokens?: number;349350/** Likelihood of specified tokens appearing in the completion. */351logit_bias?: number;352353// TODO@ulugbekna: not sure params below are supported by Copilot proxy354presence_penalty?: number;355frequency_penalty?: number;356357secretKey?: string;358359/** For github remote agents */360copilot_thread_id?: string;361copilot_skills?: string[];362363functions?: OpenAiFunctionDef[];364function_call?: { name: string };365tools?: OpenAiFunctionTool[];366/**367* Note: 'required' is not supported368*/369tool_choice?: 'none' | 'auto' | { type: 'function'; function: { name: string } };370371prediction?: Prediction;372logprobs?: boolean;373374/** Responses API */375previous_response_id?: string;376}377378379