Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ Start here for the deeper deployment details:
- [Integrations](./docs/INTEGRATIONS.md)
- [Onboarding](./docs/ONBOARDING.md)
- [Examples](./docs/examples)
- [OpenClaw integration starter](./openclaw-integration.jsonc)
- [First-wave AI-native starters](./docs/AI-NATIVE-MATRIX.md#first-wave-template-set-for-v110)
- [Second-wave AI-native starters](./docs/AI-NATIVE-MATRIX.md#second-wave-template-set)
- [Third-wave AI-native starters](./docs/AI-NATIVE-MATRIX.md#third-wave-template-set)
Expand Down
4 changes: 4 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ FoundryGate keeps the client-facing surface intentionally small: OpenAI-compatib

Returns the virtual `auto` model plus one entry for every provider that actually loaded at startup.

This is also the source of truth for OpenClaw-side model ids under a `foundrygate` provider entry.

```bash
curl -fsS http://127.0.0.1:8090/v1/models
```
Expand Down Expand Up @@ -38,6 +40,7 @@ Routes image-generation requests to providers with `capabilities.image_generatio

- validates `prompt`, `n`, and `size` before any provider call
- supports image-policy hints via `metadata.image_policy` or `X-FoundryGate-Image-Policy`
- works well with OpenClaw when `imageModel.primary` is `foundrygate/auto` or one explicit `foundrygate/<provider-id>`

```bash
curl -fsS http://127.0.0.1:8090/v1/images/generations \
Expand All @@ -57,6 +60,7 @@ Routes image-editing requests to providers with `capabilities.image_editing: tru
- currently supports one required `image` and one optional `mask`
- rejects uploads above `security.max_upload_bytes`
- accepts image-policy hints via `image_policy`, `metadata.image_policy`, or `X-FoundryGate-Image-Policy`
- requires at least one loaded provider with `capabilities.image_editing: true`

```bash
curl -fsS http://127.0.0.1:8090/v1/images/edits \
Expand Down
17 changes: 17 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ Each provider entry can include:

The comments in [`config.yaml`](../config.yaml) are the source of truth for the current schema.

## OpenClaw-Oriented Baseline

If OpenClaw is one of the main clients, these settings give the cleanest fit:

- keep provider ids readable and stable because `GET /v1/models` exposes them directly to OpenClaw
- enable `client_profiles.presets: ["openclaw"]`
- keep `auto` in the fallback path so OpenClaw can stay on one stable primary model id
- use `contract: local-worker` for local chat workers
- use `contract: image-provider` plus `image` metadata for image-capable backends

That gives OpenClaw one provider entry, one primary model id, and optional explicit aliases without mirroring every upstream directly in the OpenClaw config.

## Provider Contracts

### `generic`
Expand Down Expand Up @@ -103,6 +115,11 @@ Useful `image` metadata:
- `supported_sizes`
- `policy_tags`

If OpenClaw should route image traffic through FoundryGate, pair this with:

- `imageModel.primary: "foundrygate/auto"` for automatic image-provider selection
- or `imageModel.primary: "foundrygate/<provider-id>"` for one fixed image backend

## Client Profiles And Request Hooks

FoundryGate supports two lightweight extension seams:
Expand Down
46 changes: 43 additions & 3 deletions docs/INTEGRATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,20 @@ Current coverage:
- many-agent or delegated traffic when `x-openclaw-source` is present
- direct model aliases via the OpenClaw-side config
- caller-aware defaults through the `openclaw` client preset or explicit profile rules
- image generation and image editing through the same FoundryGate provider entry

Use:

- [openclaw-integration.jsonc](../openclaw-integration.jsonc)
- [examples/openclaw-foundrygate.jsonc](./examples/openclaw-foundrygate.jsonc)
- `client_profiles.presets: ["openclaw"]` for a standard starting point

Important rule:

- the model ids under `models.providers.foundrygate.models` in OpenClaw must match the provider ids returned by `GET /v1/models` from FoundryGate
- that means OpenClaw should use ids such as `auto`, `deepseek-chat`, `local-worker`, or `image-provider`
- it should not guess raw upstream ids unless FoundryGate itself exposes those exact provider ids

Minimal direction:

```json
Expand All @@ -34,10 +41,43 @@ Minimal direction:

For a smaller starter snippet without the full alias block, use [examples/openclaw-foundrygate.jsonc](./examples/openclaw-foundrygate.jsonc).

Recommended OpenClaw defaults:

- `model.primary: "foundrygate/auto"`
- `imageModel.primary: "foundrygate/auto"` when FoundryGate should choose among image-capable providers
- `subagents.model: "foundrygate/auto"` when delegated traffic should stay inside the same routing plane

Use an explicit image provider only when OpenClaw should pin image traffic:

```json
{
"imageModel": {
"primary": "foundrygate/image-provider",
"fallbacks": []
}
}
```

FoundryGate-side config that helps OpenClaw most:

- readable, stable provider ids because those become OpenClaw model ids
- `client_profiles.presets: ["openclaw"]`
- `contract: local-worker` for local LLM workers
- `contract: image-provider` for image-capable backends
- `capabilities.image_editing: true` only when edits really work upstream
- `image.policy_tags`, `supported_sizes`, and `max_outputs` for stronger image routing

For delegated or many-agent traffic, start from [examples/openclaw-delegated-request.json](./examples/openclaw-delegated-request.json) and keep `x-openclaw-source` stable across sub-agents so traces stay attributable.

Keep delegated/client headers short and stable. The runtime now bounds routing-header values before they reach traces, metrics, and rollout logic.

Validate OpenClaw wiring in this order:

1. `GET /v1/models` to confirm the provider ids OpenClaw should reference
2. `POST /api/route` for chat routing previews
3. `POST /api/route/image` for image routing previews
4. only then send real `POST /v1/chat/completions`, `POST /v1/images/generations`, or `POST /v1/images/edits` traffic

## n8n

n8n can use FoundryGate as a stable local model gateway.
Expand Down Expand Up @@ -252,11 +292,11 @@ When onboarding a new client:
5. use `/api/route` and `/api/traces` to validate behavior
6. only add a dedicated adapter if the client cannot cleanly use the common API surface

## Planned integration directions
## Integration extensions

These are roadmap items or early foundations:
These are the main extension seams beyond the common client starters:

- image generation and image editing routing through `POST /v1/images/generations` and `POST /v1/images/edits` for providers that declare `contract: image-provider`
- image generation and image editing through `POST /v1/images/generations` and `POST /v1/images/edits` for providers that declare `contract: image-provider`
- optional request hooks for context or optimization
- richer CLI-sidecar adapters
- provider and client onboarding helpers
9 changes: 9 additions & 0 deletions docs/ONBOARDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ OpenClaw:

Starter file: [examples/openclaw-foundrygate.jsonc](./examples/openclaw-foundrygate.jsonc)

Full reference block: [../openclaw-integration.jsonc](../openclaw-integration.jsonc)

Important:

- the model ids under `providers.foundrygate.models` must match `GET /v1/models`
- use `imageModel.primary: "foundrygate/auto"` if FoundryGate should pick the image backend
- use `imageModel.primary: "foundrygate/<provider-id>"` only when the image path should be pinned

Delegated / many-agent example:

- [examples/openclaw-delegated-request.json](./examples/openclaw-delegated-request.json)
Expand Down Expand Up @@ -215,6 +223,7 @@ Keep hooks opt-in and narrow. Good uses are:
Use:

- `POST /api/route`
- `POST /api/route/image`
- `GET /api/traces`

## Many providers, many clients
Expand Down
18 changes: 18 additions & 0 deletions docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,24 @@ Check whether `x-openclaw-source` is present.

That header is the current signal used for OpenClaw sub-agent differentiation in the stock config and built-in presets.

## OpenClaw says the model does not exist

This usually means the OpenClaw-side provider ids do not match FoundryGate's loaded provider ids.

Check:

```bash
curl -fsS http://127.0.0.1:8090/v1/models
```

Then update the ids under `models.providers.foundrygate.models` in `~/.openclaw/openclaw.json` so they match exactly.

Remember:

- `auto` is always valid
- the other ids come from FoundryGate provider names
- they are not automatically the raw upstream model ids

## Database path is wrong or unwritable

Use an absolute path outside the repo checkout:
Expand Down
27 changes: 27 additions & 0 deletions docs/examples/openclaw-foundrygate.jsonc
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// Example OpenClaw provider block for FoundryGate.
// Merge this into ~/.openclaw/openclaw.json.
//
// Important:
// - The ids listed under providers.foundrygate.models must match
// GET /v1/models from FoundryGate.
// - Use foundrygate/auto for normal chat routing and, if desired, also for
// imageModel so FoundryGate can choose among image-capable providers.
{
"models": {
"mode": "merge",
Expand All @@ -15,6 +21,18 @@
"name": "FoundryGate Auto-Router",
"contextWindow": 128000,
"maxTokens": 8000
},
{
"id": "local-worker",
"name": "Local Worker (via FoundryGate)",
"contextWindow": 128000,
"maxTokens": 8000
},
{
"id": "image-provider",
"name": "Image Provider (via FoundryGate)",
"contextWindow": 128000,
"maxTokens": 8000
}
]
}
Expand All @@ -26,6 +44,15 @@
"primary": "foundrygate/auto",
"fallbacks": []
},
"imageModel": {
"primary": "foundrygate/auto",
"fallbacks": []
},
"models": {
"foundrygate/auto": { "alias": "auto" },
"foundrygate/local-worker": { "alias": "local" },
"foundrygate/image-provider": { "alias": "img" }
},
"subagents": {
"model": "foundrygate/auto"
}
Expand Down
35 changes: 35 additions & 0 deletions openclaw-integration.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
//
// Add this block to your ~/.openclaw/openclaw.json.
//
// Important:
// - Under "providers.foundrygate.models", the ids must match GET /v1/models from
// FoundryGate. Those ids are FoundryGate provider ids, not raw upstream ids.
// - "auto" is always available.
// - Only keep provider ids here that your current FoundryGate config actually loads.
//
// Option A: FoundryGate as your primary provider (recommended)
// ---------------------------------------------------------
// FoundryGate handles routing, fallback, and model selection.
Expand Down Expand Up @@ -48,6 +54,18 @@
"contextWindow": 1000000,
"maxTokens": 8000
},
{
"id": "local-worker",
"name": "Local Worker (via FoundryGate)",
"contextWindow": 128000,
"maxTokens": 8000
},
{
"id": "image-provider",
"name": "Image Provider (via FoundryGate)",
"contextWindow": 128000,
"maxTokens": 8000
},
{
"id": "openrouter-fallback",
"name": "OpenRouter Fallback (via FoundryGate)",
Expand All @@ -70,12 +88,18 @@
"foundrygate/deepseek-reasoner": { "alias": "r1" },
"foundrygate/gemini-flash-lite": { "alias": "lite" },
"foundrygate/gemini-flash": { "alias": "flash" },
"foundrygate/local-worker": { "alias": "local" },
"foundrygate/image-provider": { "alias": "img" },
"foundrygate/openrouter-fallback": { "alias": "or" }
},
"imageModel": {
// Use foundrygate/auto when FoundryGate should choose among
// image-capable providers. Pin to foundrygate/image-provider only when
// OpenClaw should always use one explicit image backend.
"primary": "foundrygate/auto",
"fallbacks": []
},
"contextTokens": 200000,
"heartbeat": {
"every": "12h",
"model": "foundrygate/gemini-flash-lite",
Expand All @@ -100,3 +124,14 @@
// Then set "agents.defaults.model":
// "primary": "foundrygate/auto",
// "fallbacks": ["deepseek/deepseek-chat", "google/gemini-2.5-flash"]
//
// Recommended FoundryGate-side settings for OpenClaw:
// - keep provider ids stable and readable because OpenClaw will reference them
// - enable client_profiles.presets: ["openclaw"]
// - use contract: local-worker for local OpenAI-compatible workers
// - use contract: image-provider plus image.policy_tags / supported_sizes for
// image-capable providers
// - validate with:
// GET /v1/models
// POST /api/route
// POST /api/route/image
28 changes: 27 additions & 1 deletion skills/foundrygate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ metadata: {"openclaw":{"requires":{"bins":["curl"]},"emoji":"🚪","homepage":"h

FoundryGate is a local routing proxy that sits between OpenClaw and your model providers (chat and image-capable backends).

OpenClaw note: when OpenClaw talks to FoundryGate, the model ids in the OpenClaw config must match the provider ids returned by `GET /v1/models` from FoundryGate. Those ids are local FoundryGate ids such as `auto`, `deepseek-chat`, `local-worker`, or `image-provider`, not raw upstream model names.

## Available Commands

### /foundrygate stats
Expand Down Expand Up @@ -63,8 +65,24 @@ curl -s http://127.0.0.1:8090/api/route \

Show the selected provider, routing layer, rule, resolved profile, and attempt order. If relevant headers matter for routing, include them in the dry-run request.

### /foundrygate image-route <prompt>
Dry-run image routing without calling an upstream provider.

```bash
curl -s http://127.0.0.1:8090/api/route/image \
-H "Content-Type: application/json" \
-d '{
"operation": "generation",
"model": "auto",
"prompt": "PROMPT_HERE",
"size": "1024x1024"
}' | python3 -m json.tool
```

Show the selected provider, routing layer, rule, and candidate ranking for image traffic.

### /foundrygate image <prompt>
Dry-run one image-generation request shape by calling the image endpoint directly.
Send one real image-generation request through FoundryGate.

```bash
curl -s http://127.0.0.1:8090/v1/images/generations \
Expand Down Expand Up @@ -126,6 +144,14 @@ FoundryGate uses 6 routing stages for chat requests (evaluated in order, first d

Key insight: Only user messages are scored, never the system prompt. OpenClaw's system prompt is large and keyword-rich — scoring it would route everything to the expensive reasoning tier.

## OpenClaw Integration Notes

- Prefer one OpenClaw provider named `foundrygate` that points to `http://127.0.0.1:8090/v1`.
- Use `foundrygate/auto` as the default `model.primary` unless you want to pin one explicit FoundryGate provider.
- Use `foundrygate/auto` for `imageModel.primary` when FoundryGate should pick among image-capable providers. Pin `foundrygate/<provider-id>` only when the image backend must be fixed.
- If many-agent traffic should be distinguishable, keep `x-openclaw-source` short and stable.
- If you want FoundryGate to classify OpenClaw traffic automatically, enable `client_profiles.presets: ["openclaw"]` in `config.yaml`.

## Prompt Caching

DeepSeek and Gemini automatically cache repeated prefixes server-side. FoundryGate tracks cache hit/miss tokens in metrics. To maximize cache hits:
Expand Down
Loading