Path: blob/main/extensions/copilot/src/platform/endpoint/test/node/chatModelCapabilities.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 { describe, expect, test } from 'vitest';6import { ConfigKey, IConfigurationService } from '../../../configuration/common/configurationService';7import type { IChatEndpoint } from '../../../networking/common/networking';8import { IExperimentationService } from '../../../telemetry/common/nullExperimentationService';9import { modelSupportsPDFDocuments, modelSupportsToolSearch } from '../../common/chatModelCapabilities';1011function fakeModel(family: string) {12return { family } as unknown as IChatEndpoint;13}1415describe('modelSupportsPDFDocuments', () => {16test('returns true for claude family', () => {17expect(modelSupportsPDFDocuments(fakeModel('claude-3.5-sonnet'))).toBe(true);18expect(modelSupportsPDFDocuments(fakeModel('claude-3-opus'))).toBe(true);19expect(modelSupportsPDFDocuments(fakeModel('claude-4-sonnet'))).toBe(true);20});2122test('returns true for Anthropic family', () => {23expect(modelSupportsPDFDocuments(fakeModel('Anthropic'))).toBe(true);24expect(modelSupportsPDFDocuments(fakeModel('Anthropic-custom'))).toBe(true);25});2627test('returns false for non-Anthropic families', () => {28expect(modelSupportsPDFDocuments(fakeModel('gpt-4'))).toBe(false);29expect(modelSupportsPDFDocuments(fakeModel('gpt-5.1'))).toBe(false);30expect(modelSupportsPDFDocuments(fakeModel('gemini-2.0-flash'))).toBe(false);31expect(modelSupportsPDFDocuments(fakeModel('o4-mini'))).toBe(false);32});33});3435describe('modelSupportsToolSearch', () => {36test('supports Claude Sonnet/Opus 4.5 and up', () => {37expect(modelSupportsToolSearch('claude-sonnet-4-5')).toBe(true);38expect(modelSupportsToolSearch('claude-sonnet-4.5')).toBe(true);39expect(modelSupportsToolSearch('claude-sonnet-4-5-20250929')).toBe(true);40expect(modelSupportsToolSearch('claude-sonnet-4-6')).toBe(true);41expect(modelSupportsToolSearch('claude-sonnet-4.6')).toBe(true);42expect(modelSupportsToolSearch('claude-opus-4-5')).toBe(true);43expect(modelSupportsToolSearch('claude-opus-4.5')).toBe(true);44expect(modelSupportsToolSearch('claude-opus-4-5-20251101')).toBe(true);45expect(modelSupportsToolSearch('claude-opus-4-6')).toBe(true);46expect(modelSupportsToolSearch('claude-opus-4.6')).toBe(true);47expect(modelSupportsToolSearch('claude-opus-4.7')).toBe(true);48expect(modelSupportsToolSearch('[email protected]')).toBe(true);49expect(modelSupportsToolSearch('[email protected]')).toBe(true);50});5152test('rejects pre-4.5 models, including date-suffixed ones', () => {53// Regression guard: the datestamp must not be read as the minor version.54expect(modelSupportsToolSearch('claude-sonnet-4-20250514')).toBe(false);55expect(modelSupportsToolSearch('claude-sonnet-4')).toBe(false);56expect(modelSupportsToolSearch('claude-opus-4')).toBe(false);57expect(modelSupportsToolSearch('claude-opus-4-1')).toBe(false);58expect(modelSupportsToolSearch('claude-opus-4.1')).toBe(false);59expect(modelSupportsToolSearch('claude-opus-4-1-20250805')).toBe(false);60});6162test('rejects non-Sonnet/Opus Claude families', () => {63expect(modelSupportsToolSearch('claude-haiku-4-5')).toBe(false);64expect(modelSupportsToolSearch('claude-3-5-sonnet-20241022')).toBe(false);65expect(modelSupportsToolSearch('claude-3-opus')).toBe(false);66});6768test('supports OpenAI gpt-5.4 and gpt-5.5 models when the setting is enabled', () => {69const configurationService = {70getExperimentBasedConfig: (key: unknown) => key === ConfigKey.ResponsesApiToolSearchEnabled,71} as unknown as IConfigurationService;72const experimentationService = {} as IExperimentationService;7374expect(modelSupportsToolSearch('gpt-5.4', configurationService, experimentationService)).toBe(true);75expect(modelSupportsToolSearch('gpt-5.5', configurationService, experimentationService)).toBe(true);76expect(modelSupportsToolSearch('gpt-5.4')).toBe(false);77expect(modelSupportsToolSearch('gpt-5.5')).toBe(false);78});7980test('rejects suffixed gpt-5.4/5.5 variants (exact match only)', () => {81const configurationService = {82getExperimentBasedConfig: (key: unknown) => key === ConfigKey.ResponsesApiToolSearchEnabled,83} as unknown as IConfigurationService;84const experimentationService = {} as IExperimentationService;8586expect(modelSupportsToolSearch('gpt-5.4-mini', configurationService, experimentationService)).toBe(false);87expect(modelSupportsToolSearch('gpt-5.4-preview', configurationService, experimentationService)).toBe(false);88expect(modelSupportsToolSearch('gpt-5.5-preview', configurationService, experimentationService)).toBe(false);89expect(modelSupportsToolSearch('gpt5.5-preview', configurationService, experimentationService)).toBe(false);90});9192test('rejects other non-Claude models', () => {93expect(modelSupportsToolSearch('gpt-5')).toBe(false);94expect(modelSupportsToolSearch('gemini-2.5-pro')).toBe(false);95expect(modelSupportsToolSearch('o4-mini')).toBe(false);96});97});9899100