feat(agents): add model fallback configuration

This commit is contained in:
Duy Nguyen committed 2026-05-17 15:51:56 +07:00
1 parent 5a189330f9
commit 506e96cd63
30 files changed
+974 -32

No files matched your search

+10 -7
View File
@@ -35,7 +35,7 @@ const agentSelectCols = `id, agent_key, display_name, frontmatter, owner_id, pro
emoji, agent_description, thinking_level, max_tokens,
self_evolve, skill_evolve, skill_nudge_interval,
reasoning_config, workspace_sharing, chatgpt_oauth_routing,
shell_deny_groups, kg_dedup_config,
model_fallback, shell_deny_groups, kg_dedup_config,
agent_type, is_default, status, budget_monthly_cents, created_at, updated_at, tenant_id`
func (s *SQLiteAgentStore) Create(ctx context.Context, agent *store.AgentData) error {
@@ -57,9 +57,9 @@ func (s *SQLiteAgentStore) Create(ctx context.Context, agent *store.AgentData) e
emoji, agent_description, thinking_level, max_tokens,
self_evolve, skill_evolve, skill_nudge_interval,
reasoning_config, workspace_sharing, chatgpt_oauth_routing,
shell_deny_groups, kg_dedup_config,
model_fallback, shell_deny_groups, kg_dedup_config,
agent_type, is_default, status, budget_monthly_cents, created_at, updated_at, tenant_id)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
agent.ID, agent.AgentKey,
agent.DisplayName,
sql.NullString{String: agent.Frontmatter, Valid: agent.Frontmatter != ""},
@@ -70,7 +70,7 @@ func (s *SQLiteAgentStore) Create(ctx context.Context, agent *store.AgentData) e
agent.Emoji, agent.AgentDescription, agent.ThinkingLevel, agent.MaxTokens,
agent.SelfEvolve, agent.SkillEvolve, agent.SkillNudgeInterval,
jsonOrEmpty(agent.ReasoningConfig), jsonOrEmpty(agent.WorkspaceSharing), jsonOrEmpty(agent.ChatGPTOAuthRouting),
jsonOrEmpty(agent.ShellDenyGroups), jsonOrEmpty(agent.KGDedupConfig),
jsonOrEmpty(agent.ModelFallback), jsonOrEmpty(agent.ShellDenyGroups), jsonOrEmpty(agent.KGDedupConfig),
agent.AgentType, agent.IsDefault, agent.Status, agent.BudgetMonthlyCents,
now, now, tenantID,
)
@@ -151,7 +151,7 @@ func (s *SQLiteAgentStore) Update(ctx context.Context, id uuid.UUID, updates map
}
}
// NOT NULL JSON columns: null → empty object.
for _, col := range []string{"other_config", "tools_config", "reasoning_config", "workspace_sharing", "chatgpt_oauth_routing", "shell_deny_groups", "kg_dedup_config"} {
for _, col := range []string{"other_config", "tools_config", "reasoning_config", "workspace_sharing", "chatgpt_oauth_routing", "model_fallback", "shell_deny_groups", "kg_dedup_config"} {
if v, ok := updates[col]; ok && v == nil {
updates[col] = []byte("{}")
}
@@ -257,7 +257,7 @@ func scanAgentRow(row agentRowScanner) (*store.AgentData, error) {
var d store.AgentData
var frontmatter sql.NullString
var toolsCfg, sandboxCfg, subagentsCfg, memoryCfg, compactionCfg, pruningCfg, otherCfg *[]byte
var reasoningCfg, wsCfg, oauthCfg, shellCfg, kgCfg *[]byte
var reasoningCfg, wsCfg, oauthCfg, fallbackCfg, shellCfg, kgCfg *[]byte
createdAt, updatedAt := scanTimePair()
err := row.Scan(
&d.ID, &d.AgentKey, &d.DisplayName, &frontmatter, &d.OwnerID, &d.Provider, &d.Model,
@@ -265,7 +265,7 @@ func scanAgentRow(row agentRowScanner) (*store.AgentData, error) {
&toolsCfg, &sandboxCfg, &subagentsCfg, &memoryCfg, &compactionCfg, &pruningCfg, &otherCfg,
&d.Emoji, &d.AgentDescription, &d.ThinkingLevel, &d.MaxTokens,
&d.SelfEvolve, &d.SkillEvolve, &d.SkillNudgeInterval,
&reasoningCfg, &wsCfg, &oauthCfg, &shellCfg, &kgCfg,
&reasoningCfg, &wsCfg, &oauthCfg, &fallbackCfg, &shellCfg, &kgCfg,
&d.AgentType, &d.IsDefault, &d.Status, &d.BudgetMonthlyCents,
createdAt, updatedAt, &d.TenantID,
)
@@ -307,6 +307,9 @@ func scanAgentRow(row agentRowScanner) (*store.AgentData, error) {
if oauthCfg != nil {
d.ChatGPTOAuthRouting = *oauthCfg
}
if fallbackCfg != nil {
d.ModelFallback = *fallbackCfg
}
if shellCfg != nil {
d.ShellDenyGroups = *shellCfg
}
+6 -3
View File
@@ -16,7 +16,7 @@ var schemaSQL string
// SchemaVersion is the current SQLite schema version.
// Bump this when adding new migration steps below.
const SchemaVersion = 33
const SchemaVersion = 34
// migrations maps version → SQL to apply when upgrading FROM that version.
// schema.sql always represents the LATEST full schema (for fresh DBs).
@@ -593,6 +593,9 @@ CREATE INDEX IF NOT EXISTS idx_ws_activity_ws_time ON workstation_activity(w
CREATE INDEX IF NOT EXISTS idx_ws_activity_tenant_time ON workstation_activity(tenant_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ws_activity_retention ON workstation_activity(created_at);`,
// Version 33 → 34: per-agent ordered provider/model fallback config.
33: `ALTER TABLE agents ADD COLUMN model_fallback TEXT NOT NULL DEFAULT '{}';`,
// Version 23 → 24: vault_documents scope/ownership consistency triggers.
// Mirrors PG migration 000055 CHECK constraint; SQLite cannot add CHECK via
// ALTER TABLE so we use BEFORE INSERT + BEFORE UPDATE triggers instead.
@@ -764,8 +767,8 @@ CREATE TABLE IF NOT EXISTS tenant_hook_budget (
);`
// backfillV16 populates base_name / path_basename for rows that existed
// before the v15 → v16 migration. Idempotent — re-running on already-filled
// rows is a no-op thanks to the WHERE base_name = '' filter.
// before the v15 -> v16 migration. Idempotent; re-running on already-filled
// rows is a no-op for already-filled base_name values.
func backfillV16(ctx context.Context, db *sql.DB) error {
type row struct{ id, path string }
+1
View File
@@ -126,6 +126,7 @@ CREATE TABLE IF NOT EXISTS agents (
reasoning_config TEXT NOT NULL DEFAULT '{}',
workspace_sharing TEXT NOT NULL DEFAULT '{}',
chatgpt_oauth_routing TEXT NOT NULL DEFAULT '{}',
model_fallback TEXT NOT NULL DEFAULT '{}',
shell_deny_groups TEXT NOT NULL DEFAULT '{}',
kg_dedup_config TEXT NOT NULL DEFAULT '{}',
is_default BOOLEAN NOT NULL DEFAULT 0,