diff --git a/crates/goose/src/providers/base.rs b/crates/goose/src/providers/base.rs index ccaf7263ab..12b3a3c510 100644 --- a/crates/goose/src/providers/base.rs +++ b/crates/goose/src/providers/base.rs @@ -715,9 +715,15 @@ pub trait Provider: Send + Sync { ) .map_err(|e| ProviderError::ContextLengthExceeded(e.to_string()))?; + use super::cli_common::{ + SESSION_NAME_BEGIN_MARKER, SESSION_NAME_END_MARKER, SESSION_NAME_SUFFIX, + }; let user_text = format!( - "---BEGIN USER MESSAGES---\n{}\n---END USER MESSAGES---\n\nGenerate a short title for the above messages.", - context.join("\n") + "{}\n{}\n{}\n\n{}", + SESSION_NAME_BEGIN_MARKER, + context.join("\n"), + SESSION_NAME_END_MARKER, + SESSION_NAME_SUFFIX, ); let message = Message::user().with_text(&user_text); let result = self diff --git a/crates/goose/src/providers/cli_common.rs b/crates/goose/src/providers/cli_common.rs index f9368b8b72..8118aa06cf 100644 --- a/crates/goose/src/providers/cli_common.rs +++ b/crates/goose/src/providers/cli_common.rs @@ -3,6 +3,7 @@ use serde_json::Value; use super::base::{ProviderUsage, Usage}; use super::errors::ProviderError; use crate::conversation::message::{Message, MessageContent}; +use crate::utils::safe_truncate; use rmcp::model::Role; pub(crate) fn extract_usage_tokens(usage_info: &Value) -> Usage { @@ -32,6 +33,10 @@ pub(crate) fn error_from_event(provider_name: &str, parsed: &Value) -> ProviderE } } +pub(crate) const SESSION_NAME_BEGIN_MARKER: &str = "---BEGIN USER MESSAGES---"; +pub(crate) const SESSION_NAME_END_MARKER: &str = "---END USER MESSAGES---"; +pub(crate) const SESSION_NAME_SUFFIX: &str = "Generate a short title for the above messages."; + pub(crate) fn is_session_description_request(system: &str) -> bool { system.contains("four words or less") || system.contains("4 words or less") } @@ -50,10 +55,29 @@ pub(crate) fn generate_simple_session_description( }) }) .map(|text| { - text.split_whitespace() + // Strip the wrapper added by generate_session_name so we get + // the actual user content. + let stripped = text + .strip_prefix(SESSION_NAME_BEGIN_MARKER) + .unwrap_or(text) + .trim_start_matches(['\n', '\r']); + let full_suffix = format!("{}\n\n{}", SESSION_NAME_END_MARKER, SESSION_NAME_SUFFIX); + let stripped = stripped + .strip_suffix(&full_suffix) + .or_else(|| stripped.strip_suffix(SESSION_NAME_END_MARKER)) + .unwrap_or(stripped) + .trim(); + + let desc: String = stripped + .split_whitespace() .take(4) .collect::>() - .join(" ") + .join(" "); + if desc.is_empty() { + "Simple task".to_string() + } else { + safe_truncate(&desc, 100) + } }) .unwrap_or_else(|| "Simple task".to_string());