feat: chat improvements, file viewer, usage fixes, and agent filesystem awareness

This commit is contained in:
2026-04-16 13:42:06 +02:00
parent b6a5d169a9
commit a72eef4b82
10 changed files with 319 additions and 470 deletions

View File

@@ -909,17 +909,6 @@ async def get_usage(
params: list = []
n = 1
# Exclude email handler agents
handler_ids_rows = await pool.fetch(
"SELECT agent_id FROM email_accounts WHERE agent_id IS NOT NULL"
)
handler_ids = [str(r["agent_id"]) for r in handler_ids_rows]
if handler_ids:
placeholders = ", ".join(f"${n + i}" for i in range(len(handler_ids)))
clauses.append(f"ar.agent_id NOT IN ({placeholders})")
params.extend(handler_ids)
n += len(handler_ids)
if since_dt:
clauses.append(f"ar.started_at >= ${n}"); params.append(since_dt); n += 1
if end:
@@ -1039,6 +1028,20 @@ async def get_usage(
}
# ── Usage: clear cost data ────────────────────────────────────────────────────
@router.delete("/usage/cost")
async def clear_cost_data(request: Request):
"""Delete all agent_runs and null out conversation cost_usd. Admin only."""
_require_admin(request)
from ..database import get_pool as _gp
pool = await _gp()
async with pool.acquire() as conn:
await conn.execute("DELETE FROM agent_runs")
await conn.execute("UPDATE conversations SET cost_usd = NULL WHERE cost_usd IS NOT NULL")
return {"ok": True}
# ── Inbox triggers ────────────────────────────────────────────────────────────
class InboxTriggerIn(BaseModel):
@@ -2857,6 +2860,38 @@ async def download_my_file(request: Request, path: str):
)
_FB_TEXT_EXTS = {
".md", ".txt", ".json", ".xml", ".yaml", ".yml", ".csv",
".html", ".htm", ".css", ".js", ".ts", ".jsx", ".tsx",
".py", ".sh", ".bash", ".zsh", ".log", ".sql", ".toml",
".ini", ".conf", ".cfg", ".env", ".gitignore", ".dockerfile",
".rst", ".tex", ".diff", ".patch", ".nfo", ".tsv",
}
@router.get("/my/files/view")
async def view_my_file(request: Request, path: str):
user = _require_auth(request)
from ..users import get_user_folder
base = await get_user_folder(user.id)
if not base:
raise HTTPException(status_code=404, detail="No files folder configured")
target = _resolve_user_path(base, path)
if not _os.path.isfile(target):
raise HTTPException(status_code=404, detail="File not found")
ext = _os.path.splitext(target)[1].lower()
if ext not in _FB_TEXT_EXTS:
raise HTTPException(status_code=415, detail="File type not supported for viewing")
size = _os.path.getsize(target)
_MAX_VIEW = 512 * 1024 # 512 KB
try:
with open(target, "r", encoding="utf-8", errors="replace") as fh:
content = fh.read(_MAX_VIEW)
except OSError as exc:
raise HTTPException(status_code=500, detail=str(exc))
return {"content": content, "size": size, "truncated": size > _MAX_VIEW}
@router.get("/my/files/download-zip")
async def download_my_zip(request: Request, path: str = ""):
user = _require_auth(request)