-
Notifications
You must be signed in to change notification settings - Fork 6k
Dynamically refresh skill instructions each turn #9217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,30 +27,8 @@ impl SkillsClient { | |
| .map(|s| s.working_dir.clone()) | ||
| .unwrap_or_else(|| std::env::current_dir().unwrap_or_default()); | ||
|
|
||
| let mut instructions = String::new(); | ||
| if context.session.is_some() { | ||
| let sources = discover_skills(Some(&working_dir)); | ||
| let mut skills: Vec<&SourceEntry> = sources | ||
| .iter() | ||
| .filter(|s| { | ||
| s.source_type == SourceType::Skill || s.source_type == SourceType::BuiltinSkill | ||
| }) | ||
| .collect(); | ||
| skills.sort_by(|a, b| (&a.name, &a.path).cmp(&(&b.name, &b.path))); | ||
|
|
||
| if !skills.is_empty() { | ||
| instructions.push_str( | ||
| "\n\nYou have these skills at your disposal, when it is clear they can help you solve a problem or you are asked to use them:", | ||
| ); | ||
| for skill in &skills { | ||
| instructions.push_str(&format!("\n• {} - {}", skill.name, skill.description)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| let info = InitializeResult::new(ServerCapabilities::builder().enable_tools().build()) | ||
| .with_server_info(Implementation::new(EXTENSION_NAME, "1.0.0").with_title("Skills")) | ||
| .with_instructions(instructions); | ||
| .with_server_info(Implementation::new(EXTENSION_NAME, "1.0.0").with_title("Skills")); | ||
|
|
||
| Ok(Self { info, working_dir }) | ||
| } | ||
|
|
@@ -252,6 +230,29 @@ impl McpClientTrait for SkillsClient { | |
| Some(&self.info) | ||
| } | ||
|
|
||
| fn get_instructions(&self) -> Option<String> { | ||
| let sources = discover_skills(Some(&self.working_dir)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| let mut skills: Vec<&SourceEntry> = sources | ||
| .iter() | ||
| .filter(|s| { | ||
| s.source_type == SourceType::Skill || s.source_type == SourceType::BuiltinSkill | ||
| }) | ||
| .collect(); | ||
| skills.sort_by(|a, b| (&a.name, &a.path).cmp(&(&b.name, &b.path))); | ||
|
|
||
| if skills.is_empty() { | ||
| return None; | ||
| } | ||
|
|
||
| let mut instructions = String::from( | ||
| "\n\nYou have these skills at your disposal, when it is clear they can help you solve a problem or you are asked to use them:", | ||
| ); | ||
| for skill in &skills { | ||
| instructions.push_str(&format!("\n• {} - {}", skill.name, skill.description)); | ||
| } | ||
| Some(instructions) | ||
| } | ||
|
|
||
| async fn subscribe(&self) -> mpsc::Receiver<ServerNotification> { | ||
| let (_tx, rx) = mpsc::channel(1); | ||
| rx | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delegating
Extension::get_instructions()toclient.get_instructions()now makes the skills extension rundiscover_skills()on everyget_extensions_info()call (which happens whenever the system prompt is rebuilt each turn).discover_skills()performs recursivestd::fswalking, so this introduces blocking filesystem I/O in the hot path and can noticeably increase response latency when users have many skills/supporting files. Consider caching/invalidation or moving the scan off the async worker path.Useful? React with 👍 / 👎.