Skip to main content

orcs_types/
lib.rs

1//! Core types for ORCS CLI.
2//!
3//! This crate provides foundational identifier types for the ORCS
4//! (Orchestrated Runtime for Collaborative Systems) architecture.
5//!
6//! # Crate Architecture
7//!
8//! ```text
9//! ┌─────────────────────────────────────────────────────────────┐
10//! │                    Plugin SDK Layer                          │
11//! │  (External, SemVer stable, safe to depend on)               │
12//! ├─────────────────────────────────────────────────────────────┤
13//! │  orcs-types     : ID types, Principal, ErrorCode  ◄── HERE   │
14//! │  orcs-event     : Signal, Request, Event                    │
15//! │  orcs-component : Component trait (WIT target)              │
16//! └─────────────────────────────────────────────────────────────┘
17//!                               ↓
18//! ┌─────────────────────────────────────────────────────────────┐
19//! │                    Runtime Layer                             │
20//! │  (Internal implementation, NOT for plugins)                  │
21//! ├─────────────────────────────────────────────────────────────┤
22//! │  orcs-runtime   : auth, channel, engine                     │
23//! └─────────────────────────────────────────────────────────────┘
24//!                               ↓
25//! ┌─────────────────────────────────────────────────────────────┐
26//! │                   Frontend Layer                             │
27//! │  (CLI, GUI, Network interfaces)                              │
28//! ├─────────────────────────────────────────────────────────────┤
29//! │  orcs-cli       : Command-line interface                    │
30//! └─────────────────────────────────────────────────────────────┘
31//! ```
32//!
33//! # Why Plugin SDK?
34//!
35//! This crate is part of the **Plugin SDK** layer because:
36//!
37//! - **SemVer stable**: API changes follow semantic versioning
38//! - **Minimal dependencies**: Only what plugins truly need
39//! - **WIT compatible**: Types can be exported to WASM components
40//! - **Implementation freedom**: Runtime can change without breaking plugins
41//!
42//! # Event Architecture
43//!
44//! ORCS uses an EventBus-based architecture where all communication
45//! between Components flows through unified message types:
46//!
47//! - **Request/Response**: Synchronous queries between Components
48//! - **Event**: Asynchronous broadcasts (no response expected)
49//! - **Signal**: Human control interrupts (highest priority)
50//!
51//! # Identifier Design
52//!
53//! All identifiers are UUID-based for:
54//!
55//! - **Network compatibility**: Safe to transmit across processes/machines
56//! - **Cloud readiness**: Globally unique without coordination
57//! - **Serialization**: First-class serde support
58//!
59//! # Example
60//!
61//! ```
62//! use orcs_types::{ComponentId, ChannelId, RequestId, EventId};
63//!
64//! // Builtin components have deterministic UUIDs
65//! let llm = ComponentId::builtin("llm");
66//! let llm2 = ComponentId::builtin("llm");
67//! assert_eq!(llm, llm2);  // Same UUID
68//!
69//! // Custom components get random UUIDs
70//! let plugin = ComponentId::new("plugin", "my-tool");
71//!
72//! // Channel for parallel execution context
73//! let channel = ChannelId::new();
74//!
75//! // Request/Response tracking
76//! let req_id = RequestId::new();
77//!
78//! // Event broadcast tracking
79//! let evt_id = EventId::new();
80//! ```
81
82mod construct;
83mod error;
84mod id;
85pub mod intent;
86mod principal;
87mod scope;
88
89pub use construct::TryNew;
90pub use error::{assert_error_code, assert_error_codes, ErrorCode};
91pub use id::{ChannelId, ComponentId, EventId, PrincipalId, RequestId};
92pub use intent::{
93    ActionIntent, Confidence, ContentBlock, IntentDef, IntentMeta, IntentResolver, IntentResult,
94    IntentSource, MessageContent, Priority, Role, StopReason,
95};
96pub use principal::Principal;
97pub use scope::SignalScope;
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn component_id_creation() {
105        let id = ComponentId::new("test", "component");
106        assert_eq!(id.namespace, "test");
107        assert_eq!(id.name, "component");
108        assert_eq!(id.fqn(), "test::component");
109    }
110
111    #[test]
112    fn component_id_builtin_deterministic() {
113        let id1 = ComponentId::builtin("llm");
114        let id2 = ComponentId::builtin("llm");
115        assert_eq!(id1.namespace, "builtin");
116        assert_eq!(id1.name, "llm");
117        // Same name produces same UUID (deterministic)
118        assert_eq!(id1.uuid, id2.uuid);
119        assert_eq!(id1, id2);
120    }
121
122    #[test]
123    fn component_id_builtin_different_names() {
124        let id1 = ComponentId::builtin("llm");
125        let id2 = ComponentId::builtin("tool");
126        // Different names produce different UUIDs
127        assert_ne!(id1.uuid, id2.uuid);
128    }
129
130    #[test]
131    fn component_id_display() {
132        let id = ComponentId::builtin("test");
133        let display = format!("{id}");
134        assert!(display.starts_with("builtin::test@"));
135        assert!(display.contains(&id.uuid.to_string()));
136    }
137
138    #[test]
139    fn component_id_new_random() {
140        let id1 = ComponentId::new("test", "comp");
141        let id2 = ComponentId::new("test", "comp");
142        // new() produces random UUIDs
143        assert_ne!(id1.uuid, id2.uuid);
144        assert_eq!(id1.fqn(), id2.fqn());
145    }
146
147    #[test]
148    fn component_id_fqn_eq() {
149        let id1 = ComponentId::new("test", "comp");
150        let id2 = ComponentId::new("test", "comp");
151        let id3 = ComponentId::new("test", "other");
152        // Different UUIDs but same FQN
153        assert_ne!(id1, id2);
154        assert!(id1.fqn_eq(&id2));
155        assert!(!id1.fqn_eq(&id3));
156    }
157
158    #[test]
159    fn component_id_matches() {
160        let id = ComponentId::builtin("llm");
161        assert!(id.matches("builtin", "llm"));
162        assert!(!id.matches("builtin", "tool"));
163        assert!(!id.matches("custom", "llm"));
164    }
165
166    #[test]
167    fn component_id_is_builtin() {
168        let builtin = ComponentId::builtin("llm");
169        let custom = ComponentId::new("custom", "llm");
170        assert!(builtin.is_builtin());
171        assert!(!custom.is_builtin());
172    }
173
174    #[test]
175    fn channel_id_uniqueness() {
176        let id1 = ChannelId::new();
177        let id2 = ChannelId::new();
178        assert_ne!(id1, id2);
179    }
180
181    // NOTE: ChannelId does not implement Default intentionally.
182    // See id.rs for rationale.
183
184    #[test]
185    fn channel_id_display() {
186        let id = ChannelId::new();
187        let display = format!("{id}");
188        assert!(display.starts_with("ch:"));
189        assert!(display.contains(&id.uuid().to_string()));
190    }
191
192    #[test]
193    fn channel_id_uuid() {
194        let id = ChannelId::new();
195        assert_eq!(id.uuid(), id.0);
196    }
197
198    #[test]
199    fn request_id_display() {
200        let id = RequestId::new();
201        let display = format!("{id}");
202        assert!(display.starts_with("req:"));
203        assert!(display.contains(&id.uuid().to_string()));
204    }
205
206    // NOTE: RequestId does not implement Default intentionally.
207    // See id.rs for rationale.
208
209    #[test]
210    fn event_id_creation() {
211        let id = EventId::new();
212        let display = format!("{id}");
213        assert!(display.starts_with("evt:"));
214        assert!(display.contains(&id.uuid().to_string()));
215    }
216
217    #[test]
218    fn event_id_default() {
219        let id1 = EventId::default();
220        let id2 = EventId::default();
221        assert_ne!(id1, id2);
222    }
223
224    #[test]
225    fn event_id_uniqueness() {
226        let id1 = EventId::new();
227        let id2 = EventId::new();
228        assert_ne!(id1, id2);
229    }
230
231    #[test]
232    fn principal_id_creation() {
233        let id = PrincipalId::new();
234        let display = format!("{id}");
235        assert!(display.starts_with("principal:"));
236    }
237
238    #[test]
239    fn principal_id_uniqueness() {
240        let id1 = PrincipalId::new();
241        let id2 = PrincipalId::new();
242        assert_ne!(id1, id2);
243    }
244
245    #[test]
246    fn principal_id_default() {
247        let id1 = PrincipalId::default();
248        let id2 = PrincipalId::default();
249        assert_ne!(id1, id2);
250    }
251
252    #[test]
253    fn principal_id_uuid() {
254        let id = PrincipalId::new();
255        assert_eq!(id.uuid(), id.0);
256    }
257}