Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions frontend/src-tauri/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ const SESSION_TITLE_GENERATION_TIMEOUT: std::time::Duration =
std::time::Duration::from_millis(1_500);
const SESSION_TITLE_MODEL: &str = "llama3-3-70b";
const SESSION_TITLE_TEMPERATURE: f32 = 0.7;
const SESSION_TITLE_MAX_TOKENS: i32 = 15;
const SESSION_TITLE_MAX_INPUT_CHARS: usize = 500;
const SESSION_TITLE_SYSTEM_PROMPT: &str = "You are a helpful assistant that generates concise, meaningful titles (3-5 words) for chat conversations based on the user's first message. Return only the title without quotes or explanations.";
const DEFAULT_AGENT_SESSION_TITLE: &str = "New task";
Expand Down Expand Up @@ -1785,7 +1784,7 @@ async fn generate_agent_session_title(
model_config.reasoning = Some(false);
let model_config = model_config
.with_temperature(Some(SESSION_TITLE_TEMPERATURE))
.with_max_tokens(Some(SESSION_TITLE_MAX_TOKENS));
.with_max_tokens(None);
let bounded_prompt = first_prompt
.chars()
.take(SESSION_TITLE_MAX_INPUT_CHARS)
Expand Down Expand Up @@ -6763,6 +6762,7 @@ fn maple_model_config(
// Maple's authoritative catalog value is per session. Explicitly clear any
// process-global Goose context override when metadata is unavailable.
model_config.context_limit = context_limit.filter(|limit| *limit > 0);
provider::clear_output_token_limits(&mut model_config);
Ok(model_config)
}

Expand Down Expand Up @@ -6796,11 +6796,12 @@ async fn install_maple_provider_config<T>(
agent: &Arc<Agent>,
transport: &Arc<T>,
session_id: &str,
model_config: goose_providers::model::ModelConfig,
mut model_config: goose_providers::model::ModelConfig,
) -> Result<(), String>
where
T: provider::MapleInferenceTransport + 'static,
{
provider::clear_output_token_limits(&mut model_config);
let provider = Arc::new(MapleProvider::new(Arc::clone(transport)));
agent
.update_provider(provider, model_config, session_id)
Expand Down Expand Up @@ -10187,6 +10188,7 @@ mod tests {
async fn send_inference_request(
self: Arc<Self>,
_request: opensecret::InferenceRequest,
_send_budget: opensecret::InferenceSendBudget,
_cancel_token: CancellationToken,
) -> opensecret::Result<opensecret::InferenceResponse> {
Err(opensecret::Error::Other(
Expand All @@ -10208,6 +10210,7 @@ mod tests {
async fn send_inference_request(
self: Arc<Self>,
_request: opensecret::InferenceRequest,
_send_budget: opensecret::InferenceSendBudget,
_cancel_token: CancellationToken,
) -> opensecret::Result<opensecret::InferenceResponse> {
match self.0 {
Expand Down Expand Up @@ -11879,7 +11882,12 @@ mod tests {
.unwrap();
let persisted_model_config = goose_providers::model::ModelConfig::new("gemma-3-27b")
.with_context_limit(Some(64_321))
.with_temperature(Some(0.42));
.with_temperature(Some(0.42))
.with_max_tokens(Some(4_096))
.with_merged_request_params(HashMap::from([
("max_output_tokens".to_string(), json!(4_096)),
("include_reasoning".to_string(), json!(false)),
]));
session_manager
.update(&session.id)
.provider_name(MAPLE_PROVIDER_NAME)
Expand Down Expand Up @@ -11931,6 +11939,11 @@ mod tests {
.and_then(|model| model.temperature),
Some(0.42)
);
let restored_config = persisted.model_config.as_ref().unwrap();
assert_eq!(restored_config.max_tokens, None);
let restored_params = restored_config.request_params.as_ref().unwrap();
assert!(!restored_params.contains_key("max_output_tokens"));
assert_eq!(restored_params["include_reasoning"], false);

drop(manager_result);
drop(agent_manager);
Expand Down Expand Up @@ -13204,6 +13217,19 @@ mod tests {
);
}

#[test]
fn maple_model_config_omits_goose_canonical_output_limits() {
let canonical =
ModelConfig::new("deepseek-v4-flash").with_canonical_limits(MAPLE_PROVIDER_NAME);
assert!(canonical.max_tokens.is_some());

let config =
maple_model_config("deepseek-v4-flash", Some(1_048_576)).expect("Maple model config");
assert_eq!(config.model_name, "deepseek-v4-flash");
assert_eq!(config.context_limit, Some(1_048_576));
assert_eq!(config.max_tokens, None);
}

#[test]
fn agent_session_model_locks_after_first_message() {
assert!(validate_session_model_lock(0, Some("glm-5-2"), "gemma4-31b").is_ok());
Expand Down Expand Up @@ -17554,7 +17580,7 @@ mod tests {
.expect("the provider should capture one title request");
assert_eq!(capture.model_name, SESSION_TITLE_MODEL);
assert_eq!(capture.temperature, Some(SESSION_TITLE_TEMPERATURE));
assert_eq!(capture.max_tokens, Some(SESSION_TITLE_MAX_TOKENS));
assert_eq!(capture.max_tokens, None);
assert_eq!(capture.reasoning, Some(false));
assert!(!capture.request_params_present);
assert_eq!(capture.system, SESSION_TITLE_SYSTEM_PROMPT);
Expand Down
8 changes: 4 additions & 4 deletions frontend/src-tauri/src/agent/developer_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ const IMAGE_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(30);
const IMAGE_DESCRIPTION_TIMEOUT: Duration = Duration::from_secs(60);
const IMAGE_DESCRIPTION_MODEL: &str = "gemma4-31b";
const IMAGE_DESCRIPTION_TEMPERATURE: f32 = 0.0;
const IMAGE_DESCRIPTION_MAX_TOKENS: i32 = 2_048;
const IMAGE_DESCRIPTION_CONTEXT_MAX_CHARS: usize = 12_000;
pub(super) const EXTERNAL_MCP_TOOL_NAME: &str = "external_mcp";
const IMAGE_DESCRIPTION_SYSTEM_PROMPT: &str = r#"You are the visual perception helper for a coding agent that cannot inspect images directly.
Expand Down Expand Up @@ -746,7 +745,7 @@ async fn describe_image_for_text_model(
model_config.reasoning = Some(false);
let model_config = model_config
.with_temperature(Some(IMAGE_DESCRIPTION_TEMPERATURE))
.with_max_tokens(Some(IMAGE_DESCRIPTION_MAX_TOKENS));
.with_max_tokens(None);

let prompt = contextual_image_prompt(source, image_context);
let messages = [Message::user()
Expand Down Expand Up @@ -3152,7 +3151,7 @@ mod tests {
model_config.reasoning = Some(false);
let model_config = model_config
.with_temperature(Some(IMAGE_DESCRIPTION_TEMPERATURE))
.with_max_tokens(Some(IMAGE_DESCRIPTION_MAX_TOKENS));
.with_max_tokens(None);
let messages = [Message::user()
.with_text(contextual_image_prompt(
"icon.png",
Expand All @@ -3174,7 +3173,8 @@ mod tests {
let payload = captured.lock().unwrap().take().unwrap();
assert_eq!(payload["model"], IMAGE_DESCRIPTION_MODEL);
assert_eq!(payload["temperature"], IMAGE_DESCRIPTION_TEMPERATURE);
assert_eq!(payload["max_tokens"], IMAGE_DESCRIPTION_MAX_TOKENS);
assert!(payload.get("max_tokens").is_none());
assert!(payload.get("max_completion_tokens").is_none());
assert_eq!(payload["stream"], true);
assert_eq!(payload["include_reasoning"], false);
assert_eq!(payload["chat_template_kwargs"]["enable_thinking"], false);
Expand Down
Loading
Loading