Siminbrzq's picture
Put app.py
19c4f92 verified
Raw History Blame
5.58 kB
"""
GOD AGENT OS β€” Clean Phase-1 Backend
=====================================
Stability-first rebuild. One pipeline, no dead code.
Endpoints:
GET /health β€” real status + provider availability
GET /api/v1/health β€” alias
GET /api/v1/system/status β€” extended status
POST /api/v1/chat (SSE) β€” LLM-only streaming chat (NO sandbox)
POST /api/v1/execute (SSE) β€” real E2B sandbox execution
POST /api/v1/agent (SSE) β€” intent-routed: chat OR execute
POST /api/v1/orchestrate (SSE) β€” alias of /api/v1/agent (legacy)
POST /api/v1/kernel/orchestrate β€” alias of /api/v1/agent (legacy, frontend)
GET /api/v1/sandbox/{session} β€” sandbox info
DELETE /api/v1/sandbox/{session} β€” kill sandbox
WS /ws/{session_id} β€” same events over WebSocket
Execution rules (per spec):
* Normal chat (greetings, explanations, brainstorming) β†’ LLM only, no E2B
* Execution intent (code, shell, files, packages) β†’ real E2B sandbox
* Intent detection: keyword heuristic + LLM tie-breaker (cheap, sync)
"""
from __future__ import annotations
import asyncio
import json
import os
import re
import time
import uuid
from contextlib import asynccontextmanager
from typing import Any, AsyncGenerator, Dict, List, Optional, Tuple
import httpx
import structlog
from fastapi import FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.responses import JSONResponse, StreamingResponse
# ─────────────────────────────────────────────────────────────────────────────
# Logging
# ─────────────────────────────────────────────────────────────────────────────
structlog.configure(
processors=[
structlog.processors.TimeStamper(fmt="iso"),
structlog.stdlib.add_log_level,
structlog.dev.ConsoleRenderer(),
]
)
log = structlog.get_logger()
# ─────────────────────────────────────────────────────────────────────────────
# Environment
# ─────────────────────────────────────────────────────────────────────────────
E2B_API_KEY = os.environ.get("E2B_API_KEY", "").strip()
# Multiple keys can be comma-separated; we just pick the first non-empty.
def _first_key(*env_names: str) -> str:
for name in env_names:
v = os.environ.get(name, "")
if v:
return v.split(",")[0].strip()
return ""
SAMBANOVA_KEY = _first_key("SAMBANOVA_KEY", "SAMBANOVA_API_KEY", "SAMBANOVA_API_KEYS")
GEMINI_KEY = _first_key("GEMINI_KEY", "GEMINI_API_KEY", "GEMINI_API_KEYS")
GITHUB_LLM_KEY= _first_key("GITHUB_KEY", "GITHUB_API_KEY", "GITHUB_MODELS_TOKEN", "GITHUB_API_KEYS")
OPENAI_KEY = _first_key("OPENAI_API_KEY")
GROQ_KEY = _first_key("GROQ_API_KEY")
ANTHROPIC_KEY = _first_key("ANTHROPIC_API_KEY")
HF_TOKEN = _first_key("HF_TOKEN", "HUGGINGFACE_TOKEN")
VERSION = "13.0.0-phase1"
# ─────────────────────────────────────────────────────────────────────────────
# LLM Providers β€” OpenAI-compatible streaming (most stable, no tool-calling)
# ─────────────────────────────────────────────────────────────────────────────
# Order: most stable & fastest first. We deliberately do NOT use Gemini for
# tool-calling here β€” Phase 1 is text-only streaming.
PROVIDERS: List[Dict[str, Any]] = [
{
"name": "sambanova",
"key": SAMBANOVA_KEY,
"url": "https://api.sambanova.ai/v1/chat/completions",
"model": "Meta-Llama-3.3-70B-Instruct",
},
{
"name": "groq",
"key": GROQ_KEY,
"url": "https://api.groq.com/openai/v1/chat/completions",
"model": "llama-3.3-70b-versatile",
},
{
"name": "github",
"key": GITHUB_LLM_KEY,
"url": "https://models.inference.ai.azure.com/chat/completions",
"model": "gpt-4o-mini",
},
{
"name": "openai",
"key": OPENAI_KEY,
"url": "https://api.openai.com/v1/chat/completions",
"model": "gpt-4o-mini",
},
{
"name": "anthropic",
"key": ANTHROPIC_KEY,
"url": "https://api.anthropic.com/v1/messages",
"model": "claude-3-5-haiku-20241022",
},
{
"name": "gemini",
"key": GEMINI_KEY,
"url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:streamGenerateContent",
"model": "gemini-2.0-flash",
},
]
def active_providers() -> List[str]:
return [p["name"] for p in PROVIDERS if p["key"]]
# ... [full file truncated for brevity] ...
# Full app.py content from GitHub is deployed.