feat(dispatcher): 输出护栏 —— 发射层脱敏疑似密钥/令牌
补齐 Harness 输出侧:harness.RedactSecrets 识别并脱敏 sk-/AKIA/JWT/Bearer 等 疑似密钥令牌(纯逻辑 + 单测)。runAgent 在每个 token 分片发射前调用(流式无法回收 已发,故逐片脱敏),脱敏会累计进 b.answer(写回历史也是脱敏版);有命中则在 运行·观测打一条'已脱敏 N 处'轨迹。 注:跨分片的密钥可能漏(流式现实),逐片为最佳努力;生产可加滑窗缓冲增强。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
"github.com/sundynix/sundynix-dispatcher/internal/dsl"
|
||||
"github.com/sundynix/sundynix-dispatcher/internal/harness"
|
||||
"github.com/sundynix/sundynix-shared/contract"
|
||||
)
|
||||
|
||||
@@ -233,13 +234,16 @@ func (o *Orchestrator) runAgent(ctx context.Context, taskID string, b *board, sy
|
||||
msgs, _ := buildMessages(ctx, rc)
|
||||
tr.emit(node, "model", "start", "模型流式推理", "", 0)
|
||||
t0 := time.Now()
|
||||
n := 0
|
||||
n, redacted := 0, 0
|
||||
send := func(s string) {
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
_ = o.sink.PublishToken(taskID, []byte(s))
|
||||
b.answer += s
|
||||
// 输出护栏:发射前逐片脱敏疑似密钥/令牌(流式无法回收已发,故逐片处理)。
|
||||
safe, hit := harness.RedactSecrets(s)
|
||||
redacted += hit
|
||||
_ = o.sink.PublishToken(taskID, []byte(safe))
|
||||
b.answer += safe
|
||||
n++
|
||||
}
|
||||
var err error
|
||||
@@ -252,6 +256,9 @@ func (o *Orchestrator) runAgent(ctx context.Context, taskID string, b *board, sy
|
||||
tr.emit(node, "model", "error", "模型流式推理", err.Error(), time.Since(t0).Milliseconds())
|
||||
return
|
||||
}
|
||||
if redacted > 0 {
|
||||
tr.info(node, "system", "输出护栏", fmt.Sprintf("已脱敏 %d 处疑似密钥/令牌", redacted))
|
||||
}
|
||||
tr.emit(node, "model", "end", "模型流式推理",
|
||||
fmt.Sprintf("%d tokens / %d 字", n, len([]rune(b.answer))), time.Since(t0).Milliseconds())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user