实现listExperiments端点和通用转发机制

- 添加forwardToCodeAssist通用转发函数支持简单端点
- 添加handleSimpleEndpoint通用路由处理函数
- 注册listExperiments路由(v1internal和v1beta)
- 解决gemini-cli启动时404 Not Found错误
This commit is contained in:
曾庆雷
2025-11-12 14:32:45 +08:00
parent baffd02b02
commit 91ad0658a9
2 changed files with 107 additions and 0 deletions

View File

@@ -349,6 +349,65 @@ router.get('/key-info', authenticateApiKey, async (req, res) => {
}
})
// 通用的简单端点处理函数(用于直接转发的端点)
// 适用于listExperiments 等不需要特殊业务逻辑的端点
async function handleSimpleEndpoint(apiMethod) {
return async (req, res) => {
try {
if (!ensureGeminiPermission(req, res)) {
return undefined
}
const sessionHash = sessionHelper.generateSessionHash(req.body)
// 从路径参数或请求体中获取模型名
const requestedModel = req.body.model || req.params.modelName || 'gemini-2.5-flash'
const { accountId } = await unifiedGeminiScheduler.selectAccountForApiKey(
req.apiKey,
sessionHash,
requestedModel
)
const account = await geminiAccountService.getAccount(accountId)
const { accessToken, refreshToken } = account
const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
logger.info(`${apiMethod} request (${version})`, {
apiKeyId: req.apiKey?.id || 'unknown',
requestBody: req.body
})
// 解析账户的代理配置
let proxyConfig = null
if (account.proxy) {
try {
proxyConfig = typeof account.proxy === 'string' ? JSON.parse(account.proxy) : account.proxy
} catch (e) {
logger.warn('Failed to parse proxy configuration:', e)
}
}
const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig)
// 直接转发请求体,不做特殊处理
const response = await geminiAccountService.forwardToCodeAssist(
client,
apiMethod,
req.body,
proxyConfig
)
res.json(response)
} catch (error) {
const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal'
logger.error(`Error in ${apiMethod} endpoint (${version})`, { error: error.message })
res.status(500).json({
error: 'Internal server error',
message: error.message
})
}
}
}
// 共用的 loadCodeAssist 处理函数
async function handleLoadCodeAssist(req, res) {
try {
@@ -1040,6 +1099,7 @@ router.post('/v1internal\\:onboardUser', authenticateApiKey, handleOnboardUser)
router.post('/v1internal\\:countTokens', authenticateApiKey, handleCountTokens)
router.post('/v1internal\\:generateContent', authenticateApiKey, handleGenerateContent)
router.post('/v1internal\\:streamGenerateContent', authenticateApiKey, handleStreamGenerateContent)
router.post('/v1internal\\:listExperiments', authenticateApiKey, handleSimpleEndpoint('listExperiments'))
// v1beta 版本的端点 - 支持动态模型名称
router.post('/v1beta/models/:modelName\\:loadCodeAssist', authenticateApiKey, handleLoadCodeAssist)
@@ -1055,6 +1115,11 @@ router.post(
authenticateApiKey,
handleStreamGenerateContent
)
router.post(
'/v1beta/models/:modelName\\:listExperiments',
authenticateApiKey,
handleSimpleEndpoint('listExperiments')
)
// 导出处理函数供标准路由使用
module.exports = router

View File

@@ -1060,6 +1060,47 @@ async function getOauthClient(accessToken, refreshToken, proxyConfig = null) {
return client
}
// 通用的 Code Assist API 转发函数(用于简单的请求/响应端点)
// 适用于loadCodeAssist, onboardUser, countTokens, listExperiments 等不需要特殊处理的端点
async function forwardToCodeAssist(client, apiMethod, requestBody, proxyConfig = null) {
const axios = require('axios')
const CODE_ASSIST_ENDPOINT = 'https://cloudcode-pa.googleapis.com'
const CODE_ASSIST_API_VERSION = 'v1internal'
const { token } = await client.getAccessToken()
const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig)
logger.info(`📡 ${apiMethod} API调用开始`)
const axiosConfig = {
url: `${CODE_ASSIST_ENDPOINT}/${CODE_ASSIST_API_VERSION}:${apiMethod}`,
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
},
data: requestBody,
timeout: 30000
}
// 添加代理配置
if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info(
`🌐 Using proxy for ${apiMethod}: ${ProxyHelper.getProxyDescription(proxyConfig)}`
)
} else {
logger.debug(`🌐 No proxy configured for ${apiMethod}`)
}
const response = await axios(axiosConfig)
logger.info(`${apiMethod} API调用成功`)
return response.data
}
// 调用 Google Code Assist API 的 loadCodeAssist 方法(支持代理)
async function loadCodeAssist(client, projectId = null, proxyConfig = null) {
const axios = require('axios')
@@ -1529,6 +1570,7 @@ module.exports = {
getAccountRateLimitInfo,
isTokenExpired,
getOauthClient,
forwardToCodeAssist, // 通用转发函数
loadCodeAssist,
getOnboardTier,
onboardUser,