Skip to content

feat(sidecar): unify web-search and vision sidecar selection (auth slot + picker/probe filters) #2188

Description

@lidge-jun

Why

웹서치 사이드카와 비전 사이드카가 백엔드를 openai | anthropic 두 칸으로만 나누고, "Codex 전체 / Claude 전체"를 후보로 펼친다. 그 전제는 이미 깨져 있다.

이 이슈가 #414 #415 #1616 #1937을 대체한다. 백엔드를 Exa/Zen/Doubao로 하나씩 더하는 방식이 아니라, 선택 규칙을 먼저 고친다.

Auth (전역)

구현은 전역 두 플래그로 시작한다. 이름은 구현에서 isCodexAuth / isAnthropicAuth로 고정한다.

현재 코드에 이미 조각이 있다. 한곳으로 모은다.

  • Codex/ChatGPT: listOpenAiForwardSidecarCandidates (src/providers/openai-sidecar.ts) + forward authMode + 로그인된 ChatGPT 계정. planWebSearch openai 분기는 openAiSidecar가 없으면 계획이 없다 (src/web-search/index.ts:192-193).
  • Anthropic: findAnthropicSidecarProvider / findAnthropicVisionProvideradapter === "anthropic" + authMode === "oauth" + active account needsReauth !== true (src/web-search/index.ts:87-96, src/vision/index.ts:220-226).

isCodexAuth === true이면 gpt-5.6-luna는 모델 설정/피커에서 꺼져 있어도 웹서치·비전 후보에 남긴다. isAnthropicAuth === true이면 claude-haiku-4-5(현 baseline)도 같다.

지금 비전 쪽 baseline은 src/vision/eligibility.ts:37-40BASELINE_VISION_MODELS다 (openai: gpt-5.6-luna, anthropic: claude-haiku-4-5). 웹서치 기본 모델은 src/web-search/index.ts:14-16 (gpt-5.6-luna / claude-sonnet-5). 웹서치 Anthropic 기본값을 Haiku로 맞출지, Sonnet을 유지할지는 구현 PR에서 정하되, auth만으로 여는 고정 슬롯은 Luna와 Haiku다.

웹서치 사이드카

선행: 프로바이더 × 프로토콜 조사

아무 채팅 모델이나 webSearchSidecar.backend에 넣지 않는다. 서버가 검색을 실행하는 도구/엔드포인트가 있는 경우만 후보가 된다.

2026-08-20 조사로 확인한 후보군 (라이브 프로브 전, 문서 기준):

후보 프로토콜 도구/엔드포인트 비고
ChatGPT / Codex (현 openai 백엔드) Responses { type: "web_search" } 이미 src/web-search/executor.ts{baseUrl}/responses로 보낸다. Codex CLI는 cached/live web_search.
Claude (현 anthropic 백엔드) Messages web_search_20250305 / 최신 web_search_20260209 src/web-search/anthropic-executor.ts. Bedrock에는 없음.
Gemini Gemini / Interactions google_search (구 google_search_retrieval) Grounding with Google Search. 인용/groundingMetadata. API 키. 검색+다른 툴 동시 제한이 문서에 있음.
xAI Grok Responses { type: "web_search" } docs.x.ai/developers/tools/web-search. 옛 Live Search는 2026-01 deprecate. allowed_domains / excluded_domains.
OpenCode Zen / opencode-go Responses hosted web_search #1616이 2026-08-13에 POST …/zen/go/v1/responses + web_search_call 확인. ChatGPT 쿼터 안 씀.
Exa 등 전용 검색 벤더 자체 Search API 검색 JSON → SidecarOutcome 매핑 #414. LLM이 아님. 프로브 대상은 "호스트된 검색 도구를 가진 LLM"과 별선.

이 표는 후보일 뿐 구현 허가가 아니다. 라이브 프로브가 성공하고, 실행 로직이 들어온 뒤에만 active다.

거름망 (순서 고정)

  1. Codex 피커에 나타나기로 한 모델.
    피커 집합은 visibleNativeSlugs / desktopVisibleNativeSlugs (src/codex/catalog/metadata.ts:331, :371)와 관리 UI의 listManagementModelRows (src/server/management/model-rows.ts:50)다. disabledModels에 가려진 줄은 여기서 탈락한다. 예외는 위 Luna/Haiku auth 슬롯뿐이다.
  2. 라이브 프로브가 통과하고, 이 레포에 실행 로직이 들어온 active 모델만.
    문서에 도구가 있다고 피커에 올리지 않는다. Gemini google_search, Grok web_search, Zen hosted web_search는 각각 프로브 + executor가 생긴 뒤에만 2번 망을 통과한다.

GUI에서 설정 가능한 웹서치 사이드카 모델 = 1 ∩ 2 (+ auth 시 Luna/Haiku). CLI 커맨드도 같은 집합을 쓴다.

개편이 필요한 현재 로직

  • OcxWebSearchSidecarConfig.backend"openai" | "anthropic"만 받는다 (src/types/config.ts:787-796). resolveSidecarBackend는 explicit anthropic이 아니면 무조건 openai (src/web-search/index.ts:104-108). types 주석은 "unset이면 anthropic 우선"인데 코드와 어긋난다.
  • 실행기도 두 개다. runWebSearch (ChatGPT forward /responses)와 runAnthropicWebSearch. keyed/Gemini/Grok 경로가 없다.
  • 라우티드 프로바이더의 hosted web_search는 파서에서 걷어지고 사이드카로 치환된다. 그 "Codex 전체 / Claude 전체 중 하나를 빌린다"는 모델이 개편 대상이다.
  • 관리 API는 PUT으로 webSearch.model 문자열을 거의 그대로 넣는다 (src/server/management/config-routes.ts:604-606). 비전처럼 거절 게이트가 없다.

비전 사이드카

프로브 없음. 거름망만.

  1. Codex 피커에 나타나기로 한 모델 — 웹서치 1번과 같은 집합 (listManagementModelRows / visibleNativeSlugs). auth 시 Luna/Haiku는 여기 없어도 남긴다.
  2. text-only를 비전 로직에서 제외.
    이미 조각이 있다. isModelTextOnly (src/vision/index.ts:29-36)는 noVisionModels이거나 modelInputModalitiesimage가 없으면 true. modelAcceptsImageInput / isVisionEligibleModel (src/vision/eligibility.ts:112-147)은 "text-only로 증명되면 탈락, unknown은 통과"다.
    GUI에 보여줄 값은 1번을 통과한 뒤 2번으로 한 번 더 거른 집합이다. "unknown이라서 통과"를 피커에 펼치지 말고, 피커에 있는 줄만 2번에 넣는다.

개편이 필요한 현재 로직

  • visionEligibleModelOptions (src/vision/eligibility.ts:201-229)는 enabled 백엔드의 전체 catalog candidate + baseline을 펼친다. 사실상 Codex 전체 / Claude 전체다. 피커 가시성과 분리되어 있지 않다.
  • visionCandidateRows (src/server/management/vision-sidecar-options.ts:45-56)는 listManagementModelRows에서 disabled !== true만 본다. 피커 정책과 거의 같지만, auth-only Luna/Haiku와 "피커에 나타나기로 한 모델"을 한 함수로 고정하지 않았다.
  • 디스크라이버 실행은 여전히 vision/describe.ts가 ChatGPT forwardProvider.baseUrl/responses로만 가거나 Anthropic OAuth Messages로만 간다. #1937의 Doubao/volcengine 디스크라이버는 이 이슈의 2번 망을 통과한 뒤에만 후속이다. 이번 이슈는 선택 규칙을 먼저 고친다.
  • resolveVisionBackend는 unset이면 Anthropic credential이 있을 때 anthropic (src/vision/index.ts:229-235). 웹서치 resolveSidecarBackend와 반대다. 전역 isCodexAuth / isAnthropicAuth로 맞춘다.

GUI / CLI

  • GUI: 지금 대시보드 사이드카 칸 (gui + PUT /api/sidecar-settings, config-routes.ts webSearch/vision). 옵션 리스트를 위 거름망 결과만 보여 준다.
  • CLI: 같은 집합을 쓰는 설정 커맨드를 만든다 (예: ocx sidecar web-search …, ocx sidecar vision …). GUI만 열려 있고 CLI가 우회하면 거름망이 아니다.
  • 쓰기 게이트와 제안 리스트를 같은 함수에서 나온다. 비전의 visionDescriberIsProvablyBlind (vision-sidecar-options.ts:94)처럼, 웹서치도 리스트에 없는 모델을 persist하지 않는다. 예외는 auth 슬롯 Luna/Haiku.

하지 않는 것

Acceptance

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew 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