Skip to main content

letta/types/
identity.rs

1//! Identity-related types.
2
3use bon::Builder;
4use serde::{Deserialize, Serialize};
5
6use super::LettaId;
7
8/// Identity type enum.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum IdentityType {
12    /// Organization identity.
13    Org,
14    /// User identity.
15    User,
16    /// Other identity type.
17    Other,
18}
19
20impl std::fmt::Display for IdentityType {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        match self {
23            Self::Org => write!(f, "org"),
24            Self::User => write!(f, "user"),
25            Self::Other => write!(f, "other"),
26        }
27    }
28}
29
30/// Property value in an identity.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct IdentityProperty {
33    /// Property key.
34    pub key: String,
35    /// Property value (any JSON value).
36    pub value: serde_json::Value,
37    /// Property type.
38    #[serde(rename = "type")]
39    pub property_type: String,
40}
41
42/// Identity represents a user, organization, or other entity in Letta.
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Identity {
45    /// Identity ID (prefixed with "identity-").
46    pub id: LettaId,
47    /// Unique identifier key.
48    pub identifier_key: String,
49    /// Identity name.
50    pub name: String,
51    /// Identity type.
52    pub identity_type: IdentityType,
53    /// Agent IDs associated with this identity.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub agent_ids: Option<Vec<LettaId>>,
56    /// Block IDs associated with this identity.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub block_ids: Option<Vec<LettaId>>,
59    /// Project ID this identity belongs to.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub project_id: Option<LettaId>,
62    /// Identity properties.
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub properties: Option<Vec<IdentityProperty>>,
65}
66
67/// Request to create a new identity.
68#[derive(Debug, Clone, Serialize, Deserialize, Builder)]
69pub struct CreateIdentityRequest {
70    /// Unique identifier key.
71    pub identifier_key: String,
72    /// Identity name.
73    pub name: String,
74    /// Identity type.
75    pub identity_type: IdentityType,
76    /// Project ID this identity belongs to.
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub project_id: Option<String>,
79    /// Agent IDs to associate with this identity.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub agent_ids: Option<Vec<String>>,
82    /// Block IDs to associate with this identity.
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub block_ids: Option<Vec<String>>,
85    /// Identity properties.
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub properties: Option<Vec<IdentityProperty>>,
88}
89
90/// Request to update an identity.
91#[derive(Debug, Clone, Serialize, Deserialize, Default)]
92pub struct UpdateIdentityRequest {
93    /// Unique identifier key.
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub identifier_key: Option<String>,
96    /// Identity name.
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub name: Option<String>,
99    /// Identity type.
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub identity_type: Option<IdentityType>,
102    /// Agent IDs to associate with this identity.
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub agent_ids: Option<Vec<String>>,
105    /// Block IDs to associate with this identity.
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub block_ids: Option<Vec<String>>,
108    /// Identity properties.
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub properties: Option<Vec<IdentityProperty>>,
111}
112
113/// Query parameters for listing identities.
114#[derive(Debug, Clone, Serialize, Deserialize, Default)]
115pub struct ListIdentitiesParams {
116    /// Filter by name.
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub name: Option<String>,
119    /// Filter by project ID.
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub project_id: Option<String>,
122    /// Filter by identifier key.
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub identifier_key: Option<String>,
125    /// Filter by identity type.
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub identity_type: Option<IdentityType>,
128    /// Cursor for pagination (before).
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub before: Option<String>,
131    /// Cursor for pagination (after).
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub after: Option<String>,
134    /// Maximum number of results to return.
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub limit: Option<i32>,
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn test_identity_type_serialization() {
145        // Test serialization
146        let user_json = serde_json::to_string(&IdentityType::User).unwrap();
147        assert_eq!(user_json, "\"user\"");
148
149        let org_json = serde_json::to_string(&IdentityType::Org).unwrap();
150        assert_eq!(org_json, "\"org\"");
151
152        let other_json = serde_json::to_string(&IdentityType::Other).unwrap();
153        assert_eq!(other_json, "\"other\"");
154
155        // Test deserialization
156        let user: IdentityType = serde_json::from_str("\"user\"").unwrap();
157        assert_eq!(user, IdentityType::User);
158
159        let org: IdentityType = serde_json::from_str("\"org\"").unwrap();
160        assert_eq!(org, IdentityType::Org);
161
162        let other: IdentityType = serde_json::from_str("\"other\"").unwrap();
163        assert_eq!(other, IdentityType::Other);
164    }
165}