Merge pull request #7877 from hezhaoqian1/fix/upstream-channel-monitor-zhipu-path

fix(channel-monitor): build zhipu probe URL from the configured endpoint
This commit is contained in:
Wesley Liddick
2026-10-08 11:32:38 +08:00
committed by GitHub
2 changed files with 51 additions and 1 deletions
@@ -297,7 +297,7 @@ func callProvider(ctx context.Context, provider, endpoint, apiKey, model, prompt
return "", "", 0, err
}
headers := mergeHeaders(adapter.buildHeaders(apiKey), opts)
full := joinURL(endpoint, adapter.buildPath(model))
full := joinURL(endpoint, monitorRequestPath(provider, endpoint, adapter, model))
respBytes, status, err := postRawJSON(ctx, full, body, headers)
if err != nil {
return "", "", status, err
@@ -556,6 +556,37 @@ func postRawJSON(ctx context.Context, fullURL string, payload []byte, headers ma
return respBody, resp.StatusCode, nil
}
// monitorRequestPath 返回探测请求路径。智谱按 endpoint 区分:
// - 已带 /paas/v4(含 Coding Plan 的 /api/coding/paas/v4):只追加 /chat/completions
// - 官方域名根地址:/api/paas/v4/chat/completions
// - 中转站 / 本站网关:只暴露 OpenAI 兼容的 /v1/chat/completions,与 Kimi / DeepSeek 一致
func monitorRequestPath(provider, endpoint string, adapter providerAdapter, model string) string {
if provider != MonitorProviderZhipu {
return adapter.buildPath(model)
}
u, err := url.Parse(strings.TrimSpace(endpoint))
if err != nil {
return providerOpenAIPath
}
if strings.Contains(u.EscapedPath(), "/paas/v4") {
return "/chat/completions"
}
if isZhipuOfficialHost(u) {
return adapter.buildPath(model)
}
return providerOpenAIPath
}
func isZhipuOfficialHost(u *url.URL) bool {
host := strings.ToLower(u.Hostname())
for _, official := range []string{"bigmodel.cn", "z.ai"} {
if host == official || strings.HasSuffix(host, "."+official) {
return true
}
}
return false
}
// joinURL 保留 base 的上游路径前缀,并避免重复追加已有的 API 路径前缀。
// 使用 EscapedPath 匹配完整路径段,避免把 hostname 或编码斜杠当作路径。
func joinURL(base, path string) string {
@@ -84,6 +84,9 @@ func TestCallProvider_BasePath(t *testing.T) {
{"openai responses version", MonitorProviderOpenAI, MonitorAPIModeResponses, "/relay/v1", "/relay/v1/responses"},
{"gemini version", MonitorProviderGemini, "", "/relay/v1beta", "/relay/v1beta/models/test-model:generateContent"},
{"zhipu version", MonitorProviderZhipu, "", "/api/paas/v4", "/api/paas/v4/chat/completions"},
{"zhipu coding plan", MonitorProviderZhipu, "", "/api/coding/paas/v4", "/api/coding/paas/v4/chat/completions"},
{"zhipu relay origin", MonitorProviderZhipu, "", "", "/v1/chat/completions"},
{"zhipu relay version", MonitorProviderZhipu, "", "/relay/v1", "/relay/v1/chat/completions"},
} {
t.Run(tc.name, func(t *testing.T) {
_, _, status, err := callProvider(context.Background(), tc.provider,
@@ -94,3 +97,19 @@ func TestCallProvider_BasePath(t *testing.T) {
})
}
}
func TestMonitorRequestPath_Zhipu(t *testing.T) {
adapter := providerAdapters[MonitorProviderZhipu]
for endpoint, want := range map[string]string{
"https://open.bigmodel.cn": providerZhipuPath,
"https://api.z.ai": providerZhipuPath,
"https://open.bigmodel.cn/api/coding/paas/v4": "/chat/completions",
"https://birdapi.up.railway.app": providerOpenAIPath,
"https://notbigmodel.cn": providerOpenAIPath,
"https://relay.example.com/v1": providerOpenAIPath,
} {
require.Equal(t, want, monitorRequestPath(MonitorProviderZhipu, endpoint, adapter, "glm-5.3-flash"), endpoint)
}
require.Equal(t, providerOpenAIPath,
monitorRequestPath(MonitorProviderDeepseek, "https://birdapi.up.railway.app", providerAdapters[MonitorProviderDeepseek], "m"))
}