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
54 changes: 20 additions & 34 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ redis = { version = "1.5.0", default-features = false, features = ["tokio-comp"]
regex = "1.13.1"
reqwest = { version = "0.13.4", default-features = false, features = ["rustls", "json", "stream"] }
rmcp = { version = "3.1.4", default-features = false, features = ["client", "transport-streamable-http-client-reqwest", "reqwest"] }
rustls = "0.23.43"
rustls = "0.23.45"
schemars = "1.2.2"
rustls-pemfile = "2.2.0"
secrecy = { version = "0.10.3", features = ["serde"] }
Expand Down
28 changes: 28 additions & 0 deletions docs/filters/llmisvc_model_provider_resolver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!-- Generated by: cargo xtask generate-filter-docs -->
<!-- Do not edit manually -->

# `llmisvc_model_provider_resolver`

Rewrites publisher-ID body `model` values to the short model name for `LLMISvc` / `KServe` routing; the routing header is left unchanged.

## Configuration Notes

Reads the model name from the configured request header (default `X-Model`, typically set by an earlier `model_to_header`). When that value is a publisher ID (`publishers/.../models/<name>`), rewrite the body `"model"` field to `<name>` only. The routing header is never modified -- `KServe` routes on the publisher ID.

If the header is absent/empty, or the body has no `"model"` field, this filter is a no-op (it does not invent a body `"model"`).

Does **not** resolve `ExternalModel` / `ExternalProvider` CRDs, perform weighted provider selection, rewrite `Host`, or inject credentials.

## Configuration

| Field | Type | Required | Description |
|-------|------|---------|-------------|
| `header` | string | no | Request header that carries the publisher ID for `KServe` routing. Defaults to `X-Model` (same as `model_to_header`). |
| `max_body_bytes` | integer | no | Maximum request body size to buffer before parsing. |

## Example

```yaml
filter: llmisvc_model_provider_resolver
header: X-Model # optional, defaults to X-Model
```
4 changes: 4 additions & 0 deletions docs/filters/model_to_header.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

Promotes the JSON `"model"` field from the request body to a request header.

## Configuration Notes

Promotion is deferred until end-of-stream so a later body-writing filter (for example `llmisvc_model_provider_resolver`) can observe the pending header in the same `StreamBuffer` pre-read pass.

## Configuration

| Field | Type | Required | Description |
Expand Down
1 change: 1 addition & 0 deletions docs/filters/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ see the [Praxis core filter reference][core-ref].

| Filter | Description |
|--------|-------------|
| [`llmisvc_model_provider_resolver`](llmisvc_model_provider_resolver.md) | Rewrites publisher-ID body `model` values to the short model name for `LLMISvc` / `KServe` routing; the routing header is left unchanged. |
| [`model_to_header`](model_to_header.md) | Promotes the JSON `"model"` field from the request body to a request header. |

### Metering
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ before sending requests.
| [json-rpc-routing.yaml](configs/json-rpc-routing.yaml) | Routes JSON-RPC 2.0 requests to different backends based on the "method" field in the JSON request body |
| [lakera-guard.yaml](configs/lakera-guard.yaml) | Screens every request body through Lakera Guard for content moderation before forwarding to the upstream |
| [llmd-ext-proc-routing.yaml](configs/llmd-ext-proc-routing.yaml) | A real llm-d EPP or test processor returns the trusted x-gateway-destination-endpoint header |
| [llmisvc-model-provider-resolver.yaml](configs/llmisvc-model-provider-resolver.yaml) | Rewrites publisher-ID body `model` values to the short model name for LLMISvc / KServe routing; the routing header (default `X-Model`) is left unchanged so routing can still use the publisher ID |
| [mcp-classifier-routing.yaml](configs/mcp-classifier-routing.yaml) | Routes MCP requests by body-derived method and tool name |
| [mcp-stateless-broker.yaml](configs/mcp-stateless-broker.yaml) | Configurable stateless MCP broker using the final MCP 2026-07-28 stateless profile |
| [model-to-header-routing.yaml](configs/model-to-header-routing.yaml) | Routes LLM API requests to different backends based on the "model" field in the JSON request body |
Expand Down
47 changes: 47 additions & 0 deletions examples/configs/llmisvc-model-provider-resolver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# LLMISvc Model Provider Resolver
#
# Build:
# cargo build -p praxis-ai-proxy
#
# Rewrites publisher-ID body `model` values to the short model name for
# LLMISvc / KServe routing; the routing header (default `X-Model`) is
# left unchanged so routing can still use the publisher ID.
#
# Typical chain: `model_to_header` promotes the body model to
# `X-Model`, then `llmisvc_model_provider_resolver` strips the
# publisher prefix from the body only.
#
# Example request:
#
# curl -X POST http://localhost:8080/v1/chat/completions \
# -H "Content-Type: application/json" \
# -d '{"model":"publishers/rhoai/models/granite-3.1-8b","messages":[{"role":"user","content":"hi"}]}'
#
# Upstream body model becomes `granite-3.1-8b` while `X-Model`
# remains `publishers/rhoai/models/granite-3.1-8b`.

listeners:
- name: llmisvc-gateway
address: "0.0.0.0:8080" # dev value; binds all interfaces
filter_chains:
- rewrite-and-route

filter_chains:
- name: rewrite-and-route
filters:
- filter: model_to_header
header: X-Model
- filter: llmisvc_model_provider_resolver
header: X-Model
- filter: router
routes:
- path_prefix: "/"
cluster: provider
- filter: load_balancer
clusters:
- name: provider
endpoints:
- "127.0.0.1:3000"

insecure_options:
allow_private_endpoints: true # example proxies to local backends
Loading
Loading