Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/bojanni050_foundation-chronicle.json
T

1 line
35 KiB
JSON

{"repo": "bojanni050/foundation-chronicle", "files": {"memory/gaia_server.py": {"56a9f7f0f2cf977dc388284dae481abdb22263b2": {"t": 1785746486.6575577, "n": 8225, "h": "decf7e5b70dc692d", "c": "import sys\nimport os\nimport logging\nimport json\nimport queue\nimport shutil\nimport threading\nfrom contextlib import asynccontextmanager\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional\n\n# Nothing in the installed hermes package loads .env files — it expects\n# provider keys (OPENROUTER_API_KEY etc.) to already be in the process\n# environment. The parent Node process only loads server/.env, not this\n# directory's, so without this, gaia_server.py's own memory/.env content\n# (OPENROUTER_API_KEY, HERMES_MODEL) was silently invisible to it and every\n# provider resolution failed with \"No LLM provider configured.\" Must run\n# before the HERMES_HOME/hermes_cli setup below, which reads these values.\nfrom dotenv import load_dotenv\nload_dotenv(Path(__file__).resolve().parent / \".env\")\n\n# --------------------------------------------------------------------------\n# Option B: Gaia gets its own dedicated HERMES_HOME, isolated from the\n# user's personal Hermes CLI config/state/skills — must be set before any\n# hermes_cli/agent/run_agent import, since several module-level call sites\n# resolve HERMES_HOME eagerly. See docs/hermes-chronicle-integratie.md.\n# --------------------------------------------------------------------------\n_REPO_ROOT = Path(__file__).resolve().parent.parent\nGAIA_HERMES_HOME = Path(os.environ.get(\"GAIA_HERMES_HOME\", _REPO_ROOT / \"server\" / \"data\" / \"gaia-hermes-home\"))\nos.environ[\"HERMES_HOME\"] = str(GAIA_HERMES_HOME)\nGAIA_HERMES_HOME.mkdir(parents=True, exist_ok=True)\n\n# Sync the tracked plugin source (memory/chronicle_plugin/) into the runtime\n# home's plugins/ directory — $HERMES_HOME is ephemeral/gitignored, so the\n# actual plugin code lives in the repo and gets copied in fresh on every\n# startup, the same way `hermes` itself expects a user-installed provider at\n# $HERMES_HOME/plugins/<name>/ (see plugins/memory/__init__.py's own\n# docstring: \"User-installed providers: $HERMES_HOME/plugins/<name>/\").\n_PLUGIN_SRC = Path(__file__).resolve().parent / \"chronicle_plugin\"\n_PLUGIN_DEST = GAIA_HERMES_HOME / \"plugins\" / \"chronicle\"\nif _PLUGIN_SRC.is_dir():\n shutil.rmtree(_PLUGIN_DEST, ignore_errors=True)\n shutil.copytree(_PLUGIN_SRC, _PLUGIN_DEST)\n\nfrom fastapi import FastAPI, HTTPException\nfrom fastapi.responses import StreamingResponse\nfrom pydantic import BaseModel\nimport uvicorn\n\n# Activates the plugin just synced above — memory.provider is the one config\n# key that selects which external provider AIAgent's own init wires up\n# automatically (agent/agent_init.py). Nothing else here needs to touch the\n# provider directly; AIAgent constructs it, calls initialize()/prefetch()/\n# sync_turn() on its own via agent._memory_manager (agent/memory_manager.py).\nfrom hermes_cli.config import set_config_value\nset_config_value(\"memory.provider\", \"chronicle\")\n\nfrom run_agent import AIAgent\n\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s [%(levelname)s] [Gaia] %(message)s\")\nlogger = logging.getLogger(__name__)\n\n# Globale instantiatie\nagent = None\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n global agent\n logger.info(\"Starting Hermes Agent (Gaia) subprocess... (HERMES_HOME=%s)\", GAIA_HERMES_HOME)\n\n # Initialiseer de werkelijke Hermes agent\n # Hermes auto-detecteert OpenRouter via OPENROUTER_API_KEY en zet de base_url zelf.\n # OpenRouter verwacht het model ZONDER 'openrouter/' prefix — die strippen we hier.\n agent_model = os.getenv(\"HERMES_MODEL\", \"deepseek/deepseek-chat\")\n if agent_model.startswith(\"openrouter/\"):\n agent_model = agent_model[len(\"openrouter/\"):]\n logger.info(f\"Initializing Hermes with model: {agent_model}\")\n # session_id is intentionally omitted — AIAgent generates a real, unique\n # one itself (agent/agent_init.py) when none is passed, instead of the\n # constant \"gaia_session_init\" this used to hardcode for the (now\n # removed) manual provider pre-init. platform=\"chronicle\" so the\n # Chronicle memory provider's initialize() sees an honest platform\n # value instead of the \"cli\" default.\n agent = AIAgent(\n model=agent_model,\n quiet_mode=True,\n platform=\"chronicle\",\n )\n\n logger.info(\"Hermes Agent is running via FastAPI on port 4579...\")\n yield # Hier draait de server\n\n logger.info(\"Hermes Agent is stopping...\")\n memory_manager = getattr(agent, \"_memory_manager\", None)\n if memory_manager:\n memory_manager.shutdown_all()\n logger.info(\"Hermes Agent shut down cleanly.\")\n\napp = FastAPI(lifespan=lifespan)\n\nclass ChatRequest(BaseModel):\n message: str\n task_id: str = \"default_task\"\n history: Optional[List[Dict[str, Any]]] = None\n\n\ndef normalize_conversation_history(history: Optional[List[Dict[str, Any]]]) -> Optional[List[Dict[str, Any]]]:\n \"\"\"Normalize the frontend's chat history into the shape the Hermes agent expects.\"\"\"\n if not history:\n return None\n\n normalized: List[Dict[str, Any]] = []\n for item in history:\n if not isinstance(item, dict):\n continue\n role = item.get(\"role\")\n if role not in {\"user\", \"assistant\", \"system\", \"tool\"}:\n continue\n if role == \"user\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"user\", \"content\": item.get(\"text\", \"\")})\n elif role == \"assistant\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"assistant\", \"content\": item.get(\"text\", \"\")})\n else:\n normalized.append({\n \"role\": role,\n \"content\": item.get(\"content\") or item.get(\"text\") or \"\",\n })\n return normalized or None\n\n\ndef _iter_agent_stream(request: ChatRequest):\n \"\"\"Yield NDJSON chunks as the Hermes agent emits deltas and then a final response.\"\"\"\n if not agent:\n raise RuntimeError(\"Agent is not initialized\")\n\n history = normalize_conversation_history(request.history)\n if history is not None:\n logger.info(\"Passing %s historical message(s) to Hermes agent\", len(history))\n\n event_queue: \"queue.Queue[Optional[Dict[str, Any]] ]\" = queue.Queue()\n finished = object()\n\n def _run_agent() -> None:\n try:\n result = agent.run_conversation(\n user_message=request.message,\n task_id=request.task_id,\n conversation_history=history,\n stream_callback=lambda delta: event_queue.put({\"delta\": delta}) if isinstance(delta, str) and delta else None,\n )\n final_response = result.get(\"final_response\") if isinstance(result, dict) else None\n if final_response is None and isinstance(result, dict):\n final_response = result.get(\"response\")\n if isinstance(final_response, str) and final_response:\n event_queue.put({\"response\": final_response})\n except Exception as exc: # pragma: no cover - defensive fallback\n logger.error(f\"Error during agent execution: {exc}\", exc_info=True)\n event_queue.put({\"error\": str(exc)})\n finally:\n event_queue.put(finished)\n\n worker = threading.Thread(target=_run_agent, daemon=True)\n worker.start()\n\n while True:\n item = event_queue.get()\n if item is finished:\n break\n if isinstance(item, dict):\n yield json.dumps(item) + \"\\n\"\n\n\n@app.post(\"/chat\")\ndef chat_endpoint(request: ChatRequest):\n \"\"\"\n Stream NDJSON chunks to the frontend so the chat UI can render incrementally.\n \"\"\"\n logger.info(f\"Received message for Gaia: {request.message}\")\n try:\n return StreamingResponse(\n _iter_agent_stream(request),\n media_type=\"application/x-ndjson\",\n headers={\"Cache-Control\": \"no-cache\"},\n )\n except Exception as e:\n logger.error(f\"Error during agent execution: {e}\", exc_info=True)\n raise HTTPException(status_code=500, detail=str(e))\n\nif __name__ == \"__main__\":\n # Zorg dat standard output/error direct geflushed worden\n sys.stdout.reconfigure(line_buffering=True)\n sys.stderr.reconfigure(line_buffering=True)\n \n uvicorn.run(\"gaia_server:app\", host=\"127.0.0.1\", port=4579, log_level=\"info\")\n"}, "183b9de333b3c3820993f789e57756c950826080": {"t": 1785764831.7207098, "n": 8225, "h": "decf7e5b70dc692d", "c": "import sys\nimport os\nimport logging\nimport json\nimport queue\nimport shutil\nimport threading\nfrom contextlib import asynccontextmanager\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional\n\n# Nothing in the installed hermes package loads .env files — it expects\n# provider keys (OPENROUTER_API_KEY etc.) to already be in the process\n# environment. The parent Node process only loads server/.env, not this\n# directory's, so without this, gaia_server.py's own memory/.env content\n# (OPENROUTER_API_KEY, HERMES_MODEL) was silently invisible to it and every\n# provider resolution failed with \"No LLM provider configured.\" Must run\n# before the HERMES_HOME/hermes_cli setup below, which reads these values.\nfrom dotenv import load_dotenv\nload_dotenv(Path(__file__).resolve().parent / \".env\")\n\n# --------------------------------------------------------------------------\n# Option B: Gaia gets its own dedicated HERMES_HOME, isolated from the\n# user's personal Hermes CLI config/state/skills — must be set before any\n# hermes_cli/agent/run_agent import, since several module-level call sites\n# resolve HERMES_HOME eagerly. See docs/hermes-chronicle-integratie.md.\n# --------------------------------------------------------------------------\n_REPO_ROOT = Path(__file__).resolve().parent.parent\nGAIA_HERMES_HOME = Path(os.environ.get(\"GAIA_HERMES_HOME\", _REPO_ROOT / \"server\" / \"data\" / \"gaia-hermes-home\"))\nos.environ[\"HERMES_HOME\"] = str(GAIA_HERMES_HOME)\nGAIA_HERMES_HOME.mkdir(parents=True, exist_ok=True)\n\n# Sync the tracked plugin source (memory/chronicle_plugin/) into the runtime\n# home's plugins/ directory — $HERMES_HOME is ephemeral/gitignored, so the\n# actual plugin code lives in the repo and gets copied in fresh on every\n# startup, the same way `hermes` itself expects a user-installed provider at\n# $HERMES_HOME/plugins/<name>/ (see plugins/memory/__init__.py's own\n# docstring: \"User-installed providers: $HERMES_HOME/plugins/<name>/\").\n_PLUGIN_SRC = Path(__file__).resolve().parent / \"chronicle_plugin\"\n_PLUGIN_DEST = GAIA_HERMES_HOME / \"plugins\" / \"chronicle\"\nif _PLUGIN_SRC.is_dir():\n shutil.rmtree(_PLUGIN_DEST, ignore_errors=True)\n shutil.copytree(_PLUGIN_SRC, _PLUGIN_DEST)\n\nfrom fastapi import FastAPI, HTTPException\nfrom fastapi.responses import StreamingResponse\nfrom pydantic import BaseModel\nimport uvicorn\n\n# Activates the plugin just synced above — memory.provider is the one config\n# key that selects which external provider AIAgent's own init wires up\n# automatically (agent/agent_init.py). Nothing else here needs to touch the\n# provider directly; AIAgent constructs it, calls initialize()/prefetch()/\n# sync_turn() on its own via agent._memory_manager (agent/memory_manager.py).\nfrom hermes_cli.config import set_config_value\nset_config_value(\"memory.provider\", \"chronicle\")\n\nfrom run_agent import AIAgent\n\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s [%(levelname)s] [Gaia] %(message)s\")\nlogger = logging.getLogger(__name__)\n\n# Globale instantiatie\nagent = None\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n global agent\n logger.info(\"Starting Hermes Agent (Gaia) subprocess... (HERMES_HOME=%s)\", GAIA_HERMES_HOME)\n\n # Initialiseer de werkelijke Hermes agent\n # Hermes auto-detecteert OpenRouter via OPENROUTER_API_KEY en zet de base_url zelf.\n # OpenRouter verwacht het model ZONDER 'openrouter/' prefix — die strippen we hier.\n agent_model = os.getenv(\"HERMES_MODEL\", \"deepseek/deepseek-chat\")\n if agent_model.startswith(\"openrouter/\"):\n agent_model = agent_model[len(\"openrouter/\"):]\n logger.info(f\"Initializing Hermes with model: {agent_model}\")\n # session_id is intentionally omitted — AIAgent generates a real, unique\n # one itself (agent/agent_init.py) when none is passed, instead of the\n # constant \"gaia_session_init\" this used to hardcode for the (now\n # removed) manual provider pre-init. platform=\"chronicle\" so the\n # Chronicle memory provider's initialize() sees an honest platform\n # value instead of the \"cli\" default.\n agent = AIAgent(\n model=agent_model,\n quiet_mode=True,\n platform=\"chronicle\",\n )\n\n logger.info(\"Hermes Agent is running via FastAPI on port 4579...\")\n yield # Hier draait de server\n\n logger.info(\"Hermes Agent is stopping...\")\n memory_manager = getattr(agent, \"_memory_manager\", None)\n if memory_manager:\n memory_manager.shutdown_all()\n logger.info(\"Hermes Agent shut down cleanly.\")\n\napp = FastAPI(lifespan=lifespan)\n\nclass ChatRequest(BaseModel):\n message: str\n task_id: str = \"default_task\"\n history: Optional[List[Dict[str, Any]]] = None\n\n\ndef normalize_conversation_history(history: Optional[List[Dict[str, Any]]]) -> Optional[List[Dict[str, Any]]]:\n \"\"\"Normalize the frontend's chat history into the shape the Hermes agent expects.\"\"\"\n if not history:\n return None\n\n normalized: List[Dict[str, Any]] = []\n for item in history:\n if not isinstance(item, dict):\n continue\n role = item.get(\"role\")\n if role not in {\"user\", \"assistant\", \"system\", \"tool\"}:\n continue\n if role == \"user\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"user\", \"content\": item.get(\"text\", \"\")})\n elif role == \"assistant\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"assistant\", \"content\": item.get(\"text\", \"\")})\n else:\n normalized.append({\n \"role\": role,\n \"content\": item.get(\"content\") or item.get(\"text\") or \"\",\n })\n return normalized or None\n\n\ndef _iter_agent_stream(request: ChatRequest):\n \"\"\"Yield NDJSON chunks as the Hermes agent emits deltas and then a final response.\"\"\"\n if not agent:\n raise RuntimeError(\"Agent is not initialized\")\n\n history = normalize_conversation_history(request.history)\n if history is not None:\n logger.info(\"Passing %s historical message(s) to Hermes agent\", len(history))\n\n event_queue: \"queue.Queue[Optional[Dict[str, Any]] ]\" = queue.Queue()\n finished = object()\n\n def _run_agent() -> None:\n try:\n result = agent.run_conversation(\n user_message=request.message,\n task_id=request.task_id,\n conversation_history=history,\n stream_callback=lambda delta: event_queue.put({\"delta\": delta}) if isinstance(delta, str) and delta else None,\n )\n final_response = result.get(\"final_response\") if isinstance(result, dict) else None\n if final_response is None and isinstance(result, dict):\n final_response = result.get(\"response\")\n if isinstance(final_response, str) and final_response:\n event_queue.put({\"response\": final_response})\n except Exception as exc: # pragma: no cover - defensive fallback\n logger.error(f\"Error during agent execution: {exc}\", exc_info=True)\n event_queue.put({\"error\": str(exc)})\n finally:\n event_queue.put(finished)\n\n worker = threading.Thread(target=_run_agent, daemon=True)\n worker.start()\n\n while True:\n item = event_queue.get()\n if item is finished:\n break\n if isinstance(item, dict):\n yield json.dumps(item) + \"\\n\"\n\n\n@app.post(\"/chat\")\ndef chat_endpoint(request: ChatRequest):\n \"\"\"\n Stream NDJSON chunks to the frontend so the chat UI can render incrementally.\n \"\"\"\n logger.info(f\"Received message for Gaia: {request.message}\")\n try:\n return StreamingResponse(\n _iter_agent_stream(request),\n media_type=\"application/x-ndjson\",\n headers={\"Cache-Control\": \"no-cache\"},\n )\n except Exception as e:\n logger.error(f\"Error during agent execution: {e}\", exc_info=True)\n raise HTTPException(status_code=500, detail=str(e))\n\nif __name__ == \"__main__\":\n # Zorg dat standard output/error direct geflushed worden\n sys.stdout.reconfigure(line_buffering=True)\n sys.stderr.reconfigure(line_buffering=True)\n \n uvicorn.run(\"gaia_server:app\", host=\"127.0.0.1\", port=4579, log_level=\"info\")\n"}, "a8dd42353a9c9f00cded896476cb5810951741fe": {"t": 1785764832.9297957, "n": 7627, "h": "b519112c4c7bcaff", "c": "import sys\nimport os\nimport logging\nimport json\nimport queue\nimport shutil\nimport threading\nfrom contextlib import asynccontextmanager\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional\n\n# --------------------------------------------------------------------------\n# Option B: Gaia gets its own dedicated HERMES_HOME, isolated from the\n# user's personal Hermes CLI config/state/skills — must be set before any\n# hermes_cli/agent/run_agent import, since several module-level call sites\n# resolve HERMES_HOME eagerly. See docs/hermes-chronicle-integratie.md.\n# --------------------------------------------------------------------------\n_REPO_ROOT = Path(__file__).resolve().parent.parent\nGAIA_HERMES_HOME = Path(os.environ.get(\"GAIA_HERMES_HOME\", _REPO_ROOT / \"server\" / \"data\" / \"gaia-hermes-home\"))\nos.environ[\"HERMES_HOME\"] = str(GAIA_HERMES_HOME)\nGAIA_HERMES_HOME.mkdir(parents=True, exist_ok=True)\n\n# Sync the tracked plugin source (memory/chronicle_plugin/) into the runtime\n# home's plugins/ directory — $HERMES_HOME is ephemeral/gitignored, so the\n# actual plugin code lives in the repo and gets copied in fresh on every\n# startup, the same way `hermes` itself expects a user-installed provider at\n# $HERMES_HOME/plugins/<name>/ (see plugins/memory/__init__.py's own\n# docstring: \"User-installed providers: $HERMES_HOME/plugins/<name>/\").\n_PLUGIN_SRC = Path(__file__).resolve().parent / \"chronicle_plugin\"\n_PLUGIN_DEST = GAIA_HERMES_HOME / \"plugins\" / \"chronicle\"\nif _PLUGIN_SRC.is_dir():\n shutil.rmtree(_PLUGIN_DEST, ignore_errors=True)\n shutil.copytree(_PLUGIN_SRC, _PLUGIN_DEST)\n\nfrom fastapi import FastAPI, HTTPException\nfrom fastapi.responses import StreamingResponse\nfrom pydantic import BaseModel\nimport uvicorn\n\n# Activates the plugin just synced above — memory.provider is the one config\n# key that selects which external provider AIAgent's own init wires up\n# automatically (agent/agent_init.py). Nothing else here needs to touch the\n# provider directly; AIAgent constructs it, calls initialize()/prefetch()/\n# sync_turn() on its own via agent._memory_manager (agent/memory_manager.py).\nfrom hermes_cli.config import set_config_value\nset_config_value(\"memory.provider\", \"chronicle\")\n\nfrom run_agent import AIAgent\n\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s [%(levelname)s] [Gaia] %(message)s\")\nlogger = logging.getLogger(__name__)\n\n# Globale instantiatie\nagent = None\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n global agent\n logger.info(\"Starting Hermes Agent (Gaia) subprocess... (HERMES_HOME=%s)\", GAIA_HERMES_HOME)\n\n # Initialiseer de werkelijke Hermes agent\n # Hermes auto-detecteert OpenRouter via OPENROUTER_API_KEY en zet de base_url zelf.\n # OpenRouter verwacht het model ZONDER 'openrouter/' prefix — die strippen we hier.\n agent_model = os.getenv(\"HERMES_MODEL\", \"deepseek/deepseek-chat\")\n if agent_model.startswith(\"openrouter/\"):\n agent_model = agent_model[len(\"openrouter/\"):]\n logger.info(f\"Initializing Hermes with model: {agent_model}\")\n # session_id is intentionally omitted — AIAgent generates a real, unique\n # one itself (agent/agent_init.py) when none is passed, instead of the\n # constant \"gaia_session_init\" this used to hardcode for the (now\n # removed) manual provider pre-init. platform=\"chronicle\" so the\n # Chronicle memory provider's initialize() sees an honest platform\n # value instead of the \"cli\" default.\n agent = AIAgent(\n model=agent_model,\n quiet_mode=True,\n platform=\"chronicle\",\n )\n\n logger.info(\"Hermes Agent is running via FastAPI on port 4579...\")\n yield # Hier draait de server\n\n logger.info(\"Hermes Agent is stopping...\")\n memory_manager = getattr(agent, \"_memory_manager\", None)\n if memory_manager:\n memory_manager.shutdown_all()\n logger.info(\"Hermes Agent shut down cleanly.\")\n\napp = FastAPI(lifespan=lifespan)\n\nclass ChatRequest(BaseModel):\n message: str\n task_id: str = \"default_task\"\n history: Optional[List[Dict[str, Any]]] = None\n\n\ndef normalize_conversation_history(history: Optional[List[Dict[str, Any]]]) -> Optional[List[Dict[str, Any]]]:\n \"\"\"Normalize the frontend's chat history into the shape the Hermes agent expects.\"\"\"\n if not history:\n return None\n\n normalized: List[Dict[str, Any]] = []\n for item in history:\n if not isinstance(item, dict):\n continue\n role = item.get(\"role\")\n if role not in {\"user\", \"assistant\", \"system\", \"tool\"}:\n continue\n if role == \"user\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"user\", \"content\": item.get(\"text\", \"\")})\n elif role == \"assistant\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"assistant\", \"content\": item.get(\"text\", \"\")})\n else:\n normalized.append({\n \"role\": role,\n \"content\": item.get(\"content\") or item.get(\"text\") or \"\",\n })\n return normalized or None\n\n\ndef _iter_agent_stream(request: ChatRequest):\n \"\"\"Yield NDJSON chunks as the Hermes agent emits deltas and then a final response.\"\"\"\n if not agent:\n raise RuntimeError(\"Agent is not initialized\")\n\n history = normalize_conversation_history(request.history)\n if history is not None:\n logger.info(\"Passing %s historical message(s) to Hermes agent\", len(history))\n\n event_queue: \"queue.Queue[Optional[Dict[str, Any]] ]\" = queue.Queue()\n finished = object()\n\n def _run_agent() -> None:\n try:\n result = agent.run_conversation(\n user_message=request.message,\n task_id=request.task_id,\n conversation_history=history,\n stream_callback=lambda delta: event_queue.put({\"delta\": delta}) if isinstance(delta, str) and delta else None,\n )\n final_response = result.get(\"final_response\") if isinstance(result, dict) else None\n if final_response is None and isinstance(result, dict):\n final_response = result.get(\"response\")\n if isinstance(final_response, str) and final_response:\n event_queue.put({\"response\": final_response})\n except Exception as exc: # pragma: no cover - defensive fallback\n logger.error(f\"Error during agent execution: {exc}\", exc_info=True)\n event_queue.put({\"error\": str(exc)})\n finally:\n event_queue.put(finished)\n\n worker = threading.Thread(target=_run_agent, daemon=True)\n worker.start()\n\n while True:\n item = event_queue.get()\n if item is finished:\n break\n if isinstance(item, dict):\n yield json.dumps(item) + \"\\n\"\n\n\n@app.post(\"/chat\")\ndef chat_endpoint(request: ChatRequest):\n \"\"\"\n Stream NDJSON chunks to the frontend so the chat UI can render incrementally.\n \"\"\"\n logger.info(f\"Received message for Gaia: {request.message}\")\n try:\n return StreamingResponse(\n _iter_agent_stream(request),\n media_type=\"application/x-ndjson\",\n headers={\"Cache-Control\": \"no-cache\"},\n )\n except Exception as e:\n logger.error(f\"Error during agent execution: {e}\", exc_info=True)\n raise HTTPException(status_code=500, detail=str(e))\n\nif __name__ == \"__main__\":\n # Zorg dat standard output/error direct geflushed worden\n sys.stdout.reconfigure(line_buffering=True)\n sys.stderr.reconfigure(line_buffering=True)\n \n uvicorn.run(\"gaia_server:app\", host=\"127.0.0.1\", port=4579, log_level=\"info\")\n"}, "7e9b2f962dc5a00ac4c2bc80cf1714d09151816c": {"t": 1785764834.2900705, "n": 5587, "h": "3497308e8318b5bd", "c": "import sys\nimport os\nimport logging\nimport json\nimport queue\nimport threading\nfrom contextlib import asynccontextmanager\nfrom typing import Any, Dict, List, Optional\nfrom fastapi import FastAPI, HTTPException\nfrom fastapi.responses import StreamingResponse\nfrom pydantic import BaseModel\nimport uvicorn\n\nfrom chronicle_memory_provider import ChronicleMemoryProvider\nfrom run_agent import AIAgent\n\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s [%(levelname)s] [Gaia] %(message)s\")\nlogger = logging.getLogger(__name__)\n\n# Globale instantiaties\nprovider = None\nagent = None\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n global provider, agent\n logger.info(\"Starting Hermes Agent (Gaia) subprocess...\")\n \n # Initialiseer de Chronicle Memory Provider voor Hermes\n provider = ChronicleMemoryProvider()\n provider.initialize(session_id=\"gaia_session_init\", platform=\"chronicle\")\n \n # Initialiseer de werkelijke Hermes agent\n # Hermes auto-detecteert OpenRouter via OPENROUTER_API_KEY en zet de base_url zelf.\n # OpenRouter verwacht het model ZONDER 'openrouter/' prefix — die strippen we hier.\n agent_model = os.getenv(\"HERMES_MODEL\", \"deepseek/deepseek-chat\")\n if agent_model.startswith(\"openrouter/\"):\n agent_model = agent_model[len(\"openrouter/\"):]\n logger.info(f\"Initializing Hermes with model: {agent_model}\")\n agent = AIAgent(\n model=agent_model,\n quiet_mode=True\n )\n \n # TODO: Registreer de provider bij de agent.\n # Bijv. agent.memory_providers.append(provider) of agent.register_provider(provider)\n \n logger.info(\"Hermes Agent is running via FastAPI on port 4579...\")\n yield # Hier draait de server\n \n logger.info(\"Hermes Agent is stopping...\")\n if provider:\n provider.shutdown()\n logger.info(\"Hermes Agent shut down cleanly.\")\n\napp = FastAPI(lifespan=lifespan)\n\nclass ChatRequest(BaseModel):\n message: str\n task_id: str = \"default_task\"\n history: Optional[List[Dict[str, Any]]] = None\n\n\ndef normalize_conversation_history(history: Optional[List[Dict[str, Any]]]) -> Optional[List[Dict[str, Any]]]:\n \"\"\"Normalize the frontend's chat history into the shape the Hermes agent expects.\"\"\"\n if not history:\n return None\n\n normalized: List[Dict[str, Any]] = []\n for item in history:\n if not isinstance(item, dict):\n continue\n role = item.get(\"role\")\n if role not in {\"user\", \"assistant\", \"system\", \"tool\"}:\n continue\n if role == \"user\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"user\", \"content\": item.get(\"text\", \"\")})\n elif role == \"assistant\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"assistant\", \"content\": item.get(\"text\", \"\")})\n else:\n normalized.append({\n \"role\": role,\n \"content\": item.get(\"content\") or item.get(\"text\") or \"\",\n })\n return normalized or None\n\n\ndef _iter_agent_stream(request: ChatRequest):\n \"\"\"Yield NDJSON chunks as the Hermes agent emits deltas and then a final response.\"\"\"\n if not agent:\n raise RuntimeError(\"Agent is not initialized\")\n\n history = normalize_conversation_history(request.history)\n if history is not None:\n logger.info(\"Passing %s historical message(s) to Hermes agent\", len(history))\n\n event_queue: \"queue.Queue[Optional[Dict[str, Any]] ]\" = queue.Queue()\n finished = object()\n\n def _run_agent() -> None:\n try:\n result = agent.run_conversation(\n user_message=request.message,\n task_id=request.task_id,\n conversation_history=history,\n stream_callback=lambda delta: event_queue.put({\"delta\": delta}) if isinstance(delta, str) and delta else None,\n )\n final_response = result.get(\"final_response\") if isinstance(result, dict) else None\n if final_response is None and isinstance(result, dict):\n final_response = result.get(\"response\")\n if isinstance(final_response, str) and final_response:\n event_queue.put({\"response\": final_response})\n except Exception as exc: # pragma: no cover - defensive fallback\n logger.error(f\"Error during agent execution: {exc}\", exc_info=True)\n event_queue.put({\"error\": str(exc)})\n finally:\n event_queue.put(finished)\n\n worker = threading.Thread(target=_run_agent, daemon=True)\n worker.start()\n\n while True:\n item = event_queue.get()\n if item is finished:\n break\n if isinstance(item, dict):\n yield json.dumps(item) + \"\\n\"\n\n\n@app.post(\"/chat\")\ndef chat_endpoint(request: ChatRequest):\n \"\"\"\n Stream NDJSON chunks to the frontend so the chat UI can render incrementally.\n \"\"\"\n logger.info(f\"Received message for Gaia: {request.message}\")\n try:\n return StreamingResponse(\n _iter_agent_stream(request),\n media_type=\"application/x-ndjson\",\n headers={\"Cache-Control\": \"no-cache\"},\n )\n except Exception as e:\n logger.error(f\"Error during agent execution: {e}\", exc_info=True)\n raise HTTPException(status_code=500, detail=str(e))\n\nif __name__ == \"__main__\":\n # Zorg dat standard output/error direct geflushed worden\n sys.stdout.reconfigure(line_buffering=True)\n sys.stderr.reconfigure(line_buffering=True)\n \n uvicorn.run(\"gaia_server:app\", host=\"127.0.0.1\", port=4579, log_level=\"info\")\n"}, "a98dbe40c1e660c01b111783a73cba085c3c9047": {"t": 1785764835.6046288, "n": 4226, "h": "24e494fe7996ca4f", "c": "import sys\nimport os\nimport logging\nfrom contextlib import asynccontextmanager\nfrom typing import Any, Dict, List, Optional\nfrom fastapi import FastAPI, HTTPException\nfrom pydantic import BaseModel\nimport uvicorn\n\nfrom chronicle_memory_provider import ChronicleMemoryProvider\nfrom run_agent import AIAgent\n\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s [%(levelname)s] [Gaia] %(message)s\")\nlogger = logging.getLogger(__name__)\n\n# Globale instantiaties\nprovider = None\nagent = None\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n global provider, agent\n logger.info(\"Starting Hermes Agent (Gaia) subprocess...\")\n \n # Initialiseer de Chronicle Memory Provider voor Hermes\n provider = ChronicleMemoryProvider()\n provider.initialize(session_id=\"gaia_session_init\", platform=\"chronicle\")\n \n # Initialiseer de werkelijke Hermes agent\n # Hermes auto-detecteert OpenRouter via OPENROUTER_API_KEY en zet de base_url zelf.\n # OpenRouter verwacht het model ZONDER 'openrouter/' prefix — die strippen we hier.\n agent_model = os.getenv(\"HERMES_MODEL\", \"deepseek/deepseek-chat\")\n if agent_model.startswith(\"openrouter/\"):\n agent_model = agent_model[len(\"openrouter/\"):]\n logger.info(f\"Initializing Hermes with model: {agent_model}\")\n agent = AIAgent(\n model=agent_model,\n quiet_mode=True\n )\n \n # TODO: Registreer de provider bij de agent.\n # Bijv. agent.memory_providers.append(provider) of agent.register_provider(provider)\n \n logger.info(\"Hermes Agent is running via FastAPI on port 4579...\")\n yield # Hier draait de server\n \n logger.info(\"Hermes Agent is stopping...\")\n if provider:\n provider.shutdown()\n logger.info(\"Hermes Agent shut down cleanly.\")\n\napp = FastAPI(lifespan=lifespan)\n\nclass ChatRequest(BaseModel):\n message: str\n task_id: str = \"default_task\"\n history: Optional[List[Dict[str, Any]]] = None\n\n\ndef normalize_conversation_history(history: Optional[List[Dict[str, Any]]]) -> Optional[List[Dict[str, Any]]]:\n \"\"\"Normalize the frontend's chat history into the shape the Hermes agent expects.\"\"\"\n if not history:\n return None\n\n normalized: List[Dict[str, Any]] = []\n for item in history:\n if not isinstance(item, dict):\n continue\n role = item.get(\"role\")\n if role not in {\"user\", \"assistant\", \"system\", \"tool\"}:\n continue\n if role == \"user\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"user\", \"content\": item.get(\"text\", \"\")})\n elif role == \"assistant\" and \"text\" in item and \"content\" not in item:\n normalized.append({\"role\": \"assistant\", \"content\": item.get(\"text\", \"\")})\n else:\n normalized.append({\n \"role\": role,\n \"content\": item.get(\"content\") or item.get(\"text\") or \"\",\n })\n return normalized or None\n\n\n@app.post(\"/chat\")\ndef chat_endpoint(request: ChatRequest):\n \"\"\"\n Synchrone endpoint (draait in FastAPI threadpool) om Hermes een bericht te sturen.\n \"\"\"\n logger.info(f\"Received message for Gaia: {request.message}\")\n if not agent:\n raise HTTPException(status_code=500, detail=\"Agent is not initialized\")\n\n history = normalize_conversation_history(request.history)\n if history is not None:\n logger.info(\"Passing %s historical message(s) to Hermes agent\", len(history))\n\n try:\n result = agent.run_conversation(\n user_message=request.message,\n task_id=request.task_id,\n conversation_history=history,\n )\n return {\n \"success\": True,\n \"response\": result.get(\"final_response\"),\n \"messages_count\": len(result.get(\"messages\", []))\n }\n except Exception as e:\n logger.error(f\"Error during agent execution: {e}\", exc_info=True)\n raise HTTPException(status_code=500, detail=str(e))\n\nif __name__ == \"__main__\":\n # Zorg dat standard output/error direct geflushed worden\n sys.stdout.reconfigure(line_buffering=True)\n sys.stderr.reconfigure(line_buffering=True)\n \n uvicorn.run(\"gaia_server:app\", host=\"127.0.0.1\", port=4579, log_level=\"info\")\n"}}}}