1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Scenario {
8 pub id: Uuid,
9 pub agent_id: Uuid,
10 pub input: ScenarioInput,
11 pub expected: ScenarioExpected,
12 pub difficulty: DifficultyTier,
13 pub domain: Option<String>,
14 pub source: ScenarioSource,
15 pub tags: Vec<String>,
16 pub created_at: DateTime<Utc>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct ScenarioInput {
22 pub user_message: String,
24 pub conversation_history: Vec<ConversationTurn>,
26 pub context: Option<serde_json::Value>,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct ConversationTurn {
32 pub role: ConversationRole,
33 pub content: String,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
37#[serde(rename_all = "snake_case")]
38pub enum ConversationRole {
39 User,
40 Assistant,
41 System,
42 Tool,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct ScenarioExpected {
48 pub tool_calls: Vec<ExpectedToolCall>,
50 pub output_schema: Option<serde_json::Value>,
52 pub pass_criteria: String,
54 pub min_turns: Option<u32>,
56 pub max_turns: Option<u32>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct ExpectedToolCall {
62 pub tool_name: String,
63 pub required: bool,
65 pub argument_schema: Option<serde_json::Value>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
70#[serde(rename_all = "snake_case")]
71pub enum DifficultyTier {
72 Easy,
73 Medium,
74 Hard,
75 Edge,
76}
77
78impl std::fmt::Display for DifficultyTier {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 match self {
81 DifficultyTier::Easy => write!(f, "easy"),
82 DifficultyTier::Medium => write!(f, "medium"),
83 DifficultyTier::Hard => write!(f, "hard"),
84 DifficultyTier::Edge => write!(f, "edge"),
85 }
86 }
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
90#[serde(rename_all = "snake_case")]
91pub enum ScenarioSource {
92 SchemaDerived,
93 Adversarial,
94 DomainSeeded,
95 Manual,
96}
97
98impl std::fmt::Display for ScenarioSource {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 match self {
101 ScenarioSource::SchemaDerived => write!(f, "schema_derived"),
102 ScenarioSource::Adversarial => write!(f, "adversarial"),
103 ScenarioSource::DomainSeeded => write!(f, "domain_seeded"),
104 ScenarioSource::Manual => write!(f, "manual"),
105 }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn difficulty_tier_display() {
115 assert_eq!(DifficultyTier::Easy.to_string(), "easy");
116 assert_eq!(DifficultyTier::Edge.to_string(), "edge");
117 }
118
119 #[test]
120 fn scenario_source_display() {
121 assert_eq!(ScenarioSource::SchemaDerived.to_string(), "schema_derived");
122 assert_eq!(ScenarioSource::DomainSeeded.to_string(), "domain_seeded");
123 }
124}