fx-bridge

August 20, 2026 · View on GitHub

Use Vercel fx with a standard OpenAI-compatible API through a local, loopback-only protocol bridge.

fx-bridge does not patch the fx binary or replace fx authentication. It translates fx's AI SDK Language Model Specification v4 request/response format into OpenAI Chat Completions and keeps provider credentials on your machine.

Important

fx and its local gateway override are experimental. Pin a known-working fx version and run the included smoke test after every fx upgrade.

fx ── FX_GATEWAY_CHAT_URL ──▶ fx-bridge (127.0.0.1) ──▶ OpenAI-compatible API
        LMS-v4 request/SSE       Python stdlib only         Chat Completions/SSE

Features

  • No fx binary patching; fx upgrade remains available.
  • Python standard library only, with no runtime dependencies.
  • Loopback-only listener and HTTPS-only remote upstreams.
  • Streaming text, reasoning, tool calls, tool results, images, and usage.
  • Explicit model mapping and fail-closed routing by default.
  • Configurable endpoint paths, headers, request fields, and model metadata.
  • Deterministic mock mode plus unit, HTTP integration, and real-fx smoke tests.

Requirements

  • Python 3.9 or newer (including the macOS system Python used by launchd).
  • A working fx installation. fx may still require fx login or fx setup; the credential fx sends to the loopback bridge is ignored.
  • An API exposing the OpenAI Chat Completions streaming format. Provider-specific protocols such as Anthropic Messages are not supported directly.

Quick start

git clone https://github.com/elijah7x/fx-bridge.git
cd fx-bridge

mkdir -p ~/.config/fx-bridge
cp config.example.json ~/.config/fx-bridge/config.json
chmod 600 ~/.config/fx-bridge/config.json

# Prefer an environment variable over a literal key in JSON.
read -rs FX_BRIDGE_API_KEY && export FX_BRIDGE_API_KEY && echo

python3 fx-bridge.py

Start fx with both local overrides:

alias fxb='FX_GATEWAY_BASE_URL=http://127.0.0.1:8790 FX_GATEWAY_CHAT_URL=http://127.0.0.1:8790/v3/ai/language-model fx'

FX_MODEL=your-model-id fxb ask "hello"

FX_GATEWAY_CHAT_URL controls chat requests. FX_GATEWAY_BASE_URL makes fx models and the interactive model selector use the upstream model catalog exposed by the bridge.

Configuration

The default configuration path is ~/.config/fx-bridge/config.json. Use --config PATH to override it.

FieldDefaultDescription
port8790Loopback listening port.
upstream_base_urlrequiredHTTPS API base URL, or loopback HTTP for local inference. Query parameters are preserved.
upstream_api_key_envFX_BRIDGE_API_KEYEnvironment variable containing the upstream key.
upstream_api_keyemptyLegacy literal key. If used, fx-bridge warns when the config permissions are broader than 0600.
upstream_headers{}Additional or replacement upstream headers, including custom authorization schemes.
chat_pathchat/completionsPath appended to the base URL unless already present.
models_pathmodelsModel catalog path appended to the base URL.
model_map{}Exact fx model ID to upstream model ID mappings.
unknown_model_policyerrorerror, fallback, or passthrough. fallback requires default_model.
default_modelemptyModel used when the request has no model, or when fallback is explicitly enabled.
strip_provider_prefixfalseIf enabled, route vendor/model as model only when the stripped ID is present in the upstream catalog.
send_reasoning_effortfalseForward fx's low/medium/high effort as reasoning_effort.
extra_body{}Extra Chat Completions fields. Protocol-owned fields cannot be overridden.
catalog_defaultssee exampleMetadata fx requires when displaying upstream models. These are display assumptions, not provider discovery.
connect_timeout30Connection timeout in seconds.
read_timeout600Streaming read timeout in seconds.
max_request_bytes8388608Maximum request body accepted from fx.
require_upstream_donetrueReject a stream that ends before the OpenAI [DONE] sentinel.

Provider variations

The bridge supports custom headers and endpoint paths without provider-specific code:

{
  "upstream_base_url": "https://gateway.example.com/openai/v1?api-version=2026-01-01",
  "upstream_api_key_env": "MY_GATEWAY_KEY",
  "upstream_headers": {
    "X-Client": "fx-bridge"
  },
  "chat_path": "chat/completions",
  "models_path": "models",
  "unknown_model_policy": "passthrough"
}

If a provider does not implement /models, use model_map or passthrough. Use fallback only when silently routing unknown fx model IDs to one configured model is intentional.

Verification

Run the dependency-free regression suite:

python3 -m unittest discover -v

Run the HTTP-only mock server:

python3 fx-bridge.py --mock
curl -fsS http://127.0.0.1:8790/healthz

Run the end-to-end smoke test against the installed fx binary:

scripts/smoke-fx.sh

The smoke test starts an isolated mock bridge, asks fx to execute a real read_file tool call, verifies the tool result returns through a second model turn, and removes its temporary files.

Failure behavior

fx-bridge fails closed for conditions that could otherwise execute the wrong tool or accept an incomplete model response:

  • malformed fx request bodies;
  • unknown models under the default routing policy;
  • malformed streamed JSON or upstream error events;
  • invalid or incomplete tool-call arguments;
  • upstream EOF before [DONE];
  • remote plaintext HTTP endpoints.

Upstream failures are returned to fx as LMS error events. They are not converted into successful stop completions.

Diagnostics and privacy

Set FXB_DUMP=/path/request.json to capture the raw fx request for protocol debugging. Dumps can contain prompts, source code, tool output, and secrets. fx-bridge creates the file with mode 0600; review and delete it after use.

The bridge logs model routing and request counts, but never logs API keys, request bodies, the config path, or the upstream URL.

Architecture

fx_bridge/
  config.py                 validation, secrets, endpoint construction
  routing.py                explicit model routing policy
  protocols/openai_chat.py  fx request → Chat Completions
  protocols/fx_lms.py       Chat Completions stream → fx LMS-v4 SSE
  transport.py              upstream HTTP, SSE parser, model cache
  server.py                 loopback HTTP boundary
  mock.py                   deterministic two-turn tool harness

The wire contract is derived from the fx source parser and tests. FX_GATEWAY_CHAT_URL is deliberately restricted by fx to a loopback HTTP URL, but it remains an experimental integration surface rather than a public stability guarantee.

Known limitations

  • Gateway-native provider tools such as hosted web search are not forwarded. Local fx function tools continue to work.
  • Only OpenAI Chat Completions-compatible request and streaming response shapes are supported.
  • Model context windows and output limits cannot be discovered reliably from the OpenAI /models shape; configure catalog_defaults conservatively.
  • The bridge listens only on 127.0.0.1 and is not intended to be a shared network proxy.

Security

See SECURITY.md. Do not publish credentials, raw request dumps, logs, or private provider URLs in bug reports.

License and affiliation

Licensed under Apache-2.0. See LICENSE.

fx-bridge is an independent community project. It is not affiliated with, endorsed by, or sponsored by Vercel. “Vercel” and “fx” are used only to identify compatibility with the upstream product.