Skip to content

Claude Desktop 3P Auto Mode classifier retries after 64-token Anthropic OAuth outputs #545

Closed

Description

@PBJ-2

환경

  • opencodex 2.7.41 (launchd 상주, port 10100)
  • Claude Desktop 3P 모드 (gateway key 방식) + Claude Code 2.1.218~219
  • anthropic provider = Claude OAuth (Pro/Max), Auto Mode classifier 모델 = claude-sonnet-5
  • macOS, Auto Mode(권한 자동판정) 켠 상태

증상

Auto Mode 세션에서 도구 호출마다 Claude Code가 Sonnet 권한 분류 요청을 보내는데, 이 요청이 정확히 output 64토큰에서 max_tokens로 잘리고, 같은 입력으로 최대 5회 연속 반복됩니다. 대시보드에는 502(upstream_server_error)로 쌓이고, 도구 하나 승인에 12~22초씩 걸립니다. 여러 세션/병렬 도구 사용 시 체감 속도가 크게 저하됩니다.

~/.opencodex/usage.jsonl 집계 (한 세션 며칠 누적):

  • status:502, terminalStatus:incomplete, upstreamError:"Upstream incomplete: max_output_tokens", outputTokens:64 → 1,084건
  • 64 미만에서 정상 종료(200) → 143건
  • 동일 입력토큰 연속 클러스터 232개 (길이 5가 112개 — 재시도 상한 도달로 추정)
10:55:28 502 out=64 → 10:55:31 502 → 10:55:34 502 → 10:55:36 502 → 10:55:39 502
10:54:36 502 out=64 → 10:54:38 502 → 10:54:42 200 out=63   ← 태그가 64토큰 안에 닫힌 경우

원인 분석 (Claude Code 바이너리 + opencodex 소스 대조)

Claude Code의 Auto 분류기는 max_tokens 64, stop_sequences: ["</block>"](또는 </severity>), skipSystemPromptPrefix로 짧은 XML 판정을 받는 설계입니다. 64토큰 안에 태그가 안 닫히면 파싱 실패로 같은 요청을 재시도합니다.

Desktop 3P는 gateway key(ocx)라 wantsNativePassthrough()(src/server/claude-messages.ts:91)가 false → Messages→Responses→Messages 이중 번역 경로를 타는데, 이 과정에서 원 요청과 달라지는 점:

  1. identity 블록 강제 삽입 — anthropic OAuth 경로에서 CLAUDE_CODE_SYSTEM_INSTRUCTION을 system 첫 블록에 prepend (src/adapters/anthropic.ts). 원 요청은 skipSystemPromptPrefix를 명시한 분류기 요청이라 1P 대비 프롬프트가 달라짐
  2. thinking/effort 관련 필드가 왕복 변환에서 소실 (실패 1,084건 전부 requestedEffort 부재)
  3. 이중 번역 자체로 인한 프롬프트 형태의 미세 변화

프롬프트가 1P와 달라지니 응답 길이 분포가 밀려 64토큰 상한에 걸리는 빈도가 급증하는 것으로 추정합니다. (1P 쪽 분류 요청은 관측 불가라 실패율 직접 비교는 못 했습니다 — 가설 부분은 검증 환영)

제안

  • A (핵심): anthropic provider로 라우팅되는 claude-* 모델은 gateway key여도 Anthropic body를 왕복 번역 없이 그대로 전달(auth/system 첫 블록 요건만 처리)하는 direct bridge 검토
  • B (완화): inbound system에 이미 Claude Code identity가 있으면 중복 prepend 생략, thinking/effort 필드 보존
  • C (별건): request log가 incomplete/max_output_tokens를 502 upstream_server_error로 표기 (src/server/request-log.ts httpStatusForTerminalStatus) — 실제 HTTP는 200이고 서버 오류가 아니어서 진단에 혼선. 별도 상태/라벨 제안

