mirror of
https://github.com/block/goose.git
synced 2026-04-26 10:40:45 +00:00
Some system prompt tidying (#5313)
Some checks failed
CI / changes (push) Waiting to run
CI / Check Rust Code Format (push) Blocked by required conditions
CI / Build and Test Rust Project (push) Blocked by required conditions
CI / Test and Lint Electron Desktop App (push) Blocked by required conditions
CI / bundle-desktop-unsigned (push) Blocked by required conditions
Documentation Site Preview / deploy (push) Waiting to run
Canary / Prepare Version (push) Has been cancelled
Publish Docker Image / docker (push) Has been cancelled
Canary / Upload Install Script (push) Has been cancelled
Canary / bundle-desktop (push) Has been cancelled
Canary / bundle-desktop-linux (push) Has been cancelled
Canary / bundle-desktop-windows (push) Has been cancelled
Canary / build-cli (push) Has been cancelled
Canary / Release (push) Has been cancelled
Some checks failed
CI / changes (push) Waiting to run
CI / Check Rust Code Format (push) Blocked by required conditions
CI / Build and Test Rust Project (push) Blocked by required conditions
CI / Test and Lint Electron Desktop App (push) Blocked by required conditions
CI / bundle-desktop-unsigned (push) Blocked by required conditions
Documentation Site Preview / deploy (push) Waiting to run
Canary / Prepare Version (push) Has been cancelled
Publish Docker Image / docker (push) Has been cancelled
Canary / Upload Install Script (push) Has been cancelled
Canary / bundle-desktop (push) Has been cancelled
Canary / bundle-desktop-linux (push) Has been cancelled
Canary / bundle-desktop-windows (push) Has been cancelled
Canary / build-cli (push) Has been cancelled
Canary / Release (push) Has been cancelled
This commit is contained in:
parent
774baf1cdb
commit
97743fd1b6
10 changed files with 285 additions and 184 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
crates/goose/src/agents/snapshots/*.snap linguist-language=Text
|
||||
|
|
@ -1369,6 +1369,8 @@ impl Agent {
|
|||
|
||||
let extensions_info = self.extension_manager.get_extensions_info().await;
|
||||
tracing::debug!("Retrieved {} extensions info", extensions_info.len());
|
||||
let (extension_count, tool_count) =
|
||||
self.extension_manager.get_extension_and_tool_counts().await;
|
||||
|
||||
// Get model name from provider
|
||||
let provider = self.provider().await.map_err(|e| {
|
||||
|
|
@ -1380,15 +1382,12 @@ impl Agent {
|
|||
tracing::debug!("Using model: {}", model_name);
|
||||
|
||||
let prompt_manager = self.prompt_manager.lock().await;
|
||||
let system_prompt = prompt_manager.build_system_prompt(
|
||||
extensions_info,
|
||||
self.frontend_instructions.lock().await.clone(),
|
||||
self.extension_manager
|
||||
.suggest_disable_extensions_prompt()
|
||||
.await,
|
||||
model_name,
|
||||
false,
|
||||
);
|
||||
let system_prompt = prompt_manager
|
||||
.builder(model_name)
|
||||
.with_extensions(extensions_info.into_iter())
|
||||
.with_frontend_instructions(self.frontend_instructions.lock().await.clone())
|
||||
.with_extension_and_tool_counts(extension_count, tool_count)
|
||||
.build();
|
||||
|
||||
let recipe_prompt = prompt_manager.get_recipe_prompt().await;
|
||||
let tools = self
|
||||
|
|
@ -1612,8 +1611,7 @@ mod tests {
|
|||
);
|
||||
|
||||
let prompt_manager = agent.prompt_manager.lock().await;
|
||||
let system_prompt =
|
||||
prompt_manager.build_system_prompt(vec![], None, Value::Null, "gpt-4o", false);
|
||||
let system_prompt = prompt_manager.builder("gpt-4o").build();
|
||||
|
||||
let final_output_tool_ref = agent.final_output_tool.lock().await;
|
||||
let final_output_tool_system_prompt =
|
||||
|
|
|
|||
|
|
@ -549,7 +549,7 @@ impl ExtensionManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn suggest_disable_extensions_prompt(&self) -> Value {
|
||||
pub async fn get_extension_and_tool_counts(&self) -> (usize, usize) {
|
||||
let enabled_extensions_count = self.extensions.lock().await.len();
|
||||
|
||||
let total_tools = self
|
||||
|
|
@ -558,27 +558,7 @@ impl ExtensionManager {
|
|||
.map(|tools| tools.len())
|
||||
.unwrap_or(0);
|
||||
|
||||
// Check if either condition is met
|
||||
const MIN_EXTENSIONS: usize = 5;
|
||||
const MIN_TOOLS: usize = 50;
|
||||
|
||||
if enabled_extensions_count > MIN_EXTENSIONS || total_tools > MIN_TOOLS {
|
||||
Value::String(format!(
|
||||
"The user currently has enabled {} extensions with a total of {} tools. \
|
||||
Since this exceeds the recommended limits ({} extensions or {} tools), \
|
||||
you should ask the user if they would like to disable some extensions for this session.\n\n\
|
||||
Use the search_available_extensions tool to find extensions available to disable. \
|
||||
You should only disable extensions found from the search_available_extensions tool. \
|
||||
List all the extensions available to disable in the response. \
|
||||
Explain that minimizing extensions helps with the recall of the correct tools to use.",
|
||||
enabled_extensions_count,
|
||||
total_tools,
|
||||
MIN_EXTENSIONS,
|
||||
MIN_TOOLS,
|
||||
))
|
||||
} else {
|
||||
Value::String(String::new()) // Empty string if under limits
|
||||
}
|
||||
(enabled_extensions_count, total_tools)
|
||||
}
|
||||
|
||||
pub async fn list_extensions(&self) -> ExtensionResult<Vec<String>> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#[cfg(test)]
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::agents::extension::ExtensionInfo;
|
||||
|
|
@ -9,6 +11,9 @@ use crate::agents::recipe_tools::dynamic_task_tools::should_enabled_subagents;
|
|||
use crate::agents::router_tools::llm_search_tool_prompt;
|
||||
use crate::{config::Config, prompt_template, utils::sanitize_unicode_tags};
|
||||
|
||||
const MAX_EXTENSIONS: usize = 5;
|
||||
const MAX_TOOLS: usize = 50;
|
||||
|
||||
pub struct PromptManager {
|
||||
system_prompt_override: Option<String>,
|
||||
system_prompt_extras: Vec<String>,
|
||||
|
|
@ -21,50 +26,68 @@ impl Default for PromptManager {
|
|||
}
|
||||
}
|
||||
|
||||
impl PromptManager {
|
||||
pub fn new() -> Self {
|
||||
PromptManager {
|
||||
system_prompt_override: None,
|
||||
system_prompt_extras: Vec::new(),
|
||||
// Use the fixed current date time so that prompt cache can be used.
|
||||
// Filtering to an hour to balance user time accuracy and multi session prompt cache hits.
|
||||
current_date_timestamp: Utc::now().format("%Y-%m-%d %H:00").to_string(),
|
||||
}
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
struct SystemPromptContext {
|
||||
extensions: Vec<ExtensionInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
tool_selection_strategy: Option<String>,
|
||||
current_date_time: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
extension_tool_limits: Option<(usize, usize)>,
|
||||
goose_mode: String,
|
||||
is_autonomous: bool,
|
||||
enable_subagents: bool,
|
||||
max_extensions: usize,
|
||||
max_tools: usize,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn with_timestamp(dt: DateTime<Utc>) -> Self {
|
||||
PromptManager {
|
||||
system_prompt_override: None,
|
||||
system_prompt_extras: Vec::new(),
|
||||
// Use the fixed current date time so that prompt cache can be used.
|
||||
current_date_timestamp: dt.format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||
}
|
||||
}
|
||||
pub struct SystemPromptBuilder<'a, M> {
|
||||
model_name: String,
|
||||
manager: &'a M,
|
||||
|
||||
/// Add an additional instruction to the system prompt
|
||||
pub fn add_system_prompt_extra(&mut self, instruction: String) {
|
||||
self.system_prompt_extras.push(instruction);
|
||||
}
|
||||
|
||||
/// Override the system prompt with custom text
|
||||
pub fn set_system_prompt_override(&mut self, template: String) {
|
||||
self.system_prompt_override = Some(template);
|
||||
}
|
||||
|
||||
pub fn build_system_prompt(
|
||||
&self,
|
||||
extensions_info: Vec<ExtensionInfo>,
|
||||
frontend_instructions: Option<String>,
|
||||
suggest_disable_extensions_prompt: Value,
|
||||
model_name: &str,
|
||||
extension_tool_count: Option<(usize, usize)>,
|
||||
router_enabled: bool,
|
||||
) -> String {
|
||||
let mut context: HashMap<&str, Value> = HashMap::new();
|
||||
let mut extensions_info = extensions_info.clone();
|
||||
}
|
||||
|
||||
impl<'a> SystemPromptBuilder<'a, PromptManager> {
|
||||
pub fn with_extension(mut self, extension: ExtensionInfo) -> Self {
|
||||
self.extensions_info.push(extension);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_extensions(mut self, extensions: impl Iterator<Item = ExtensionInfo>) -> Self {
|
||||
for extension in extensions {
|
||||
self.extensions_info.push(extension);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_frontend_instructions(mut self, frontend_instructions: Option<String>) -> Self {
|
||||
self.frontend_instructions = frontend_instructions;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_extension_and_tool_counts(
|
||||
mut self,
|
||||
extension_count: usize,
|
||||
tool_count: usize,
|
||||
) -> Self {
|
||||
self.extension_tool_count = Some((extension_count, tool_count));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_router_enabled(mut self, enabled: bool) -> Self {
|
||||
self.router_enabled = enabled;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> String {
|
||||
let mut extensions_info = self.extensions_info;
|
||||
|
||||
// Add frontend instructions to extensions_info to simplify json rendering
|
||||
if let Some(frontend_instructions) = frontend_instructions {
|
||||
if let Some(frontend_instructions) = self.frontend_instructions {
|
||||
extensions_info.push(ExtensionInfo::new(
|
||||
"frontend",
|
||||
&frontend_instructions,
|
||||
|
|
@ -82,38 +105,28 @@ impl PromptManager {
|
|||
})
|
||||
.collect();
|
||||
|
||||
context.insert(
|
||||
"extensions",
|
||||
serde_json::to_value(sanitized_extensions_info).unwrap(),
|
||||
);
|
||||
|
||||
if router_enabled {
|
||||
context.insert(
|
||||
"tool_selection_strategy",
|
||||
Value::String(llm_search_tool_prompt()),
|
||||
);
|
||||
}
|
||||
|
||||
context.insert(
|
||||
"current_date_time",
|
||||
Value::String(self.current_date_timestamp.clone()),
|
||||
);
|
||||
|
||||
// Add the suggestion about disabling extensions if flag is true
|
||||
context.insert(
|
||||
"suggest_disable",
|
||||
Value::String(suggest_disable_extensions_prompt.to_string()),
|
||||
);
|
||||
|
||||
let config = Config::global();
|
||||
let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string());
|
||||
context.insert("goose_mode", Value::String(goose_mode.clone()));
|
||||
context.insert(
|
||||
"enable_subagents",
|
||||
Value::Bool(should_enabled_subagents(model_name)),
|
||||
);
|
||||
let goose_mode = config
|
||||
.get_param("GOOSE_MODE")
|
||||
.unwrap_or_else(|_| Cow::from("auto"));
|
||||
|
||||
let base_prompt = if let Some(override_prompt) = &self.system_prompt_override {
|
||||
let extension_tool_limits = self
|
||||
.extension_tool_count
|
||||
.filter(|(extensions, tools)| *extensions > MAX_EXTENSIONS || *tools > MAX_TOOLS);
|
||||
|
||||
let context = SystemPromptContext {
|
||||
extensions: sanitized_extensions_info,
|
||||
tool_selection_strategy: self.router_enabled.then(llm_search_tool_prompt),
|
||||
current_date_time: self.manager.current_date_timestamp.clone(),
|
||||
extension_tool_limits,
|
||||
goose_mode: goose_mode.to_string(),
|
||||
is_autonomous: goose_mode == "auto",
|
||||
enable_subagents: should_enabled_subagents(self.model_name.as_str()),
|
||||
max_extensions: MAX_EXTENSIONS,
|
||||
max_tools: MAX_TOOLS,
|
||||
};
|
||||
|
||||
let base_prompt = if let Some(override_prompt) = &self.manager.system_prompt_override {
|
||||
let sanitized_override_prompt = sanitize_unicode_tags(override_prompt);
|
||||
prompt_template::render_inline_once(&sanitized_override_prompt, &context)
|
||||
} else {
|
||||
|
|
@ -123,7 +136,7 @@ impl PromptManager {
|
|||
"You are a general-purpose AI agent called goose, created by Block".to_string()
|
||||
});
|
||||
|
||||
let mut system_prompt_extras = self.system_prompt_extras.clone();
|
||||
let mut system_prompt_extras = self.manager.system_prompt_extras.clone();
|
||||
if goose_mode == "chat" {
|
||||
system_prompt_extras.push(
|
||||
"Right now you are in the chat only mode, no access to any tool use and system."
|
||||
|
|
@ -146,6 +159,49 @@ impl PromptManager {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PromptManager {
|
||||
pub fn new() -> Self {
|
||||
PromptManager {
|
||||
system_prompt_override: None,
|
||||
system_prompt_extras: Vec::new(),
|
||||
// Use the fixed current date time so that prompt cache can be used.
|
||||
// Filtering to an hour to balance user time accuracy and multi session prompt cache hits.
|
||||
current_date_timestamp: Utc::now().format("%Y-%m-%d %H:00").to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn with_timestamp(dt: DateTime<Utc>) -> Self {
|
||||
PromptManager {
|
||||
system_prompt_override: None,
|
||||
system_prompt_extras: Vec::new(),
|
||||
current_date_timestamp: dt.format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an additional instruction to the system prompt
|
||||
pub fn add_system_prompt_extra(&mut self, instruction: String) {
|
||||
self.system_prompt_extras.push(instruction);
|
||||
}
|
||||
|
||||
/// Override the system prompt with custom text
|
||||
pub fn set_system_prompt_override(&mut self, template: String) {
|
||||
self.system_prompt_override = Some(template);
|
||||
}
|
||||
|
||||
pub fn builder<'a>(&'a self, model_name: &str) -> SystemPromptBuilder<'a, Self> {
|
||||
SystemPromptBuilder {
|
||||
model_name: model_name.to_string(),
|
||||
manager: self,
|
||||
|
||||
extensions_info: vec![],
|
||||
frontend_instructions: None,
|
||||
extension_tool_count: None,
|
||||
router_enabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_recipe_prompt(&self) -> String {
|
||||
let context: HashMap<&str, Value> = HashMap::new();
|
||||
|
|
@ -166,13 +222,7 @@ mod tests {
|
|||
let malicious_override = "System prompt\u{E0041}\u{E0042}\u{E0043}with hidden text";
|
||||
manager.set_system_prompt_override(malicious_override.to_string());
|
||||
|
||||
let result = manager.build_system_prompt(
|
||||
vec![],
|
||||
None,
|
||||
Value::String("".to_string()),
|
||||
"gpt-4o",
|
||||
false,
|
||||
);
|
||||
let result = manager.builder("gpt-4o").build();
|
||||
|
||||
assert!(!result.contains('\u{E0041}'));
|
||||
assert!(!result.contains('\u{E0042}'));
|
||||
|
|
@ -187,13 +237,7 @@ mod tests {
|
|||
let malicious_extra = "Extra instruction\u{E0041}\u{E0042}\u{E0043}hidden";
|
||||
manager.add_system_prompt_extra(malicious_extra.to_string());
|
||||
|
||||
let result = manager.build_system_prompt(
|
||||
vec![],
|
||||
None,
|
||||
Value::String("".to_string()),
|
||||
"gpt-4o",
|
||||
false,
|
||||
);
|
||||
let result = manager.builder("gpt-4o").build();
|
||||
|
||||
assert!(!result.contains('\u{E0041}'));
|
||||
assert!(!result.contains('\u{E0042}'));
|
||||
|
|
@ -209,13 +253,7 @@ mod tests {
|
|||
manager.add_system_prompt_extra("Second\u{E0042}instruction".to_string());
|
||||
manager.add_system_prompt_extra("Third\u{E0043}instruction".to_string());
|
||||
|
||||
let result = manager.build_system_prompt(
|
||||
vec![],
|
||||
None,
|
||||
Value::String("".to_string()),
|
||||
"gpt-4o",
|
||||
false,
|
||||
);
|
||||
let result = manager.builder("gpt-4o").build();
|
||||
|
||||
assert!(!result.contains('\u{E0041}'));
|
||||
assert!(!result.contains('\u{E0042}'));
|
||||
|
|
@ -231,13 +269,7 @@ mod tests {
|
|||
let legitimate_unicode = "Instruction with 世界 and 🌍 emojis";
|
||||
manager.add_system_prompt_extra(legitimate_unicode.to_string());
|
||||
|
||||
let result = manager.build_system_prompt(
|
||||
vec![],
|
||||
None,
|
||||
Value::String("".to_string()),
|
||||
"gpt-4o",
|
||||
false,
|
||||
);
|
||||
let result = manager.builder("gpt-4o").build();
|
||||
|
||||
assert!(result.contains("世界"));
|
||||
assert!(result.contains("🌍"));
|
||||
|
|
@ -254,13 +286,10 @@ mod tests {
|
|||
false,
|
||||
);
|
||||
|
||||
let result = manager.build_system_prompt(
|
||||
vec![malicious_extension_info],
|
||||
None,
|
||||
Value::String("".to_string()),
|
||||
"gpt-4o",
|
||||
false,
|
||||
);
|
||||
let result = manager
|
||||
.builder("gpt-4o")
|
||||
.with_extension(malicious_extension_info)
|
||||
.build();
|
||||
|
||||
assert!(!result.contains('\u{E0041}'));
|
||||
assert!(!result.contains('\u{E0042}'));
|
||||
|
|
@ -273,13 +302,7 @@ mod tests {
|
|||
fn test_basic() {
|
||||
let manager = PromptManager::with_timestamp(DateTime::<Utc>::from_timestamp(0, 0).unwrap());
|
||||
|
||||
let system_prompt = manager.build_system_prompt(
|
||||
vec![],
|
||||
None,
|
||||
Value::String("".to_string()),
|
||||
"gpt-4o",
|
||||
false,
|
||||
);
|
||||
let system_prompt = manager.builder("gpt-4o").build();
|
||||
|
||||
assert_snapshot!(system_prompt)
|
||||
}
|
||||
|
|
@ -288,17 +311,38 @@ mod tests {
|
|||
fn test_one_extension() {
|
||||
let manager = PromptManager::with_timestamp(DateTime::<Utc>::from_timestamp(0, 0).unwrap());
|
||||
|
||||
let system_prompt = manager.build_system_prompt(
|
||||
vec![ExtensionInfo::new(
|
||||
let system_prompt = manager
|
||||
.builder("gpt-4o")
|
||||
.with_extension(ExtensionInfo::new(
|
||||
"test",
|
||||
"how to use this extension",
|
||||
true,
|
||||
)],
|
||||
None,
|
||||
Value::String("".to_string()),
|
||||
"gpt-4o",
|
||||
))
|
||||
.with_router_enabled(true)
|
||||
.build();
|
||||
|
||||
assert_snapshot!(system_prompt)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_typical_setup() {
|
||||
let manager = PromptManager::with_timestamp(DateTime::<Utc>::from_timestamp(0, 0).unwrap());
|
||||
|
||||
let system_prompt = manager
|
||||
.builder("gpt-4o")
|
||||
.with_extension(ExtensionInfo::new(
|
||||
"extension_A",
|
||||
"<instructions on how to use extension A>",
|
||||
true,
|
||||
);
|
||||
))
|
||||
.with_extension(ExtensionInfo::new(
|
||||
"extension_B",
|
||||
"<instructions on how to use extension B (no resources)>",
|
||||
false,
|
||||
))
|
||||
.with_router_enabled(true)
|
||||
.with_extension_and_tool_counts(MAX_EXTENSIONS + 1, MAX_TOOLS + 1)
|
||||
.build();
|
||||
|
||||
assert_snapshot!(system_prompt)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ impl Agent {
|
|||
|
||||
// Prepare system prompt
|
||||
let extensions_info = self.extension_manager.get_extensions_info().await;
|
||||
let (extension_count, tool_count) =
|
||||
self.extension_manager.get_extension_and_tool_counts().await;
|
||||
|
||||
// Get model name from provider
|
||||
let provider = self.provider().await?;
|
||||
|
|
@ -74,15 +76,13 @@ impl Agent {
|
|||
let model_name = &model_config.model_name;
|
||||
|
||||
let prompt_manager = self.prompt_manager.lock().await;
|
||||
let mut system_prompt = prompt_manager.build_system_prompt(
|
||||
extensions_info,
|
||||
self.frontend_instructions.lock().await.clone(),
|
||||
self.extension_manager
|
||||
.suggest_disable_extensions_prompt()
|
||||
.await,
|
||||
model_name,
|
||||
router_enabled,
|
||||
);
|
||||
let mut system_prompt = prompt_manager
|
||||
.builder(model_name)
|
||||
.with_extensions(extensions_info.into_iter())
|
||||
.with_frontend_instructions(self.frontend_instructions.lock().await.clone())
|
||||
.with_extension_and_tool_counts(extension_count, tool_count)
|
||||
.with_router_enabled(router_enabled)
|
||||
.build();
|
||||
|
||||
// Handle toolshim if enabled
|
||||
let mut toolshim_tools = vec![];
|
||||
|
|
|
|||
|
|
@ -25,20 +25,11 @@ extension_name. You should only enable extensions found from the search_availabl
|
|||
If Extension Manager is not available, you can only work with currently enabled extensions and cannot dynamically load
|
||||
new ones.
|
||||
|
||||
|
||||
No extensions are defined. You should let the user know that they should add extensions.
|
||||
|
||||
|
||||
|
||||
|
||||
# Suggestion
|
||||
|
||||
""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# sub agents
|
||||
|
||||
Execute self contained tasks where step-by-step visibility is not important through subagents.
|
||||
|
|
@ -51,7 +42,6 @@ Execute self contained tasks where step-by-step visibility is not important thro
|
|||
- Use extension filters to limit resource access
|
||||
- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice.
|
||||
|
||||
|
||||
# Response Guidelines
|
||||
|
||||
- Use Markdown formatting for all responses.
|
||||
|
|
|
|||
|
|
@ -25,33 +25,20 @@ extension_name. You should only enable extensions found from the search_availabl
|
|||
If Extension Manager is not available, you can only work with currently enabled extensions and cannot dynamically load
|
||||
new ones.
|
||||
|
||||
|
||||
Because you dynamically load extensions, your conversation history may refer
|
||||
to interactions with extensions that are not currently active. The currently
|
||||
active extensions are below. Each of these extensions provides tools that are
|
||||
in your tool specification.
|
||||
|
||||
|
||||
|
||||
## test
|
||||
|
||||
|
||||
test supports resources, you can use platform__read_resource,
|
||||
and platform__list_resources on this extension.
|
||||
|
||||
### Instructions
|
||||
how to use this extension
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Suggestion
|
||||
|
||||
""
|
||||
|
||||
|
||||
# LLM Tool Selection Instructions
|
||||
Important: the user has opted to dynamically enable tools, so although an extension could be enabled, \
|
||||
please invoke the llm search tool to actually retrieve the most relevant tools to use according to the user's messages.
|
||||
|
|
@ -67,7 +54,6 @@ how to use this extension
|
|||
- list_resources
|
||||
|
||||
|
||||
|
||||
# sub agents
|
||||
|
||||
Execute self contained tasks where step-by-step visibility is not important through subagents.
|
||||
|
|
@ -80,7 +66,6 @@ Execute self contained tasks where step-by-step visibility is not important thro
|
|||
- Use extension filters to limit resource access
|
||||
- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice.
|
||||
|
||||
|
||||
# Response Guidelines
|
||||
|
||||
- Use Markdown formatting for all responses.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
source: crates/goose/src/agents/prompt_manager.rs
|
||||
expression: system_prompt
|
||||
---
|
||||
You are a general-purpose AI agent called goose, created by Block, the parent company of Square, CashApp, and Tidal.
|
||||
goose is being developed as an open-source software project.
|
||||
|
||||
The current date is 1970-01-01 00:00:00.
|
||||
|
||||
goose uses LLM providers with tool calling capability. You can be used with different language models (gpt-4o,
|
||||
claude-sonnet-4, o1, llama-3.2, deepseek-r1, etc).
|
||||
These models have varying knowledge cut-off dates depending on when they were trained, but typically it's between 5-10
|
||||
months prior to the current date.
|
||||
|
||||
# Extensions
|
||||
|
||||
Extensions allow other applications to provide context to goose. Extensions connect goose to different data sources and
|
||||
tools.
|
||||
You are capable of dynamically plugging into new extensions and learning how to use them. You solve higher level
|
||||
problems using the tools in these extensions, and can interact with multiple at once.
|
||||
|
||||
If the Extension Manager extension is enabled, you can use the search_available_extensions tool to discover additional
|
||||
extensions that can help with your task. To enable or disable extensions, use the manage_extensions tool with the
|
||||
extension_name. You should only enable extensions found from the search_available_extensions tool.
|
||||
If Extension Manager is not available, you can only work with currently enabled extensions and cannot dynamically load
|
||||
new ones.
|
||||
|
||||
Because you dynamically load extensions, your conversation history may refer
|
||||
to interactions with extensions that are not currently active. The currently
|
||||
active extensions are below. Each of these extensions provides tools that are
|
||||
in your tool specification.
|
||||
|
||||
|
||||
## extension_A
|
||||
|
||||
extension_A supports resources, you can use platform__read_resource,
|
||||
and platform__list_resources on this extension.
|
||||
### Instructions
|
||||
<instructions on how to use extension A>
|
||||
## extension_B
|
||||
|
||||
### Instructions
|
||||
<instructions on how to use extension B (no resources)>
|
||||
|
||||
# Suggestion
|
||||
|
||||
The user currently has enabled 6 extensions with a total of 51 tools.
|
||||
Since this exceeds the recommended limits (5 extensions or 50 tools),
|
||||
you should ask the user if they would like to disable some extensions for this session.
|
||||
|
||||
Use the search_available_extensions tool to find extensions available to disable.
|
||||
You should only disable extensions found from the search_available_extensions tool.
|
||||
List all the extensions available to disable in the response.
|
||||
Explain that minimizing extensions helps with the recall of the correct tools to use.
|
||||
|
||||
# LLM Tool Selection Instructions
|
||||
Important: the user has opted to dynamically enable tools, so although an extension could be enabled, \
|
||||
please invoke the llm search tool to actually retrieve the most relevant tools to use according to the user's messages.
|
||||
For example, if the user has 3 extensions enabled, but they are asking for a tool to read a pdf file, \
|
||||
you would invoke the llm_search tool to find the most relevant read pdf tool.
|
||||
By dynamically enabling tools, you (goose) as the agent save context window space and allow the user to dynamically retrieve the most relevant tools.
|
||||
Be sure to format a query packed with relevant keywords to search for the most relevant tools.
|
||||
In addition to the extension names available to you, you also have platform extension tools available to you.
|
||||
The platform extension contains the following tools:
|
||||
- search_available_extensions
|
||||
- manage_extensions
|
||||
- read_resource
|
||||
- list_resources
|
||||
|
||||
|
||||
# sub agents
|
||||
|
||||
Execute self contained tasks where step-by-step visibility is not important through subagents.
|
||||
|
||||
- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests,
|
||||
verification, exploration
|
||||
- Parallel subagents for multiple operations, single subagents for independent work
|
||||
- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering)
|
||||
- Provide all needed context — subagents cannot see your context
|
||||
- Use extension filters to limit resource access
|
||||
- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice.
|
||||
|
||||
# Response Guidelines
|
||||
|
||||
- Use Markdown formatting for all responses.
|
||||
- Follow best practices for Markdown, including:
|
||||
- Using headers for organization.
|
||||
- Bullet points for lists.
|
||||
- Links formatted correctly, either as linked text (e.g., [this is linked text](https://example.com)) or automatic
|
||||
links using angle brackets (e.g., <http://example.com/>).
|
||||
- For code examples, use fenced code blocks by placing triple backticks (` ``` `) before and after the code. Include the
|
||||
language identifier after the opening backticks (e.g., ` ```python `) to enable syntax highlighting.
|
||||
- Ensure clarity, conciseness, and proper formatting to enhance readability and usability.
|
||||
|
|
@ -16,6 +16,8 @@ static CORE_PROMPTS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/src/prompts");
|
|||
/// - *Not* used for extension prompts (which are ephemeral).
|
||||
static GLOBAL_ENV: Lazy<Arc<RwLock<Environment<'static>>>> = Lazy::new(|| {
|
||||
let mut env = Environment::new();
|
||||
env.set_trim_blocks(true);
|
||||
env.set_lstrip_blocks(true);
|
||||
|
||||
// Pre-load all core templates from the embedded dir.
|
||||
for file in CORE_PROMPTS_DIR.files() {
|
||||
|
|
|
|||
|
|
@ -43,11 +43,19 @@ and platform__list_resources on this extension.
|
|||
No extensions are defined. You should let the user know that they should add extensions.
|
||||
{% endif %}
|
||||
|
||||
{% if suggest_disable is defined %}
|
||||
|
||||
{% if extension_tool_limits is defined %}
|
||||
{% with (extension_count, tool_count) = extension_tool_limits %}
|
||||
# Suggestion
|
||||
|
||||
{{suggest_disable}}
|
||||
The user currently has enabled {{extension_count}} extensions with a total of {{tool_count}} tools.
|
||||
Since this exceeds the recommended limits ({{max_extensions}} extensions or {{max_tools}} tools),
|
||||
you should ask the user if they would like to disable some extensions for this session.
|
||||
|
||||
Use the search_available_extensions tool to find extensions available to disable.
|
||||
You should only disable extensions found from the search_available_extensions tool.
|
||||
List all the extensions available to disable in the response.
|
||||
Explain that minimizing extensions helps with the recall of the correct tools to use.
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
{{tool_selection_strategy}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue