feat: operator-defined model aliases

Spec §5 (v0.2): Config.ModelAliases map[string]string, alias-first
resolution precedence ahead of provider-prefix splitting, alias-OR-target
authorization, lazy target resolution with a 404 naming both ids,
/v1/models listing, admin overview alias table (JSON + dashboard), and
construction-time validation (shape, prefix-shadow, explicit-model
collision, chain, empty target).

routes_unified.go/routes_media.go needed no resolution-call-site changes
- both already pass the client's raw requested id through to
registry.resolve, so aliases inherit the __alias echo and multipart
rewrite machinery for free. cache.go needed no changes either - cacheKey
already hashes requestedModel, so two aliases resolving to the same
target already produce distinct cache entries.

Adds registry_test.go validation table + precedence/authz/lazy-404/
listing coverage, a dedicated cache-key split test, chat/embeddings/
images/audio-transcriptions end-to-end tests, an extended admin overview
test, and an integration test covering the openai-type vs anthropic-type
echo asymmetry under real Traefik+Yaegi.
This commit is contained in:
2026-08-20 20:56:01 +01:00
parent f49c51b341
commit 2090b31ae2
12 changed files with 1221 additions and 15 deletions
+13 -3
View File
@@ -98,9 +98,10 @@ http:
mcpServers:
tool:
url: "http://mocktool:8080"
# v0.2 features (spec §1, §2, §4), all opt-in and off by default
# in v0.1: enabled here so the integration suite exercises every
# one under real Traefik+Yaegi, not just go test.
# v0.2 features (spec §1, §2, §4, §5), all opt-in and off by
# default in v0.1: enabled here so the integration suite
# exercises every one under real Traefik+Yaegi, not just go
# test.
retry:
enabled: true
attempts: 1 # one retry after the first try — matches handleFlakyOpenAIChat's single forced 503
@@ -109,6 +110,15 @@ http:
ttl: "2m"
admin:
enabled: true
# Task 6 (spec §5): one alias per mock provider type, so the
# integration suite proves the echo-behavior asymmetry under
# real Traefik+Yaegi — openai-type forwards the upstream body
# verbatim (its "model" field carries "gpt-mock", not the
# alias); anthropic-type builds its own envelope and echoes the
# client's exact alias string back.
modelAliases:
aliased/mock: "gpt-mock"
aliased/claude: "claude-mock"
# Second, separate middleware instance carrying only the optional
# real-upstream smoke test's "uni" provider (task 7, INTEGRATION_REAL=1