llmrouter: Namensräume openrouter/, alt/, role/; Klasse über drei Indexe relativ

- openrouter/<id>[:effort] 1:1, alt/<id>[:effort] günstigste Alternative auf
  Abruf (ohne Last-Probe, im Takt erneuert), role/<name> aus config.rollen
- Klasse: Intelligence, Coding, Agentic je >= 95 % der Referenz (relativ statt
  3 Punkte), Kontext >= 90 %, billiger; Kandidaten auch ohne OpenRouter-Index,
  wenn AA Stufen kennt (OpenRouter führt Intelligence nur für 53 Modelle)
- ACL-Muster mit *, /models mit allen Konto-Modellen je Namensraum und Stufe
- Rollen aus der LiteLLM-Zeit übernommen (Führung high, Rest medium)
Andreas 2026-09-05.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-05 09:47:22 +02:00
committed by andreas
co-authored by Claude Fable 5.1
parent e13baaab28
commit 34d6c08a3d
6 changed files with 299 additions and 127 deletions
+9 -1
View File
@@ -26,6 +26,8 @@ export type Config = {
altnamen?: Record<string, string>;
/** Unbekannte Modellnamen unveraendert an diesen Upstream (Parallelbetrieb mit LiteLLM). */
fallback?: { upstream: string };
/** role/<name> -> Zielname (42i/*, openrouter/*, alt/*). Agenten kennen nur Rollen; Modelle stellt man hier um. */
rollen?: Record<string, string>;
};
export const BASE = resolve(dirname(import.meta.path), "..");
@@ -45,7 +47,7 @@ export function configLaden(): Config {
return c;
}
/** Name -> erlaubte Aliasse; leere Liste = alles. */
/** Name -> erlaubte Namen oder Muster (`openrouter/*`, `alt/*`, `role/*`); leere Liste = alles. */
export function aclLaden(): Map<string, string[]> {
const pfad = process.env.LLMROUTER_ACLS ?? `${dirname(CONFIG_PATH)}/key-acls.json`;
const d = JSON.parse(readFileSync(pfad, "utf8")) as { keys: Record<string, string[]> };
@@ -63,6 +65,12 @@ export function tokenLaden(): Map<string, string> {
}
}
/** Prueft einen angefragten Namen gegen die ACL-Liste; `*` am Ende ist ein Praefix-Muster. */
export function erlaubt(liste: string[], name: string): boolean {
if (liste.length === 0) return true;
return liste.some((m) => (m.endsWith("*") ? name.startsWith(m.slice(0, -1)) : m === name));
}
export function upstreamKey(u: Upstream): string | undefined {
return u.keyEnv === undefined ? undefined : process.env[u.keyEnv];
}