llm-gateway-public/docs/subscription-bridges.md
2026-07-17 22:10:34 +02:00

217 lines
5.4 KiB
Markdown

# Subscription Bridges
Subscription bridges let the gateway route requests to user-owned AI subscription tools through
a local HTTP interface.
The bridge pattern is:
```text
gateway
-> local bridge
-> installed CLI or local adapter
-> subscription-backed response
```
The gateway does not need direct access to the subscription account material. The CLI or adapter
keeps its own authentication state.
## Why Bridges Exist
Many subscription tools are designed for interactive use, not direct API access. A bridge gives
the gateway a small, testable HTTP surface around those tools:
- `GET /health`
- `POST /api/generate`
- `POST /v1/chat/completions`
This makes subscription tools easier to test, monitor, and route alongside other providers.
## Discovery
Discovery checks:
- CLI binary availability
- version probe result
- authentication status when a safe probe exists
- default bridge health
- configured bridge URL
Run discovery:
```bash
curl -X POST http://localhost:3100/api/subscriptions/scan \
-H "Authorization: Bearer <key>"
```
List subscriptions:
```bash
curl http://localhost:3100/api/subscriptions \
-H "Authorization: Bearer <key>"
```
Search:
```bash
curl "http://localhost:3100/api/subscriptions?search=claude" \
-H "Authorization: Bearer <key>"
```
## Join
Join records that the operator wants to use a subscription.
```bash
curl -X POST http://localhost:3100/api/subscriptions/join \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{ "subscription_id": "chatgpt", "auto_spawn": true }'
```
Joining does not expose OAuth state or account credentials.
The subscription summary returned by the list endpoint contains the generated access card,
including the direct gateway API URL for that subscription.
## Spawn
Spawn one bridge:
```bash
curl -X POST http://localhost:3100/api/subscriptions/bridges \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{ "subscription_id": "chatgpt" }'
```
Spawn all eligible bridges:
```bash
curl -X POST http://localhost:3100/api/subscriptions/bridges \
-H "Authorization: Bearer <key>"
```
## Test
```bash
curl -X POST http://localhost:3100/api/subscriptions/test \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{
"subscription_id": "chatgpt",
"message": "Reply with a bridge smoke test."
}'
```
The test response should include:
- subscription ID
- model
- bridge URL
- HTTP status
- latency
- response snippet
## Call A Joined Subscription
Every joined subscription can be called through its own OpenAI-compatible gateway URL:
```bash
curl -X POST http://localhost:3100/api/subscriptions/chatgpt/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{
"model": "gpt-4-turbo",
"messages": [
{ "role": "user", "content": "Reply through the ChatGPT subscription bridge." }
]
}'
```
The unified endpoint can also target a specific subscription:
```bash
curl -X POST http://localhost:3100/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-H "X-LLM-Gateway-Subscription: chatgpt" \
-d '{
"model": "gpt-4-turbo",
"messages": [
{ "role": "user", "content": "Reply through the ChatGPT subscription bridge." }
]
}'
```
For ambiguous model IDs, prefer the direct subscription URL or the
`X-LLM-Gateway-Subscription` header. This keeps routing explicit when several subscription
tools expose similar model names.
Chat messages are compressed before bridge dispatch when compression can reduce the request.
Responses include gateway compression metadata where available.
## Access Card
Each subscription summary includes an access card with:
- gateway base URL
- chat completions URL
- per-subscription chat completions URL
- model list
- default model
- required headers
- `X-LLM-Gateway-Subscription` header value
- bridge URL
- bridge env var
- curl example
Use the gateway endpoint from the access card in client applications, not the subscription
credentials.
## Adding A Bridge Implementation
Add or update:
- `packages/gateway/src/modules/subscription-discovery.ts`
- `packages/gateway/src/modules/bridge-spawner.ts`
- `packages/gateway/src/routes/subscriptions.ts`
- `packages/gateway/src/pipeline/external-providers.ts`
Minimum checklist:
1. Add a catalog entry.
2. Add a version probe.
3. Add an auth probe if the CLI supports one safely.
4. Pick a localhost bridge port.
5. Add one or more model IDs.
6. Implement the CLI invocation.
7. Return OpenAI-compatible chat output where possible.
8. Add health behavior.
9. Add tests or a documented smoke test.
## Security Rules
- Bind local bridges to localhost.
- Do not print OAuth artifacts.
- Do not return subscription account data in API responses.
- Avoid logging full prompts by default.
- Treat bridge errors as operational state, not as successful routing.
- Prefer explicit join before auto-spawn in shared environments.
## Troubleshooting
### Installed But Not Authenticated
Log in through the CLI directly, then run scan again.
### Bridge Port Already In Use
Check whether a previous bridge process is still running or configure a different bridge URL.
### Unified Chat Returns Provider Missing
Check whether the selected model ID belongs to a discovered, joined, and running subscription.
### CLI Works But Bridge Fails
Run the gateway with a verbose log level and test the bridge endpoint directly.