feat(gateway): add web search emulation for Anthropic API Key accounts
Inject web search capability for Claude Console (API Key) accounts that don't natively support Anthropic's web_search tool. When a pure web_search request is detected, the gateway calls Brave Search or Tavily API directly and constructs an Anthropic-protocol-compliant SSE/JSON response without forwarding to upstream. Backend: - New `pkg/websearch/` SDK: Brave and Tavily provider implementations with io.LimitReader, proxy support, and Redis-based quota tracking (Lua atomic INCR + TTL, DECR rollback on failure) - Global config via `settings.web_search_emulation_config` (JSON) with in-process cache + singleflight, input validation, API key merge on save, and sanitized API responses - Channel-level toggle via `channels.features_config` JSONB column (DB migration 101) - Account-level toggle via `accounts.extra.web_search_emulation` - Request interception in `Forward()` with SSE streaming response construction using json.Marshal (no manual string concatenation) - Manager hot-reload: `RebuildWebSearchManager()` called on config save and startup via `SetWebSearchRedisClient()` - 70 unit tests covering providers, manager, config validation, sanitization, tool detection, query extraction, and response building Frontend: - Settings → Gateway tab: Web Search Emulation config card with global toggle, provider list (add/remove, API key, priority, quota, proxy) - Channels → Anthropic tab: web search emulation toggle with global state linkage (disabled when global off) - Account Create/Edit modals: web search emulation toggle for API Key type with Toggle component - Full i18n coverage (zh + en)
This commit is contained in:
@@ -1836,6 +1836,9 @@ export default {
|
||||
defaultPerRequestPrice: 'Default per-request price (fallback when no tier matches)',
|
||||
defaultImagePrice: 'Default image price (fallback when no tier matches)',
|
||||
platformConfig: 'Platform Configuration',
|
||||
webSearchEmulation: 'Web Search Emulation',
|
||||
webSearchEmulationHint: '⚠️ When enabled, all accounts in this channel\'s Anthropic groups will intercept web_search requests. Use with caution.',
|
||||
webSearchEmulationGlobalDisabled: 'Please enable the global switch first in Settings → Gateway → Web Search Emulation',
|
||||
basicSettings: 'Basic Settings',
|
||||
addPlatform: 'Add Platform',
|
||||
noPlatforms: 'Click "Add Platform" to start configuring the channel',
|
||||
@@ -2325,7 +2328,10 @@ export default {
|
||||
anthropic: {
|
||||
apiKeyPassthrough: 'Auto passthrough (auth only)',
|
||||
apiKeyPassthroughDesc:
|
||||
'Only applies to Anthropic API Key accounts. When enabled, messages/count_tokens are forwarded in passthrough mode with auth replacement only, while billing/concurrency/audit and safety filtering are preserved. Disable to roll back immediately.'
|
||||
'Only applies to Anthropic API Key accounts. When enabled, messages/count_tokens are forwarded in passthrough mode with auth replacement only, while billing/concurrency/audit and safety filtering are preserved. Disable to roll back immediately.',
|
||||
webSearchEmulation: 'Web Search Emulation',
|
||||
webSearchEmulationDesc:
|
||||
'Enable web search emulation for this API Key account. When a pure web_search request is detected, the gateway calls a third-party search API and constructs the response locally.',
|
||||
},
|
||||
modelRestriction: 'Model Restriction (Optional)',
|
||||
modelWhitelist: 'Model Whitelist',
|
||||
@@ -4358,6 +4364,31 @@ export default {
|
||||
cchSigning: 'CCH Signing',
|
||||
cchSigningHint: 'Sign the billing header in forwarded requests with CCH hash. When disabled, the placeholder is preserved.',
|
||||
},
|
||||
webSearchEmulation: {
|
||||
title: 'Web Search Emulation',
|
||||
description: 'Inject web search capability for Anthropic API Key accounts that don\'t natively support it',
|
||||
enabled: 'Enable Web Search Emulation',
|
||||
enabledHint: 'Global switch. When disabled, web search emulation is inactive for all channels and accounts.',
|
||||
providers: 'Search Providers',
|
||||
addProvider: 'Add Provider',
|
||||
providerType: 'Provider Type',
|
||||
apiKey: 'API Key',
|
||||
apiKeyPlaceholder: 'Enter API Key',
|
||||
apiKeyConfigured: 'Configured',
|
||||
priority: 'Priority',
|
||||
priorityHint: 'Lower number = higher priority',
|
||||
quotaLimit: 'Quota Limit',
|
||||
quotaLimitHint: '0 = unlimited',
|
||||
quotaRefreshInterval: 'Refresh Interval',
|
||||
quotaUsed: 'Used',
|
||||
proxy: 'Proxy',
|
||||
expiresAt: 'Expires At',
|
||||
removeProvider: 'Remove',
|
||||
daily: 'Daily',
|
||||
weekly: 'Weekly',
|
||||
monthly: 'Monthly',
|
||||
noProviders: 'No search providers configured',
|
||||
},
|
||||
site: {
|
||||
title: 'Site Settings',
|
||||
description: 'Customize site branding',
|
||||
|
||||
@@ -1915,6 +1915,9 @@ export default {
|
||||
defaultPerRequestPrice: '默认单次价格(未命中层级时使用)',
|
||||
defaultImagePrice: '默认图片价格(未命中层级时使用)',
|
||||
platformConfig: '平台配置',
|
||||
webSearchEmulation: 'Web Search 模拟',
|
||||
webSearchEmulationHint: '⚠️ 开启后该渠道下所有 Anthropic 分组的账号将自动拦截 web_search 请求,请谨慎操作',
|
||||
webSearchEmulationGlobalDisabled: '请先在系统设置 → 网关 → Web Search 模拟中启用全局开关',
|
||||
basicSettings: '基础设置',
|
||||
addPlatform: '添加平台',
|
||||
noPlatforms: '点击"添加平台"开始配置渠道',
|
||||
@@ -2472,7 +2475,10 @@ export default {
|
||||
anthropic: {
|
||||
apiKeyPassthrough: '自动透传(仅替换认证)',
|
||||
apiKeyPassthroughDesc:
|
||||
'仅对 Anthropic API Key 生效。开启后,messages/count_tokens 请求将透传上游并仅替换认证,保留计费/并发/审计及必要安全过滤;关闭即可回滚到现有兼容链路。'
|
||||
'仅对 Anthropic API Key 生效。开启后,messages/count_tokens 请求将透传上游并仅替换认证,保留计费/并发/审计及必要安全过滤;关闭即可回滚到现有兼容链路。',
|
||||
webSearchEmulation: 'Web Search 模拟',
|
||||
webSearchEmulationDesc:
|
||||
'为该 API Key 账号启用 web search 模拟。客户端发送纯 web_search 请求时,由网关调用第三方搜索 API 并构造响应返回。',
|
||||
},
|
||||
modelRestriction: '模型限制(可选)',
|
||||
modelWhitelist: '模型白名单',
|
||||
@@ -4520,6 +4526,31 @@ export default {
|
||||
cchSigning: 'CCH 签名',
|
||||
cchSigningHint: '对转发请求的 billing header 进行 CCH 哈希签名。关闭时保留原始占位符。',
|
||||
},
|
||||
webSearchEmulation: {
|
||||
title: 'Web Search 模拟',
|
||||
description: '为不原生支持搜索的 Anthropic API Key 账号注入 web search 能力',
|
||||
enabled: '启用 Web Search 模拟',
|
||||
enabledHint: '全局开关。关闭后所有渠道和账号的 web search 模拟均不生效。',
|
||||
providers: '搜索服务商',
|
||||
addProvider: '添加服务商',
|
||||
providerType: '服务商类型',
|
||||
apiKey: 'API Key',
|
||||
apiKeyPlaceholder: '输入 API Key',
|
||||
apiKeyConfigured: '已配置',
|
||||
priority: '优先级',
|
||||
priorityHint: '数值越小优先级越高',
|
||||
quotaLimit: '配额上限',
|
||||
quotaLimitHint: '0 表示无限制',
|
||||
quotaRefreshInterval: '刷新周期',
|
||||
quotaUsed: '已使用',
|
||||
proxy: '代理',
|
||||
expiresAt: '过期时间',
|
||||
removeProvider: '删除',
|
||||
daily: '每日',
|
||||
weekly: '每周',
|
||||
monthly: '每月',
|
||||
noProviders: '未配置搜索服务商',
|
||||
},
|
||||
site: {
|
||||
title: '站点设置',
|
||||
description: '自定义站点品牌',
|
||||
|
||||
Reference in New Issue
Block a user