재현: Desktop 3P + anthropic OAuth 라우팅 + Auto Mode 세션에서 도구 몇 개 실행 → usage.jsonl에서 sonnet/out=64/502 클러스터 확인. 로그 필요하면 제공 가능합니다.

Translated Message

Original language: Korean

Environment

  • opencodex 2.7.41 (running on launchd, port 10100)
  • Claude Desktop 3P mode (using gateway key) + Claude Code 2.1.218~219
  • anthropic provider = Claude OAuth (Pro/Max), Auto Mode classifier model = claude-sonnet-5
  • macOS, Auto Mode (automatic permission determination) enabled

Symptoms

In the Auto Mode session, Claude Code sends a Sonnet permission classification request for each tool call, and this request is cut off exactly at 64 tokens by max_tokens, and is repeated up to 5 times consecutively with the same input. It accumulates 502 (upstream_server_error) on the dashboard, and it takes 12 to 22 seconds to approve a single tool. The perceived speed significantly decreases when using multiple sessions/parallel tools.

~/.opencodex/usage.jsonl aggregation (compiled over several days for one session):

  • status:502, terminalStatus:incomplete, upstreamError:"Upstream incomplete: max_output_tokens", outputTokens:64 → 1,084 occurrences
  • Normal termination (200) below 64 → 143 occurrences
  • Continuous clusters of the same input tokens 232 (length 5 is 112 — estimated due to reaching retry limit)
10:55:28 502 out=64 → 10:55:31 502 → 10:55:34 502 → 10:55:36 502 → 10:55:39 502
10:54:36 502 out=64 → 10:54:38 502 → 10:54:42 200 out=63   ← case where tags close within 64 tokens

Cause Analysis (Comparing Claude Code binary + opencodex source)

The Auto classifier of Claude Code is designed to receive a short XML determination with max_tokens of 64, stop_sequences: ["</block>"] (or </severity>), and skipSystemPromptPrefix. If tags do not close within 64 tokens, it retries the same request due to parsing failure.

Desktop 3P is gateway key (ocx) so wantsNativePassthrough() (src/server/claude-messages.ts:91) returns false → Messages→Responses→Messages double translation path is taken, resulting in differences from the original request:

  1. Forced insertion of identity block — prepends CLAUDE_CODE_SYSTEM_INSTRUCTION to the first block of the system in the anthropic OAuth path (src/adapters/anthropic.ts). The original request is a classifier request explicitly stating skipSystemPromptPrefix, resulting in a different prompt compared to 1P.
  2. Fields related to thinking/effort are lost during round-trip conversion (all 1,084 failed requests lack requestedEffort)
  3. Subtle changes in prompt form due to double translation itself

Due to the difference in prompt from 1P, it is presumed that the frequency of hitting the upper bound of 64 tokens increases drastically. (It is not possible to directly compare failure rates as the classifier requests on the 1P side are not observable — verification of this hypothesis is welcome)

Suggestions

  • A (Core): Consider implementing a direct bridge that transmits claude-* models routed via the anthropic provider without round-trip translation, preserving only the first block requirements of the auth/system.
  • B (Mitigation): If there is already a Claude Code identity in the inbound system, omit duplicate prepend and preserve thinking/effort fields.
  • C (Other): The request log notes incomplete/max_output_tokens as 502 upstream_server_error (src/server/request-log.ts httpStatusForTerminalStatus) — the actual HTTP is 200 and not a server error, leading to confusion in diagnosis. A separate status/label suggestion.

Reproduction: Run a few tools in the session with Desktop 3P + anthropic OAuth routing + Auto Mode → check for sonnet/out=64/502 clusters in usage.jsonl. Logs can be provided if needed.

