use chrono::{DateTime, Utc};
use scouter_types::genai::AssertionResult;
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use tracing::debug;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TaskType {
Assertion,
LLMJudge,
TraceAssertion,
AgentAssertion,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TaskMetadata {
pub task_type: TaskType,
pub is_conditional: bool,
}
#[derive(Debug)]
pub struct TaskRegistry {
registry: HashMap<String, TaskMetadata>,
dependency_map: HashMap<String, Arc<Vec<String>>>,
skipped_tasks: HashSet<String>,
}
impl TaskRegistry {
pub fn new() -> Self {
debug!("Initializing TaskRegistry");
Self {
registry: HashMap::new(),
dependency_map: HashMap::new(),
skipped_tasks: HashSet::new(),
}
}
pub fn mark_skipped(&mut self, task_id: String) {
self.skipped_tasks.insert(task_id);
}
pub fn is_skipped(&self, task_id: &str) -> bool {
self.skipped_tasks.contains(task_id)
}
pub fn register(&mut self, task_id: String, task_type: TaskType, is_conditional: bool) {
self.registry.insert(
task_id,
TaskMetadata {
task_type,
is_conditional,
},
);
}
pub fn get_type(&self, task_id: &str) -> Option<TaskType> {
self.registry.get(task_id).map(|meta| meta.task_type)
}
pub fn is_conditional(&self, task_id: &str) -> bool {
self.registry
.get(task_id)
.map(|meta| meta.is_conditional)
.unwrap_or(false)
}
pub fn contains(&self, task_id: &str) -> bool {
self.registry.contains_key(task_id)
}
pub fn register_dependencies(&mut self, task_id: String, dependencies: Vec<String>) {
self.dependency_map.insert(task_id, Arc::new(dependencies));
}
pub fn get_dependencies(&self, task_id: &str) -> Option<Arc<Vec<String>>> {
if !self.registry.contains_key(task_id) {
return None;
}
Some(self.dependency_map.get(task_id)?.clone())
}
}
impl Default for TaskRegistry {
fn default() -> Self {
Self::new()
}
}
type AssertionResultType = (DateTime<Utc>, DateTime<Utc>, AssertionResult);
#[derive(Debug)]
pub struct AssertionResultStore {
store: HashMap<String, AssertionResultType>,
}
impl AssertionResultStore {
pub fn new() -> Self {
AssertionResultStore {
store: HashMap::new(),
}
}
pub fn store(
&mut self,
task_id: String,
start_time: DateTime<Utc>,
end_time: DateTime<Utc>,
result: AssertionResult,
) {
self.store.insert(task_id, (start_time, end_time, result));
}
pub fn retrieve(&self, task_id: &str) -> Option<AssertionResultType> {
self.store.get(task_id).cloned()
}
}
impl Default for AssertionResultStore {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct LLMResponseStore {
store: HashMap<String, serde_json::Value>,
}
impl LLMResponseStore {
pub fn new() -> Self {
LLMResponseStore {
store: HashMap::new(),
}
}
pub fn store(&mut self, task_id: String, response: serde_json::Value) {
self.store.insert(task_id, response);
}
pub fn retrieve(&self, task_id: &str) -> Option<serde_json::Value> {
self.store.get(task_id).cloned()
}
}
impl Default for LLMResponseStore {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_task_registry() {
let mut registry = TaskRegistry::new();
registry.register("task1".to_string(), TaskType::Assertion, false);
registry.register("task2".to_string(), TaskType::LLMJudge, false);
assert_eq!(registry.get_type("task1"), Some(TaskType::Assertion));
assert_eq!(registry.get_type("task2"), Some(TaskType::LLMJudge));
assert!(registry.contains("task1"));
assert!(!registry.contains("task3"));
}
}