Codex model response latency increases significantly as conversation grows #6577

Open
opened 2026-02-16 18:04:38 -05:00 by yindo · 23 comments
Owner

Originally created by @Skyline-23 on GitHub (Jan 17, 2026).

Originally assigned to: @rekram1-node on GitHub.

Problem

When using Codex models (via OAuth authentication), response latency increases significantly as the conversation grows longer. This happens because the entire conversation history is sent with every API request.

Root Cause

After investigating the codebase:

  1. The OpenAI Responses API returns a responseId in providerMetadata.openai.responseId
  2. The SDK supports previousResponseId option (openai-responses-language-model.ts:285)
  3. However, this feature is never actually used - the responseId from responses is not stored, and previousResponseId is never set

Current Flow

Request 1 → Send full history → Get response with responseId (discarded)
Request 2 → Send full history again → Get response with responseId (discarded)
Request N → Send increasingly large history → Slow response

Expected Flow with previous_response_id

Request 1 → Send full history → Get response with responseId (saved)
Request 2 → Send previousResponseId + new message only → Fast response
Request N → Reference previous response → Consistent speed

Impact

  • Codex API calls become progressively slower as conversations grow
  • Poor user experience with long coding sessions
  • Unnecessary bandwidth and compute usage

Proposed Solution

  1. Add responseId field to AssistantMessage schema
  2. Store responseId from providerMetadata when receiving responses
  3. Pass previousResponseId to subsequent requests via providerOptions
Originally created by @Skyline-23 on GitHub (Jan 17, 2026). Originally assigned to: @rekram1-node on GitHub. ## Problem When using Codex models (via OAuth authentication), response latency increases significantly as the conversation grows longer. This happens because the entire conversation history is sent with every API request. ## Root Cause After investigating the codebase: 1. The OpenAI Responses API returns a `responseId` in `providerMetadata.openai.responseId` 2. The SDK supports `previousResponseId` option (`openai-responses-language-model.ts:285`) 3. However, **this feature is never actually used** - the `responseId` from responses is not stored, and `previousResponseId` is never set ### Current Flow ``` Request 1 → Send full history → Get response with responseId (discarded) Request 2 → Send full history again → Get response with responseId (discarded) Request N → Send increasingly large history → Slow response ``` ### Expected Flow with previous_response_id ``` Request 1 → Send full history → Get response with responseId (saved) Request 2 → Send previousResponseId + new message only → Fast response Request N → Reference previous response → Consistent speed ``` ## Impact - Codex API calls become progressively slower as conversations grow - Poor user experience with long coding sessions - Unnecessary bandwidth and compute usage ## Proposed Solution 1. Add `responseId` field to `AssistantMessage` schema 2. Store `responseId` from `providerMetadata` when receiving responses 3. Pass `previousResponseId` to subsequent requests via `providerOptions`
yindo added the perf label 2026-02-16 18:04:38 -05:00
Author
Owner

@fatihdogmus commented on GitHub (Jan 17, 2026):

yeah realized that as well. when the conversations get longer and longer, the slower the requests become.

@fatihdogmus commented on GitHub (Jan 17, 2026): yeah realized that as well. when the conversations get longer and longer, the slower the requests become.
Author
Owner

@rekram1-node commented on GitHub (Jan 17, 2026):

I'm pretty sure that codex (openais agent) itself doesn't even use this unless you're on azure. Verifying

@rekram1-node commented on GitHub (Jan 17, 2026): I'm pretty sure that codex (openais agent) itself doesn't even use this unless you're on azure. Verifying
Author
Owner

@c0rtechs commented on GitHub (Jan 17, 2026):

Currently experiencing this as well, current task has been running for about 3 hours at this point and in the last hour or so it has run a total of 6 grep commands, taking like 5-10 minutes per action. Is definitely a longer conversation history, as I ran a plan agent first and continued from that plan into a build.

@c0rtechs commented on GitHub (Jan 17, 2026): Currently experiencing this as well, current task has been running for about 3 hours at this point and in the last hour or so it has run a total of 6 grep commands, taking like 5-10 minutes per action. Is definitely a longer conversation history, as I ran a plan agent first and continued from that plan into a build.
Author
Owner

@Skyline-23 commented on GitHub (Jan 17, 2026):

Why Codex Gets Slower as Conversations Grow (and Why Opus Stays Fast)

Did some digging into the docs and codebase to understand this better.


OpenAI's previous_response_id

From the OpenAI docs:

The previous_response_id parameter lets you chain responses and create a threaded conversation.

response = client.responses.create(model="gpt-4o-mini", input="tell me a joke")

# Instead of sending full history, just reference the previous response
second_response = client.responses.create(
    model="gpt-4o-mini",
    previous_response_id=response.id,
    input=[{"role": "user", "content": "explain why this is funny."}],
)

The SDK already supports this, but it was never wired up in opencode.


The store Parameter Problem

There's also this in the codebase:

if (input.model.providerID.includes("codex")) {
  result["store"] = false
}

From OpenAI's docs:

You can disable storing responses by setting store to false.

If responses aren't stored, previous_response_id has nothing to reference. So even if we add support for it, it wouldn't work with store: false.

