|
|
|
|
|
import os |
|
|
import asyncio |
|
|
import random |
|
|
import re |
|
|
import json |
|
|
import logging |
|
|
from colorama import Fore, Style |
|
|
from groq import AsyncGroq, RateLimitError |
|
|
from mistralai import Mistral |
|
|
from openai import AsyncOpenAI |
|
|
import traceback |
|
|
|
|
|
|
|
|
logger = logging.getLogger("JadeHeavy") |
|
|
logger.setLevel(logging.INFO) |
|
|
|
|
|
class JadeHeavyAgent: |
|
|
def __init__(self): |
|
|
self.groq_api_key = os.getenv("GROQ_API_KEY") |
|
|
self.mistral_api_key = os.getenv("MISTRAL_API_KEY") |
|
|
self.openrouter_api_key = os.getenv("OPENROUTER_API_KEY") |
|
|
|
|
|
if not self.groq_api_key: |
|
|
logger.warning("GROQ_API_KEY not set. Jade Heavy may fail.") |
|
|
|
|
|
self.groq_client = AsyncGroq(api_key=self.groq_api_key) |
|
|
|
|
|
self.mistral = None |
|
|
if self.mistral_api_key: |
|
|
self.mistral = Mistral(api_key=self.mistral_api_key) |
|
|
else: |
|
|
logger.warning("MISTRAL_API_KEY not set. Mistral model will be skipped or substituted.") |
|
|
|
|
|
self.openrouter = None |
|
|
if self.openrouter_api_key: |
|
|
self.openrouter = AsyncOpenAI( |
|
|
base_url="https://openrouter.ai/api/v1", |
|
|
api_key=self.openrouter_api_key, |
|
|
) |
|
|
else: |
|
|
logger.warning("OPENROUTER_API_KEY not set. Qwen/OpenRouter models will be skipped.") |
|
|
|
|
|
|
|
|
self.models = { |
|
|
"Kimi": "moonshotai/kimi-k2-instruct-0905", |
|
|
"Mistral": "mistral-large-latest", |
|
|
"Llama": "openai/gpt-oss-120b", |
|
|
"Qwen": "qwen/qwen3-coder:free" |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
self.judge_id = "moonshotai/kimi-k2-instruct-0905" |
|
|
|
|
|
async def _safe_propose(self, model_name, history_text): |
|
|
"""Phase 1: Strategic Planning""" |
|
|
|
|
|
delay_map = {"Kimi": 0, "Mistral": 1.0, "Llama": 2.0, "Qwen": 3.0} |
|
|
await asyncio.sleep(delay_map.get(model_name, 1) + random.uniform(0.1, 0.5)) |
|
|
|
|
|
sys_prompt = ( |
|
|
"You are a Strategic Architect. Create a high-level roadmap to answer the user's request comprehensively.\n" |
|
|
"DO NOT write the final response yet. Just plan the structure and key points.\n" |
|
|
"FORMAT: 1. [INTENT ANALYSIS] 2. [KEY POINTS] 3. [STRUCTURE PROPOSAL]" |
|
|
) |
|
|
|
|
|
messages = [{"role": "system", "content": sys_prompt}, {"role": "user", "content": history_text}] |
|
|
|
|
|
try: |
|
|
content = "" |
|
|
if model_name == "Mistral" and self.mistral: |
|
|
resp = await self.mistral.chat.complete_async(model=self.models["Mistral"], messages=messages) |
|
|
content = resp.choices[0].message.content |
|
|
elif model_name == "Qwen" and self.openrouter: |
|
|
|
|
|
resp = await self.openrouter.chat.completions.create(model="qwen/qwen3-235b-a22b:free", messages=messages) |
|
|
content = resp.choices[0].message.content |
|
|
else: |
|
|
|
|
|
|
|
|
target_model = self.models.get(model_name) |
|
|
if not target_model or (model_name == "Mistral" and not self.mistral) or (model_name == "Qwen" and not self.openrouter): |
|
|
target_model = "openai/gpt-oss-120b" |
|
|
|
|
|
resp = await self.groq_client.chat.completions.create( |
|
|
model=target_model, |
|
|
messages=messages, |
|
|
temperature=0.7 |
|
|
) |
|
|
content = resp.choices[0].message.content |
|
|
|
|
|
if content: |
|
|
return f"--- {model_name} Plan ---\n{content}" |
|
|
except Exception as e: |
|
|
logger.error(f"Error in propose ({model_name}): {e}") |
|
|
return "" |
|
|
return "" |
|
|
|
|
|
async def _safe_expand(self, model_name, history_text, strategy): |
|
|
"""Phase 3: Execution/Expansion""" |
|
|
delay_map = {"Kimi": 0, "Mistral": 1.5, "Llama": 3.0, "Qwen": 4.5} |
|
|
await asyncio.sleep(delay_map.get(model_name, 1)) |
|
|
|
|
|
sys_prompt = ( |
|
|
f"You are a Precision Engine. Execute the following plan to answer the user request:\n\n{strategy}\n\n" |
|
|
"Write a detailed, natural, and high-quality response following this plan.\n" |
|
|
"Do not output internal reasoning like '[DECOMPOSITION]', just the final response text." |
|
|
) |
|
|
|
|
|
messages = [{"role": "system", "content": sys_prompt}, {"role": "user", "content": history_text}] |
|
|
|
|
|
try: |
|
|
content = "" |
|
|
if model_name == "Mistral" and self.mistral: |
|
|
resp = await self.mistral.chat.complete_async(model=self.models["Mistral"], messages=messages) |
|
|
content = resp.choices[0].message.content |
|
|
elif model_name == "Qwen" and self.openrouter: |
|
|
resp = await self.openrouter.chat.completions.create(model="qwen/qwen3-coder:free", messages=messages) |
|
|
content = resp.choices[0].message.content |
|
|
else: |
|
|
target_model = self.models.get(model_name) |
|
|
if not target_model or (model_name == "Mistral" and not self.mistral) or (model_name == "Qwen" and not self.openrouter): |
|
|
target_model = "openai/gpt-oss-120b" |
|
|
|
|
|
resp = await self.groq_client.chat.completions.create( |
|
|
model=target_model, |
|
|
messages=messages, |
|
|
temperature=0.7 |
|
|
) |
|
|
content = resp.choices[0].message.content |
|
|
|
|
|
if content: |
|
|
return f"[{model_name} Draft]:\n{content}" |
|
|
except Exception as e: |
|
|
logger.error(f"Error in expand ({model_name}): {e}") |
|
|
return "" |
|
|
return "" |
|
|
|
|
|
async def respond(self, history, user_input, user_id="default", vision_context=None): |
|
|
""" |
|
|
Main entry point for the Heavy Agent. |
|
|
History is a list of dicts: [{"role": "user", "content": "..."}...] |
|
|
""" |
|
|
|
|
|
|
|
|
full_context = "" |
|
|
for msg in history[-6:]: |
|
|
full_context += f"{msg['role'].upper()}: {msg['content']}\n" |
|
|
|
|
|
if vision_context: |
|
|
full_context += f"SYSTEM (Vision): {vision_context}\n" |
|
|
|
|
|
full_context += f"USER: {user_input}\n" |
|
|
|
|
|
agents = ["Kimi", "Mistral", "Llama", "Qwen"] |
|
|
|
|
|
|
|
|
logger.info("Jade Heavy: Phase 1 - Planning...") |
|
|
tasks = [self._safe_propose(m, full_context) for m in agents] |
|
|
results = await asyncio.gather(*tasks) |
|
|
valid_strats = [s for s in results if s] |
|
|
|
|
|
if not valid_strats: |
|
|
return "Failed to generate a plan.", None, history |
|
|
|
|
|
|
|
|
logger.info("Jade Heavy: Phase 2 - Pruning...") |
|
|
prune_prompt = ( |
|
|
f"User Request Context:\n{full_context}\n\nProposed Plans:\n" + |
|
|
"\n".join(valid_strats) + |
|
|
"\n\nTASK: SELECT THE SINGLE MOST ROBUST AND HELPFUL PLAN. Return ONLY the content of the best plan." |
|
|
) |
|
|
try: |
|
|
best_strat_resp = await self.groq_client.chat.completions.create( |
|
|
model=self.judge_id, |
|
|
messages=[{"role":"user","content":prune_prompt}], |
|
|
temperature=0.5 |
|
|
) |
|
|
best_strat = best_strat_resp.choices[0].message.content |
|
|
except Exception as e: |
|
|
logger.error(f"Pruning failed: {e}") |
|
|
best_strat = valid_strats[0] |
|
|
|
|
|
|
|
|
logger.info("Jade Heavy: Phase 3 - Expansion...") |
|
|
tasks_exp = [self._safe_expand(m, full_context, best_strat) for m in agents] |
|
|
results_exp = await asyncio.gather(*tasks_exp) |
|
|
valid_sols = [s for s in results_exp if s] |
|
|
|
|
|
if not valid_sols: |
|
|
return "Failed to generate drafts.", None, history |
|
|
|
|
|
|
|
|
logger.info("Jade Heavy: Phase 4 - Verdict...") |
|
|
council_prompt = ( |
|
|
f"User Request:\n{full_context}\n\nCandidate Responses:\n" + |
|
|
"\n".join(valid_sols) + |
|
|
"\n\nTASK: Synthesize the best parts of these drafts into a FINAL, PERFECT RESPONSE." |
|
|
"The response should be natural, helpful, and high-quality. Do not mention the agents or the process." |
|
|
) |
|
|
|
|
|
final_answer = "" |
|
|
try: |
|
|
resp = await self.groq_client.chat.completions.create( |
|
|
model=self.judge_id, |
|
|
messages=[{"role":"system","content":"You are the Chief Editor."},{"role":"user","content":council_prompt}], |
|
|
temperature=0.5 |
|
|
) |
|
|
final_answer = resp.choices[0].message.content |
|
|
except Exception as e: |
|
|
logger.error(f"Verdict failed: {e}") |
|
|
final_answer = valid_sols[0].replace(f"[{agents[0]} Draft]:\n", "") |
|
|
|
|
|
|
|
|
history.append({"role": "user", "content": user_input}) |
|
|
history.append({"role": "assistant", "content": final_answer}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return final_answer, None, history |
|
|
|