feat: Web-Such-Budget pro Nutzer/Tag
Neue Tabelle web_search_usage + Store-Zaehler (web_search_count / add_web_search_usage, kaskadiert in delete_user). Pro-Nutzer-Limit web_search_daily_limit (Pref > global; 0 = unbegrenzt) in quota.py (web_search_within_budget). ws.py: Gate vor _resolve (Budget aufgebraucht -> Web-Suche fuer den Turn aus) + Zaehlung nach dem Turn (trace.web_searches, gezaehlt im Orchestrator je on_citations). Admin: Feld + UI-Eingabe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5609741039
commit
88c8c9df7f
8 changed files with 106 additions and 5 deletions
38
app/store.py
38
app/store.py
|
|
@ -120,6 +120,14 @@ class Store(ABC):
|
|||
def add_usage(self, user_id: str, units: int = 0, day: str | None = None) -> int:
|
||||
"""Zaehlt eine Anfrage (+units) und liefert die neue Tages-Anfragezahl."""
|
||||
|
||||
@abstractmethod
|
||||
def web_search_count(self, user_id: str, day: str | None = None) -> int:
|
||||
"""Anzahl Web-Suchen des Nutzers am Tag (Default: heute, UTC)."""
|
||||
|
||||
@abstractmethod
|
||||
def add_web_search_usage(self, user_id: str, n: int = 1, day: str | None = None) -> int:
|
||||
"""Zaehlt n Web-Suchen dazu und liefert die neue Tages-Zahl."""
|
||||
|
||||
@abstractmethod
|
||||
def delete_user(self, user_id: str) -> bool:
|
||||
"""Loescht einen Nutzer und alle seine Daten (Sessions, Nachrichten, Erinnerungen,
|
||||
|
|
@ -229,6 +237,12 @@ class SQLiteStore(Store):
|
|||
units INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (user_id, day)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS web_search_usage (
|
||||
user_id TEXT NOT NULL,
|
||||
day TEXT NOT NULL,
|
||||
count INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (user_id, day)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS emergency_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT NOT NULL,
|
||||
|
|
@ -480,6 +494,29 @@ class SQLiteStore(Store):
|
|||
).fetchone()
|
||||
return int(row["requests"])
|
||||
|
||||
def web_search_count(self, user_id: str, day: str | None = None) -> int:
|
||||
day = day or self._today()
|
||||
with self._connect() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT count FROM web_search_usage WHERE user_id = ? AND day = ?",
|
||||
(user_id, day),
|
||||
).fetchone()
|
||||
return int(row["count"]) if row else 0
|
||||
|
||||
def add_web_search_usage(self, user_id: str, n: int = 1, day: str | None = None) -> int:
|
||||
day = day or self._today()
|
||||
with self._connect() as conn:
|
||||
conn.execute(
|
||||
"INSERT INTO web_search_usage (user_id, day, count) VALUES (?, ?, ?)"
|
||||
" ON CONFLICT(user_id, day) DO UPDATE SET count = count + excluded.count",
|
||||
(user_id, day, int(n)),
|
||||
)
|
||||
row = conn.execute(
|
||||
"SELECT count FROM web_search_usage WHERE user_id = ? AND day = ?",
|
||||
(user_id, day),
|
||||
).fetchone()
|
||||
return int(row["count"])
|
||||
|
||||
def delete_user(self, user_id: str) -> bool:
|
||||
if user_id == ANONYMOUS_USER_ID:
|
||||
raise ValueError("Der anonyme Nutzer kann nicht geloescht werden.")
|
||||
|
|
@ -494,6 +531,7 @@ class SQLiteStore(Store):
|
|||
conn.execute("DELETE FROM sessions WHERE user_id = ?", (user_id,))
|
||||
conn.execute("DELETE FROM memories WHERE user_id = ?", (user_id,))
|
||||
conn.execute("DELETE FROM usage WHERE user_id = ?", (user_id,))
|
||||
conn.execute("DELETE FROM web_search_usage WHERE user_id = ?", (user_id,))
|
||||
conn.execute("DELETE FROM users WHERE id = ?", (user_id,))
|
||||
return True
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue