Pass routing headers to ChatGPT subscription API (#62556)
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions

## Objective

Improve cache hit rate of LLM requests sent to ChatGPT subscription API.

## Solution

Set headers that help route request to the correct servers. This is
ChatGPT specific; plain OpenAI API doesn't require it.

## Testing

I run a benchmark which imitates a thread that makes 20 sequential tool
calls. I tried different cache route strategies. Results are below:


| Configuration                                   | Hit rate |
|-------------------------------------------------|---------:|
| No identity headers, no cache key               | 22.2%    |
| `thread-id` only, no cache key                  | 44.4%    |
| `thread-id` + matching cache key                | 42.1%    |
| Cache key only                                  | 53.6%    |
| Turn state + cache key                          | 47.4%    |
| `session-id` + matching cache key               | 100.0%   |
| `session-id` + `thread-id` + matching cache key | 97.4%    |



---

Release Notes:

- Improved ChatGPT subscription caching
This commit is contained in:
Oleksiy Syvokon 2026-08-13 01:04:16 +00:00 committed by GitHub
parent c05e34637b
commit a8fafdd7ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -403,7 +403,10 @@ impl OpenAiSubscribedLanguageModel {
}
}
fn codex_extra_headers(credentials: &CodexCredentials) -> CustomHeaders {
fn codex_extra_headers(
credentials: &CodexCredentials,
routing_cache_key: Option<&str>,
) -> CustomHeaders {
let mut header_pairs: Vec<(HeaderName, HeaderValue)> = vec![
(
HeaderName::from_static("originator"),
@ -420,6 +423,12 @@ fn codex_extra_headers(credentials: &CodexCredentials) -> CustomHeaders {
{
header_pairs.push((HeaderName::from_static("chatgpt-account-id"), value));
}
if let Some(routing_cache_key) = routing_cache_key
&& let Ok(value) = HeaderValue::from_str(routing_cache_key)
{
header_pairs.push((HeaderName::from_static("session-id"), value.clone()));
header_pairs.push((HeaderName::from_static("thread-id"), value));
}
CustomHeaders::new(header_pairs)
}
@ -492,7 +501,8 @@ impl LanguageModel for OpenAiSubscribedLanguageModel {
cx.spawn(async move |cx| {
let creds = get_fresh_credentials(&state, &http_client, cx).await?;
let extra_headers = codex_extra_headers(&creds);
let extra_headers =
codex_extra_headers(&creds, responses_request.prompt_cache_key.as_deref());
let access_token = creds.access_token.clone();
let response_stream = request_limiter
.stream(async move {
@ -604,7 +614,8 @@ impl LanguageModel for OpenAiSubscribedLanguageModel {
let future = cx.spawn(async move |cx| {
let creds = get_fresh_credentials(&state, &http_client, cx).await?;
let extra_headers = codex_extra_headers(&creds);
let extra_headers =
codex_extra_headers(&creds, responses_request.prompt_cache_key.as_deref());
let access_token = creds.access_token.clone();
request_limiter
@ -1365,6 +1376,20 @@ mod tests {
.and_then(|value| value.to_str().ok()),
Some("account-123")
);
assert_eq!(
request
.headers()
.get("session-id")
.and_then(|value| value.to_str().ok()),
Some("thread-123")
);
assert_eq!(
request
.headers()
.get("thread-id")
.and_then(|value| value.to_str().ok()),
Some("thread-123")
);
let mut request_body = String::new();
smol::io::AsyncReadExt::read_to_string(
&mut request.into_body(),
@ -1403,6 +1428,7 @@ mod tests {
reasoning_details: None,
}],
compact_at_tokens: Some(100_000),
thread_id: Some("thread-123".to_string()),
..Default::default()
};
let async_cx = cx.to_async();
@ -1451,6 +1477,20 @@ mod tests {
request.uri().to_string(),
"https://chatgpt.com/backend-api/codex/responses"
);
assert_eq!(
request
.headers()
.get("session-id")
.and_then(|value| value.to_str().ok()),
Some("thread-123")
);
assert_eq!(
request
.headers()
.get("thread-id")
.and_then(|value| value.to_str().ok()),
Some("thread-123")
);
let mut request_body = String::new();
smol::io::AsyncReadExt::read_to_string(&mut request.into_body(), &mut request_body)
.await?;
@ -1478,6 +1518,7 @@ mod tests {
reasoning_details: None,
}],
compact_at_tokens: Some(100_000),
thread_id: Some("thread-123".to_string()),
..Default::default()
};