systemprompt_identifiers/
brain.rs1use crate::error::IdValidationError;
16
17crate::define_id!(BrainFactId, checked, validate_fact_id);
18crate::define_id!(FactKindId, checked, |value| validate_key(
19 "FactKindId",
20 value
21));
22crate::define_id!(TopicId, checked, |value| validate_key("TopicId", value));
23crate::define_id!(InterestId, checked, |value| validate_key(
24 "InterestId",
25 value
26));
27crate::define_id!(WorkflowId, checked, |value| validate_key(
28 "WorkflowId",
29 value
30));
31crate::define_id!(BrainExtractionId, uuid);
32crate::define_id!(BrainProposalId, uuid);
33crate::define_id!(BrainRecallId, uuid);
34crate::define_id!(BrainDisputeId, uuid);
35crate::define_id!(BrainFactRevisionId, uuid);
36crate::define_id!(PipelineVersion, checked, validate_pipeline_version);
37
38const FACT_ID_PREFIX: &str = "m_";
39const KEY_MAX_LEN: usize = 64;
40const PIPELINE_VERSION_LEN: usize = 16;
41
42impl BrainFactId {
43 pub fn generate() -> Self {
44 Self(format!("{FACT_ID_PREFIX}{}", uuid::Uuid::new_v4()))
45 }
46}
47
48fn validate_fact_id(value: &str) -> Result<(), IdValidationError> {
49 let Some(rest) = value.strip_prefix(FACT_ID_PREFIX) else {
50 return Err(IdValidationError::invalid(
51 "BrainFactId",
52 "must start with 'm_'",
53 ));
54 };
55 crate::macros::validate_uuid("BrainFactId", rest)
56}
57
58fn validate_key(name: &'static str, value: &str) -> Result<(), IdValidationError> {
59 if value.is_empty() {
60 return Err(IdValidationError::empty(name));
61 }
62 if value.len() > KEY_MAX_LEN {
63 return Err(IdValidationError::invalid(
64 name,
65 "must be at most 64 characters",
66 ));
67 }
68 if !value.bytes().all(|b| {
69 b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'_' || b == b'.' || b == b'-'
70 }) {
71 return Err(IdValidationError::invalid(
72 name,
73 "must contain only lowercase letters, digits, '_', '.' and '-'",
74 ));
75 }
76 Ok(())
77}
78
79fn validate_pipeline_version(value: &str) -> Result<(), IdValidationError> {
80 if value.len() != PIPELINE_VERSION_LEN
81 || !value
82 .bytes()
83 .all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b))
84 {
85 return Err(IdValidationError::invalid(
86 "PipelineVersion",
87 "must be 16 lowercase hex characters",
88 ));
89 }
90 Ok(())
91}