chore(router): address the hosted router by hostname, TLS verification on
Docker / publish (push) Canceled after 0s
Release / crates-io (push) Canceled after 0s
Release / release (macos-14, aarch64-apple-darwin) (push) Canceled after 0s
Release / release (ubuntu-latest, x86_64-unknown-linux-gnu) (push) Canceled after 0s
Release / release (windows-latest, x86_64-pc-windows-msvc) (push) Canceled after 0s

router.allaigate.com now resolves and serves a valid certificate, so the
hosted routing API no longer has to be reached by bare IP with certificate
verification switched off. Make https://router.allaigate.com the default
[router].url with verify_tls = true.

Existing configs still pointing at 138.226.222.209 (with or without a scheme
or a trailing slash) are moved to the hostname on load and have verification
restored, then saved: it is the same machine, and this is the difference
between a verified connection and a blind one. A self-hosted router URL is
left untouched.

README, docs/ROUTER.md (both languages), config/gateway.example.toml and
bench/accuracy.py follow.

Verified live: the migration rewrites a legacy config on startup, admin
health reports the hostname reachable over verified TLS (389 ms), and real
requests route through it - "math"/medium 0.416 and "translation"/low 0.268
with route_source=router.
This commit is contained in:
infosave2007
2026-08-21 13:21:24 +03:00
parent f65f131c41
commit 9c15109f26
10 changed files with 107 additions and 23 deletions
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/).
## [0.2.47] - 2026-08-21
### Changed
- **The hosted allaigate router is addressed by hostname:
`https://router.allaigate.com`** is now the default `[router].url`, and
`verify_tls` defaults to `true`. The endpoint used to be reachable only by bare IP,
whose certificate is issued for the hostname — so every hosted setup had to run with
certificate verification switched off. It no longer does.
- **Existing configs are migrated on load.** A `[router].url` still pointing at the old
`138.226.222.209` (with or without a scheme or trailing slash) is rewritten to the
hostname, `verify_tls` is turned back on, and the file is saved — the endpoint is the
same machine, and this is the difference between a verified connection and a blind one.
A self-hosted router URL is never touched.
- README, `docs/ROUTER.md` (both languages), `config/gateway.example.toml` and
`bench/accuracy.py` updated to the hostname.
## [0.2.46] - 2026-08-21
Verified end to end against a real Open WebUI container talking to the gateway.
Generated
+1 -1
View File
@@ -285,7 +285,7 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "cortiq-gateway"
version = "0.2.46"
version = "0.2.47"
dependencies = [
"anyhow",
"arc-swap",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "cortiq-gateway"
version = "0.2.46"
version = "0.2.47"
edition = "2021"
rust-version = "1.75"
license = "Apache-2.0"
+3 -3
View File
@@ -175,9 +175,9 @@ print(resp.choices[0].message.content)
`model: "cortiq-auto"` enables routing. Any **real** model name from the config
(`"gpt-4o-mini"`, `"local-qwen"`) is a direct passthrough, without routing.
> **Using the hosted allaigate router?** Set `url = "https://138.226.222.209"`,
> `verify_tls = false`, `taxonomy_id = "data-assistant"`, and a `cortiq_…` key in
> `CORTIQ_ROUTER_KEY`. On hard prompts the router escalates to an oracle (~10 s), so
> **Using the hosted allaigate router?** It is the default: `url =
> "https://router.allaigate.com"` with `verify_tls = true`. Set `taxonomy_id =
> "data-assistant"` and a `cortiq_…` key in `CORTIQ_ROUTER_KEY`. On hard prompts the router escalates to an oracle (~10 s), so
> set `timeout_ms = 12000+` — otherwise the gateway gracefully degrades to the default model.
---
+3 -3
View File
@@ -167,9 +167,9 @@ print(resp.choices[0].message.content)
`model: "cortiq-auto"` включает роутинг. Любое **реальное** имя модели из конфига
(`"gpt-4o-mini"`, `"local-qwen"`) — это passthrough напрямую, без роутинга.
> **Используете хостовый allaigate-роутер?** Укажите `url = "https://138.226.222.209"`,
> `verify_tls = false`, `taxonomy_id = "data-assistant"` и ключ `cortiq_…` в
> `CORTIQ_ROUTER_KEY`. На сложных запросах роутер эскалирует к oracle (~10 с), поэтому
> **Используете хостовый allaigate-роутер?** Он стоит по умолчанию: `url =
> "https://router.allaigate.com"`, `verify_tls = true`. Задайте `taxonomy_id =
> "data-assistant"` и ключ `cortiq_…` в `CORTIQ_ROUTER_KEY`. На сложных запросах роутер эскалирует к oracle (~10 с), поэтому
> ставьте `timeout_ms = 12000+` — иначе шлюз мягко деградирует на default-модель.
---
+2 -2
View File
@@ -4,12 +4,12 @@ heuristic (what you get without a semantic classifier, e.g. with LiteLLM/Portkey
CORTIQ_ROUTER_KEY=cortiq_... python3 bench/accuracy.py
Env: CORTIQ_ROUTER_KEY (required), ROUTER_URL (default https://138.226.222.209),
Env: CORTIQ_ROUTER_KEY (required), ROUTER_URL (default https://router.allaigate.com),
TAXONOMY (default data-assistant).
"""
import json, os, ssl, sys, urllib.request
ROUTER_URL = os.environ.get("ROUTER_URL", "https://138.226.222.209").rstrip("/")
ROUTER_URL = os.environ.get("ROUTER_URL", "https://router.allaigate.com").rstrip("/")
TAXONOMY = os.environ.get("TAXONOMY", "data-assistant")
KEY = os.environ.get("CORTIQ_ROUTER_KEY", "")
CTX = ssl._create_unverified_context()
+2 -2
View File
@@ -8,13 +8,13 @@
listen = "0.0.0.0:9000"
# --- connection to cortiq-router (decides task type / complexity) -----------
# Hosted allaigate router: url = "https://138.226.222.209", verify_tls = false
# Hosted allaigate router: url = "https://router.allaigate.com" (the default)
# (cert is bound to an IP), taxonomy_id = "data-assistant", a cortiq_… key in
# CORTIQ_ROUTER_KEY.
# NOTE: on hard prompts the router escalates to an oracle LLM (~10 s) — for the
# hosted router set timeout_ms = 12000+, otherwise the gateway degrades to default.
[router]
url = "https://138.226.222.209" # hosted allaigate router (or your own cortiq-router URL)
url = "https://router.allaigate.com" # hosted allaigate router (or your own cortiq-router URL)
api_key_env = "CORTIQ_ROUTER_KEY" # name of the env var holding the router key
timeout_ms = 12000 # hard prompts escalate to an oracle (~10 s)
taxonomy_id = "data-assistant" # the hosted router's task taxonomy
+4 -4
View File
@@ -41,11 +41,11 @@ minted and shown to you.
```toml
[router]
url = "https://138.226.222.209" # allaigate routing API
verify_tls = false # cert is bound to an IP
url = "https://router.allaigate.com" # allaigate routing API (the default)
verify_tls = true # valid certificate — keep verification on
taxonomy_id = "data-assistant"
api_key_env = "CORTIQ_ROUTER_KEY" # your cortiq_… key
timeout_ms = 15000 # allow for oracle escalation on hard prompts
api_key_env = "CORTIQ_ROUTER_KEY" # your cortiq_… key
timeout_ms = 15000 # allow for oracle escalation on hard prompts
```
```bash
+4 -4
View File
@@ -40,11 +40,11 @@ Cortiq Gateway — тонкий и быстрый прокси; **интелле
```toml
[router]
url = "https://138.226.222.209" # routing API allaigate
verify_tls = false # серт привязан к IP
url = "https://router.allaigate.com" # routing API allaigate (значение по умолчанию)
verify_tls = true # валидный сертификат — проверку не выключаем
taxonomy_id = "data-assistant"
api_key_env = "CORTIQ_ROUTER_KEY" # ваш ключ cortiq_…
timeout_ms = 15000 # запас под oracle-эскалацию на сложных запросах
api_key_env = "CORTIQ_ROUTER_KEY" # ваш ключ cortiq_…
timeout_ms = 15000 # запас под oracle-эскалацию на сложных запросах
```
```bash
+71 -3
View File
@@ -318,6 +318,34 @@ fn default_verify_tls() -> bool {
true
}
/// The hosted allaigate routing API.
pub const DEFAULT_ROUTER_URL: &str = "https://router.allaigate.com";
/// The bare IP the hosted router used to be addressed by. It served a
/// certificate for `router.allaigate.com`, so every config pointing at it had to
/// turn TLS verification off. The hostname now resolves, so configs written
/// before it existed are moved over on load — the endpoint is the same machine,
/// and this is the difference between a verified connection and a blind one.
const LEGACY_ROUTER_HOSTS: &[&str] = &[
"https://138.226.222.209",
"http://138.226.222.209",
"138.226.222.209",
];
impl RouterCfg {
/// Point a legacy IP-addressed router config at the hostname and restore TLS
/// verification. Returns true when something changed.
fn migrate_hosted_endpoint(&mut self) -> bool {
let url = self.url.trim().trim_end_matches('/');
if !LEGACY_ROUTER_HOSTS.contains(&url) {
return false;
}
self.url = DEFAULT_ROUTER_URL.to_string();
self.verify_tls = true;
true
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RouteCfg {
#[serde(default = "default_text_strategy")]
@@ -882,9 +910,9 @@ impl Default for Config {
// models and the console asks for one; nothing breaks.
router: RouterCfg {
enabled: true,
url: "https://138.226.222.209".to_string(),
url: DEFAULT_ROUTER_URL.to_string(),
timeout_ms: 15_000, // hard prompts escalate to an oracle (~10 s)
verify_tls: false, // the hosted endpoint is IP-bound
verify_tls: true,
api_key_env: Some("CORTIQ_ROUTER_KEY".to_string()),
taxonomy_id: Some("data-assistant".to_string()),
},
@@ -954,7 +982,14 @@ impl Config {
pub fn load(path: &str) -> anyhow::Result<Self> {
let raw = std::fs::read_to_string(path)
.map_err(|e| anyhow::anyhow!("cannot read config {path}: {e}"))?;
let cfg: Config = toml::from_str(&raw)?;
let mut cfg: Config = toml::from_str(&raw)?;
if cfg.router.migrate_hosted_endpoint() {
tracing::info!(
url = DEFAULT_ROUTER_URL,
"router endpoint moved from the bare IP to the hostname; TLS verification is on"
);
let _ = cfg.save(path);
}
cfg.validate()?;
Ok(cfg)
}
@@ -1091,6 +1126,39 @@ impl Config {
mod tests {
use super::*;
#[test]
fn the_hosted_router_defaults_to_the_hostname_with_tls_on() {
let cfg = Config::default();
assert_eq!(cfg.router.url, "https://router.allaigate.com");
assert!(cfg.router.verify_tls);
}
#[test]
fn a_legacy_ip_router_config_moves_to_the_hostname() {
for legacy in [
"https://138.226.222.209",
"https://138.226.222.209/",
"138.226.222.209",
] {
let mut r = Config::default().router;
r.url = legacy.to_string();
r.verify_tls = false;
assert!(r.migrate_hosted_endpoint(), "{legacy} must migrate");
assert_eq!(r.url, DEFAULT_ROUTER_URL);
assert!(r.verify_tls, "TLS verification must be restored");
}
}
#[test]
fn a_self_hosted_router_url_is_left_alone() {
let mut r = Config::default().router;
r.url = "http://127.0.0.1:8081".to_string();
r.verify_tls = false;
assert!(!r.migrate_hosted_endpoint());
assert_eq!(r.url, "http://127.0.0.1:8081");
assert!(!r.verify_tls);
}
const SAMPLE: &str = r#"
listen = "0.0.0.0:9000"