pub mod assembler;
pub mod classifier;
pub mod cost_tracker;
pub mod learner;
#[cfg(feature = "native")]
pub mod llm_adapter;
pub mod mutation;
pub mod permissions;
pub mod rate_limiter;
pub mod router;
pub mod scorer;
pub mod tiered_router;
pub mod traits;
pub mod transport;
use std::sync::Arc;
use clawft_types::config::PipelineConfig;
use self::learner::{NoopLearner, TrajectoryLearner, TrajectoryLearnerConfig};
use self::scorer::{FitnessScorer, NoopScorer};
use self::traits::{LearningBackend, QualityScorer};
pub fn build_scorer(config: &PipelineConfig) -> Arc<dyn QualityScorer> {
match config.scorer.as_str() {
"fitness" => Arc::new(FitnessScorer::new()),
_ => Arc::new(NoopScorer::new()),
}
}
pub fn build_learner(config: &PipelineConfig) -> Arc<dyn LearningBackend> {
match config.learner.as_str() {
"trajectory" => Arc::new(TrajectoryLearner::new(TrajectoryLearnerConfig::default())),
_ => Arc::new(NoopLearner::new()),
}
}
#[cfg(test)]
mod factory_tests {
use super::*;
use clawft_types::config::PipelineConfig;
#[test]
fn build_scorer_noop_default() {
let config = PipelineConfig::default();
let scorer = build_scorer(&config);
let req = traits::ChatRequest {
messages: vec![],
tools: vec![],
model: None,
max_tokens: None,
temperature: None,
auth_context: None,
complexity_boost: 0.0,
};
let resp = clawft_types::provider::LlmResponse {
id: "test".into(),
content: vec![],
stop_reason: clawft_types::provider::StopReason::EndTurn,
usage: clawft_types::provider::Usage {
input_tokens: 0,
output_tokens: 0,
total_tokens: 0,
},
metadata: std::collections::HashMap::new(),
};
let score = scorer.score(&req, &resp);
assert!((score.overall - 1.0).abs() < f32::EPSILON);
}
#[test]
fn build_scorer_fitness() {
let config = PipelineConfig {
scorer: "fitness".into(),
learner: "noop".into(),
};
let scorer = build_scorer(&config);
let req = traits::ChatRequest {
messages: vec![],
tools: vec![],
model: None,
max_tokens: None,
temperature: None,
auth_context: None,
complexity_boost: 0.0,
};
let resp = clawft_types::provider::LlmResponse {
id: "test".into(),
content: vec![],
stop_reason: clawft_types::provider::StopReason::EndTurn,
usage: clawft_types::provider::Usage {
input_tokens: 0,
output_tokens: 0,
total_tokens: 0,
},
metadata: std::collections::HashMap::new(),
};
let score = scorer.score(&req, &resp);
assert!(score.overall < 1.0);
}
#[test]
fn build_learner_noop_default() {
let config = PipelineConfig::default();
let _learner = build_learner(&config);
}
#[test]
fn build_learner_trajectory() {
let config = PipelineConfig {
scorer: "noop".into(),
learner: "trajectory".into(),
};
let _learner = build_learner(&config);
}
#[test]
fn build_scorer_unknown_falls_to_noop() {
let config = PipelineConfig {
scorer: "unknown_thing".into(),
learner: "noop".into(),
};
let scorer = build_scorer(&config);
let req = traits::ChatRequest {
messages: vec![],
tools: vec![],
model: None,
max_tokens: None,
temperature: None,
auth_context: None,
complexity_boost: 0.0,
};
let resp = clawft_types::provider::LlmResponse {
id: "test".into(),
content: vec![],
stop_reason: clawft_types::provider::StopReason::EndTurn,
usage: clawft_types::provider::Usage {
input_tokens: 0,
output_tokens: 0,
total_tokens: 0,
},
metadata: std::collections::HashMap::new(),
};
let score = scorer.score(&req, &resp);
assert!((score.overall - 1.0).abs() < f32::EPSILON);
}
#[test]
fn build_learner_unknown_falls_to_noop() {
let config = PipelineConfig {
scorer: "noop".into(),
learner: "not_real".into(),
};
let _learner = build_learner(&config);
}
}