-- Model Presets: named wrappers around base models with bundled config. -- Admins create org-wide presets, users create personal ones. CREATE TABLE IF NOT EXISTS model_presets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(200) NOT NULL, description TEXT DEFAULT '', base_model_id TEXT NOT NULL, -- e.g. "gpt-4o", "claude-sonnet-4-20250514" api_config_id UUID REFERENCES api_configs(id) ON DELETE CASCADE, system_prompt TEXT DEFAULT '', temperature REAL, -- NULL = use model default max_tokens INTEGER, -- NULL = use model default tools_enabled JSONB DEFAULT '[]'::jsonb, -- reserved for future tool framework scope VARCHAR(20) NOT NULL DEFAULT 'personal' CHECK (scope IN ('global', 'team', 'personal')), team_id UUID, -- nullable; for future team scoping created_by UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, is_shared BOOLEAN DEFAULT false, -- personal presets visible to others is_active BOOLEAN DEFAULT true, icon VARCHAR(10) DEFAULT '', -- emoji or short icon code created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_model_presets_scope ON model_presets(scope); CREATE INDEX IF NOT EXISTS idx_model_presets_created_by ON model_presets(created_by); CREATE INDEX IF NOT EXISTS idx_model_presets_team ON model_presets(team_id) WHERE team_id IS NOT NULL; COMMENT ON TABLE model_presets IS 'Named model configurations: org-wide or personal wrappers around base models'; COMMENT ON COLUMN model_presets.base_model_id IS 'The underlying model_id (matches model_configs.model_id)'; COMMENT ON COLUMN model_presets.api_config_id IS 'Which provider config to use (NULL = resolve at completion time)'; COMMENT ON COLUMN model_presets.scope IS 'global = admin-created for all users; team = team-scoped; personal = user-created'; COMMENT ON COLUMN model_presets.tools_enabled IS 'JSON array of tool names enabled for this preset (future use)';