Activity

  1. changed the title [-]Desktop 3P + Auto Mode: Sonnet 권한 분류기 요청이 64토큰 잘림 후 최대 5회 반복 (이중 번역 경로 영향 추정)[/-] [+]Desktop 3P + Auto Mode: Request for Sonnet Permission Classifier Cuts Tokens at 64 and Repeats Up to 5 Times (Estimating Impact of Double Translation Path)[/+] on Jul 27, 2026
  2. github-actions commented on Jul 27, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: unknown.

  3. Ingwannu commented on Jul 27, 2026

    @Ingwannu
    Owner

    I checked this against the current dev path. Part C is confirmed: a routed Responses turn that ends with response.incomplete / max_output_tokens is translated back to Anthropic stop_reason=max_tokens and the HTTP stream remains successful, but the request logger currently maps every incomplete terminal to 502/upstream_server_error. I will fix that first by retaining the structured incomplete reason, recording max_output_tokens as status 200 with terminalStatus=incomplete, keeping real incomplete failures such as adapter_eof and upstream_stall_timeout at 502, and adding a focused regression test.

    I am not going to implement A or B from the hypothesis alone: the gateway-key direct bridge changes authentication/routing ownership, and the report does not yet include a 1P control or a redacted inbound system/body sample proving duplicate identity or effort loss for the classifier request. After the logging fix lands, please provide one redacted failing request shape plus its corresponding terminal frames if the five-attempt delay remains; that will let us fix the classifier path without guessing.

  4. Ingwannu commented on Jul 27, 2026

    @Ingwannu
    Owner

    The confirmed logging bug is fixed on dev in 7fcaa91. response.incomplete with the structured reason max_output_tokens now records status 200, terminalStatus=incomplete, no upstream_server_error code, and the diagnostic label Output reached the requested token limit. Stall, adapter EOF, content-filter, and unknown incomplete terminals still fail closed. Regression coverage was added in tests/request-log.test.ts. Validation: focused request-log suite 41/41, full pre-push 5,047/5,047, typecheck, GUI lint, privacy gate, and the 131-page docs build all passed.\n\nI am leaving the issue open for the repeated 64-token classifier behavior itself. The direct-bridge and identity/effort hypotheses still need one redacted failing inbound request shape and its terminal frames or a 1P control before we change the auth/routing path.

  5. added
    bugSomething isn't working
    needs-infoWaiting on reporter for a concrete spec or reproduction
    on Jul 27, 2026
  6. PBJ-2 commented on Jul 27, 2026

    @PBJ-2
    Author

    I captured one complete Auto Mode failure sequence on OpenCodex 2.7.41 using a temporary privacy-first structural logger. The attached JSON contains no prompt/system/message text, tool names/descriptions/schemas/arguments/results, credentials, user identifiers, or filesystem paths.

    The capture correlates each inbound request with its terminal result using OpenCodex's requestId.

    Reproduction result

    Claude Desktop 3P Auto Mode sent the same classifier-shaped request five times:

    • model: claude-sonnet-5
    • max_tokens: 64
    • stop_sequences: ["</block>"]
    • thinking.type: disabled
    • system: array, 3 text blocks, 108,391 total characters
    • messages: 2 user messages, array content, 67 text blocks total
    • tools: 0
    • all five requests had the same process-local system equality tag and identical structural shape

    Each request terminated as:

    • event: response.incomplete
    • response.status: incomplete
    • incomplete_details.reason: max_output_tokens
    • output usage: exactly 64 tokens

    OpenCodex 2.7.41 logged each terminal as status 502 / upstream_server_error, although this is the already-identified logger representation issue fixed by 7fcaa91; the important part for the remaining Auto Mode issue is that the classifier output hit the 64-token ceiling five times and the client repeated the same request shape.

    The five attempts took 31.312 seconds from the first request start through the fifth terminal event. The first attempt wrote part of the prompt cache; attempts 2–5 reused the same cached input, which further supports that these were retries of the same classifier input rather than unrelated Sonnet calls.

    Complete redacted evidence JSON
    {
      "schema": "opencodex-issue-545-evidence-v2",
      "capture": {
        "opencodexVersion": "2.7.41",
        "surface": "claude-desktop-3p",
        "privacy": "Allowlisted structural metadata only. No prompt/system/message text, tool names/descriptions/schemas/arguments/results, credentials, user identifiers, or filesystem paths.",
        "correlation": "Each inbound request and terminal summary is joined by requestId."
      },
      "finding": {
        "attemptCount": 5,
        "sameInboundShape": true,
        "elapsedMsFromFirstStartToLastTerminal": 31312,
        "model": "claude-sonnet-5",
        "maxTokens": 64,
        "stopSequences": [
          "</block>"
        ],
        "terminalEventType": "response.incomplete",
        "terminalReason": "max_output_tokens",
        "outputTokensEach": 64
      },
      "attempts": [
        {
          "attempt": 1,
          "requestId": "ocx-ms34xvwg-g",
          "startOffsetMs": 0,
          "inbound": {
            "model": "claude-sonnet-5",
            "resolvedModel": "claude-sonnet-5",
            "maxTokens": 64,
            "stopSequences": [
              "</block>"
            ],
            "thinkingType": "disabled",
            "metadataKeys": [
              "user_id"
            ],
            "hasMetadataUserId": true,
            "hasSystem": true,
            "anthropicBeta": "claude-code-20250219,interleaved-thinking-2025-05-14,mid-conversation-system-2026-04-07",
            "systemEqualityTag": "4606ae41",
            "systemShape": {
              "form": "array",
              "blockCount": 3,
              "blockTypes": {
                "text": 3
              },
              "totalChars": 108391
            },
            "messagesShape": {
              "count": 2,
              "roleCounts": {
                "user": 2
              },
              "contentForms": {
                "array": 2
              },
              "contentBlockTypes": {
                "text": 67
              }
            },
            "toolsShape": {
              "count": 0,
              "typeCounts": {}
            }
          },
          "terminal": {
            "eventType": "response.incomplete",
            "loggedStatus": 502,
            "terminalStatus": "incomplete",
            "reason": "max_output_tokens",
            "durationMs": 6703,
            "closeReason": "terminal",
            "usage": {
              "inputTokens": 71698,
              "outputTokens": 64,
              "cachedInputTokens": 36539,
              "cacheReadInputTokens": 36539,
              "cacheCreationInputTokens": 35157
            }
          }
        },
        {
          "attempt": 2,
          "requestId": "ocx-ms34y12r-h",
          "startOffsetMs": 6707,
          "inbound": {
            "model": "claude-sonnet-5",
            "resolvedModel": "claude-sonnet-5",
            "maxTokens": 64,
            "stopSequences": [
              "</block>"
            ],
            "thinkingType": "disabled",
            "metadataKeys": [
              "user_id"
            ],
            "hasMetadataUserId": true,
            "hasSystem": true,
            "anthropicBeta": "claude-code-20250219,interleaved-thinking-2025-05-14,mid-conversation-system-2026-04-07",
            "systemEqualityTag": "4606ae41",
            "systemShape": {
              "form": "array",
              "blockCount": 3,
              "blockTypes": {
                "text": 3
              },
              "totalChars": 108391
            },
            "messagesShape": {
              "count": 2,
              "roleCounts": {
                "user": 2
              },
              "contentForms": {
                "array": 2
              },
              "contentBlockTypes": {
                "text": 67
              }
            },
            "toolsShape": {
              "count": 0,
              "typeCounts": {}
            }
          },
          "terminal": {
            "eventType": "response.incomplete",
            "loggedStatus": 502,
            "terminalStatus": "incomplete",
            "reason": "max_output_tokens",
            "durationMs": 4443,
            "closeReason": "terminal",
            "usage": {
              "inputTokens": 71698,
              "outputTokens": 64,
              "cachedInputTokens": 71696,
              "cacheReadInputTokens": 71696,
              "cacheCreationInputTokens": 0
            }
          }
        },
        {
          "attempt": 3,
          "requestId": "ocx-ms34y4ia-i",
          "startOffsetMs": 11154,
          "inbound": {
            "model": "claude-sonnet-5",
            "resolvedModel": "claude-sonnet-5",
            "maxTokens": 64,
            "stopSequences": [
              "</block>"
            ],
            "thinkingType": "disabled",
            "metadataKeys": [
              "user_id"
            ],
            "hasMetadataUserId": true,
            "hasSystem": true,
            "anthropicBeta": "claude-code-20250219,interleaved-thinking-2025-05-14,mid-conversation-system-2026-04-07",
            "systemEqualityTag": "4606ae41",
            "systemShape": {
              "form": "array",
              "blockCount": 3,
              "blockTypes": {
                "text": 3
              },
              "totalChars": 108391
            },
            "messagesShape": {
              "count": 2,
              "roleCounts": {
                "user": 2
              },
              "contentForms": {
                "array": 2
              },
              "contentBlockTypes": {
                "text": 67
              }
            },
            "toolsShape": {
              "count": 0,
              "typeCounts": {}
            }
          },
          "terminal": {
            "eventType": "response.incomplete",
            "loggedStatus": 502,
            "terminalStatus": "incomplete",
            "reason": "max_output_tokens",
            "durationMs": 7899,
            "closeReason": "terminal",
            "usage": {
              "inputTokens": 71698,
              "outputTokens": 64,
              "cachedInputTokens": 71696,
              "cacheReadInputTokens": 71696,
              "cacheCreationInputTokens": 0
            }
          }
        },
        {
          "attempt": 4,
          "requestId": "ocx-ms34yalt-j",
          "startOffsetMs": 19057,
          "inbound": {
            "model": "claude-sonnet-5",
            "resolvedModel": "claude-sonnet-5",
            "maxTokens": 64,
            "stopSequences": [
              "</block>"
            ],
            "thinkingType": "disabled",
            "metadataKeys": [
              "user_id"
            ],
            "hasMetadataUserId": true,
            "hasSystem": true,
            "anthropicBeta": "claude-code-20250219,interleaved-thinking-2025-05-14,mid-conversation-system-2026-04-07",
            "systemEqualityTag": "4606ae41",
            "systemShape": {
              "form": "array",
              "blockCount": 3,
              "blockTypes": {
                "text": 3
              },
              "totalChars": 108391
            },
            "messagesShape": {
              "count": 2,
              "roleCounts": {
                "user": 2
              },
              "contentForms": {
                "array": 2
              },
              "contentBlockTypes": {
                "text": 67
              }
            },
            "toolsShape": {
              "count": 0,
              "typeCounts": {}
            }
          },
          "terminal": {
            "eventType": "response.incomplete",
            "loggedStatus": 502,
            "terminalStatus": "incomplete",
            "reason": "max_output_tokens",
            "durationMs": 6960,
            "closeReason": "terminal",
            "usage": {
              "inputTokens": 71698,
              "outputTokens": 64,
              "cachedInputTokens": 71696,
              "cacheReadInputTokens": 71696,
              "cacheCreationInputTokens": 0
            }
          }
        },
        {
          "attempt": 5,
          "requestId": "ocx-ms34yfz8-k",
          "startOffsetMs": 26020,
          "inbound": {
            "model": "claude-sonnet-5",
            "resolvedModel": "claude-sonnet-5",
            "maxTokens": 64,
            "stopSequences": [
              "</block>"
            ],
            "thinkingType": "disabled",
            "metadataKeys": [
              "user_id"
            ],
            "hasMetadataUserId": true,
            "hasSystem": true,
            "anthropicBeta": "claude-code-20250219,interleaved-thinking-2025-05-14,mid-conversation-system-2026-04-07",
            "systemEqualityTag": "4606ae41",
            "systemShape": {
              "form": "array",
              "blockCount": 3,
              "blockTypes": {
                "text": 3
              },
              "totalChars": 108391
            },
            "messagesShape": {
              "count": 2,
              "roleCounts": {
                "user": 2
              },
              "contentForms": {
                "array": 2
              },
              "contentBlockTypes": {
                "text": 67
              }
            },
            "toolsShape": {
              "count": 0,
              "typeCounts": {}
            }
          },
          "terminal": {
            "eventType": "response.incomplete",
            "loggedStatus": 502,
            "terminalStatus": "incomplete",
            "reason": "max_output_tokens",
            "durationMs": 5292,
            "closeReason": "terminal",
            "usage": {
              "inputTokens": 71698,
              "outputTokens": 64,
              "cachedInputTokens": 71696,
              "cacheReadInputTokens": 71696,
              "cacheCreationInputTokens": 0
            }
          }
        }
      ]
    }
  7. Ingwannu commented on Jul 27, 2026

    @Ingwannu
    Owner

    Thanks — this confirms the repeated behavior itself: five structurally identical 64-token classifier requests, each ending in max_output_tokens, with the logging-only misclassification already fixed by 7fcaa911.

    It does not yet establish that OpenCodex created the 108k system payload or lost the stop sequence: your capture is the inbound Anthropic body, where the large system and </block> stop sequence are already present. Current dev maps both max_tokens -> max_output_tokens and stop_sequences -> stop on the internal request, then maps the stop sequence back for an Anthropic provider. Raising the caller's explicit 64-token cap would also change client semantics and is not safe as a generic fix.

    The next useful capture is therefore the redacted outbound provider request for one failed attempt: max_tokens, stop_sequences, system block count/total chars, and whether the short Claude OAuth identity block was prepended. No text contents are needed. That will distinguish a translation loss from the model simply failing to emit </block> within the caller's limit. I am leaving this open under needs-info and will not change the auth/routing path on hypothesis alone.

  8. PBJ-2 commented on Jul 27, 2026

    @PBJ-2
    Author

    I captured the requested Anthropic-provider outbound structure on OpenCodex 2.7.41. The temporary hook ran immediately before JSON.stringify(body) in the Anthropic adapter and stored allowlisted structural scalars only—no prompt/message/system text, tool data, headers, credentials, user identifiers, or filesystem paths.

    Outbound result

    The same classifier sequence produced five outbound Anthropic requests. All five had:

    • model: claude-sonnet-5
    • max_tokens: 64
    • stop_sequences: ["</block>"]
    • system: array, 2 text blocks, 108,457 total characters
    • Anthropic OAuth: enabled
    • Claude OAuth identity block: confirmed as the first system block (exact equality checked in memory; its text was not stored)

    All five corresponding terminal records ended as incomplete / max_output_tokens with exactly 64 output tokens. The first request created the prompt cache; attempts 2–5 read the same 68,090 cached input tokens. Each structural capture occurred 15–26 ms after its matching OpenCodex request start, in the same order, making the correlation unambiguous.

    What this establishes—and what it does not

    This rules out loss of the caller's explicit token cap or stop sequence in the Anthropic provider translation: both survive into the final outbound provider body.

    It does not establish parity with Claude Desktop's native 1P path, and I do not think the remaining behavior can yet be assigned to Claude Desktop or the model alone. In this 3P/OpenCodex path, the inbound capture had 3 system text blocks totaling 108,391 characters, while the final outbound body had 2 system text blocks totaling 108,457 characters. That exact 66-character increase is consistent with OpenCodex collapsing the three inbound blocks into one with two \n\n separators (+4 characters) and prepending the 62-character Claude OAuth identity block as a separate block.

    The repeated truncation is not observed when I use Claude Desktop without OpenCodex/3P. The remaining issue therefore appears specific to the Claude Desktop 3P/OpenCodex compatibility path. Plausible remaining distinctions are:

    1. the native 1P deployment may not invoke this classifier through the same request path; or
    2. the system-block reconstruction/identity prepend in the 3P path may change Sonnet's classifier output enough that it fails to emit </block> within 64 tokens.

    The current capture cannot distinguish those two possibilities. It only shows that max_tokens and stop_sequences are preserved correctly, while the system block structure is not byte/structure-identical to the inbound request.

    OpenCodex 2.7.41 still records these incomplete terminals as status 502; as noted earlier, that is the logging-only representation fixed by 7fcaa91 and is separate from the repeated classifier behavior.

    Privacy-reviewed redacted outbound evidence (5 attempts)
    {
      "capture": "OpenCodex 2.7.41 Anthropic provider outbound structural evidence",
      "privacy": {
        "containsPromptOrMessageText": false,
        "containsSystemText": false,
        "containsToolNamesDescriptionsSchemasArgumentsOrResults": false,
        "containsHeadersCredentialsUserIdentifiersOrFilesystemPaths": false,
        "note": "Only allowlisted structural scalars were captured in memory immediately before JSON serialization for the Anthropic provider."
      },
      "interpretation": {
        "attemptCount": 5,
        "allPreservedCallerMaxTokens64": true,
        "allPreservedStopSequence": true,
        "allSystemBlockCounts": [
          2
        ],
        "allSystemTotalChars": [
          108457
        ],
        "allOAuthIdentityPrepended": true,
        "allTerminalMaxOutputTokensAt64": true,
        "translationLossObserved": false,
        "loggerNote": "OpenCodex 2.7.41 records these incomplete terminals as 502; that logging-only representation is fixed by 7fcaa91."
      },
      "attempts": [
        {
          "attempt": 1,
          "requestId": "ocx-ms39ch40-49",
          "outboundCaptureId": 106,
          "outboundAt": 1785158612660,
          "requestStartedAt": 1785158612640,
          "captureOffsetMs": 20,
          "provider": "anthropic",
          "isOAuth": true,
          "model": "claude-sonnet-5",
          "maxTokens": 64,
          "stopSequences": [
            "</block>"
          ],
          "systemShape": {
            "form": "array",
            "blockCount": 2,
            "blockTypes": {
              "text": 2
            },
            "totalChars": 108457
          },
          "oauthIdentityPrepended": true,
          "terminal": {
            "status": "incomplete",
            "reason": "max_output_tokens",
            "loggerStatus": 502,
            "durationMs": 2997,
            "usage": {
              "inputTokens": 68092,
              "outputTokens": 64,
              "cachedInputTokens": 0,
              "cacheReadInputTokens": 0,
              "cacheCreationInputTokens": 68090
            }
          }
        },
        {
          "attempt": 2,
          "requestId": "ocx-ms39cjfe-4a",
          "outboundCaptureId": 107,
          "outboundAt": 1785158615658,
          "requestStartedAt": 1785158615642,
          "captureOffsetMs": 16,
          "provider": "anthropic",
          "isOAuth": true,
          "model": "claude-sonnet-5",
          "maxTokens": 64,
          "stopSequences": [
            "</block>"
          ],
          "systemShape": {
            "form": "array",
            "blockCount": 2,
            "blockTypes": {
              "text": 2
            },
            "totalChars": 108457
          },
          "oauthIdentityPrepended": true,
          "terminal": {
            "status": "incomplete",
            "reason": "max_output_tokens",
            "loggerStatus": 502,
            "durationMs": 2469,
            "usage": {
              "inputTokens": 68092,
              "outputTokens": 64,
              "cachedInputTokens": 68090,
              "cacheReadInputTokens": 68090,
              "cacheCreationInputTokens": 0
            }
          }
        },
        {
          "attempt": 3,
          "requestId": "ocx-ms39clc3-4b",
          "outboundCaptureId": 108,
          "outboundAt": 1785158618131,
          "requestStartedAt": 1785158618115,
          "captureOffsetMs": 16,
          "provider": "anthropic",
          "isOAuth": true,
          "model": "claude-sonnet-5",
          "maxTokens": 64,
          "stopSequences": [
            "</block>"
          ],
          "systemShape": {
            "form": "array",
            "blockCount": 2,
            "blockTypes": {
              "text": 2
            },
            "totalChars": 108457
          },
          "oauthIdentityPrepended": true,
          "terminal": {
            "status": "incomplete",
            "reason": "max_output_tokens",
            "loggerStatus": 502,
            "durationMs": 2575,
            "usage": {
              "inputTokens": 68092,
              "outputTokens": 64,
              "cachedInputTokens": 68090,
              "cacheReadInputTokens": 68090,
              "cacheCreationInputTokens": 0
            }
          }
        },
        {
          "attempt": 4,
          "requestId": "ocx-ms39cnbs-4c",
          "outboundCaptureId": 109,
          "outboundAt": 1785158620711,
          "requestStartedAt": 1785158620696,
          "captureOffsetMs": 15,
          "provider": "anthropic",
          "isOAuth": true,
          "model": "claude-sonnet-5",
          "maxTokens": 64,
          "stopSequences": [
            "</block>"
          ],
          "systemShape": {
            "form": "array",
            "blockCount": 2,
            "blockTypes": {
              "text": 2
            },
            "totalChars": 108457
          },
          "oauthIdentityPrepended": true,
          "terminal": {
            "status": "incomplete",
            "reason": "max_output_tokens",
            "loggerStatus": 502,
            "durationMs": 1944,
            "usage": {
              "inputTokens": 68092,
              "outputTokens": 64,
              "cachedInputTokens": 68090,
              "cacheReadInputTokens": 68090,
              "cacheCreationInputTokens": 0
            }
          }
        },
        {
          "attempt": 5,
          "requestId": "ocx-ms39coty-4d",
          "outboundCaptureId": 110,
          "outboundAt": 1785158622672,
          "requestStartedAt": 1785158622646,
          "captureOffsetMs": 26,
          "provider": "anthropic",
          "isOAuth": true,
          "model": "claude-sonnet-5",
          "maxTokens": 64,
          "stopSequences": [
            "</block>"
          ],
          "systemShape": {
            "form": "array",
            "blockCount": 2,
            "blockTypes": {
              "text": 2
            },
            "totalChars": 108457
          },
          "oauthIdentityPrepended": true,
          "terminal": {
            "status": "incomplete",
            "reason": "max_output_tokens",
            "loggerStatus": 502,
            "durationMs": 2243,
            "usage": {
              "inputTokens": 68092,
              "outputTokens": 64,
              "cachedInputTokens": 68090,
              "cacheReadInputTokens": 68090,
              "cacheCreationInputTokens": 0
            }
          }
        }
      ]
    }
  9. removed
    needs-infoWaiting on reporter for a concrete spec or reproduction
    on Jul 27, 2026
  10. changed the title [-]Desktop 3P + Auto Mode: Request for Sonnet Permission Classifier Cuts Tokens at 64 and Repeats Up to 5 Times (Estimating Impact of Double Translation Path)[/-] [+]Claude Desktop 3P Auto Mode classifier retries after 64-token Anthropic OAuth outputs[/+] on Jul 27, 2026
  11. Ingwannu commented on Jul 27, 2026

    @Ingwannu
    Owner

    Thanks — this is sufficient to close the evidence gap.

    The capture confirms that OpenCodex preserves both caller controls all the way to Anthropic: max_tokens: 64 and stop_sequences: ["</block>"] are present on every outbound request. The original translation-loss hypothesis is therefore disproven. The 66-character system difference is also accounted for by the required Claude OAuth identity block plus block joining; it is not an unexplained truncation or dropped field.

    What remains is a narrower compatibility issue: Claude Desktop 3P's Auto Mode classifier, routed through Anthropic OAuth, sometimes does not emit its closing tag within the client's explicit 64-token budget and Desktop repeats the classifier request five times. We cannot safely fix that by raising the caller's explicit budget, removing the OAuth identity instruction, or pretending an incomplete response completed.

    I have narrowed the title, removed needs-info, and added provider-compatibility. Leaving it open for a deliberately scoped Desktop-3P/Anthropic classifier solution or an upstream behavior change; it is no longer tracked as a generic Messages↔Responses field-loss bug. The separate 502 logging defect remains fixed on dev by 7fcaa911.

  12. 20 remaining items

  13. added a commit that references this issue on Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't workingplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)providerProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportstoolstool_calls, MCP, web-search / sidecar tools

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions