Skip to main content

systemprompt_identifiers/
agent.rs

1//! Agent identity newtypes: opaque [`AgentId`] (UUID-backed), validated
2//! [`AgentName`] (non-empty, reserves `"unknown"`), and
3//! [`ExternalAgentId`] for off-platform "super-agents" (Claude Desktop,
4//! Codex CLI, Claude Code) that connect via the bridge binary.
5//!
6//! Copyright (c) systemprompt.io — Business Source License 1.1.
7//! See <https://systemprompt.io> for licensing details.
8
9crate::define_id!(AgentId, generate, schema);
10crate::define_id!(ExternalAgentId, non_empty);
11
12use crate::error::IdValidationError;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, schemars::JsonSchema)]
15#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
16#[cfg_attr(feature = "sqlx", sqlx(transparent))]
17#[serde(transparent)]
18pub struct AgentName(String);
19
20impl AgentName {
21    pub fn try_new(name: impl Into<String>) -> Result<Self, IdValidationError> {
22        let name = name.into();
23        if name.is_empty() {
24            return Err(IdValidationError::empty("AgentName"));
25        }
26        if name.eq_ignore_ascii_case("unknown") {
27            return Err(IdValidationError::invalid(
28                "AgentName",
29                "'unknown' is reserved for error detection",
30            ));
31        }
32        Ok(Self(name))
33    }
34
35    pub fn as_str(&self) -> &str {
36        &self.0
37    }
38
39    pub fn system() -> Self {
40        Self("system".to_owned())
41    }
42
43    pub fn bridge() -> Self {
44        Self("bridge".to_owned())
45    }
46
47    // Why: placeholder for artifact metadata built before a request context
48    // exists; `with_request` replaces it, and "unset" is distinguishable from
49    // the reserved "unknown" that `try_new` rejects.
50    pub fn unset() -> Self {
51        Self("unset".to_owned())
52    }
53}
54
55crate::__define_id_validated_conversions!(AgentName);
56crate::__define_id_common!(AgentName);