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 contextlib import asynccontextmanager
|
||||||
from pathlib import Path
|
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.responses import HTMLResponse, RedirectResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
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
|
# Code-Agents: nur deaktivieren, damit sie beim nächsten Sync wieder da sind
|
||||||
await set_agent_enabled(db, agent_id, False)
|
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)
|
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 delete_agent(db, agent_id)
|
||||||
await log_audit(db, agent_id=agent_id, user_id=user_id, action="agent_deleted", target=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")
|
@app.post("/api/agents/{agent_id}/enable")
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import aiosqlite
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
import secrets
|
import secrets
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from config import settings
|
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):
|
async def create_session(db, user_id="default", ttl_hours=24):
|
||||||
token = secrets.token_urlsafe(32)
|
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(
|
await db.execute(
|
||||||
"INSERT INTO sessions (token, user_id, expires_at) VALUES (?, ?, ?)",
|
"INSERT INTO sessions (token, user_id, expires_at) VALUES (?, ?, ?)",
|
||||||
(token, user_id, expires)
|
(token, user_id, expires)
|
||||||
@@ -284,6 +284,6 @@ async def validate_session(db, token):
|
|||||||
row = await cur.fetchone()
|
row = await cur.fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
return None
|
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 None
|
||||||
return row[0]
|
return row[0]
|
||||||
|
|||||||
@@ -72,10 +72,20 @@ async def chat(
|
|||||||
|
|
||||||
usage = {}
|
usage = {}
|
||||||
if hasattr(response, "usage") and response.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 = {
|
usage = {
|
||||||
"prompt_tokens": response.usage.prompt_tokens or 0,
|
"prompt_tokens": response.usage.prompt_tokens or 0,
|
||||||
"completion_tokens": response.usage.completion_tokens or 0,
|
"completion_tokens": response.usage.completion_tokens or 0,
|
||||||
"total_tokens": response.usage.total_tokens or 0,
|
"total_tokens": response.usage.total_tokens or 0,
|
||||||
|
"cached_tokens": cached_tokens,
|
||||||
"finish_reason": response.choices[0].finish_reason or "stop",
|
"finish_reason": response.choices[0].finish_reason or "stop",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user