Bifrost Gateway¶
The Compose stack runs two LGOS API services behind one pinned Bifrost gateway.
Both services use the same demo image and graph set today. They remain separate
so the demo proves that independently deployed APIs, including APIs with
different graph sets later, can share one proxy endpoint. The configuration at
demo/docker/bifrost/config.json belongs to the demo, not the LGOS package.
Run The Gateway¶
Bifrost exposes each service as a custom provider:
| Provider | Upstream | Example UI model ID |
|---|---|---|
lgos-a |
lgos-demo-api-a:8000 |
lgos-a/simple-graph |
lgos-b |
lgos-demo-api-b:8000 |
lgos-b/simple-graph |
Use Bifrost's normalized OpenAI endpoint as the shared model catalog and its raw pass-through endpoint for detailed model metadata and inference:
from openai import OpenAI
catalog = OpenAI(
base_url="http://localhost:3000/v1",
api_key="DUMMY",
)
passthrough = OpenAI(
base_url="http://localhost:3000/openai_passthrough/v1",
api_key="DUMMY",
)
model_ids = [
model.id
for model in catalog.models.list().data
if model.owned_by == "langgraph-openai-serve"
]
print(model_ids)
selected = "lgos-b/custom-input-output-context"
provider, model_id = selected.split("/", 1)
headers = {"x-model-provider": provider}
model = passthrough.models.retrieve(model_id, extra_headers=headers)
extension = (model.model_extra or {}).get("langgraph_openai_serve")
assert extension is not None
response = passthrough.chat.completions.create(
model=model_id,
messages=[{"role": "user", "content": "Show me custom schemas."}],
extra_headers=headers,
)
print(response.choices[0].message.content)
Bifrost's catalog owns the provider-qualified IDs. For pass-through requests,
the client splits that ID, sends the prefix as x-model-provider, and sends the
remaining native graph name as the OpenAI model. Bifrost strips
/openai_passthrough and forwards the remaining path and body. The raw route
preserves detailed LGOS model extensions and extension-only stream chunks.
The normalized /v1 route returns provider-qualified catalog IDs but does not
preserve the LGOS model extension. Both dynamic UI integrations therefore use
it only for discovery. Metadata-bearing model listing, detailed retrieval, and
chat use pass-through.
Configuration Boundary¶
Both Bifrost custom providers use openai as their base provider and enable
model listing, Chat Completions, and streaming and non-streaming pass-through.
Chat Completions keep the normalized route useful for the limited-functionality
demonstration; pass-through preserves the complete LGOS protocol. Their
upstream base URLs omit /v1, and private-network access is enabled for the
Compose network.
The demo uses DUMMY upstream keys because LGOS authentication is not enabled.
Replace each key when its target application enforces authentication.
Pass-through tradeoffs
Pass-through intentionally skips response normalization. Do not rely on Bifrost response additions, model-catalog routing, cross-provider fallbacks, or semantic caching on this route. Configured authentication, request-based governance, transport retries, and observability remain available.
Usage-based token and cost controls require a standard upstream usage
object. LGOS does not currently emit usage in streaming chunks, so enforce
request limits independently of streaming token totals.
Open WebUI's dynamic integration and Chainlit discover provider-qualified LGOS
models from Bifrost's catalog, then add x-model-provider only for pass-through
requests. Neither contains a provider list. The fixed-model Open WebUI example
uses pass-through without catalog discovery. Chainlit omits its optional catalog
URL when it runs directly against one LGOS API. From the package checkout, run
make test-bifrost after starting the gateway to verify model listing, LGOS
metadata, inference, and client events through both APIs with the OpenAI SDK.
See Bifrost's custom-provider documentation, pass-through contract, and the pinned version's provider-header routing for the gateway-owned behavior.