Curious why this was set to false originally - @rekram1-node do you know the history here?


Why Anthropic (Opus) Doesn't Have This Issue

Anthropic does automatic prefix caching:

Prompt caching reduces latency by up to 85% for long prompts.

It just works - send the same prefix and it's cached. No explicit state management needed.

Provider How it works Result
Anthropic Auto prefix caching Long convos stay fast
OpenAI/Codex Needs previous_response_id Currently resends everything

The Fix

PR #9046 adds previous_response_id support and changes store to true so responses are actually saved for referencing.

This should help with the 5-10 min response times @c0rtechs mentioned.

@Skyline-23 commented on GitHub (Jan 17, 2026): ## Why Codex Gets Slower as Conversations Grow (and Why Opus Stays Fast) Did some digging into the docs and codebase to understand this better. --- ### OpenAI's `previous_response_id` From the [OpenAI docs](https://platform.openai.com/docs/guides/conversation-state): > The `previous_response_id` parameter lets you chain responses and create a threaded conversation. ```python response = client.responses.create(model="gpt-4o-mini", input="tell me a joke") # Instead of sending full history, just reference the previous response second_response = client.responses.create( model="gpt-4o-mini", previous_response_id=response.id, input=[{"role": "user", "content": "explain why this is funny."}], ) ``` The SDK already supports this, but it was never wired up in opencode. --- ### The `store` Parameter Problem There's also this in the codebase: ```typescript if (input.model.providerID.includes("codex")) { result["store"] = false } ``` From [OpenAI's docs](https://platform.openai.com/docs/guides/prompt-caching): > You can disable storing responses by setting `store` to `false`. If responses aren't stored, `previous_response_id` has nothing to reference. So even if we add support for it, it wouldn't work with `store: false`. Curious why this was set to false originally - @rekram1-node do you know the history here? --- ### Why Anthropic (Opus) Doesn't Have This Issue Anthropic does automatic prefix caching: > Prompt caching reduces latency by up to 85% for long prompts. It just works - send the same prefix and it's cached. No explicit state management needed. | Provider | How it works | Result | |----------|-------------|--------| | Anthropic | Auto prefix caching | Long convos stay fast | | OpenAI/Codex | Needs `previous_response_id` | Currently resends everything | --- ### The Fix PR #9046 adds `previous_response_id` support and changes `store` to `true` so responses are actually saved for referencing. This should help with the 5-10 min response times @c0rtechs mentioned.
Author
Owner

@c0rtechs commented on GitHub (Jan 18, 2026):

Unsure if it's related or not, but I also just experienced it running for about 3-4 hours nonstop in plan mode and it eventually just hit the context limit and ended without producing any plan or compacting to continue. GPT Pro Subscription using 5.2 xhigh. Shows the following in terminal:

271,002 68% (.00)

^--- at top right

Error message:

{"type":"error","sequence_number":2,"error":{"type":"invalid_request_error","code":"context_length_exceeded","message":"Your input exceeds the context window of this model. Please adjust your input and try again.","param":"input"}}

@c0rtechs commented on GitHub (Jan 18, 2026): Unsure if it's related or not, but I also just experienced it running for about 3-4 hours nonstop in plan mode and it eventually just hit the context limit and ended without producing any plan or compacting to continue. GPT Pro Subscription using 5.2 xhigh. Shows the following in terminal: > 271,002 68% (.00) ^--- at top right Error message: > {"type":"error","sequence_number":2,"error":{"type":"invalid_request_error","code":"context_length_exceeded","message":"Your input exceeds the context window of this model. Please adjust your input and try again.","param":"input"}}
Author
Owner

@rekram1-node commented on GitHub (Jan 18, 2026):

Looking into compaction issue

As for previous response id stuff we are trying to match codex cli, I dont think they use that either

@rekram1-node commented on GitHub (Jan 18, 2026): Looking into compaction issue As for previous response id stuff we are trying to match codex cli, I dont think they use that either
Author
Owner

@Skyline-23 commented on GitHub (Jan 18, 2026):

@rekram1-node I dug into the Codex CLI source code to see how they handle this.

What I found:

  1. Codex uses a session_id header - not previous_response_id
// codex-rs/codex-api/src/requests/headers.rs
pub fn build_conversation_headers(conversation_id: Option<String>) -> HeaderMap {
    let mut headers = HeaderMap::new();
    if let Some(id) = conversation_id {
        insert_header(&mut headers, "session_id", &id);
    }
    headers
}
  1. They don't use previous_response_id - you're right about that
  2. They use store: false (except for Azure)

My guess:

The session_id header is probably how OpenAI's server does session-level caching/optimization internally. But this isn't documented anywhere in the public API docs - it's an internal/private API.

Why I think previous_response_id is the better choice:

  • Codex CLI is an OpenAI internal project, so they can use private APIs without worry
  • opencode is an external project - relying on undocumented APIs is risky since they could change anytime without notice
  • previous_response_id is officially documented and supported

Just my 2 cents - matching Codex CLI behavior 1:1 might not be the best approach when they have access to internal APIs that we don't.

@Skyline-23 commented on GitHub (Jan 18, 2026): @rekram1-node I dug into the Codex CLI source code to see how they handle this. ### What I found: 1. **Codex uses a `session_id` header** - not `previous_response_id` ```rust // codex-rs/codex-api/src/requests/headers.rs pub fn build_conversation_headers(conversation_id: Option<String>) -> HeaderMap { let mut headers = HeaderMap::new(); if let Some(id) = conversation_id { insert_header(&mut headers, "session_id", &id); } headers } ``` 2. **They don't use `previous_response_id`** - you're right about that 3. **They use `store: false`** (except for Azure) ### My guess: The `session_id` header is probably how OpenAI's server does session-level caching/optimization internally. But this isn't documented anywhere in the public API docs - it's an internal/private API. ### Why I think `previous_response_id` is the better choice: - Codex CLI is an OpenAI internal project, so they can use private APIs without worry - opencode is an external project - relying on undocumented APIs is risky since they could change anytime without notice - `previous_response_id` is [officially documented](https://platform.openai.com/docs/guides/conversation-state) and supported Just my 2 cents - matching Codex CLI behavior 1:1 might not be the best approach when they have access to internal APIs that we don't.
Author
Owner

@Skyline-23 commented on GitHub (Jan 18, 2026):

Did some more digging into the Codex CLI source.

Key finding: Codex CLI uses SSE HTTP by default, not WebSocket

// codex-rs/core/src/model_provider_info.rs
pub fn create_openai_provider() -> ModelProviderInfo {
    wire_api: WireApi::Responses,  // SSE HTTP, not WebSocket
    // ...
}

WebSocket (ResponsesWebsocket) is marked as "experimental" and isn't the default.

So what makes Codex CLI faster?

Comparing SSE HTTP mode:

Feature Codex CLI opencode
prompt_cache_key uses conversation_id uses sessionID
session_id header sends it doesn't send
store false false → true (this PR)
previous_response_id not used (this PR)

The main difference in SSE HTTP mode is the session_id header.

My take

We have two options:

  1. Add session_id header (match Codex CLI exactly)

    • Undocumented/private API
    • Could break anytime without notice
  2. Use previous_response_id (this PR)

I still think option 2 is safer for an external project. But if you want to match Codex CLI exactly, we'd need to add the session_id header instead.

What do you think @rekram1-node?

@Skyline-23 commented on GitHub (Jan 18, 2026): Did some more digging into the Codex CLI source. ### Key finding: Codex CLI uses SSE HTTP by default, not WebSocket ```rust // codex-rs/core/src/model_provider_info.rs pub fn create_openai_provider() -> ModelProviderInfo { wire_api: WireApi::Responses, // SSE HTTP, not WebSocket // ... } ``` WebSocket (`ResponsesWebsocket`) is marked as "experimental" and isn't the default. ### So what makes Codex CLI faster? Comparing SSE HTTP mode: | Feature | Codex CLI | opencode | |---------|-----------|----------| | `prompt_cache_key` | ✅ uses conversation_id | ✅ uses sessionID | | `session_id` header | ✅ sends it | ❌ doesn't send | | `store` | false | false → true (this PR) | | `previous_response_id` | ❌ not used | ✅ (this PR) | The main difference in SSE HTTP mode is the **`session_id` header**. ### My take We have two options: 1. **Add `session_id` header** (match Codex CLI exactly) - Undocumented/private API - Could break anytime without notice 2. **Use `previous_response_id`** (this PR) - [Officially documented](https://platform.openai.com/docs/guides/conversation-state) - Stable, supported by OpenAI I still think option 2 is safer for an external project. But if you want to match Codex CLI exactly, we'd need to add the `session_id` header instead. What do you think @rekram1-node?
Author
Owner

@Skyline-23 commented on GitHub (Jan 19, 2026):

Hi, just wanted to check in — is this still under verification?

This issue is quite critical for me. I genuinely enjoy using opencode, but at the moment I’m unable to use Codex within it due to the significant performance slowdown as conversations grow.

I’d really appreciate it if this could be addressed in the near future. @rekram1-node

@Skyline-23 commented on GitHub (Jan 19, 2026): Hi, just wanted to check in — is this still under verification? This issue is quite critical for me. I genuinely enjoy using opencode, but at the moment I’m unable to use Codex within it due to the significant performance slowdown as conversations grow. I’d really appreciate it if this could be addressed in the near future. @rekram1-node
Author
Owner

@rekram1-node commented on GitHub (Jan 19, 2026):

All these responses are ai so i don't know if you are actually finding things and responding or if you are just pasting things in here

Also pretty sure you can't use previous_response_id w/ out store=true but you may have noticed that

@rekram1-node commented on GitHub (Jan 19, 2026): All these responses are ai so i don't know if you are actually finding things and responding or if you are just pasting things in here Also pretty sure you can't use `previous_response_id` w/ out store=true but you may have noticed that
Author
Owner

@Skyline-23 commented on GitHub (Jan 19, 2026):

Just to clarify a couple of things.

First, English isn’t my first language, so I used AI to help phrase my comments more clearly. That’s purely for communication, not for generating conclusions.

Separately, I did use AI as a helper to locate potentially relevant parts of the codebase. However, the analysis itself was done by me. I personally read through the identified sections, compared what was different, and formed my conclusions based on my own understanding of the source. The AI didn’t make technical judgments — it only helped narrow down where to look.

Regarding previous_response_id, I’m aware it requires store=true, which is why I already updated the PR accordingly. https://github.com/anomalyco/opencode/pull/9046/commits/3141606e79f22b6b59a6193ce0f7b2b9fd583677

I’m fully open to being corrected on the technical details if something is wrong — that’s the point of this discussion. However, the implication that I’m just pasting AI output without doing the work was honestly frustrating to read. I’d appreciate keeping the conversation focused on the technical substance rather than questioning intent or effort.
@rekram1-node

@Skyline-23 commented on GitHub (Jan 19, 2026): Just to clarify a couple of things. First, English isn’t my first language, so I used AI to help phrase my comments more clearly. That’s purely for communication, not for generating conclusions. Separately, I did use AI as a helper to locate potentially relevant parts of the codebase. However, the analysis itself was done by me. I personally read through the identified sections, compared what was different, and formed my conclusions based on my own understanding of the source. The AI didn’t make technical judgments — it only helped narrow down where to look. Regarding `previous_response_id`, I’m aware it requires `store=true`, which is why I already updated the PR accordingly. https://github.com/anomalyco/opencode/pull/9046/commits/3141606e79f22b6b59a6193ce0f7b2b9fd583677 I’m fully open to being corrected on the technical details if something is wrong — that’s the point of this discussion. However, the implication that I’m just pasting AI output without doing the work was honestly frustrating to read. I’d appreciate keeping the conversation focused on the technical substance rather than questioning intent or effort. @rekram1-node
Author
Owner

@rekram1-node commented on GitHub (Jan 19, 2026):

Fair point, it's just hard to deal w/ some of the people on here i didnt mean to imply anything I just wanted to confirm you are a real person

apologies

@rekram1-node commented on GitHub (Jan 19, 2026): Fair point, it's just hard to deal w/ some of the people on here i didnt mean to imply anything I just wanted to confirm you are a real person apologies
Author
Owner

@rekram1-node commented on GitHub (Jan 19, 2026):

Are you having super long conversations? I just don't see why we need to diverge from how codex cli works here, I want to be in parity I don't wanna have to deal with all the issues store=true brings if we can help it

@rekram1-node commented on GitHub (Jan 19, 2026): Are you having super long conversations? I just don't see why we need to diverge from how codex cli works here, I want to be in parity I don't wanna have to deal with all the issues store=true brings if we can help it
Author
Owner

@Skyline-23 commented on GitHub (Jan 19, 2026):

Thanks for apologies 😌

Yes — in real usage, conversations do get quite long, especially in flows like plan → implement → iterate → refactor. That’s where the slowdown becomes very noticeable.

I agree that parity with Codex CLI is a good goal in principle. The main concern I had is that Codex CLI appears to rely on internal mechanisms (like the session_id header) that aren’t part of the public API. As an external project, opencode doesn’t really have the same guarantees there.

That’s why I leaned toward previous_response_id — not because it’s perfect, but because it’s officially documented and supported. My thinking was that matching behavior via public APIs might be safer long-term than depending on undocumented internals.

That said, I understand the hesitation around store=true and the issues it can introduce. If there’s a clean way to achieve the same effect while staying close to Codex CLI behavior, I’m definitely open to that — my main goal here is addressing the real performance degradation in long-running sessions.

@Skyline-23 commented on GitHub (Jan 19, 2026): Thanks for apologies 😌 Yes — in real usage, conversations do get quite long, especially in flows like plan → implement → iterate → refactor. That’s where the slowdown becomes very noticeable. I agree that parity with Codex CLI is a good goal in principle. The main concern I had is that Codex CLI appears to rely on internal mechanisms (like the session_id header) that aren’t part of the public API. As an external project, opencode doesn’t really have the same guarantees there. That’s why I leaned toward previous_response_id — not because it’s perfect, but because it’s officially documented and supported. My thinking was that matching behavior via public APIs might be safer long-term than depending on undocumented internals. That said, I understand the hesitation around store=true and the issues it can introduce. If there’s a clean way to achieve the same effect while staying close to Codex CLI behavior, I’m definitely open to that — my main goal here is addressing the real performance degradation in long-running sessions.
Author
Owner

@rekram1-node commented on GitHub (Jan 19, 2026):

I think that session id thing tho isnt related to the speed of requests

like are u noticing significant differences? compared to their cli?

One note that dev is more up to date than latest release, in dev openai models perform better and faster than in production currently and a lot of this is due to codex parity

@rekram1-node commented on GitHub (Jan 19, 2026): I think that session id thing tho isnt related to the speed of requests like are u noticing significant differences? compared to their cli? One note that dev is more up to date than latest release, in dev openai models perform better and faster than in production currently and a lot of this is due to codex parity
Author
Owner

@Skyline-23 commented on GitHub (Jan 19, 2026):

The problem isn’t simply that requests are “slow” — it’s that they start off very fast, and then become dramatically slower as the conversation grows. Early in a session, responses come back almost immediately. Later on, asking a similarly simple question can take orders of magnitude longer.

That progressive slowdown is the behavior I’m trying to explain and address.

I agree that it’s hard to conclusively prove this with a clean, isolated benchmark, and I’m actively looking for a reliable way to demonstrate it more concretely.

@Skyline-23 commented on GitHub (Jan 19, 2026): The problem isn’t simply that requests are “slow” — it’s that they start off very fast, and then become dramatically slower as the conversation grows. Early in a session, responses come back almost immediately. Later on, asking a similarly simple question can take orders of magnitude longer. That progressive slowdown is the behavior I’m trying to explain and address. I agree that it’s hard to conclusively prove this with a clean, isolated benchmark, and I’m actively looking for a reliable way to demonstrate it more concretely.
Author
Owner

@mirlas commented on GitHub (Jan 19, 2026):

..Besides the slowdown, which really becomes noticeable quite quickly, there’s another issue that wasn’t mentioned — repeated token consumption. In my scenario, OpenCode burned through half of the weekly Pro subscription limit in just a couple of days… And yes, it all ended with editing a bash script taking 30 minutes. After that, I stopped using it.

@mirlas commented on GitHub (Jan 19, 2026): ..Besides the slowdown, which really becomes noticeable quite quickly, there’s another issue that wasn’t mentioned — repeated token consumption. In my scenario, OpenCode burned through half of the weekly Pro subscription limit in just a couple of days… And yes, it all ended with editing a bash script taking 30 minutes. After that, I stopped using it.
Author
Owner

@rekram1-node commented on GitHub (Jan 19, 2026):

@mirlas hard to say what caused it unless you are using plugins, are you using any plugins by chance?

@rekram1-node commented on GitHub (Jan 19, 2026): @mirlas hard to say what caused it unless you are using plugins, are you using any plugins by chance?
Author
Owner

@mirlas commented on GitHub (Jan 19, 2026):

@rekram1-node No, no plugins at all. This was actually my first time trying OpenCode.
The only thing I configured (the project is fairly heavy) was sub-agents :)
However, the amount of work they managed to get done was several times less than what a single Codex CLI does..

@mirlas commented on GitHub (Jan 19, 2026): @rekram1-node No, no plugins at all. This was actually my first time trying OpenCode. The only thing I configured (the project is fairly heavy) was sub-agents :) However, the amount of work they managed to get done was several times less than what a single Codex CLI does..
Author
Owner

@Skyline-23 commented on GitHub (Jan 19, 2026):

@rekram1-node

If we are not going to use previous_response_id, then we have to reduce the client‑side payload itself; otherwise performance will continue to degrade as the session grows. I ran direct, same‑model comparisons between opencode and Codex CLI (MCP disabled) and captured the actual request JSON payloads to measure sizes and counts. Below is the full test design and exact measurements.


1) Test design and measurement method

(1) Request capture

  • opencode: captured request bodies to /tmp/opencode-req-*.json
  • Codex CLI: captured request bodies to /tmp/codex-request-*.json
  • All measurements computed directly from those JSON files

(2) Measurement commands

# request file size
stat -f%z /tmp/opencode-req-*.json
stat -f%z /tmp/codex-request-*.json

# input payload size
jq '.body.input | tojson | length' <file>

# input item count
jq '.body.input | length' <file>

# tool call count
jq '[.body.input[] | select(.type == "function_call")] | length' <file>

# tool output total size
jq '[.body.input[] | select(.type == "function_call_output") | .output | length] | add' <file>

# max output size
jq '[.body.input[] | select(.type == "function_call_output") | .output | length] | max' <file>

(3) Files/paths used in tests

  • Directory: packages/opencode/src/session
  • Directory: packages/opencode/src/provider
  • File: packages/opencode/src/session/prompt.ts
  • File: packages/opencode/src/session/llm.ts
  • File: packages/opencode/src/session/processor.ts

2) Test A — Large file read (initial repro)

Task: read all TS files in packages/opencode/src/session + packages/opencode/src/provider

Commands:

# opencode
cd packages/opencode
bun run --conditions=browser ./src/index.ts run --format json --model openai/gpt-5.2-codex \
  "read ALL typescript files in src/session and src/provider directories"

# Codex CLI (MCP disabled)
cd /Users/skyline23/Downloads/opencode
codex exec "read ALL typescript files in packages/opencode/src/session and packages/opencode/src/provider directories"

Exact measurements (from request JSON):

  • opencode request file: /tmp/opencode-req-1768823713888-15.json
  • Codex request file: /tmp/codex-request-1768824736636.json
Metric opencode Codex CLI Ratio
Request size 421,653 bytes 248,443 bytes 1.70x
Input payload size 334,249 bytes 139,646 bytes 2.39x
Input items 66 23 2.87x
Tool calls 29 7 4.14x
Tool output total 297,806 bytes 90,984 bytes 3.27x
Max single output 61,890 bytes 40,156 bytes 1.54x
Turn 1 time 300s+ (timeout) 144s 2x+

