chore: C2 DELETE 204+body, C4 cached_tokens, C5 utcnow + LICENSE (T011)
tests / pytest (push) Has been cancelled
tests / pytest (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Leopold
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -8,7 +8,7 @@ from typing import Optional, Dict, Any, List
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Depends, HTTPException, Request
|
||||
from fastapi import FastAPI, Depends, HTTPException, Request, Response
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
@@ -198,10 +198,10 @@ async def api_delete_agent(
|
||||
# Code-Agents: nur deaktivieren, damit sie beim nächsten Sync wieder da sind
|
||||
await set_agent_enabled(db, agent_id, False)
|
||||
await log_audit(db, agent_id=agent_id, user_id=user_id, action="agent_disabled_via_delete", target=agent_id)
|
||||
return {"status": "disabled", "note": "Code-Agents werden nicht gelöscht, nur deaktiviert"}
|
||||
return Response(status_code=204)
|
||||
await delete_agent(db, agent_id)
|
||||
await log_audit(db, agent_id=agent_id, user_id=user_id, action="agent_deleted", target=agent_id)
|
||||
return {"status": "deleted"}
|
||||
return Response(status_code=204)
|
||||
|
||||
|
||||
@app.post("/api/agents/{agent_id}/enable")
|
||||
|
||||
@@ -8,7 +8,7 @@ import aiosqlite
|
||||
import json
|
||||
import uuid
|
||||
import secrets
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from config import settings
|
||||
|
||||
@@ -267,7 +267,7 @@ async def list_audit(db, agent_id=None, limit=100):
|
||||
|
||||
async def create_session(db, user_id="default", ttl_hours=24):
|
||||
token = secrets.token_urlsafe(32)
|
||||
expires = (datetime.utcnow() + timedelta(hours=ttl_hours)).isoformat()
|
||||
expires = (datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(hours=ttl_hours)).isoformat()
|
||||
await db.execute(
|
||||
"INSERT INTO sessions (token, user_id, expires_at) VALUES (?, ?, ?)",
|
||||
(token, user_id, expires)
|
||||
@@ -284,6 +284,6 @@ async def validate_session(db, token):
|
||||
row = await cur.fetchone()
|
||||
if not row:
|
||||
return None
|
||||
if row[1] and datetime.fromisoformat(row[1]) < datetime.utcnow():
|
||||
if row[1] and datetime.fromisoformat(row[1]) < datetime.now(timezone.utc).replace(tzinfo=None):
|
||||
return None
|
||||
return row[0]
|
||||
|
||||
@@ -72,10 +72,20 @@ async def chat(
|
||||
|
||||
usage = {}
|
||||
if hasattr(response, "usage") and response.usage:
|
||||
# LiteLLM exposes cached prompt tokens via prompt_tokens_details.cached_tokens
|
||||
# (see litellm.types.utils.Usage). Providers like Anthropic/OpenAI surface this
|
||||
# when prompt caching is active; surfacing it here flows through LLMResponse.usage
|
||||
# to any audit log that serialises the usage dict.
|
||||
cached_tokens = 0
|
||||
details = getattr(response.usage, "prompt_tokens_details", None)
|
||||
if details is not None:
|
||||
cached_tokens = getattr(details, "cached_tokens", None) or 0
|
||||
|
||||
usage = {
|
||||
"prompt_tokens": response.usage.prompt_tokens or 0,
|
||||
"completion_tokens": response.usage.completion_tokens or 0,
|
||||
"total_tokens": response.usage.total_tokens or 0,
|
||||
"cached_tokens": cached_tokens,
|
||||
"finish_reason": response.choices[0].finish_reason or "stop",
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user