diff --git a/.agents/gateways/RULES.md b/.agents/gateways/RULES.md index d356f679..96242270 100644 --- a/.agents/gateways/RULES.md +++ b/.agents/gateways/RULES.md @@ -27,7 +27,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S 3a. **Agent-side env vars are SDK placeholders, set by the eval image.** Agents inside the eval image consult provider-native env vars to satisfy their SDK's startup requirements (`OPENAI_API_KEY=sk-proxy`, `ANTHROPIC_API_KEY=sk-proxy`, `GEMINI_API_KEY=sk-proxy`). The value is a placeholder because the agent talks to the local gateway (which accepts any auth header), not the real provider. Eval images MUST set these placeholders so each SDK boots; the gateway's upstream credentials are read from the *gateway* container's env, populated separately at deploy time (k8s Secret, compose `env_file`, etc.). -4. **Configuration as template.** Where the gateway requires a static config file (`config.json`, `config.yaml`, etc.), the image MUST ship the file as a `.template` with `${VAR}` placeholders. The `start` script MUST render the live config via `envsubst` (or equivalent) at container startup, before launching the gateway process. Hardcoded provider blocks, model names, or URLs in the committed template are forbidden. Credential refs MUST point to provider-native env vars (per rule 3), not framework aliases. +4. **Configuration as template.** Where the gateway requires a static config file (`config.json`, `config.yaml`, etc.), the image MUST ship the file as a `.template` with `${VAR}` placeholders. The `start` script MUST render the live config from the template at container startup, before launching the gateway process. Hardcoded provider blocks, model names, or URLs in the committed template are forbidden. Credential refs MUST point to provider-native env vars (per rule 3), not framework aliases. ### Path-Prefix Protocol Namespace @@ -123,3 +123,4 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S |------|--------| | 2026-05-17 | Initial version. Defines provider-agnostic gateway images, the `//` URL namespace, the `EVAL_MODEL=/` env contract, and the gateway↔model separation (gateways/ holds implementations, models/ holds pre-built combos). | | 2026-05-18 | Rule 2a added: gateways MUST work with any model out of the box (one-env-var swap, no rebuild). Rule 16 rewritten: `models/--` combo images are OPTIONAL convenience wrappers, MUST equal bare-gateway-plus-mounted-template behavior. | +| 2026-07-06 | Rule 4 reworded: the `start` script renders config "from the template" at startup; the rule no longer names a specific render tool (gateways render with POSIX `sed`). | diff --git a/containers/benchmarks/_chart/values.yaml b/containers/benchmarks/_chart/values.yaml index 0d6d3538..3de48c2f 100644 --- a/containers/benchmarks/_chart/values.yaml +++ b/containers/benchmarks/_chart/values.yaml @@ -1,8 +1,8 @@ # Defaults for the shared eval Job. The benchmark is selected with # `--set benchmark=` (required); a benchmark with bespoke topology overrides # what differs via an optional `presets/.yaml` in this chart. The per-run axes -# (agent, task, model, …) come from `--set` (or the eval-containers CLI). envsubst -# is gone: Helm fills these and gets the types right (task stays a quoted string). +# (agent, task, model, …) come from `--set` (or the eval-containers CLI). Helm +# fills these and gets the types right (task stays a quoted string). # ── Per-run axes (overridden at deploy via --set / the eval-containers CLI) ── agent: claude-code diff --git a/containers/core/benchmark-base-duckdb/Dockerfile b/containers/core/benchmark-base-duckdb/Dockerfile index dfb439af..da1f2a02 100644 --- a/containers/core/benchmark-base-duckdb/Dockerfile +++ b/containers/core/benchmark-base-duckdb/Dockerfile @@ -13,7 +13,7 @@ ARG DUCKDB_VERSION=1.5.3 RUN set -e; ok=0; \ for i in 1 2 3 4 5; do \ if apt-get update --fix-missing && apt-get install -y --no-install-recommends \ - curl ca-certificates unzip jq gettext-base; then ok=1; break; fi; \ + curl ca-certificates unzip jq; then ok=1; break; fi; \ echo "apt attempt $i failed; retry" >&2; sleep $((i*5)); \ done; \ [ "$ok" = 1 ] || { echo "apt install failed after 5 tries" >&2; exit 1; }; \ diff --git a/containers/core/benchmark-base-external/Dockerfile b/containers/core/benchmark-base-external/Dockerfile index 17c688ee..edfe0fad 100644 --- a/containers/core/benchmark-base-external/Dockerfile +++ b/containers/core/benchmark-base-external/Dockerfile @@ -20,7 +20,7 @@ RUN set -e; ok=0; \ if apt-get update --fix-missing \ && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ - curl ca-certificates git jq gettext-base; then ok=1; break; fi; \ + curl ca-certificates git jq; then ok=1; break; fi; \ echo "apt attempt $i failed; retry" >&2; sleep $((i*5)); \ done; \ [ "$ok" = 1 ] || { echo "apt install failed after 5 tries" >&2; exit 1; }; \ diff --git a/containers/core/benchmark-base-github/Dockerfile b/containers/core/benchmark-base-github/Dockerfile index 2aa81c94..82a8252d 100644 --- a/containers/core/benchmark-base-github/Dockerfile +++ b/containers/core/benchmark-base-github/Dockerfile @@ -14,7 +14,7 @@ RUN set -e; ok=0; \ if apt-get update --fix-missing \ && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ - curl ca-certificates git jq gettext-base; then ok=1; break; fi; \ + curl ca-certificates git jq; then ok=1; break; fi; \ echo "apt attempt $i failed; retry" >&2; sleep $((i*5)); \ done; \ [ "$ok" = 1 ] || { echo "apt install failed after 5 tries" >&2; exit 1; }; \ diff --git a/containers/core/benchmark-base-hf/Dockerfile b/containers/core/benchmark-base-hf/Dockerfile index e2b0b4d7..b81fe7f7 100644 --- a/containers/core/benchmark-base-hf/Dockerfile +++ b/containers/core/benchmark-base-hf/Dockerfile @@ -23,7 +23,7 @@ RUN set -e; ok=0; \ if apt-get update --fix-missing \ && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ - curl ca-certificates git jq gettext-base; then ok=1; break; fi; \ + curl ca-certificates git jq; then ok=1; break; fi; \ echo "apt attempt $i failed; retry" >&2; sleep $((i*5)); \ done; \ [ "$ok" = 1 ] || { echo "apt install failed after 5 tries" >&2; exit 1; }; \ diff --git a/containers/core/benchmark-base-python-slim/Dockerfile b/containers/core/benchmark-base-python-slim/Dockerfile index 1487a722..b1f5875f 100644 --- a/containers/core/benchmark-base-python-slim/Dockerfile +++ b/containers/core/benchmark-base-python-slim/Dockerfile @@ -15,7 +15,7 @@ LABEL eval.base.kind="python-slim" RUN set -e; ok=0; \ for i in 1 2 3 4 5; do \ if apt-get update --fix-missing && apt-get install -y --no-install-recommends \ - jq ca-certificates curl gettext-base; then ok=1; break; fi; \ + jq ca-certificates curl; then ok=1; break; fi; \ echo "apt attempt $i failed; retry" >&2; sleep $((i*5)); \ done; \ [ "$ok" = 1 ] || { echo "apt install failed after 5 tries" >&2; exit 1; }; \ diff --git a/containers/core/benchmark-base-slim/Dockerfile b/containers/core/benchmark-base-slim/Dockerfile index f580ea54..20ade178 100644 --- a/containers/core/benchmark-base-slim/Dockerfile +++ b/containers/core/benchmark-base-slim/Dockerfile @@ -13,7 +13,7 @@ LABEL eval.base.kind="slim" RUN set -e; ok=0; \ for i in 1 2 3 4 5; do \ if apt-get update --fix-missing && apt-get install -y --no-install-recommends \ - jq ca-certificates curl gettext-base; then ok=1; break; fi; \ + jq ca-certificates curl; then ok=1; break; fi; \ echo "apt attempt $i failed; retry" >&2; sleep $((i*5)); \ done; \ [ "$ok" = 1 ] || { echo "apt install failed after 5 tries" >&2; exit 1; }; \ diff --git a/containers/gateways/bifrost/Dockerfile b/containers/gateways/bifrost/Dockerfile index 21e896f0..361f64a5 100644 --- a/containers/gateways/bifrost/Dockerfile +++ b/containers/gateways/bifrost/Dockerfile @@ -14,7 +14,7 @@ # /opt/gateway/data/ also where bifrost writes its SQLite # # Honest size: ~105 MB. The Go binary is statically linked, ca-certs + -# envsubst are the only runtime deps. UI is `go:embed`-ed into the +# curl are the only runtime deps. UI is `go:embed`-ed into the # binary unconditionally upstream (no flag to strip without forking). # # Bifrost natively exposes the framework's path-prefix namespace @@ -32,7 +32,7 @@ LABEL gateway.kind="bifrost" LABEL gateway.bifrost_version="${BIFROST_VERSION}" LABEL gateway.translates_protocols="true" -RUN apk add --no-cache ca-certificates curl gettext +RUN apk add --no-cache ca-certificates curl # Pull just the binary out of the upstream distribution. The /app/data # directory and the dashboard's docker-entrypoint.sh are not copied — diff --git a/containers/gateways/litellm/Dockerfile b/containers/gateways/litellm/Dockerfile index f0749140..c70ce6cb 100644 --- a/containers/gateways/litellm/Dockerfile +++ b/containers/gateways/litellm/Dockerfile @@ -57,7 +57,7 @@ LABEL gateway.translates_protocols="true" # eval image (FROM benchmark-base-hf, debian) already has it; we add # it here so the same /opt/gateway/health works when this image runs # standalone in compose mode. -RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates gettext-base \ +RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \ && rm -rf /var/lib/apt/lists/* # Caddy: tiny shim that maps the framework's protocol-namespaced URLs diff --git a/containers/gateways/portkey/Dockerfile b/containers/gateways/portkey/Dockerfile index feda8f9d..01583a3e 100644 --- a/containers/gateways/portkey/Dockerfile +++ b/containers/gateways/portkey/Dockerfile @@ -31,7 +31,7 @@ LABEL gateway.portkey_version="${PORTKEY_VERSION}" LABEL gateway.translates_protocols="false" LABEL gateway.protocols="openai" -RUN apk add --no-cache ca-certificates curl gettext +RUN apk add --no-cache ca-certificates curl # Caddy: path-prefix + header-injection shim. COPY --from=docker.io/library/caddy:2.8-alpine /usr/bin/caddy /usr/bin/caddy diff --git a/containers/models/litellm/Dockerfile b/containers/models/litellm/Dockerfile index 975e3511..bc6eee88 100644 --- a/containers/models/litellm/Dockerfile +++ b/containers/models/litellm/Dockerfile @@ -1,6 +1,6 @@ # Provider-agnostic litellm gateway image. Provider, model name, and # credentials are resolved at runtime from env: -# UPSTREAM_MODEL / — e.g., openai/gpt-4, +# EVAL_MODEL / — e.g., openai/gpt-4, # anthropic/claude-3-5-sonnet, bedrock/anthropic... # Litellm parses the prefix natively to dispatch # to the right provider plugin. @@ -14,5 +14,5 @@ LABEL gateway.kind="litellm" # litellm reads /opt/gateway/config.yaml (set by gateways/litellm's # `start` script via --config /opt/gateway/config.yaml). We ship a -# TEMPLATE; the start script envsubsts UPSTREAM_MODEL into it at boot. +# TEMPLATE; the start script fills EVAL_MODEL into it at boot. COPY config.yaml.template /opt/gateway/config.yaml.template diff --git a/containers/models/litellm/config.yaml.template b/containers/models/litellm/config.yaml.template index f10c64a2..a92b46d8 100644 --- a/containers/models/litellm/config.yaml.template +++ b/containers/models/litellm/config.yaml.template @@ -1,5 +1,5 @@ # Provider-agnostic litellm config. EVAL_MODEL=/ -# (envsubst'd at startup) tells litellm which provider plugin to dispatch +# (rendered at startup) tells litellm which provider plugin to dispatch # to and which upstream model name to use. Upstream credentials are read # via `os.environ/VAR` — by provider-native names, whatever the user's # SDK conventionally reads (OPENAI_API_KEY+OPENAI_API_BASE for OpenAI-