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