Skip to main content

netget/llm/
default_instructions.rs

1//! Default instruction registry for all protocols
2//!
3//! This module provides default instructions for each protocol's events.
4//! These are simple, general instructions that can be overridden.
5
6use crate::llm::event_instructions::EventInstructions;
7use once_cell::sync::Lazy;
8use std::collections::HashMap;
9
10/// Global registry of default instructions
11pub static DEFAULT_INSTRUCTIONS: Lazy<DefaultInstructionsRegistry> =
12    Lazy::new(DefaultInstructionsRegistry::new);
13
14/// Registry containing default instructions for all event types
15pub struct DefaultInstructionsRegistry {
16    instructions: HashMap<String, EventInstructions>,
17}
18
19impl Default for DefaultInstructionsRegistry {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl DefaultInstructionsRegistry {
26    /// Create and populate the default registry
27    pub fn new() -> Self {
28        let mut instructions = HashMap::new();
29
30        // HTTP defaults
31        instructions.insert(
32            "http_request".to_string(),
33            EventInstructions::new(
34                "Parse the HTTP request and return an appropriate response based on the server's instruction.",
35            )
36            .with_example(
37                "GET / HTTP/1.1",
38                r#"{"type": "send_http_response", "status": 200, "body": "Hello World"}"#,
39            )
40            .with_example(
41                "POST /api/data",
42                r#"{"type": "send_http_response", "status": 200, "headers": {"Content-Type": "application/json"}, "body": "{\"status\": \"success\"}"}"#,
43            ),
44        );
45
46        // SSH defaults
47        instructions.insert(
48            "ssh_auth".to_string(),
49            EventInstructions::new(
50                "Handle SSH authentication. Accept or reject based on the server's instruction.",
51            )
52            .with_example(
53                r#"{"username": "admin", "auth_type": "password"}"#,
54                r#"{"type": "ssh_auth_decision", "accept": true}"#,
55            ),
56        );
57
58        instructions.insert(
59            "ssh_command".to_string(),
60            EventInstructions::new(
61                "Execute or simulate the SSH command based on the server's instruction.",
62            )
63            .with_example(
64                "ls -la",
65                r#"{"type": "ssh_send_output", "output": "total 24\ndrwxr-xr-x  3 user user 4096 Jan 1 00:00 .\n"}"#,
66            ),
67        );
68
69        // TCP defaults
70        instructions.insert(
71            "tcp_data_received".to_string(),
72            EventInstructions::new(
73                "Process the incoming TCP data and respond according to the server's instruction.",
74            )
75            .with_example(
76                "HELLO",
77                r#"{"type": "send_tcp_data", "data": "HELLO BACK"}"#,
78            ),
79        );
80
81        // DNS defaults
82        instructions.insert(
83            "dns_query".to_string(),
84            EventInstructions::new(
85                "Resolve the DNS query based on the server's instruction.",
86            )
87            .with_example(
88                r#"{"query": "example.com", "query_type": "A"}"#,
89                r#"{"type": "dns_response", "answers": [{"name": "example.com", "type": "A", "data": "93.184.216.34"}]}"#,
90            ),
91        );
92
93        // WebSocket defaults
94        instructions.insert(
95            "websocket_message".to_string(),
96            EventInstructions::new("Handle the WebSocket message and respond as configured.")
97                .with_example(
98                    r#"{"type": "text", "data": "ping"}"#,
99                    r#"{"type": "send_websocket_message", "message": "pong"}"#,
100                ),
101        );
102
103        // MQTT defaults
104        instructions.insert(
105            "mqtt_publish".to_string(),
106            EventInstructions::new(
107                "Handle MQTT publish message according to the server's configuration.",
108            )
109            .with_example(
110                r#"{"topic": "sensors/temp", "payload": "22.5"}"#,
111                r#"{"type": "mqtt_publish", "topic": "sensors/temp/ack", "payload": "received"}"#,
112            ),
113        );
114
115        // Redis defaults
116        instructions.insert(
117            "redis_command".to_string(),
118            EventInstructions::new("Execute the Redis command and return appropriate response.")
119                .with_example(
120                    "GET key1",
121                    r#"{"type": "redis_response", "response": "value1"}"#,
122                )
123                .with_example(
124                    "SET key2 value2",
125                    r#"{"type": "redis_response", "response": "OK"}"#,
126                ),
127        );
128
129        // MySQL defaults
130        instructions.insert(
131            "mysql_query".to_string(),
132            EventInstructions::new(
133                "Execute or simulate the MySQL query based on server configuration.",
134            )
135            .with_example(
136                "SELECT * FROM users",
137                r#"{"type": "mysql_result", "rows": [{"id": 1, "name": "Alice"}]}"#,
138            ),
139        );
140
141        // S3 defaults
142        instructions.insert(
143            "s3_request".to_string(),
144            EventInstructions::new(
145                "Handle S3 API request according to the server's configuration.",
146            )
147            .with_example(
148                r#"{"method": "GET", "bucket": "mybucket", "key": "file.txt"}"#,
149                r#"{"type": "s3_response", "status": 200, "body": "file contents"}"#,
150            ),
151        );
152
153        Self { instructions }
154    }
155
156    /// Get default instructions for an event type
157    pub fn get(&self, event_type: &str) -> Option<&EventInstructions> {
158        self.instructions.get(event_type)
159    }
160
161    /// Get all registered event types
162    pub fn event_types(&self) -> Vec<&str> {
163        self.instructions.keys().map(|s| s.as_str()).collect()
164    }
165
166    /// Add or update default instructions (useful for testing)
167    pub fn register(&mut self, event_type: String, instructions: EventInstructions) {
168        self.instructions.insert(event_type, instructions);
169    }
170}
171
172/// Resolve instructions for an event using the priority chain
173///
174/// Priority order:
175/// 1. Script (if configured)
176/// 2. Event-specific override
177/// 3. Default instructions
178/// 4. Global instructions only
179pub fn resolve_instructions(
180    event_type: &str,
181    config: &crate::llm::event_instructions::ServerInstructionConfig,
182) -> crate::llm::event_instructions::InstructionSource {
183    use crate::llm::event_instructions::InstructionSource;
184
185    // Check for script first (highest priority)
186    if config.has_script_for_event(event_type) {
187        return InstructionSource::Script(format!("Script configured for {}", event_type));
188    }
189
190    // Check for event override
191    if let Some(override_instructions) = config.get_instructions_for_event(event_type) {
192        return InstructionSource::EventOverride(override_instructions.clone());
193    }
194
195    // Check for defaults
196    if let Some(default_instructions) = DEFAULT_INSTRUCTIONS.get(event_type) {
197        return InstructionSource::Default(default_instructions.clone());
198    }
199
200    // Fall back to global instructions
201    if let Some(global) = &config.global_instructions {
202        return InstructionSource::GlobalOnly(global.clone());
203    }
204
205    InstructionSource::None
206}