Path: blob/main/extensions/copilot/src/extension/byok/node/test/openAIEndpoint.spec.ts
13405 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 { Raw } from '@vscode/prompt-tsx';6import { afterEach, beforeEach, describe, expect, it } from 'vitest';7import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService';8import { IChatModelInformation, ModelSupportedEndpoint } from '../../../../platform/endpoint/common/endpointProvider';9import { ICreateEndpointBodyOptions } from '../../../../platform/networking/common/networking';10import { ITestingServicesAccessor } from '../../../../platform/test/node/services';11import { DisposableStore } from '../../../../util/vs/base/common/lifecycle';12import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation';13import { createExtensionUnitTestingServices } from '../../../test/node/services';14import { OpenAIEndpoint } from '../openAIEndpoint';1516// Test fixtures for thinking content17const createThinkingMessage = (thinkingId: string, thinkingText: string): Raw.ChatMessage => ({18role: Raw.ChatRole.Assistant,19content: [20{21type: Raw.ChatCompletionContentPartKind.Opaque,22value: {23type: 'thinking',24thinking: {25id: thinkingId,26text: thinkingText27}28}29}30]31});3233const createTestOptions = (messages: Raw.ChatMessage[]): ICreateEndpointBodyOptions => ({34debugName: 'test',35messages,36requestId: 'test-req-123',37postOptions: {},38finishedCb: undefined,39location: undefined as any40});4142describe('OpenAIEndpoint - Reasoning Properties', () => {43let modelMetadata: IChatModelInformation;44const disposables = new DisposableStore();45let accessor: ITestingServicesAccessor;46let instaService: IInstantiationService;4748beforeEach(() => {49modelMetadata = {50id: 'test-model',51name: 'Test Model',52vendor: 'Test Vendor',53version: '1.0',54model_picker_enabled: true,55is_chat_default: false,56is_chat_fallback: false,57supported_endpoints: [ModelSupportedEndpoint.ChatCompletions, ModelSupportedEndpoint.Responses],58capabilities: {59type: 'chat',60family: 'openai',61tokenizer: 'o200k_base' as any,62supports: {63parallel_tool_calls: false,64streaming: true,65tool_calls: false,66vision: false,67prediction: false,68thinking: true69},70limits: {71max_prompt_tokens: 4096,72max_output_tokens: 2048,73max_context_window_tokens: 614474}75}76};7778const testingServiceCollection = createExtensionUnitTestingServices();79accessor = disposables.add(testingServiceCollection.createTestingAccessor());80instaService = accessor.get(IInstantiationService);81});8283afterEach(() => {84disposables.clear();85});8687describe('CAPI mode (useResponsesApi = false)', () => {88it('should set cot_id and cot_summary properties when processing thinking content', () => {89const endpoint = instaService.createInstance(OpenAIEndpoint,90{91...modelMetadata,92supported_endpoints: [ModelSupportedEndpoint.ChatCompletions]93},94'test-api-key',95'https://api.openai.com/v1/chat/completions');9697const thinkingMessage = createThinkingMessage('test-thinking-123', 'this is my reasoning');98const options = createTestOptions([thinkingMessage]);99100const body = endpoint.createRequestBody(options);101102expect(body.messages).toBeDefined();103const messages = body.messages as any[];104expect(messages).toHaveLength(1);105expect(messages[0].cot_id).toBe('test-thinking-123');106expect(messages[0].cot_summary).toBe('this is my reasoning');107});108109it('should handle multiple messages with thinking content', () => {110const endpoint = instaService.createInstance(OpenAIEndpoint,111{112...modelMetadata,113supported_endpoints: [ModelSupportedEndpoint.ChatCompletions]114},115'test-api-key',116'https://api.openai.com/v1/chat/completions');117118const userMessage: Raw.ChatMessage = {119role: Raw.ChatRole.User,120content: [{ type: Raw.ChatCompletionContentPartKind.Text, text: 'Hello' }]121};122const thinkingMessage = createThinkingMessage('reasoning-456', 'complex reasoning here');123const options = createTestOptions([userMessage, thinkingMessage]);124125const body = endpoint.createRequestBody(options);126127expect(body.messages).toBeDefined();128const messages = body.messages as any[];129expect(messages).toHaveLength(2);130131// User message should not have thinking properties132expect(messages[0].cot_id).toBeUndefined();133expect(messages[0].cot_summary).toBeUndefined();134135// Assistant message should have thinking properties136expect(messages[1].cot_id).toBe('reasoning-456');137expect(messages[1].cot_summary).toBe('complex reasoning here');138});139});140141describe('Responses API mode (useResponsesApi = true)', () => {142it('should preserve reasoning object when thinking is supported', () => {143accessor.get(IConfigurationService).setConfig(ConfigKey.ResponsesApiReasoningSummary, 'detailed');144const endpoint = instaService.createInstance(OpenAIEndpoint,145modelMetadata,146'test-api-key',147'https://api.openai.com/v1/chat/completions');148149const thinkingMessage = createThinkingMessage('resp-api-789', 'responses api reasoning');150const options = createTestOptions([thinkingMessage]);151152const body = endpoint.createRequestBody(options);153154expect(body.store).toBe(true);155expect(body.n).toBeUndefined();156expect(body.stream_options).toBeUndefined();157expect(body.reasoning).toBeDefined(); // Should preserve reasoning object158});159160it('should remove reasoning object when thinking is not supported', () => {161const modelWithoutThinking = {162...modelMetadata,163capabilities: {164...modelMetadata.capabilities,165supports: {166...modelMetadata.capabilities.supports,167thinking: false168}169}170};171172accessor.get(IConfigurationService).setConfig(ConfigKey.ResponsesApiReasoningSummary, 'detailed');173const endpoint = instaService.createInstance(OpenAIEndpoint,174modelWithoutThinking,175'test-api-key',176'https://api.openai.com/v1/chat/completions');177178const thinkingMessage = createThinkingMessage('no-thinking-999', 'should be removed');179const options = createTestOptions([thinkingMessage]);180181const body = endpoint.createRequestBody(options);182183expect(body.reasoning).toBeUndefined(); // Should be removed184});185});186});187188