PYAE1994 commited on
Commit
660d02b
·
unverified ·
1 Parent(s): 8001a61

feat(v8): KeyPool Multi-API Router — Gemini + SambaNova Primary LLMs

Browse files

God Agent OS v8: KeyPool system with Gemini (6 keys) + SambaNova (9 keys), AIRouterV8, main_v8.py entry point, AI Router Panel UI

.github/workflows/deploy.yml CHANGED
@@ -1,4 +1,4 @@
1
- name: 🚀 God Agent OS v7 — Auto Deploy
2
 
3
  on:
4
  push:
@@ -10,7 +10,7 @@ env:
10
  VERCEL_PROJECT: god-agent-os
11
 
12
  jobs:
13
- # ── Build & Test ──────────────────────────────────────────────────────────
14
  build-check:
15
  name: ✅ Build Check
16
  runs-on: ubuntu-latest
@@ -28,10 +28,12 @@ jobs:
28
  cd backend
29
  pip install -r requirements.txt
30
 
31
- - name: Syntax check backend
32
  run: |
33
  cd backend
34
- python -m py_compile main_v7.py
 
 
35
  python -m py_compile agents/orchestrator_v7.py
36
  python -m py_compile agents/browser_agent.py
37
  python -m py_compile agents/file_agent.py
@@ -55,7 +57,7 @@ jobs:
55
  env:
56
  NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL || 'https://PYAE1994-autonomous-coding-system.hf.space' }}
57
 
58
- # ── Deploy to Hugging Face Spaces ────────────────────────────────────────
59
  deploy-huggingface:
60
  name: 🤗 Deploy to HF Spaces
61
  runs-on: ubuntu-latest
@@ -72,23 +74,24 @@ jobs:
72
  git config --global user.email "action@github.com"
73
  git config --global user.name "God Agent CI"
74
 
75
- - name: Deploy backend to HF Space
76
  env:
77
  HF_TOKEN: ${{ secrets.HF_TOKEN }}
78
  run: |
79
- # Install HF CLI
80
  pip install huggingface_hub -q
81
 
82
- # Clone HF space
83
  git clone https://pyae1994:$HF_TOKEN@huggingface.co/spaces/PYAE1994/autonomous-coding-system /tmp/hf-space
84
-
85
  # Copy backend files
86
  cp -r backend/. /tmp/hf-space/
87
-
88
- # Create HF-specific README
 
 
 
89
  cat > /tmp/hf-space/README.md << 'EOF'
90
  ---
91
- title: God Agent OS v7
92
  emoji: 🤖
93
  colorFrom: indigo
94
  colorTo: purple
@@ -96,27 +99,23 @@ jobs:
96
  app_port: 7860
97
  pinned: true
98
  license: mit
99
- short_description: Autonomous Engineering OS — Manus + Genspark + Devin
100
  ---
101
 
102
- # 🤖 God Agent OS v7
103
- **Autonomous Engineering PlatformManus + Genspark + Devin (OneHand)**
104
 
105
- 16-agent system for autonomous software engineering.
106
  EOF
107
 
108
- # Use HF Dockerfile
109
- cp backend/Dockerfile.hf /tmp/hf-space/Dockerfile
110
-
111
- # Commit and push
112
  cd /tmp/hf-space
113
  git add -A
114
- git diff --cached --quiet || git commit -m "🚀 God Agent OS v7 deploy $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
115
  git push origin main || git push origin master || true
116
-
117
  echo "✅ Deployed to HF Space: https://huggingface.co/spaces/PYAE1994/autonomous-coding-system"
118
 
119
- # ── Deploy to Vercel ───────────────────────────────────────────────────────
120
  deploy-vercel:
121
  name: ▲ Deploy to Vercel
122
  runs-on: ubuntu-latest
 
1
+ name: 🚀 God Agent OS v8 — Auto Deploy
2
 
3
  on:
4
  push:
 
10
  VERCEL_PROJECT: god-agent-os
11
 
12
  jobs:
13
+ # ── Build & Syntax Check ──────────────────────────────────────────────────
14
  build-check:
15
  name: ✅ Build Check
16
  runs-on: ubuntu-latest
 
28
  cd backend
29
  pip install -r requirements.txt
30
 
31
+ - name: Syntax check backend (v8)
32
  run: |
33
  cd backend
34
+ python -m py_compile main_v8.py
35
+ python -m py_compile ai_router/router_v8.py
36
+ python -m py_compile ai_router/key_pool.py
37
  python -m py_compile agents/orchestrator_v7.py
38
  python -m py_compile agents/browser_agent.py
39
  python -m py_compile agents/file_agent.py
 
57
  env:
58
  NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL || 'https://PYAE1994-autonomous-coding-system.hf.space' }}
59
 
60
+ # ── Deploy to Hugging Face Spaces ────────────────────────────────────────
61
  deploy-huggingface:
62
  name: 🤗 Deploy to HF Spaces
63
  runs-on: ubuntu-latest
 
74
  git config --global user.email "action@github.com"
75
  git config --global user.name "God Agent CI"
76
 
77
+ - name: Deploy backend to HF Space (v8)
78
  env:
79
  HF_TOKEN: ${{ secrets.HF_TOKEN }}
80
  run: |
 
81
  pip install huggingface_hub -q
82
 
 
83
  git clone https://pyae1994:$HF_TOKEN@huggingface.co/spaces/PYAE1994/autonomous-coding-system /tmp/hf-space
84
+
85
  # Copy backend files
86
  cp -r backend/. /tmp/hf-space/
87
+
88
+ # Use v8 Dockerfile
89
+ cp backend/Dockerfile.hf /tmp/hf-space/Dockerfile
90
+
91
+ # Create HF README with v8 metadata
92
  cat > /tmp/hf-space/README.md << 'EOF'
93
  ---
94
+ title: God Agent OS v8
95
  emoji: 🤖
96
  colorFrom: indigo
97
  colorTo: purple
 
99
  app_port: 7860
100
  pinned: true
101
  license: mit
102
+ short_description: Autonomous Engineering OS v8 KeyPool Multi-API (Gemini + SambaNova)
103
  ---
104
 
105
+ # 🤖 God Agent OS v8
106
+ **KeyPool Multi-API RoutingGemini + SambaNova Primary LLMs**
107
 
108
+ 16-agent autonomous engineering OS with intelligent key pooling.
109
  EOF
110
 
 
 
 
 
111
  cd /tmp/hf-space
112
  git add -A
113
+ git diff --cached --quiet || git commit -m "🚀 God Agent OS v8 deploy $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
114
  git push origin main || git push origin master || true
115
+
116
  echo "✅ Deployed to HF Space: https://huggingface.co/spaces/PYAE1994/autonomous-coding-system"
117
 
118
+ # ── Deploy to Vercel ─────────────────────────────────────────────────────
119
  deploy-vercel:
120
  name: ▲ Deploy to Vercel
121
  runs-on: ubuntu-latest
.gitignore ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dependencies
2
+ node_modules/
3
+ frontend/node_modules/
4
+ __pycache__/
5
+ *.pyc
6
+ *.pyo
7
+ *.pyd
8
+ .Python
9
+
10
+ # Build outputs
11
+ frontend/.next/
12
+ frontend/out/
13
+ dist/
14
+ build/
15
+ *.egg-info/
16
+
17
+ # Environment
18
+ .env
19
+ .env.local
20
+ .env.production
21
+ *.env
22
+
23
+ # Logs
24
+ *.log
25
+ logs/
26
+
27
+ # Database
28
+ *.db
29
+ *.sqlite
30
+
31
+ # OS
32
+ .DS_Store
33
+ Thumbs.db
34
+
35
+ # IDE
36
+ .vscode/
37
+ .idea/
38
+ *.swp
39
+
40
+ # Temporary
41
+ tmp/
42
+ temp/
43
+ /tmp/
44
+
45
+ # Python cache
46
+ backend/__pycache__/
47
+ backend/**/__pycache__/
48
+ backend/ai_router/__pycache__/
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: God Agent OS v7
3
  emoji: 🤖
4
  colorFrom: indigo
5
  colorTo: purple
@@ -7,24 +7,39 @@ sdk: docker
7
  app_port: 7860
8
  pinned: true
9
  license: mit
10
- short_description: Autonomous Engineering OS — Manus + Genspark + Devin (OneHand)
11
  ---
12
 
13
- # 🤖 GOD AGENT OS v7
14
  **Autonomous Engineering Operating System**
15
- *Manus + Genspark + Devin (OneHand) — Combined*
16
 
