pub struct TaskComplexityAnalyzer;
impl TaskComplexityAnalyzer {
pub fn new() -> Self {
Self
}
pub fn analyze(&self, task: &str) -> f32 {
let lower = task.to_lowercase();
let words: Vec<&str> = lower.split_whitespace().collect();
let word_count = words.len();
let length_score = (word_count as f32 / 200.0).min(1.0) * 0.25;
let sentence_count = lower
.chars()
.filter(|c| *c == '.' || *c == '?' || *c == '!' || *c == ';')
.count()
.max(1); let sentence_score = ((sentence_count as f32 - 1.0) / 5.0).clamp(0.0, 1.0) * 0.15;
let technical_keywords = [
"api",
"database",
"schema",
"authentication",
"authorization",
"deploy",
"kubernetes",
"docker",
"algorithm",
"concurrency",
"async",
"microservice",
"architecture",
"security",
"encryption",
"sql",
"graphql",
"websocket",
"distributed",
"cache",
"index",
"migration",
];
let tech_hits = technical_keywords
.iter()
.filter(|kw| lower.contains(**kw))
.count();
let tech_score = (tech_hits as f32 / 4.0).min(1.0) * 0.25;
let step_indicators = [
"first",
"second",
"third",
"then",
"finally",
"next",
"step 1",
"step 2",
"step 3",
"after that",
"followed by",
"in addition",
];
let step_hits = step_indicators
.iter()
.filter(|si| lower.contains(**si))
.count();
let step_score = (step_hits as f32 / 3.0).min(1.0) * 0.20;
let code_score = if lower.contains("```") { 0.15 } else { 0.0 };
(length_score + sentence_score + tech_score + step_score + code_score).clamp(0.0, 1.0)
}
}
impl Default for TaskComplexityAnalyzer {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_question_low_complexity() {
let a = TaskComplexityAnalyzer::new();
let score = a.analyze("What is 2 + 2?");
assert!(
score < 0.3,
"simple question should be low complexity, got {score}"
);
}
#[test]
fn complex_multipart_request_higher() {
let a = TaskComplexityAnalyzer::new();
let simple = a.analyze("What is Rust?");
let complex = a.analyze(
"First, design the database schema for a distributed authentication \
microservice. Then implement the API endpoints with proper authorization. \
Next, add caching with Redis. Finally, deploy to Kubernetes with \
encrypted secrets.",
);
assert!(
complex > simple,
"complex ({complex}) should beat simple ({simple})"
);
}
#[test]
fn technical_keywords_raise_complexity() {
let a = TaskComplexityAnalyzer::new();
let no_tech = a.analyze("Tell me a story about a cat.");
let with_tech = a.analyze("Set up the database schema and deploy to kubernetes.");
assert!(
with_tech > no_tech,
"technical ({with_tech}) should beat non-technical ({no_tech})"
);
}
#[test]
fn empty_task_returns_zero() {
let a = TaskComplexityAnalyzer::new();
let score = a.analyze("");
assert!(
score.abs() < f32::EPSILON,
"empty task should be 0.0, got {score}"
);
}
#[test]
fn score_clamped_to_unit_range() {
let a = TaskComplexityAnalyzer::new();
let score = a.analyze(
"First, design the api architecture for a distributed database microservice \
with authentication and authorization. Then implement concurrency with async \
websocket connections. Next, add encryption and caching. Finally, deploy to \
kubernetes with docker. Step 1: schema migration. Step 2: graphql index. \
Step 3: security audit. ```code here``` After that, followed by more work. \
In addition, add algorithm for sql cache.",
);
assert!(score <= 1.0, "score should be <= 1.0, got {score}");
assert!(score >= 0.0, "score should be >= 0.0, got {score}");
}
#[test]
fn code_fences_raise_complexity() {
let a = TaskComplexityAnalyzer::new();
let no_code = a.analyze("Explain this function.");
let with_code = a.analyze("Explain this function: ```fn main() {}```");
assert!(
with_code > no_code,
"with code ({with_code}) should beat without ({no_code})"
);
}
#[test]
fn step_indicators_raise_complexity() {
let a = TaskComplexityAnalyzer::new();
let no_steps = a.analyze("Do the thing.");
let with_steps = a.analyze("First do A, then do B, finally do C.");
assert!(
with_steps > no_steps,
"with steps ({with_steps}) should beat without ({no_steps})"
);
}
#[test]
fn default_trait_creates_valid_analyzer() {
let a = TaskComplexityAnalyzer::default();
let score = a.analyze("hello");
assert!(score >= 0.0);
assert!(score <= 1.0);
}
#[test]
fn longer_text_scores_higher_than_shorter() {
let a = TaskComplexityAnalyzer::new();
let short = a.analyze("help");
let long = a.analyze(&"word ".repeat(100));
assert!(
long > short,
"long text ({long}) should beat short ({short})"
);
}
#[test]
fn multiple_sentences_increase_score() {
let a = TaskComplexityAnalyzer::new();
let one = a.analyze("Do the task.");
let many = a.analyze("Do task A. Then task B. Also task C. Check task D. Review task E.");
assert!(
many > one,
"many sentences ({many}) should beat one ({one})"
);
}
}