Skip to content

feat(sidecar): OpenCode Zen (opencode.ai/zen/go/v1) as web-search sidecar backend — natively serves hosted web_search, no ChatGPT/Claude quota #1616

Description

@carlosqwqqwq

Area

Proxy and routing · Web-search sidecar

What are you trying to accomplish?

When the main model is routed through a third-party provider, the web-search sidecar currently has only two backends: openai (gpt-mini via the ChatGPT forward path) and anthropic (stored Claude OAuth). Both borrow an account the user may have very little quota on — and when that quota is exhausted, search turns degrade (the exact scenario from #398).

I'd like to point the web-search sidecar at a provider I actually have quota on: OpenCode Zen (https://opencode.ai/zen/go/v1, the built-in "opencode-go" provider), using e.g. deepseek-v4-flash to execute the search — with zero ChatGPT/Claude quota consumption.

What prevents this today?

  • OcxWebSearchSidecarConfig.backend is hardcoded to "openai" | "anthropic" (src/types.ts, src/web-search/index.ts resolveSidecarBackend); there is no keyed/custom-provider option.
  • The hosted web_search tool is unconditionally stripped for routed providers (src/responses/parser.ts buildTools), and the sidecar executor only knows how to POST to the ChatGPT forward endpoint with forwarded OAuth headers (src/web-search/executor.ts runWebSearch).
  • I verified there is no config-only workaround (changing webSearchSidecar.model, disabling the sidecar, or repointing the openai provider's baseUrl all fail — the latter breaks isCanonicalOpenAiForwardProvider).

Key fact: OpenCode Zen natively serves hosted web_search

Unlike a plain OpenAI-compatible chat gateway, OpenCode Zen executes the Responses API's hosted web_search tool server-side. Tested 2026-08-13 with a opencode-go API key (model deepseek-v4-flash):

  • POST https://opencode.ai/zen/go/v1/responses with tools: [{type: "web_search", max_results: 5}] + tool_choice: {type: "web_search"} → 200.
  • The model ran real multi-step searches (web_search_call with search and open_page actions) and returned a summary with source URLs.
  • Streaming emits standard Responses SSE — response.output_text.delta, response.output_text.done, response.completed (plus ping heartbeats) — exactly the event shapes parseSidecarSSE already handles.
  • The gateway reports "cost": "0" for these calls; either way, the spend lands on the user's Zen key, not ChatGPT/Claude.

This is the "provider-native search capability" category of #415 — Zen just isn't on the list there yet. It also fits #414's "decouple which account backs search" goal without adding a dedicated search vendor.

Proposed change (minimal, additive)

Add a third sidecar backend, e.g. backend: "keyed" with provider + model config, that POSTs to the named provider's {baseUrl}/responses with Authorization: Bearer <apiKey> and the same hosted tool + BASE_INSTRUCTION, reusing the existing loop, parseSidecarSSE, and format-result unchanged:

  • src/types.ts — extend OcxWebSearchSidecarConfig (backend: "keyed", provider?: string)
  • src/web-search/executor.ts — add runKeyedWebSearch() (~30 lines, mirrors runWebSearch with Bearer auth)
  • src/web-search/index.ts — planWebSearch keyed branch, resolving a configured key-auth openai-responses provider
  • src/web-search/loop.ts + src/server/responses/core.ts — thread the keyed provider through and dispatch

Roughly 60–80 additive lines; the ChatGPT forward path and anthropic path stay untouched.

Acceptance criteria

  • Config like webSearchSidecar: { backend: "keyed", provider: "opencode-go", model: "deepseek-v4-flash" } makes search runs on the Zen key with no ChatGPT/Claude quota involvement.
  • Search cells, citations/sources, and the loop behavior match the existing openai backend.

Related

#398 (original fixed-backend bug), #414 (dedicated search vendors like Exa), #415 (provider-native search, e.g. Gemini Grounding — Zen is a sibling case), #1276 (superseded umbrella; maintainer's note that arbitrary LLMs can't auto-back search is exactly why Zen's hosted tool is special).

Activity

  1. coderabbitai commented on Aug 13, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #652 - feat(providers): add bounded model discovery contract [merged]
    #671 - feat(codex): add exact account routing [merged]
    #1161 - feat(vision): add chat and Google sidecars [open]
    #1529 - fix(codex): keep direct MCP tools visible for routed models [merged]
    #1645 - feat(vision): add chat and Google sidecars [open]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. added
    enhancementNew feature or request
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    toolstool_calls, MCP, web-search / sidecar tools
    on Aug 13, 2026
  3. github-actions commented on Aug 13, 2026

    @github-actions
    Contributor

    Maintainer decision respected

    A maintainer has reopened this issue. The automated closure has been deactivated.

  4. reopened this on Aug 13, 2026
  5. lidge-jun commented on Aug 13, 2026

    @lidge-jun
    Owner

    Accepted as a provider-native web-search sidecar request, with a narrower implementation contract than the proposed generic executor.

    Verified against current dev: OcxWebSearchSidecarConfig.backend permits only "openai" | "anthropic" in src/types.ts:1141, and resolveSidecarBackend can resolve only those two values in src/web-search/index.ts:103. The management endpoint rejects every other backend in src/server/management/config-routes.ts:465. opencode-go exists as a key-auth provider at src/providers/registry.ts:1188 but cannot be selected for search, so your "no config-only workaround" claim reproduces and is not fixed on dev.

    Please do not implement this as an unrestricted backend: "keyed" branch accepting any configured provider. The sidecar sends a provider API key to an outbound endpoint, so selection must fail closed unless the provider is enabled, key-authenticated with a resolvable key, uses the Responses wire, and carries an explicit tested declaration that it supports the hosted web_search tool. Keep redirects disabled/manual as the existing credential-bearing executor does (src/web-search/executor.ts:81), and keep API keys and raw upstream bodies out of logs.

    The change must thread the selected provider through the plan and loop rather than falling back to the OpenAI forward executor: the loop currently dispatches only the Anthropic executor or runWebSearch with a forward provider (src/web-search/loop.ts:653). Add focused tests for provider eligibility, missing/disabled/unresolved credentials, exact Authorization: Bearer request shape, manual redirect handling, SSE text/citation parsing, tool-loop result injection, and confirmation that neither ChatGPT nor Anthropic credentials are selected. Update /api/sidecar-settings, Claude override validation, and the Sidecars documentation, which currently documents only the two existing backends (docs-site/src/content/docs/guides/sidecars.md:11).

    This is a valid capability request, but it crosses an outbound credential and third-party hosted-tool trust boundary. It needs a capability-gated design and a real Zen compatibility capture before implementation.

    DISPOSITION: ACCEPTED

  6. Wibias commented on Aug 16, 2026

    @Wibias
    Contributor

    Triage relationship

    Parent umbrella: #415.

    This issue is the provider-specific OpenCode Zen child under the broader provider-native search sidecar investigation. Keep its own provider evidence and acceptance criteria here.

  7. Wibias commented on Aug 17, 2026

    @Wibias
    Contributor

    [GD] Opened PR #1890 to address this.

  8. self-assigned this
    on Aug 17, 2026
  9. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 44 / 80

    웹검색 사이드카를 ChatGPT/Claude 할당량이 아니라 OpenCode Zen 키로 돌리고 싶다는 요청입니다. Zen의 /zen/go/v1/responses가 hosted web_search를 서버에서 실행한다는 점이 핵심입니다. 일반 LLM에게 검색을 맡기는 요청이 아니라, 이미 호스팅 도구를 제공하는 백엔드입니다.

    현재 dev의 src/types.ts에서 OcxWebSearchSidecarConfig.backend는 "openai" | "anthropic"만 허용합니다. src/web-search/index.ts의 resolveSidecarBackend()와 src/web-search/loop.ts도 그 두 갈래만 봅니다. 실행은 src/web-search/executor.ts의 runWebSearch(ChatGPT forward)와 anthropic-executor입니다. keyed 프로바이더나 opencode-go 분기는 없습니다.

    이슈가 원하는 설정은 webSearchSidecar.backend를 keyed처럼 열고 provider/model을 지정하는 것입니다. 그러면 Authorization Bearer와 기존 parseSidecarSSE 루프를 재사용할 수 있습니다. ChatGPT/Claude 경로는 그대로 두라는 조건은 코드 구조와 맞습니다.

    해결방안: 타입과 resolveSidecarBackend에 세 번째 백엔드를 더하고, 설정된 openai-responses 키 프로바이더의 baseUrl/responses로 POST하면 됩니다. 이슈가 검증한 Zen 이벤트 모양이 기존 파서와 같다면 루프 변경은 작습니다. 임의의 채팅 게이트웨이에 hosted web_search를 가정하면 안 되고, 네이티브 도구를 증명할 수 있는 프로바이더만 열어야 합니다.

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

  10. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 44 / 80 · 유지

    웹서치를 ChatGPT/Claude 말고 OpenCode Zen(opencode-go) 키로 돌리자는 요청. Zen이 hosted web_search를 서버에서 해 줌. backend가 지금 openai | anthropic만 받음.

    유지함. #415 + 비전 사이드카 #1937 이랑 묶음. 사이드카 백엔드를 계정/프로바이더로 여는 같은 설계. 전용 Exa(#414)랑은 다름.

    해결방안: webSearchSidecar.backend: "keyed" + provider/model. ChatGPT/Claude 경로는 그대로. 설계는 #1937/#415 먼저.

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

  11. lidge-jun commented on Aug 20, 2026

    @lidge-jun
    Owner

    이 이슈는 #2188로 합침. 백엔드를 하나씩 더하는 대신, 전역 auth 슬롯 + Codex 피커 거름망 + (웹서치는 라이브 프로브)로 선택 규칙을 먼저 고친다. 후속 구현은 #2188을 보면 됨.

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, plansenhancementNew feature or requesttoolstool_calls, MCP, web-search / sidecar tools

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions