Skip to content

OpenCode Go requests are missing x-opencode-session #3344

Closed as not planned
Closed as not planned

Description

@colthreepv

Client or integration

Codex App

Provider or upstream service

OpenCode Go (opencode-go)

OpenCodex version

2.40.0

Endpoint or capability

OpenCode Go inference requests (/v1/chat/completions)

Current behaviour

On 3 September 2026, I received an email from updates@opencode.ai, subject “Missing OpenCode Go Header.” It says some requests are missing x-opencode-session, identifies their user agent as Bun fetch, and warns that requests without the header may error starting 09/06.

OpenCodex uses Bun for upstream requests and does not appear to send this header.

Expected behaviour

OpenCodex should send x-opencode-session: <stable-id-per-conversation> with OpenCode Go requests.

Minimal redacted request or reproduction

1. Configure OpenCode Go in OpenCodex.
2. Use an opencode-go model from Codex App.
3. Send multiple turns in one task.
4. The provider reports that requests from "Bun fetch" lack x-opencode-session.

Actual response or error

Provider email: requests without x-opencode-session may error starting 09/06.
User agent: Bun fetch

Upstream documentation

No public specification found. This requirement was communicated directly by updates@opencode.ai on 3 September 2026.

Suggested mapping or implementation notes

Send a stable opaque value per conversation, as requested by the provider.

Additional context and attachments

Related: #2160

Checks

  • I searched existing provider and compatibility issues.
  • The request and response were redacted.
  • The expected behaviour is based on an upstream specification or a concrete client requirement.

Activity

  1. github-actions commented on Sep 3, 2026

    @github-actions
    Contributor

    Issue reopened

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

  2. lidge-jun commented on Sep 3, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 74 / 80

    설명

    이 이슈는 OpenCode Go(opencode-go)로 나가는 요청에 x-opencode-session 헤더가 없어서, 업스트림이 09/06부터 그 요청을 거절할 수 있다는 경고다. 보고자(colthreepv)는 2026-09-03에 updates@opencode.ai에서 "Missing OpenCode Go Header" 메일을 받았고, User-Agent가 Bun fetch로 찍혔다고 한다. OpenCodex는 업스트림 fetch에 Bun을 쓰므로, 메일 대상이 이 프로젝트(또는 같은 런타임을 쓰는 다른 프록시)일 가능성이 높다.

    지금 dev HEAD는 b15cbb2c3 (package 2.41.0)이다. src/providers/registry.ts의 opencode-go 줄(대략 1572행부터)을 보면 baseUrl은 https://opencode.ai/zen/go/v1, adapter는 openai-chat(일부 모델만 modelWireDefaults로 openai-responses)이고, staticHeaders가 없다. 반대로 같은 파일의 opencode-free는 #2160에서 이미 User-Agent: opencode와 x-opencode-client: desktop를 staticHeaders에 넣었다. 헤더는 mergeRegistryStaticHeaders(registry.ts)가 router.ts resolve 시점에 합치고, openai-chat.ts / openai-responses.ts가 provider.headers로 업스트림에 실어 보낸다. 저장소 전체를 찾아도 x-opencode-session 문자열은 코드에 없고, devlog/_plan/260820_bug_pr_backlog_consolidation/080_residual_dispositions.md에만 "당시 429 수정에는 불필요 / 대화 파생 세션 ID는 프라이버시 이슈라 별도 증거가 필요"라고 적어 두고 일부러 안 넣었던 흔적만 있다. 그 판단은 그 시점의 opencode-free 429에는 맞았지만, 지금은 업스트림이 Go에 대해 헤더를 요구한다고 직접 통보한 상태라 전제가 바뀌었다.

    왜 중요한가. opencode-go는 featured 키 프로바이더이고 Codex App에서 많이 쓴다. 09/06이 지나면 "가끔 429"가 아니라 요청 자체가 깨질 수 있다. 오늘은 09/03(KST)이라 남은 시간이 짧다. staticHeaders에 고정 문자열만 넣는 방식은 opencode-free의 User-Agent 수정과는 성격이 다르다. 메일이 요구하는 값은 대화마다 안정적인 opaque id이기 때문이다. 고정 UUID 하나를 전 요청에 붙이면 "헤더는 있다"만 만족하고, 세션 단위 추적은 사실상 무력화된다. 대화마다 다른 값을 넣으려면 registry 정적 헤더만으로는 부족하고, 요청 경로에서 conversation/thread 정체성을 읽어 헤더를 채우는 동적 처리가 필요하다. 이미 비슷한 패턴이 있다. src/providers/xai-transport.ts의 x-grok-conv-id / x-grok-session-id affinity, src/adapters/kiro-wire.ts의 stableConversationId가 그 예다. OmniRoute(open-sse/executors/opencode.ts)도 예전에 conversation 파생 또는 UUID로 x-opencode-session을 보낸다고 우리 plan 문서에 기록돼 있다.

    공개 스펙 URL은 아직 없다(이슈에도 "No public specification found"). 그래서 구현 전에 확인할 것은 (1) 값이 정말 per-conversation opaque여야 하는지, (2) Chat(/v1/chat/completions)만이 아니라 Responses 경로(gpt-5.6-luna, muse-spark-*의 modelWireDefaults)에도 같은 헤더가 필요한지, (3) opencode-zen / opencode-free에도 같은 규칙이 곧 적용되는지다. 그래도 "메일 + Bun fetch + 09/06"이면 우선순위는 높다. types.ts/config.ts 분할 캠페인과는 무관한 프로바이더 호환 핫픽스라서, 그 분할에 묶지 말고 독립 PR로 빠르게 넣는 편이 맞다.

    라인 - 문제

    src/providers/registry.ts opencode-go 엔트리 - staticHeaders가 없어 User-Agent/x-opencode-session을 registry 기본값으로 실어 보내지 않는다. 업스트림에는 Bun 기본 UA만 보일 수 있다.
    x-opencode-session (저장소 전체) - 심볼/문자열이 코드에 없다. 09/06 강제 전에 헤더를 붙이는 경로가 아직 없다.
    src/adapters/openai-chat.ts openAIChatTransport - provider.headers만 합친다. 대화별 세션 ID를 여기서(또는 상위 resolve에서) 채우는 로직이 없다.
    src/adapters/openai-responses.ts outbound headers - Go의 Luna/Muse Spark Responses 경로에도 동일 헤더가 필요할 수 있는데, 지금 코드는 대화 세션 헤더를 넣지 않는다.
    devlog/.../080_residual_dispositions.md - #2160 때 x-opencode-session을 의도적으로 제외했다. 그 전제(증거 없음)는 이번 업스트림 메일로 깨졌으니, Go 쪽은 재검토가 필요하다.
    관련 #2160 - opencode-free의 UA/x-opencode-client만 다뤘고 Go 세션 헤더는 범위 밖이었다. 이 이슈의 직접 수정이 아니다.

    메인테이너의 판단이 필요한 지점

    • 세션 ID 소스: Codex conversation/thread id를 해시·재사용할지, 프록시가 opaque UUID를 발급해 _providerContinuation에 넣을지.
    • 적용 범위: opencode-go만 먼저 할지, opencode-zen/opencode-free까지 같은 헤더를 미리 넣을지.
    • 고정 헤더 vs 동적 헤더: 임시로 프로세스/설치 단위 고정값을 넣어 09/06 거절만 막을지, 처음부터 per-conversation으로 갈지.
    • 메일 원문/스펙: 가능하면 updates@opencode.ai 요구사항(필수 여부, 값 형식, Chat vs Responses)을 이슈에 붙여 재현 기준을 고정할지.

    너의 추천

    help wanted보다 우선 핫픽스로 본다. opencode-go 요청(Chat + 해당 Responses 모델)에 per-conversation(또는 최소한 per-task) opaque x-opencode-session을 붙이는 작은 PR을 09/06 전에 dev에 랜딩하자. 구현은 xai-transport affinity / kiro-wire stableConversationId 패턴을 참고하고, registry staticHeaders만으로는 부족하니 요청 경로에서 동적으로 넣자. 공개 스펙이 없어도 메일 데드라인은 실재하니, 값 형식은 opaque UUID로 시작하고 업스트림 확인이 오면 조정하면 된다. 중복 이슈는 없고 types 분할에도 묶지 말 것.

    이 댓글은 grok-bot이 작성했습니다

  3. matheussilva421 commented on Sep 3, 2026

    @matheussilva421

    Client or integration

    Codex App through OpenCodex

    Provider or upstream service

    OpenCode Go (opencode-go)

    OpenCodex version

    2.40.0 — tag and main both resolved to commit 35ff3a462e786bd5efc394dfb1a8a5cc946e454f on 2026-09-03.

    Runtime / OS

    • Windows x64
    • Bun 1.3.14

    Summary

    OpenCodex 2.40.0 does not send x-opencode-session on OpenCode Go inference requests.

    On 2026-09-03, OpenCode emailed that requests identified as “Bun fetch” were missing this header and may start failing on 2026-09-06. The deadline comes from that direct provider notification; I could not find a public specification for the enforcement date.

    The missing header is independently confirmed by:

    1. static inspection of the exact 2.40.0 source; and
    2. a non-billable loopback wire probe using the installed OpenCodex adapter and Bun fetch.

    The official OpenCode client sends its stable session ID as x-opencode-session for OpenCode providers, and the current Zen handler uses the value as its sticky-routing key.

    Current behavior

    The opencode-go registry entry defines the canonical Go endpoint and its wire defaults, but no session header:

    The Chat adapter materializes Content-Type, authorization, router defaults, and provider.headers; it does not derive a session header:

    Provider transport enrichment runs before final wire selection, but currently handles GitHub Copilot and xAI only. All other providers are returned unchanged:

    A repository/source search under src/ finds no x-opencode-session implementation.

    Minimal non-billable reproduction

    I imported buildOpenAIChatPassthroughRequest from the installed 2.40.0 package, replaced only the provider base URL with a Bun loopback server, built an ordinary Chat request, and dispatched it with Bun's native fetch.

    The capture was sanitized to booleans and non-secret values:

    {
      "userAgent": "Bun/1.3.14",
      "hasOpenCodeSession": false,
      "hasAuthorization": true,
      "contentType": "application/json"
    }

    No request reached opencode.ai; no real key, prompt, or billable model was used.

    Expected behavior

    Every OpenCode Go inference request that has a stable conversation identity should include exactly one:

    x-opencode-session: <stable opaque id for this conversation lane>

    The value should:

    • remain stable across turns and retries in the same conversation;
    • differ across unrelated conversations;
    • differ across sibling subagents under the same parent task;
    • not expose a raw Codex thread/session identifier;
    • not be persisted into the user's provider configuration;
    • not leak to non-OpenCode Go destinations.

    Upstream evidence

    The official OpenCode client sends input.sessionID in x-opencode-session, together with its request/project/client metadata, for providers whose IDs start with opencode:

    The current Zen handler reads the header, uses it as stickyId, looks up the sticky provider before provider selection, includes it in metrics, and stores a truncated value in usage records:

    So this is routing/correlation metadata, not only an optional analytics tag.

    Suggested implementation boundary

    The safest location appears to be the existing runtime transport-enrichment stage, before resolveWireProtocolOverride, rather than duplicating logic in each adapter.

    Suggested behavior:

    1. Compute the existing sessionLaneIdFromRequest(req.headers) once. It already combines parent + specific child identity and explicitly avoids collapsing sibling subagents:
    2. Pass that lane into provider transport resolution.
    3. Identify the canonical OpenCode Go destination before the wire override, including aliases such as opencode-go-2. registryEntryForProviderDestination is already used by the quota path for this exact alias/destination problem.
    4. Derive an opaque, domain-separated SHA-256 value from the lane (for example, ocx_ plus 32 hex characters). This mirrors the existing deriveXaiConvId privacy pattern without sending the raw internal ID.
    5. Add the derived value to runtime-only provider.headers, allowing the existing Chat/Responses adapters and explicit wire overrides to carry it.
    6. Preserve an explicitly configured operator header case-insensitively, following the precedent established in PR #2160. A fixed manual value should be documented as sharing affinity across conversations.
    7. If no stable identity exists, do not generate a fresh UUID per request. That would satisfy header presence while defeating session affinity. A promptCacheKey fallback should only be used when it is known not to represent a shared cohort.

    This should not be implemented as a registry staticHeaders value: a global static session ID would merge every conversation into one upstream affinity group. An analogous client bug documents that failure mode: earendil-works/pi #4847.

    Acceptance criteria / tests

    • RED-first unit test: same lane produces the same opaque ID.
    • Different conversations produce different IDs.
    • Same parent + different child thread/session produces different IDs.
    • The generated value contains no raw thread/session identifier.
    • Canonical OpenCode Go and a valid alias receive the header.
    • A noncanonical/lookalike endpoint and unrelated providers do not receive it.
    • A case-variant explicit operator header wins without duplication.
    • Chat and Responses wire requests carry the same conversation value; cover Anthropic too if a supported override can select it.
    • Same-target retries, 429/5xx replay, and key rotation preserve the conversation value.
    • Exported/persisted config does not contain the derived value.
    • Focused provider/router tests, typecheck, full relevant suite, and privacy scan pass.

    Risks / additional context

    • OpenCode issue #46011 reports a recent, model-specific kimi-k2.7-code shard problem where a particular session ID consistently selects a failing replica. This is an upstream sticky-routing defect, not a reason to send a random value or omit a now-required header. A new conversation provides a different affinity key as a temporary workaround.
    • The generated ID is intentionally correlatable within one conversation because that is the header's purpose. Hashing/domain separation limits disclosure of OpenCodex's internal identifiers.
    • No live/billable OpenCode Go request was made for this report.

    Checks

    • Existing issues searched; this updates OpenCode Go requests are missing x-opencode-session #3344 rather than opening a duplicate.
    • Exact OpenCodex 2.40.0 source identity verified.
    • Reproduced locally without contacting the provider.
    • Request evidence is redacted and contains no credential or prompt data.
    • Expected behavior is grounded in the official OpenCode client and Zen handler.
  4. lidge-jun commented on Sep 3, 2026

    @lidge-jun
    Owner

    Closing in favor of #3378, which tracks both OpenCode Go wire-contract defects together.

    Thank you @colthreepv — your report on the missing x-opencode-session header was accurate and reproducible.

    Verified. Confirmed: the opencode-go registry row in src/providers/registry.ts defines no session-header behavior, and x-opencode-session does not appear anywhere under src/.

    This is grouped with the other open opencode-go defect because both have the same cause — a provider-specific wire requirement the adapter does not represent — and fixing them in one pass avoids a second round of the same investigation. #3378 names this issue and credits you.

    Please follow #3378 for the fix.

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

    providerProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reports

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions