fix(providers): support OpenAI models requiring max_completion_tokens (#2251)

This commit is contained in:
Ryanba
2026-08-25 20:37:27 +08:00
committed by GitHub
parent 636c023945
commit ca40f6ea7a
3 changed files with 47 additions and 3 deletions
@@ -62,6 +62,7 @@ export const providerOpenAI = defineProvider<OpenAICompatibleConfig>({
validators: {
...createOpenAICompatibleValidators({
checks: [ProviderValidationCheck.Connectivity, ProviderValidationCheck.ModelList, ProviderValidationCheck.ChatCompletions],
chatCompletionTokenParameter: 'max_completion_tokens',
}),
},
})
@@ -4,6 +4,7 @@ import type { ProviderExtraMethods, ProviderInstance } from '../types'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { providerOpenAI } from '../providers/openai'
import { ProviderValidationCheck } from '../types'
import { createOpenAICompatibleValidators } from './openai-compatible'
@@ -34,10 +35,10 @@ async function getProviderValidators(options?: Parameters<typeof createOpenAICom
interface TestConfig { apiKey?: string, baseUrl?: string }
describe('createOpenAICompatibleValidators', () => {
const config: TestConfig = {
const config = {
apiKey: 'test-key',
baseUrl: 'https://example.com/v1/',
}
} satisfies TestConfig
const provider: ProviderInstance = {
model: () => ({
apiKey: config.apiKey,
@@ -143,6 +144,7 @@ describe('createOpenAICompatibleValidators', () => {
expect(result.valid).toBe(true)
expect(generateTextMock).toHaveBeenCalledWith(expect.objectContaining({
model: 'seed-2-0-pro-260328',
max_tokens: 16,
}))
})
@@ -171,4 +173,42 @@ describe('createOpenAICompatibleValidators', () => {
max_tokens: 16,
}))
})
it('uses max_completion_tokens when the provider requires the newer parameter', async () => {
listModelsMock.mockResolvedValue([
{ id: 'gpt-5' },
])
const [, chatValidator] = await getProviderValidators({
checks: [ProviderValidationCheck.Connectivity, ProviderValidationCheck.ChatCompletions],
chatCompletionTokenParameter: 'max_completion_tokens',
})
const result = await chatValidator.validator(config, provider, providerExtra, { t: mockT })
expect(result.valid).toBe(true)
expect(generateTextMock).toHaveBeenCalledWith(expect.objectContaining({
model: 'gpt-5',
max_completion_tokens: 16,
}))
expect(generateTextMock.mock.calls[0][0]).not.toHaveProperty('max_tokens')
})
it('configures the OpenAI provider validation with max_completion_tokens', async () => {
listModelsMock.mockResolvedValue([
{ id: 'gpt-5' },
])
const validators = await Promise.all((providerOpenAI.validators?.validateProvider || []).map(create => create({ t: mockT })))
const chatValidator = validators.find(validator => validator.id === 'openai-compatible:check-chat-completions')
expect(chatValidator).toBeDefined()
const result = await chatValidator!.validator(config, provider, providerExtra, { t: mockT })
expect(result.valid).toBe(true)
expect(generateTextMock).toHaveBeenCalledWith(expect.objectContaining({
max_completion_tokens: 16,
}))
expect(generateTextMock.mock.calls[0][0]).not.toHaveProperty('max_tokens')
})
})
@@ -22,6 +22,7 @@ interface OpenAICompatibleValidationOptions<TConfig extends { apiKey?: string, b
skipApiKeyCheck?: boolean
connectivityFailureReason?: (input: { config: TConfig, error: unknown, errorMessage: string }) => string
modelListFailureReason?: (input: { config: TConfig, error: unknown, errorMessage: string }) => string
chatCompletionTokenParameter?: 'max_tokens' | 'max_completion_tokens'
}
function extractStatusCode(error: unknown): number | null {
@@ -145,7 +146,9 @@ export function createOpenAICompatibleValidators<TConfig extends { apiKey?: stri
// OpenRouter documents this minimum for some upstream providers.
// Source/context: https://openrouter.ai/docs/api/api-reference/chat/send-chat-completion-request
// Removal condition: All supported providers accept lower limits, or the probe learns each model's minimum.
max_tokens: 16,
...(options?.chatCompletionTokenParameter === 'max_completion_tokens'
? { max_completion_tokens: 16 }
: { max_tokens: 16 }),
})
return { connectivityOk: true, chatOk: true }