mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
Dynamically refresh skill instructions each turn (#9217)
Signed-off-by: Douwe Osinga <douwe@squareup.com> Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
@@ -56,7 +56,7 @@ impl McpClientTrait for MockClient {
|
||||
}
|
||||
|
||||
fn get_info(&self) -> std::option::Option<&rmcp::model::InitializeResult> {
|
||||
todo!()
|
||||
None
|
||||
}
|
||||
|
||||
async fn read_resource(
|
||||
|
||||
@@ -106,9 +106,7 @@ impl Extension {
|
||||
}
|
||||
|
||||
fn get_instructions(&self) -> Option<String> {
|
||||
self.server_info
|
||||
.as_ref()
|
||||
.and_then(|info| info.instructions.clone())
|
||||
self.client.get_instructions()
|
||||
}
|
||||
|
||||
fn get_client(&self) -> McpClientBox {
|
||||
|
||||
@@ -84,6 +84,13 @@ pub trait McpClientTrait: Send + Sync {
|
||||
|
||||
fn get_info(&self) -> Option<&InitializeResult>;
|
||||
|
||||
/// Return the extension's current instructions. The default reads from
|
||||
/// `get_info()`, but platform extensions can override this to provide
|
||||
/// dynamically computed instructions (e.g. freshly discovered skills).
|
||||
fn get_instructions(&self) -> Option<String> {
|
||||
self.get_info().and_then(|info| info.instructions.clone())
|
||||
}
|
||||
|
||||
async fn list_resources(
|
||||
&self,
|
||||
_session_id: &str,
|
||||
|
||||
@@ -441,11 +441,9 @@ mod tests {
|
||||
.values()
|
||||
.map(|def| {
|
||||
let client = (def.client_factory)(context.clone());
|
||||
let info = client.get_info();
|
||||
let instructions = info
|
||||
.and_then(|i| i.instructions.clone())
|
||||
.unwrap_or_default();
|
||||
let has_resources = info
|
||||
let instructions = client.get_instructions().unwrap_or_default();
|
||||
let has_resources = client
|
||||
.get_info()
|
||||
.and_then(|i| i.capabilities.resources.as_ref())
|
||||
.is_some();
|
||||
ExtensionInfo::new(def.name, &instructions, has_resources)
|
||||
|
||||
@@ -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));
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user