systemprompt_models/auth/
actor.rs1use serde::{Deserialize, Serialize};
15use systemprompt_identifiers::{AgentName, ClientId};
16
17use super::claims::TokenInteraction;
18
19pub const UNNAMED_AGENT: &str = "agent";
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
23#[serde(tag = "kind", rename_all = "snake_case")]
24pub enum RequestActor {
25 Human,
26 Agent { name: AgentName, attended: bool },
27}
28
29impl RequestActor {
30 #[must_use]
31 pub const fn is_agent(&self) -> bool {
32 matches!(self, Self::Agent { .. })
33 }
34
35 #[must_use]
36 pub const fn is_unattended_agent(&self) -> bool {
37 matches!(
38 self,
39 Self::Agent {
40 attended: false,
41 ..
42 }
43 )
44 }
45}
46
47#[must_use]
48pub fn bearer_actor(
49 purpose: Option<&str>,
50 client_id: Option<&ClientId>,
51 interaction: Option<TokenInteraction>,
52) -> RequestActor {
53 let attended = interaction == Some(TokenInteraction::Interactive) && purpose.is_none();
54 RequestActor::Agent {
55 name: agent_name(purpose, client_id),
56 attended,
57 }
58}
59
60#[must_use]
61pub fn agent_name(purpose: Option<&str>, client_id: Option<&ClientId>) -> AgentName {
62 purpose
63 .or_else(|| client_id.map(ClientId::as_str))
64 .and_then(|name| AgentName::try_new(name).ok())
65 .unwrap_or_else(|| AgentName::new(UNNAMED_AGENT))
66}