1use crate::{
14 Capability, CapabilityRegistry, Connector, ConnectorRegistry, DriverRegistry, EgressService,
15 EmailSender, UtilityLlmService,
16 traits::{DisabledSessionFileSystemFactory, SessionFileSystemFactory},
17 vector_store::{InMemoryVectorStore, VectorStore},
18};
19use serde_json::Value;
20use std::sync::Arc;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum BuiltInHarnessRole {
29 Base,
32 Default,
35 Chat,
37}
38
39#[derive(Debug, Clone)]
41pub struct BuiltInCapabilityDefinition {
42 pub id: String,
44 pub config: Value,
46}
47
48impl BuiltInCapabilityDefinition {
49 pub fn new(id: impl Into<String>) -> Self {
51 Self {
52 id: id.into(),
53 config: serde_json::json!({}),
54 }
55 }
56
57 pub fn with_config(id: impl Into<String>, config: Value) -> Self {
59 Self {
60 id: id.into(),
61 config,
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
71pub struct BuiltInHarnessDefinition {
72 pub name: String,
74 pub display_name: String,
76 pub description: String,
78 pub system_prompt: String,
80 pub parent_name: Option<String>,
82 pub tags: Vec<String>,
84 pub capabilities: Vec<BuiltInCapabilityDefinition>,
86 pub roles: Vec<BuiltInHarnessRole>,
88}
89
90impl BuiltInHarnessDefinition {
91 pub fn new(
93 name: impl Into<String>,
94 display_name: impl Into<String>,
95 description: impl Into<String>,
96 system_prompt: impl Into<String>,
97 ) -> Self {
98 Self {
99 name: name.into(),
100 display_name: display_name.into(),
101 description: description.into(),
102 system_prompt: system_prompt.into(),
103 parent_name: None,
104 tags: Vec::new(),
105 capabilities: Vec::new(),
106 roles: Vec::new(),
107 }
108 }
109
110 pub fn with_tags<I, S>(mut self, tags: I) -> Self
112 where
113 I: IntoIterator<Item = S>,
114 S: Into<String>,
115 {
116 self.tags = tags.into_iter().map(Into::into).collect();
117 self
118 }
119
120 pub fn with_parent_name(mut self, parent_name: impl Into<String>) -> Self {
122 self.parent_name = Some(parent_name.into());
123 self
124 }
125
126 pub fn with_capabilities<I>(mut self, capabilities: I) -> Self
128 where
129 I: IntoIterator<Item = BuiltInCapabilityDefinition>,
130 {
131 self.capabilities = capabilities.into_iter().collect();
132 self
133 }
134
135 pub fn with_roles<I>(mut self, roles: I) -> Self
137 where
138 I: IntoIterator<Item = BuiltInHarnessRole>,
139 {
140 self.roles = roles.into_iter().collect();
141 self
142 }
143
144 pub fn has_role(&self, role: BuiltInHarnessRole) -> bool {
146 self.roles.contains(&role)
147 }
148}
149
150#[derive(Clone)]
184pub struct PlatformDefinition {
185 capability_registry: CapabilityRegistry,
186 driver_registry: DriverRegistry,
187 connectors: ConnectorRegistry,
188 built_in_harnesses: Vec<BuiltInHarnessDefinition>,
189 egress_service: Arc<dyn EgressService>,
190 email_sender: Arc<dyn EmailSender>,
191 utility_llm_service: Arc<dyn UtilityLlmService>,
192 session_file_system_factory: Arc<dyn SessionFileSystemFactory>,
193 vector_store: Arc<dyn VectorStore>,
194}
195
196impl PlatformDefinition {
197 pub fn new(capability_registry: CapabilityRegistry, driver_registry: DriverRegistry) -> Self {
199 Self {
200 capability_registry,
201 driver_registry,
202 connectors: ConnectorRegistry::new(),
203 built_in_harnesses: Vec::new(),
204 egress_service: Arc::new(crate::DirectEgressService::default()),
205 email_sender: Arc::new(crate::DisabledEmailSender),
206 utility_llm_service: Arc::new(crate::DisabledUtilityLlmService),
207 session_file_system_factory: Arc::new(DisabledSessionFileSystemFactory),
208 vector_store: Arc::new(InMemoryVectorStore::new()),
209 }
210 }
211
212 pub fn builder() -> PlatformDefinitionBuilder {
214 PlatformDefinitionBuilder::new()
215 }
216
217 pub fn capability_registry(&self) -> &CapabilityRegistry {
219 &self.capability_registry
220 }
221
222 pub fn capability_registry_mut(&mut self) -> &mut CapabilityRegistry {
224 &mut self.capability_registry
225 }
226
227 pub fn driver_registry(&self) -> &DriverRegistry {
229 &self.driver_registry
230 }
231
232 pub fn driver_registry_mut(&mut self) -> &mut DriverRegistry {
234 &mut self.driver_registry
235 }
236
237 pub fn connectors(&self) -> &ConnectorRegistry {
239 &self.connectors
240 }
241
242 pub fn connectors_mut(&mut self) -> &mut ConnectorRegistry {
244 &mut self.connectors
245 }
246
247 pub fn built_in_harnesses(&self) -> &[BuiltInHarnessDefinition] {
249 &self.built_in_harnesses
250 }
251
252 pub fn built_in_harnesses_mut(&mut self) -> &mut Vec<BuiltInHarnessDefinition> {
254 &mut self.built_in_harnesses
255 }
256
257 pub fn egress_service(&self) -> Arc<dyn EgressService> {
259 self.egress_service.clone()
260 }
261
262 pub fn email_sender(&self) -> Arc<dyn EmailSender> {
264 self.email_sender.clone()
265 }
266
267 pub fn utility_llm_service(&self) -> Arc<dyn UtilityLlmService> {
269 self.utility_llm_service.clone()
270 }
271
272 pub fn session_file_system_factory(&self) -> Arc<dyn SessionFileSystemFactory> {
274 self.session_file_system_factory.clone()
275 }
276
277 pub fn vector_store(&self) -> Arc<dyn VectorStore> {
280 self.vector_store.clone()
281 }
282
283 pub fn add_built_in_harness(&mut self, harness: BuiltInHarnessDefinition) {
285 self.built_in_harnesses.push(harness);
286 }
287
288 pub fn harness_for_role(&self, role: BuiltInHarnessRole) -> Option<&BuiltInHarnessDefinition> {
290 self.built_in_harnesses.iter().find(|h| h.has_role(role))
291 }
292}
293
294impl Default for PlatformDefinition {
295 fn default() -> Self {
296 Self::new(CapabilityRegistry::new(), DriverRegistry::new())
297 }
298}
299
300impl std::fmt::Debug for PlatformDefinition {
301 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302 let harness_keys: Vec<_> = self.built_in_harnesses.iter().map(|h| &h.name).collect();
303 f.debug_struct("PlatformDefinition")
304 .field("capabilities", &self.capability_registry)
305 .field("drivers", &self.driver_registry.registered_providers())
306 .field("connectors", &self.connectors)
307 .field("built_in_harnesses", &harness_keys)
308 .field("egress_service", &self.egress_service.name())
309 .field("email_sender", &self.email_sender.name())
310 .field("utility_llm_service", &self.utility_llm_service.name())
311 .field(
312 "session_file_system_factory",
313 &self.session_file_system_factory.name(),
314 )
315 .field("vector_store", &"<dyn VectorStore>")
316 .finish()
317 }
318}
319
320pub struct PlatformDefinitionBuilder {
322 platform: PlatformDefinition,
323}
324
325impl PlatformDefinitionBuilder {
326 pub fn new() -> Self {
328 Self {
329 platform: PlatformDefinition::default(),
330 }
331 }
332
333 pub fn capability_registry(mut self, registry: CapabilityRegistry) -> Self {
335 self.platform.capability_registry = registry;
336 self
337 }
338
339 pub fn capability(mut self, capability: impl Capability + 'static) -> Self {
341 self.platform.capability_registry.register(capability);
342 self
343 }
344
345 pub fn driver_registry(mut self, registry: DriverRegistry) -> Self {
347 self.platform.driver_registry = registry;
348 self
349 }
350
351 pub fn connectors(mut self, registry: ConnectorRegistry) -> Self {
353 self.platform.connectors = registry;
354 self
355 }
356
357 pub fn connector(mut self, provider: impl Connector + 'static) -> Self {
359 self.platform.connectors.register(provider);
360 self
361 }
362
363 pub fn built_in_harnesses<I>(mut self, harnesses: I) -> Self
365 where
366 I: IntoIterator<Item = BuiltInHarnessDefinition>,
367 {
368 self.platform.built_in_harnesses = harnesses.into_iter().collect();
369 self
370 }
371
372 pub fn add_built_in_harness(mut self, harness: BuiltInHarnessDefinition) -> Self {
374 self.platform.built_in_harnesses.push(harness);
375 self
376 }
377
378 pub fn egress_service(mut self, service: Arc<dyn EgressService>) -> Self {
380 self.platform.egress_service = service;
381 self
382 }
383
384 pub fn email_sender(mut self, sender: Arc<dyn EmailSender>) -> Self {
386 self.platform.email_sender = sender;
387 self
388 }
389
390 pub fn utility_llm_service(mut self, service: Arc<dyn UtilityLlmService>) -> Self {
392 self.platform.utility_llm_service = service;
393 self
394 }
395
396 pub fn session_file_system_factory(
398 mut self,
399 factory: Arc<dyn SessionFileSystemFactory>,
400 ) -> Self {
401 self.platform.session_file_system_factory = factory;
402 self
403 }
404
405 pub fn vector_store(mut self, vector_store: Arc<dyn VectorStore>) -> Self {
407 self.platform.vector_store = vector_store;
408 self
409 }
410
411 pub fn build(self) -> PlatformDefinition {
413 self.platform
414 }
415}
416
417impl Default for PlatformDefinitionBuilder {
418 fn default() -> Self {
419 Self::new()
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426 use crate::connector::{ConnectorFormSchema, ConnectorType, ConnectorValidation, FormField};
427 use crate::{CapabilityStatus, CurrentTimeCapability};
428 use async_trait::async_trait;
429
430 struct TestProvider;
431
432 #[async_trait]
433 impl Connector for TestProvider {
434 fn provider_id(&self) -> &str {
435 "test_provider"
436 }
437
438 fn display_name(&self) -> &str {
439 "Test Provider"
440 }
441
442 fn description(&self) -> &str {
443 "Test connection provider"
444 }
445
446 fn icon(&self) -> &str {
447 "plug"
448 }
449
450 fn connection_type(&self) -> ConnectorType {
451 ConnectorType::ApiKey
452 }
453
454 fn form_schema(&self) -> Option<ConnectorFormSchema> {
455 Some(ConnectorFormSchema {
456 fields: vec![FormField::password("api_key", "API Key").required()],
457 instructions_markdown: "Enter the API key.".to_string(),
458 })
459 }
460
461 async fn validate(&self, _credential: &str) -> Result<ConnectorValidation, String> {
462 Ok(ConnectorValidation {
463 provider_username: Some("test-user".to_string()),
464 provider_metadata: None,
465 })
466 }
467 }
468
469 #[cfg(feature = "llmsim")]
471 #[test]
472 fn test_platform_definition_builder() {
473 let mut drivers = DriverRegistry::new();
474 crate::llmsim_driver::register_driver(&mut drivers);
475
476 let platform = PlatformDefinition::builder()
477 .driver_registry(drivers.clone())
478 .capability(CurrentTimeCapability)
479 .connector(TestProvider)
480 .add_built_in_harness(
481 BuiltInHarnessDefinition::new(
482 "minimal",
483 "Minimal",
484 "Minimal harness",
485 "You are helpful.",
486 )
487 .with_roles([BuiltInHarnessRole::Base, BuiltInHarnessRole::Default]),
488 )
489 .build();
490
491 assert!(platform.capability_registry().has("current_time"));
492 assert!(platform.connectors().has("test_provider"));
493 assert_eq!(
494 platform
495 .harness_for_role(BuiltInHarnessRole::Base)
496 .unwrap()
497 .name,
498 "minimal"
499 );
500 assert!(
501 platform
502 .driver_registry()
503 .has_driver(&crate::DriverId::LlmSim)
504 );
505 }
506
507 #[test]
508 fn test_platform_definition_mutation() {
509 let mut platform = PlatformDefinition::default();
510 platform
511 .capability_registry_mut()
512 .register(CurrentTimeCapability);
513 platform.connectors_mut().register(TestProvider);
514 platform.add_built_in_harness(
515 BuiltInHarnessDefinition::new("chat", "Chat", "Chat harness", "You are helpful.")
516 .with_roles([BuiltInHarnessRole::Chat]),
517 );
518
519 let info = crate::CapabilityInfo::from_core(
520 platform
521 .capability_registry()
522 .get("current_time")
523 .expect("current_time registered")
524 .as_ref(),
525 );
526 assert_eq!(info.status, CapabilityStatus::Available);
527 assert!(platform.connectors().has("test_provider"));
528 assert_eq!(
529 platform
530 .harness_for_role(BuiltInHarnessRole::Chat)
531 .unwrap()
532 .name,
533 "chat"
534 );
535 }
536}