#!/bin/bash set -e SUGGESTIONS_FILE="/app/montaigne-config/prompt_suggestions.json" POLICY_FILE="/app/montaigne-config/ui_policy.json" MINIMAL_UI_PATCH_FILE="/app/montaigne-config/minimal_ui_patch.js" if [ -f "$SUGGESTIONS_FILE" ] || [ -f "$POLICY_FILE" ]; then echo "Syncing Montaigne UI policy to OpenWebUI..." python3 - <<'PY' import json import os import sqlite3 from pathlib import Path from urllib.parse import unquote from open_webui.env import DATA_DIR, DATABASE_URL def load_suggestions(path: Path) -> list: payload = json.loads(path.read_text(encoding="utf-8")) suggestions = payload.get("default_prompt_suggestions", []) if not isinstance(suggestions, list): raise ValueError("default_prompt_suggestions must be a list") return suggestions def load_policy(path: Path) -> dict: return json.loads(path.read_text(encoding="utf-8")) def deep_update(target: dict, updates: dict) -> None: """Recursively update *target* with *updates*, creating missing keys.""" for key, value in updates.items(): if isinstance(value, dict) and isinstance(target.get(key), dict): deep_update(target[key], value) else: target[key] = value def merge_config(config: dict, suggestions: list, policy: dict) -> dict: if not isinstance(config, dict): config = {} # Prompt suggestions ui = config.get("ui") if not isinstance(ui, dict): ui = {} ui["prompt_suggestions"] = suggestions config["ui"] = ui # Policy fields if "default_models" in policy: config["default_models"] = policy["default_models"] if "default_pinned_models" in policy: config["default_pinned_models"] = policy["default_pinned_models"] # Permissions if "permissions" in policy: perms = config.get("permissions") if not isinstance(perms, dict): perms = {} deep_update(perms, policy["permissions"]) config["permissions"] = perms # Global features if "features" in policy: feats = config.get("features") if not isinstance(feats, dict): feats = {} deep_update(feats, policy["features"]) config["features"] = feats config.setdefault("version", 0) return config suggestions_file = Path("/app/montaigne-config/prompt_suggestions.json") policy_file = Path("/app/montaigne-config/ui_policy.json") suggestions = load_suggestions(suggestions_file) if suggestions_file.exists() else [] policy = load_policy(policy_file) if policy_file.exists() else {} data_dir = Path(DATA_DIR) database_url = str(DATABASE_URL) if database_url.startswith("sqlite:///"): db_path = Path(unquote(database_url.replace("sqlite:///", "", 1))) if not db_path.exists(): config = merge_config({}, suggestions, policy) config_path = data_dir / "config.json" config_path.parent.mkdir(parents=True, exist_ok=True) config_path.write_text(json.dumps(config, indent=2), encoding="utf-8") print(f"Wrote bootstrap config to {config_path}") raise SystemExit(0) conn = sqlite3.connect(db_path) try: cursor = conn.cursor() cursor.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name='config'" ) table_exists = cursor.fetchone() is not None if not table_exists: config = merge_config({}, suggestions, policy) config_path = data_dir / "config.json" config_path.parent.mkdir(parents=True, exist_ok=True) config_path.write_text(json.dumps(config, indent=2), encoding="utf-8") print(f"Wrote bootstrap config to {config_path}") raise SystemExit(0) cursor.execute("SELECT id, data FROM config ORDER BY id ASC LIMIT 1") row = cursor.fetchone() if row is None: config = merge_config({}, suggestions, policy) cursor.execute( "INSERT INTO config (data, version) VALUES (?, ?)", (json.dumps(config), int(config.get("version", 0))), ) else: config_id, raw_data = row try: current = json.loads(raw_data) if raw_data else {} except json.JSONDecodeError: current = {} updated = merge_config(current, suggestions, policy) cursor.execute( "UPDATE config SET data = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?", (json.dumps(updated), config_id), ) conn.commit() print( f"Applied {len(suggestions)} prompt suggestions " f"and {len(policy)} policy keys to sqlite config" ) finally: conn.close() else: if suggestions: os.environ["DEFAULT_PROMPT_SUGGESTIONS"] = json.dumps( suggestions, separators=(",", ":") ) print("Non-sqlite database: exported DEFAULT_PROMPT_SUGGESTIONS fallback") print("Policy enforcement requires sqlite database; skipped.") PY fi if [ -f "$MINIMAL_UI_PATCH_FILE" ] && [ -f "/app/build/index.html" ]; then cp "$MINIMAL_UI_PATCH_FILE" "/app/build/montaigne-minimal-ui.js" python3 - <<'PY' from pathlib import Path index_path = Path('/app/build/index.html') script_tag = '' html = index_path.read_text(encoding='utf-8') if script_tag not in html: if '' in html: html = html.replace('', f' {script_tag}\n', 1) elif '' in html: html = html.replace('', f' {script_tag}\n', 1) index_path.write_text(html, encoding='utf-8') PY echo "Injected Montaigne minimal UI patch" fi exec "$@"