mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
[fix] Droid: dynamic x-api-provider and custom User-Agent support
- Dynamic x-api-provider selection for OpenAI endpoint based on model - Models with '-max' suffix use 'openai' provider - Other models use 'azure_openai' provider - Fixes gpt-5.1-codex-max model compatibility issue - Update default User-Agent to factory-cli/0.32.1 - Add custom User-Agent field for Droid accounts - Backend: userAgent field in createAccount and updateAccount - Frontend: User-Agent input in account creation/edit UI - Supports all Droid auth modes: OAuth, Manual, API Key This resolves the issue where gpt-5.1-codex-max failed with 'Azure OpenAI only supports...' error due to incorrect provider header.
This commit is contained in:
@@ -556,7 +556,8 @@ class DroidAccountService {
|
||||
tokenType = 'Bearer',
|
||||
authenticationMethod = '',
|
||||
expiresIn = null,
|
||||
apiKeys = []
|
||||
apiKeys = [],
|
||||
userAgent = '' // 自定义 User-Agent
|
||||
} = options
|
||||
|
||||
const accountId = uuidv4()
|
||||
@@ -832,7 +833,8 @@ class DroidAccountService {
|
||||
: '',
|
||||
apiKeys: hasApiKeys ? JSON.stringify(apiKeyEntries) : '',
|
||||
apiKeyCount: hasApiKeys ? String(apiKeyEntries.length) : '0',
|
||||
apiKeyStrategy: hasApiKeys ? 'random_sticky' : ''
|
||||
apiKeyStrategy: hasApiKeys ? 'random_sticky' : '',
|
||||
userAgent: userAgent || '' // 自定义 User-Agent
|
||||
}
|
||||
|
||||
await redis.setDroidAccount(accountId, accountData)
|
||||
@@ -931,6 +933,11 @@ class DroidAccountService {
|
||||
sanitizedUpdates.endpointType = this._sanitizeEndpointType(sanitizedUpdates.endpointType)
|
||||
}
|
||||
|
||||
// 处理 userAgent 字段
|
||||
if (typeof sanitizedUpdates.userAgent === 'string') {
|
||||
sanitizedUpdates.userAgent = sanitizedUpdates.userAgent.trim()
|
||||
}
|
||||
|
||||
const parseProxyConfig = (value) => {
|
||||
if (!value) {
|
||||
return null
|
||||
|
||||
@@ -26,7 +26,7 @@ class DroidRelayService {
|
||||
comm: '/o/v1/chat/completions'
|
||||
}
|
||||
|
||||
this.userAgent = 'factory-cli/0.19.12'
|
||||
this.userAgent = 'factory-cli/0.32.1'
|
||||
this.systemPrompt = SYSTEM_PROMPT
|
||||
this.API_KEY_STICKY_PREFIX = 'droid_api_key'
|
||||
}
|
||||
@@ -241,7 +241,8 @@ class DroidRelayService {
|
||||
accessToken,
|
||||
normalizedRequestBody,
|
||||
normalizedEndpoint,
|
||||
clientHeaders
|
||||
clientHeaders,
|
||||
account
|
||||
)
|
||||
|
||||
if (selectedApiKey) {
|
||||
@@ -982,11 +983,13 @@ class DroidRelayService {
|
||||
/**
|
||||
* 构建请求头
|
||||
*/
|
||||
_buildHeaders(accessToken, requestBody, endpointType, clientHeaders = {}) {
|
||||
_buildHeaders(accessToken, requestBody, endpointType, clientHeaders = {}, account = null) {
|
||||
// 使用账户配置的 userAgent 或默认值
|
||||
const userAgent = account?.userAgent || this.userAgent
|
||||
const headers = {
|
||||
'content-type': 'application/json',
|
||||
authorization: `Bearer ${accessToken}`,
|
||||
'user-agent': this.userAgent,
|
||||
'user-agent': userAgent,
|
||||
'x-factory-client': 'cli',
|
||||
connection: 'keep-alive'
|
||||
}
|
||||
@@ -1003,9 +1006,15 @@ class DroidRelayService {
|
||||
}
|
||||
}
|
||||
|
||||
// OpenAI 特定头
|
||||
// OpenAI 特定头 - 根据模型动态选择 provider
|
||||
if (endpointType === 'openai') {
|
||||
headers['x-api-provider'] = 'azure_openai'
|
||||
const model = (requestBody?.model || '').toLowerCase()
|
||||
// -max 模型使用 openai provider,其他使用 azure_openai
|
||||
if (model.includes('-max')) {
|
||||
headers['x-api-provider'] = 'openai'
|
||||
} else {
|
||||
headers['x-api-provider'] = 'azure_openai'
|
||||
}
|
||||
}
|
||||
|
||||
// Comm 端点根据模型动态设置 provider
|
||||
|
||||
@@ -1944,6 +1944,22 @@
|
||||
rows="4"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Droid User-Agent 配置 (OAuth/Manual 模式) -->
|
||||
<div v-if="form.platform === 'droid'">
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
|
||||
>自定义 User-Agent (可选)</label
|
||||
>
|
||||
<input
|
||||
v-model="form.userAgent"
|
||||
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
|
||||
placeholder="factory-cli/0.32.1"
|
||||
type="text"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
留空使用默认值 factory-cli/0.32.1,可根据需要自定义
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API Key 模式输入 -->
|
||||
@@ -1989,6 +2005,22 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Droid User-Agent 配置 -->
|
||||
<div>
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
|
||||
>自定义 User-Agent (可选)</label
|
||||
>
|
||||
<input
|
||||
v-model="form.userAgent"
|
||||
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
|
||||
placeholder="factory-cli/0.32.1"
|
||||
type="text"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
留空使用默认值 factory-cli/0.32.1,可根据需要自定义
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-white/70 p-3 text-xs text-purple-800 dark:border-purple-700 dark:bg-purple-800/20 dark:text-purple-100"
|
||||
>
|
||||
@@ -3639,6 +3671,22 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Droid User-Agent 配置 (编辑模式) -->
|
||||
<div v-if="form.platform === 'droid'">
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
|
||||
>自定义 User-Agent (可选)</label
|
||||
>
|
||||
<input
|
||||
v-model="form.userAgent"
|
||||
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
|
||||
placeholder="factory-cli/0.32.1"
|
||||
type="text"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
留空使用默认值 factory-cli/0.32.1,可根据需要自定义
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 代理设置 -->
|
||||
<ProxyConfig v-model="form.proxy" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user