fix(runtime): M52 把 *url.Error 直打的 19 处换成 trace.URLCause

model / multimodal / tts / embedding 里所有「把 net/http 的 *url.Error 直接打进
错误串」的地方(M51 清单的 B1 组 17 处 + 清单外的同根因 2 处)统一改走
trace.URLCause:错误串只少一段地址,底层原因、哨兵分类、状态码、重试/降级判据
一字不动。

清单内(17):
- model/openai.go: Chat / ChatStream 的 NewRequest、doRequest
- model/anthropic.go: chatOnce / streamOnce 的 NewRequest、doRequest
- multimodal/vision/adapter.go: ask 的 NewRequest、client.Do
- multimodal/voice/cloud.go: postJSON 的 NewRequest、client.Do
- multimodal/voice/dashscope.go: download(预签名 OSS 地址)与 dashscopePost 各两处
- voice/tts/client.go: unreachable(返回值与同一行日志的 err 字段都只留原因,
  地址只由 redactURL(endpoint) 出现一次)
- embedding/api.go: embedChunk 的 client.Do、newEmbeddingRequest 的 NewRequest

清单外同根因(2,均为 %w 形态,B1 清单按 %v 搜时漏掉):
- voice/tts/client.go: speak 的 NewRequest 失败
- embedding/endpoint.go: normalizeEndpointURL 的 url.Parse 失败

测试:5 个新文件 18 个用例,逐处可变异打红(实测:把任一处的 URLCause 去掉 ⇒
对应用例红);dashscope 预签名地址单独一条用例,并另有一条钉住 403 状态码仍在。
This commit is contained in:
AskaEth committed 2026-10-26 19:55:05 +08:00
1 parent 2702777950
commit 969857682f
13 files changed
+657 -20

No files matched your search

@@ -12,6 +12,7 @@ import (
"unicode"
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
)
// 语音链云端一级的 DashScope(阿里百炼)STT/TTS 适配器。请求
@@ -246,11 +247,11 @@ func (t *DashscopeTTS) audioBytes(ctx context.Context, body []byte) ([]byte, err
func (t *DashscopeTTS) download(ctx context.Context, url string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, fmt.Errorf("voice: %w: build: %v", ErrProviderFailed, err)
return nil, fmt.Errorf("voice: %w: build: %v", ErrProviderFailed, trace.URLCause(err))
}
resp, err := t.client.Do(req)
if err != nil {
return nil, fmt.Errorf("voice: %w: download: %v", ErrProviderFailed, err)
return nil, fmt.Errorf("voice: %w: download: %v", ErrProviderFailed, trace.URLCause(err))
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
@@ -380,7 +381,7 @@ func firstNonEmpty(a, b string) string {
func dashscopePost(ctx context.Context, client *http.Client, apiKey, url string, payload []byte, sse string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(payload))
if err != nil {
return nil, fmt.Errorf("voice: %w: build: %v", ErrProviderFailed, err)
return nil, fmt.Errorf("voice: %w: build: %v", ErrProviderFailed, trace.URLCause(err))
}
req.Header.Set("Content-Type", "application/json")
if apiKey != "" {
@@ -391,7 +392,7 @@ func dashscopePost(ctx context.Context, client *http.Client, apiKey, url string,
}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("voice: %w: request: %v", ErrProviderFailed, err)
return nil, fmt.Errorf("voice: %w: request: %v", ErrProviderFailed, trace.URLCause(err))
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {