diff --git a/README.md b/README.md index 5efaf9d..6f489b6 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/docs/API.md b/docs/API.md index 5bc8426..1fe5094 100644 --- a/docs/API.md +++ b/docs/API.md @@ -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 ``` @@ -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/` ```bash curl -fsS http://127.0.0.1:8090/v1/images/generations \ @@ -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 \ diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 185ed3d..dcc4a5a 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -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` @@ -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/"` for one fixed image backend + ## Client Profiles And Request Hooks FoundryGate supports two lightweight extension seams: diff --git a/docs/INTEGRATIONS.md b/docs/INTEGRATIONS.md index 481f545..560fc34 100644 --- a/docs/INTEGRATIONS.md +++ b/docs/INTEGRATIONS.md @@ -16,6 +16,7 @@ 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: @@ -23,6 +24,12 @@ Use: - [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 @@ -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. @@ -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 diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md index 767f61c..d53c629 100644 --- a/docs/ONBOARDING.md +++ b/docs/ONBOARDING.md @@ -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/"` only when the image path should be pinned + Delegated / many-agent example: - [examples/openclaw-delegated-request.json](./examples/openclaw-delegated-request.json) @@ -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 diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index f3ad392..12a45c2 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -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: diff --git a/docs/examples/openclaw-foundrygate.jsonc b/docs/examples/openclaw-foundrygate.jsonc index 47b05e9..4bb6cd7 100644 --- a/docs/examples/openclaw-foundrygate.jsonc +++ b/docs/examples/openclaw-foundrygate.jsonc @@ -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", @@ -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 } ] } @@ -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" } diff --git a/openclaw-integration.jsonc b/openclaw-integration.jsonc index 950b48e..5d0d28f 100644 --- a/openclaw-integration.jsonc +++ b/openclaw-integration.jsonc @@ -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. @@ -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)", @@ -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", @@ -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 diff --git a/skills/foundrygate/SKILL.md b/skills/foundrygate/SKILL.md index 81999bc..2b86123 100644 --- a/skills/foundrygate/SKILL.md +++ b/skills/foundrygate/SKILL.md @@ -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 @@ -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 +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 -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 \ @@ -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/` 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: