From 201d95c84e634e53bf91cce997fabefd88350729 Mon Sep 17 00:00:00 2001
From: John Doe
Date: Sun, 7 Dec 2025 21:08:48 +0300
Subject: [PATCH] [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.
---
src/services/droidAccountService.js | 11 ++++-
src/services/droidRelayService.js | 21 +++++---
.../src/components/accounts/AccountForm.vue | 48 +++++++++++++++++++
3 files changed, 72 insertions(+), 8 deletions(-)
diff --git a/src/services/droidAccountService.js b/src/services/droidAccountService.js
index f0f50c64..ccca2bd4 100644
--- a/src/services/droidAccountService.js
+++ b/src/services/droidAccountService.js
@@ -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
diff --git a/src/services/droidRelayService.js b/src/services/droidRelayService.js
index f2f7e455..e62d5e85 100644
--- a/src/services/droidRelayService.js
+++ b/src/services/droidRelayService.js
@@ -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
diff --git a/web/admin-spa/src/components/accounts/AccountForm.vue b/web/admin-spa/src/components/accounts/AccountForm.vue
index a3f77c76..f135a1a5 100644
--- a/web/admin-spa/src/components/accounts/AccountForm.vue
+++ b/web/admin-spa/src/components/accounts/AccountForm.vue
@@ -1944,6 +1944,22 @@
rows="4"
/>
+
+
+
+
+
+
+ 留空使用默认值 factory-cli/0.32.1,可根据需要自定义
+
+
@@ -1989,6 +2005,22 @@
+
+
+
+
+
+ 留空使用默认值 factory-cli/0.32.1,可根据需要自定义
+
+
+
@@ -3639,6 +3671,22 @@
+
+
+
+
+
+ 留空使用默认值 factory-cli/0.32.1,可根据需要自定义
+
+
+