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