fix: move goosehints/AGENTS.md handling to goose, and out of developer extension (#5575)

This commit is contained in:
Alex Hancock
2025-11-06 17:04:46 -05:00
committed by GitHub
parent e0f0898781
commit c62c61cc07
12 changed files with 76 additions and 261 deletions
+10 -3
View File
@@ -245,6 +245,7 @@ impl Agent {
async fn prepare_reply_context(
&self,
unfixed_conversation: Conversation,
working_dir: &std::path::Path,
) -> Result<ReplyContext> {
let unfixed_messages = unfixed_conversation.messages().clone();
let (conversation, issues) = fix_conversation(unfixed_conversation.clone());
@@ -261,7 +262,8 @@ impl Agent {
let initial_messages = conversation.messages().clone();
let config = Config::global();
let (tools, toolshim_tools, system_prompt) = self.prepare_tools_and_prompt().await?;
let (tools, toolshim_tools, system_prompt) =
self.prepare_tools_and_prompt(working_dir).await?;
let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto);
self.tool_inspection_manager
@@ -830,7 +832,9 @@ impl Agent {
session: Session,
cancel_token: Option<CancellationToken>,
) -> Result<BoxStream<'_, Result<AgentEvent>>> {
let context = self.prepare_reply_context(conversation).await?;
let context = self
.prepare_reply_context(conversation, &session.working_dir)
.await?;
let ReplyContext {
mut conversation,
mut tools,
@@ -844,6 +848,7 @@ impl Agent {
let provider = self.provider().await?;
let session_id = session_config.id.clone();
let working_dir = session.working_dir.clone();
tokio::spawn(async move {
if let Err(e) = SessionManager::maybe_update_name(&session_id, provider).await {
warn!("Failed to generate session description: {}", e);
@@ -1137,7 +1142,8 @@ impl Agent {
}
}
if tools_updated {
(tools, toolshim_tools, system_prompt) = self.prepare_tools_and_prompt().await?;
(tools, toolshim_tools, system_prompt) =
self.prepare_tools_and_prompt(&working_dir).await?;
}
let mut exit_chat = false;
if no_tools_called {
@@ -1307,6 +1313,7 @@ impl Agent {
.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_hints(&std::env::current_dir()?)
.build();
let recipe_prompt = prompt_manager.get_recipe_prompt().await;
+37
View File
@@ -8,11 +8,13 @@ use std::collections::HashMap;
use crate::agents::extension::ExtensionInfo;
use crate::agents::recipe_tools::dynamic_task_tools::should_enabled_subagents;
use crate::agents::router_tools::llm_search_tool_prompt;
use crate::hints::load_hints::{load_hint_files, AGENTS_MD_FILENAME, GOOSE_HINTS_FILENAME};
use crate::{
config::{Config, GooseMode},
prompt_template,
utils::sanitize_unicode_tags,
};
use std::path::Path;
const MAX_EXTENSIONS: usize = 5;
const MAX_TOOLS: usize = 50;
@@ -52,6 +54,7 @@ pub struct SystemPromptBuilder<'a, M> {
frontend_instructions: Option<String>,
extension_tool_count: Option<(usize, usize)>,
router_enabled: bool,
hints: Option<String>,
}
impl<'a> SystemPromptBuilder<'a, PromptManager> {
@@ -86,6 +89,33 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> {
self
}
pub fn with_hints(mut self, working_dir: &Path) -> Self {
let config = Config::global();
let hints_filenames = config
.get_param::<Vec<String>>("CONTEXT_FILE_NAMES")
.unwrap_or_else(|_| {
vec![
GOOSE_HINTS_FILENAME.to_string(),
AGENTS_MD_FILENAME.to_string(),
]
});
let ignore_patterns = {
let builder = ignore::gitignore::GitignoreBuilder::new(working_dir);
builder.build().unwrap_or_else(|_| {
ignore::gitignore::GitignoreBuilder::new(working_dir)
.build()
.expect("Failed to build default gitignore")
})
};
let hints = load_hint_files(working_dir, &hints_filenames, &ignore_patterns);
if !hints.is_empty() {
self.hints = Some(hints);
}
self
}
pub fn build(self) -> String {
let mut extensions_info = self.extensions_info;
@@ -138,6 +168,12 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> {
});
let mut system_prompt_extras = self.manager.system_prompt_extras.clone();
// Add hints if provided
if let Some(hints) = self.hints {
system_prompt_extras.push(hints);
}
if goose_mode == GooseMode::Chat {
system_prompt_extras.push(
"Right now you are in the chat only mode, no access to any tool use and system."
@@ -201,6 +237,7 @@ impl PromptManager {
frontend_instructions: None,
extension_tool_count: None,
router_enabled: false,
hints: None,
}
}
+8 -2
View File
@@ -107,7 +107,10 @@ async fn toolshim_postprocess(
}
impl Agent {
pub async fn prepare_tools_and_prompt(&self) -> Result<(Vec<Tool>, Vec<Tool>, String)> {
pub async fn prepare_tools_and_prompt(
&self,
working_dir: &std::path::Path,
) -> Result<(Vec<Tool>, Vec<Tool>, String)> {
// Get router enabled status
let router_enabled = self.tool_route_manager.is_router_enabled().await;
@@ -156,6 +159,7 @@ impl Agent {
.with_frontend_instructions(self.frontend_instructions.lock().await.clone())
.with_extension_and_tool_counts(extension_count, tool_count)
.with_router_enabled(router_enabled)
.with_hints(working_dir)
.build();
// Handle toolshim if enabled
@@ -468,7 +472,9 @@ mod tests {
.await
.unwrap();
let (tools, _toolshim_tools, _system_prompt) = agent.prepare_tools_and_prompt().await?;
let working_dir = std::env::current_dir()?;
let (tools, _toolshim_tools, _system_prompt) =
agent.prepare_tools_and_prompt(&working_dir).await?;
// Ensure both platform and frontend tools are present
let names: Vec<String> = tools.iter().map(|t| t.name.clone().into_owned()).collect();