fix(goose): exclude preprompt from session title generation (#8793)
Some checks are pending
Canary / Prepare Version (push) Waiting to run
Canary / build-cli (push) Blocked by required conditions
Canary / Upload Install Script (push) Blocked by required conditions
Canary / bundle-desktop (push) Blocked by required conditions
Canary / bundle-desktop-intel (push) Blocked by required conditions
Canary / bundle-desktop-linux (push) Blocked by required conditions
Canary / bundle-desktop-windows (push) Blocked by required conditions
Canary / Release (push) Blocked by required conditions
Cargo Deny / deny (push) Waiting to run
Unused Dependencies / machete (push) Waiting to run
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 / Build Rust Project on Windows (push) Waiting to run
CI / Check MSRV (push) Blocked by required conditions
CI / Lint Rust Code (push) Blocked by required conditions
CI / Check Generated Schemas are Up-to-Date (push) Blocked by required conditions
CI / Test and Lint Electron Desktop App (push) Blocked by required conditions
Live Provider Tests / check-fork (push) Waiting to run
Live Provider Tests / changes (push) Blocked by required conditions
Live Provider Tests / Build Binary (push) Blocked by required conditions
Live Provider Tests / Smoke Tests (push) Blocked by required conditions
Live Provider Tests / Smoke Tests (Code Execution) (push) Blocked by required conditions
Live Provider Tests / Compaction Tests (push) Blocked by required conditions
Live Provider Tests / goose server HTTP integration tests (push) Blocked by required conditions
Publish Docker Image / docker (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Toohey 2026-04-28 06:21:26 +12:00 committed by GitHub
parent 739f4e88b8
commit 002440b48a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 48 additions and 4 deletions

View file

@ -731,16 +731,44 @@ pub trait Provider: Send + Sync {
))
}
/// Returns the first 3 user messages as strings for session naming
/// Returns the first 3 user messages as strings for session naming,
/// filtering out assistant-only content (e.g. preprompt blocks).
fn get_initial_user_messages(&self, messages: &Conversation) -> Vec<String> {
messages
.iter()
.filter(|m| m.role == rmcp::model::Role::User)
.take(MSG_COUNT_FOR_SESSION_NAME_GENERATION)
.map(|m| m.as_concat_text())
.map(|m| {
m.content
.iter()
.filter_map(|c| c.filter_for_audience(rmcp::model::Role::User))
.filter_map(|c| c.as_text().map(|s| s.to_string()))
.collect::<Vec<_>>()
.join("\n")
})
.collect()
}
/// Extracts preprompt context (assistant-audience blocks) from the first user message.
/// These are content blocks visible to the assistant but not the user.
fn get_preprompt_context(&self, messages: &Conversation) -> String {
messages
.iter()
.filter(|m| m.role == rmcp::model::Role::User)
.take(1)
.flat_map(|m| m.content.iter())
.filter_map(|c| {
// If this block is NOT visible to the user, it's preprompt/assistant-only content
if c.filter_for_audience(rmcp::model::Role::User).is_none() {
c.as_text().map(|s| s.to_string())
} else {
None
}
})
.collect::<Vec<_>>()
.join("\n")
}
/// Generate a session name/description based on the conversation history
/// Creates a prompt asking for a concise description in 4 words or less.
async fn generate_session_name(
@ -749,6 +777,7 @@ pub trait Provider: Send + Sync {
messages: &Conversation,
) -> Result<String, ProviderError> {
let context = self.get_initial_user_messages(messages);
let preprompt_context = self.get_preprompt_context(messages);
let system = crate::prompt_template::render_template(
"session_name.md",
&std::collections::HashMap::<String, String>::new(),
@ -758,8 +787,19 @@ pub trait Provider: Send + Sync {
use super::cli_common::{
SESSION_NAME_BEGIN_MARKER, SESSION_NAME_END_MARKER, SESSION_NAME_SUFFIX,
};
let preprompt_section = if preprompt_context.is_empty() {
String::new()
} else {
format!(
"---BEGIN BACKGROUND CONTEXT (for understanding only, do NOT base the title on this)---\n{}\n---END BACKGROUND CONTEXT---\n\n",
preprompt_context
)
};
let user_text = format!(
"{}\n{}\n{}\n\n{}",
"{}{}\n{}\n{}\n\n{}",
preprompt_section,
SESSION_NAME_BEGIN_MARKER,
context.join("\n"),
SESSION_NAME_END_MARKER,

View file

@ -56,7 +56,11 @@ pub(crate) fn generate_simple_session_description(
})
.map(|text| {
// Strip the wrapper added by generate_session_name so we get
// the actual user content.
// the actual user content. First strip the optional background context section.
let text = text
.rfind(SESSION_NAME_BEGIN_MARKER)
.and_then(|idx| text.get(idx..))
.unwrap_or(text);
let stripped = text
.strip_prefix(SESSION_NAME_BEGIN_MARKER)
.unwrap_or(text)