From a9c8b64fd853cf369280f497cb04817295f2df93 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Tue, 2 Jun 2026 17:09:27 -0400 Subject: [PATCH] refactor: move ThinkingEffort to goose-types Signed-off-by: Jack Amadeo --- Cargo.lock | 11 +++++ crates/goose-cli/Cargo.toml | 1 + crates/goose-cli/src/session/mod.rs | 2 +- crates/goose-server/Cargo.toml | 1 + crates/goose-server/src/openapi.rs | 3 +- crates/goose-types/Cargo.toml | 16 ++++++++ crates/goose-types/src/lib.rs | 41 +++++++++++++++++++ crates/goose/Cargo.toml | 1 + crates/goose/src/model.rs | 38 +---------------- crates/goose/src/providers/chatgpt_codex.rs | 2 +- crates/goose/src/providers/codex.rs | 18 ++++---- .../goose/src/providers/formats/anthropic.rs | 3 +- crates/goose/src/providers/formats/google.rs | 2 +- .../goose/src/providers/formats/openrouter.rs | 3 +- crates/goose/src/providers/utils.rs | 3 +- 15 files changed, 92 insertions(+), 53 deletions(-) create mode 100644 crates/goose-types/Cargo.toml create mode 100644 crates/goose-types/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c43c024c17..aef2e3ee15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4484,6 +4484,7 @@ dependencies = [ "goose-providers", "goose-sdk", "goose-test-support", + "goose-types", "http 1.4.1", "http-body-util", "icu_calendar", @@ -4613,6 +4614,7 @@ dependencies = [ "goose", "goose-mcp", "goose-providers", + "goose-types", "indicatif", "open", "rand 0.8.6", @@ -4715,6 +4717,7 @@ dependencies = [ "goose", "goose-mcp", "goose-providers", + "goose-types", "hex", "http 1.4.1", "openssl", @@ -4765,6 +4768,14 @@ dependencies = [ "tokio", ] +[[package]] +name = "goose-types" +version = "1.37.0" +dependencies = [ + "serde", + "utoipa 4.2.3", +] + [[package]] name = "group" version = "0.13.0" diff --git a/crates/goose-cli/Cargo.toml b/crates/goose-cli/Cargo.toml index 3d7736232f..2bb6aa8012 100644 --- a/crates/goose-cli/Cargo.toml +++ b/crates/goose-cli/Cargo.toml @@ -22,6 +22,7 @@ path = "src/bin/generate_manpages.rs" [dependencies] clap_mangen = { version = "0.2", default-features = false } goose = { path = "../goose", default-features = false } +goose-types = { path = "../goose-types", default-features = false } goose-providers = { path = "../goose-providers", default-features = false } goose-mcp = { path = "../goose-mcp", default-features = false } rmcp = { workspace = true } diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index cd7e63b740..6d984cc283 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -2366,7 +2366,7 @@ mod tests { assert_eq!(current.model_name, "gpt-5.4"); assert_eq!( current.thinking_effort(), - Some(goose::model::ThinkingEffort::High) + Some(goose_types::ThinkingEffort::High) ); let switched = build_switched_model_config("openai", "gpt-5.4", ¤t).unwrap(); diff --git a/crates/goose-server/Cargo.toml b/crates/goose-server/Cargo.toml index 22d93d3212..54229b0dfb 100644 --- a/crates/goose-server/Cargo.toml +++ b/crates/goose-server/Cargo.toml @@ -54,6 +54,7 @@ native-tls = [ [dependencies] goose = { path = "../goose", default-features = false } +goose-types = { path = "../goose-types", default-features = false } goose-providers = { path = "../goose-providers", default-features = false } goose-mcp = { path = "../goose-mcp", default-features = false } rmcp = { workspace = true } diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index 5749b6440a..c21935d0b8 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -5,10 +5,11 @@ use goose::config::permission::PermissionLevel; use goose::config::ExtensionEntry; use goose::conversation::Conversation; use goose::download_manager::{DownloadProgress, DownloadStatus}; -use goose::model::{ModelConfig, ThinkingEffort}; +use goose::model::ModelConfig; use goose::permission::permission_confirmation::{Permission, PrincipalType}; use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata, ProviderType}; use goose::session::{Session, SessionInsights, SessionType, SystemInfo}; +use goose_types::ThinkingEffort; use rmcp::model::{ Annotations, Content, EmbeddedResource, Icon, IconTheme, ImageContent, JsonObject, RawAudioContent, RawContent, RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, diff --git a/crates/goose-types/Cargo.toml b/crates/goose-types/Cargo.toml new file mode 100644 index 0000000000..8911b38738 --- /dev/null +++ b/crates/goose-types/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "goose-types" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +description.workspace = true + +[lints] +workspace = true + +[dependencies] +serde = { workspace = true } +utoipa = { workspace = true } diff --git a/crates/goose-types/src/lib.rs b/crates/goose-types/src/lib.rs new file mode 100644 index 0000000000..bec1c850c9 --- /dev/null +++ b/crates/goose-types/src/lib.rs @@ -0,0 +1,41 @@ +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::str::FromStr; +use utoipa::ToSchema; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "lowercase")] +pub enum ThinkingEffort { + Off, + Low, + Medium, + High, + Max, +} + +impl FromStr for ThinkingEffort { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "off" | "disabled" | "none" => Ok(Self::Off), + "low" => Ok(Self::Low), + "medium" | "med" => Ok(Self::Medium), + "high" => Ok(Self::High), + "max" | "xhigh" => Ok(Self::Max), + other => Err(format!("unknown thinking effort: '{other}'")), + } + } +} + +impl fmt::Display for ThinkingEffort { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Off => write!(f, "off"), + Self::Low => write!(f, "low"), + Self::Medium => write!(f, "medium"), + Self::High => write!(f, "high"), + Self::Max => write!(f, "max"), + } + } +} diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index 9204ac4952..0e024267a2 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -126,6 +126,7 @@ etcetera = { workspace = true } fs-err = { version = "3.1", default-features = false } goose-sdk = { path = "../goose-sdk", default-features = false } goose-providers = { path = "../goose-providers", default-features = false } +goose-types = { path = "../goose-types", default-features = false } rand = { workspace = true } utoipa = { workspace = true, features = ["chrono"] } tokio-cron-scheduler = { version = "0.15", default-features = false } diff --git a/crates/goose/src/model.rs b/crates/goose/src/model.rs index bc094d6fff..73b2372f1a 100644 --- a/crates/goose/src/model.rs +++ b/crates/goose/src/model.rs @@ -3,48 +3,12 @@ use serde::de::Deserializer; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; -use std::fmt; -use std::str::FromStr; use thiserror::Error; use utoipa::ToSchema; pub const DEFAULT_CONTEXT_LIMIT: usize = 128_000; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] -#[serde(rename_all = "lowercase")] -pub enum ThinkingEffort { - Off, - Low, - Medium, - High, - Max, -} - -impl FromStr for ThinkingEffort { - type Err = String; - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "off" | "disabled" | "none" => Ok(Self::Off), - "low" => Ok(Self::Low), - "medium" | "med" => Ok(Self::Medium), - "high" => Ok(Self::High), - "max" | "xhigh" => Ok(Self::Max), - other => Err(format!("unknown thinking effort: '{other}'")), - } - } -} - -impl fmt::Display for ThinkingEffort { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Off => write!(f, "off"), - Self::Low => write!(f, "low"), - Self::Medium => write!(f, "medium"), - Self::High => write!(f, "high"), - Self::Max => write!(f, "max"), - } - } -} +use goose_types::ThinkingEffort; #[derive(Debug, Clone, Deserialize)] struct PredefinedModel { diff --git a/crates/goose/src/providers/chatgpt_codex.rs b/crates/goose/src/providers/chatgpt_codex.rs index 17cd31bc07..e7a4737f9b 100644 --- a/crates/goose/src/providers/chatgpt_codex.rs +++ b/crates/goose/src/providers/chatgpt_codex.rs @@ -230,7 +230,7 @@ fn get_reasoning_effort(model_name: &str) -> String { } fn reasoning_effort_for_config(model_config: &ModelConfig) -> Option { - use crate::model::ThinkingEffort; + use goose_types::ThinkingEffort; model_config .thinking_effort() diff --git a/crates/goose/src/providers/codex.rs b/crates/goose/src/providers/codex.rs index 8b420d4146..8a88161357 100644 --- a/crates/goose/src/providers/codex.rs +++ b/crates/goose/src/providers/codex.rs @@ -60,25 +60,25 @@ pub struct CodexProvider { } impl CodexProvider { - fn legacy_reasoning_effort() -> Option { + fn legacy_reasoning_effort() -> Option { Config::global() .get_param::("CODEX_REASONING_EFFORT") .ok() .and_then(|effort| match effort.to_lowercase().as_str() { - "none" => Some(crate::model::ThinkingEffort::Off), - "low" => Some(crate::model::ThinkingEffort::Low), - "medium" => Some(crate::model::ThinkingEffort::Medium), - "high" => Some(crate::model::ThinkingEffort::High), - "xhigh" => Some(crate::model::ThinkingEffort::Max), + "none" => Some(goose_types::ThinkingEffort::Off), + "low" => Some(goose_types::ThinkingEffort::Low), + "medium" => Some(goose_types::ThinkingEffort::Medium), + "high" => Some(goose_types::ThinkingEffort::High), + "xhigh" => Some(goose_types::ThinkingEffort::Max), _ => None, }) } fn map_thinking_effort( _model_name: &str, - effort: Option, + effort: Option, ) -> Option { - use crate::model::ThinkingEffort; + use goose_types::ThinkingEffort; match effort .or_else(Self::legacy_reasoning_effort) .unwrap_or(ThinkingEffort::High) @@ -1238,7 +1238,7 @@ mod tests { #[test] fn test_map_thinking_effort() { - use crate::model::ThinkingEffort; + use goose_types::ThinkingEffort; let _guard = env_lock::lock_env([ ("CODEX_REASONING_EFFORT", None::<&str>), diff --git a/crates/goose/src/providers/formats/anthropic.rs b/crates/goose/src/providers/formats/anthropic.rs index d39b0bacc4..a95f6b9fdd 100644 --- a/crates/goose/src/providers/formats/anthropic.rs +++ b/crates/goose/src/providers/formats/anthropic.rs @@ -1,10 +1,11 @@ use crate::conversation::message::{Message, MessageContent}; use crate::mcp_utils::extract_text_from_resource; -use crate::model::{ModelConfig, ThinkingEffort}; +use crate::model::ModelConfig; use crate::providers::base::Usage; use crate::providers::errors::ProviderError; use crate::providers::utils::{convert_image, ImageFormat}; use anyhow::{anyhow, Result}; +use goose_types::ThinkingEffort; use rmcp::model::{object, CallToolRequestParams, ErrorCode, ErrorData, JsonObject, Role, Tool}; use rmcp::object as json_object; use serde_json::{json, Value}; diff --git a/crates/goose/src/providers/formats/google.rs b/crates/goose/src/providers/formats/google.rs index b35c2db504..f20e8f0316 100644 --- a/crates/goose/src/providers/formats/google.rs +++ b/crates/goose/src/providers/formats/google.rs @@ -542,7 +542,7 @@ fn get_thinking_config(model_config: &ModelConfig) -> Option { } if is_gemini_3 { - use crate::model::ThinkingEffort; + use goose_types::ThinkingEffort; let effort = model_config .thinking_effort() .unwrap_or(ThinkingEffort::Off); diff --git a/crates/goose/src/providers/formats/openrouter.rs b/crates/goose/src/providers/formats/openrouter.rs index 22ac7465b2..3b7df324fe 100644 --- a/crates/goose/src/providers/formats/openrouter.rs +++ b/crates/goose/src/providers/formats/openrouter.rs @@ -1,6 +1,7 @@ use crate::conversation::message::{Message, MessageContent, ProviderMetadata}; -use crate::model::{ModelConfig, ThinkingEffort}; +use crate::model::ModelConfig; use crate::providers::formats::openai; +use goose_types::ThinkingEffort; use rmcp::model::Role; use serde_json::{json, Value}; diff --git a/crates/goose/src/providers/utils.rs b/crates/goose/src/providers/utils.rs index 919db63fc2..1471fc53cc 100644 --- a/crates/goose/src/providers/utils.rs +++ b/crates/goose/src/providers/utils.rs @@ -1,11 +1,12 @@ use super::base::Usage; use super::errors::GoogleErrorCode; use crate::config::paths::Paths; -use crate::model::{ModelConfig, ThinkingEffort}; +use crate::model::ModelConfig; use crate::providers::errors::ProviderError; use anyhow::{anyhow, Result}; use base64::Engine; use fs_err::File; +use goose_types::ThinkingEffort; use regex::Regex; use reqwest::{Response, StatusCode}; use rmcp::model::{AnnotateAble, ImageContent, RawImageContent};