diff --git a/src/utils/ai.js b/src/utils/ai.js index cafd1de1..62048fcb 100644 --- a/src/utils/ai.js +++ b/src/utils/ai.js @@ -7,7 +7,7 @@ const { OpenAI } = require('openai'); const { DEFAULT_MODEL, FALLBACK_MODEL, getBedrockModelId, getBedrockMaxOut } = require('./models'); const logger = require('./logger'); -const { resolveGenerationOptions } = require('./generationOptions'); +const { resolveGenerationOptions, addReasoningOptions } = require('./generationOptions'); var activeProvider = process.env.AI_PROVIDER || (process.env.LITELLM_API_BASE ? 'litellm' : 'openrouter'); @@ -368,12 +368,6 @@ async function callVertex(messages, model, temperature, maxTokens) { // ============================================================ // CALL LITELLM (OpenAI-compatible proxy) // ============================================================ -function addReasoningOptions(request, generation) { - if (generation.reasoningEffort != null) request.reasoning_effort = generation.reasoningEffort; - if (generation.reasoningFormat != null) request.reasoning_format = generation.reasoningFormat; - return request; -} - async function callLiteLLM(messages, model, temperature, maxTokens, generation) { if (!litellmClient) throw new Error('LiteLLM not configured. Set LITELLM_API_BASE in .env'); diff --git a/src/utils/generationOptions.js b/src/utils/generationOptions.js index 21705a14..5aa0ef3e 100644 --- a/src/utils/generationOptions.js +++ b/src/utils/generationOptions.js @@ -8,4 +8,13 @@ function resolveGenerationOptions(options) { }; } -module.exports = { resolveGenerationOptions }; +function addReasoningOptions(request, generation) { + // These OpenAI-compatible fields are rejected by ordinary chat models such as GPT-4.1. + // Keep the Clinical Assistant profile, but only send it to the Groq Qwen model that supports both fields. + if (request.model !== 'groq-qwen3.8-27b') return request; + if (generation.reasoningEffort != null) request.reasoning_effort = generation.reasoningEffort; + if (generation.reasoningFormat != null) request.reasoning_format = generation.reasoningFormat; + return request; +} + +module.exports = { resolveGenerationOptions, addReasoningOptions }; diff --git a/test/clinical-generation-options.test.js b/test/clinical-generation-options.test.js index 2f85a7e5..800ca1d7 100644 --- a/test/clinical-generation-options.test.js +++ b/test/clinical-generation-options.test.js @@ -2,7 +2,7 @@ const test = require('node:test'); const assert = require('node:assert/strict'); const { assistantGenerationOptions } = require('../src/utils/clinicalAnswer'); -const { resolveGenerationOptions } = require('../src/utils/generationOptions'); +const { resolveGenerationOptions, addReasoningOptions } = require('../src/utils/generationOptions'); test('clinical assistant profile requests low reasoning without exposing it', () => { assert.deepEqual(assistantGenerationOptions({ temperature: 0, maxTokens: 80 }), { @@ -17,3 +17,11 @@ test('generation defaults preserve an explicit zero temperature', () => { assert.equal(resolveGenerationOptions({ temperature: 0 }).temperature, 0); assert.equal(resolveGenerationOptions({}).temperature, 0.3); }); + +test('reasoning fields are sent only to the confirmed Groq Qwen model', () => { + const profile = { reasoningEffort: 'low', reasoningFormat: 'hidden' }; + assert.deepEqual(addReasoningOptions({ model: 'openai-gpt-4.1' }, profile), { model: 'openai-gpt-4.1' }); + assert.deepEqual(addReasoningOptions({ model: 'groq-qwen3.8-27b' }, profile), { + model: 'groq-qwen3.8-27b', reasoning_effort: 'low', reasoning_format: 'hidden' + }); +});