mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
feat(bedrock): add Claude Code compatibility transformations for Bedrock accounts
Add channel-level Bedrock CC compatibility toggle (similar to web_search_emulation) that fixes 4 types of Bedrock 400 errors seen with Claude Code: 1. thinking.type "enabled" → "adaptive" for Opus 4.7+ (only supports adaptive) 2. Add default budget_tokens when missing for older models 3. Replace illegal characters in tool_use IDs to match Bedrock's ^[a-zA-Z0-9_-]+$ pattern 4. anthropic_version / invalid beta flag (already handled elsewhere) Transformations run in Forward() before any forwarding path, so both native Bedrock accounts and apikey passthrough accounts pointing to Bedrock relays benefit. Includes channel-level toggle UI and unit tests.
This commit is contained in:
@@ -2358,6 +2358,8 @@ export default {
|
||||
webSearchEmulationGlobalDisabled: 'Please enable the global switch first in Settings → Gateway → Web Search Emulation',
|
||||
codexImageGenerationBridge: 'Codex Image Generation Bridge',
|
||||
codexImageGenerationBridgeHint: 'When enabled, Codex /responses text requests in OpenAI groups may be automatically given the image_generation tool. Keep off unless the routed accounts support image generation.',
|
||||
bedrockCCCompat: 'Bedrock CC Compatibility',
|
||||
bedrockCCCompatHint: '⚠️ When enabled, requests to Bedrock accounts in this channel will be transformed for Claude Code compatibility (thinking type conversion, tool_use ID sanitization).',
|
||||
basicSettings: 'Basic Settings',
|
||||
addPlatform: 'Add Platform',
|
||||
noPlatforms: 'Click "Add Platform" to start configuring the channel',
|
||||
|
||||
@@ -2435,6 +2435,8 @@ export default {
|
||||
webSearchEmulationGlobalDisabled: '请先在系统设置 → 网关 → Web Search 模拟中启用全局开关',
|
||||
codexImageGenerationBridge: 'Codex 图片生成桥接',
|
||||
codexImageGenerationBridgeHint: '开启后,OpenAI 分组的 Codex /responses 文本请求可能会被自动注入 image_generation 工具。仅在路由账号支持图片生成时开启。',
|
||||
bedrockCCCompat: 'Bedrock CC 兼容',
|
||||
bedrockCCCompatHint: '⚠️ 开启后,该渠道下 Bedrock 账号的请求将进行 Claude Code 兼容处理(thinking 类型转换、tool_use ID 清理)',
|
||||
basicSettings: '基础设置',
|
||||
addPlatform: '添加平台',
|
||||
noPlatforms: '点击"添加平台"开始配置渠道',
|
||||
|
||||
@@ -354,6 +354,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bedrock CC Compatibility (Anthropic only) -->
|
||||
<div v-if="section.platform === 'anthropic'" class="border-t border-gray-200 pt-3 dark:border-dark-600">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<label class="text-xs font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.channels.form.bedrockCCCompat') }}
|
||||
</label>
|
||||
<p class="mt-0.5 text-[11px] text-amber-600 dark:text-amber-400">
|
||||
{{ t('admin.channels.form.bedrockCCCompatHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="section.bedrock_cc_compat" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Model Mapping -->
|
||||
<div>
|
||||
<div class="mb-1 flex items-center justify-between">
|
||||
@@ -669,6 +684,7 @@ interface PlatformSection {
|
||||
model_pricing: PricingFormEntry[]
|
||||
web_search_emulation: boolean
|
||||
codex_image_generation_bridge: boolean
|
||||
bedrock_cc_compat: boolean
|
||||
account_stats_pricing_rules: FormPricingRule[]
|
||||
}
|
||||
|
||||
@@ -765,6 +781,7 @@ function addPlatformSection(platform: GroupPlatform) {
|
||||
model_pricing: [],
|
||||
web_search_emulation: false,
|
||||
codex_image_generation_bridge: false,
|
||||
bedrock_cc_compat: false,
|
||||
account_stats_pricing_rules: [],
|
||||
})
|
||||
}
|
||||
@@ -1125,6 +1142,19 @@ function formToAPI(): { group_ids: number[], model_pricing: ChannelModelPricing[
|
||||
delete featuresConfig.codex_image_generation_bridge
|
||||
}
|
||||
|
||||
const bedrockCCCompat: Record<string, boolean> = {}
|
||||
for (const section of form.platforms) {
|
||||
if (!section.enabled) continue
|
||||
if (section.platform === 'anthropic') {
|
||||
bedrockCCCompat[section.platform] = !!section.bedrock_cc_compat
|
||||
}
|
||||
}
|
||||
if (Object.keys(bedrockCCCompat).length > 0) {
|
||||
featuresConfig.bedrock_cc_compat = bedrockCCCompat
|
||||
} else {
|
||||
delete featuresConfig.bedrock_cc_compat
|
||||
}
|
||||
|
||||
return { group_ids, model_pricing, model_mapping, features_config: featuresConfig }
|
||||
}
|
||||
|
||||
@@ -1175,6 +1205,8 @@ function apiToForm(channel: Channel): PlatformSection[] {
|
||||
const webSearchEnabled = wsEmulation?.[platform] === true
|
||||
const codexImageGenerationBridge = fc?.codex_image_generation_bridge as Record<string, boolean> | undefined
|
||||
const codexImageGenerationBridgeEnabled = codexImageGenerationBridge?.[platform] === true
|
||||
const bedrockCCCompat = fc?.bedrock_cc_compat as Record<string, boolean> | undefined
|
||||
const bedrockCCCompatEnabled = bedrockCCCompat?.[platform] === true
|
||||
|
||||
sections.push({
|
||||
platform,
|
||||
@@ -1185,6 +1217,7 @@ function apiToForm(channel: Channel): PlatformSection[] {
|
||||
model_pricing: pricing,
|
||||
web_search_emulation: webSearchEnabled,
|
||||
codex_image_generation_bridge: codexImageGenerationBridgeEnabled,
|
||||
bedrock_cc_compat: bedrockCCCompatEnabled,
|
||||
account_stats_pricing_rules: [],
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user