objects/object/
state_attribution.rs1use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8pub struct Principal {
9 pub name: String,
11 pub email: String,
13}
14
15impl Principal {
16 pub fn new(name: impl Into<String>, email: impl Into<String>) -> Self {
18 Self {
19 name: name.into(),
20 email: email.into(),
21 }
22 }
23
24 pub fn from_env() -> Option<Self> {
26 let name = std::env::var("HEDDLE_PRINCIPAL_NAME").ok()?;
27 let email = std::env::var("HEDDLE_PRINCIPAL_EMAIL").ok()?;
28 if name.trim().is_empty() || email.trim().is_empty() {
29 return None;
30 }
31 Some(Self { name, email })
32 }
33}
34
35impl std::fmt::Display for Principal {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(f, "{} <{}>", self.name, self.email)
38 }
39}
40
41#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
43pub struct Agent {
44 pub provider: String,
46 pub model: String,
48 pub session_id: Option<String>,
50 pub segment_id: Option<String>,
52 pub policy_id: Option<String>,
54}
55
56impl Agent {
57 pub fn new(provider: impl Into<String>, model: impl Into<String>) -> Self {
59 Self {
60 provider: provider.into(),
61 model: model.into(),
62 session_id: None,
63 segment_id: None,
64 policy_id: None,
65 }
66 }
67
68 pub fn with_session(
70 mut self,
71 session_id: impl Into<String>,
72 segment_id: impl Into<String>,
73 ) -> Self {
74 self.session_id = Some(session_id.into());
75 self.segment_id = Some(segment_id.into());
76 self
77 }
78
79 pub fn with_policy(mut self, policy_id: impl Into<String>) -> Self {
81 self.policy_id = Some(policy_id.into());
82 self
83 }
84
85 pub fn from_env() -> Option<Self> {
87 let provider = std::env::var("HEDDLE_AGENT_PROVIDER").ok()?;
88 let model = std::env::var("HEDDLE_AGENT_MODEL").ok()?;
89 let session_id = std::env::var("HEDDLE_SESSION_ID").ok();
90 let segment_id = std::env::var("HEDDLE_SESSION_SEGMENT").ok();
91 let policy_id = std::env::var("HEDDLE_AGENT_POLICY").ok();
92 Some(Self {
93 provider,
94 model,
95 session_id,
96 segment_id,
97 policy_id,
98 })
99 }
100}
101
102impl std::fmt::Display for Agent {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 write!(f, "{}/{}", self.provider, self.model)
105 }
106}
107
108#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
110pub struct Attribution {
111 pub principal: Principal,
113 pub agent: Option<Agent>,
115}
116
117impl Attribution {
118 pub fn human(principal: Principal) -> Self {
120 Self {
121 principal,
122 agent: None,
123 }
124 }
125
126 pub fn with_agent(principal: Principal, agent: Agent) -> Self {
128 Self {
129 principal,
130 agent: Some(agent),
131 }
132 }
133}
134
135impl std::fmt::Display for Attribution {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 if let Some(agent) = &self.agent {
138 write!(f, "{} (via {})", self.principal, agent)
139 } else {
140 write!(f, "{}", self.principal)
141 }
142 }
143}