17
  [![GitHub](https://img.shields.io/badge/GitHub-god--agent--os-blue?logo=github)](https://github.com/pyaesonegtckglay-dotcom/god-agent-os)
18
- [![Version](https://img.shields.io/badge/version-7.0.0-indigo)](https://github.com/pyaesonegtckglay-dotcom/god-agent-os)
 
19
 
20
- ## 🚀 What is God Agent OS?
21
 
22
- God Agent OS is a fully autonomous AI engineering platform that combines:
23
- - **Manus** — Deep reasoning, multi-step planning, autonomous orchestration
24
- - **Genspark** — Repository-scale code generation, multi-model AI routing
25
- - **Devin/OneHand** Self-healing code execution, browser control, file mastery
 
26
 
27
- ## 🤖 16-Agent Fleet (v7 NEW!)
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  | Agent | Capability | Status |
30
  |-------|-----------|--------|
@@ -32,52 +47,61 @@ God Agent OS is a fully autonomous AI engineering platform that combines:
32
  | 📋 Planner | Task decomposition & planning | Core |
33
  | 💻 Coding | Production code generation | Core |
34
  | 🐛 Debug | Self-healing error resolution | Core |
35
- | 🌐 **Browser** | Web research & scraping | ⭐ NEW v7 |
36
- | 📁 **File** | File system & project scaffold | ⭐ NEW v7 |
37
- | 🔀 **Git** | Git ops & GitHub PR creation | ⭐ NEW v7 |
38
- | 🧪 **Test** | Auto test generation & execution | ⭐ NEW v7 |
39
- | 🎨 **Vision** | Design-to-code UI generation | ⭐ NEW v7 |
40
  | 🖥️ Sandbox | Isolated code execution | Core |
41
  | 🚀 Deploy | Auto-deploy to cloud | Core |
42
  | 🔌 Connector | External integrations | Core |
43
  | 🧠 Memory | Long-term context | Core |
44
  | ⚙️ Workflow | n8n automation | Core |
 
 
45
 
46
- ## 🔑 Required API Keys
47
 
48
- Set these in Space Settings → Variables and Secrets:
49
 
50
- | Variable | Description | Required |
51
- |----------|-------------|----------|
 
 
 
52
  | `OPENAI_API_KEY` | GPT-4o | Optional |
53
- | `GROQ_API_KEY` | Llama 3.3 70B (Free!) | Recommended |
54
- | `OPENROUTER_API_KEY` | 100+ models | Optional |
55
  | `ANTHROPIC_API_KEY` | Claude 3.5 | Optional |
56
- | `GITHUB_TOKEN` | Git operations | Optional |
57
-
58
- > **Note:** System works in demo mode without any keys. Add at least `GROQ_API_KEY` for full AI power (it's free!).
59
 
60
  ## 🌐 API Documentation
61
 
62
  - Interactive docs: `/api/docs`
63
  - Health check: `/health`
 
 
64
 
65
  ## 📦 Architecture
66
 
67
  ```
68
  god-agent-os/
69
- ├── backend/ # FastAPI backend (16 agents)
70
- │ ├─ agents/ # All 16 specialized agents
71
- │ ├── ai_router/ # Multi-model AI router (5 providers)
72
- │ ├── api/ # REST + WebSocket endpoints
73
- │ ├── core/ # Task engine & models
74
- ── memory/ # SQLite persistent memory
75
- ── connectors/ # External service connectors
76
- ── frontend/ # Next.js 14 UI (deployed on Vercel)
 
 
 
 
 
 
 
 
77
  ```
78
 
79
  ## 🔄 Auto-Deploy Pipeline
80
 
81
  GitHub Push → Build Check → HF Space Deploy + Vercel Deploy
82
-
83
- All automatic via GitHub Actions!
 
1
  ---
2
+ title: God Agent OS v8
3
  emoji: 🤖
4
  colorFrom: indigo
5
  colorTo: purple
 
7
  app_port: 7860
8
  pinned: true
9
  license: mit
10
+ short_description: Autonomous Engineering OS v8 KeyPool Multi-API (Gemini + SambaNova)
11
  ---
12
 
13
+ # 🤖 GOD AGENT OS v8
14
  **Autonomous Engineering Operating System**
15
+ *Manus + Genspark + Devin (OneHand) — KeyPool Multi-API Edition*
16
 
17
  [![GitHub](https://img.shields.io/badge/GitHub-god--agent--os-blue?logo=github)](https://github.com/pyaesonegtckglay-dotcom/god-agent-os)
18
+ [![Version](https://img.shields.io/badge/version-8.0.0-indigo)](https://github.com/pyaesonegtckglay-dotcom/god-agent-os)
19
+ [![HF Space](https://img.shields.io/badge/HF%20Space-PYAE1994-orange)](https://huggingface.co/spaces/PYAE1994/autonomous-coding-system)
20
 
21
+ ## 🚀 What is God Agent OS v8?
22
 
23
+ God Agent OS v8 is a fully autonomous AI engineering platform with **KeyPool Multi-API Routing**:
24
+ - **Gemini** (6 keys) Google Gemini 1.5 Flash primary LLM
25
+ - **SambaNova** (9 keys) Meta Llama 3.3 70B primary LLM
26
+ - **GitHub API** (9 keys) Pooled Git operations
27
+ - **Automatic failover** across 7 providers
28
 
29
+ ## 🔑 v8 KeyPool System
30
+
31
+ ```
32
+ Priority Chain:
33
+ SambaNova (9 keys) → Gemini (6 keys) → OpenAI → Groq → Cerebras → OpenRouter → Anthropic
34
+
35
+ Each key pool:
36
+ - Round-robin key selection
37
+ - Failure tracking per key
38
+ - Automatic cooldown (60s after 3 failures)
39
+ - Real-time status dashboard in UI
40
+ ```
41
+
42
+ ## 🤖 16-Agent Fleet
43
 
44
  | Agent | Capability | Status |
45
  |-------|-----------|--------|
 
47
  | 📋 Planner | Task decomposition & planning | Core |
48
  | 💻 Coding | Production code generation | Core |
49
  | 🐛 Debug | Self-healing error resolution | Core |
50
+ | 🌐 Browser | Web research & scraping | v7 |
51
+ | 📁 File | File system & project scaffold | v7 |
52
+ | 🔀 Git | Git ops & GitHub PR creation | v7 |
53
+ | 🧪 Test | Auto test generation & execution | v7 |
54
+ | 🎨 Vision | Design-to-code UI generation | v7 |
55
  | 🖥️ Sandbox | Isolated code execution | Core |
56
  | 🚀 Deploy | Auto-deploy to cloud | Core |
57
  | 🔌 Connector | External integrations | Core |
58
  | 🧠 Memory | Long-term context | Core |
59
  | ⚙️ Workflow | n8n automation | Core |
60
+ | 🔍 Reasoning | Deep reasoning & analysis | Core |
61
+ | 🎨 UI | Real-time UI state | Core |
62
 
63
+ ## 🔑 API Keys Configuration
64
 
65
+ Set these in Hugging Face Space Settings → Variables:
66
 
67
+ | Variable | Description | Keys |
68
+ |----------|-------------|------|
69
+ | `GEMINI_API_KEYS` | Google Gemini (comma-separated) | 6 keys |
70
+ | `SAMBANOVA_API_KEYS` | SambaNova (comma-separated) | 9 keys |
71
+ | `GITHUB_API_KEYS` | GitHub API (comma-separated) | 9 keys |
72
  | `OPENAI_API_KEY` | GPT-4o | Optional |
73
+ | `GROQ_API_KEY` | Llama 3.3 70B (Free) | Optional |
 
74
  | `ANTHROPIC_API_KEY` | Claude 3.5 | Optional |
 
 
 
75
 
76
  ## 🌐 API Documentation
77
 
78
  - Interactive docs: `/api/docs`
79
  - Health check: `/health`
80
+ - AI Router stats: `/api/v1/ai/stats`
81
+ - Key pool status: `/api/v1/ai/pool-status`
82
 
83
  ## 📦 Architecture
84
 
85
  ```
86
  god-agent-os/
87
+ ├── backend/
88
+ │ ├─��� agents/ # 16 specialized agents
89
+ │ ├── ai_router/
90
+ ├── key_pool.py # KeyPool multi-key manager (NEW v8)
91
+ ├── router_v8.py # AIRouterV8 with KeyPool (NEW v8)
92
+ │ └── router.py # Legacy router (retained)
93
+ ── api/ # REST + WebSocket endpoints
94
+ │ ├── core/ # Task engine & models
95
+ │ ├── memory/ # SQLite persistent memory
96
+ │ ├── connectors/ # External service connectors
97
+ │ ├── main_v8.py # v8 Entry point (NEW)
98
+ │ └── Dockerfile.hf # HF Spaces Docker
99
+ └── frontend/ # Next.js 14 UI
100
+ └── components/
101
+ └── layout/
102
+ └── AIRouterPanel.tsx # v8 Key pool status UI (NEW)
103
  ```
104
 
105
  ## 🔄 Auto-Deploy Pipeline
106
 
107
  GitHub Push → Build Check → HF Space Deploy + Vercel Deploy
 
 
backend/Dockerfile.hf CHANGED
@@ -22,6 +22,16 @@ ENV PORT=7860
22
  ENV WORKSPACE_DIR=/tmp/god_workspace
23
  ENV PYTHONPATH=/app
24
 
 
 
 
 
 
 
 
 
 
 
25
  EXPOSE 7860
26
 
27
- CMD ["uvicorn", "main_v7:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
 
22
  ENV WORKSPACE_DIR=/tmp/god_workspace
23
  ENV PYTHONPATH=/app
24
 
25
+ # API Keys are configured via HF Space Secrets (Settings → Variables and Secrets)
26
+ # Set these in your HF Space:
27
+ # GEMINI_API_KEYS — comma-separated Gemini API keys
28
+ # SAMBANOVA_API_KEYS — comma-separated SambaNova API keys
29
+ # GITHUB_API_KEYS — comma-separated GitHub tokens
30
+ # GITHUB_TOKEN — primary GitHub token
31
+ # OPENAI_API_KEY — OpenAI API key (optional)
32
+ # GROQ_API_KEY — Groq API key (optional, free)
33
+ # ANTHROPIC_API_KEY — Anthropic API key (optional)
34
+
35
  EXPOSE 7860
36
 
37
+ CMD ["uvicorn", "main_v8:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
backend/__pycache__/main.cpython-312.pyc DELETED
Binary file (9.42 kB)
 
backend/agents/debug_agent.py CHANGED
@@ -44,12 +44,12 @@ class DebugAgent(BaseAgent):
44
  messages = [
45
  {"role": "system", "content": DEBUG_SYSTEM},
46
  {"role": "user", "content": (
47
- f"Debug and fix this issue (attempt {attempt}):\n\n"
48
- f"{task}\n\n"
49
- f"Provide:\n"
50
- f"1. Root cause analysis\n"
51
- f"2. Exact fix (code/config)\n"
52
- f"3. Prevention strategy"
53
  )},
54
  ]
55
 
@@ -71,14 +71,19 @@ class DebugAgent(BaseAgent):
71
 
72
  async def analyze_error(self, error_output: str, source_code: str = "", task_id: str = "", session_id: str = "") -> Dict:
73
  """Deep error analysis with structured output."""
 
 
 
 
 
74
  messages = [
75
  {"role": "system", "content": DEBUG_SYSTEM},
76
  {"role": "user", "content": (
77
- f"Analyze this error and provide structured diagnosis:\n\n"
78
- f"Error:\n{error_output[:2000]}\n\n"
79
- f"{'Source Code:\\n```\\n' + source_code[:1000] + '\\n```' if source_code else ''}\n\n"
80
- f"Respond with JSON:\n"
81
- f'{{"error_type": "...", "root_cause": "...", "fix": "...", "prevention": "...", "severity": "low|medium|high|critical"}}'
82
  )},
83
  ]
84
  raw = await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.1, max_tokens=1000)
@@ -111,10 +116,10 @@ class DebugAgent(BaseAgent):
111
  messages = [
112
  {"role": "system", "content": DEBUG_SYSTEM},
113
  {"role": "user", "content": (
114
- f"Fix attempt {attempt}/{max_retries}:\n\n"
115
- f"Error: {current_error}\n\n"
116
- f"Code:\n```\n{current_code[:3000]}\n```\n\n"
117
- f"Return ONLY the fixed code."
118
  )},
119
  ]
120
 
@@ -143,7 +148,7 @@ class DebugAgent(BaseAgent):
143
  compile(code, "<string>", "exec")
144
  return {"valid": True, "error": ""}
145
  except SyntaxError as e:
146
- return {"valid": False, "error": f"SyntaxError: {e}"}
147
  except Exception as e:
148
  return {"valid": False, "error": str(e)}
149
 
 
44
  messages = [
45
  {"role": "system", "content": DEBUG_SYSTEM},
46
  {"role": "user", "content": (
47
+ "Debug and fix this issue (attempt " + str(attempt) + "):\n\n"
48
+ + task + "\n\n"
49
+ "Provide:\n"
50
+ "1. Root cause analysis\n"
51
+ "2. Exact fix (code/config)\n"
52
+ "3. Prevention strategy"
53
  )},
54
  ]
55
 
 
71
 
72
  async def analyze_error(self, error_output: str, source_code: str = "", task_id: str = "", session_id: str = "") -> Dict:
73
  """Deep error analysis with structured output."""
74
+ if source_code:
75
+ source_section = "Source Code:\n```\n" + source_code[:1000] + "\n```"
76
+ else:
77
+ source_section = ""
78
+
79
  messages = [
80
  {"role": "system", "content": DEBUG_SYSTEM},
81
  {"role": "user", "content": (
82
+ "Analyze this error and provide structured diagnosis:\n\n"
83
+ "Error:\n" + error_output[:2000] + "\n\n"
84
+ + source_section + "\n\n"
85
+ "Respond with JSON:\n"
86
+ '{"error_type": "...", "root_cause": "...", "fix": "...", "prevention": "...", "severity": "low|medium|high|critical"}'
87
  )},
88
  ]
89
  raw = await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.1, max_tokens=1000)
 
116
  messages = [
117
  {"role": "system", "content": DEBUG_SYSTEM},
118
  {"role": "user", "content": (
119
+ "Fix attempt " + str(attempt) + "/" + str(max_retries) + ":\n\n"
120
+ "Error: " + current_error + "\n\n"
121
+ "Code:\n```\n" + current_code[:3000] + "\n```\n\n"
122
+ "Return ONLY the fixed code."
123
  )},
124
  ]
125
 
 
148
  compile(code, "<string>", "exec")
149
  return {"valid": True, "error": ""}
150
  except SyntaxError as e:
151
+ return {"valid": False, "error": "SyntaxError: " + str(e)}
152
  except Exception as e:
153
  return {"valid": False, "error": str(e)}
154
 
backend/agents/reasoning_agent.py CHANGED
@@ -1,24 +1,34 @@
1
  """
2
- 🚀 GOD MODE+ v3 - Reasoning Agent
3
- Specialized agent for complex reasoning tasks using DeepSeek R1, Qwen QwQ, o1-mini
4
- Version: 3.0.0
5
  """
6
 
7
  import asyncio
8
  import json
9
- from typing import Dict, Any, Optional
10
 
11
  import structlog
12
 
13
- from core.agent import BaseAgent
14
 
15
  log = structlog.get_logger()
16
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  class ReasoningAgent(BaseAgent):
19
  """
20
  Specialized agent for complex reasoning, analysis, and problem-solving tasks.
21
-
22
  Capabilities:
23
  - Multi-step reasoning with chain-of-thought
24
  - Complex problem decomposition
@@ -27,259 +37,127 @@ class ReasoningAgent(BaseAgent):
27
  - Strategic planning
28
  """
29
 
30
- def __init__(self, ws_manager, ai_router):
31
- """Initialize Reasoning Agent."""
32
- super().__init__(
33
- name="ReasoningAgent",
34
- color="🟦",
35
- description="Complex reasoning and analysis",
36
- ws_manager=ws_manager,
37
- ai_router=ai_router,
38
- )
39
- self.reasoning_depth = 3 # Number of reasoning steps
40
  self.max_reasoning_tokens = 16000
41
 
42
- async def process(self, task: Dict[str, Any]) -> Dict[str, Any]:
43
- """
44
- Process reasoning task with multi-step reasoning.
45
- """
46
- user_message = task.get("content", "")
47
- session_id = task.get("session_id", "")
48
- context = task.get("context", {})
49
 
50
- log.info("🧠 Reasoning Agent activated", message=user_message[:100])
 
 
 
51
 
52
  try:
53
  # Step 1: Analyze the problem
54
- analysis = await self._analyze_problem(user_message, context)
55
- await self._broadcast(session_id, {
56
- "type": "reasoning_step",
57
- "step": "analysis",
58
- "data": analysis,
59
- })
60
-
61
- # Step 2: Break down into sub-problems
62
- sub_problems = await self._decompose_problem(user_message, analysis)
63
- await self._broadcast(session_id, {
64
- "type": "reasoning_step",
65
- "step": "decomposition",
66
- "data": sub_problems,
67
- })
68
-
69
- # Step 3: Solve each sub-problem
70
- solutions = []
71
- for i, sub_problem in enumerate(sub_problems):
72
- solution = await self._solve_sub_problem(sub_problem, context)
73
- solutions.append(solution)
74
- await self._broadcast(session_id, {
75
- "type": "reasoning_step",
76
- "step": f"solution_{i+1}",
77
- "data": solution,
78
- })
79
-
80
- # Step 4: Synthesize final answer
81
- final_answer = await self._synthesize_answer(
82
- user_message,
83
- analysis,
84
- sub_problems,
85
- solutions
86
- )
87
-
88
- await self._broadcast(session_id, {
89
- "type": "reasoning_complete",
90
- "answer": final_answer,
91
  "reasoning_depth": self.reasoning_depth,
92
- })
93
 
94
- return {
95
- "success": True,
96
- "agent": self.name,
97
- "answer": final_answer,
98
- "reasoning_steps": {
99
- "analysis": analysis,
100
- "sub_problems": sub_problems,
101
- "solutions": solutions,
102
- },
103
- }
104
 
105
  except Exception as e:
106
- log.error(" Reasoning Agent failed", error=str(e))
107
- return {
108
- "success": False,
109
- "agent": self.name,
110
- "error": str(e),
111
- }
112
-
113
- async def _analyze_problem(self, problem: str, context: Dict[str, Any]) -> Dict[str, Any]:
114
- """
115
- Analyze the problem using reasoning model.
116
- """
117
- prompt = f"""Analyze this problem and identify:
118
- 1. Core problem statement
119
- 2. Key constraints
120
- 3. Required information
121
- 4. Potential approaches
122
-
123
- Problem: {problem}
124
-
125
- Provide structured analysis."""
126
-
127
- response = await self.ai_router.route(
128
- prompt,
129
- context={"task_type": "reasoning"},
130
- optimize_for="quality"
131
- )
132
-
133
- return {
134
- "problem_type": self._classify_problem(problem),
135
- "complexity": self._estimate_complexity(problem),
136
- "analysis": response.get("response", ""),
137
- }
138
-
139
- async def _decompose_problem(
140
- self,
141
- problem: str,
142
- analysis: Dict[str, Any]
143
- ) -> list:
144
- """
145
- Break down complex problem into manageable sub-problems.
146
- """
147
- prompt = f"""Based on this analysis, break down the problem into 3-5 specific sub-problems:
148
-
149
- Problem: {problem}
150
- Analysis: {json.dumps(analysis, indent=2)}
151
-
152
- List each sub-problem clearly and explain the dependencies."""
153
-
154
- response = await self.ai_router.route(
155
- prompt,
156
- context={"task_type": "reasoning"},
157
- optimize_for="quality"
158
  )
159
 
160
- # Parse sub-problems from response
161
- sub_problems = self._parse_sub_problems(response.get("response", ""))
162
- return sub_problems
163
-
164
- async def _solve_sub_problem(
165
- self,
166
- sub_problem: str,
167
- context: Dict[str, Any]
168
- ) -> Dict[str, Any]:
169
- """
170
- Solve individual sub-problem.
171
- """
172
- prompt = f"""Solve this sub-problem step by step:
173
-
174
- {sub_problem}
175
-
176
- Provide:
177
- 1. Step-by-step solution
178
- 2. Key insights
179
- 3. Confidence level (0-100)"""
180
-
181
- response = await self.ai_router.route(
182
- prompt,
183
- context={"task_type": "reasoning"},
184
- optimize_for="quality"
185
- )
186
 
187
- return {
188
- "sub_problem": sub_problem,
189
- "solution": response.get("response", ""),
190
- "model_used": response.get("model", "unknown"),
191
- }
 
 
192
 
193
  async def _synthesize_answer(
194
  self,
195
- original_problem: str,
196
- analysis: Dict[str, Any],
197
- sub_problems: list,
198
- solutions: list
 
 
199
  ) -> str:
200
- """
201
- Synthesize final answer from all reasoning steps.
202
- """
203
- synthesis_prompt = f"""Based on the analysis and solutions, provide a comprehensive answer:
204
-
205
- Original Problem: {original_problem}
206
-
207
- Analysis: {json.dumps(analysis, indent=2)}
208
-
209
- Solutions:
210
- {json.dumps(solutions, indent=2)}
211
-
212
- Provide a clear, well-reasoned final answer that:
213
- 1. Directly addresses the original problem
214
- 2. Integrates insights from all sub-problems
215
- 3. Explains the reasoning clearly
216
- 4. Suggests any follow-up actions if needed"""
217
-
218
- response = await self.ai_router.route(
219
- synthesis_prompt,
220
- context={"task_type": "reasoning"},
221
- optimize_for="quality"
222
  )
223
-
224
- return response.get("response", "Unable to synthesize answer")
225
-
226
- def _classify_problem(self, problem: str) -> str:
227
- """Classify problem type."""
228
- problem_lower = problem.lower()
229
-
230
- if any(word in problem_lower for word in ["math", "calculate", "equation"]):
231
- return "mathematical"
232
- elif any(word in problem_lower for word in ["logic", "reason", "why"]):
233
- return "logical"
234
- elif any(word in problem_lower for word in ["plan", "strategy", "approach"]):
235
- return "strategic"
236
- elif any(word in problem_lower for word in ["analyze", "compare", "evaluate"]):
237
- return "analytical"
238
- else:
239
- return "general"
240
-
241
- def _estimate_complexity(self, problem: str) -> str:
242
- """Estimate problem complexity."""
243
- word_count = len(problem.split())
244
-
245
- if word_count < 20:
246
- return "simple"
247
- elif word_count < 100:
248
- return "moderate"
249
- else:
250
- return "complex"
251
-
252
- def _parse_sub_problems(self, response: str) -> list:
253
- """Parse sub-problems from model response."""
254
- # Simple parsing - can be enhanced
255
- lines = response.split("\n")
256
- sub_problems = []
257
-
258
- for line in lines:
259
- line = line.strip()
260
- if line and any(line.startswith(f"{i}.") for i in range(1, 10)):
261
- sub_problems.append(line)
262
-
263
- return sub_problems if sub_problems else [response]
264
-
265
- async def _broadcast(self, session_id: str, data: Dict[str, Any]):
266
- """Broadcast reasoning progress to client."""
267
- if self.ws_manager:
268
- await self.ws_manager.broadcast(
269
- room=f"chat:{session_id}",
270
- message={
271
- "type": "agent_message",
272
- "agent": self.name,
273
- "color": self.color,
274
- **data,
275
- }
276
- )
277
 
278
  def get_status(self) -> Dict[str, Any]:
279
  """Get agent status."""
280
  return {
281
  "name": self.name,
282
- "color": self.color,
283
  "status": "ready",
284
  "capabilities": [
285
  "Multi-step reasoning",
@@ -289,7 +167,6 @@ Provide a clear, well-reasoned final answer that:
289
  "Strategic planning",
290
  ],
291
  "reasoning_depth": self.reasoning_depth,
292
- "max_reasoning_tokens": self.max_reasoning_tokens,
293
  }
294
 
295
 
 
1
  """
2
+ ReasoningAgent v7 Complex reasoning, analysis, and multi-step problem solving
3
+ GOD AGENT OS Using DeepSeek R1, Qwen QwQ, o1-mini style reasoning
 
4
  """
5
 
6
  import asyncio
7
  import json
8
+ from typing import Dict, Any, List, Optional
9
 
10
  import structlog
11
 
12
+ from .base_agent import BaseAgent
13
 
14
  log = structlog.get_logger()
15
 
16
+ REASONING_SYSTEM = """You are an elite autonomous reasoning and analysis agent.
17
+ You excel at:
18
+ - Multi-step reasoning with chain-of-thought
19
+ - Complex problem decomposition and analysis
20
+ - Mathematical and logical reasoning
21
+ - Strategic planning and decision making
22
+ - Root cause analysis
23
+
24
+ Always think step by step, show your reasoning, and provide confident conclusions.
25
+ """
26
+
27
 
28
  class ReasoningAgent(BaseAgent):
29
  """
30
  Specialized agent for complex reasoning, analysis, and problem-solving tasks.
31
+
32
  Capabilities:
33
  - Multi-step reasoning with chain-of-thought
34
  - Complex problem decomposition
 
37
  - Strategic planning
38
  """
39
 
40
+ def __init__(self, ws_manager=None, ai_router=None):
41
+ super().__init__("ReasoningAgent", ws_manager, ai_router)
42
+ self.reasoning_depth = 3
 
 
 
 
 
 
 
43
  self.max_reasoning_tokens = 16000
44
 
45
+ async def run(self, task: str, context: Dict = {}, **kwargs) -> str:
46
+ """Execute reasoning task."""
47
+ session_id = kwargs.get("session_id", "")
48
+ task_id = kwargs.get("task_id", "")
 
 
 
49
 
50
+ await self.emit(task_id, "agent_start", {
51
+ "agent": "ReasoningAgent",
52
+ "task": task[:80],
53
+ }, session_id)
54
 
55
  try:
56
  # Step 1: Analyze the problem
57
+ analysis = await self._analyze_problem(task, context, task_id, session_id)
58
+
59
+ # Step 2: Decompose if complex
60
+ if len(task.split()) > 30:
61
+ sub_problems = await self._decompose_problem(task, analysis, task_id, session_id)
62
+ solutions = []
63
+ for sub in sub_problems[:3]:
64
+ sol = await self._solve_sub_problem(sub, context, task_id, session_id)
65
+ solutions.append(sol)
66
+ result = await self._synthesize_answer(task, analysis, sub_problems, solutions, task_id, session_id)
67
+ else:
68
+ result = analysis
69
+
70
+ await self.emit(task_id, "reasoning_complete", {
71
+ "agent": "ReasoningAgent",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  "reasoning_depth": self.reasoning_depth,
73
+ }, session_id)
74
 
75
+ return result
 
 
 
 
 
 
 
 
 
76
 
77
  except Exception as e:
78
+ log.error("ReasoningAgent failed", error=str(e))
79
+ return "Reasoning agent encountered an error: " + str(e)
80
+
81
+ async def _analyze_problem(self, problem: str, context: Dict, task_id: str, session_id: str) -> str:
82
+ """Analyze the problem using reasoning model."""
83
+ messages = [
84
+ {"role": "system", "content": REASONING_SYSTEM},
85
+ {"role": "user", "content": (
86
+ "Analyze this problem step by step:\n\n"
87
+ + problem + "\n\n"
88
+ "Provide:\n"
89
+ "1. Problem type and complexity\n"
90
+ "2. Key constraints and requirements\n"
91
+ "3. Step-by-step solution\n"
92
+ "4. Final answer/recommendation"
93
+ )},
94
+ ]
95
+ return await self.llm(
96
+ messages,
97
+ task_id=task_id,
98
+ session_id=session_id,
99
+ temperature=0.2,
100
+ max_tokens=self.max_reasoning_tokens,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  )
102
 
103
+ async def _decompose_problem(self, problem: str, analysis: str, task_id: str, session_id: str) -> List[str]:
104
+ """Break down complex problem into sub-problems."""
105
+ messages = [
106
+ {"role": "system", "content": REASONING_SYSTEM},
107
+ {"role": "user", "content": (
108
+ "Break this complex problem into 3 specific sub-problems:\n\n"
109
+ + problem + "\n\n"
110
+ "Initial analysis: " + analysis[:500] + "\n\n"
111
+ "List each sub-problem on a new line starting with '1.', '2.', '3.'"
112
+ )},
113
+ ]
114
+ raw = await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.3, max_tokens=2000)
115
+ # Parse numbered sub-problems
116
+ lines = raw.split("\n")
117
+ sub_problems = []
118
+ for line in lines:
119
+ line = line.strip()
120
+ if line and any(line.startswith(str(i) + ".") for i in range(1, 10)):
121
+ sub_problems.append(line)
122
+ return sub_problems if sub_problems else [problem]
 
 
 
 
 
 
123
 
124
+ async def _solve_sub_problem(self, sub_problem: str, context: Dict, task_id: str, session_id: str) -> str:
125
+ """Solve individual sub-problem."""
126
+ messages = [
127
+ {"role": "system", "content": REASONING_SYSTEM},
128
+ {"role": "user", "content": "Solve this specific problem:\n\n" + sub_problem},
129
+ ]
130
+ return await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.2, max_tokens=4096)
131
 
132
  async def _synthesize_answer(
133
  self,
134
+ original: str,
135
+ analysis: str,
136
+ sub_problems: List[str],
137
+ solutions: List[str],
138
+ task_id: str,
139
+ session_id: str,
140
  ) -> str:
141
+ """Synthesize final answer from all reasoning steps."""
142
+ solutions_text = "\n".join(
143
+ "Sub-problem " + str(i + 1) + ": " + sol[:300]
144
+ for i, sol in enumerate(solutions)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  )
146
+ messages = [
147
+ {"role": "system", "content": REASONING_SYSTEM},
148
+ {"role": "user", "content": (
149
+ "Original problem: " + original + "\n\n"
150
+ "Analysis: " + analysis[:800] + "\n\n"
151
+ "Solutions to sub-problems:\n" + solutions_text + "\n\n"
152
+ "Provide a comprehensive final answer that integrates all insights."
153
+ )},
154
+ ]
155
+ return await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.3, max_tokens=8192)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
  def get_status(self) -> Dict[str, Any]:
158
  """Get agent status."""
159
  return {
160
  "name": self.name,
 
161
  "status": "ready",
162
  "capabilities": [
163
  "Multi-step reasoning",
 
167
  "Strategic planning",
168
  ],
169
  "reasoning_depth": self.reasoning_depth,
 
170
  }
171
 
172
 
backend/ai_router/__init__.py CHANGED
@@ -1,4 +1,6 @@
1
- # Multi-Model AI Router
2
  from .router import AIRouter
 
 
3
 
4
- __all__ = ["AIRouter"]
 
1
+ # Multi-Model AI Router — God Agent OS v8
2
  from .router import AIRouter
3
+ from .router_v8 import AIRouterV8
4
+ from .key_pool import KeyPool, KeyPoolRegistry
5
 
6
+ __all__ = ["AIRouter", "AIRouterV8", "KeyPool", "KeyPoolRegistry"]
backend/ai_router/key_pool.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ KeyPool — Multi-API Key Manager with Failover & Cooldown
3
+ God Agent OS v8 — Supports Gemini, SambaNova, GitHub, OpenAI, Groq, etc.
4
+ Each provider can have multiple comma-separated keys.
5
+ """
6
+
7
+ import asyncio
8
+ import time
9
+ from collections import defaultdict
10
+ from typing import Dict, List, Optional
11
+ import structlog
12
+
13
+ log = structlog.get_logger()
14
+
15
+ COOLDOWN_SECONDS = 60 # Key cooling time after max failures
16
+ MAX_FAILURES = 3 # Max fails before cooldown
17
+
18
+
19
+ class KeyEntry:
20
+ def __init__(self, key: str):
21
+ self.key = key
22
+ self.failures = 0
23
+ self.cooldown_until = 0.0
24
+ self.calls = 0
25
+ self.last_used = 0.0
26
+
27
+ def is_available(self) -> bool:
28
+ if self.cooldown_until > time.time():
29
+ return False
30
+ return True
31
+
32
+ def mark_fail(self):
33
+ self.failures += 1
34
+ if self.failures >= MAX_FAILURES:
35
+ self.cooldown_until = time.time() + COOLDOWN_SECONDS
36
+ log.warning("Key cooldown activated", failures=self.failures)
37
+
38
+ def mark_success(self):
39
+ self.failures = max(0, self.failures - 1)
40
+ self.cooldown_until = 0.0
41
+ self.calls += 1
42
+ self.last_used = time.time()
43
+
44
+ def status(self) -> dict:
45
+ remaining = max(0, self.cooldown_until - time.time())
46
+ return {
47
+ "key_preview": self.key[:8] + "..." + self.key[-4:] if len(self.key) > 12 else "***",
48
+ "available": self.is_available(),
49
+ "failures": self.failures,
50
+ "calls": self.calls,
51
+ "cooldown_remaining_s": round(remaining, 1),
52
+ }
53
+
54
+
55
+ class KeyPool:
56
+ """
57
+ Pool of API keys for a single provider.
58
+ Round-robins through available keys with failure tracking.
59
+ """
60
+
61
+ def __init__(self, provider: str, keys: List[str]):
62
+ self.provider = provider
63
+ self._keys: List[KeyEntry] = [KeyEntry(k.strip()) for k in keys if k.strip()]
64
+ self._index = 0
65
+
66
+ def __len__(self) -> int:
67
+ return len(self._keys)
68
+
69
+ def pick(self) -> Optional[str]:
70
+ """Pick the next available key (round-robin, skip cooling down keys)."""
71
+ if not self._keys:
72
+ return None
73
+ n = len(self._keys)
74
+ for _ in range(n):
75
+ entry = self._keys[self._index % n]
76
+ self._index = (self._index + 1) % n
77
+ if entry.is_available():
78
+ return entry.key
79
+ # All keys in cooldown — try the one with shortest cooldown
80
+ soonest = min(self._keys, key=lambda e: e.cooldown_until)
81
+ log.warning(
82
+ "All keys in cooldown, using soonest",
83
+ provider=self.provider,
84
+ cooldown_remaining=round(soonest.cooldown_until - time.time(), 1),
85
+ )
86
+ return soonest.key
87
+
88
+ def mark_fail(self, key: str):
89
+ for e in self._keys:
90
+ if e.key == key:
91
+ e.mark_fail()
92
+ return
93
+
94
+ def mark_success(self, key: str):
95
+ for e in self._keys:
96
+ if e.key == key:
97
+ e.mark_success()
98
+ return
99
+
100
+ def available_count(self) -> int:
101
+ return sum(1 for e in self._keys if e.is_available())
102
+
103
+ def status(self) -> dict:
104
+ return {
105
+ "provider": self.provider,
106
+ "total_keys": len(self._keys),
107
+ "available_keys": self.available_count(),
108
+ "keys": [e.status() for e in self._keys],
109
+ }
110
+
111
+
112
+ # ─── Global Key Pool Registry ─────────────────────────────────────────────────
113
+
114
+ class KeyPoolRegistry:
115
+ """Central registry for all provider key pools."""
116
+
117
+ def __init__(self):
118
+ self._pools: Dict[str, KeyPool] = {}
119
+
120
+ def register(self, provider: str, keys_csv: str):
121
+ """Register comma-separated keys for a provider."""
122
+ keys = [k.strip() for k in keys_csv.split(",") if k.strip()]
123
+ if keys:
124
+ self._pools[provider] = KeyPool(provider, keys)
125
+ log.info("KeyPool registered", provider=provider, count=len(keys))
126
+
127
+ def get(self, provider: str) -> Optional[KeyPool]:
128
+ return self._pools.get(provider)
129
+
130
+ def all_status(self) -> dict:
131
+ return {name: pool.status() for name, pool in self._pools.items()}
backend/ai_router/router_v8.py ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ AIRouter v8 — God Agent OS
3
+ Multi-provider AI router with KeyPool failover.
4
+ Supports: Gemini, SambaNova, OpenAI, Groq, Cerebras, OpenRouter, Anthropic
5
+ Primary LLMs: Gemini (6 keys) + SambaNova (9 keys) — fully pooled
6
+ """
7
+
8
+ import asyncio
9
+ import json
10
+ import os
11
+ import time
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ import httpx
15
+ import structlog
16
+
17
+ from ai_router.key_pool import KeyPoolRegistry
18
+
19
+ log = structlog.get_logger()
20
+
21
+ # ─── Provider Definitions ─────────────────────────────────────────────────────
22
+
23
+ PROVIDER_CONFIG = [
24
+ # Priority 1 — SambaNova (fast, free tier)
25
+ {
26
+ "name": "sambanova",
27
+ "key_env": "SAMBANOVA_API_KEYS",
28
+ "base_url": "https://api.sambanova.ai/v1",
29
+ "default_model": "Meta-Llama-3.3-70B-Instruct",
30
+ "type": "openai_compat",
31
+ "max_tokens": 4096,
32
+ "priority": 1,
33
+ },
34
+ # Priority 2 — Gemini (Google AI)
35
+ {
36
+ "name": "gemini",
37
+ "key_env": "GEMINI_API_KEYS",
38
+ "base_url": "https://generativelanguage.googleapis.com",
39
+ "default_model": "gemini-1.5-flash",
40
+ "type": "gemini",
41
+ "max_tokens": 8192,
42
+ "priority": 2,
43
+ },
44
+ # Priority 3 — OpenAI
45
+ {
46
+ "name": "openai",
47
+ "key_env": "OPENAI_API_KEY",
48
+ "base_url": os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1"),
49
+ "default_model": os.environ.get("DEFAULT_MODEL", "gpt-4o"),
50
+ "type": "openai_compat",
51
+ "max_tokens": 4096,
52
+ "priority": 3,
53
+ },
54
+ # Priority 4 — Groq
55
+ {
56
+ "name": "groq",
57
+ "key_env": "GROQ_API_KEY",
58
+ "base_url": "https://api.groq.com/openai/v1",
59
+ "default_model": "llama-3.3-70b-versatile",
60
+ "type": "openai_compat",
61
+ "max_tokens": 4096,
62
+ "priority": 4,
63
+ },
64
+ # Priority 5 — Cerebras
65
+ {
66
+ "name": "cerebras",
67
+ "key_env": "CEREBRAS_API_KEY",
68
+ "base_url": "https://api.cerebras.ai/v1",
69
+ "default_model": "llama3.1-70b",
70
+ "type": "openai_compat",
71
+ "max_tokens": 4096,
72
+ "priority": 5,
73
+ },
74
+ # Priority 6 — OpenRouter
75
+ {
76
+ "name": "openrouter",
77
+ "key_env": "OPENROUTER_API_KEY",
78
+ "base_url": "https://openrouter.ai/api/v1",
79
+ "default_model": "meta-llama/llama-3.3-70b-instruct:free",
80
+ "type": "openai_compat",
81
+ "max_tokens": 4096,
82
+ "priority": 6,
83
+ },
84
+ # Priority 7 — Anthropic
85
+ {
86
+ "name": "anthropic",
87
+ "key_env": "ANTHROPIC_API_KEY",
88
+ "base_url": "https://api.anthropic.com/v1",
89
+ "default_model": "claude-3-5-sonnet-20241022",
90
+ "type": "anthropic",
91
+ "max_tokens": 4096,
92
+ "priority": 7,
93
+ },
94
+ ]
95
+
96
+
97
+ class AIRouterV8:
98
+ """
99
+ God Agent OS v8 AI Router.
100
+ - KeyPool-based multi-key management per provider
101
+ - Gemini + SambaNova as primary LLMs
102
+ - Full failover chain
103
+ - Streaming support via WebSocket
104
+ """
105
+
106
+ def __init__(self, ws_manager=None):
107
+ self.ws = ws_manager
108
+ self._registry = KeyPoolRegistry()
109
+ self._stats: Dict[str, Dict] = {}
110
+ self._setup_pools()
111
+
112
+ def _setup_pools(self):
113
+ """Initialize key pools from environment variables."""
114
+ for cfg in PROVIDER_CONFIG:
115
+ env_val = os.environ.get(cfg["key_env"], "")
116
+ if env_val:
117
+ self._registry.register(cfg["name"], env_val)
118
+ self._stats[cfg["name"]] = {"calls": 0, "errors": 0, "latency": []}
119
+ elif cfg["name"] not in self._stats:
120
+ self._stats[cfg["name"]] = {"calls": 0, "errors": 0, "latency": []}
121
+
122
+ def _get_available_providers(self) -> List[Dict]:
123
+ """Return providers with at least one available key, sorted by priority."""
124
+ available = []
125
+ for cfg in sorted(PROVIDER_CONFIG, key=lambda x: x["priority"]):
126
+ pool = self._registry.get(cfg["name"])
127
+ # Also check single-key env vars (for backward compat)
128
+ env_val = os.environ.get(cfg["key_env"], "")
129
+ if (pool and pool.available_count() > 0) or (env_val and not pool):
130
+ # Register single keys on-the-fly if not pooled
131
+ if not pool and env_val:
132
+ self._registry.register(cfg["name"], env_val)
133
+ if cfg["name"] not in self._stats:
134
+ self._stats[cfg["name"]] = {"calls": 0, "errors": 0, "latency": []}
135
+ available.append(cfg)
136
+ return available
137
+
138
+ # ─── Main Entry Point ──────────────────────────────────────────────────────
139
+
140
+ async def complete(
141
+ self,
142
+ messages: List[Dict],
143
+ task_id: str = "",
144
+ session_id: str = "",
145
+ temperature: float = 0.7,
146
+ max_tokens: int = 4096,
147
+ preferred_model: str = "",
148
+ stream: bool = True,
149
+ ) -> str:
150
+ """Route request through available providers with KeyPool failover."""
151
+ providers = self._get_available_providers()
152
+
153
+ if not providers:
154
+ return await self._demo_stream(messages, task_id, session_id)
155
+
156
+ last_error = None
157
+ for cfg in providers:
158
+ pool = self._registry.get(cfg["name"])
159
+ if not pool:
160
+ continue
161
+
162
+ key = pool.pick()
163
+ if not key:
164
+ continue
165
+
166
+ try:
167
+ start = time.time()
168
+ result = await self._call_provider(
169
+ cfg, key, messages, task_id, session_id,
170
+ temperature, max_tokens, preferred_model
171
+ )
172
+ elapsed = time.time() - start
173
+ pool.mark_success(key)
174
+ self._stats[cfg["name"]]["calls"] += 1
175
+ self._stats[cfg["name"]]["latency"].append(elapsed)
176
+ log.info("AIRouter v8 success", provider=cfg["name"], ms=round(elapsed * 1000))
177
+ return result
178
+ except Exception as e:
179
+ last_error = e
180
+ pool.mark_fail(key)
181
+ self._stats[cfg["name"]]["errors"] += 1
182
+ log.warning("AIRouter v8 failover", provider=cfg["name"], error=str(e)[:200])
183
+ continue
184
+
185
+ log.error("All AI providers failed", error=str(last_error))
186
+ return await self._demo_stream(messages, task_id, session_id)
187
+
188
+ async def _call_provider(
189
+ self, cfg: Dict, key: str, messages: List[Dict],
190
+ task_id: str, session_id: str, temperature: float,
191
+ max_tokens: int, preferred_model: str
192
+ ) -> str:
193
+ """Dispatch to the correct call method based on provider type."""
194
+ ptype = cfg["type"]
195
+ if ptype == "gemini":
196
+ return await self._gemini_call(cfg, key, messages, task_id, session_id, temperature, max_tokens, preferred_model)
197
+ elif ptype == "anthropic":
198
+ return await self._anthropic_call(cfg, key, messages, task_id, session_id, temperature, max_tokens)
199
+ else:
200
+ return await self._openai_compat_call(cfg, key, messages, task_id, session_id, temperature, max_tokens, preferred_model)
201
+
202
+ # ─── Gemini API ────────────────────────────────────────────────────────────
203
+
204
+ async def _gemini_call(
205
+ self, cfg: Dict, key: str, messages: List[Dict],
206
+ task_id: str, session_id: str, temperature: float,
207
+ max_tokens: int, preferred_model: str
208
+ ) -> str:
209
+ model = preferred_model or cfg["default_model"]
210
+ url = f"{cfg['base_url']}/v1beta/models/{model}:streamGenerateContent?key={key}&alt=sse"
211
+
212
+ # Convert messages to Gemini format
213
+ system_instruction = None
214
+ contents = []
215
+ for m in messages:
216
+ if m["role"] == "system":
217
+ system_instruction = {"parts": [{"text": m["content"]}]}
218
+ else:
219
+ role = "user" if m["role"] == "user" else "model"
220
+ contents.append({"role": role, "parts": [{"text": m["content"]}]})
221
+
222
+ payload: Dict[str, Any] = {
223
+ "contents": contents,
224
+ "generationConfig": {
225
+ "temperature": temperature,
226
+ "maxOutputTokens": max_tokens,
227
+ },
228
+ }
229
+ if system_instruction:
230
+ payload["systemInstruction"] = system_instruction
231
+
232
+ full_text = ""
233
+ async with httpx.AsyncClient(timeout=120) as client:
234
+ async with client.stream("POST", url, json=payload, headers={"Content-Type": "application/json"}) as resp:
235
+ resp.raise_for_status()
236
+ async for line in resp.aiter_lines():
237
+ if not line.startswith("data:"):
238
+ continue
239
+ chunk_str = line[5:].strip()
240
+ if not chunk_str or chunk_str == "[DONE]":
241
+ continue
242
+ try:
243
+ data = json.loads(chunk_str)
244
+ for cand in data.get("candidates", []):
245
+ for part in cand.get("content", {}).get("parts", []):
246
+ delta = part.get("text", "")
247
+ if delta:
248
+ full_text += delta
249
+ await self._emit_chunk(delta, task_id, session_id)
250
+ except Exception:
251
+ pass
252
+ return full_text
253
+
254
+ # ─── OpenAI-compatible ─────────────────────────────────────────────────────
255
+
256
+ async def _openai_compat_call(
257
+ self, cfg: Dict, key: str, messages: List[Dict],
258
+ task_id: str, session_id: str, temperature: float,
259
+ max_tokens: int, preferred_model: str
260
+ ) -> str:
261
+ model = preferred_model or cfg["default_model"]
262
+ headers = {
263
+ "Authorization": f"Bearer {key}",
264
+ "Content-Type": "application/json",
265
+ }
266
+ if cfg["name"] == "openrouter":
267
+ headers["HTTP-Referer"] = "https://god-agent.ai"
268
+ headers["X-Title"] = "God Agent OS"
269
+
270
+ payload = {
271
+ "model": model,
272
+ "messages": messages,
273
+ "stream": True,
274
+ "temperature": temperature,
275
+ "max_tokens": max_tokens,
276
+ }
277
+ full_text = ""
278
+ async with httpx.AsyncClient(timeout=120) as client:
279
+ async with client.stream(
280
+ "POST", f"{cfg['base_url']}/chat/completions",
281
+ headers=headers, json=payload
282
+ ) as resp:
283
+ resp.raise_for_status()
284
+ async for line in resp.aiter_lines():
285
+ if not line.startswith("data:"):
286
+ continue
287
+ chunk = line[6:].strip()
288
+ if chunk == "[DONE]":
289
+ break
290
+ try:
291
+ data = json.loads(chunk)
292
+ delta = data["choices"][0]["delta"].get("content", "")
293
+ if delta:
294
+ full_text += delta
295
+ await self._emit_chunk(delta, task_id, session_id)
296
+ except Exception:
297
+ pass
298
+ return full_text
299
+
300
+ # ─── Anthropic ─────────────────────────────────────────────────────────────
301
+
302
+ async def _anthropic_call(
303
+ self, cfg: Dict, key: str, messages: List[Dict],
304
+ task_id: str, session_id: str, temperature: float, max_tokens: int
305
+ ) -> str:
306
+ headers = {
307
+ "x-api-key": key,
308
+ "anthropic-version": "2023-06-01",
309
+ "Content-Type": "application/json",
310
+ }
311
+ system = ""
312
+ filtered = []
313
+ for m in messages:
314
+ if m["role"] == "system":
315
+ system = m["content"]
316
+ else:
317
+ filtered.append(m)
318
+ payload: Dict[str, Any] = {
319
+ "model": cfg["default_model"],
320
+ "max_tokens": max_tokens,
321
+ "messages": filtered,
322
+ "stream": True,
323
+ "temperature": temperature,
324
+ }
325
+ if system:
326
+ payload["system"] = system
327
+ full_text = ""
328
+ async with httpx.AsyncClient(timeout=120) as client:
329
+ async with client.stream(
330
+ "POST", f"{cfg['base_url']}/messages",
331
+ headers=headers, json=payload
332
+ ) as resp:
333
+ resp.raise_for_status()
334
+ async for line in resp.aiter_lines():
335
+ if not line.startswith("data:"):
336
+ continue
337
+ try:
338
+ data = json.loads(line[5:].strip())
339
+ if data.get("type") == "content_block_delta":
340
+ delta = data["delta"].get("text", "")
341
+ if delta:
342
+ full_text += delta
343
+ await self._emit_chunk(delta, task_id, session_id)
344
+ except Exception:
345
+ pass
346
+ return full_text
347
+
348
+ # ─── Demo Stream ───────────────────────────────────────────────────────────
349
+
350
+ async def _demo_stream(self, messages: List[Dict], task_id: str, session_id: str) -> str:
351
+ last_user = next((m["content"] for m in reversed(messages) if m["role"] == "user"), "Hello")
352
+ response = (
353
+ "🤖 **God Agent OS v8** (Demo Mode)\n\n"
354
+ f"Received: *{last_user[:100]}*\n\n"
355
+ "To enable full AI power, set API keys in environment variables:\n"
356
+ "- `GEMINI_API_KEYS` (Google Gemini — multiple keys supported)\n"
357
+ "- `SAMBANOVA_API_KEYS` (SambaNova — multiple keys supported)\n"
358
+ "- `OPENAI_API_KEY`, `GROQ_API_KEY`, `ANTHROPIC_API_KEY`\n\n"
359
+ "**Active Capabilities:**\n"
360
+ "- ⚡ 16-agent autonomous orchestration\n"
361
+ "- 🔑 Multi-key pool with automatic failover\n"
362
+ "- 🧠 Persistent memory system\n"
363
+ "- 🔌 Connector ecosystem\n"
364
+ "- 📡 Real-time WebSocket streaming\n"
365
+ )
366
+ full_text = ""
367
+ for word in response.split():
368
+ chunk = word + " "
369
+ full_text += chunk
370
+ await asyncio.sleep(0.02)
371
+ await self._emit_chunk(chunk, task_id, session_id, demo=True)
372
+ return full_text
373
+
374
+ # ─── Emit Helper ───────────────────────────────────────────────────────────
375
+
376
+ async def _emit_chunk(self, chunk: str, task_id: str, session_id: str, demo: bool = False):
377
+ if not self.ws:
378
+ return
379
+ payload = {"chunk": chunk, "demo": demo}
380
+ if task_id:
381
+ await self.ws.emit(task_id, "llm_chunk", payload, session_id=session_id)
382
+ elif session_id:
383
+ await self.ws.emit_chat(session_id, "llm_chunk", payload)
384
+
385
+ # ─── Stats ─────────────────────────────────────────────────────────────────
386
+
387
+ def get_stats(self) -> Dict:
388
+ result = {}
389
+ for cfg in PROVIDER_CONFIG:
390
+ name = cfg["name"]
391
+ s = self._stats.get(name, {"calls": 0, "errors": 0, "latency": []})
392
+ pool = self._registry.get(name)
393
+ lat = s["latency"][-20:]
394
+ avg_lat = round(sum(lat) / max(len(lat), 1) * 1000, 1) if lat else 0
395
+ result[name] = {
396
+ "calls": s["calls"],
397
+ "errors": s["errors"],
398
+ "avg_latency_ms": avg_lat,
399
+ "available": bool(os.environ.get(cfg["key_env"], "")),
400
+ "key_count": len(pool) if pool else 0,
401
+ "available_keys": pool.available_count() if pool else 0,
402
+ "priority": cfg["priority"],
403
+ }
404
+ return result
405
+
406
+ def get_pool_status(self) -> Dict:
407
+ return self._registry.all_status()
backend/main_v8.py ADDED
@@ -0,0 +1,326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 🚀 GOD AGENT OS v8 — Autonomous Engineering Operating System
3
+ Manus + Genspark + Devin (OneHand) Combined
4
+ Version: 8.0.0 — KeyPool Multi-API Routing (Gemini + SambaNova Primary LLMs)
5
+ """
6
+
7
+ import asyncio
8
+ import json
9
+ import os
10
+ import time
11
+ import uuid
12
+ from contextlib import asynccontextmanager
13
+ from typing import Optional
14
+
15
+ import structlog
16
+ from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException, Request
17
+ from fastapi.middleware.cors import CORSMiddleware
18
+ from fastapi.middleware.gzip import GZipMiddleware
19
+ from fastapi.responses import JSONResponse
20
+ from slowapi import Limiter, _rate_limit_exceeded_handler
21
+ from slowapi.util import get_remote_address
22
+ from slowapi.errors import RateLimitExceeded
23
+
24
+ from api.routes import tasks, chat, memory, github, health
25
+ from api.routes import connectors, agents as agents_router
26
+ from api.websocket_manager import WebSocketManager
27
+ from core.task_engine import TaskEngine
28
+ from memory.db import init_db
29
+
30
+ # ─── v8 AI Router (KeyPool-based) ─────────────────────────────────────────────
31
+ from ai_router.router_v8 import AIRouterV8
32
+
33
+ # ─── Agent Ecosystem ──────────────────────────────────────────────────────────
34
+ from agents.orchestrator_v7 import GodAgentOrchestratorV7
35
+ from agents.chat_agent import ChatAgent
36
+ from agents.planner_agent import PlannerAgent
37
+ from agents.coding_agent import CodingAgent
38
+ from agents.debug_agent import DebugAgent
39
+ from agents.memory_agent import MemoryAgent
40
+ from agents.connector_agent import ConnectorAgent
41
+ from agents.deploy_agent import DeployAgent
42
+ from agents.workflow_agent import WorkflowAgent
43
+ from agents.sandbox_agent import SandboxAgent
44
+ from agents.ui_agent import UIAgent
45
+ from agents.reasoning_agent import ReasoningAgent
46
+ from agents.browser_agent import BrowserAgent
47
+ from agents.file_agent import FileAgent
48
+ from agents.git_agent import GitAgent
49
+ from agents.test_agent import TestAgent
50
+ from agents.vision_agent import VisionAgent
51
+ from connectors.manager import ConnectorManager
52
+
53
+ # ─── Structured Logging ───────────────────────────────────────────────────────
54
+ structlog.configure(
55
+ processors=[
56
+ structlog.processors.TimeStamper(fmt="iso"),
57
+ structlog.stdlib.add_log_level,
58
+ structlog.processors.StackInfoRenderer(),
59
+ structlog.dev.ConsoleRenderer(),
60
+ ]
61
+ )
62
+ log = structlog.get_logger()
63
+
64
+ limiter = Limiter(key_func=get_remote_address)
65
+
66
+ # ─── Global Managers ──────────────────────────────────────────────────────────
67
+ ws_manager = WebSocketManager()
68
+ task_engine = TaskEngine(ws_manager)
69
+ ai_router = AIRouterV8(ws_manager)
70
+ connector_manager = ConnectorManager()
71
+
72
+
73
+ def build_orchestrator() -> GodAgentOrchestratorV7:
74
+ orchestrator = GodAgentOrchestratorV7(ws_manager=ws_manager, ai_router=ai_router)
75
+ orchestrator.register_agent("chat", ChatAgent(ws_manager, ai_router))
76
+ orchestrator.register_agent("planner", PlannerAgent(ws_manager, ai_router))
77
+ orchestrator.register_agent("coding", CodingAgent(ws_manager, ai_router))
78
+ orchestrator.register_agent("debug", DebugAgent(ws_manager, ai_router))
79
+ orchestrator.register_agent("memory", MemoryAgent(ws_manager, ai_router))
80
+ orchestrator.register_agent("connector", ConnectorAgent(ws_manager, ai_router))
81
+ orchestrator.register_agent("deploy", DeployAgent(ws_manager, ai_router))
82
+ orchestrator.register_agent("workflow", WorkflowAgent(ws_manager, ai_router))
83
+ orchestrator.register_agent("sandbox", SandboxAgent(ws_manager, ai_router))
84
+ orchestrator.register_agent("ui", UIAgent(ws_manager, ai_router))
85
+ orchestrator.register_agent("reasoning", ReasoningAgent(ws_manager, ai_router))
86
+ orchestrator.register_agent("browser", BrowserAgent(ws_manager, ai_router))
87
+ orchestrator.register_agent("file", FileAgent(ws_manager, ai_router))
88
+ orchestrator.register_agent("git", GitAgent(ws_manager, ai_router))
89
+ orchestrator.register_agent("test", TestAgent(ws_manager, ai_router))
90
+ orchestrator.register_agent("vision", VisionAgent(ws_manager, ai_router))
91
+ log.info("🤖 GOD AGENT v8 Ecosystem initialized", agents=16)
92
+ return orchestrator
93
+
94
+
95
+ orchestrator = build_orchestrator()
96
+
97
+
98
+ @asynccontextmanager
99
+ async def lifespan(app: FastAPI):
100
+ log.info("🚀 Starting GOD AGENT OS v8 — KeyPool Multi-API Edition...")
101
+ await init_db()
102
+ await task_engine.start()
103
+ asyncio.create_task(ws_manager.heartbeat_loop())
104
+ # Print router status
105
+ stats = ai_router.get_stats()
106
+ active = [name for name, s in stats.items() if s["available"]]
107
+ log.info("✅ GOD AGENT v8 — 16 agents online")
108
+ log.info(f"🔑 Active AI providers: {active}")
109
+ log.info("🌐 AI Routing: SambaNova → Gemini → OpenAI → Groq → Cerebras → OpenRouter → Anthropic")
110
+ yield
111
+ log.info("🛑 Shutting down GOD AGENT v8...")
112
+ await task_engine.stop()
113
+
114
+
115
+ app = FastAPI(
116
+ title="🤖 GOD AGENT OS v8",
117
+ description="Autonomous Engineering OS — Gemini + SambaNova KeyPool Multi-API Routing",
118
+ version="8.0.0",
119
+ lifespan=lifespan,
120
+ docs_url="/api/docs",
121
+ redoc_url="/api/redoc",
122
+ )
123
+
124
+ app.state.limiter = limiter
125
+ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
126
+ app.state.ws_manager = ws_manager
127
+ app.state.task_engine = task_engine
128
+ app.state.ai_router = ai_router
129
+ app.state.orchestrator = orchestrator
130
+ app.state.connector_manager = connector_manager
131
+
132
+ app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
133
+ app.add_middleware(GZipMiddleware, minimum_size=1000)
134
+
135
+
136
+ @app.middleware("http")
137
+ async def log_requests(request: Request, call_next):
138
+ start = time.time()
139
+ response = await call_next(request)
140
+ ms = round((time.time() - start) * 1000, 2)
141
+ log.info("HTTP", method=request.method, path=request.url.path, status=response.status_code, ms=ms)
142
+ return response
143
+
144
+
145
+ # ─── REST Routers ─────────────────────────────────────────────────────────────
146
+ app.include_router(health.router, prefix="/api/v1", tags=["health"])
147
+ app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"])
148
+ app.include_router(chat.router, prefix="/api/v1", tags=["chat"])
149
+ app.include_router(memory.router, prefix="/api/v1/memory", tags=["memory"])
150
+ app.include_router(github.router, prefix="/api/v1/github", tags=["github"])
151
+ app.include_router(connectors.router, prefix="/api/v1/connectors", tags=["connectors"])
152
+ app.include_router(agents_router.router, prefix="/api/v1/agents", tags=["agents"])
153
+
154
+
155
+ # ─── WebSocket Endpoints ──────────────────────────────────────────────────────
156
+ @app.websocket("/ws/tasks/{task_id}")
157
+ async def ws_task(websocket: WebSocket, task_id: str):
158
+ await ws_manager.connect(websocket, room=f"task:{task_id}")
159
+ try:
160
+ while True:
161
+ data = await websocket.receive_text()
162
+ msg = json.loads(data)
163
+ if msg.get("type") == "ping":
164
+ await websocket.send_json({"type": "pong", "timestamp": time.time()})
165
+ except WebSocketDisconnect:
166
+ ws_manager.disconnect(websocket, room=f"task:{task_id}")
167
+
168
+
169
+ @app.websocket("/ws/logs")
170
+ async def ws_logs(websocket: WebSocket):
171
+ await ws_manager.connect(websocket, room="logs")
172
+ try:
173
+ while True:
174
+ data = await websocket.receive_text()
175
+ msg = json.loads(data)
176
+ if msg.get("type") == "ping":
177
+ await websocket.send_json({"type": "pong", "timestamp": time.time()})
178
+ except WebSocketDisconnect:
179
+ ws_manager.disconnect(websocket, room="logs")
180
+
181
+
182
+ @app.websocket("/ws/chat/{session_id}")
183
+ async def ws_chat(websocket: WebSocket, session_id: str):
184
+ await ws_manager.connect(websocket, room=f"chat:{session_id}")
185
+ try:
186
+ while True:
187
+ data = await websocket.receive_text()
188
+ msg = json.loads(data)
189
+ if msg.get("type") == "ping":
190
+ await websocket.send_json({"type": "pong", "timestamp": time.time()})
191
+ elif msg.get("type") == "chat_message":
192
+ asyncio.create_task(orchestrator.orchestrate(
193
+ user_message=msg.get("content", ""),
194
+ session_id=session_id,
195
+ context=msg.get("context", {}),
196
+ ))
197
+ elif msg.get("type") == "task_message":
198
+ from core.models import TaskCreateRequest
199
+ req = TaskCreateRequest(goal=msg.get("content", ""), session_id=session_id)
200
+ asyncio.create_task(task_engine.submit(req))
201
+ except WebSocketDisconnect:
202
+ ws_manager.disconnect(websocket, room=f"chat:{session_id}")
203
+
204
+
205
+ @app.websocket("/ws/agent/status")
206
+ async def ws_agent_status(websocket: WebSocket):
207
+ await ws_manager.connect(websocket, room="agent_status")
208
+ try:
209
+ while True:
210
+ data = await websocket.receive_text()
211
+ msg = json.loads(data)
212
+ if msg.get("type") == "ping":
213
+ await websocket.send_json({"type": "pong", "timestamp": time.time()})
214
+ elif msg.get("type") == "get_status":
215
+ await websocket.send_json({"type": "agent_status", "data": orchestrator.get_status()})
216
+ except WebSocketDisconnect:
217
+ ws_manager.disconnect(websocket, room="agent_status")
218
+
219
+
220
+ @app.websocket("/ws/sandbox/{session_id}")
221
+ async def ws_sandbox(websocket: WebSocket, session_id: str):
222
+ await ws_manager.connect(websocket, room=f"sandbox:{session_id}")
223
+ sandbox = orchestrator.get_agent("sandbox")
224
+ try:
225
+ while True:
226
+ data = await websocket.receive_text()
227
+ msg = json.loads(data)
228
+ if msg.get("type") == "ping":
229
+ await websocket.send_json({"type": "pong", "timestamp": time.time()})
230
+ elif msg.get("type") == "execute" and sandbox:
231
+ cmd = msg.get("command", "")
232
+ result = await sandbox.execute(cmd, session_id=session_id)
233
+ await websocket.send_json({"type": "terminal_output", "command": cmd, "output": result, "timestamp": time.time()})
234
+ except WebSocketDisconnect:
235
+ ws_manager.disconnect(websocket, room=f"sandbox:{session_id}")
236
+
237
+
238
+ # ─── v8 Key Pool & AI Router Status Endpoints ─────────────────────────────────
239
+ @app.get("/api/v1/ai/stats")
240
+ async def get_ai_stats():
241
+ return {"stats": ai_router.get_stats()}
242
+
243
+
244
+ @app.get("/api/v1/ai/pool-status")
245
+ async def get_pool_status():
246
+ return {"pools": ai_router.get_pool_status()}
247
+
248
+
249
+ @app.post("/api/v1/browser/research")
250
+ async def browser_research(request: Request):
251
+ body = await request.json()
252
+ browser = orchestrator.get_agent("browser")
253
+ if not browser:
254
+ raise HTTPException(status_code=503, detail="BrowserAgent not available")
255
+ result = await browser.run(body.get("query", ""), session_id=body.get("session_id", ""))
256
+ return {"result": result}
257
+
258
+
259
+ @app.get("/api/v1/files/workspace")
260
+ async def list_workspace():
261
+ file_agent = orchestrator.get_agent("file")
262
+ if not file_agent:
263
+ return {"workspace": "/tmp/god_workspace", "files": [], "total": 0}
264
+ return file_agent.list_workspace()
265
+
266
+
267
+ @app.post("/api/v1/git/pr")
268
+ async def create_pr(request: Request):
269
+ body = await request.json()
270
+ git_agent = orchestrator.get_agent("git")
271
+ if not git_agent:
272
+ raise HTTPException(status_code=503, detail="GitAgent not available")
273
+ result = await git_agent.create_github_pr(
274
+ repo_owner=body.get("owner", ""),
275
+ repo_name=body.get("repo", ""),
276
+ title=body.get("title", ""),
277
+ body=body.get("body", ""),
278
+ head_branch=body.get("head_branch", "main"),
279
+ base_branch=body.get("base_branch", "main"),
280
+ )
281
+ return result
282
+
283
+
284
+ @app.post("/api/v1/vision/generate")
285
+ async def generate_ui(request: Request):
286
+ body = await request.json()
287
+ vision = orchestrator.get_agent("vision")
288
+ if not vision:
289
+ raise HTTPException(status_code=503, detail="VisionAgent not available")
290
+ result = await vision.run(body.get("prompt", ""), context=body.get("context", {}), session_id=body.get("session_id", ""))
291
+ return {"result": result}
292
+
293
+
294
+ # ─── Root ─────────────────────────────────────────────────────────────────────
295
+ @app.get("/")
296
+ async def root():
297
+ cs = connector_manager.get_summary()
298
+ status = orchestrator.get_status()
299
+ stats = ai_router.get_stats()
300
+ active_providers = [name for name, s in stats.items() if s["available"]]
301
+ return {
302
+ "name": "🤖 GOD AGENT OS v8",
303
+ "version": "8.0.0",
304
+ "status": "operational",
305
+ "mode": "autonomous_engineering_os",
306
+ "description": "KeyPool Multi-API Routing — Gemini + SambaNova Primary LLMs",
307
+ "agents": status["agents"],
308
+ "total_agents": status["total_agents"],
309
+ "ai_providers": active_providers,
310
+ "connectors": {"connected": cs["connected"], "total": cs["total"]},
311
+ "docs": "/api/docs",
312
+ "v8_features": [
313
+ "🔑 KeyPool multi-key management (Gemini 6 keys + SambaNova 9 keys)",
314
+ "🔄 Automatic key failover with cooldown tracking",
315
+ "⚡ SambaNova → Gemini → OpenAI → Groq → Cerebras chain",
316
+ "📊 Per-key usage stats & health monitoring",
317
+ "🤖 16-agent autonomous fleet",
318
+ "🌐 Real-time streaming via WebSocket",
319
+ ],
320
+ }
321
+
322
+
323
+ if __name__ == "__main__":
324
+ import uvicorn
325
+ port = int(os.environ.get("PORT", 8000))
326
+ uvicorn.run("main_v8:app", host="0.0.0.0", port=port, reload=False, workers=1)
frontend/app/page.tsx CHANGED
@@ -13,6 +13,7 @@ import ConnectorsPanel from '@/components/layout/ConnectorsPanel'
13
  import SandboxPanel from '@/components/layout/SandboxPanel'
14
  import FileExplorer from '@/components/layout/FileExplorer'
15
  import BrowserPanel from '@/components/layout/BrowserPanel'
 
16
  import { Zap } from 'lucide-react'
17
 
18
  export default function HomePage() {
@@ -39,8 +40,9 @@ export default function HomePage() {
39
  <Zap size={28} className="text-indigo-400" />
40
  </div>
41
  <h2 className="text-lg font-bold mb-1" style={{ color: 'var(--text-primary)' }}>GOD AGENT OS</h2>
42
- <p className="text-sm mb-1" style={{ color: 'var(--text-muted)' }}>Autonomous Engineering Platform v7.0</p>
43
- <p className="text-xs mb-4" style={{ color: 'var(--text-muted)' }}>Manus + Genspark + Devin</p>
 
44
  <div className="flex gap-1.5 justify-center">
45
  {[0, 1, 2].map(i => (
46
  <div key={i} className="typing-dot" style={{ animationDelay: `${i * 0.16}s` }} />
@@ -59,6 +61,7 @@ export default function HomePage() {
59
  case 'sandbox': return <SandboxPanel />
60
  case 'files': return <FileExplorer />
61
  case 'browser': return <BrowserPanel />
 
62
  default: return <ExecutionTimeline />
63
  }
64
  }
 
13
  import SandboxPanel from '@/components/layout/SandboxPanel'
14
  import FileExplorer from '@/components/layout/FileExplorer'
15
  import BrowserPanel from '@/components/layout/BrowserPanel'
16
+ import AIRouterPanel from '@/components/layout/AIRouterPanel'
17
  import { Zap } from 'lucide-react'
18
 
19
  export default function HomePage() {
 
40
  <Zap size={28} className="text-indigo-400" />
41
  </div>
42
  <h2 className="text-lg font-bold mb-1" style={{ color: 'var(--text-primary)' }}>GOD AGENT OS</h2>
43
+ <p className="text-sm mb-1" style={{ color: 'var(--text-muted)' }}>Autonomous Engineering Platform v8.0</p>
44
+ <p className="text-xs mb-1" style={{ color: 'var(--text-muted)' }}>Manus + Genspark + Devin</p>
45
+ <p className="text-xs mb-4" style={{ color: '#6366f1' }}>KeyPool: Gemini × 6 + SambaNova × 9</p>
46
  <div className="flex gap-1.5 justify-center">
47
  {[0, 1, 2].map(i => (
48
  <div key={i} className="typing-dot" style={{ animationDelay: `${i * 0.16}s` }} />
 
61
  case 'sandbox': return <SandboxPanel />
62
  case 'files': return <FileExplorer />
63
  case 'browser': return <BrowserPanel />
64
+ case 'ai_router': return <AIRouterPanel />
65
  default: return <ExecutionTimeline />
66
  }
67
  }
frontend/components/layout/AIRouterPanel.tsx ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client'
2
+
3
+ import { useEffect, useState } from 'react'
4
+ import { useAgentStore } from '@/hooks/useAgentStore'
5
+ import { Cpu, Key, RefreshCw, CheckCircle2, XCircle, AlertCircle, Zap, Activity } from 'lucide-react'
6
+
7
+ const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:7860'
8
+
9
+ interface ProviderStat {
10
+ calls: number
11
+ errors: number
12
+ avg_latency_ms: number
13
+ available: boolean
14
+ key_count: number
15
+ available_keys: number
16
+ priority: number
17
+ }
18
+
19
+ interface KeyInfo {
20
+ key_preview: string
21
+ available: boolean
22
+ failures: number
23
+ calls: number
24
+ cooldown_remaining_s: number
25
+ }
26
+
27
+ interface PoolStatus {
28
+ provider: string
29
+ total_keys: number
30
+ available_keys: number
31
+ keys: KeyInfo[]
32
+ }
33
+
34
+ const PROVIDER_ICONS: Record<string, string> = {
35
+ sambanova: '⚡',
36
+ gemini: '✨',
37
+ openai: '🤖',
38
+ groq: '🦙',
39
+ cerebras: '🧠',
40
+ openrouter: '🔀',
41
+ anthropic: '🪄',
42
+ }
43
+
44
+ const PROVIDER_COLORS: Record<string, string> = {
45
+ sambanova: '#f97316',
46
+ gemini: '#4285f4',
47
+ openai: '#10a37f',
48
+ groq: '#f59e0b',
49
+ cerebras: '#8b5cf6',
50
+ openrouter: '#6366f1',
51
+ anthropic: '#d97706',
52
+ }
53
+
54
+ export default function AIRouterPanel() {
55
+ const { locale } = useAgentStore()
56
+ const [stats, setStats] = useState<Record<string, ProviderStat>>({})
57
+ const [pools, setPools] = useState<Record<string, PoolStatus>>({})
58
+ const [loading, setLoading] = useState(true)
59
+ const [expandedProvider, setExpandedProvider] = useState<string | null>(null)
60
+ const [lastRefresh, setLastRefresh] = useState<Date | null>(null)
61
+
62
+ const load = async () => {
63
+ setLoading(true)
64
+ try {
65
+ const [statsRes, poolRes] = await Promise.all([
66
+ fetch(`${API_URL}/api/v1/ai/stats`).then(r => r.json()).catch(() => ({})),
67
+ fetch(`${API_URL}/api/v1/ai/pool-status`).then(r => r.json()).catch(() => ({})),
68
+ ])
69
+ setStats(statsRes.stats || {})
70
+ setPools(poolRes.pools || {})
71
+ setLastRefresh(new Date())
72
+ } catch {}
73
+ setLoading(false)
74
+ }
75
+
76
+ useEffect(() => {
77
+ load()
78
+ const interval = setInterval(load, 30000)
79
+ return () => clearInterval(interval)
80
+ }, [])
81
+
82
+ const sortedProviders = Object.entries(stats).sort(
83
+ ([, a], [, b]) => (a.priority || 99) - (b.priority || 99)
84
+ )
85
+
86
+ const activeCount = sortedProviders.filter(([, s]) => s.available).length
87
+ const totalCalls = sortedProviders.reduce((sum, [, s]) => sum + s.calls, 0)
88
+
89
+ return (
90
+ <div className="flex flex-col h-full" style={{ background: 'var(--bg-2)' }}>
91
+ {/* Header */}
92
+ <div className="flex items-center justify-between px-4 py-2.5 border-b shrink-0"
93
+ style={{ borderColor: 'var(--border)', background: 'var(--bg-3)' }}>
94
+ <div className="flex items-center gap-2">
95
+ <Cpu size={14} className="text-indigo-400" />
96
+ <span className="text-sm font-semibold" style={{ color: 'var(--text-primary)' }}>
97
+ {locale === 'my' ? 'AI Router v8' : 'AI Router v8'}
98
+ </span>
99
+ <span className="text-[10px] px-1.5 py-0.5 rounded-full"
100
+ style={{
101
+ background: activeCount > 0 ? 'rgba(34,197,94,0.15)' : 'rgba(239,68,68,0.15)',
102
+ color: activeCount > 0 ? '#4ade80' : '#f87171',
103
+ border: `1px solid ${activeCount > 0 ? 'rgba(34,197,94,0.3)' : 'rgba(239,68,68,0.3)'}`,
104
+ }}>
105
+ {activeCount} active
106
+ </span>
107
+ </div>
108
+ <button onClick={load} disabled={loading}
109
+ className="p-1.5 rounded-lg hover:bg-white/5 transition-colors" title="Refresh">
110
+ <RefreshCw size={12} style={{ color: 'var(--text-muted)' }}
111
+ className={loading ? 'animate-spin' : ''} />
112
+ </button>
113
+ </div>
114
+
115
+ {/* Summary */}
116
+ <div className="px-3 py-2 border-b flex gap-3 text-xs"
117
+ style={{ borderColor: 'var(--border)', background: 'rgba(99,102,241,0.05)' }}>
118
+ <div className="flex items-center gap-1">
119
+ <Activity size={10} className="text-indigo-400" />
120
+ <span style={{ color: 'var(--text-muted)' }}>Total calls:</span>
121
+ <span className="font-mono font-semibold" style={{ color: 'var(--text-primary)' }}>{totalCalls}</span>
122
+ </div>
123
+ <div className="flex items-center gap-1">
124
+ <Key size={10} className="text-indigo-400" />
125
+ <span style={{ color: 'var(--text-muted)' }}>Providers:</span>
126
+ <span className="font-mono font-semibold" style={{ color: 'var(--text-primary)' }}>
127
+ {activeCount}/{sortedProviders.length}
128
+ </span>
129
+ </div>
130
+ {lastRefresh && (
131
+ <div className="ml-auto text-[10px]" style={{ color: 'var(--text-muted)' }}>
132
+ {lastRefresh.toLocaleTimeString()}
133
+ </div>
134
+ )}
135
+ </div>
136
+
137
+ {/* Provider List */}
138
+ <div className="flex-1 overflow-y-auto">
139
+ {loading && sortedProviders.length === 0 ? (
140
+ <div className="flex items-center justify-center h-24">
141
+ <div className="flex gap-1">
142
+ {[0, 1, 2].map(i => (
143
+ <div key={i} className="w-1.5 h-1.5 rounded-full animate-bounce"
144
+ style={{ background: 'var(--brand)', animationDelay: `${i * 0.15}s` }} />
145
+ ))}
146
+ </div>
147
+ </div>
148
+ ) : sortedProviders.length === 0 ? (
149
+ <div className="p-4 text-center text-xs" style={{ color: 'var(--text-muted)' }}>
150
+ No providers configured
151
+ </div>
152
+ ) : (
153
+ <div className="p-2 flex flex-col gap-1.5">
154
+ {sortedProviders.map(([name, stat]) => {
155
+ const pool = pools[name]
156
+ const icon = PROVIDER_ICONS[name] || '🔌'
157
+ const color = PROVIDER_COLORS[name] || '#6366f1'
158
+ const isExpanded = expandedProvider === name
159
+ const successRate = stat.calls > 0
160
+ ? Math.round(((stat.calls - stat.errors) / stat.calls) * 100)
161
+ : 100
162
+
163
+ return (
164
+ <div key={name}
165
+ className="rounded-xl border overflow-hidden cursor-pointer hover:border-opacity-60 transition-all"
166
+ style={{
167
+ borderColor: stat.available ? `${color}40` : 'var(--border)',
168
+ background: stat.available ? `${color}08` : 'var(--bg-3)',
169
+ }}
170
+ onClick={() => setExpandedProvider(isExpanded ? null : name)}>
171
+
172
+ {/* Provider Header */}
173
+ <div className="flex items-center gap-2 px-3 py-2">
174
+ <span className="text-sm">{icon}</span>
175
+ <div className="flex-1 min-w-0">
176
+ <div className="flex items-center gap-2">
177
+ <span className="text-xs font-semibold capitalize" style={{ color: 'var(--text-primary)' }}>
178
+ {name}
179
+ </span>
180
+ {stat.priority <= 2 && (
181
+ <span className="text-[9px] px-1 py-0.5 rounded font-bold"
182
+ style={{ background: `${color}25`, color }}>
183
+ PRIMARY
184
+ </span>
185
+ )}
186
+ </div>
187
+ <div className="flex items-center gap-2 mt-0.5">
188
+ <span className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
189
+ {stat.calls} calls · {stat.avg_latency_ms}ms avg
190
+ </span>
191
+ {pool && (
192
+ <span className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
193
+ · {pool.available_keys}/{pool.total_keys} keys
194
+ </span>
195
+ )}
196
+ </div>
197
+ </div>
198
+ <div className="flex items-center gap-1.5">
199
+ {/* Success Rate Bar */}
200
+ {stat.calls > 0 && (
201
+ <div className="w-12 h-1.5 rounded-full overflow-hidden"
202
+ style={{ background: 'var(--bg-0)' }}>
203
+ <div className="h-full rounded-full transition-all"
204
+ style={{
205
+ width: `${successRate}%`,
206
+ background: successRate > 80 ? '#4ade80' : successRate > 50 ? '#fbbf24' : '#f87171',
207
+ }} />
208
+ </div>
209
+ )}
210
+ {stat.available ? (
211
+ <CheckCircle2 size={12} style={{ color: '#4ade80' }} />
212
+ ) : (
213
+ <XCircle size={12} style={{ color: '#f87171' }} />
214
+ )}
215
+ </div>
216
+ </div>
217
+
218
+ {/* Expanded Key Pool */}
219
+ {isExpanded && pool && pool.keys.length > 0 && (
220
+ <div className="px-3 pb-3 border-t" style={{ borderColor: 'var(--border)' }}>
221
+ <div className="pt-2 text-[10px] font-semibold mb-2" style={{ color: 'var(--text-muted)' }}>
222
+ KEY POOL ({pool.available_keys}/{pool.total_keys} available)
223
+ </div>
224
+ <div className="flex flex-col gap-1">
225
+ {pool.keys.map((k, i) => (
226
+ <div key={i} className="flex items-center gap-2 px-2 py-1 rounded-lg"
227
+ style={{ background: k.available ? 'rgba(34,197,94,0.05)' : 'rgba(239,68,68,0.05)' }}>
228
+ <Key size={9} style={{ color: k.available ? '#4ade80' : '#f87171' }} />
229
+ <span className="font-mono text-[10px] flex-1" style={{ color: 'var(--text-secondary)' }}>
230
+ {k.key_preview}
231
+ </span>
232
+ <span className="text-[9px]" style={{ color: 'var(--text-muted)' }}>
233
+ {k.calls} calls
234
+ </span>
235
+ {k.failures > 0 && (
236
+ <span className="text-[9px]" style={{ color: '#fbbf24' }}>
237
+ {k.failures} fails
238
+ </span>
239
+ )}
240
+ {!k.available && k.cooldown_remaining_s > 0 && (
241
+ <span className="text-[9px] px-1 rounded"
242
+ style={{ background: 'rgba(239,68,68,0.15)', color: '#f87171' }}>
243
+ {Math.round(k.cooldown_remaining_s)}s
244
+ </span>
245
+ )}
246
+ </div>
247
+ ))}
248
+ </div>
249
+ </div>
250
+ )}
251
+ </div>
252
+ )
253
+ })}
254
+ </div>
255
+ )}
256
+ </div>
257
+
258
+ {/* Footer Info */}
259
+ <div className="px-3 py-2 border-t text-[10px]"
260
+ style={{ borderColor: 'var(--border)', color: 'var(--text-muted)', background: 'var(--bg-3)' }}>
261
+ <div className="flex items-center gap-1">
262
+ <Zap size={9} className="text-indigo-400" />
263
+ <span>Priority: SambaNova → Gemini → OpenAI → Groq → Cerebras → Anthropic</span>
264
+ </div>
265
+ </div>
266
+ </div>
267
+ )
268
+ }
frontend/components/layout/Sidebar.tsx CHANGED
@@ -17,6 +17,7 @@ const PANELS: { id: ActivePanel; icon: React.ElementType; labelEn: string; label
17
  { id: 'browser', icon: Globe, labelEn: 'Browser', labelMy: 'ဘရောင်ဇာ', badge: 'v7' },
18
  { id: 'memory', icon: Brain, labelEn: 'Memory', labelMy: 'မှတ်ဉာဏ်' },
19
  { id: 'connectors', icon: Plug, labelEn: 'Connectors', labelMy: 'ချိတ်ဆက်မှု' },
 
20
  ]
21
 
22
  const AGENT_META: Record<string, { icon: React.ElementType; color: string; label: string; isNew?: boolean }> = {
@@ -128,7 +129,7 @@ export default function Sidebar() {
128
  <div className="flex items-center gap-2 px-2 py-1.5 rounded-lg text-[10px]"
129
  style={{ background: 'rgba(99,102,241,0.08)', border: '1px solid rgba(99,102,241,0.2)' }}>
130
  <Bot size={10} className="text-indigo-400" />
131
- <span style={{ color: 'var(--text-muted)' }}>God Agent OS v7.0</span>
132
  <div className="ml-auto w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse" />
133
  </div>
134
  </div>
 
17
  { id: 'browser', icon: Globe, labelEn: 'Browser', labelMy: 'ဘရောင်ဇာ', badge: 'v7' },
18
  { id: 'memory', icon: Brain, labelEn: 'Memory', labelMy: 'မှတ်ဉာဏ်' },
19
  { id: 'connectors', icon: Plug, labelEn: 'Connectors', labelMy: 'ချိတ်ဆက်မှု' },
20
+ { id: 'ai_router', icon: Cpu, labelEn: 'AI Router', labelMy: 'AI Router', badge: 'v8' },
21
  ]
22
 
23
  const AGENT_META: Record<string, { icon: React.ElementType; color: string; label: string; isNew?: boolean }> = {
 
129
  <div className="flex items-center gap-2 px-2 py-1.5 rounded-lg text-[10px]"
130
  style={{ background: 'rgba(99,102,241,0.08)', border: '1px solid rgba(99,102,241,0.2)' }}>
131
  <Bot size={10} className="text-indigo-400" />
132
+ <span style={{ color: 'var(--text-muted)' }}>God Agent OS v8.0</span>
133
  <div className="ml-auto w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse" />
134
  </div>
135
  </div>
frontend/hooks/useAgentStore.ts CHANGED
@@ -9,7 +9,7 @@ import { nanoid } from './nanoid'
9
  export type Theme = 'dark' | 'light' | 'amoled' | 'neon' | 'glass'
10
  export type Locale = 'en' | 'my'
11
  export type AgentName = 'chat' | 'planner' | 'coding' | 'debug' | 'memory' | 'connector' | 'deploy' | 'workflow' | 'sandbox' | 'ui' | 'browser' | 'file' | 'git' | 'test' | 'vision' | 'reasoning'
12
- export type ActivePanel = 'timeline' | 'tasks' | 'memory' | 'connectors' | 'sandbox' | 'files' | 'browser'
13
 
14
  export interface Message {
15
  id: string
 
9
  export type Theme = 'dark' | 'light' | 'amoled' | 'neon' | 'glass'
10
  export type Locale = 'en' | 'my'
11
  export type AgentName = 'chat' | 'planner' | 'coding' | 'debug' | 'memory' | 'connector' | 'deploy' | 'workflow' | 'sandbox' | 'ui' | 'browser' | 'file' | 'git' | 'test' | 'vision' | 'reasoning'
12
+ export type ActivePanel = 'timeline' | 'tasks' | 'memory' | 'connectors' | 'sandbox' | 'files' | 'browser' | 'ai_router'
13
 
14
  export interface Message {
15
  id: string