fix(provider): 将rust分支的gemini cli端点行为对齐到python分支 (#321)

* fix(provider): 对齐 Vertex/Gemini 上游发包与 Python master

- provider-transport: 为 custom+aiplatform 推断 Vertex API key 上下文并统一 URL 构建顺序,复用共享 request_url 构建最终上游地址
- ai-pipeline/gateway: Vertex Gemini 路径改为仅使用 URL query key,不再向上游附带 x-goog-api-key header;同步对齐 standard/admin/test-connection/runtime miss 摘要中的最终 URL
- gemini conversion: 按 Python master 输出 Gemini 请求体,补齐 system_instruction / generation_config / tool_config / function_declarations 形态,并移植 Gemini schema 清洗逻辑
- scheduler/executor: 将最终 upstream_url、mapped_model、key_name 写入候选 extra_data,运行时 miss 诊断优先展示真实展开后的上游 URL 便于服务器排障

* fix(provider): 修复 Vertex provider 测试与本地调度链路

* fix(provider): 对齐 Vertex 本地执行与 Rust CI
This commit is contained in:
Entropy.Xu
2026-04-23 23:01:06 +08:00
committed by GitHub
parent ccec46eddd
commit 0f94f92c37
29 changed files with 1879 additions and 497 deletions

View File

@@ -392,28 +392,40 @@ function filterAvailableApiFormats(formats: string[]): string[] {
return formats.filter(format => availableFormatSet.has(normalizeApiFormat(format)))
}
function getSelectableApiFormats(authType = form.value.auth_type): string[] {
const sorted = sortApiFormats(props.availableApiFormats)
if (props.providerType !== 'vertex_ai') {
return sorted
}
const allowed = getVertexAllowedFormatsByAuth(authType)
return sorted.filter(fmt => allowed.has(normalizeApiFormat(fmt)))
}
function sanitizeApiFormats(formats: string[], authType = form.value.auth_type): string[] {
const selectable = new Set(getSelectableApiFormats(authType).map(normalizeApiFormat))
if (selectable.size === 0) {
return []
}
return formats.filter(format => selectable.has(normalizeApiFormat(format)))
}
function getDefaultApiFormats(): string[] {
const endpointFormat = props.endpoint?.api_format
if (endpointFormat) {
const endpointFormats = filterAvailableApiFormats([endpointFormat])
const endpointFormats = sanitizeApiFormats([endpointFormat])
if (endpointFormats.length > 0) {
return endpointFormats
}
}
const firstAvailableFormat = sortApiFormats(props.availableApiFormats)[0]
const firstAvailableFormat = getSelectableApiFormats()[0]
return firstAvailableFormat ? [firstAvailableFormat] : []
}
// 按 provider/auth_type 过滤后的可用 API 格式列表
const visibleApiFormats = computed(() => {
const sorted = sortApiFormats(props.availableApiFormats)
if (props.providerType !== 'vertex_ai') {
return sorted
}
const allowed = getVertexAllowedFormatsByAuth(form.value.auth_type)
return sorted.filter(fmt => allowed.has(normalizeApiFormat(fmt)))
})
const visibleApiFormats = computed(() => getSelectableApiFormats())
const showAuthTypeSelector = computed(() => props.providerType === 'vertex_ai')
@@ -517,11 +529,7 @@ const form = ref({
watch(
[() => form.value.auth_type, () => props.providerType, () => props.availableApiFormats],
() => {
if (props.providerType !== 'vertex_ai') {
return
}
const allowed = getVertexAllowedFormatsByAuth(form.value.auth_type)
const filtered = form.value.api_formats.filter(fmt => allowed.has(normalizeApiFormat(fmt)))
const filtered = sanitizeApiFormats(form.value.api_formats)
if (filtered.length !== form.value.api_formats.length) {
form.value.api_formats = [...filtered]
}
@@ -536,7 +544,7 @@ watch(
return
}
const filtered = filterAvailableApiFormats(form.value.api_formats)
const filtered = sanitizeApiFormats(form.value.api_formats)
if (filtered.length !== form.value.api_formats.length) {
form.value.api_formats = [...filtered]
return
@@ -639,7 +647,10 @@ function loadKeyData() {
auth_type: props.editingKey.auth_type === 'service_account' ? 'service_account' : 'api_key',
auth_config_text: '', // auth_config 不返回给前端,编辑时需要重新输入
api_formats: props.editingKey.api_formats?.length > 0
? filterAvailableApiFormats(props.editingKey.api_formats)
? sanitizeApiFormats(
props.editingKey.api_formats,
props.editingKey.auth_type === 'service_account' ? 'service_account' : 'api_key'
)
: [], // 编辑模式下保持原有选择,不默认全选
rate_multipliers: { ...(props.editingKey.rate_multipliers || {}) },
internal_priority: props.editingKey.internal_priority ?? 10,
@@ -731,6 +742,8 @@ async function handleSave() {
}
}
form.value.api_formats = sanitizeApiFormats(form.value.api_formats)
// 验证至少选择一个 API 格式
if (form.value.api_formats.length === 0) {
showError('请至少选择一个 API 格式', '验证失败')

View File

@@ -732,6 +732,7 @@ async function handleStartMappingTest() {
displayLabel: `[${endpoint.api_format}] 映射 "${testingModelName.value}"`,
apiFormat: endpoint.api_format,
endpointId: endpoint.id,
endpointBaseUrl: endpoint.base_url,
requestHeaders,
requestBody,
concurrency: isPoolManagedProvider.value ? POOL_TEST_CONCURRENCY : SINGLE_TEST_CONCURRENCY,

View File

@@ -517,6 +517,7 @@ async function handleStartPendingTest() {
displayLabel: `${endpointPrefix}${modelName}`,
apiFormat: endpoint.api_format,
endpointId: endpoint.id,
endpointBaseUrl: endpoint.base_url,
requestHeaders,
requestBody,
concurrency: isPoolManagedProvider.value ? POOL_TEST_CONCURRENCY : SINGLE_TEST_CONCURRENCY,