Skip to main content

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