feat(search): add OpenAI search passthrough#175
Conversation
The Codex CLI's web-search tool POSTs a SearchRequest to `/alpha/search`
and feeds the returned `output` string back to the model. Serve it from
Floway's own configured web-search provider instead of proxying
chatgpt.com.
codex's `commands` is an object keyed by command kind
(`{search_query:[{q}], open:[{ref_id}], find:[{ref_id,pattern}], …}`) —
byte-for-byte the shape the Responses web_search shim already parses. So
extract the protocol-neutral execution engine (command parsing, provider
resolution, search/open/find execution, page cache, IR building, text
rendering, domain filtering) out of the Responses shim into a shared
tools/web-search/operations.ts, and build both surfaces on it: the shim
wraps each op into a web_search_call wire item; the Codex endpoint
concatenates the rendered text of every op into one output string.
Unimplemented command kinds (image_query, click, screenshot, finance,
weather, sports, time, response_length) surface as deterministic per-op
error text. Disabled/missing search config surfaces the same in-band
'provider not configured' text the shim uses. Request validated with a
zod schema mirroring codex-rs SearchRequest; usage accounted per API key.
Route tests through the codex namespace: auth, zod schema rejection (non-object commands, bad search_context_size), search/open/find command execution and rendered output, per-key usage accounting, unsupported command text, domain-filter blocking, empty commands, and disabled / missing-credential provider states surfaced as in-band output.
Codex derives its remote web-search URL from different base URLs across auth and provider modes. Mount the same authenticated, schema-validated handler at /alpha/search and /v1/alpha/search in addition to the generated config's /azure-api.codex/alpha/search path.
Parameterize routing, missing/invalid auth, and schema rejection across the namespaced, root, and /v1 alpha-search paths so aliases cannot drift from the primary handler.
Route /alpha/search to the gateway in Vite development, Cloudflare Static Assets, and the Docker nginx topology. /v1/alpha/search is already covered by each topology's existing /v1 prefix rule.
|
Claude Code agent update: root compatibility aliases are being added. Codex joins |
Codex recognizes a custom provider as eligible for its remote web.run tool when the provider config carries a non-empty x-openai-actor-authorization header. Treat that dashboard-generated marker as gateway-owned identity and strip it before provider dispatch so it reaches Floway's routing decision but never leaks to an LLM upstream.
Codex gates the remote web-search extension on either an OpenAI provider identity or a non-empty x-openai-actor-authorization provider header. Keep the provider key/name as floway/Floway so the wider is_openai behavior stays disabled, and add a non-secret marker header that enables only the actor-auth compatibility gates. The gateway scrubs the marker before upstream dispatch. Cover the generated TOML so the provider identity, namespaced base URL, and compatibility marker cannot drift.
The actor-authorization marker that enables remote web.run also makes Codex consider its remote image-generation extension. Floway does not serve the provider-relative images/generations path, so explicitly disable that feature while retaining the marker for web search. Cover and document the generated feature block.
Keep the inbound-header scrub list alphabetic, describe alpha-search output in the parser's canonical operation order rather than JSON key order, and make the shared truncated-page hint neutral across Responses and Codex callers.
|
Claude Code agent correction: the generated |
Keep the generated Codex provider config faithful to Floway: do not inject x-openai-actor-authorization, do not special-case that vendor header in the gateway scrubber, and do not disable image generation. Remove the associated gating claims and retain only the actual alpha-search route behavior in the documentation.
…aa14b68090a # Conflicts: # packages/gateway/src/data-plane/chat/responses/interceptors/server-tools/web-search.ts # packages/gateway/src/data-plane/codex/routes.ts
Add callAlphaSearch to the provider contract. Codex dispatches to the ChatGPT subscription endpoint with its OAuth account, custom dispatches to /v1/alpha/search with static auth, and other provider kinds reject the unsupported call.
Persist a default-off OpenAI search passthrough selection with upstream and model. Add the Settings toggle and scoped Codex/Custom upstream and chat-model pickers while preserving the existing general search provider as the default.
Resolve the configured upstream and model without fallback. Raw Codex alpha-search requests relay the selected provider response, while the existing Responses web-search shim adapts commands and structured results through the same provider call.
Thread the default-off passthrough shape through existing search fixtures and finish the merged web-search filter and Azure unsupported-provider paths.
Verify custom and Codex provider wires, raw alpha-route relay, Responses shim adaptation, persisted configuration, and the Codex/Custom-only settings picker.
Type the settings component against its minimal upstream picker shape, handle the nullable model store at the page boundary, and apply workspace lint rules to the alpha dispatcher path.
Keep search configuration export and import fixtures aligned with the OpenAI search passthrough settings.
Publish the required OpenAI search passthrough settings under transfer format v10 so incompatible payload shapes never share a version number.
Keep Codex request identity and optional metadata coherent, document the ChatGPT search path, and route Custom alpha search through the existing endpoint override policy.
Make search configuration writes typed, remove lossy post-validation normalization, enforce the stored boolean domain, and keep the dashboard selector invariants explicit.
Use a callable alpha dispatcher, remove test-only compatibility exports, preserve cancellation through local search execution, and align comments and references with both local and passthrough modes.
Keep the README focused on public Floway endpoints and omit the internal Codex compatibility namespace.
Rebuild passthrough responses with mutable headers before returning through Hono so Custom-to-Floway alpha-search chains preserve the upstream stream, status, and headers on Node.
State that the selected upstream must support alpha search and that Anthropic Messages remains on the general search provider.
|
Codex agent update: the ChatGPT Codex standalone-search wire probe is complete. This comment embeds the full publishable experiment archive; it is self-contained and does not depend on a gist or external host. Evidence: 349 Important findings for this PR:
Redaction removed all access/refresh/ID tokens, account and user identifiers, emails, personal paths, proxy configuration, IPs, opaque encrypted payloads, account-plan headers, and full fetched page bodies. Successful responses retain types, key sets, counts, lengths, and diagnostic classifications. The supplied credential's refresh token was never read or invoked by the online runners. Archive: Reconstruct on Linux:
Reconstruct on macOS:
Base64 archive body |
Fetch exposes a decoded body while retaining upstream content-encoding and content-length. Rebuilding the alpha response with those stale headers makes a downstream Floway or Codex client decode plain JSON again and fail with a terminated stream.\n\nStrip hop-by-hop, stale representation-framing, and upstream cookie headers while retaining content type and vendor metadata. Cover the shared fetched-response relay behavior directly.
Live alpha-search results are opaque UI metadata and omit the hosted web_search snippet field. The existing compatibility filter therefore dropped every real result before silently falling back to the rendered output.\n\nKeep the upstream output as the lossless model-facing payload and emit one clearly synthetic Responses result when that surface needs result-shaped data. Raw alpha routes continue relaying the upstream response untouched.
|
Codex agent update: the isolated Codex 2×3 end-to-end matrix is complete on the final PR head.
Each cell used its own Routing evidence:
The first cascade attempt exposed a real response-relay bug: Node Fetch had decoded upstream gzip bytes but Floway relayed the stale The live alpha study also showed that official structured results omit hosted-search Final verification:
|
What
Add an optional OpenAI search passthrough backend without turning alpha search into a generic Floway Search API.
The existing general search provider remains the default for Messages and Responses web search. Settings can enable Passthrough OpenAI search (/alpha/search and Responses hosted tool) and select an enabled Codex or Custom upstream plus chat model. The selected backend is scoped by the calling API key, is used only for the Codex-compatible alpha-search routes and the existing Responses web-search shim, and never falls back to another search backend. Anthropic Messages is unaffected.
Provider instances expose a dedicated
callAlphaSearchoperation. Codex forwards to the ChatGPT subscription endpoint with its OAuth account, quota, retry, and request-identity handling. Custom uses its OpenAI-compatible alpha-search path and existing path-override policy. Azure, Copilot, Claude Code, and Ollama reject the unsupported operation.Floway serves the Codex-compatible request at
/alpha/searchand/v1/alpha/search. In local mode those routes execute supported commands through the configured Tavily, Microsoft Grounding, or Jina provider. In passthrough mode the upstream status, decoded body stream, content type, and representation-safe metadata are relayed; stale content encoding/length, hop-by-hop headers, and upstream cookies are removed so another Floway or Fetch client can consume the response safely.The Responses shim preserves the alpha endpoint's model-facing
outputexactly. Alpharesultsare opaque UI metadata and live responses omit the hosted-searchsnippetfield, so the shim does not retype them as hosted results; it emits one explicitly synthetic result fromoutputwhen the Responses surface needs result-shaped data. The raw alpha routes remain lossless for the upstream JSON body.Account affinity for future Codex account pools remains an explicit TODO. This change adds no fallback or loop-prevention protocol.
The search settings migration stores the toggle, upstream, and model. Import/export uses strict format v10 because the required search-config shape changed.
Evidence
The live-wire study covered 349 ChatGPT Codex
/alpha/searchcalls and six Responses hosted-search comparisons. Its redacted spec, runners, and per-case structural reports are embedded in this PR comment.The local Codex 0.144.4 end-to-end matrix covered both tool modes across all three search routes:
web.run+/alpha/searchThe official test upstream contained an already-issued access token and no refresh token. Every cell emitted one completed
web_searchitem and the expected IANA URL; cascade audit recorded/v1/responses → /v1/alpha/search → /v1/responsesfor both modes.Test plan
pnpm run test— 358 files / 4,361 testspnpm run lintpnpm run typecheck— 19 workspace projects/openai/v1/modelscontrol returned 200; v1 default,api-version=preview,api-version=v1, Bearer, legacy resource, and deployment alpha-search paths all returned 404HOME/CODEX_HOMEpairs, covering hosted/client tools × general/official/cascade routes