3) Test B — Truncation comparison (same file)

Task: read the ENTIRE prompt.ts (60,975 bytes)

Commands:

# opencode
cd packages/opencode
bun run --conditions=browser ./src/index.ts run --format json --model openai/gpt-5.2-codex \
  "read the ENTIRE content of src/session/prompt.ts"

# Codex CLI (MCP disabled)
cd /Users/skyline23/Downloads/opencode
codex exec "read the ENTIRE content of packages/opencode/src/session/prompt.ts and find all function names"

Exact measurements:

  • opencode output length: 61,890 bytes (message: “Output truncated at 51200 bytes”)
  • Codex output length: 24,155 bytes (message: “…9244 tokens truncated…”)
Metric opencode Codex CLI Ratio
Truncation policy 50KB bytes 10,000 tokens -
Output size 61,890 bytes 24,155 bytes 2.56x

4) Test C — Tool access strategy (line count)

Task: line counts for llm.ts, processor.ts, prompt.ts

Commands:

# opencode
cd packages/opencode
bun run --conditions=browser ./src/index.ts run --format json --model openai/gpt-5.2-codex \
  "read src/session/llm.ts, src/session/processor.ts, src/session/prompt.ts and tell me line counts"

# Codex CLI (MCP disabled)
cd /Users/skyline23/Downloads/opencode
codex exec "read packages/opencode/src/session/llm.ts, packages/opencode/src/session/processor.ts, packages/opencode/src/session/prompt.ts and tell me line counts"

Exact measurements:

  • opencode output total: 93,066 bytes
  • Codex output total: 8,418 bytes
Metric opencode Codex CLI Ratio
Approach read full files wc -l shell -
Output total 93,066 bytes 8,418 bytes 11.6x
Request size 193,620 bytes 53,130 bytes 3.64x
Tool calls 5 7 0.71x
Time 36s 58s 0.62x

5) Root causes (data‑backed)

  1. Tool access strategy

    • opencode often reads full file contents
    • Codex uses shell summaries (wc -l, rg, ls)
      → output can be 11.6x larger for the same task
  2. Truncation policy difference

    • opencode: 50KB byte‑based
    • Codex: 10,000 token‑based
      → same file output 2.56x larger in opencode
  3. Prompt parity gap

    • opencode Codex prompt: packages/opencode/src/session/prompt/codex.txt + codex_header.txt
    • Codex CLI prompt: codex-rs/core/gpt-5.2-codex_prompt.md
    • opencode prompt biases toward Read/Glob/Write tools; Codex prompt prefers fast shell discovery
      → tool usage pattern divergence

6) Recommendations (core)

High impact / low effort

  1. Switch truncation to token‑based (10k tokens)
    • Matches Codex
    • Measured 2.56x output size reduction
  2. Improve compaction trigger
    • Trigger before overflow
    • Consider token‑based thresholds

High impact / medium effort

  1. Prefer shell summaries for simple queries
    • line counts, file lists, grep → wc -l, rg, ls
  2. Align prompt with Codex CLI
    • strengthen shell‑first guidance
  3. Multi‑file read path
    • reduce tool call counts
  4. LLM‑based compaction
    • Codex‑style summary replacement

P.S. I double‑checked and confirmed that opencode is already sending session_id. Sorry for the earlier confusion on my side.
I’ll share concrete benchmark numbers about previous_response_id for that as soon as I have them ready.
As a fan of open code who wants to use codex well in opencode, Thanks again.
Can I prepare PR for improvements that I recommended?

