Version 1.2.2. Added usage overview. Shows token used and cost in $.

This commit is contained in:
2026-04-15 10:00:39 +02:00
parent 752691fe54
commit d4c6420481
18 changed files with 1657 additions and 86 deletions

View File

@@ -1,5 +1,21 @@
"""
users.py — User CRUD operations (async, PostgreSQL).
Design decisions:
- User IDs are TEXT (UUID stored as string), NOT the PostgreSQL UUID type.
Reason: PostgreSQL UUID type causes FK mismatch errors with asyncpg when columns
in other tables store user_id as TEXT. Keeping everything TEXT avoids implicit
type casting and makes joins reliable.
- New users get personality files seeded from the global SOUL.md / USER.md.
Admins get the real USER.md verbatim. Non-admins get a blank template so they
can fill in their own context without seeing the admin's personal info.
- User email addresses are automatically added to email_whitelist so the agent
can reply to the user without manual whitelist configuration.
- User folders (provisioned in {users_base_folder}/{username}/) allow non-admin
users to have a private filesystem space without configuring the global whitelist.
"""
from __future__ import annotations
@@ -137,6 +153,12 @@ async def _sync_email_whitelist(pool, old_email: str | None, new_email: str | No
async def create_user(username: str, password: str, role: str = "user", email: str = "") -> dict:
"""
Create a new user. Automatically:
- Seeds per-user personality from global SOUL.md / USER.md
- Adds user's email to email_whitelist (so the agent can reply)
- Provisions a user folder if system:users_base_folder is configured
"""
user_id = str(uuid.uuid4())
now = _now()
pw_hash = hash_password(password)
@@ -222,6 +244,11 @@ async def update_user(user_id: str, **fields) -> bool:
async def delete_user(user_id: str) -> bool:
"""
Delete a user. Nullifies FK references first to avoid constraint violations.
Agents, conversations, and audit entries are preserved (owner set to NULL)
rather than cascade-deleted — important for audit trail integrity.
"""
pool = await get_pool()
# Fetch email before delete for whitelist cleanup
old_row = await pool.fetchrow("SELECT email FROM users WHERE id = $1", user_id)