From 1cba5166dbba3ceb7ee640c242edfbea45ed40ff Mon Sep 17 00:00:00 2001 From: chrischristiansen-glitch Date: Sun, 24 May 2026 16:44:04 +0200 Subject: [PATCH] fix: ADK 1.x Runner pattern + gemini-3.5-flash for A+ reasoning --- agents/core-logic/agent.py | 77 ++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/agents/core-logic/agent.py b/agents/core-logic/agent.py index b678fe6..0796e35 100644 --- a/agents/core-logic/agent.py +++ b/agents/core-logic/agent.py @@ -4,7 +4,8 @@ agent.py — OSVauco root agent using ADK 1.x with A / A+ mode routing. Modes: A (standard) — gemini-2.0-flash, $1/task hard stop - A+ (audit+) — gemini-2.5-pro orchestrator, $3/task hard stop, + A+ (audit+) — gemini-2.5-pro orchestrator + subagents, + gemini-3.5-flash reasoning, $3/task hard stop, multi-agent pipeline enabled Authorized users for A+: opax, admin @@ -13,11 +14,15 @@ Requires: google-adk >= 1.0.0,<2.0.0 google-cloud-aiplatform >= 1.112.0 """ +import asyncio import os import logging from typing import Literal from google.adk.agents import Agent +from google.adk.runners import Runner +from google.adk.sessions.in_memory_session_service import InMemorySessionService +from google.genai import types logger = logging.getLogger(__name__) @@ -30,22 +35,23 @@ LOCATION = os.environ.get("GOOGLE_CLOUD_LOCATION", "us-central1") RAG_CORPUS = os.environ.get("RAG_CORPUS", "") # Standard (A) models -ORCHESTRATOR_MODEL = os.environ.get("ORCHESTRATOR_MODEL", "gemini-2.0-flash") -SUBAGENT_MODEL = os.environ.get("SUBAGENT_MODEL", "gemini-2.0-flash") -REASONING_MODEL = os.environ.get("REASONING_MODEL", "gemini-2.0-flash") +ORCHESTRATOR_MODEL = os.environ.get("ORCHESTRATOR_MODEL", "gemini-2.0-flash") +SUBAGENT_MODEL = os.environ.get("SUBAGENT_MODEL", "gemini-2.0-flash") +REASONING_MODEL = os.environ.get("REASONING_MODEL", "gemini-2.0-flash") # A+ (audit+) models -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") +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-3.5-flash") # NOT 2.5-flash # Budget hard stops (USD per task) -BUDGET_A = float(os.environ.get("BUDGET_A_USD_PER_TASK", "1.0")) -BUDGET_APLUS = float(os.environ.get("HEAVY_MODE_BUDGET_USD_PER_DAY", "3.0")) +BUDGET_A = float(os.environ.get("BUDGET_A_USD_PER_TASK", "1.0")) +BUDGET_APLUS = float(os.environ.get("HEAVY_MODE_BUDGET_USD_PER_DAY", "3.0")) HEAVY_MODE_ALLOWED_USERS = ["opax", "admin"] Mode = Literal["A", "A+"] +APP_NAME = "opax" # --------------------------------------------------------------------------- @@ -138,9 +144,48 @@ root_agent = build_agent(mode="A") # --------------------------------------------------------------------------- -# run() — programmatic entry point for Cloud Run /run endpoint +# run() — async core, sync wrapper for Cloud Run /run endpoint # --------------------------------------------------------------------------- +async def _run_async( + message: str, + user_id: str, + session_id: str, + mode: Mode, +) -> str: + """Async implementation using ADK 1.x Runner pattern.""" + agent = build_agent(mode=mode) + session_service = InMemorySessionService() + + session = await session_service.create_session( + app_name=APP_NAME, + user_id=user_id, + session_id=session_id, + ) + + runner = Runner( + agent=agent, + app_name=APP_NAME, + session_service=session_service, + ) + + new_message = types.Content( + role="user", + parts=[types.Part(text=message)], + ) + + final_text = "" + async for event in runner.run_async( + user_id=user_id, + session_id=session.id, + new_message=new_message, + ): + if event.is_final_response() and event.content and event.content.parts: + final_text = event.content.parts[0].text or "" + + return final_text + + def run( message: str, user_id: str = "opax", @@ -160,7 +205,7 @@ def run( Agent response as a string. Raises: - PermissionError: If user_id is not authorized for the requested mode. + PermissionError: If user_id is not authorized for A+ mode. ValueError: If mode is not 'A' or 'A+'. """ if mode not in ("A", "A+"): @@ -168,13 +213,12 @@ def run( authorize_mode(user_id, mode) - agent = build_agent(mode=mode) - response = agent.run( + return asyncio.run(_run_async( message=message, - session_id=session_id, user_id=user_id, - ) - return response.text if hasattr(response, "text") else str(response) + session_id=session_id, + mode=mode, + )) # --------------------------------------------------------------------------- @@ -183,6 +227,7 @@ 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 A+ mode?" requested_mode = sys.argv[2] if len(sys.argv) > 2 else "A"