mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-10-03 15:44:05 +00:00
feat: config.yaml only, OpenRouter free models, remove runtime.json config
- Move all config (auto rules, keys) from runtime.json to config.yaml - Store now only holds runtime sources (WebUI-created) - Add OpenRouter free models to config.yaml - One-time migration from legacy runtime.json on startup - Fix gateway tests for new config structure - Update core.go with migrateFromRuntime, saveConfig, seedKeys/seedAuto - Remove SaveKey/KeyByValue/AutoRules from Store - Add Config.Save() with YAML marshaling - Update WebUI admin keys visibility (show all keys including admin) - Bump binary to 11MB with luajit
This commit is contained in:
@ -37,9 +37,13 @@ func mockUpstream() *httptest.Server {
|
||||
|
||||
func newTestGateway(t *testing.T, srcs ...config.Source) *Gateway {
|
||||
t.Helper()
|
||||
td := t.TempDir()
|
||||
cfgPath := filepath.Join(td, "config.yaml")
|
||||
os.WriteFile(cfgPath, []byte("listen: :0"), 0644)
|
||||
cfg := &config.Config{
|
||||
AdapterDir: filepath.Join(t.TempDir(), "adapters"),
|
||||
RuntimeFile: filepath.Join(t.TempDir(), "runtime.json"),
|
||||
Path: cfgPath,
|
||||
AdapterDir: filepath.Join(td, "adapters"),
|
||||
RuntimeFile: filepath.Join(td, "runtime.json"),
|
||||
GatewayKeys: []string{"sk-test"},
|
||||
Sources: srcs,
|
||||
}
|
||||
@ -543,9 +547,9 @@ func TestSourcesAPIAddAndPersist(t *testing.T) {
|
||||
if !strings.Contains(rr.Body.String(), "new-m") {
|
||||
t.Fatalf("new model not live: %s", rr.Body.String())
|
||||
}
|
||||
// verify persistence file exists
|
||||
if _, err := os.Stat(g.core.Config().RuntimeFile); err != nil {
|
||||
t.Fatalf("runtime file not written: %v", err)
|
||||
// verify source persisted to config.yaml
|
||||
if _, err := os.Stat(g.core.Config().Path); err != nil {
|
||||
t.Fatalf("config file not written: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -203,9 +203,10 @@ textarea{min-height:200px;resize:vertical;font-family:'JetBrains Mono',ui-monosp
|
||||
select{cursor:pointer}
|
||||
label{display:block;font-size:12px;color:var(--muted);margin:12px 0 5px}
|
||||
.row{display:flex;gap:12px}.row>div{flex:1}
|
||||
.model-row{display:flex;gap:8px;align-items:center}
|
||||
.model-row input,.model-row select{margin:0 0 8px}
|
||||
.model-row .del{flex:0 0 auto;padding:5px 9px}
|
||||
.model-row{display:flex;gap:6px;align-items:center;width:100%}
|
||||
.model-row .m-id{flex:1;min-width:0;width:0}
|
||||
.model-row .m-kind{flex:0 0 70px;width:70px}
|
||||
.model-row .del{flex:0 0 auto;padding:4px 8px}
|
||||
.muted{color:var(--muted)}
|
||||
.hidden,.hidden#tab-chat{display:none}
|
||||
#toast{position:fixed;bottom:24px;right:24px;z-index:100;background:var(--card-solid);border:1px solid var(--line);
|
||||
@ -2179,7 +2180,7 @@ async function renderKeysAdmin() {
|
||||
async function loadKeys() {
|
||||
const el = $('#k-list'); if (!el) return;
|
||||
const j = await api('/api/keys');
|
||||
const ks = (j.keys || []).filter(k => k.role === 'user');
|
||||
const ks = (j.keys || []);
|
||||
el.innerHTML = ks.length ? ks.map(k => keyCanvasHtml(k)).join('') : `<div class="muted">${t('kEmpty')}</div>`;
|
||||
el.querySelectorAll('.kc-blocks').forEach(cv => bindCanvasDrop(cv));
|
||||
el.querySelectorAll('.mb').forEach(b => bindBrickDrag(b));
|
||||
|
||||
Reference in New Issue
Block a user