feat(openai): 增加 gpt-5.4-mini/nano 模型支持与定价配置
- 接入 gpt-5.4-mini/nano 模型识别与规范化,补充默认模型列表 - 增加 gpt-5.4-mini/nano 输入/缓存命中/输出价格与计费兜底逻辑 - 同步前端模型白名单与 OpenCode 配置 - 补充 service tier(priority/flex) 计费回归测试
This commit is contained in:
@@ -705,6 +705,38 @@ function generateOpenCodeConfig(platform: string, baseUrl: string, apiKey: strin
|
||||
xhigh: {}
|
||||
}
|
||||
},
|
||||
'gpt-5.4-mini': {
|
||||
name: 'GPT-5.4 Mini',
|
||||
limit: {
|
||||
context: 400000,
|
||||
output: 128000
|
||||
},
|
||||
options: {
|
||||
store: false
|
||||
},
|
||||
variants: {
|
||||
low: {},
|
||||
medium: {},
|
||||
high: {},
|
||||
xhigh: {}
|
||||
}
|
||||
},
|
||||
'gpt-5.4-nano': {
|
||||
name: 'GPT-5.4 Nano',
|
||||
limit: {
|
||||
context: 400000,
|
||||
output: 128000
|
||||
},
|
||||
options: {
|
||||
store: false
|
||||
},
|
||||
variants: {
|
||||
low: {},
|
||||
medium: {},
|
||||
high: {},
|
||||
xhigh: {}
|
||||
}
|
||||
},
|
||||
'gpt-5.3-codex-spark': {
|
||||
name: 'GPT-5.3 Codex Spark',
|
||||
limit: {
|
||||
|
||||
53
frontend/src/components/keys/__tests__/UseKeyModal.spec.ts
Normal file
53
frontend/src/components/keys/__tests__/UseKeyModal.spec.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
vi.mock('vue-i18n', () => ({
|
||||
useI18n: () => ({
|
||||
t: (key: string) => key
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('@/composables/useClipboard', () => ({
|
||||
useClipboard: () => ({
|
||||
copyToClipboard: vi.fn().mockResolvedValue(true)
|
||||
})
|
||||
}))
|
||||
|
||||
import UseKeyModal from '../UseKeyModal.vue'
|
||||
|
||||
describe('UseKeyModal', () => {
|
||||
it('renders updated GPT-5.4 mini/nano names in OpenCode config', async () => {
|
||||
const wrapper = mount(UseKeyModal, {
|
||||
props: {
|
||||
show: true,
|
||||
apiKey: 'sk-test',
|
||||
baseUrl: 'https://example.com/v1',
|
||||
platform: 'openai'
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
BaseDialog: {
|
||||
template: '<div><slot /><slot name="footer" /></div>'
|
||||
},
|
||||
Icon: {
|
||||
template: '<span />'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const opencodeTab = wrapper.findAll('button').find((button) =>
|
||||
button.text().includes('keys.useKeyModal.cliTabs.opencode')
|
||||
)
|
||||
|
||||
expect(opencodeTab).toBeDefined()
|
||||
await opencodeTab!.trigger('click')
|
||||
await nextTick()
|
||||
|
||||
const codeBlock = wrapper.find('pre code')
|
||||
expect(codeBlock.exists()).toBe(true)
|
||||
expect(codeBlock.text()).toContain('"name": "GPT-5.4 Mini"')
|
||||
expect(codeBlock.text()).toContain('"name": "GPT-5.4 Nano"')
|
||||
})
|
||||
})
|
||||
@@ -11,6 +11,8 @@ describe('useModelWhitelist', () => {
|
||||
const models = getModelsByPlatform('openai')
|
||||
|
||||
expect(models).toContain('gpt-5.4')
|
||||
expect(models).toContain('gpt-5.4-mini')
|
||||
expect(models).toContain('gpt-5.4-nano')
|
||||
expect(models).toContain('gpt-5.4-2026-03-05')
|
||||
})
|
||||
|
||||
@@ -52,4 +54,13 @@ describe('useModelWhitelist', () => {
|
||||
'gpt-5.4-2026-03-05': 'gpt-5.4-2026-03-05'
|
||||
})
|
||||
})
|
||||
|
||||
it('whitelist keeps GPT-5.4 mini and nano exact mappings', () => {
|
||||
const mapping = buildModelMappingObject('whitelist', ['gpt-5.4-mini', 'gpt-5.4-nano'], [])
|
||||
|
||||
expect(mapping).toEqual({
|
||||
'gpt-5.4-mini': 'gpt-5.4-mini',
|
||||
'gpt-5.4-nano': 'gpt-5.4-nano'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -25,7 +25,7 @@ const openaiModels = [
|
||||
'gpt-5.2', 'gpt-5.2-2025-12-11', 'gpt-5.2-chat-latest',
|
||||
'gpt-5.2-codex', 'gpt-5.2-pro', 'gpt-5.2-pro-2025-12-11',
|
||||
// GPT-5.4 系列
|
||||
'gpt-5.4', 'gpt-5.4-2026-03-05',
|
||||
'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.4-nano', 'gpt-5.4-2026-03-05',
|
||||
// GPT-5.3 系列
|
||||
'gpt-5.3-codex', 'gpt-5.3-codex-spark',
|
||||
'chatgpt-4o-latest',
|
||||
|
||||
Reference in New Issue
Block a user