From d211eb6150a7b4a615463be64c0d88a00c3494db Mon Sep 17 00:00:00 2001 From: infosave2007 Date: Wed, 8 Jul 2026 17:39:43 +0300 Subject: [PATCH] feat: fresh install starts with an empty model pool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - config.rs: validate() no longer errors on zero models — an empty pool is allowed (warns instead), so the admin console comes up on a fresh install and the user adds models in /admin -> Models (or points [cmf] at a local .cmf). - gateway.example.toml: ships an EMPTY pool (no seed cmf-local/local-embed, empty routing), so `cp example -> gateway.toml && run` shows an empty list — what a new user expects. --- config/gateway.example.toml | 45 ++++++++++++++----------------------- src/config.rs | 7 +++++- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/config/gateway.example.toml b/config/gateway.example.toml index 641627a..7f269fe 100644 --- a/config/gateway.example.toml +++ b/config/gateway.example.toml @@ -28,40 +28,29 @@ cache_ttl = "60s" profile = "balanced" # cost-saver | balanced | quality-first # ============================================================================ -# Model pool. This example ships ONE local CMF model, served by the managed -# cortiq server (see the [cmf] section below). Add more models — local or cloud — -# by copying the [[models]] shape: provider = "openai"/"anthropic", and for a -# hosted provider an api_key_env = "..." (never put secrets in this file). +# Model pool — EMPTY by default. A fresh gateway starts with no models and an +# empty pool; add them in the admin console (/admin → Models), or run a local +# .cmf via the [cmf] section below. To add one by hand, copy this shape: +# +# [[models]] +# id = "my-model" +# provider = "openai" # openai | anthropic (openai also covers +# base_url = "http://127.0.0.1:8081/v1" # OpenRouter/Together/Groq/vLLM/Ollama) +# model = "my-model" +# # api_key_env = "OPENAI_API_KEY" # for hosted providers (never inline a key) +# cost_tier = "local" +# caps = ["tools"] # ============================================================================ -[[models]] -id = "cmf-local" -provider = "openai" -base_url = "http://127.0.0.1:8081/v1" # the managed cortiq server (see [cmf]) -model = "cmf-local" -cost_tier = "local" -price_in = 0.0 -price_out = 0.0 -caps = ["tools"] - -# --- embedding model (optional: /v1/embeddings + the semantic cache) --------- -[[models]] -id = "local-embed" -provider = "openai" -base_url = "http://localhost:8000/v1" # a local embeddings server (vLLM / llama.cpp / Ollama) -model = "nomic-embed-text" -cost_tier = "local" -kind = "embedding" - # ============================================================================ # Routing table: complexity tier → ordered pool (priority = fallback chain). -# Add cloud models above and list them here for cost/quality-based fallback. +# Leave default empty for a fresh install; set it to a model id once you add one. # ============================================================================ [routing] -low = ["cmf-local"] -medium = ["cmf-local"] -high = ["cmf-local"] -default = "cmf-local" # used when the router is unreachable +low = [] +medium = [] +high = [] +default = "" # set to a model id once you add one [routing.policy] mode = "fixed_table" # fixed_table | cost_aware diff --git a/src/config.rs b/src/config.rs index 94b0bbb..56845df 100644 --- a/src/config.rs +++ b/src/config.rs @@ -599,7 +599,12 @@ impl Config { // is what lets the gateway run on local models alone (no cloud, no router). let has_local = self.cmf.manage_server && !self.cmf.local_model.trim().is_empty(); if self.models.is_empty() && !has_local { - anyhow::bail!("config: at least one [[models]] entry (or a managed local CMF model) is required"); + // Fresh install: start with an EMPTY model pool so the admin console + // comes up — the user adds models in /admin → Models (or points [cmf] + // at a local .cmf). Routing simply has nothing to select until then. + tracing::warn!( + "no models configured — starting with an empty pool; add one in /admin → Models" + ); } // uniqueness of model ids let mut seen = std::collections::HashSet::new();