Skip to main content

lellm_graph/
trace.rs

1//! ExecutionTrace + TraceSink — 审计日志,与 Checkpoint 分离。
2//!
3//! Checkpoint = Snapshot(恢复)
4//! ExecutionTrace = WAL(审计)
5//!
6//! Runtime 层:强类型 `ExecutionTrace<E>`,`E = S::Mutation`
7//! 导出层:`ExportedTrace`,JSON 序列化
8
9use serde::{Deserialize, Serialize};
10
11use crate::checkpoint::NodeId;
12
13// ─── TraceStep ─────────────────────────────────────────────────
14
15/// 执行步骤记录 — 单个节点的 Mutation 审计。
16#[derive(Debug, Clone)]
17pub struct TraceStep<E> {
18    /// 步骤序号(从 1 开始)
19    pub step: usize,
20    /// 节点标识
21    pub node_id: NodeId,
22    /// 该节点产生的 Effects
23    pub mutations: Vec<E>,
24}
25
26// ─── ExecutionTrace ────────────────────────────────────────────
27
28/// 执行追踪 — 强类型 Mutation 审计日志。
29///
30/// `E = S::Mutation`,Runtime 层保持编译期类型安全。
31#[derive(Debug, Clone, Default)]
32pub struct ExecutionTrace<E> {
33    pub steps: Vec<TraceStep<E>>,
34}
35
36impl<E> ExecutionTrace<E> {
37    pub fn new() -> Self {
38        Self { steps: Vec::new() }
39    }
40
41    pub fn push(&mut self, step: TraceStep<E>) {
42        self.steps.push(step);
43    }
44
45    pub fn len(&self) -> usize {
46        self.steps.len()
47    }
48
49    pub fn is_empty(&self) -> bool {
50        self.steps.is_empty()
51    }
52}
53
54// ─── TraceSink ─────────────────────────────────────────────────
55
56/// 审计日志接收器 — Executor 通过 TraceSink 记录每一步。
57///
58/// 默认实现:`MemoryTraceSink<E>`(内存收集)
59/// 未来扩展:`SqliteTraceSink`、`OpenTelemetryTraceSink`、`ParquetTraceSink`
60pub trait TraceSink<E>: Send + Sync {
61    /// 记录一个执行步骤。
62    fn record_step(&mut self, step: TraceStep<E>);
63}
64
65/// 内存 TraceSink — v0.4 默认实现。
66#[derive(Debug)]
67pub struct MemoryTraceSink<E: Send + Sync> {
68    pub trace: ExecutionTrace<E>,
69}
70
71impl<E: Send + Sync> Default for MemoryTraceSink<E> {
72    fn default() -> Self {
73        Self {
74            trace: ExecutionTrace::new(),
75        }
76    }
77}
78
79impl<E: Send + Sync> MemoryTraceSink<E> {
80    pub fn new() -> Self {
81        Self::default()
82    }
83
84    pub fn into_trace(self) -> ExecutionTrace<E> {
85        self.trace
86    }
87}
88
89impl<E: Send + Sync> TraceSink<E> for MemoryTraceSink<E> {
90    fn record_step(&mut self, step: TraceStep<E>) {
91        self.trace.push(step);
92    }
93}
94
95// ─── ExportedTrace ─────────────────────────────────────────────
96
97/// 导出的追踪记录 — 统一 JSON 序列化,供外部消费。
98///
99/// 通过 `ExecutionTrace::export()` 生成。
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct ExportedTrace {
102    pub steps: Vec<ExportedTraceStep>,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct ExportedTraceStep {
107    pub step: usize,
108    pub node_id: String,
109    pub mutations: Vec<serde_json::Value>,
110}
111
112impl<E: Serialize> ExecutionTrace<E> {
113    /// 导出为 JSON 可序列化的追踪记录。
114    pub fn export(&self) -> ExportedTrace {
115        ExportedTrace {
116            steps: self
117                .steps
118                .iter()
119                .map(|s| ExportedTraceStep {
120                    step: s.step,
121                    node_id: s.node_id.0.clone(),
122                    mutations: s
123                        .mutations
124                        .iter()
125                        .filter_map(|e| serde_json::to_value(e).ok())
126                        .collect(),
127                })
128                .collect(),
129        }
130    }
131}