From 248a39ba0c023db6fcce846bd90c023cb81f197f Mon Sep 17 00:00:00 2001 From: steelstring <42084164+steelstring@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:49:19 +0800 Subject: [PATCH] This fixes a data integrity issue affecting fresh installations of Desktop Lite and any environment where agent.other_config and serveral columns are not pre-initialized. This will stop Desktop Lite edtion from saving any agent setting. (#897) The root cause is missing default initialization of JSON field in update flow, leading to NOT NULL violations in both SQLite and Postgres. Fix ensures consistent behavior across Lite and Standard deployments. Co-authored-by: Viet Tran Co-authored-by: Chunning Ha --- internal/store/pg/agents.go | 12 ++++++++---- internal/store/sqlitestore/agents.go | 16 +++++++++++++--- .../frontend/src/hooks/use-agent-detail-state.ts | 4 ++-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/internal/store/pg/agents.go b/internal/store/pg/agents.go index 6d537839..1074a7fd 100644 --- a/internal/store/pg/agents.go +++ b/internal/store/pg/agents.go @@ -196,14 +196,18 @@ func (s *PGAgentStore) Update(ctx context.Context, id uuid.UUID, updates map[str updates[col] = "" } } - // Promoted INT columns: null → 0. - for _, col := range []string{"skill_nudge_interval", "max_tokens"} { + // Promoted INT/BOOL columns: null → 0/false. + for _, col := range []string{"skill_nudge_interval", "max_tokens", "self_evolve", "skill_evolve", "is_default"} { if v, ok := updates[col]; ok && v == nil { - updates[col] = 0 + if col == "self_evolve" || col == "skill_evolve" || col == "is_default" { + updates[col] = false + } else { + updates[col] = 0 + } } } // NOT NULL JSONB columns: null → empty object. - for _, col := range []string{"chatgpt_oauth_routing", "reasoning_config", "workspace_sharing", "shell_deny_groups", "kg_dedup_config"} { + for _, col := range []string{"other_config", "tools_config", "chatgpt_oauth_routing", "reasoning_config", "workspace_sharing", "shell_deny_groups", "kg_dedup_config"} { if v, ok := updates[col]; ok && v == nil { updates[col] = []byte("{}") } diff --git a/internal/store/sqlitestore/agents.go b/internal/store/sqlitestore/agents.go index 65acd565..9e12e307 100644 --- a/internal/store/sqlitestore/agents.go +++ b/internal/store/sqlitestore/agents.go @@ -140,10 +140,20 @@ func (s *SQLiteAgentStore) Update(ctx context.Context, id uuid.UUID, updates map updates[col] = "" } } - // Promoted INT columns: null → 0. - for _, col := range []string{"skill_nudge_interval", "max_tokens"} { + // Promoted INT/BOOL columns: null → 0/false. + for _, col := range []string{"skill_nudge_interval", "max_tokens", "self_evolve", "skill_evolve", "is_default"} { if v, ok := updates[col]; ok && v == nil { - updates[col] = 0 + if col == "self_evolve" || col == "skill_evolve" || col == "is_default" { + updates[col] = false + } else { + updates[col] = 0 + } + } + } + // 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"} { + if v, ok := updates[col]; ok && v == nil { + updates[col] = []byte("{}") } } diff --git a/ui/desktop/frontend/src/hooks/use-agent-detail-state.ts b/ui/desktop/frontend/src/hooks/use-agent-detail-state.ts index bf561b2f..3fb9a632 100644 --- a/ui/desktop/frontend/src/hooks/use-agent-detail-state.ts +++ b/ui/desktop/frontend/src/hooks/use-agent-detail-state.ts @@ -114,11 +114,11 @@ export function useAgentDetailState( max_tool_iterations: maxToolIterations, is_default: isDefault, status, - other_config: Object.keys(otherConfig).length > 0 ? otherConfig : null, + other_config: Object.keys(otherConfig).length > 0 ? otherConfig : {}, context_pruning: pruningEnabled ? pruningConfig : null, compaction_config: compactionConfig, subagents_config: subEnabled ? subConfig : null, - tools_config: toolsEnabled ? toolsConfig : null, + tools_config: toolsEnabled ? toolsConfig : {}, sandbox_config: sandboxEnabled ? sandboxConfig : null, }) onClose()