llm_toolkit/
context.rs

1//! Context types for agent behavior and expertise activation.
2//!
3//! This module defines core types for controlling agent behavior based on
4//! task context, health status, and priority levels.
5
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9/// Priority: Instruction strength/enforcement level
10///
11/// Controls how strongly a knowledge fragment should be enforced during
12/// prompt generation. Higher priority fragments appear first and are
13/// treated as more critical constraints.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
15#[serde(rename_all = "snake_case")]
16pub enum Priority {
17    /// Critical: Absolute must-follow (violation = error / strong negative constraint)
18    Critical,
19    /// High: Recommended/emphasized (explicit instruction)
20    High,
21    /// Normal: Standard context (general guidance)
22    #[default]
23    Normal,
24    /// Low: Reference information (background info)
25    Low,
26}
27
28// Custom ordering: Critical > High > Normal > Low
29impl PartialOrd for Priority {
30    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
31        Some(self.cmp(other))
32    }
33}
34
35impl Ord for Priority {
36    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
37        self.weight().cmp(&other.weight())
38    }
39}
40
41impl Priority {
42    /// Returns a numeric value for ordering (higher = more important)
43    pub fn weight(&self) -> u8 {
44        match self {
45            Priority::Critical => 4,
46            Priority::High => 3,
47            Priority::Normal => 2,
48            Priority::Low => 1,
49        }
50    }
51
52    /// Returns a display label for visualization
53    pub fn label(&self) -> &'static str {
54        match self {
55            Priority::Critical => "CRITICAL",
56            Priority::High => "HIGH",
57            Priority::Normal => "NORMAL",
58            Priority::Low => "LOW",
59        }
60    }
61}
62
63/// TaskHealth: Task health/quality status indicator
64///
65/// Represents the current state of a task for triggering adaptive behavior.
66/// Enables "gear shifting" based on progress and quality.
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
68#[serde(rename_all = "snake_case")]
69pub enum TaskHealth {
70    /// On track: Proceed confidently (Action: Go/SpeedUp)
71    OnTrack,
72
73    /// At risk: Proceed cautiously with verification (Action: Review/Clarify)
74    AtRisk,
75
76    /// Off track: Stop and reassess (Action: Stop/Reject)
77    OffTrack,
78}
79
80impl TaskHealth {
81    /// Returns a display label for visualization
82    pub fn label(&self) -> &'static str {
83        match self {
84            TaskHealth::OnTrack => "On Track",
85            TaskHealth::AtRisk => "At Risk",
86            TaskHealth::OffTrack => "Off Track",
87        }
88    }
89
90    /// Returns an emoji representation
91    pub fn emoji(&self) -> &'static str {
92        match self {
93            TaskHealth::OnTrack => "✅",
94            TaskHealth::AtRisk => "⚠️",
95            TaskHealth::OffTrack => "🚫",
96        }
97    }
98}
99
100/// ContextProfile: Activation conditions for knowledge fragments
101///
102/// Defines when a fragment should be included in the generated prompt
103/// based on various contextual factors.
104#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
105#[serde(tag = "type", rename_all = "snake_case")]
106pub enum ContextProfile {
107    /// Always active (no conditions)
108    #[default]
109    Always,
110
111    /// Conditionally active based on context matching
112    Conditional {
113        /// Task types (e.g., "Debug", "Ideation", "Review")
114        #[serde(default, skip_serializing_if = "Vec::is_empty")]
115        task_types: Vec<String>,
116
117        /// User states (e.g., "Beginner", "Confused", "Expert")
118        #[serde(default, skip_serializing_if = "Vec::is_empty")]
119        user_states: Vec<String>,
120
121        /// Task health status for behavior adjustment
122        #[serde(default, skip_serializing_if = "Option::is_none")]
123        task_health: Option<TaskHealth>,
124    },
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn test_priority_ordering() {
133        assert!(Priority::Critical > Priority::High);
134        assert!(Priority::High > Priority::Normal);
135        assert!(Priority::Normal > Priority::Low);
136    }
137
138    #[test]
139    fn test_priority_weight() {
140        assert_eq!(Priority::Critical.weight(), 4);
141        assert_eq!(Priority::High.weight(), 3);
142        assert_eq!(Priority::Normal.weight(), 2);
143        assert_eq!(Priority::Low.weight(), 1);
144    }
145}