Harden QuoteJudge managed persistence
This commit is contained in:
42
agent.py
42
agent.py
@@ -54,10 +54,10 @@ ALLOWED_UPLOAD_MEDIA_TYPES = {
|
||||
"application/vnd.ms-excel",
|
||||
"text/plain",
|
||||
}
|
||||
|
||||
# Local/dev fallback only. Hosted production uses DATABASE_URL and managed Postgres.
|
||||
_LOCAL_COMPARISONS: dict[tuple[str, str], dict[str, Any]] = {}
|
||||
_LOCAL_RECEIPTS: list[dict[str, Any]] = []
|
||||
AGENT_VERSION = "0.1.4"
|
||||
DB_CONNECT_TIMEOUT_SECONDS = 5
|
||||
DB_STATEMENT_TIMEOUT_MS = 10_000
|
||||
DB_LOCK_TIMEOUT_MS = 5_000
|
||||
|
||||
|
||||
class QuoteJudgeStudioV1Config(BaseModel):
|
||||
@@ -128,7 +128,7 @@ class QuoteJudgeStudioV1(A2AAgent[QuoteJudgeStudioV1Config, PlatformUserAuth]):
|
||||
"scoring, persists per-user comparisons, supports browser uploads, and serves "
|
||||
"a polished packed product UI."
|
||||
)
|
||||
version = "0.1.3"
|
||||
version = AGENT_VERSION
|
||||
|
||||
config_model = QuoteJudgeStudioV1Config
|
||||
auth_model = PlatformUserAuth
|
||||
@@ -229,6 +229,12 @@ class QuoteJudgeStudioV1(A2AAgent[QuoteJudgeStudioV1Config, PlatformUserAuth]):
|
||||
record = await asyncio.to_thread(_load_comparison, tenant, comparison_id)
|
||||
if record is None:
|
||||
return {"ok": False, "code": "comparison_not_found", "comparison_id": comparison_id}
|
||||
if record.get("ok") is False:
|
||||
return {
|
||||
"ok": False,
|
||||
"code": record.get("code", "persistence_unavailable"),
|
||||
"comparison_id": comparison_id,
|
||||
}
|
||||
result = dict(record["result"])
|
||||
result["comparison_id"] = comparison_id
|
||||
result["ok"] = True
|
||||
@@ -477,7 +483,15 @@ def _connect() -> Any:
|
||||
url = _database_url()
|
||||
if not url:
|
||||
raise RuntimeError("DATABASE_URL is not configured")
|
||||
return psycopg.connect(url, row_factory=dict_row)
|
||||
return psycopg.connect(
|
||||
url,
|
||||
row_factory=dict_row,
|
||||
connect_timeout=DB_CONNECT_TIMEOUT_SECONDS,
|
||||
options=(
|
||||
f"-c statement_timeout={DB_STATEMENT_TIMEOUT_MS} "
|
||||
f"-c lock_timeout={DB_LOCK_TIMEOUT_MS}"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _persist_comparison(
|
||||
@@ -487,13 +501,7 @@ def _persist_comparison(
|
||||
receipt: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
if not _database_url() or psycopg is None:
|
||||
_LOCAL_COMPARISONS[(tenant_key, comparison_id)] = {
|
||||
"result": json.loads(json.dumps(result)),
|
||||
"updated_at": receipt["created_at"],
|
||||
"latest_receipt_id": receipt["receipt_id"],
|
||||
}
|
||||
_LOCAL_RECEIPTS.append(receipt)
|
||||
return {"ok": True, "warning": "local_ephemeral_persistence"}
|
||||
return {"ok": False, "code": "persistence_unavailable"}
|
||||
try:
|
||||
with _connect() as conn:
|
||||
with conn.cursor() as cur:
|
||||
@@ -550,12 +558,12 @@ def _persist_comparison(
|
||||
conn.commit()
|
||||
return {"ok": True}
|
||||
except Exception:
|
||||
return {"ok": False, "warning": "persistence_unavailable"}
|
||||
return {"ok": False, "code": "persistence_unavailable"}
|
||||
|
||||
|
||||
def _load_comparison(tenant_key: str, comparison_id: str) -> dict[str, Any] | None:
|
||||
if not _database_url() or psycopg is None:
|
||||
return _LOCAL_COMPARISONS.get((tenant_key, comparison_id))
|
||||
return {"ok": False, "code": "persistence_unavailable"}
|
||||
try:
|
||||
with _connect() as conn:
|
||||
with conn.cursor() as cur:
|
||||
@@ -577,7 +585,7 @@ def _load_comparison(tenant_key: str, comparison_id: str) -> dict[str, Any] | No
|
||||
"latest_receipt_id": row.get("latest_receipt_id"),
|
||||
}
|
||||
except Exception:
|
||||
return None
|
||||
return {"ok": False, "code": "persistence_unavailable"}
|
||||
|
||||
|
||||
def _build_receipt(
|
||||
@@ -603,7 +611,7 @@ def _build_receipt(
|
||||
"schema": "quotejudge.production_receipt.v1",
|
||||
"receipt_id": receipt_id,
|
||||
"agent_name": "quote-judge-studio-v1",
|
||||
"agent_version": "0.1.0",
|
||||
"agent_version": AGENT_VERSION,
|
||||
"skill_name": skill_name,
|
||||
"comparison_id": comparison_id,
|
||||
"status": "ok" if result.get("ok") else "error",
|
||||
|
||||
Reference in New Issue
Block a user