mirror of
https://github.com/openai/codex.git
synced 2026-11-13 22:47:20 +00:00
Feature to auto-enable websockets transport (#9578)
This commit is contained in:
1 parent
fabc2bcc32
commit
527b7b4c02
5 files changed
+61
-1
No files matched your search
@@ -113,7 +113,9 @@ impl<A: AuthProvider> ResponsesWebsocketClient<A> {
|
|||||||
extra_headers: HeaderMap,
|
extra_headers: HeaderMap,
|
||||||
turn_state: Option<Arc<OnceLock<String>>>,
|
turn_state: Option<Arc<OnceLock<String>>>,
|
||||||
) -> Result<ResponsesWebsocketConnection, ApiError> {
|
) -> Result<ResponsesWebsocketConnection, ApiError> {
|
||||||
let ws_url = Url::parse(&self.provider.url_for_path("responses"))
|
let ws_url = self
|
||||||
|
.provider
|
||||||
|
.websocket_url_for_path("responses")
|
||||||
.map_err(|err| ApiError::Stream(format!("failed to build websocket URL: {err}")))?;
|
.map_err(|err| ApiError::Stream(format!("failed to build websocket URL: {err}")))?;
|
||||||
|
|
||||||
let mut headers = self.provider.headers.clone();
|
let mut headers = self.provider.headers.clone();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use http::Method;
|
|||||||
use http::header::HeaderMap;
|
use http::header::HeaderMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
/// Wire-level APIs supported by a `Provider`.
|
/// Wire-level APIs supported by a `Provider`.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -105,6 +106,19 @@ impl Provider {
|
|||||||
self.base_url.to_ascii_lowercase().contains("openai.azure.")
|
self.base_url.to_ascii_lowercase().contains("openai.azure.")
|
||||||
|| matches_azure_responses_base_url(&self.base_url)
|
|| matches_azure_responses_base_url(&self.base_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn websocket_url_for_path(&self, path: &str) -> Result<Url, url::ParseError> {
|
||||||
|
let mut url = Url::parse(&self.url_for_path(path))?;
|
||||||
|
|
||||||
|
let scheme = match url.scheme() {
|
||||||
|
"http" => "ws",
|
||||||
|
"https" => "wss",
|
||||||
|
"ws" | "wss" => return Ok(url),
|
||||||
|
_ => return Ok(url),
|
||||||
|
};
|
||||||
|
let _ = url.set_scheme(scheme);
|
||||||
|
Ok(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_azure_responses_base_url(base_url: &str) -> bool {
|
fn matches_azure_responses_base_url(base_url: &str) -> bool {
|
||||||
|
|||||||
@@ -109,6 +109,9 @@
|
|||||||
"remote_models": {
|
"remote_models": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"responses_websockets": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"shell_snapshot": {
|
"shell_snapshot": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
@@ -601,6 +604,9 @@
|
|||||||
"remote_models": {
|
"remote_models": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"responses_websockets": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"shell_snapshot": {
|
"shell_snapshot": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1363,6 +1363,12 @@ impl Config {
|
|||||||
|| cfg.sandbox_mode.is_some();
|
|| cfg.sandbox_mode.is_some();
|
||||||
|
|
||||||
let mut model_providers = built_in_model_providers();
|
let mut model_providers = built_in_model_providers();
|
||||||
|
if features.enabled(Feature::ResponsesWebsockets)
|
||||||
|
&& let Some(provider) = model_providers.get_mut("openai")
|
||||||
|
&& provider.is_openai()
|
||||||
|
{
|
||||||
|
provider.wire_api = crate::model_provider_info::WireApi::ResponsesWebsocket;
|
||||||
|
}
|
||||||
// Merge user-defined providers into the built-in list.
|
// Merge user-defined providers into the built-in list.
|
||||||
for (key, provider) in cfg.model_providers.into_iter() {
|
for (key, provider) in cfg.model_providers.into_iter() {
|
||||||
model_providers.entry(key).or_insert(provider);
|
model_providers.entry(key).or_insert(provider);
|
||||||
@@ -2511,6 +2517,30 @@ profile = "project"
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn responses_websockets_feature_updates_openai_provider() -> std::io::Result<()> {
|
||||||
|
let codex_home = TempDir::new()?;
|
||||||
|
let mut entries = BTreeMap::new();
|
||||||
|
entries.insert("responses_websockets".to_string(), true);
|
||||||
|
let cfg = ConfigToml {
|
||||||
|
features: Some(crate::features::FeaturesToml { entries }),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = Config::load_from_base_config_with_overrides(
|
||||||
|
cfg,
|
||||||
|
ConfigOverrides::default(),
|
||||||
|
codex_home.path().to_path_buf(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
config.model_provider.wire_api,
|
||||||
|
crate::model_provider_info::WireApi::ResponsesWebsocket
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn config_honors_explicit_file_oauth_store_mode() -> std::io::Result<()> {
|
fn config_honors_explicit_file_oauth_store_mode() -> std::io::Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
|
|||||||
@@ -107,6 +107,8 @@ pub enum Feature {
|
|||||||
Steer,
|
Steer,
|
||||||
/// Enable collaboration modes (Plan, Pair Programming, Execute).
|
/// Enable collaboration modes (Plan, Pair Programming, Execute).
|
||||||
CollaborationModes,
|
CollaborationModes,
|
||||||
|
/// Use the Responses API WebSocket transport for OpenAI by default.
|
||||||
|
ResponsesWebsockets,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Feature {
|
impl Feature {
|
||||||
@@ -461,4 +463,10 @@ pub const FEATURES: &[FeatureSpec] = &[
|
|||||||
stage: Stage::Beta,
|
stage: Stage::Beta,
|
||||||
default_enabled: false,
|
default_enabled: false,
|
||||||
},
|
},
|
||||||
|
FeatureSpec {
|
||||||
|
id: Feature::ResponsesWebsockets,
|
||||||
|
key: "responses_websockets",
|
||||||
|
stage: Stage::Beta,
|
||||||
|
default_enabled: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
Reference in new issue
Block a user