1use std::collections::HashMap;
6
7use chrono::{DateTime, Utc};
8use everruns_core::network_access::NetworkAccessList;
9use everruns_core::{
10 Agent, AgentCapabilityConfig, AgentId, AgentStatus, DEFAULT_ORG_PUBLIC_ID, Harness, HarnessId,
11 HarnessStatus, ModelId, PrincipalId, ScopedMcpServers, Session, SessionId, SessionStatus,
12 ToolDefinition, plugin_capability_id,
13};
14use uuid::Uuid;
15
16#[derive(Debug, Clone)]
22pub struct HarnessBuilder {
23 id: HarnessId,
24 name: String,
25 display_name: Option<String>,
26 description: Option<String>,
27 system_prompt: String,
28 parent_harness_id: Option<HarnessId>,
29 default_model_id: Option<ModelId>,
30 tags: Vec<String>,
31 capabilities: Vec<AgentCapabilityConfig>,
32 initial_files: Vec<everruns_core::InitialFile>,
33 network_access: Option<NetworkAccessList>,
34 mcp_servers: ScopedMcpServers,
35 embedder_metadata: HashMap<String, String>,
36 is_built_in: bool,
37 status: HarnessStatus,
38 created_at: Option<DateTime<Utc>>,
39 updated_at: Option<DateTime<Utc>>,
40}
41
42impl HarnessBuilder {
43 pub fn new(name: impl Into<String>, system_prompt: impl Into<String>) -> Self {
45 Self {
46 id: HarnessId::new(),
47 name: name.into(),
48 display_name: None,
49 description: None,
50 system_prompt: system_prompt.into(),
51 parent_harness_id: None,
52 default_model_id: None,
53 tags: Vec::new(),
54 capabilities: Vec::new(),
55 initial_files: Vec::new(),
56 network_access: None,
57 mcp_servers: ScopedMcpServers::default(),
58 embedder_metadata: HashMap::new(),
59 is_built_in: false,
60 status: HarnessStatus::Active,
61 created_at: None,
62 updated_at: None,
63 }
64 }
65
66 pub fn id(mut self, id: HarnessId) -> Self {
68 self.id = id;
69 self
70 }
71
72 pub fn harness_id(&self) -> HarnessId {
74 self.id
75 }
76
77 pub fn name(mut self, name: impl Into<String>) -> Self {
78 self.name = name.into();
79 self
80 }
81
82 pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
83 self.display_name = Some(display_name.into());
84 self
85 }
86
87 pub fn description(mut self, description: impl Into<String>) -> Self {
88 self.description = Some(description.into());
89 self
90 }
91
92 pub fn system_prompt(mut self, system_prompt: impl Into<String>) -> Self {
93 self.system_prompt = system_prompt.into();
94 self
95 }
96
97 pub fn parent_harness_id(mut self, parent_harness_id: HarnessId) -> Self {
98 self.parent_harness_id = Some(parent_harness_id);
99 self
100 }
101
102 pub fn default_model_id(mut self, default_model_id: ModelId) -> Self {
103 self.default_model_id = Some(default_model_id);
104 self
105 }
106
107 pub fn tag(mut self, tag: impl Into<String>) -> Self {
108 self.tags.push(tag.into());
109 self
110 }
111
112 pub fn tags<I, S>(mut self, tags: I) -> Self
113 where
114 I: IntoIterator<Item = S>,
115 S: Into<String>,
116 {
117 self.tags.extend(tags.into_iter().map(Into::into));
118 self
119 }
120
121 pub fn capability(mut self, capability: impl Into<AgentCapabilityConfig>) -> Self {
122 self.capabilities.push(capability.into());
123 self
124 }
125
126 pub fn with_capability(self, capability: impl Into<AgentCapabilityConfig>) -> Self {
127 self.capability(capability)
128 }
129
130 pub fn capabilities<I, C>(mut self, capabilities: I) -> Self
131 where
132 I: IntoIterator<Item = C>,
133 C: Into<AgentCapabilityConfig>,
134 {
135 self.capabilities
136 .extend(capabilities.into_iter().map(Into::into));
137 self
138 }
139
140 pub fn initial_file(mut self, file: everruns_core::InitialFile) -> Self {
141 self.initial_files.push(file);
142 self
143 }
144
145 pub fn network_access(mut self, network_access: NetworkAccessList) -> Self {
146 self.network_access = Some(network_access);
147 self
148 }
149
150 pub fn mcp_servers(mut self, mcp_servers: ScopedMcpServers) -> Self {
151 self.mcp_servers = mcp_servers;
152 self
153 }
154
155 pub fn metadata_entry(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
156 self.embedder_metadata.insert(key.into(), value.into());
157 self
158 }
159
160 pub fn metadata_entries<I, K, V>(mut self, entries: I) -> Self
161 where
162 I: IntoIterator<Item = (K, V)>,
163 K: Into<String>,
164 V: Into<String>,
165 {
166 self.embedder_metadata
167 .extend(entries.into_iter().map(|(k, v)| (k.into(), v.into())));
168 self
169 }
170
171 pub fn is_built_in(mut self, is_built_in: bool) -> Self {
172 self.is_built_in = is_built_in;
173 self
174 }
175
176 pub fn status(mut self, status: HarnessStatus) -> Self {
177 self.status = status;
178 self
179 }
180
181 pub fn created_at(mut self, created_at: DateTime<Utc>) -> Self {
182 self.created_at = Some(created_at);
183 self
184 }
185
186 pub fn updated_at(mut self, updated_at: DateTime<Utc>) -> Self {
187 self.updated_at = Some(updated_at);
188 self
189 }
190
191 pub fn build(self) -> Harness {
193 let created_at = self.created_at.unwrap_or_else(Utc::now);
194 let updated_at = self.updated_at.unwrap_or(created_at);
195
196 Harness {
197 id: self.id,
198 name: self.name,
199 display_name: self.display_name,
200 description: self.description,
201 system_prompt: self.system_prompt,
202 parent_harness_id: self.parent_harness_id,
203 default_model_id: self.default_model_id,
204 tags: self.tags,
205 capabilities: self.capabilities,
206 initial_files: self.initial_files,
207 network_access: self.network_access,
208 mcp_servers: self.mcp_servers,
209 embedder_metadata: self.embedder_metadata,
210 is_built_in: self.is_built_in,
211 status: self.status,
212 created_at,
213 updated_at,
214 archived_at: None,
215 deleted_at: None,
216 }
217 }
218}
219
220#[derive(Debug, Clone)]
222pub struct AgentBuilder {
223 id: AgentId,
224 name: String,
225 display_name: Option<String>,
226 description: Option<String>,
227 system_prompt: String,
228 default_model_id: Option<ModelId>,
229 tags: Vec<String>,
230 capabilities: Vec<AgentCapabilityConfig>,
231 initial_files: Vec<everruns_core::InitialFile>,
232 network_access: Option<NetworkAccessList>,
233 max_iterations: Option<usize>,
234 tools: Vec<ToolDefinition>,
235 mcp_servers: ScopedMcpServers,
236 status: AgentStatus,
237 created_at: Option<DateTime<Utc>>,
238 updated_at: Option<DateTime<Utc>>,
239}
240
241impl AgentBuilder {
242 pub fn new(name: impl Into<String>, system_prompt: impl Into<String>) -> Self {
244 Self {
245 id: AgentId::new(),
246 name: name.into(),
247 display_name: None,
248 description: None,
249 system_prompt: system_prompt.into(),
250 default_model_id: None,
251 tags: Vec::new(),
252 capabilities: Vec::new(),
253 initial_files: Vec::new(),
254 network_access: None,
255 max_iterations: None,
256 tools: Vec::new(),
257 mcp_servers: ScopedMcpServers::default(),
258 status: AgentStatus::Active,
259 created_at: None,
260 updated_at: None,
261 }
262 }
263
264 pub fn id(mut self, id: AgentId) -> Self {
266 self.id = id;
267 self
268 }
269
270 pub fn agent_id(&self) -> AgentId {
272 self.id
273 }
274
275 pub fn name(mut self, name: impl Into<String>) -> Self {
276 self.name = name.into();
277 self
278 }
279
280 pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
281 self.display_name = Some(display_name.into());
282 self
283 }
284
285 pub fn description(mut self, description: impl Into<String>) -> Self {
286 self.description = Some(description.into());
287 self
288 }
289
290 pub fn system_prompt(mut self, system_prompt: impl Into<String>) -> Self {
291 self.system_prompt = system_prompt.into();
292 self
293 }
294
295 pub fn default_model_id(mut self, default_model_id: ModelId) -> Self {
296 self.default_model_id = Some(default_model_id);
297 self
298 }
299
300 pub fn tag(mut self, tag: impl Into<String>) -> Self {
301 self.tags.push(tag.into());
302 self
303 }
304
305 pub fn tags<I, S>(mut self, tags: I) -> Self
306 where
307 I: IntoIterator<Item = S>,
308 S: Into<String>,
309 {
310 self.tags.extend(tags.into_iter().map(Into::into));
311 self
312 }
313
314 pub fn capability(mut self, capability: impl Into<AgentCapabilityConfig>) -> Self {
315 self.capabilities.push(capability.into());
316 self
317 }
318
319 pub fn with_capability(self, capability: impl Into<AgentCapabilityConfig>) -> Self {
320 self.capability(capability)
321 }
322
323 pub fn capabilities<I, C>(mut self, capabilities: I) -> Self
324 where
325 I: IntoIterator<Item = C>,
326 C: Into<AgentCapabilityConfig>,
327 {
328 self.capabilities
329 .extend(capabilities.into_iter().map(Into::into));
330 self
331 }
332
333 pub fn initial_file(mut self, file: everruns_core::InitialFile) -> Self {
334 self.initial_files.push(file);
335 self
336 }
337
338 pub fn network_access(mut self, network_access: NetworkAccessList) -> Self {
339 self.network_access = Some(network_access);
340 self
341 }
342
343 pub fn max_iterations(mut self, max_iterations: usize) -> Self {
344 self.max_iterations = Some(max_iterations);
345 self
346 }
347
348 pub fn tool(mut self, tool: ToolDefinition) -> Self {
349 self.tools.push(tool);
350 self
351 }
352
353 pub fn tools<I>(mut self, tools: I) -> Self
354 where
355 I: IntoIterator<Item = ToolDefinition>,
356 {
357 self.tools.extend(tools);
358 self
359 }
360
361 pub fn mcp_servers(mut self, mcp_servers: ScopedMcpServers) -> Self {
362 self.mcp_servers = mcp_servers;
363 self
364 }
365
366 pub fn status(mut self, status: AgentStatus) -> Self {
367 self.status = status;
368 self
369 }
370
371 pub fn created_at(mut self, created_at: DateTime<Utc>) -> Self {
372 self.created_at = Some(created_at);
373 self
374 }
375
376 pub fn updated_at(mut self, updated_at: DateTime<Utc>) -> Self {
377 self.updated_at = Some(updated_at);
378 self
379 }
380
381 pub fn build(self) -> Agent {
383 let created_at = self.created_at.unwrap_or_else(Utc::now);
384 let updated_at = self.updated_at.unwrap_or(created_at);
385
386 Agent {
387 public_id: self.id,
388 internal_id: Uuid::nil(),
389 name: self.name,
390 display_name: self.display_name,
391 description: self.description,
392 system_prompt: self.system_prompt,
393 default_model_id: self.default_model_id,
394 default_version_id: None,
395 forked_from_agent_id: None,
396 forked_from_version_id: None,
397 root_agent_id: None,
398 tags: self.tags,
399 capabilities: self.capabilities,
400 initial_files: self.initial_files,
401 network_access: self.network_access,
402 max_iterations: self.max_iterations,
403 tools: self.tools,
404 mcp_servers: self.mcp_servers,
405 status: self.status,
406 created_at,
407 updated_at,
408 archived_at: None,
409 deleted_at: None,
410 usage: None,
411 }
412 }
413}
414
415#[derive(Debug, Clone)]
417pub struct SessionBuilder {
418 id: SessionId,
419 organization_id: String,
420 harness_id: HarnessId,
421 agent_id: Option<AgentId>,
422 owner_principal_id: PrincipalId,
423 title: Option<String>,
424 locale: Option<String>,
425 tags: Vec<String>,
426 model_id: Option<ModelId>,
427 capabilities: Vec<AgentCapabilityConfig>,
428 tools: Vec<ToolDefinition>,
429 mcp_servers: ScopedMcpServers,
430 system_prompt: Option<String>,
431 initial_files: Vec<everruns_core::InitialFile>,
432 network_access: Option<NetworkAccessList>,
433 max_iterations: Option<usize>,
434 status: SessionStatus,
435 created_at: Option<DateTime<Utc>>,
436 updated_at: Option<DateTime<Utc>>,
437}
438
439impl SessionBuilder {
440 pub fn new(harness_id: HarnessId) -> Self {
442 Self {
443 id: SessionId::new(),
444 organization_id: DEFAULT_ORG_PUBLIC_ID.to_string(),
445 harness_id,
446 agent_id: None,
447 owner_principal_id: PrincipalId::from_seed(1),
448 title: None,
449 locale: None,
450 tags: Vec::new(),
451 model_id: None,
452 capabilities: Vec::new(),
453 tools: Vec::new(),
454 mcp_servers: ScopedMcpServers::default(),
455 system_prompt: None,
456 initial_files: Vec::new(),
457 network_access: None,
458 max_iterations: None,
459 status: SessionStatus::Started,
460 created_at: None,
461 updated_at: None,
462 }
463 }
464
465 pub fn id(mut self, id: SessionId) -> Self {
467 self.id = id;
468 self
469 }
470
471 pub fn session_id(&self) -> SessionId {
473 self.id
474 }
475
476 pub fn organization_id(mut self, organization_id: impl Into<String>) -> Self {
477 self.organization_id = organization_id.into();
478 self
479 }
480
481 pub fn harness(mut self, harness_id: HarnessId) -> Self {
482 self.harness_id = harness_id;
483 self
484 }
485
486 pub fn agent(mut self, agent_id: AgentId) -> Self {
487 self.agent_id = Some(agent_id);
488 self
489 }
490
491 pub fn owner_principal_id(mut self, owner_principal_id: PrincipalId) -> Self {
492 self.owner_principal_id = owner_principal_id;
493 self
494 }
495
496 pub fn title(mut self, title: impl Into<String>) -> Self {
497 self.title = Some(title.into());
498 self
499 }
500
501 pub fn locale(mut self, locale: impl Into<String>) -> Self {
502 self.locale = Some(locale.into());
503 self
504 }
505
506 pub fn tag(mut self, tag: impl Into<String>) -> Self {
507 self.tags.push(tag.into());
508 self
509 }
510
511 pub fn tags<I, S>(mut self, tags: I) -> Self
512 where
513 I: IntoIterator<Item = S>,
514 S: Into<String>,
515 {
516 self.tags.extend(tags.into_iter().map(Into::into));
517 self
518 }
519
520 pub fn model_id(mut self, model_id: ModelId) -> Self {
521 self.model_id = Some(model_id);
522 self
523 }
524
525 pub fn capability(mut self, capability: impl Into<AgentCapabilityConfig>) -> Self {
526 self.capabilities.push(capability.into());
527 self
528 }
529
530 pub fn with_capability(self, capability: impl Into<AgentCapabilityConfig>) -> Self {
531 self.capability(capability)
532 }
533
534 pub fn capabilities<I, C>(mut self, capabilities: I) -> Self
535 where
536 I: IntoIterator<Item = C>,
537 C: Into<AgentCapabilityConfig>,
538 {
539 self.capabilities
540 .extend(capabilities.into_iter().map(Into::into));
541 self
542 }
543
544 pub fn tool(mut self, tool: ToolDefinition) -> Self {
545 self.tools.push(tool);
546 self
547 }
548
549 pub fn tools<I>(mut self, tools: I) -> Self
550 where
551 I: IntoIterator<Item = ToolDefinition>,
552 {
553 self.tools.extend(tools);
554 self
555 }
556
557 pub fn mcp_servers(mut self, mcp_servers: ScopedMcpServers) -> Self {
558 self.mcp_servers = mcp_servers;
559 self
560 }
561
562 pub fn system_prompt(mut self, system_prompt: impl Into<String>) -> Self {
563 self.system_prompt = Some(system_prompt.into());
564 self
565 }
566
567 pub fn initial_file(mut self, file: everruns_core::InitialFile) -> Self {
568 self.initial_files.push(file);
569 self
570 }
571
572 pub fn network_access(mut self, network_access: NetworkAccessList) -> Self {
573 self.network_access = Some(network_access);
574 self
575 }
576
577 pub fn max_iterations(mut self, max_iterations: usize) -> Self {
578 self.max_iterations = Some(max_iterations);
579 self
580 }
581
582 pub fn status(mut self, status: SessionStatus) -> Self {
583 self.status = status;
584 self
585 }
586
587 pub fn created_at(mut self, created_at: DateTime<Utc>) -> Self {
588 self.created_at = Some(created_at);
589 self
590 }
591
592 pub fn updated_at(mut self, updated_at: DateTime<Utc>) -> Self {
593 self.updated_at = Some(updated_at);
594 self
595 }
596
597 pub fn build(self) -> Session {
599 let created_at = self.created_at.unwrap_or_else(Utc::now);
600 let updated_at = self.updated_at.unwrap_or(created_at);
601
602 Session {
603 id: self.id,
604 workspace_id: everruns_core::WorkspaceId::from_uuid((self.id).uuid()),
605 organization_id: self.organization_id,
606 harness_id: self.harness_id,
607 agent_id: self.agent_id,
608 agent_version_id: None,
609 agent_identity_id: None,
610 owner_principal_id: self.owner_principal_id,
611 resolved_owner_user_id: None,
612 owner: None,
613 effective_owner: None,
614 title: self.title,
615 locale: self.locale,
616 preview: None,
617 output_preview: None,
618 tags: self.tags,
619 model_id: self.model_id,
620 capabilities: self.capabilities,
621 tools: self.tools,
622 mcp_servers: self.mcp_servers,
623 system_prompt: self.system_prompt,
624 initial_files: self.initial_files,
625 hints: None,
626 network_access: self.network_access,
627 max_iterations: self.max_iterations,
628 status: self.status,
629 created_at,
630 updated_at,
631 started_at: None,
632 finished_at: None,
633 usage: None,
634 is_pinned: None,
635 active_schedule_count: None,
636 features: Vec::new(),
637 parent_session_id: None,
638 blueprint_id: None,
639 blueprint_config: None,
640 }
641 }
642}
643
644#[derive(Debug, Clone)]
649pub struct SingleSessionBuilder {
650 harness: HarnessBuilder,
651 agent: AgentBuilder,
652 session: SessionBuilder,
653}
654
655impl Default for SingleSessionBuilder {
656 fn default() -> Self {
657 let harness = HarnessBuilder::new("embedded-harness", "");
658 let agent = AgentBuilder::new("embedded-agent", "");
659 let session = SessionBuilder::new(harness.harness_id()).agent(agent.agent_id());
660 Self {
661 harness,
662 agent,
663 session,
664 }
665 }
666}
667
668impl SingleSessionBuilder {
669 pub fn harness(mut self, name: impl Into<String>, system_prompt: impl Into<String>) -> Self {
673 let harness_id = self.harness.harness_id();
674 self.harness = self.harness.name(name).system_prompt(system_prompt);
675 self.session = self.session.harness(harness_id);
676 self
677 }
678
679 pub fn agent(mut self, name: impl Into<String>, system_prompt: impl Into<String>) -> Self {
683 let agent_id = self.agent.agent_id();
684 self.agent = self.agent.name(name).system_prompt(system_prompt);
685 self.session = self.session.agent(agent_id);
686 self
687 }
688
689 pub fn with_capability(self, capability: impl Into<AgentCapabilityConfig>) -> Self {
691 self.harness_capability(capability)
692 }
693
694 pub fn harness_capability(mut self, capability: impl Into<AgentCapabilityConfig>) -> Self {
696 self.harness = self.harness.capability(capability);
697 self
698 }
699
700 pub fn agent_capability(mut self, capability: impl Into<AgentCapabilityConfig>) -> Self {
702 self.agent = self.agent.capability(capability);
703 self
704 }
705
706 pub fn agent_plugin(mut self, name: &str) -> Self {
719 self.agent = self.agent.capability(plugin_capability_id(name));
720 self
721 }
722
723 pub fn session_capability(mut self, capability: impl Into<AgentCapabilityConfig>) -> Self {
725 self.session = self.session.capability(capability);
726 self
727 }
728
729 pub fn session_mcp_servers(mut self, mcp_servers: ScopedMcpServers) -> Self {
732 self.session = self.session.mcp_servers(mcp_servers);
733 self
734 }
735
736 pub fn harness_display_name(mut self, display_name: impl Into<String>) -> Self {
737 self.harness = self.harness.display_name(display_name);
738 self
739 }
740
741 pub fn agent_display_name(mut self, display_name: impl Into<String>) -> Self {
742 self.agent = self.agent.display_name(display_name);
743 self
744 }
745
746 pub fn harness_description(mut self, description: impl Into<String>) -> Self {
747 self.harness = self.harness.description(description);
748 self
749 }
750
751 pub fn agent_description(mut self, description: impl Into<String>) -> Self {
752 self.agent = self.agent.description(description);
753 self
754 }
755
756 pub fn session_title(mut self, title: impl Into<String>) -> Self {
757 self.session = self.session.title(title);
758 self
759 }
760
761 pub fn locale(mut self, locale: impl Into<String>) -> Self {
762 self.session = self.session.locale(locale);
763 self
764 }
765
766 pub fn tag(mut self, tag: impl Into<String>) -> Self {
767 let tag = tag.into();
768 self.harness = self.harness.tag(tag.clone());
769 self.agent = self.agent.tag(tag.clone());
770 self.session = self.session.tag(tag);
771 self
772 }
773
774 pub fn session_model_id(mut self, model_id: ModelId) -> Self {
775 self.session = self.session.model_id(model_id);
776 self
777 }
778
779 pub fn harness_default_model_id(mut self, model_id: ModelId) -> Self {
780 self.harness = self.harness.default_model_id(model_id);
781 self
782 }
783
784 pub fn agent_default_model_id(mut self, model_id: ModelId) -> Self {
785 self.agent = self.agent.default_model_id(model_id);
786 self
787 }
788
789 pub fn agent_max_iterations(mut self, max_iterations: usize) -> Self {
790 self.agent = self.agent.max_iterations(max_iterations);
791 self
792 }
793
794 pub fn session_max_iterations(mut self, max_iterations: usize) -> Self {
795 self.session = self.session.max_iterations(max_iterations);
796 self
797 }
798
799 pub fn agent_tool(mut self, tool: ToolDefinition) -> Self {
800 self.agent = self.agent.tool(tool);
801 self
802 }
803
804 pub fn session_tool(mut self, tool: ToolDefinition) -> Self {
805 self.session = self.session.tool(tool);
806 self
807 }
808
809 pub fn harness_initial_file(mut self, file: everruns_core::InitialFile) -> Self {
810 self.harness = self.harness.initial_file(file);
811 self
812 }
813
814 pub fn agent_initial_file(mut self, file: everruns_core::InitialFile) -> Self {
815 self.agent = self.agent.initial_file(file);
816 self
817 }
818
819 pub fn session_initial_file(mut self, file: everruns_core::InitialFile) -> Self {
820 self.session = self.session.initial_file(file);
821 self
822 }
823
824 pub fn harness_network_access(mut self, network_access: NetworkAccessList) -> Self {
825 self.harness = self.harness.network_access(network_access);
826 self
827 }
828
829 pub fn agent_network_access(mut self, network_access: NetworkAccessList) -> Self {
830 self.agent = self.agent.network_access(network_access);
831 self
832 }
833
834 pub fn session_network_access(mut self, network_access: NetworkAccessList) -> Self {
835 self.session = self.session.network_access(network_access);
836 self
837 }
838
839 pub fn harness_id(&self) -> HarnessId {
840 self.harness.harness_id()
841 }
842
843 pub fn agent_id(&self) -> AgentId {
844 self.agent.agent_id()
845 }
846
847 pub fn session_id(mut self, id: SessionId) -> Self {
854 self.session = self.session.id(id);
855 self
856 }
857
858 pub(crate) fn build(self) -> (Harness, Agent, Session, SessionId) {
859 let session_id = self.session.session_id();
860 (
861 self.harness.build(),
862 self.agent.build(),
863 self.session.build(),
864 session_id,
865 )
866 }
867}