Files
AskaEth b99268d019
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(trace,loop,orchestration): memory/guardrail/orchestration 真 span + 参数摘要脱敏 + Guardrail 输出侧异步(裁决 11.4.2/11.4.3/13.4.1)
- 11.4.2:三类节点首次真进图 —— memory.recall/memory.write(loop/memory.go 召回与写入点)、
  guardrail.input/output(流式主路径两侧 + agent.RunStep 静音路径)、orchestration.spawn
  (scheduler 每次派发/收束);新增 trace.ChildSpan 让不持有 Tracer 的叶子包也能开子 span
- 11.4.3(设计先行,规格先写进 design/19 §1.1):tool 节点参数摘要 —— 放行表 argValueKeys +
  trace.IsSecretKey 统一判据(密钥类键不给值)+ 单值 80 rune / ≤24 条 + 出图前再清洗;
  前端 NodeDetail 新增「参数摘要」区,未放行键显示「值未展示」
- 13.4.1:流式主路径输出侧护栏改后台 goroutine(脱离 context、30s 兜底、不阻塞回合),
  输入侧仍在模型调用前同步拦下;拦截闭环到 guardrail 节点 + 审计事件
- 拆文件:scheduler.go 加 span 后 546 行 → 编排 span 助手拆出 scheduler_spans.go(回到 492)
- 契约:无帧名/事件形状变化;graph_update 节点 props 新增**可选**键(tool args_keys/args_summary、
  guardrail action/allow/elapsed_ms、memory action/scope/hits/…、orchestration subagent/persona),
  文档同步由主会话统一落
2026-10-04 12:31:20 +08:00

63 lines
2.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package trace
import (
"context"
"time"
)
// 本文件是 span 生产者侧的桥接层:它让不持有 *Tracer 句柄的叶子包
// (internal/runtime/agent 的护栏检查等)也能在当前 span 之下再开一个
// 子 span,从而把「尽可能深」的结构化追踪补齐(design/04 §9:LLM /
// 工具 / 编排 / 状态转移 / 子代理 / 记忆读写 / guardrail 全都要有生产者)。
//
// 图谱(graph*.go)与生产者(span 生产点)在这里分工:图构建器只负责把
// span 折成节点,生产者只负责如实记录发生了什么。两者都不需要对方存在
// —— 没有 tracer 时 ChildSpan 返回 nil,生产点照常跑完业务。
// ChildSpan 在当前 ctx 携带的 span 之下开一个具名字 span:新 span 复用其父
// span 的 Tracer(因此 Finish 时同样交给 Writer 落盘),ParentID 指向父
// span,返回的 ctx 把新 span 作为当前 span 继续往下传。
//
// ctx 未携带 span(未开追踪、或在根 span 之外调用)时返回 (ctx, nil):
// 调用方必须容忍 nil span(不要用它,也不要把 nil span 的 ctx 当真)。
// 空 ctx 按 context.Background() 处理。
func ChildSpan(ctx context.Context, name string, kind SpanKind) (context.Context, *Span) {
if ctx == nil {
ctx = context.Background()
}
parent := SpanFromContext(ctx)
if parent == nil {
return ctx, nil
}
parent.mu.RLock()
tracer := parent.tracer
parent.mu.RUnlock()
if tracer == nil {
return ctx, nil
}
span := tracer.newSpan(name, kind, parent)
return context.WithValue(ctx, spanKey{}, span), span
}
// FinishChild 关闭一个由 ChildSpan 开出的 span 并记录耗时与结果:span 为
// nil(未开追踪)时是空操作,因此生产点可以无条件调用它,不必在调用处
// 再写一遍 nil 判断。status 为 ok/error,err 为 nil 时代码不记录 error 属性。
func FinishChild(span *Span, status SpanStatus, err error) {
if span == nil {
return
}
if err != nil {
_ = span.SetProp("error", err.Error())
}
span.Finish(status)
}
// ElapsedMS 报告 span 自开始以来经过的毫秒数;nil span 或零 StartAt 返回 0。
// 它让叶子包在不依赖 loop 内部助手的情况下记录「耗时」属性。
func ElapsedMS(span *Span) int64 {
if span == nil || span.StartedAt.IsZero() {
return 0
}
return time.Since(span.StartedAt).Milliseconds()
}