Spaces:
Paused
Paused
Commit ·
3bcc261
1
Parent(s): 4463796
Bypass cached validator endpoints
Browse files- Dockerfile +1 -1
- README.md +1 -1
- openenv.yaml +7 -0
- server/app.py +44 -4
Dockerfile
CHANGED
|
@@ -8,7 +8,7 @@
|
|
| 8 |
FROM python:3.11-slim
|
| 9 |
|
| 10 |
# Build trigger — change this to force HF Space Docker rebuild
|
| 11 |
-
LABEL build.version="2026-04-12-
|
| 12 |
|
| 13 |
# Non-root user for security
|
| 14 |
RUN useradd -m -u 1000 appuser
|
|
|
|
| 8 |
FROM python:3.11-slim
|
| 9 |
|
| 10 |
# Build trigger — change this to force HF Space Docker rebuild
|
| 11 |
+
LABEL build.version="2026-04-12-v4"
|
| 12 |
|
| 13 |
# Non-root user for security
|
| 14 |
RUN useradd -m -u 1000 appuser
|
README.md
CHANGED
|
@@ -13,7 +13,7 @@ tags:
|
|
| 13 |
- reinforcement-learning
|
| 14 |
pinned: false
|
| 15 |
fullWidth: false
|
| 16 |
-
build_version: 2026-04-12-
|
| 17 |
---
|
| 18 |
|
| 19 |
# PayOps — Payment Operations Incident Response
|
|
|
|
| 13 |
- reinforcement-learning
|
| 14 |
pinned: false
|
| 15 |
fullWidth: false
|
| 16 |
+
build_version: 2026-04-12-v4
|
| 17 |
---
|
| 18 |
|
| 19 |
# PayOps — Payment Operations Incident Response
|
openenv.yaml
CHANGED
|
@@ -4,6 +4,13 @@ type: space
|
|
| 4 |
runtime: fastapi
|
| 5 |
app: server.app:app
|
| 6 |
port: 7860
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
tasks:
|
| 8 |
- id: EASY-001
|
| 9 |
task_id: EASY-001
|
|
|
|
| 4 |
runtime: fastapi
|
| 5 |
app: server.app:app
|
| 6 |
port: 7860
|
| 7 |
+
endpoints:
|
| 8 |
+
reset: /reset
|
| 9 |
+
step: /step
|
| 10 |
+
tasks: /tasks-v2
|
| 11 |
+
grader: /grader-v2
|
| 12 |
+
health: /health-v2
|
| 13 |
+
metadata: /metadata-v2
|
| 14 |
tasks:
|
| 15 |
- id: EASY-001
|
| 16 |
task_id: EASY-001
|
server/app.py
CHANGED
|
@@ -25,7 +25,7 @@ import time
|
|
| 25 |
from collections import defaultdict
|
| 26 |
from typing import Any, Dict, List, Optional
|
| 27 |
|
| 28 |
-
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect
|
| 29 |
from fastapi.responses import JSONResponse
|
| 30 |
from pydantic import BaseModel, ConfigDict
|
| 31 |
|
|
@@ -45,9 +45,25 @@ app = FastAPI(
|
|
| 45 |
"Payment Operations Incident Response environment. "
|
| 46 |
"An AI agent reviews financial transactions and decides how to handle them."
|
| 47 |
),
|
| 48 |
-
version="2.0.
|
| 49 |
)
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
@app.get("/", include_in_schema=False)
|
| 53 |
async def root():
|
|
@@ -64,10 +80,16 @@ async def metadata():
|
|
| 64 |
"Payment Operations Incident Response environment. "
|
| 65 |
"An AI agent reviews financial transactions and decides how to handle them."
|
| 66 |
),
|
| 67 |
-
"version":
|
| 68 |
}
|
| 69 |
|
| 70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
# Per-session environment instances — one per /reset call.
|
| 72 |
# Keyed by episode_id; keeps the last _MAX_SESSIONS sessions to bound memory.
|
| 73 |
_MAX_SESSIONS = 20
|
|
@@ -293,6 +315,12 @@ async def tasks():
|
|
| 293 |
return result
|
| 294 |
|
| 295 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
@app.get("/grader", summary="Grade the current episode")
|
| 297 |
async def grader():
|
| 298 |
"""
|
|
@@ -374,6 +402,12 @@ async def grader():
|
|
| 374 |
}
|
| 375 |
|
| 376 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 377 |
@app.post("/baseline", response_model=BaselineResult, summary="Run the baseline agent")
|
| 378 |
async def baseline():
|
| 379 |
"""
|
|
@@ -582,7 +616,7 @@ async def health():
|
|
| 582 |
return {
|
| 583 |
"status": "healthy",
|
| 584 |
"environment": "payops_env",
|
| 585 |
-
"version":
|
| 586 |
"episode_id": episode_id,
|
| 587 |
"episode_seed": episode_seed,
|
| 588 |
"current_task_id": current_task,
|
|
@@ -591,6 +625,12 @@ async def health():
|
|
| 591 |
}
|
| 592 |
|
| 593 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 594 |
# ---------------------------------------------------------------------------
|
| 595 |
# Entry point
|
| 596 |
# ---------------------------------------------------------------------------
|
|
|
|
| 25 |
from collections import defaultdict
|
| 26 |
from typing import Any, Dict, List, Optional
|
| 27 |
|
| 28 |
+
from fastapi import FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect
|
| 29 |
from fastapi.responses import JSONResponse
|
| 30 |
from pydantic import BaseModel, ConfigDict
|
| 31 |
|
|
|
|
| 45 |
"Payment Operations Incident Response environment. "
|
| 46 |
"An AI agent reviews financial transactions and decides how to handle them."
|
| 47 |
),
|
| 48 |
+
version="2.0.2",
|
| 49 |
)
|
| 50 |
|
| 51 |
+
_APP_VERSION = "2.0.2"
|
| 52 |
+
_NO_CACHE_HEADERS = {
|
| 53 |
+
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
| 54 |
+
"Pragma": "no-cache",
|
| 55 |
+
"Expires": "0",
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
@app.middleware("http")
|
| 60 |
+
async def disable_cache_for_validator_paths(request: Request, call_next):
|
| 61 |
+
"""Prevent stale validator responses from being served from caches."""
|
| 62 |
+
response = await call_next(request)
|
| 63 |
+
if request.method in {"GET", "HEAD"}:
|
| 64 |
+
response.headers.update(_NO_CACHE_HEADERS)
|
| 65 |
+
return response
|
| 66 |
+
|
| 67 |
|
| 68 |
@app.get("/", include_in_schema=False)
|
| 69 |
async def root():
|
|
|
|
| 80 |
"Payment Operations Incident Response environment. "
|
| 81 |
"An AI agent reviews financial transactions and decides how to handle them."
|
| 82 |
),
|
| 83 |
+
"version": _APP_VERSION,
|
| 84 |
}
|
| 85 |
|
| 86 |
|
| 87 |
+
@app.get("/metadata-v2")
|
| 88 |
+
async def metadata_v2():
|
| 89 |
+
"""Versioned metadata alias used to bypass stale edge caches."""
|
| 90 |
+
return await metadata()
|
| 91 |
+
|
| 92 |
+
|
| 93 |
# Per-session environment instances — one per /reset call.
|
| 94 |
# Keyed by episode_id; keeps the last _MAX_SESSIONS sessions to bound memory.
|
| 95 |
_MAX_SESSIONS = 20
|
|
|
|
| 315 |
return result
|
| 316 |
|
| 317 |
|
| 318 |
+
@app.get("/tasks-v2", summary="List all available tasks")
|
| 319 |
+
async def tasks_v2():
|
| 320 |
+
"""Versioned tasks alias used to bypass stale edge caches."""
|
| 321 |
+
return await tasks()
|
| 322 |
+
|
| 323 |
+
|
| 324 |
@app.get("/grader", summary="Grade the current episode")
|
| 325 |
async def grader():
|
| 326 |
"""
|
|
|
|
| 402 |
}
|
| 403 |
|
| 404 |
|
| 405 |
+
@app.get("/grader-v2", summary="Grade the current episode")
|
| 406 |
+
async def grader_v2():
|
| 407 |
+
"""Versioned grader alias used to bypass stale edge caches."""
|
| 408 |
+
return await grader()
|
| 409 |
+
|
| 410 |
+
|
| 411 |
@app.post("/baseline", response_model=BaselineResult, summary="Run the baseline agent")
|
| 412 |
async def baseline():
|
| 413 |
"""
|
|
|
|
| 616 |
return {
|
| 617 |
"status": "healthy",
|
| 618 |
"environment": "payops_env",
|
| 619 |
+
"version": _APP_VERSION,
|
| 620 |
"episode_id": episode_id,
|
| 621 |
"episode_seed": episode_seed,
|
| 622 |
"current_task_id": current_task,
|
|
|
|
| 625 |
}
|
| 626 |
|
| 627 |
|
| 628 |
+
@app.get("/health-v2", summary="Health check")
|
| 629 |
+
async def health_v2():
|
| 630 |
+
"""Versioned health alias used to bypass stale edge caches."""
|
| 631 |
+
return await health()
|
| 632 |
+
|
| 633 |
+
|
| 634 |
# ---------------------------------------------------------------------------
|
| 635 |
# Entry point
|
| 636 |
# ---------------------------------------------------------------------------
|