beyonder_core/
provenance.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::{ActorId, BlockId};
5
6#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9pub struct ProvenanceChain {
10 pub nodes: Vec<ProvenanceNode>,
11}
12
13impl ProvenanceChain {
14 pub fn with_cause(mut self, cause: CauseKind, actor: ActorId) -> Self {
15 self.nodes.push(ProvenanceNode {
16 cause,
17 actor,
18 timestamp: Utc::now(),
19 });
20 self
21 }
22
23 pub fn immediate_cause(&self) -> Option<&ProvenanceNode> {
25 self.nodes.last()
26 }
27
28 pub fn root_cause(&self) -> Option<&ProvenanceNode> {
30 self.nodes.first()
31 }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct ProvenanceNode {
36 pub cause: CauseKind,
37 pub actor: ActorId,
38 pub timestamp: DateTime<Utc>,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(tag = "type", rename_all = "snake_case")]
44pub enum CauseKind {
45 HumanPrompt { prompt_summary: String },
47 BlockOutput { block_id: BlockId },
49 ToolResult { tool_name: String },
51 ApprovalGranted { approval_block_id: BlockId },
53 AgentPlan { plan_description: String },
55 System { reason: String },
57}