Skip to content

[Bug] Reasoning effort selected in Codex Desktop is not propagated to routed DeepSeek and GLM models #1100

Closed

Description

@c3right

Client or integration

Codex App

Area

Catalog / models

Summary

When a routed third-party model is selected in Codex Desktop with reasoning effort set to Max, the UI shows Max, but the actual request received by OpenCodex contains no reasoning effort.

The model is routed correctly, but Logs & Debug shows Effort: -, and the raw log contains none of:

  • requestedEffort
  • effectiveEffort
  • reasoningWireField
  • reasoningWireValue

This is reproducible with both DeepSeek and GLM, in direct conversations and in sub-agent paths.

Important nuance: in normal use, both GLM-5.2 Max and DeepSeek V4 Flash Max subjectively appear to have meaningful reasoning depth. This report is therefore about missing propagation/observability and the lack of a verifiable effort guarantee, not a claim that the upstream models definitely run without thinking.

Expected: when Codex Desktop displays Max for a routed model, the inbound Responses request should preserve the selected effort so OpenCodex can map it to the provider wire format and report the effective value.

Actual: the provider/model selection is preserved, but the reasoning effort is absent before the request reaches the provider adapter.

Reproduction

A. Direct DeepSeek conversation

  1. Start OpenCodex and sync routed models into Codex.

  2. Open a new Codex Desktop conversation.

  3. Select deepseek/deepseek-v4-flash.

  4. Select reasoning effort Max.

  5. Send a no-tool prompt such as:

    This is a reasoning effort propagation test.
    Do not call tools. Reply only:
    DIRECT_MAX_PROBE
    
  6. Inspect the request in OpenCodex Logs & Debug.

Observed:

Model: deepseek-v4-flash
Effort: -
Provider: deepseek
Status: 200

The request reports nonzero reasoningOutputTokens, so thinking is enabled, but the selected effort tier cannot be verified.

B. Direct GLM conversation

Provider setup:

  • Custom provider using BigModel.cn Coding Plan
  • Base URL: https://open.bigmodel.cn/api/coding/paas/v4
  • Model: GLM/glm-5.2
  • Adapter: OpenAI-compatible chat

Steps:

  1. Open a new Codex Desktop conversation.
  2. Select GLM/glm-5.2.
  3. Select reasoning effort Max.
  4. Send the same no-tool probe.
  5. Inspect the request in Logs & Debug.

Observed:

Model: glm-5.2
Effort: -
Provider: GLM
Status: 200

Again, no effort-related raw log fields are present.

C. Explicit V1 spawn_agent override

A gpt-5.6-sol Medium parent invoked V1 spawn_agent with:

model = deepseek/deepseek-v4-flash
reasoning_effort = max
fork_context = false

The child was created successfully and routed to DeepSeek without fallback, but the resulting DeepSeek requests again showed Effort: - and no effort-related raw log fields.

D. Custom agent role

A user-level Codex agent role was configured with:

model = "deepseek/deepseek-v4-flash"
model_reasoning_effort = "max"

The role was registered and successfully selected through:

agent_type = deepseek_executor_max
fork_context = false

The role's developer instructions were applied correctly, and the child returned the expected role marker. The model was also correctly routed to DeepSeek, but the request still showed Effort: - with no effort-related raw log fields.

No provider fallback was observed in any reproduction.

Version

@bitkyc08/opencodex@2.10.1

Operating system

Windows 10, build 19045, x64

Provider and model

  • deepseek / deepseek-v4-flash
  • Custom GLM / glm-5.2 using BigModel.cn Coding Plan

Logs or error output

# Direct DeepSeek request
Model: deepseek-v4-flash
Effort: -
Provider: deepseek
Status: 200

# Sanitized raw log excerpt
{
  "model": "deepseek-v4-flash",
  "provider": "deepseek",
  "admissionKind": "loopback",
  "inboundProtocol": "responses",
  "requestedModel": "deepseek/deepseek-v4-flash",
  "resolvedModel": "deepseek-v4-flash",
  "status": 200,
  "routeDecision": {
    "routeKind": "explicit-provider",
    "selected": {
      "provider": "deepseek",
      "model": "deepseek-v4-flash",
      "reason": "explicit-provider-namespace"
    }
  }
}

# Direct GLM request
Model: glm-5.2
Effort: -
Provider: GLM
Status: 200

# Sanitized raw log excerpt
{
  "model": "glm-5.2",
  "provider": "GLM",
  "admissionKind": "loopback",
  "inboundProtocol": "responses",
  "requestedModel": "GLM/glm-5.2",
  "resolvedModel": "glm-5.2",
  "status": 200,
  "routeDecision": {
    "routeKind": "explicit-provider",
    "selected": {
      "provider": "GLM",
      "model": "glm-5.2",
      "reason": "explicit-provider-namespace"
    }
  }
}

# Missing from both request records
requestedEffort
effectiveEffort
reasoningWireField
reasoningWireValue

Screenshots and supporting files

The behavior was reproduced in Codex Desktop and OpenCodex Logs & Debug. Sanitized raw logs are included above. No secrets or complete local paths are included.

Redacted configuration

{
  "opencodexVersion": "2.10.1",
  "client": "Codex Desktop for Windows",
  "subAgentSurface": "v1",
  "providers": {
    "deepseek": {
      "model": "deepseek-v4-flash",
      "adapter": "openai-chat"
    },
    "GLM": {
      "baseUrl": "https://open.bigmodel.cn/api/coding/paas/v4",
      "model": "glm-5.2",
      "adapter": "openai-chat"
    }
  }
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. github-actions commented on Aug 6, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: English.

  2. github-actions commented on Aug 6, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  3. c3right commented on Aug 6, 2026

    @c3right
    Author

    Potentially related upstream Codex issues:

    Our reproduction differs in that opencodex has already generated routed catalog entries and Codex Desktop visibly offers Max, yet the inbound request still reaches opencodex without any effort field for both deepseek/deepseek-v4-flash and GLM/glm-5.2. This may still share the same upstream request-construction gate around model metadata.

  4. added
    bugSomething isn't working
    catalogModel catalog, slugs, visibility, routed entries
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    on Aug 6, 2026
  5. lidge-jun commented on Aug 6, 2026

    @lidge-jun
    Owner

    Investigated this on current dev and against your 2.10.1. Thank you for the four-path reproduction — running the same probe through direct chat, a custom provider, V1 spawn_agent, and a custom agent role is what makes the finding below provable rather than speculative, because all four failing while routing succeeds narrows the cause sharply.

    Your read is correct, and your upstream link openai/codex#30697 is the right one. The trigger, though, is metadata we emit.

    What we found, in the order it matters:

    1. Nothing arrives. Inbound parsing accepts only Responses reasoning.effort (src/responses/schema.ts:126,144 → src/responses/parser.ts:652), and requestedEffort is assigned directly from that parsed value before routing (src/server/responses/core.ts:1379). So Effort: - with no requestedEffort means the field is genuinely absent on the wire, not dropped by us. That holds in 2.10.1 too.

    2. Our request path does not drop it. For the GLM route, the OpenAI-chat adapter maps a parsed effort and writes reasoning_effort plus the wire diagnostics (src/adapters/openai-chat.ts:759,771). For DeepSeek's Responses passthrough, the normalizers strip unsupported summary and context fields but never an effort (src/adapters/openai-responses.ts:171,193). Given an effort, both paths would carry it.

    3. The routed catalog we sync to Codex is internally contradictory. Every routed entry has supports_reasoning_summaries deleted and then defaulted to false (src/codex/catalog/parsing.ts:353 then :266), while supported_reasoning_levels is populated with a full ladder including max (src/codex/catalog/sync.ts:266, src/codex/catalog/effort.ts:150). Generated locally with no network, deepseek/deepseek-v4-flash comes out as supported_reasoning_levels: ["low","high","max","ultra"] with supports_reasoning_summaries: false; GLM/glm-5.2 is the same shape. Native gpt-5.6-sol has the ladder and true.

    That combination is exactly what openai/codex#30697 describes: Codex gates construction of the whole reasoning object on the capability flag, so the picker renders every level in supported_reasoning_levels while the outbound request omits reasoning entirely. The picker showing Max and the wire carrying nothing are consistent with each other under that gate.

    Worth being precise about why that delete exists — it is deliberate, not an oversight. The comment at parsing.ts:352 says routed rows cloned from native templates must not inherit OpenAI-only summary delivery. Reasoning summaries are a different capability from reasoning effort, and we were right not to claim the former for arbitrary providers. The bug is that upstream appears to treat one flag as gating both, so being honest about summaries costs us effort propagation.

    One qualification against overclaiming. The missing effectiveEffort/reasoningWire* fields are not independently decisive for DeepSeek, because the Responses passthrough has no reasoningLog producer and those fields only populate when an adapter supplies one (src/server/request-log.ts:397). requestedEffort is the load-bearing signal. For GLM's chat route, a parsed effort would have produced them.

    On #1057/#1069: that shipped in v2.10.2, after your 2.10.1. It corrected DeepSeek's advertised ladder to what each model honors, but max was already advertised and mapped in 2.10.1, so upgrading will not fix this. Please do not expect it to.

    What would settle it beyond doubt: one sanitized full HTTP body as it arrives at opencodex ingress for a single Max request. If it contains "reasoning":{"effort":"max"}, the defect is ours and we will chase it. If reasoning is absent or null, the upstream gate is confirmed and the fix is on the catalog side. Your existing Logs & Debug raw view should have this; redact anything sensitive.

    Keeping this open as a real defect, not as needs-info — the catalog contradiction is ours regardless of where the final fix lands, and there is currently no test asserting the joint contract that a routed model advertising reasoning levels also carries whatever flag Codex needs to emit reasoning.effort. That gap is on us.

    Your closing nuance was the right instinct, by the way: nonzero reasoningOutputTokens means the providers are thinking at their own defaults, so this is a lost-control and lost-observability problem rather than thinking being off.

  6. added
    upstream-trackingBlocked on an upstream (Codex CLI/Desktop) fix; kept open for discoverability
    on Aug 6, 2026
  7. lidge-jun commented on Aug 6, 2026

    @lidge-jun
    Owner

    Follow-up with something actionable you can try today, plus what landed on our side.

    There is a supported workaround, and it works for your exact provider shape. Set modelSupportsReasoningSummaries for the model in your provider config:

    "GLM": {
      "adapter": "openai-chat",
      "baseUrl": "https://open.bigmodel.cn/api/coding/paas/v4",
      "models": ["glm-5.2"],
      "modelReasoningEfforts": { "glm-5.2": ["low", "medium", "high", "max"] },
      "modelSupportsReasoningSummaries": { "glm-5.2": true }
    }

    I generated the catalog locally with your provider shape, no network, and compared with and without that one key:

    GLM/glm-5.2       summaries=true   levels=low,medium,high,max,ultra
    GLMplain/glm-5.2  summaries=false  levels=low,medium,high,max,ultra
    

    That flag is what Codex gates the whole Responses reasoning object on, so setting it should make your Max selection actually reach the wire. The same applies to a DeepSeek entry you configure yourself.

    Be clear-eyed about what you are asserting when you set it. It tells Codex the model accepts reasoning-summary delivery. For GLM and DeepSeek that is very likely fine, and the field is documented today only as a way to turn summaries off — using it to turn them on is the other half of the same switch. If your endpoint rejects the resulting request shape, that is the signal to take it back out, and I would want to hear about it. Please report back either way: a confirmation that Effort: starts showing a value is exactly the evidence that would close this issue.

    What we changed. Nothing in the request path — the investigation held up, and the effort genuinely is absent before it reaches us. What was missing on our side was any test asserting that the opt-in survives the routed-catalog normalization at all. It survives only because of the order of two calls in src/codex/catalog/sync.ts, and a future reordering would have silently disabled effort propagation for every provider that opted in, with a green suite. That contract is now pinned by three tests, including one that fails if the order is swapped.

    What we deliberately did not change: routed models still default to supports_reasoning_summaries: false. Claiming OpenAI-only summary delivery for every third-party endpoint would trade your problem for a harder one — requests failing at providers that reject the shape, for users who configured nothing. The per-model opt-in above is the honest version of that fix.

    So this stays open, and your upstream links remain the right thread to pull: if Codex gated on a reasoning-specific capability rather than on summaries, the default would not have to be a trade-off at all. If the workaround does not restore effort for you, that would point back at us and I would reopen the request-path investigation.

  8. c3right commented on Aug 7, 2026

    @c3right
    Author

    Tested the documented per-model workaround successfully on Windows with @bitkyc08/opencodex@2.10.2.

    I added only the following opt-in to each existing provider entry (no other provider fields were changed):

    "modelSupportsReasoningSummaries": {
      "glm-5.2": true
    }

    and separately:

    "modelSupportsReasoningSummaries": {
      "deepseek-v4-flash": true
    }

    After closing Codex, running Sync, reopening Codex, and starting fresh requests, reasoning effort propagation was restored for both providers.

    GLM / BigModel Coding Plan

    Provider endpoint:

    https://open.bigmodel.cn/api/coding/paas/v4
    

    Direct GLM requests succeeded with both xhigh and max selected in Codex.

    For max, Logs & Debug showed:

    Model: glm-5.2
    Provider: GLM
    Effort: max (reasoning_effort=max)
    Status: 200
    

    Sanitized raw-log fields:

    {
      "requestedModel": "GLM/glm-5.2",
      "requestedEffort": "max",
      "effectiveEffort": "max",
      "reasoningWireField": "reasoning_effort",
      "reasoningWireValue": "max",
      "resolvedModel": "glm-5.2",
      "status": 200
    }

    xhigh behaved the same way:

    {
      "requestedEffort": "xhigh",
      "effectiveEffort": "xhigh",
      "reasoningWireField": "reasoning_effort",
      "reasoningWireValue": "xhigh",
      "status": 200
    }

    I also tested GLM as a V1 sub-agent from a gpt-5.6-luna parent running at high. Both independently requested child efforts worked:

    • parent luna/high -> child GLM/glm-5.2/max: PASS
    • parent luna/high -> child GLM/glm-5.2/xhigh: PASS

    The child logs again showed the requested/effective/wire effort values and HTTP 200.

    DeepSeek V4 Flash

    Direct deepseek/deepseek-v4-flash with Codex set to Max now shows:

    Model: deepseek-v4-flash
    Provider: DeepSeek
    Effort: max
    Status: 200
    

    Sanitized raw-log fields:

    {
      "requestedModel": "deepseek/deepseek-v4-flash",
      "requestedEffort": "max",
      "resolvedModel": "deepseek-v4-flash",
      "status": 200
    }

    A direct xhigh selection also arrived as:

    {
      "requestedModel": "deepseek/deepseek-v4-flash",
      "requestedEffort": "xhigh",
      "resolvedModel": "deepseek-v4-flash",
      "status": 200
    }

    I then tested DeepSeek as a V1 sub-agent from the same gpt-5.6-luna/high parent, explicitly requesting deepseek/deepseek-v4-flash at max. The child completed successfully and its request showed:

    {
      "requestedModel": "deepseek/deepseek-v4-flash",
      "requestedEffort": "max",
      "resolvedModel": "deepseek-v4-flash",
      "status": 200,
      "usage": {
        "reasoningOutputTokens": 530
      }
    }

    So the workaround is working for both direct conversations and V1 spawn_agent model/effort overrides in my setup.

    One UI/logging difference confirmed

    GLM shows the smaller gray wire-diagnostic line under the effort value, e.g.:

    max
    reasoning_effort=max
    

    DeepSeek does not show that gray secondary line; it only shows max (or xhigh) in the main Effort field. The DeepSeek raw log likewise has requestedEffort but no effectiveEffort / reasoningWireField / reasoningWireValue.

    This matches your earlier explanation that DeepSeek's Responses passthrough has no reasoningLog producer and that requestedEffort is the load-bearing signal there, while GLM's OpenAI-chat adapter produces the additional wire diagnostics.

    No 4xx/provider rejection or other obvious regression was observed during these tests.

  9. 22 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcatalogModel catalog, slugs, visibility, routed entriesproviderProvider adapters, OpenAI-compat presets, upstream API quirks

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions