① light.go 的 2 处 "light judge: " + d.Reason 与 engage.go 同形(model reason → 返回值 → coalesce_prepare 的 Debug)。把上一轮的 engageReason 提成包内共用的 judgeReason(judge_reason.go,RedactTextLimited + strings.Fields,60 rune), engage.go 7 处 + light.go 2 处 + notice.go 的 "notice review failed: "+err.Error() 统一走它。控制流零改动:只换「进去的那份文本」,判定条件与返回值拼接结构未动。 ② MCP 的 Logger 面先探针后修:go-sdk v1.8.0 的 keepalive 会把对端 JSON-RPC error 原样打进日志(实测泄漏,见 sdklog_probe_test.go 的输出),tools/call 路径不打日志。 新增 sdklog.go:redactingLogger 交给 SDK,wire 错误(链上有 *jsonrpc.Error)只留 code + message_bytes(复用 upstreamError),本地错误保留原因,消息/属性压平+打码+300 rune。 ③ errortoken.go 的口径注释纠正:从「包外不得调用」改为按字段类别判定(协议枚举可守、 自由文本默认不带),并把 cdp.go 这条 M51 用法作为例子写进去。
60 lines
2.3 KiB
Go
60 lines
2.3 KiB
Go
package mcp
|
|
|
|
// 本文件钉住 sdklog.go 的两条分支(线上错误 / 本地错误),sdklog_probe_test.go 则
|
|
// 用真 server 证明这条日志面确实走过收敛。
|
|
//
|
|
// 变异判据:把 scrubSDKError 的分支判据摘掉(一律保留原文)⇒ 第一条子用例红;
|
|
// 反过来「一律只留骨架」⇒ 第二、三条子用例红(运维会丢掉「为什么 session 被关掉」)。
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
|
|
sdkjsonrpc "github.com/modelcontextprotocol/go-sdk/jsonrpc"
|
|
)
|
|
|
|
// TestScrubSDKError_SplitsWireFromLocal 是分类判据的正面证据。
|
|
func TestScrubSDKError_SplitsWireFromLocal(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// 1. 线上错误(链上有 *jsonrpc.Error):自由文本一个字节都不留,只留码与长度。
|
|
wire := fmt.Errorf("calling %q: %w", "ping",
|
|
&sdkjsonrpc.Error{Code: sdkjsonrpc.CodeInternalError, Message: "SENTINEL-MCPLOG 她刚才说的话"})
|
|
got := scrubSDKError(wire)
|
|
if strings.Contains(got, "SENTINEL-MCPLOG") {
|
|
t.Fatalf("线上错误的自由文本进了日志:%q", got)
|
|
}
|
|
if !strings.Contains(got, "code=-32603") {
|
|
t.Fatalf("线上错误的协议码被丢掉了:%q", got)
|
|
}
|
|
|
|
// 2. 本地错误:原因必须保留(运维靠它判断失败性质)。
|
|
if got := scrubSDKError(context.DeadlineExceeded); !strings.Contains(got, "deadline exceeded") {
|
|
t.Fatalf("本地错误的原因被吞掉了:%q", got)
|
|
}
|
|
|
|
// 3. 本地错误里的凭据形状仍要打码,换行仍要压平。
|
|
leaky := errors.New("dial failed: Authorization: Bearer sk-live-0123456789abcdef\nsecond line")
|
|
got = scrubSDKError(leaky)
|
|
if strings.Contains(got, "sk-live") {
|
|
t.Fatalf("本地错误里的凭据没被打码:%q", got)
|
|
}
|
|
if strings.Contains(got, "\n") || !strings.Contains(got, "second line") {
|
|
t.Fatalf("本地错误的换行没被压平(或压平把内容吞了):%q", got)
|
|
}
|
|
}
|
|
|
|
// TestScrubSDKAttr_KeepsScalars 钉住「只收敛自由文本面」:数字/布尔/时间是体积与
|
|
// 状态,不该被字符串化或截断。
|
|
func TestScrubSDKAttr_KeepsScalars(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if got := scrubSDKAttr(slog.Int("consecutiveFailures", 3)); got.Value.Kind().String() != "Int64" {
|
|
t.Fatalf("数字属性被改成了 %s(应保持数字)", got.Value.Kind())
|
|
}
|
|
}
|