Skip to content

Commit d201070

Browse files
authored
feat(prompts): implement skill-based dynamic prompt architecture (#21)
feat(prompts): implement skill-based dynamic prompt architecture This PR transforms the monolithic system prompt architecture into a modular skill-based system where the agent loads specialized skills on-demand based on task requirements. This reduces context window usage by only including relevant instructions. Changes: - Add builtin_skills.rs with six built-in skills (git, code-quality, file-operations, debugging, security, planning) - Add base_agent.rs with minimal base prompt and skill loading mechanism - Integrate skill system with prompt builder in cortex-engine - Add built-in skill support to UseSkill handler - Integrate top_agent module from PR #20 Benefits: - Reduced context usage (~500 tokens base vs ~2000+ monolithic) - Modular updates: skills can be updated independently - Clear organization: instructions organized by domain - Backward compatible: original monolithic prompt still available Testing: 200+ tests covering all new functionality
1 parent d544e8a commit d201070

File tree

9 files changed

+4824
-17
lines changed

9 files changed

+4824
-17
lines changed

src/cortex-engine/src/session/handlers.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use crate::rollout::recorder::SessionMeta;
1717
use crate::summarization::SummarizationStrategy;
1818

1919
use super::Session;
20-
use super::prompt::build_system_prompt;
20+
use super::prompt::{
21+
USE_SKILL_BASED_PROMPT, auto_detect_skills_from_message, build_system_prompt,
22+
build_system_prompt_with_skills, inject_skills,
23+
};
2124

2225
impl Session {
2326
/// Handle an incoming submission.
@@ -122,7 +125,12 @@ impl Session {
122125
// Update system prompt in existing message history
123126
if let Some(msg) = self.messages.first_mut() {
124127
if matches!(msg.role, crate::client::MessageRole::System) {
125-
*msg = Message::system(build_system_prompt(&self.config));
128+
let new_prompt = if USE_SKILL_BASED_PROMPT {
129+
build_system_prompt_with_skills(&self.config, &[])
130+
} else {
131+
build_system_prompt(&self.config)
132+
};
133+
*msg = Message::system(new_prompt);
126134
}
127135
}
128136
}
@@ -193,6 +201,29 @@ impl Session {
193201

194202
tracing::debug!("User message: {}", user_text);
195203

204+
// Auto-detect and inject skills based on the user's message (only on first message)
205+
// This reduces context window usage by only loading relevant skills.
206+
if USE_SKILL_BASED_PROMPT && self.turn_id == 1 {
207+
let detected_skills = auto_detect_skills_from_message(&user_text);
208+
if !detected_skills.is_empty() {
209+
tracing::info!("Auto-detected skills for task: {:?}", detected_skills);
210+
211+
// Update the system prompt with detected skills
212+
if let Some(msg) = self.messages.first_mut() {
213+
if matches!(msg.role, MessageRole::System) {
214+
if let Some(current_content) = msg.content.as_text() {
215+
let updated_prompt = inject_skills(current_content, &detected_skills);
216+
*msg = Message::system(updated_prompt);
217+
tracing::debug!(
218+
"Injected skills into system prompt: {:?}",
219+
detected_skills
220+
);
221+
}
222+
}
223+
}
224+
}
225+
}
226+
196227
// Track messages for potential redo functionality
197228
let _msg_start_idx = self.messages.len();
198229

src/cortex-engine/src/session/lifecycle.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::rollout::{RolloutRecorder, SESSIONS_SUBDIR, get_rollout_path, read_ro
2121
use crate::tools::ToolRouter;
2222

2323
use super::Session;
24-
use super::prompt::build_system_prompt;
24+
use super::prompt::{USE_SKILL_BASED_PROMPT, build_system_prompt, build_system_prompt_with_skills};
2525
use super::types::{SessionHandle, SessionInfo, TokenCounter};
2626

2727
impl Session {
@@ -64,8 +64,16 @@ impl Session {
6464
recorder.record_meta(&meta)?;
6565

6666
// Initialize with system prompt
67+
// Use skill-based minimal prompt by default to reduce context window usage.
68+
// Skills will be loaded on-demand based on task requirements.
6769
let mut messages = Vec::new();
68-
messages.push(Message::system(build_system_prompt(&config)));
70+
let initial_prompt = if USE_SKILL_BASED_PROMPT {
71+
// Start with the minimal base prompt - skills will be injected on first user message
72+
build_system_prompt_with_skills(&config, &[])
73+
} else {
74+
build_system_prompt(&config)
75+
};
76+
messages.push(Message::system(initial_prompt));
6977

7078
// Initialize snapshot manager
7179
let snapshot_dir = config
@@ -145,8 +153,15 @@ impl Session {
145153
let mut tool_router = ToolRouter::new();
146154

147155
// Rebuild messages from events
156+
// For resumed sessions, we still use the base prompt since skills might have been
157+
// loaded during the previous session and we want consistency.
148158
let mut messages = Vec::new();
149-
messages.push(Message::system(build_system_prompt(&config)));
159+
let initial_prompt = if USE_SKILL_BASED_PROMPT {
160+
build_system_prompt_with_skills(&config, &[])
161+
} else {
162+
build_system_prompt(&config)
163+
};
164+
messages.push(Message::system(initial_prompt));
150165

151166
let events = get_events(&entries);
152167
for event_msg in events {
@@ -257,7 +272,12 @@ impl Session {
257272
let entries = read_rollout(&rollout_path)?;
258273

259274
let mut messages = Vec::new();
260-
messages.push(Message::system(build_system_prompt(&config)));
275+
let initial_prompt = if USE_SKILL_BASED_PROMPT {
276+
build_system_prompt_with_skills(&config, &[])
277+
} else {
278+
build_system_prompt(&config)
279+
};
280+
messages.push(Message::system(initial_prompt));
261281

262282
let events = get_events(&entries);
263283

src/cortex-engine/src/session/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ use crate::rollout::RolloutRecorder;
2222
use crate::tools::ToolRouter;
2323

2424
pub use lifecycle::list_sessions;
25-
pub use prompt::build_system_prompt;
25+
pub use prompt::{
26+
USE_SKILL_BASED_PROMPT, auto_detect_skills_from_message, available_skills, build_system_prompt,
27+
build_system_prompt_with_skills, inject_skills, is_valid_skill,
28+
};
2629
pub use types::{SessionHandle, SessionInfo, TokenCounter};
2730

2831
/// A running session that handles conversation with the model.

0 commit comments

Comments
 (0)