import { DyFM_AI_CallSettings, DyFM_AI_ModelInfo, DyFM_AI_ModelType, DyFM_AI_Provider, } from '@futdevpro/fsm-dynamo/ai'; import { DyNTS_AI_LLM_ServiceBase } from './ai-llm.service-base'; /** Minden-false capability-blokk a teszt-registry bejegyzesekhez. */ const NO_CAPS: any = { functionCalling: false, vision: false, streaming: false, jsonMode: false, audioInput: false, audioOutput: false, imageGeneration: false, embeddings: false, adultContent: false, }; /** Teszt-registry: egy schema-val rendelkezo es egy schema-mentes modell. */ const TEST_REGISTRY: DyFM_AI_ModelInfo[] = [ { id: 'schema-model', provider: DyFM_AI_Provider.OpenAI, modelType: DyFM_AI_ModelType.Chat, capabilities: NO_CAPS, settingsSchema: { supported: ['maxTokens'], unsupported: ['temperature', 'topP'], extraParams: ['reasoningEffort'], constraints: { maxTokens: { min: 10, max: 100 }, }, }, }, { id: 'plain-model', provider: DyFM_AI_Provider.OpenAI, modelType: DyFM_AI_ModelType.Chat, capabilities: NO_CAPS, }, ]; class ReconcilerTestService extends DyNTS_AI_LLM_ServiceBase { readonly aiProvider: any = {} as any; readonly capabilities: any = {} as any; setup = (config: any): void => {}; testConnection = async (issuer: string): Promise => true; readonly defaultSettings: DyFM_AI_CallSettings = { systemPrompt: 'Test', useModel: 'schema-model', debugLog: false, }; readonly predefinedRequests = { yesNo: { upperCaseYes: 'YES' } }; requestSimpleMessage = async (set: any): Promise => { return ''; }; requestYesNo = async (set: any): Promise => { return false; }; requestPercentage = async (set: any): Promise => { return 0; }; requestSelect = async (set: any): Promise => { return null as any; }; requestMultiselect = async (set: any): Promise => { return []; }; requestJSON = async (set: any): Promise => { return null as any; }; requestJSONQuestionWithKeysDescription = async (set: any): Promise => { return null as any; }; requestJSONWithExactKeys = async (set: any): Promise => { return null as any; }; requestList = async (set: any): Promise => { return []; }; protected override getModelRegistry(): DyFM_AI_ModelInfo[] { return TEST_REGISTRY; } static getInstance(): ReconcilerTestService { return ReconcilerTestService.getSingletonInstance(); } } describe('| DyNTS_AI_LLM_ServiceBase — FR-048 reconcileCallSettings', () => { let service: ReconcilerTestService; beforeEach(() => { service = ReconcilerTestService.getInstance(); }); it('| dropolja az `unsupported` kulcsokat, a tobbit meghagyja', () => { const result: DyFM_AI_CallSettings = (service as any).reconcileCallSettings('schema-model', { temperature: 0.7, topP: 0.9, maxTokens: 50, }); expect(result.temperature).toBeUndefined(); expect(result.topP).toBeUndefined(); expect(result.maxTokens).toBe(50); }); it('| NEM mutalja az eredeti settings-objektumot', () => { const original: DyFM_AI_CallSettings = { temperature: 0.7, maxTokens: 50 }; (service as any).reconcileCallSettings('schema-model', original); expect(original.temperature).toBe(0.7); }); it('| clamp-eli a `constraints` min/max szerint', () => { const tooHigh: DyFM_AI_CallSettings = (service as any).reconcileCallSettings('schema-model', { maxTokens: 500 }); const tooLow: DyFM_AI_CallSettings = (service as any).reconcileCallSettings('schema-model', { maxTokens: 1 }); expect(tooHigh.maxTokens).toBe(100); expect(tooLow.maxTokens).toBe(10); }); it('| schema-mentes modell → permisszi­v passthrough (non-breaking)', () => { const input: DyFM_AI_CallSettings = { temperature: 0.7, topP: 0.9 }; const result: DyFM_AI_CallSettings = (service as any).reconcileCallSettings('plain-model', input); expect(result).toBe(input); expect(result.temperature).toBe(0.7); }); it('| ismeretlen modell → permisszi­v passthrough (honesty, nem dob)', () => { const input: DyFM_AI_CallSettings = { temperature: 0.7 }; const result: DyFM_AI_CallSettings = (service as any).reconcileCallSettings('nincs-ilyen-modell', input); expect(result).toBe(input); }); it('| undefined settings → valtozatlanul visszaadva', () => { expect((service as any).reconcileCallSettings('schema-model', undefined)).toBeUndefined(); }); });