use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Scenario {
pub id: Uuid,
pub agent_id: Uuid,
pub input: ScenarioInput,
pub expected: ScenarioExpected,
pub difficulty: DifficultyTier,
pub domain: Option<String>,
pub source: ScenarioSource,
pub tags: Vec<String>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScenarioInput {
pub user_message: String,
pub conversation_history: Vec<ConversationTurn>,
pub context: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationTurn {
pub role: ConversationRole,
pub content: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ConversationRole {
User,
Assistant,
System,
Tool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScenarioExpected {
pub tool_calls: Vec<ExpectedToolCall>,
pub output_schema: Option<serde_json::Value>,
pub pass_criteria: String,
pub min_turns: Option<u32>,
pub max_turns: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExpectedToolCall {
pub tool_name: String,
pub required: bool,
pub argument_schema: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum DifficultyTier {
Easy,
Medium,
Hard,
Edge,
}
impl std::fmt::Display for DifficultyTier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DifficultyTier::Easy => write!(f, "easy"),
DifficultyTier::Medium => write!(f, "medium"),
DifficultyTier::Hard => write!(f, "hard"),
DifficultyTier::Edge => write!(f, "edge"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ScenarioSource {
SchemaDerived,
Adversarial,
DomainSeeded,
Manual,
}
impl std::fmt::Display for ScenarioSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ScenarioSource::SchemaDerived => write!(f, "schema_derived"),
ScenarioSource::Adversarial => write!(f, "adversarial"),
ScenarioSource::DomainSeeded => write!(f, "domain_seeded"),
ScenarioSource::Manual => write!(f, "manual"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn difficulty_tier_display() {
assert_eq!(DifficultyTier::Easy.to_string(), "easy");
assert_eq!(DifficultyTier::Edge.to_string(), "edge");
}
#[test]
fn scenario_source_display() {
assert_eq!(ScenarioSource::SchemaDerived.to_string(), "schema_derived");
assert_eq!(ScenarioSource::DomainSeeded.to_string(), "domain_seeded");
}
}