Merge upstream/main into fix/api-double-billing

This commit is contained in:
benjamin committed 2026-07-13 11:10:33 +08:00
commit 0d9c140bc2
120 files changed
+6391 -402

No files matched your search

@@ -0,0 +1,30 @@
import { describe, expect, it } from 'vitest'
import en from '../locales/en'
import zh from '../locales/zh'
describe('OpenAI Fast/Flex policy locale keys', () => {
it('exposes user scope copy at the runtime zh path', () => {
expect(zh.admin.settings.openaiFastPolicy).toMatchObject({
userIds: '指定用户',
userIdsHint: '输入任意邮箱关键词进行模糊搜索。留空表示对全部 Sub2API 用户生效;选中用户的 API Key 请求优先匹配用户规则。',
userSearchPlaceholder: '输入用户邮箱搜索',
userSearchEmpty: '未找到匹配用户',
userDeleted: '(已删除)',
userIdFallback: '用户 #{id}',
removeUser: '移除用户'
})
})
it('exposes user scope copy at the runtime en path', () => {
expect(en.admin.settings.openaiFastPolicy).toMatchObject({
userIds: 'Specific users',
userIdsHint: 'Type any part of a user email to search. Leave empty to apply to all Sub2API users. Selected users match requests from their API keys and take precedence over global rules.',
userSearchPlaceholder: 'Search by user email',
userSearchEmpty: 'No matching users found',
userDeleted: '(deleted)',
userIdFallback: 'User #{id}',
removeUser: 'Remove user'
})
})
})
@@ -1,5 +1,6 @@
import { describe, expect, it } from 'vitest'
import en from '@/i18n/locales/en'
import zh from '@/i18n/locales/zh'
function flattenKeys(obj: Record<string, any>, prefix = ''): string[] {
const keys: string[] = []
@@ -35,4 +36,18 @@ describe('groups locale key completeness', () => {
const enKeys = flattenKeys(en)
expect(enKeys).toContain('admin.groups.failedToSave')
})
const webSearchPricingKeys = [
'admin.groups.webSearchPricing.title',
'admin.groups.webSearchPricing.pricePerCall',
'admin.groups.webSearchPricing.pricePerCallHint',
'admin.groups.webSearchPricing.finalPricePreview',
]
for (const key of webSearchPricingKeys) {
it(`en and zh locales both have ${key}`, () => {
expect(flattenKeys(en)).toContain(key)
expect(flattenKeys(zh)).toContain(key)
})
}
})
@@ -939,6 +939,13 @@ export default {
finalPricePreview: 'Final per-second price preview',
notConfigured: 'Not configured'
},
webSearchPricing: {
title: 'Codex Web Search Pricing',
pricePerCall: 'Price per search call (USD)',
pricePerCallHint:
'Leave empty to use the default $0.01 per call (official pricing: $10 per 1,000 calls); 0 means free. The group rate multiplier is applied on top.',
finalPricePreview: 'Per-call price after current multiplier: {price}'
},
peakRate: {
enable: 'Enable peak rate multiplier',
peakStart: 'Peak start',
@@ -979,11 +979,6 @@ export default {
scopeOAuth: 'OAuth only',
scopeAPIKey: 'API Key only',
scopeBedrock: 'Bedrock only',
userIds: 'Specific user IDs',
userIdsHint: 'Leave empty to apply to all Sub2API users. Specified users match requests from their API keys and take precedence over global rules.',
userIdPlaceholder: 'e.g., 1001',
addUserId: 'Add user ID',
removeUserId: 'Remove user ID',
errorMessage: 'Error message',
errorMessagePlaceholder: 'Custom error message when blocked',
errorMessageHint: 'Leave empty for default message',
@@ -1024,6 +1019,13 @@ export default {
scopeOAuth: 'OAuth only',
scopeAPIKey: 'API Key only',
scopeBedrock: 'Bedrock only',
userIds: 'Specific users',
userIdsHint: 'Type any part of a user email to search. Leave empty to apply to all Sub2API users. Selected users match requests from their API keys and take precedence over global rules.',
userSearchPlaceholder: 'Search by user email',
userSearchEmpty: 'No matching users found',
userDeleted: '(deleted)',
userIdFallback: 'User #{id}',
removeUser: 'Remove user',
errorMessage: 'Error message',
errorMessagePlaceholder: 'Custom error message when blocked',
errorMessageHint: 'Leave empty for the default message.',
@@ -146,6 +146,7 @@ export default {
geminiCli: 'Gemini CLI',
codexCli: 'Codex CLI',
codexCliWs: 'Codex CLI (WebSocket)',
grokCli: 'Grok CLI',
opencode: 'OpenCode',
},
antigravity: {
@@ -160,6 +161,12 @@ export default {
modelComment: 'If you have Gemini 3 access, you can use: gemini-3-pro-preview',
note: 'These environment variables will be active in the current terminal session. For permanent configuration, add them to ~/.bashrc, ~/.zshrc, or the appropriate configuration file.',
},
grok: {
description: 'Configure Grok Build or OpenCode to send Responses API traffic through your Sub2API Grok group.',
configTomlHint: 'Back up an existing config.toml before merging this model entry. Run grok inspect after saving to verify the effective configuration.',
note: 'Save the file as ~/.grok/config.toml, then run grok inspect and select sub2api-grok from /model.',
noteWindows: 'Save the file as %USERPROFILE%\\.grok\\config.toml, then run grok inspect and select sub2api-grok from /model.',
},
opencode: {
title: 'OpenCode Example',
subtitle: 'opencode.json',
@@ -930,6 +930,13 @@ export default {
finalPricePreview: '最终每秒价格预览',
notConfigured: '未配置'
},
webSearchPricing: {
title: 'Codex 网页搜索计费',
pricePerCall: '搜索单次价格(USD/次)',
pricePerCallHint:
'留空使用默认价 $0.01/次(官方定价 $10/1000 次);填 0 表示免费。实际扣费会叠加分组费率倍数。',
finalPricePreview: '应用当前倍率后的单次价格:{price}'
},
peakRate: {
enable: '启用高峰倍率',
peakStart: '高峰开始',
@@ -974,11 +974,6 @@ export default {
scopeOAuth: '仅 OAuth 账号',
scopeAPIKey: '仅 API Key 账号',
scopeBedrock: '仅 Bedrock 账号',
userIds: '指定用户 ID',
userIdsHint: '留空表示对全部 Sub2API 用户生效。指定后仅匹配这些用户的 API Key 请求,且优先于全局规则。',
userIdPlaceholder: '例如: 1001',
addUserId: '添加用户 ID',
removeUserId: '移除用户 ID',
errorMessage: '错误消息',
errorMessagePlaceholder: '拦截时返回的自定义错误消息',
errorMessageHint: '留空则使用默认错误消息',
@@ -1019,6 +1014,13 @@ export default {
scopeOAuth: '仅 OAuth 账号',
scopeAPIKey: '仅 API Key 账号',
scopeBedrock: '仅 Bedrock 账号',
userIds: '指定用户',
userIdsHint: '输入任意邮箱关键词进行模糊搜索。留空表示对全部 Sub2API 用户生效;选中用户的 API Key 请求优先匹配用户规则。',
userSearchPlaceholder: '输入用户邮箱搜索',
userSearchEmpty: '未找到匹配用户',
userDeleted: '(已删除)',
userIdFallback: '用户 #{id}',
removeUser: '移除用户',
errorMessage: '错误消息',
errorMessagePlaceholder: '拦截时返回的自定义错误消息',
errorMessageHint: '留空则使用默认错误消息。',
@@ -147,6 +147,7 @@ export default {
geminiCli: 'Gemini CLI',
codexCli: 'Codex CLI',
codexCliWs: 'Codex CLI (WebSocket)',
grokCli: 'Grok CLI',
opencode: 'OpenCode'
},
antigravity: {
@@ -164,6 +165,12 @@ export default {
modelComment: '如果你有 Gemini 3 权限可以填:gemini-3-pro-preview',
note: '这些环境变量将在当前终端会话中生效。如需永久配置,请将其添加到 ~/.bashrc、~/.zshrc 或相应的配置文件中。'
},
grok: {
description: '配置 Grok Build 或 OpenCode,让 Responses API 请求通过当前 Sub2API Grok 分组发送。',
configTomlHint: '如已有 config.toml,请先备份再合并此模型配置。保存后运行 grok inspect 验证生效配置。',
note: '保存为 ~/.grok/config.toml,然后运行 grok inspect,并在 /model 中选择 sub2api-grok。',
noteWindows: '保存为 %USERPROFILE%\\.grok\\config.toml,然后运行 grok inspect,并在 /model 中选择 sub2api-grok。'
},
opencode: {
title: 'OpenCode 配置示例',
subtitle: 'opencode.json',