use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Principal {
pub name: String,
pub email: String,
}
impl Principal {
pub fn new(name: impl Into<String>, email: impl Into<String>) -> Self {
Self {
name: name.into(),
email: email.into(),
}
}
pub fn from_env() -> Option<Self> {
let name = std::env::var("HEDDLE_PRINCIPAL_NAME").ok()?;
let email = std::env::var("HEDDLE_PRINCIPAL_EMAIL").ok()?;
if name.trim().is_empty() || email.trim().is_empty() {
return None;
}
Some(Self { name, email })
}
}
impl std::fmt::Display for Principal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} <{}>", self.name, self.email)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Agent {
pub provider: String,
pub model: String,
pub session_id: Option<String>,
pub segment_id: Option<String>,
pub policy_id: Option<String>,
}
impl Agent {
pub fn new(provider: impl Into<String>, model: impl Into<String>) -> Self {
Self {
provider: provider.into(),
model: model.into(),
session_id: None,
segment_id: None,
policy_id: None,
}
}
pub fn with_session(
mut self,
session_id: impl Into<String>,
segment_id: impl Into<String>,
) -> Self {
self.session_id = Some(session_id.into());
self.segment_id = Some(segment_id.into());
self
}
pub fn with_policy(mut self, policy_id: impl Into<String>) -> Self {
self.policy_id = Some(policy_id.into());
self
}
pub fn from_env() -> Option<Self> {
let provider = std::env::var("HEDDLE_AGENT_PROVIDER").ok()?;
let model = std::env::var("HEDDLE_AGENT_MODEL").ok()?;
let session_id = std::env::var("HEDDLE_SESSION_ID").ok();
let segment_id = std::env::var("HEDDLE_SESSION_SEGMENT").ok();
let policy_id = std::env::var("HEDDLE_AGENT_POLICY").ok();
Some(Self {
provider,
model,
session_id,
segment_id,
policy_id,
})
}
}
impl std::fmt::Display for Agent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}/{}", self.provider, self.model)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Attribution {
pub principal: Principal,
pub agent: Option<Agent>,
}
impl Attribution {
pub fn human(principal: Principal) -> Self {
Self {
principal,
agent: None,
}
}
pub fn with_agent(principal: Principal, agent: Agent) -> Self {
Self {
principal,
agent: Some(agent),
}
}
}
impl std::fmt::Display for Attribution {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(agent) = &self.agent {
write!(f, "{} (via {})", self.principal, agent)
} else {
write!(f, "{}", self.principal)
}
}
}