feat: add per-user customization suppression toggles and API endpoints for profile

This commit is contained in:
2026-06-09 20:52:51 +00:00
parent c2c5166720
commit a3f9b949ca
15 changed files with 495 additions and 19 deletions
@@ -131,4 +131,31 @@ CUSTOMIZATION_ACTIONS: tuple[Action, ...] = (
),
),
),
Action(
name="customize_set_enabled",
method="LOCAL",
path="",
summary="Show or suppress the user's customizations without deleting them",
description=(
"Toggles whether the user's saved customizations render, keeping the stored code intact. "
"category='global' controls the site-wide customizations; category='pagetype' controls every "
"per-page-type customization at once. enabled=false hides them; enabled=true shows them again. "
"Mirrors the toggle buttons on the user's profile page."
),
handler="customization",
requires_auth=True,
params=(
arg(
"category",
"Which set to toggle: 'global' (whole site) or 'pagetype' (all per-page customizations).",
required=True,
),
arg(
"enabled",
"true to show the customizations, false to suppress them.",
required=True,
kind="boolean",
),
),
),
)
+3 -1
View File
@@ -137,7 +137,9 @@ SYSTEM_PROMPT = (
"after the application boots, with access to window, document and the global 'app'. After saving, "
"call reload_page so the server-applied version is shown. List existing customizations with "
"customize_list, and remove them with customize_reset (confirm=true; scope='all' removes "
"everything) to restore the default look and behaviour.\n\n"
"everything) to restore the default look and behaviour. To hide saved customizations WITHOUT "
"deleting them (the same toggles on the user's profile page), call customize_set_enabled with "
"category='global' or 'pagetype' and enabled=false; enabled=true brings them back.\n\n"
"USER-DEFINED TOOLS (VIBE TOOLS)\n"
"The user can invent new tools for you by describing them ('when I say X, do Y'). When they do, "
"call tool_create with a short trigger-oriented description (so you know when to use it), the "
@@ -8,10 +8,13 @@ from typing import Any
from devplacepy.database import (
CUSTOMIZATION_LANGS,
CUSTOMIZATION_PREF_COLUMNS,
delete_custom_override,
get_custom_override,
get_customization_prefs,
list_custom_overrides,
set_custom_override,
set_customization_pref,
)
from devplacepy.services.devii.errors import ToolInputError
@@ -36,6 +39,8 @@ class CustomizationController:
return self._set(arguments, "js", "js")
if name == "customize_reset":
return self._reset(arguments)
if name == "customize_set_enabled":
return self._set_enabled(arguments)
raise ToolInputError(f"Unknown customization tool: {name}")
def _scope(self, arguments: dict[str, Any]) -> str:
@@ -68,8 +73,15 @@ class CustomizationController:
}
for row in rows
]
prefs = get_customization_prefs(self._owner_kind, self._owner_id)
return json.dumps(
{"status": "success", "customizations": items}, ensure_ascii=False
{
"status": "success",
"customizations": items,
"disabled_global": prefs["disable_global"],
"disabled_pagetype": prefs["disable_pagetype"],
},
ensure_ascii=False,
)
def _get(self, arguments: dict[str, Any]) -> str:
@@ -111,6 +123,36 @@ class CustomizationController:
ensure_ascii=False,
)
def _category(self, arguments: dict[str, Any]) -> str:
category = str(arguments.get("category", "")).strip().lower()
if category not in CUSTOMIZATION_PREF_COLUMNS:
raise ToolInputError("'category' must be 'global' or 'pagetype'.")
return category
def _enabled(self, arguments: dict[str, Any]) -> bool:
raw = arguments.get("enabled")
if isinstance(raw, bool):
return raw
return str(raw).strip().lower() in ("true", "1", "yes", "on")
def _set_enabled(self, arguments: dict[str, Any]) -> str:
if self._owner_kind != "user":
raise ToolInputError(
"Suppressing customizations is only available for signed-in users."
)
category = self._category(arguments)
enabled = self._enabled(arguments)
set_customization_pref(self._owner_id, category, disabled=not enabled)
return json.dumps(
{
"status": "success",
"category": category,
"enabled": enabled,
"note": "Saved. Call reload_page so the user sees it applied by the server.",
},
ensure_ascii=False,
)
def _reset(self, arguments: dict[str, Any]) -> str:
scope = self._scope(arguments)
lang = self._lang(arguments)