@Skyline-23 commented on GitHub (Jan 19, 2026): @rekram1-node If we are not going to use `previous_response_id`, then we have to reduce the client‑side payload itself; otherwise performance will continue to degrade as the session grows. I ran direct, same‑model comparisons between opencode and Codex CLI (MCP disabled) and captured the actual request JSON payloads to measure sizes and counts. Below is the full test design and exact measurements. --- ## 1) Test design and measurement method ### (1) Request capture - opencode: captured request bodies to `/tmp/opencode-req-*.json` - Codex CLI: captured request bodies to `/tmp/codex-request-*.json` - All measurements computed directly from those JSON files ### (2) Measurement commands ``` # request file size stat -f%z /tmp/opencode-req-*.json stat -f%z /tmp/codex-request-*.json # input payload size jq '.body.input | tojson | length' <file> # input item count jq '.body.input | length' <file> # tool call count jq '[.body.input[] | select(.type == "function_call")] | length' <file> # tool output total size jq '[.body.input[] | select(.type == "function_call_output") | .output | length] | add' <file> # max output size jq '[.body.input[] | select(.type == "function_call_output") | .output | length] | max' <file> ``` ### (3) Files/paths used in tests - Directory: `packages/opencode/src/session` - Directory: `packages/opencode/src/provider` - File: `packages/opencode/src/session/prompt.ts` - File: `packages/opencode/src/session/llm.ts` - File: `packages/opencode/src/session/processor.ts` --- ## 2) Test A — Large file read (initial repro) Task: read all TS files in `packages/opencode/src/session` + `packages/opencode/src/provider` Commands: ``` # opencode cd packages/opencode bun run --conditions=browser ./src/index.ts run --format json --model openai/gpt-5.2-codex \ "read ALL typescript files in src/session and src/provider directories" # Codex CLI (MCP disabled) cd /Users/skyline23/Downloads/opencode codex exec "read ALL typescript files in packages/opencode/src/session and packages/opencode/src/provider directories" ``` Exact measurements (from request JSON): - opencode request file: `/tmp/opencode-req-1768823713888-15.json` - Codex request file: `/tmp/codex-request-1768824736636.json` | Metric | opencode | Codex CLI | Ratio | | ------------------ | --------------- | ------------- | ----- | | Request size | 421,653 bytes | 248,443 bytes | **1.70x** | | Input payload size | 334,249 bytes | 139,646 bytes | **2.39x** | | Input items | 66 | 23 | **2.87x** | | Tool calls | 29 | 7 | **4.14x** | | Tool output total | 297,806 bytes | 90,984 bytes | **3.27x** | | Max single output | 61,890 bytes | 40,156 bytes | **1.54x** | | Turn 1 time | 300s+ (timeout) | 144s | **2x+** | --- ## 3) Test B — Truncation comparison (same file) Task: read the ENTIRE `prompt.ts` (60,975 bytes) Commands: ``` # opencode cd packages/opencode bun run --conditions=browser ./src/index.ts run --format json --model openai/gpt-5.2-codex \ "read the ENTIRE content of src/session/prompt.ts" # Codex CLI (MCP disabled) cd /Users/skyline23/Downloads/opencode codex exec "read the ENTIRE content of packages/opencode/src/session/prompt.ts and find all function names" ``` Exact measurements: - opencode output length: **61,890 bytes** (message: “Output truncated at 51200 bytes”) - Codex output length: **24,155 bytes** (message: “…9244 tokens truncated…”) | Metric | opencode | Codex CLI | Ratio | | ----------------- | ------------ | ------------- | ----- | | Truncation policy | 50KB bytes | 10,000 tokens | - | | Output size | 61,890 bytes | 24,155 bytes | **2.56x** | --- ## 4) Test C — Tool access strategy (line count) Task: line counts for `llm.ts`, `processor.ts`, `prompt.ts` Commands: ``` # opencode cd packages/opencode bun run --conditions=browser ./src/index.ts run --format json --model openai/gpt-5.2-codex \ "read src/session/llm.ts, src/session/processor.ts, src/session/prompt.ts and tell me line counts" # Codex CLI (MCP disabled) cd /Users/skyline23/Downloads/opencode codex exec "read packages/opencode/src/session/llm.ts, packages/opencode/src/session/processor.ts, packages/opencode/src/session/prompt.ts and tell me line counts" ``` Exact measurements: - opencode output total: **93,066 bytes** - Codex output total: **8,418 bytes** | Metric | opencode | Codex CLI | Ratio | | ------------ | --------------- | ------------ | ----- | | Approach | read full files | `wc -l` shell | - | | Output total | 93,066 bytes | 8,418 bytes | **11.6x** | | Request size | 193,620 bytes | 53,130 bytes | **3.64x** | | Tool calls | 5 | 7 | 0.71x | | Time | 36s | 58s | 0.62x | --- ## 5) Root causes (data‑backed) 1. **Tool access strategy** - opencode often reads full file contents - Codex uses shell summaries (`wc -l`, `rg`, `ls`) → output can be **11.6x larger** for the same task 2. **Truncation policy difference** - opencode: 50KB byte‑based - Codex: 10,000 token‑based → same file output **2.56x larger** in opencode 3. **Prompt parity gap** - opencode Codex prompt: `packages/opencode/src/session/prompt/codex.txt` + `codex_header.txt` - Codex CLI prompt: `codex-rs/core/gpt-5.2-codex_prompt.md` - opencode prompt biases toward Read/Glob/Write tools; Codex prompt prefers fast shell discovery → tool usage pattern divergence --- ## 6) Recommendations (core) ### High impact / low effort 1. **Switch truncation to token‑based (10k tokens)** - Matches Codex - Measured **2.56x output size reduction** 2. **Improve compaction trigger** - Trigger before overflow - Consider token‑based thresholds ### High impact / medium effort 1. **Prefer shell summaries for simple queries** - line counts, file lists, grep → `wc -l`, `rg`, `ls` 2. **Align prompt with Codex CLI** - strengthen shell‑first guidance 3. **Multi‑file read path** - reduce tool call counts 4. **LLM‑based compaction** - Codex‑style summary replacement --- P.S. I double‑checked and confirmed that opencode is already sending `session_id`. Sorry for the earlier confusion on my side. I’ll share concrete benchmark numbers about `previous_response_id` for that as soon as I have them ready. As a fan of open code who wants to use codex well in opencode, Thanks again. Can I prepare PR for improvements that I recommended?
Author
Owner

@rekram1-node commented on GitHub (Jan 19, 2026):

I wonder if latest release has any improvements for you, multiple people said it was faster

@rekram1-node commented on GitHub (Jan 19, 2026): I wonder if latest release has any improvements for you, multiple people said it was faster
Author
Owner

