heddle_object_model/object/
state_attribution.rs1use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8pub struct Principal {
9 #[serde(with = "serde_bytes")]
11 pub name: Vec<u8>,
12 #[serde(with = "serde_bytes")]
14 pub email: Vec<u8>,
15}
16
17impl Principal {
18 pub fn new(name: impl AsRef<[u8]>, email: impl AsRef<[u8]>) -> Self {
20 Self {
21 name: name.as_ref().to_vec(),
22 email: email.as_ref().to_vec(),
23 }
24 }
25
26 pub fn name_lossy(&self) -> std::borrow::Cow<'_, str> {
28 String::from_utf8_lossy(&self.name)
29 }
30
31 pub fn email_lossy(&self) -> std::borrow::Cow<'_, str> {
33 String::from_utf8_lossy(&self.email)
34 }
35
36 pub fn from_env() -> Option<Self> {
38 let name = std::env::var("HEDDLE_PRINCIPAL_NAME").ok()?;
39 let email = std::env::var("HEDDLE_PRINCIPAL_EMAIL").ok()?;
40 if name.trim().is_empty() || email.trim().is_empty() {
41 return None;
42 }
43 Some(Self {
44 name: name.into_bytes(),
45 email: email.into_bytes(),
46 })
47 }
48}
49
50impl std::fmt::Display for Principal {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 write!(f, "{} <{}>", self.name_lossy(), self.email_lossy())
53 }
54}
55
56#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
58pub struct Agent {
59 pub provider: String,
61 pub model: String,
63 pub session_id: Option<String>,
65 pub segment_id: Option<String>,
67 pub policy_id: Option<String>,
69}
70
71impl Agent {
72 pub fn new(provider: impl Into<String>, model: impl Into<String>) -> Self {
74 Self {
75 provider: provider.into(),
76 model: model.into(),
77 session_id: None,
78 segment_id: None,
79 policy_id: None,
80 }
81 }
82
83 pub fn with_session(
85 mut self,
86 session_id: impl Into<String>,
87 segment_id: impl Into<String>,
88 ) -> Self {
89 self.session_id = Some(session_id.into());
90 self.segment_id = Some(segment_id.into());
91 self
92 }
93
94 pub fn with_policy(mut self, policy_id: impl Into<String>) -> Self {
96 self.policy_id = Some(policy_id.into());
97 self
98 }
99
100 pub fn from_env() -> Option<Self> {
102 let provider = std::env::var("HEDDLE_AGENT_PROVIDER").ok()?;
103 let model = std::env::var("HEDDLE_AGENT_MODEL").ok()?;
104 let session_id = std::env::var("HEDDLE_SESSION_ID").ok();
105 let segment_id = std::env::var("HEDDLE_SESSION_SEGMENT").ok();
106 let policy_id = std::env::var("HEDDLE_AGENT_POLICY").ok();
107 Some(Self {
108 provider,
109 model,
110 session_id,
111 segment_id,
112 policy_id,
113 })
114 }
115}
116
117impl std::fmt::Display for Agent {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 write!(f, "{}/{}", self.provider, self.model)
120 }
121}
122
123#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
125pub struct Attribution {
126 pub principal: Principal,
128 pub agent: Option<Agent>,
130}
131
132impl Attribution {
133 pub fn human(principal: Principal) -> Self {
135 Self {
136 principal,
137 agent: None,
138 }
139 }
140
141 pub fn with_agent(principal: Principal, agent: Agent) -> Self {
143 Self {
144 principal,
145 agent: Some(agent),
146 }
147 }
148}
149
150impl std::fmt::Display for Attribution {
151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 if let Some(agent) = &self.agent {
153 write!(f, "{} (via {})", self.principal, agent)
154 } else {
155 write!(f, "{}", self.principal)
156 }
157 }
158}