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 upgraderemains 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 loginorfx 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.
| Field | Default | Description |
|---|---|---|
port | 8790 | Loopback listening port. |
upstream_base_url | required | HTTPS API base URL, or loopback HTTP for local inference. Query parameters are preserved. |
upstream_api_key_env | FX_BRIDGE_API_KEY | Environment variable containing the upstream key. |
upstream_api_key | empty | Legacy 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_path | chat/completions | Path appended to the base URL unless already present. |
models_path | models | Model catalog path appended to the base URL. |
model_map | {} | Exact fx model ID to upstream model ID mappings. |
unknown_model_policy | error | error, fallback, or passthrough. fallback requires default_model. |
default_model | empty | Model used when the request has no model, or when fallback is explicitly enabled. |
strip_provider_prefix | false | If enabled, route vendor/model as model only when the stripped ID is present in the upstream catalog. |
send_reasoning_effort | false | Forward fx's low/medium/high effort as reasoning_effort. |
extra_body | {} | Extra Chat Completions fields. Protocol-owned fields cannot be overridden. |
catalog_defaults | see example | Metadata fx requires when displaying upstream models. These are display assumptions, not provider discovery. |
connect_timeout | 30 | Connection timeout in seconds. |
read_timeout | 600 | Streaming read timeout in seconds. |
max_request_bytes | 8388608 | Maximum request body accepted from fx. |
require_upstream_done | true | Reject 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
/modelsshape; configurecatalog_defaultsconservatively. - The bridge listens only on
127.0.0.1and 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.