Session-level model client (#10664)

Make ModelClient a session-scoped object.
Move state that is session level onto the client, and make state that is
per-turn explicit on corresponding methods.
Stop taking a huge Config object, instead only pass in values that are
actually needed.

---------

Co-authored-by: Josh McKinney <joshka@openai.com>
This commit is contained in:
pakrym-oai
2026-02-04 16:58:48 -08:00
committed by GitHub
parent 224c9f768d
commit 0e8d359da9
12 changed files with 601 additions and 333 deletions

View File

@@ -10,7 +10,6 @@ use codex_core::ModelProviderInfo;
use codex_core::Prompt;
use codex_core::ResponseEvent;
use codex_core::ResponseItem;
use codex_core::TransportManager;
use codex_core::WEB_SEARCH_ELIGIBLE_HEADER;
use codex_core::WireApi;
use codex_core::models_manager::manager::ModelsManager;
@@ -88,19 +87,19 @@ async fn responses_stream_includes_subagent_header_on_review() {
session_source.clone(),
);
let mut client_session = ModelClient::new(
Arc::clone(&config),
let web_search_eligible = !matches!(config.web_search_mode, Some(WebSearchMode::Disabled));
let client = ModelClient::new(
None,
model_info,
otel_manager,
provider,
effort,
summary,
conversation_id,
provider.clone(),
session_source,
TransportManager::new(),
)
.new_session(None);
config.model_verbosity,
false,
false,
false,
None,
);
let mut client_session = client.new_session();
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {
@@ -113,7 +112,18 @@ async fn responses_stream_includes_subagent_header_on_review() {
phase: None,
}];
let mut stream = client_session.stream(&prompt).await.expect("stream failed");
let mut stream = client_session
.stream(
&prompt,
&model_info,
&otel_manager,
effort,
summary,
web_search_eligible,
None,
)
.await
.expect("stream failed");
while let Some(event) = stream.next().await {
if matches!(event, Ok(ResponseEvent::Completed { .. })) {
break;
@@ -188,19 +198,19 @@ async fn responses_stream_includes_subagent_header_on_other() {
session_source.clone(),
);
let mut client_session = ModelClient::new(
Arc::clone(&config),
let web_search_eligible = !matches!(config.web_search_mode, Some(WebSearchMode::Disabled));
let client = ModelClient::new(
None,
model_info,
otel_manager,
provider,
effort,
summary,
conversation_id,
provider.clone(),
session_source,
TransportManager::new(),
)
.new_session(None);
config.model_verbosity,
false,
false,
false,
None,
);
let mut client_session = client.new_session();
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {
@@ -213,7 +223,18 @@ async fn responses_stream_includes_subagent_header_on_other() {
phase: None,
}];
let mut stream = client_session.stream(&prompt).await.expect("stream failed");
let mut stream = client_session
.stream(
&prompt,
&model_info,
&otel_manager,
effort,
summary,
web_search_eligible,
None,
)
.await
.expect("stream failed");
while let Some(event) = stream.next().await {
if matches!(event, Ok(ResponseEvent::Completed { .. })) {
break;
@@ -346,19 +367,19 @@ async fn responses_respects_model_info_overrides_from_config() {
session_source.clone(),
);
let mut client = ModelClient::new(
Arc::clone(&config),
let web_search_eligible = !matches!(config.web_search_mode, Some(WebSearchMode::Disabled));
let client = ModelClient::new(
None,
model_info,
otel_manager,
provider,
effort,
summary,
conversation_id,
provider.clone(),
session_source,
TransportManager::new(),
)
.new_session(None);
config.model_verbosity,
false,
false,
false,
None,
);
let mut client_session = client.new_session();
let mut prompt = Prompt::default();
prompt.input = vec![ResponseItem::Message {
@@ -371,7 +392,18 @@ async fn responses_respects_model_info_overrides_from_config() {
phase: None,
}];
let mut stream = client.stream(&prompt).await.expect("stream failed");
let mut stream = client_session
.stream(
&prompt,
&model_info,
&otel_manager,
effort,
summary,
web_search_eligible,
None,
)
.await
.expect("stream failed");
while let Some(event) = stream.next().await {
if matches!(event, Ok(ResponseEvent::Completed { .. })) {
break;