diff --git a/crates/goose-providers/src/formats/openai_responses.rs b/crates/goose-providers/src/formats/openai_responses.rs index 54cbc0b09c..d6daef7853 100644 --- a/crates/goose-providers/src/formats/openai_responses.rs +++ b/crates/goose-providers/src/formats/openai_responses.rs @@ -596,10 +596,11 @@ pub fn create_responses_request( None }; + let store = model_config.request_param::("store").unwrap_or(false); let mut payload = json!({ "model": model_name, "input": input_items, - "store": false, + "store": store, }); if let Some(effort) = reasoning_effort { @@ -1412,6 +1413,27 @@ mod tests { ); } + #[test] + fn test_request_params_override_store() { + let model_config = ModelConfig { + model_name: "o3".to_string(), + context_limit: None, + temperature: None, + max_tokens: None, + toolshim: false, + toolshim_model: None, + request_params: Some(std::collections::HashMap::from([( + "store".to_string(), + serde_json::json!(true), + )])), + reasoning: None, + }; + + let result = create_responses_request(&model_config, "", &[], &[]).unwrap(); + + assert_eq!(result["store"], true); + } + #[test] fn test_user_image_serialized_in_responses_request() { use crate::conversation::message::Message; diff --git a/crates/goose/src/config/base.rs b/crates/goose/src/config/base.rs index 81585e7ad8..0cd9a22ada 100644 --- a/crates/goose/src/config/base.rs +++ b/crates/goose/src/config/base.rs @@ -1172,6 +1172,10 @@ impl Config { self.set_param("GOOSE_THINKING_EFFORT", v) } + pub fn get_openai_store(&self) -> Option { + self.get_param::("OPENAI_STORE").ok() + } + fn legacy_thinking_effort(&self) -> Option { if let Ok(value) = self.get_param::("CLAUDE_THINKING_TYPE") { if let Some(effort) = match value.to_lowercase().as_str() { diff --git a/crates/goose/src/model_config.rs b/crates/goose/src/model_config.rs index cc9a275f5d..145e6ac776 100644 --- a/crates/goose/src/model_config.rs +++ b/crates/goose/src/model_config.rs @@ -27,7 +27,7 @@ pub fn model_config_from_user_config_with_session_settings( ) -> Result { let config = Config::global(); let model = base_model_config_from_user_config(model_name.as_ref())?; - let model = materialize_model_config_inner(model, false)? + let model = materialize_model_config_inner(model, provider_name, false)? .with_context_limit(context_limit) .with_inherited_session_settings_from(previous, request_params) .with_default_thinking_effort(config.get_goose_thinking_effort()); @@ -36,12 +36,13 @@ pub fn model_config_from_user_config_with_session_settings( } pub fn materialize_model_config(provider_name: &str, model: ModelConfig) -> Result { - let model = materialize_model_config_inner(model, true)?; + let model = materialize_model_config_inner(model, provider_name, true)?; Ok(model.with_canonical_limits(provider_name)) } fn materialize_model_config_inner( mut model: ModelConfig, + provider_name: &str, include_default_thinking_effort: bool, ) -> Result { let config = Config::global(); @@ -62,6 +63,10 @@ fn materialize_model_config_inner( model = model.with_default_thinking_effort(config.get_goose_thinking_effort()); } + if provider_name == goose_providers::openai::OPEN_AI_PROVIDER_NAME { + model = apply_openai_request_params(model); + } + Ok(model) } @@ -152,6 +157,17 @@ async fn provider_default_fast_model(provider_name: &str) -> Option { .and_then(|entry| entry.metadata().fast_model.clone()) } +fn apply_openai_request_params(mut model: ModelConfig) -> ModelConfig { + let config = Config::global(); + if let Some(store) = config.get_openai_store() { + model = model.with_merged_request_params(HashMap::from([( + "store".to_string(), + serde_json::json!(store), + )])); + } + model +} + fn base_model_config_from_user_config(model_name: &str) -> Result { let config = Config::global(); let mut model = ModelConfig { diff --git a/documentation/docs/getting-started/providers.md b/documentation/docs/getting-started/providers.md index 494f9d25e6..9480415118 100644 --- a/documentation/docs/getting-started/providers.md +++ b/documentation/docs/getting-started/providers.md @@ -289,6 +289,7 @@ Need to connect to multiple OpenAI-compatible endpoints? [Configure custom provi | `OPENAI_ORGANIZATION` | No | Organization ID for usage tracking and governance | | `OPENAI_PROJECT` | No | Project identifier for resource management | | `OPENAI_CUSTOM_HEADERS` | No | Additional headers to include in the request. Can be set via environment variable, configuration file, or CLI, in the format `HEADER_A=VALUE_A,HEADER_B=VALUE_B`. | +| `OPENAI_STORE` | No | Whether to persist the generated Responses API response for later retrieval via API. Defaults to `false`. | #### Example Configurations