fix(upstream): M51 收敛剩余上游自由文本出口 - CDP/MCP/flowgate/channelbridge WARN
- channelbridge: 拨号失败的 WARN 不再带原始 dial 错误(含 ?access_token=), URLCause 剥壳 + 内嵌地址 MaskQuery 打码 + HostOf 保留目标来源;控制流零改动 - browser/cdp.go: CDP error.message 只有像协议枚举(ErrorToken)才出镜,其余只留字节数 - mcp: 第三方 server 的错误文本默认不带,只留 server/工具/JSON-RPC 码/message 长度, 分类链(errors.Is/As、context.Canceled)经 Unwrap 保留 - channel/adapter/flowgate: 审查输出摘要由 40 字节改 40 rune(防切 UTF-8)并过 RedactText 四处均补了会随回退变红的用例(变异已实测)。
This commit is contained in:
1 parent
2702777950
commit
d6493d79f4
10 files changed
+538
-23
No files matched your search
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
|
||||
)
|
||||
|
||||
// utf8BOM 是 UTF-8 的字节序标记。对端(审查模型网关)会把它原样回带,而
|
||||
@@ -13,9 +15,13 @@ import (
|
||||
// 并把「每窗口一次」的节流打穿(见 DevDocs/audit/群聊排队与回旧话-2026-10-24.md)。
|
||||
const utf8BOM = "\ufeff"
|
||||
|
||||
// reviewExcerptLen 是解析失败时附带在错误里的模型输出长度(字节)。它只含模型
|
||||
// reviewExcerptLen 是解析失败时附带在错误里的模型输出长度(**rune**)。它只含模型
|
||||
// 返回的编号数组(数字/方括号/逗号/围栏),足以定位「又换了什么壳」,不至于把
|
||||
// 消息内容带进日志。
|
||||
//
|
||||
// 🔴 单位是 rune 不是字节:审查模型回的中文/全角标点每个字 3 字节,按 40 **字节**
|
||||
// 截会把其中一个字切成半个 —— 错误串变成非法 UTF-8,终端显示 U+FFFD、JSON 客户端
|
||||
// 各自乱码。带上限出镜是刻意的(失败原因对排障有用),但上限必须以字符计。
|
||||
const reviewExcerptLen = 40
|
||||
|
||||
// ParseReviewIndices decodes the keep-index array a review model returned, rising
|
||||
@@ -83,12 +89,12 @@ func unwrapCodeFence(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
// reviewExcerpt truncates text for an error message so the next parse failure is
|
||||
// diagnosable without logging the whole completion.
|
||||
// reviewExcerpt 把模型输出裁成一段可以进错误串的摘要。两步都不是可选的:
|
||||
//
|
||||
// - trace.RedactTextLimited 先清洗凭据形状(审查网关偶有把 Authorization 回显进
|
||||
// 输出的),再按 **rune** 截到 reviewExcerptLen —— 按字节截会把多字节字符切成
|
||||
// 半个,错误串因此变成非法 UTF-8;
|
||||
// - 压平空白:一条诊断只占一行,也挡掉换行注入。
|
||||
func reviewExcerpt(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) <= reviewExcerptLen {
|
||||
return s
|
||||
}
|
||||
return s[:reviewExcerptLen] + "…"
|
||||
return trace.RedactTextLimited(strings.Join(strings.Fields(s), " "), reviewExcerptLen)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// bomReviewFixture 是审查模型网关的实际回包形状:UTF-8 BOM(EF BB BF)紧接一个
|
||||
@@ -126,3 +127,45 @@ func TestParseReviewIndices_RejectsGarbage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestReviewExcerpt_TruncatesByRune 钉住「上限按字符计,不按字节计」:审查模型回的中文
|
||||
// 每个字 3 字节,按 40 **字节**截会把其中一个字切成半个,错误串因此成为非法 UTF-8
|
||||
// (终端显示 U+FFFD、JSON 客户端各自乱码)。
|
||||
//
|
||||
// 变异判据:把 reviewExcerpt 换回 `s[:reviewExcerptLen] + "…"` 的字节截断 ⇒ 本用例红
|
||||
// (utf8.ValidString 为 false)。
|
||||
func TestReviewExcerpt_TruncatesByRune(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := reviewExcerpt(strings.Repeat("中", reviewExcerptLen*2))
|
||||
if !utf8.ValidString(got) {
|
||||
t.Fatalf("截断后不是合法 UTF-8(按字节截断了半个汉字):%q", got)
|
||||
}
|
||||
body := strings.TrimSuffix(got, "…")
|
||||
if n := utf8.RuneCountInString(body); n != reviewExcerptLen {
|
||||
t.Fatalf("保留 %d 个字符,期望 %d:%q", n, reviewExcerptLen, got)
|
||||
}
|
||||
if !strings.HasSuffix(got, "…") {
|
||||
t.Errorf("超限时应当带省略号:%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestReviewExcerpt_RedactsCredentialShapes 钉住「带上限出镜 ≠ 原样出镜」:摘要仍要
|
||||
// 过 trace.RedactText,网关回显的凭据形状(sk-… / token=… 等)必须被打码。
|
||||
//
|
||||
// 变异判据:让 reviewExcerpt 只做截断、不过 trace.RedactTextLimited ⇒ 本用例红。
|
||||
func TestReviewExcerpt_RedactsCredentialShapes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const secret = "sk-abcdefghijklmnop"
|
||||
got := reviewExcerpt("[0, 1] Authorization: Bearer " + secret)
|
||||
if strings.Contains(got, secret) {
|
||||
t.Fatalf("凭据形状没被打码:%q", got)
|
||||
}
|
||||
if !strings.Contains(got, "[redacted]") {
|
||||
t.Errorf("打码标记缺失:%q", got)
|
||||
}
|
||||
if !strings.Contains(got, "[0, 1]") {
|
||||
t.Errorf("摘要丢了诊断价值(编号数组):%q", got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user