@Skyline-23 commented on GitHub (Jan 20, 2026):

I think latest release effect a little bit faster but I feel problem not solved.....
and the benchmark was tested on dev branch, not in the .25 version

@Skyline-23 commented on GitHub (Jan 20, 2026): I think latest release effect a little bit faster but I feel problem not solved..... and the benchmark was tested on dev branch, not in the .25 version
Author
Owner

@Skyline-23 commented on GitHub (Jan 20, 2026):

@rekram1-node
I reran a 3‑run benchmark on dev vs Codex CLI and published a reproducible script + Codex logging patch instructions in a gist. If you run the gist, you should see the same numbers.

Gist (script + README)
https://gist.github.com/Skyline-23/70a9a3366003705f0d626c9b79b700a7

  • bench-dev-vs-codex.sh
    • Runs A/B/C scenarios 3x
    • Captures opencode + Codex requests to /tmp/*-request-*.json
    • Writes /tmp/bench-results.csv
  • bench-dev-vs-codex-README.md
    • Codex CLI request logging patch (transport.rs)
    • cargo rebuild steps
    • run instructions / notes

Latest 3‑run averages (dev vs Codex, MCP off)

A) Large file read

  • opencode: 110.60s, req 110,428B, input 31,217B, items 83.67, calls 38.33, output 4,786B, max 1,811B
  • Codex: 166.12s, req 361,206B, input 336,499B, items 85.00, calls 32.00, output 265,068B, max 29,490B

B) Full prompt.ts read

  • opencode: 110.11s, req 159,949B, input 83,560B, items 9.00, calls 2.67, output 71,011B, max 61,763B
  • Codex: 32.51s, req 97,450B, input 77,071B, items 18.67, calls 5.33, output 62,488B, max 16,554B

C) Line counts

  • opencode: 30.99s, req 151,480B, input 74,893B, items 13.00, calls 4.67, output 61,876B, max 41,245B
  • Codex: 15.33s, req 30,525B, input 10,541B, items 10.00, calls 2.00, output 560B, max 349B

Observed pattern

  • Higher tool‑call counts correlate with slower opencode runs (A/C).
  • Large max outputs (B/C) also correlate with higher opencode latency.
  • Overall, payload growth (tool calls + output size) still appears to be the main driver of slowdown.

I’m planning to split fixes into 3 PRs

  1. Switch truncation to token‑based (10k tokens)

    • Match Codex
    • Reduce max output size
  2. Shell‑first / tool usage strategy

    • Prefer shell for line counts, file lists, grep
    • Reduce unnecessary full‑file reads
  3. Compaction trigger / multi‑read improvements

    • Trigger earlier than overflow
    • Reduce tool‑call explosion
@Skyline-23 commented on GitHub (Jan 20, 2026): @rekram1-node I reran a **3‑run benchmark on dev vs Codex CLI** and published a reproducible script + Codex logging patch instructions in a gist. If you run the gist, you should see the same numbers. **Gist (script + README)** https://gist.github.com/Skyline-23/70a9a3366003705f0d626c9b79b700a7 - `bench-dev-vs-codex.sh` - Runs A/B/C scenarios 3x - Captures opencode + Codex requests to `/tmp/*-request-*.json` - Writes `/tmp/bench-results.csv` - `bench-dev-vs-codex-README.md` - Codex CLI request logging patch (`transport.rs`) - cargo rebuild steps - run instructions / notes --- ## Latest 3‑run averages (dev vs Codex, MCP off) **A) Large file read** - opencode: **110.60s**, req **110,428B**, input **31,217B**, items **83.67**, calls **38.33**, output **4,786B**, max **1,811B** - Codex: **166.12s**, req **361,206B**, input **336,499B**, items **85.00**, calls **32.00**, output **265,068B**, max **29,490B** **B) Full prompt.ts read** - opencode: **110.11s**, req **159,949B**, input **83,560B**, items **9.00**, calls **2.67**, output **71,011B**, max **61,763B** - Codex: **32.51s**, req **97,450B**, input **77,071B**, items **18.67**, calls **5.33**, output **62,488B**, max **16,554B** **C) Line counts** - opencode: **30.99s**, req **151,480B**, input **74,893B**, items **13.00**, calls **4.67**, output **61,876B**, max **41,245B** - Codex: **15.33s**, req **30,525B**, input **10,541B**, items **10.00**, calls **2.00**, output **560B**, max **349B** --- ### Observed pattern - **Higher tool‑call counts correlate with slower opencode runs** (A/C). - **Large max outputs (B/C)** also correlate with higher opencode latency. - Overall, payload growth (tool calls + output size) still appears to be the main driver of slowdown. --- ## I’m planning to split fixes into 3 PRs 1) **Switch truncation to token‑based (10k tokens)** - Match Codex - Reduce max output size 2) **Shell‑first / tool usage strategy** - Prefer shell for line counts, file lists, grep - Reduce unnecessary full‑file reads 3) **Compaction trigger / multi‑read improvements** - Trigger earlier than overflow - Reduce tool‑call explosion
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#6577