diff --git a/Procfile b/Procfile index 302d889..5cd858d 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: gunicorn main:app --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 120 +web: uvicorn main:app --host 0.0.0.0 --port $PORT --workers 1 diff --git a/main.py b/main.py index e8c65b0..332d25c 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ main.py — Cloud Run entrypoint for OSVauco OPAX agent. -Exposes a minimal Flask HTTP API that wraps agent.run(). +Exposes a FastAPI HTTP API that wraps agent.run(). """ import os @@ -10,44 +10,44 @@ import sys # Ensure agents/core-logic is on the path sys.path.insert(0, os.path.join(os.path.dirname(__file__), "agents", "core-logic")) -from flask import Flask, request, jsonify +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel from agent import run # agents/core-logic/agent.py -app = Flask(__name__) +app = FastAPI(title="OSVauco OPAX Agent") -@app.route("/health", methods=["GET"]) +class RunRequest(BaseModel): + message: str + user_id: str = "opax" + session_id: str = "default" + mode: str = "A" + + +@app.get("/health") def health(): - return jsonify({"status": "ok"}) + return {"status": "ok"} -@app.route("/run", methods=["POST"]) -def run_agent(): - body = request.get_json(force=True, silent=True) or {} - message = body.get("message", "") - user_id = body.get("user_id", "opax") - session_id = body.get("session_id", "default") - mode = body.get("mode", "A") - - if not message: - return jsonify({"error": "'message' field required"}), 400 - +@app.post("/run") +def run_agent(req: RunRequest): try: response = run( - message=message, - user_id=user_id, - session_id=session_id, - mode=mode, + message=req.message, + user_id=req.user_id, + session_id=req.session_id, + mode=req.mode, ) - return jsonify({"response": response}) + return {"response": response} except PermissionError as e: - return jsonify({"error": str(e)}), 403 + raise HTTPException(status_code=403, detail=str(e)) except ValueError as e: - return jsonify({"error": str(e)}), 400 + raise HTTPException(status_code=400, detail=str(e)) except Exception as e: - return jsonify({"error": str(e)}), 500 + raise HTTPException(status_code=500, detail=str(e)) if __name__ == "__main__": + import uvicorn port = int(os.environ.get("PORT", 8080)) - app.run(host="0.0.0.0", port=port) + uvicorn.run(app, host="0.0.0.0", port=port) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..92106db --- /dev/null +++ b/requirements.txt @@ -0,0 +1,27 @@ +# OSVauco agent dependencies + +# ADK — must stay <2.0.0 while google-cloud-aiplatform[adk,agent_engines] requires google-adk<2.0.0 +google-adk>=1.0.0,<2.0.0 +google-cloud-aiplatform[adk,agent_engines,evaluation]>=1.112.0 + +# Secret Manager integration +google-cloud-secret-manager>=2.20.0 + +# MCP toolset +httpx>=0.27.0 +google-auth>=2.29.0 +google-auth-httplib2>=0.2.0 + +# Observability +opentelemetry-sdk>=1.25.0 +opentelemetry-exporter-gcp-trace>=1.8.0 +google-cloud-logging>=3.10.0 +google-cloud-monitoring>=2.22.0 + +# HTTP server for Cloud Run +uvicorn[standard]>=0.29.0 +fastapi>=0.111.0 + +# Utilities +python-dotenv>=1.0.0 +pydantic>=2.7.0