fix(models): gemini-2.5-flash (light) + gemini-2.5-pro (heavy), LOCATION=global for modellkall

This commit is contained in:
chrischristiansen-glitch 2026-05-26 01:37:28 +02:00
parent f711f7be74
commit 7585a485e0
2 changed files with 35 additions and 39 deletions

View File

@ -1,16 +1,17 @@
#!/usr/bin/env python3
"""
agent.py Cloud Run entrypoint for OSVauco OPAX agent.
agent.py OSVauco OPAX agent.
Modes:
light (standard) gemini-2.0-flash-001, $1/task hard stop
heavy (audit+) gemini-2.5-pro-001, $3/task hard stop
light gemini-2.5-flash, $1/task
heavy gemini-2.5-pro, $3/task
Legacy values 'A' and 'A+' are accepted and normalized.
Authorized users for heavy: opax, admin
Legacy 'A' / 'A+' normaliseres automatisk.
Authoriserte brukere for heavy: opax, admin
Requires: google-adk >= 1.0.0,<2.0.0
google-cloud-aiplatform >= 1.112.0
Gjeldende modell-tilgjengelighet (mai 2026):
gemini-2.0-flash-001 kun for eksisterende kunder bruk IKKE.
gemini-2.5-flash / gemini-2.5-pro krever GOOGLE_CLOUD_LOCATION=global.
"""
import asyncio
@ -26,18 +27,18 @@ from google.genai import types
logger = logging.getLogger(__name__)
PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT", "propane-will-491900-m5")
LOCATION = os.environ.get("GOOGLE_CLOUD_LOCATION", "us-central1")
LOCATION = os.environ.get("GOOGLE_CLOUD_LOCATION", "global")
RAG_CORPUS = os.environ.get("RAG_CORPUS", "")
# Light mode — pinned to stable versioned alias
ORCHESTRATOR_MODEL = os.environ.get("ORCHESTRATOR_MODEL", "gemini-2.0-flash-001")
SUBAGENT_MODEL = os.environ.get("SUBAGENT_MODEL", "gemini-2.0-flash-001")
REASONING_MODEL = os.environ.get("REASONING_MODEL", "gemini-2.0-flash-001")
# Light mode — gemini-2.5-flash (GA, global)
ORCHESTRATOR_MODEL = os.environ.get("ORCHESTRATOR_MODEL", "gemini-2.5-flash")
SUBAGENT_MODEL = os.environ.get("SUBAGENT_MODEL", "gemini-2.5-flash")
REASONING_MODEL = os.environ.get("REASONING_MODEL", "gemini-2.5-flash")
# Heavy mode
HEAVY_ORCHESTRATOR = os.environ.get("HEAVY_ORCHESTRATOR_MODEL", "gemini-2.5-pro-001")
HEAVY_SUBAGENT = os.environ.get("HEAVY_SUBAGENT_MODEL", "gemini-2.5-pro-001")
HEAVY_REASONING = os.environ.get("HEAVY_REASONING_MODEL", "gemini-2.5-flash-001")
# Heavy mode — gemini-2.5-pro (GA, global)
HEAVY_ORCHESTRATOR = os.environ.get("HEAVY_ORCHESTRATOR_MODEL", "gemini-2.5-pro")
HEAVY_SUBAGENT = os.environ.get("HEAVY_SUBAGENT_MODEL", "gemini-2.5-pro")
HEAVY_REASONING = os.environ.get("HEAVY_REASONING_MODEL", "gemini-2.5-flash")
BUDGET_LIGHT = float(os.environ.get("BUDGET_A_USD_PER_TASK", "1.0"))
BUDGET_HEAVY = float(os.environ.get("HEAVY_MODE_BUDGET_USD_PER_DAY", "3.0"))
@ -59,8 +60,7 @@ def _normalize_mode(mode: str) -> str:
def authorize_mode(user_id: str, mode: str) -> None:
"""Normalize mode first, then check authorization. Raises ValueError or PermissionError."""
mode = _normalize_mode(mode) # raises ValueError for unknown modes
mode = _normalize_mode(mode)
if mode == "heavy" and user_id not in HEAVY_MODE_ALLOWED_USERS:
raise PermissionError(
f"User '{user_id}' is not authorized for heavy mode. "
@ -80,11 +80,11 @@ if RAG_CORPUS:
similarity_top_k=10,
vector_distance_threshold=0.6,
)
logger.info(f"RAG tool initialised with corpus: {RAG_CORPUS}")
logger.info(f"RAG tool initialised: {RAG_CORPUS}")
except ImportError as e:
logger.warning(f"VertexAiRagRetrieval not available — running without RAG: {e}")
logger.warning(f"VertexAiRagRetrieval ikke tilgjengelig: {e}")
else:
logger.warning("RAG_CORPUS env var not set — running without RAG retrieval")
logger.warning("RAG_CORPUS ikke satt — kjører uten RAG")
def get_models_for_mode(mode: Mode) -> dict:
@ -108,18 +108,16 @@ def get_models_for_mode(mode: Mode) -> dict:
def build_agent(mode: str = "light") -> Agent:
mode = _normalize_mode(mode)
models = get_models_for_mode(mode)
mode_label = "heavy" if mode == "heavy" else "light"
instruction = (
f"Du er OPAX — OSVauco AI-agent. "
f"Modus: {mode_label}. Budsjettgrense per oppgave: ${models['budget_usd']}. "
"Bruk retrieve_knowledge-verktøyet for å hente dokumentasjon og kontekst. "
"Foretrekk alltid dokumenterte svar fremfor spekulasjon. "
"Svar alltid på norsk (bokmål) med mindre brukeren eksplisitt ber om et annet språk."
f"Du er OPAX — OSVauco AI-agent. Modus: {mode}. "
f"Budsjettgrense per oppgave: ${models['budget_usd']}. "
"Bruk retrieve_knowledge for å hente dokumentasjon. "
"Svar på norsk (bokmål) med mindre annet er bedt om."
)
return Agent(
model=models["orchestrator"],
name="opax_agent",
description=f"OPAX — OSVauco enterprise agent [{mode_label}]",
description=f"OPAX — OSVauco enterprise agent [{mode}]",
instruction=instruction,
tools=[rag_tool] if rag_tool else [],
)
@ -162,9 +160,8 @@ def run(
if __name__ == "__main__":
import sys
logging.basicConfig(level=logging.WARNING)
query = sys.argv[1] if len(sys.argv) > 1 else "Hva er OPAX heavy mode?"
requested_mode = sys.argv[2] if len(sys.argv) > 2 else "light"
print(f"Mode : {requested_mode}")
print(f"Query: {query}")
query = sys.argv[1] if len(sys.argv) > 1 else "Hva er OPAX?"
mode = sys.argv[2] if len(sys.argv) > 2 else "light"
print(f"Mode: {mode} | Query: {query}")
print("-" * 60)
print(run(message=query, user_id="opax", mode=requested_mode))
print(run(message=query, user_id="opax", mode=mode))

11
main.py
View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3
"""
main.py Cloud Run entrypoint for OSVauco OPAX agent.
Modes: light (default, gemini-2.0-flash-001) | heavy (gemini-2.5-pro-001)
ML-1: telemetri, state store, DAG-endepunkter.
main.py Cloud Run entrypoint, OSVauco OPAX.
Modes: light (gemini-2.5-flash) | heavy (gemini-2.5-pro)
ML-1: telemetri, state store, DAG.
"""
import os
@ -31,7 +31,7 @@ class RunRequest(BaseModel):
class DagRequest(BaseModel):
messages: List[str] = Field(..., description="Liste av meldinger som kjøres parallelt")
messages: List[str] = Field(...)
user_id: str = "opax"
session_id: str = "default"
mode: str = "light"
@ -45,7 +45,6 @@ def health():
@app.post("/run")
def run_agent(req: RunRequest):
# Validate mode and authorization before any work — returns 400/403 on bad input
try:
authorize_mode(req.user_id, req.mode)
except ValueError as e:
@ -71,7 +70,7 @@ def run_agent(req: RunRequest):
finally:
duration = round(time.monotonic() - start, 3)
success = error_msg is None
model = "gemini-2.0-flash-001" if req.mode in ("light", "A") else "gemini-2.5-pro-001"
model = "gemini-2.5-flash" if req.mode in ("light", "A") else "gemini-2.5-pro"
log_agent_call(
agent_id=AGENT_ID,
input_payload={"message": req.message, "mode": req.mode},