mecha10_nodes_llm_command/
config.rs

1//! Configuration for LLM Command Node
2
3use mecha10_core::behavior_interrupt::BehaviorInterruptConfig;
4use serde::{Deserialize, Serialize};
5
6/// LLM Command Node Configuration
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct OpenAIReasoningConfig {
9    /// LLM provider (openai, claude, local)
10    #[serde(default = "default_provider")]
11    pub provider: String,
12
13    /// LLM model identifier (e.g., "gpt-4o-mini", "claude-3-5-sonnet-20241022")
14    #[serde(default = "default_model")]
15    pub llm_model: String,
16
17    /// System prompt for the LLM
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub system_prompt: Option<String>,
20
21    /// Temperature for sampling (0.0 - 1.0)
22    #[serde(default = "default_temperature")]
23    pub temperature: f32,
24
25    /// Maximum tokens to generate
26    #[serde(default = "default_max_tokens")]
27    pub max_tokens: u32,
28
29    /// Whether vision queries are enabled
30    #[serde(default)]
31    pub vision_enabled: bool,
32
33    /// Topic configuration
34    #[serde(default)]
35    pub topics: TopicConfig,
36
37    /// Behavior interrupt configuration
38    #[serde(default)]
39    pub behavior_interrupt: BehaviorInterruptConfig,
40}
41
42impl Default for OpenAIReasoningConfig {
43    fn default() -> Self {
44        Self {
45            provider: default_provider(),
46            llm_model: default_model(),
47            system_prompt: Some(default_system_prompt()),
48            temperature: default_temperature(),
49            max_tokens: default_max_tokens(),
50            vision_enabled: true, // Enable vision queries by default
51            topics: TopicConfig::default(),
52            behavior_interrupt: BehaviorInterruptConfig::default(),
53        }
54    }
55}
56
57/// Topic paths for the reasoning node
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct TopicConfig {
60    /// Input topic for natural language commands
61    #[serde(default = "default_command_topic")]
62    pub command_in: String,
63
64    /// Output topic for LLM responses
65    #[serde(default = "default_response_topic")]
66    pub response_out: String,
67
68    /// Input topic for camera images (for vision queries)
69    #[serde(default = "default_camera_topic")]
70    pub camera_in: String,
71
72    /// Input topic for object detections (for vision queries)
73    #[serde(default = "default_detections_topic")]
74    pub detections_in: String,
75
76    /// Output topic for navigation goals
77    #[serde(default = "default_nav_goal_topic")]
78    pub nav_goal_out: String,
79
80    /// Output topic for motor commands
81    #[serde(default = "default_motor_cmd_topic")]
82    pub motor_cmd_out: String,
83
84    /// Output topic for behavior execution
85    #[serde(default = "default_behavior_topic")]
86    pub behavior_out: String,
87}
88
89impl Default for TopicConfig {
90    fn default() -> Self {
91        Self {
92            command_in: default_command_topic(),
93            response_out: default_response_topic(),
94            camera_in: default_camera_topic(),
95            detections_in: default_detections_topic(),
96            nav_goal_out: default_nav_goal_topic(),
97            motor_cmd_out: default_motor_cmd_topic(),
98            behavior_out: default_behavior_topic(),
99        }
100    }
101}
102
103// === Default Functions ===
104
105fn default_provider() -> String {
106    "openai".to_string()
107}
108
109fn default_model() -> String {
110    "gpt-4o-mini".to_string()
111}
112
113fn default_system_prompt() -> String {
114    r#"You are a helpful robot assistant. Parse user commands and respond with structured actions.
115
116For navigation commands (e.g., "go to the door", "move to coordinates"), extract the goal and respond with JSON:
117{"action": "navigate", "goal": {"x": 5.0, "y": 3.0, "theta": 0.0}}
118
119For motor commands (e.g., "move forward", "turn left", "stop"), respond with JSON:
120{"action": "motor", "linear": 0.5, "angular": 0.0}
121
122For motor commands with duration (e.g., "drive forward for 2 seconds", "turn left for 1 second"), include duration_secs:
123{"action": "motor", "linear": 0.5, "angular": 0.0, "duration_secs": 2.0}
124
125For behavior commands (e.g., "follow that person", "patrol the area"), respond with JSON:
126{"action": "behavior", "name": "follow_person"}
127
128For vision queries (e.g., "what do you see?", "is there a person?", "how many cars?"):
129- You will receive current object detections from the robot's vision system
130- Analyze the detections and provide a natural language response
131- If no detections are available, mention that the vision system is not active
132- Be specific about what objects are detected and their confidence levels
133
134For general questions, respond conversationally."#
135        .to_string()
136}
137
138fn default_temperature() -> f32 {
139    0.7
140}
141
142fn default_max_tokens() -> u32 {
143    500
144}
145
146fn default_command_topic() -> String {
147    "/ai/command".to_string()
148}
149
150fn default_response_topic() -> String {
151    "/ai/response".to_string()
152}
153
154fn default_camera_topic() -> String {
155    "/robot/sensors/camera/rgb".to_string()
156}
157
158fn default_detections_topic() -> String {
159    "/vision/object/detections".to_string()
160}
161
162fn default_nav_goal_topic() -> String {
163    "/nav/goal".to_string()
164}
165
166fn default_motor_cmd_topic() -> String {
167    "/motor/cmd_vel".to_string()
168}
169
170fn default_behavior_topic() -> String {
171    "/behavior/execute".to_string()
172}