From a3a6f765e79bc87c88394b88239a2cefded0378d Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Thu, 7 May 2026 12:01:28 -0400 Subject: [PATCH] feat: add logic_level and primary_use metadata to model groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Schema: Added logic_level (INTEGER) and primary_use (TEXT) columns to model_groups table with auto-migration for existing databases. Seed: Three new default groups: heavy-logic (level 9) — Complex Coding, Logic, Agents standard-pro (level 5) — General Assistant, Long Docs fast-flow (level 2) — Classification, JSON, Basic Q&A Admin API: INSERT/UPDATE handlers now accept and persist the new fields. Dashboard: Table shows Level and Primary Use columns; form includes both fields with appropriate inputs and placeholders. --- internal/db/db.go | 26 +++++++++++++++++++++----- internal/server/model_groups_admin.go | 10 +++++----- static/js/pages/model_groups.js | 20 +++++++++++++++++++- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/internal/db/db.go b/internal/db/db.go index c7156d82..8203da3a 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -130,6 +130,8 @@ func (db *DB) RunMigrations() error { targets TEXT NOT NULL DEFAULT '[]', complexity_threshold INTEGER, heuristic_rules TEXT, + logic_level INTEGER, + primary_use TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP )`, @@ -162,6 +164,10 @@ func (db *DB) RunMigrations() error { } } + // Add columns to existing model_groups tables (safe — SQLite ignores duplicates on error) + db.Exec("ALTER TABLE model_groups ADD COLUMN logic_level INTEGER") + db.Exec("ALTER TABLE model_groups ADD COLUMN primary_use TEXT") + // Default admin user var count int if err := db.Get(&count, "SELECT COUNT(*) FROM users"); err != nil { @@ -190,14 +196,19 @@ func (db *DB) RunMigrations() error { // Seed default model groups defaultGroups := []struct { id, strategy, targets string + logicLevel *int + primaryUse *string }{ - {"deepseek-auto", "heuristic", `["deepseek-chat","deepseek-reasoner"]`}, - {"openai-auto", "heuristic", `["gpt-4o-mini","gpt-4o"]`}, - {"gemini-auto", "heuristic", `["gemini-2.0-flash","gemini-2.5-pro"]`}, + {"deepseek-auto", "heuristic", `["deepseek-chat","deepseek-reasoner"]`, nil, nil}, + {"openai-auto", "heuristic", `["gpt-4o-mini","gpt-4o"]`, nil, nil}, + {"gemini-auto", "heuristic", `["gemini-2.0-flash","gemini-2.5-pro"]`, nil, nil}, + {"heavy-logic", "heuristic", `["grok-4.3","kimi-k2.5","deepseek-v4-pro"]`, intPtr(9), strPtr("Complex Coding, Logic, Agents.")}, + {"standard-pro", "heuristic", `["gpt-5.4-mini","gemini-3-flash"]`, intPtr(5), strPtr("General Assistant, Long Docs.")}, + {"fast-flow", "heuristic", `["deepseek-v4-flash","gpt-5.4-nano"]`, intPtr(2), strPtr("Classification, JSON, Basic Q&A.")}, } for _, g := range defaultGroups { - db.Exec(`INSERT OR IGNORE INTO model_groups (id, strategy, targets) VALUES (?, ?, ?)`, - g.id, g.strategy, g.targets) + db.Exec(`INSERT OR IGNORE INTO model_groups (id, strategy, targets, logic_level, primary_use) VALUES (?, ?, ?, ?, ?)`, + g.id, g.strategy, g.targets, g.logicLevel, g.primaryUse) } return nil @@ -293,6 +304,11 @@ type ModelGroup struct { Targets string `db:"targets" json:"targets"` // JSON array ComplexityThreshold *int `db:"complexity_threshold" json:"complexity_threshold"` HeuristicRules *string `db:"heuristic_rules" json:"heuristic_rules"` + LogicLevel *int `db:"logic_level" json:"logic_level"` + PrimaryUse *string `db:"primary_use" json:"primary_use"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } + +func intPtr(v int) *int { return &v } +func strPtr(v string) *string { return &v } diff --git a/internal/server/model_groups_admin.go b/internal/server/model_groups_admin.go index f804f212..e68a6eda 100644 --- a/internal/server/model_groups_admin.go +++ b/internal/server/model_groups_admin.go @@ -28,10 +28,10 @@ func (s *Server) handleCreateModelGroup(c *gin.Context) { } _, err := s.database.Exec(` - INSERT INTO model_groups (id, strategy, selector_model, targets, complexity_threshold, heuristic_rules) - VALUES (?, ?, ?, ?, ?, ?)`, + INSERT INTO model_groups (id, strategy, selector_model, targets, complexity_threshold, heuristic_rules, logic_level, primary_use) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, group.ID, group.Strategy, group.SelectorModel, group.Targets, - group.ComplexityThreshold, group.HeuristicRules) + group.ComplexityThreshold, group.HeuristicRules, group.LogicLevel, group.PrimaryUse) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return @@ -50,10 +50,10 @@ func (s *Server) handleUpdateModelGroup(c *gin.Context) { } _, err := s.database.Exec(` - UPDATE model_groups SET strategy=?, selector_model=?, targets=?, complexity_threshold=?, heuristic_rules=?, updated_at=CURRENT_TIMESTAMP + UPDATE model_groups SET strategy=?, selector_model=?, targets=?, complexity_threshold=?, heuristic_rules=?, logic_level=?, primary_use=?, updated_at=CURRENT_TIMESTAMP WHERE id=?`, group.Strategy, group.SelectorModel, group.Targets, - group.ComplexityThreshold, group.HeuristicRules, id) + group.ComplexityThreshold, group.HeuristicRules, group.LogicLevel, group.PrimaryUse, id) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return diff --git a/static/js/pages/model_groups.js b/static/js/pages/model_groups.js index a85be0a3..91d69ee6 100644 --- a/static/js/pages/model_groups.js +++ b/static/js/pages/model_groups.js @@ -30,12 +30,14 @@ class ModelGroupsPage { } let html = ''; - html += ''; + html += ''; html += ''; groups.forEach(g => { html += ''; html += ''; + html += ''; + html += ''; html += ''; html += ''; html += '
Group IDStrategyTargetsActionsGroup IDLevelPrimary UseStrategyTargetsActions
' + this.esc(g.id) + '' + (g.logic_level != null ? g.logic_level : '—') + '' + this.esc(g.primary_use || '—') + '' + this.esc(g.strategy) + '' + this.esc(g.targets) + ''; @@ -106,6 +108,18 @@ class ModelGroupsPage { Pattern to match in user messages. target = index into targets array. +
+ + + Rough complexity scale. 1-3: fast/light, 4-7: standard, 8-10: heavy. +
+
+ + + Brief description of what this group is best used for. +
@@ -129,12 +143,16 @@ class ModelGroupsPage { var selectorModel = document.getElementById('mg-selector-model').value.trim() || null; var thresholdVal = document.getElementById('mg-threshold').value; var rules = document.getElementById('mg-rules').value.trim() || null; + var logicLevelVal = document.getElementById('mg-level').value; + var primaryUse = document.getElementById('mg-primary-use').value.trim() || null; try { JSON.parse(targets); } catch (e) { alert('Targets must be valid JSON array'); return; } if (rules) { try { JSON.parse(rules); } catch (e) { alert('Heuristic rules must be valid JSON'); return; } } var body = { id: id, strategy: strategy, targets: targets, selector_model: selectorModel, heuristic_rules: rules }; if (thresholdVal) body.complexity_threshold = parseInt(thresholdVal); + if (logicLevelVal) body.logic_level = parseInt(logicLevelVal); + if (primaryUse) body.primary_use = primaryUse; try { if (isEdit) {