helion: deepseek-first, on-demand CrewAI, local subagent profiles, concise post-synthesis
This commit is contained in:
@@ -64,7 +64,7 @@ helion:
|
|||||||
synthesis:
|
synthesis:
|
||||||
role_context: HELION Orchestrator
|
role_context: HELION Orchestrator
|
||||||
system_prompt_ref: roles/helion/orchestrator_synthesis.md
|
system_prompt_ref: roles/helion/orchestrator_synthesis.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
team:
|
team:
|
||||||
- id: energy_researcher
|
- id: energy_researcher
|
||||||
role_context: Energy Researcher
|
role_context: Energy Researcher
|
||||||
@@ -73,7 +73,7 @@ helion:
|
|||||||
- id: systems_modeler
|
- id: systems_modeler
|
||||||
role_context: Systems Modeler
|
role_context: Systems Modeler
|
||||||
system_prompt_ref: roles/helion/systems_modeler.md
|
system_prompt_ref: roles/helion/systems_modeler.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: policy_analyst
|
- id: policy_analyst
|
||||||
role_context: Policy Analyst
|
role_context: Policy Analyst
|
||||||
system_prompt_ref: roles/helion/policy_analyst.md
|
system_prompt_ref: roles/helion/policy_analyst.md
|
||||||
@@ -81,7 +81,7 @@ helion:
|
|||||||
- id: risk_assessor
|
- id: risk_assessor
|
||||||
role_context: Risk Assessor
|
role_context: Risk Assessor
|
||||||
system_prompt_ref: roles/helion/risk_assessor.md
|
system_prompt_ref: roles/helion/risk_assessor.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: communicator
|
- id: communicator
|
||||||
role_context: Communicator
|
role_context: Communicator
|
||||||
system_prompt_ref: roles/helion/communicator.md
|
system_prompt_ref: roles/helion/communicator.md
|
||||||
@@ -95,12 +95,12 @@ helion:
|
|||||||
synthesis:
|
synthesis:
|
||||||
role_context: Executive Synthesis (CEO-mode)
|
role_context: Executive Synthesis (CEO-mode)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_synthesis.md
|
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_synthesis.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
team:
|
team:
|
||||||
- id: orchestrator_front_desk_router
|
- id: orchestrator_front_desk_router
|
||||||
role_context: Orchestrator (Front Desk / Router)
|
role_context: Orchestrator (Front Desk / Router)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_front_desk_router.md
|
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_front_desk_router.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: knowledge_curator_rag_librarian
|
- id: knowledge_curator_rag_librarian
|
||||||
role_context: Knowledge Curator (L1–L3 RAG Librarian)
|
role_context: Knowledge Curator (L1–L3 RAG Librarian)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/knowledge_curator_rag_librarian.md
|
system_prompt_ref: roles/helion/HELION_CORE/knowledge_curator_rag_librarian.md
|
||||||
@@ -108,15 +108,15 @@ helion:
|
|||||||
- id: safety_anti_hallucination_gate
|
- id: safety_anti_hallucination_gate
|
||||||
role_context: Safety & Anti-Hallucination Gate
|
role_context: Safety & Anti-Hallucination Gate
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/safety_anti_hallucination_gate.md
|
system_prompt_ref: roles/helion/HELION_CORE/safety_anti_hallucination_gate.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: legal_compliance_gdpr_mica_aml_kyc
|
- id: legal_compliance_gdpr_mica_aml_kyc
|
||||||
role_context: Legal & Compliance (GDPR/MiCA/AML/KYC)
|
role_context: Legal & Compliance (GDPR/MiCA/AML/KYC)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/legal_compliance_gdpr_mica_aml_kyc.md
|
system_prompt_ref: roles/helion/HELION_CORE/legal_compliance_gdpr_mica_aml_kyc.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: security_anti_fraud_anti_fake
|
- id: security_anti_fraud_anti_fake
|
||||||
role_context: Security & Anti-Fraud / Anti-Fake
|
role_context: Security & Anti-Fraud / Anti-Fake
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/security_anti_fraud_anti_fake.md
|
system_prompt_ref: roles/helion/HELION_CORE/security_anti_fraud_anti_fake.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: energy_systems_engineer
|
- id: energy_systems_engineer
|
||||||
role_context: Energy Systems Engineer (GGU/BioMiner/SES)
|
role_context: Energy Systems Engineer (GGU/BioMiner/SES)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/energy_systems_engineer.md
|
system_prompt_ref: roles/helion/HELION_CORE/energy_systems_engineer.md
|
||||||
@@ -124,7 +124,7 @@ helion:
|
|||||||
- id: finance_roi_modeler
|
- id: finance_roi_modeler
|
||||||
role_context: Finance & ROI Modeler
|
role_context: Finance & ROI Modeler
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/finance_roi_modeler.md
|
system_prompt_ref: roles/helion/HELION_CORE/finance_roi_modeler.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: dao_guide_governance_onboarding
|
- id: dao_guide_governance_onboarding
|
||||||
role_context: DAO Guide (Governance & Onboarding)
|
role_context: DAO Guide (Governance & Onboarding)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/dao_guide_governance_onboarding.md
|
system_prompt_ref: roles/helion/HELION_CORE/dao_guide_governance_onboarding.md
|
||||||
@@ -132,7 +132,7 @@ helion:
|
|||||||
- id: tokenization_rwa_nft_architect
|
- id: tokenization_rwa_nft_architect
|
||||||
role_context: Tokenization & RWA/NFT Architect
|
role_context: Tokenization & RWA/NFT Architect
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/tokenization_rwa_nft_architect.md
|
system_prompt_ref: roles/helion/HELION_CORE/tokenization_rwa_nft_architect.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: growth_soft_selling_cx
|
- id: growth_soft_selling_cx
|
||||||
role_context: Growth & Soft-Selling CX
|
role_context: Growth & Soft-Selling CX
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/growth_soft_selling_cx.md
|
system_prompt_ref: roles/helion/HELION_CORE/growth_soft_selling_cx.md
|
||||||
|
|||||||
@@ -469,6 +469,18 @@ SENPAI_CONFIG = load_agent_config(
|
|||||||
default_prompt="Ти — Гордон Сенпай (Gordon Senpai), радник з ринків капіталу та цифрових активів. Допомагаєш з трейдингом, ризик-менеджментом, аналізом ринків.",
|
default_prompt="Ти — Гордон Сенпай (Gordon Senpai), радник з ринків капіталу та цифрових активів. Допомагаєш з трейдингом, ризик-менеджментом, аналізом ринків.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 1OK Configuration
|
||||||
|
ONEOK_CONFIG = load_agent_config(
|
||||||
|
agent_id="oneok",
|
||||||
|
name=os.getenv("ONEOK_NAME", "1OK"),
|
||||||
|
prompt_path=os.getenv(
|
||||||
|
"ONEOK_PROMPT_PATH",
|
||||||
|
str(Path(__file__).parent / "oneok_prompt.txt"),
|
||||||
|
),
|
||||||
|
telegram_token_env="ONEOK_TELEGRAM_BOT_TOKEN",
|
||||||
|
default_prompt="Ти — 1OK, асистент віконного майстра. Допомагаєш з кваліфікацією ліда, підготовкою заміру та формуванням комерційної пропозиції.",
|
||||||
|
)
|
||||||
|
|
||||||
# SOUL / Athena Configuration
|
# SOUL / Athena Configuration
|
||||||
SOUL_CONFIG = load_agent_config(
|
SOUL_CONFIG = load_agent_config(
|
||||||
agent_id="soul",
|
agent_id="soul",
|
||||||
@@ -517,6 +529,7 @@ AGENT_REGISTRY: Dict[str, AgentConfig] = {
|
|||||||
"clan": CLAN_CONFIG,
|
"clan": CLAN_CONFIG,
|
||||||
"eonarch": EONARCH_CONFIG,
|
"eonarch": EONARCH_CONFIG,
|
||||||
"senpai": SENPAI_CONFIG,
|
"senpai": SENPAI_CONFIG,
|
||||||
|
"oneok": ONEOK_CONFIG,
|
||||||
"soul": SOUL_CONFIG,
|
"soul": SOUL_CONFIG,
|
||||||
"yaromir": YAROMIR_CONFIG,
|
"yaromir": YAROMIR_CONFIG,
|
||||||
"sofiia": SOFIIA_CONFIG,
|
"sofiia": SOFIIA_CONFIG,
|
||||||
@@ -707,6 +720,11 @@ async def eonarch_telegram_webhook(update: TelegramUpdate):
|
|||||||
async def senpai_telegram_webhook(update: TelegramUpdate):
|
async def senpai_telegram_webhook(update: TelegramUpdate):
|
||||||
return await handle_telegram_webhook(SENPAI_CONFIG, update)
|
return await handle_telegram_webhook(SENPAI_CONFIG, update)
|
||||||
|
|
||||||
|
# 1OK webhook endpoint
|
||||||
|
@router.post("/oneok/telegram/webhook")
|
||||||
|
async def oneok_telegram_webhook(update: TelegramUpdate):
|
||||||
|
return await handle_telegram_webhook(ONEOK_CONFIG, update)
|
||||||
|
|
||||||
|
|
||||||
# SOUL / Athena webhook endpoint
|
# SOUL / Athena webhook endpoint
|
||||||
@router.post("/soul/telegram/webhook")
|
@router.post("/soul/telegram/webhook")
|
||||||
@@ -897,50 +915,6 @@ def _resolve_stt_upload_url() -> str:
|
|||||||
# Helper Functions
|
# Helper Functions
|
||||||
# ========================================
|
# ========================================
|
||||||
|
|
||||||
async def send_telegram_message(chat_id: str, text: str, bot_token: Optional[str] = None) -> bool:
|
|
||||||
"""
|
|
||||||
Відправити повідомлення в Telegram.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
chat_id: ID чату
|
|
||||||
text: Текст повідомлення
|
|
||||||
bot_token: Telegram bot token (якщо None, використовується TELEGRAM_BOT_TOKEN)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True якщо успішно, False інакше
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
token = bot_token or os.getenv("TELEGRAM_BOT_TOKEN")
|
|
||||||
if not token:
|
|
||||||
logger.error("TELEGRAM_BOT_TOKEN not set")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Strip <think>...</think> tags (DeepSeek reasoning leak)
|
|
||||||
import re
|
|
||||||
text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
|
|
||||||
text = re.sub(r'<think>.*$', '', text, flags=re.DOTALL) # unclosed tag
|
|
||||||
# Strip any DSML/XML-like markup
|
|
||||||
text = re.sub(r'</?(?:function_calls|invoke|parameter)[^>]*>', '', text)
|
|
||||||
text = text.strip()
|
|
||||||
if not text:
|
|
||||||
text = "..."
|
|
||||||
|
|
||||||
url = f"https://api.telegram.org/bot{token}/sendMessage"
|
|
||||||
payload = {
|
|
||||||
"chat_id": chat_id,
|
|
||||||
"text": text,
|
|
||||||
"parse_mode": "Markdown"
|
|
||||||
}
|
|
||||||
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
response = await client.post(url, json=payload, timeout=10.0)
|
|
||||||
response.raise_for_status()
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to send Telegram message: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
async def get_telegram_file_path(file_id: str, bot_token: Optional[str] = None) -> Optional[str]:
|
async def get_telegram_file_path(file_id: str, bot_token: Optional[str] = None) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Отримати шлях до файлу з Telegram API.
|
Отримати шлях до файлу з Telegram API.
|
||||||
@@ -2491,7 +2465,11 @@ async def handle_telegram_webhook(
|
|||||||
+ "\n(Не потрібно щоразу представлятися по імені або писати шаблонне: 'чим можу допомогти'.)"
|
+ "\n(Не потрібно щоразу представлятися по імені або писати шаблонне: 'чим можу допомогти'.)"
|
||||||
)
|
)
|
||||||
|
|
||||||
if needs_complex_reasoning:
|
# Helion policy: DeepSeek-first primary response path.
|
||||||
|
if agent_config.agent_id == "helion":
|
||||||
|
router_request["metadata"]["provider"] = "cloud_deepseek"
|
||||||
|
router_request["metadata"]["reason"] = "helion_primary_deepseek"
|
||||||
|
elif needs_complex_reasoning:
|
||||||
router_request["metadata"]["provider"] = "cloud_deepseek"
|
router_request["metadata"]["provider"] = "cloud_deepseek"
|
||||||
router_request["metadata"]["reason"] = "auto_complex"
|
router_request["metadata"]["reason"] = "auto_complex"
|
||||||
|
|
||||||
@@ -3546,27 +3524,52 @@ async def _artifact_job_done(job_id: str, note: str) -> None:
|
|||||||
raise HTTPException(status_code=502, detail=f"Job done error: {resp.text[:200]}")
|
raise HTTPException(status_code=502, detail=f"Job done error: {resp.text[:200]}")
|
||||||
|
|
||||||
|
|
||||||
async def send_telegram_message(chat_id: str, text: str, bot_token: str = None):
|
async def send_telegram_message(chat_id: str, text: str, bot_token: Optional[str] = None) -> bool:
|
||||||
"""Send message to Telegram chat"""
|
"""Send message to Telegram chat with explicit error diagnostics."""
|
||||||
telegram_token = bot_token or os.getenv("TELEGRAM_BOT_TOKEN")
|
telegram_token = bot_token or os.getenv("TELEGRAM_BOT_TOKEN")
|
||||||
if not telegram_token:
|
if not telegram_token:
|
||||||
logger.error("TELEGRAM_BOT_TOKEN not set")
|
logger.error("TELEGRAM_BOT_TOKEN not set")
|
||||||
return
|
return False
|
||||||
|
|
||||||
|
# Defensive cleanup for occasional reasoning/markup leaks.
|
||||||
|
import re
|
||||||
|
safe_text = re.sub(r'<think>.*?</think>', '', text or "", flags=re.DOTALL)
|
||||||
|
safe_text = re.sub(r'<think>.*$', '', safe_text, flags=re.DOTALL)
|
||||||
|
safe_text = safe_text.strip() or "..."
|
||||||
|
|
||||||
|
token_id = telegram_token.split(":", 1)[0] if ":" in telegram_token else "unknown"
|
||||||
url = f"https://api.telegram.org/bot{telegram_token}/sendMessage"
|
url = f"https://api.telegram.org/bot{telegram_token}/sendMessage"
|
||||||
payload = {
|
payload = {
|
||||||
"chat_id": chat_id,
|
"chat_id": str(chat_id),
|
||||||
"text": text,
|
"text": safe_text,
|
||||||
# "parse_mode": "Markdown", # Removed to prevent 400 errors
|
"disable_web_page_preview": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
response = await client.post(url, json=payload, timeout=10.0)
|
response = await client.post(url, json=payload, timeout=15.0)
|
||||||
response.raise_for_status()
|
|
||||||
logger.info(f"Telegram message sent to chat {chat_id}")
|
if response.status_code >= 400:
|
||||||
|
err_desc = response.text[:300]
|
||||||
|
try:
|
||||||
|
body = response.json()
|
||||||
|
err_desc = body.get("description") or err_desc
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
logger.error(
|
||||||
|
"Telegram sendMessage failed: bot_id=%s chat_id=%s status=%s desc=%s",
|
||||||
|
token_id,
|
||||||
|
chat_id,
|
||||||
|
response.status_code,
|
||||||
|
err_desc,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
logger.info("Telegram message sent: bot_id=%s chat_id=%s", token_id, chat_id)
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error sending Telegram message: {e}")
|
logger.error("Telegram sendMessage exception: bot_id=%s chat_id=%s error=%s", token_id, chat_id, e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
# ========================================
|
# ========================================
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ GATEWAY_MAX_TOKENS_CONCISE = int(os.getenv("GATEWAY_MAX_TOKENS_CONCISE", "220"))
|
|||||||
GATEWAY_MAX_TOKENS_TRAINING = int(os.getenv("GATEWAY_MAX_TOKENS_TRAINING", "900"))
|
GATEWAY_MAX_TOKENS_TRAINING = int(os.getenv("GATEWAY_MAX_TOKENS_TRAINING", "900"))
|
||||||
GATEWAY_TEMPERATURE_DEFAULT = float(os.getenv("GATEWAY_TEMPERATURE_DEFAULT", "0.4"))
|
GATEWAY_TEMPERATURE_DEFAULT = float(os.getenv("GATEWAY_TEMPERATURE_DEFAULT", "0.4"))
|
||||||
GATEWAY_MAX_TOKENS_SENPAI_DEFAULT = int(os.getenv("GATEWAY_MAX_TOKENS_SENPAI_DEFAULT", "320"))
|
GATEWAY_MAX_TOKENS_SENPAI_DEFAULT = int(os.getenv("GATEWAY_MAX_TOKENS_SENPAI_DEFAULT", "320"))
|
||||||
|
GATEWAY_MAX_TOKENS_HELION_DEFAULT = int(os.getenv("GATEWAY_MAX_TOKENS_HELION_DEFAULT", "240"))
|
||||||
GATEWAY_MAX_TOKENS_DETAILED = int(os.getenv("GATEWAY_MAX_TOKENS_DETAILED", "900"))
|
GATEWAY_MAX_TOKENS_DETAILED = int(os.getenv("GATEWAY_MAX_TOKENS_DETAILED", "900"))
|
||||||
|
|
||||||
|
|
||||||
@@ -87,6 +88,8 @@ async def send_to_router(body: Dict[str, Any]) -> Dict[str, Any]:
|
|||||||
# Senpai tends to over-verbose responses in Telegram; use lower default unless user asked details.
|
# Senpai tends to over-verbose responses in Telegram; use lower default unless user asked details.
|
||||||
if agent_id == "senpai":
|
if agent_id == "senpai":
|
||||||
max_tokens = GATEWAY_MAX_TOKENS_SENPAI_DEFAULT
|
max_tokens = GATEWAY_MAX_TOKENS_SENPAI_DEFAULT
|
||||||
|
elif agent_id == "helion":
|
||||||
|
max_tokens = min(max_tokens, GATEWAY_MAX_TOKENS_HELION_DEFAULT)
|
||||||
|
|
||||||
if metadata.get("is_training_group"):
|
if metadata.get("is_training_group"):
|
||||||
max_tokens = GATEWAY_MAX_TOKENS_TRAINING
|
max_tokens = GATEWAY_MAX_TOKENS_TRAINING
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ helion:
|
|||||||
synthesis:
|
synthesis:
|
||||||
role_context: HELION Orchestrator
|
role_context: HELION Orchestrator
|
||||||
system_prompt_ref: roles/helion/orchestrator_synthesis.md
|
system_prompt_ref: roles/helion/orchestrator_synthesis.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
team:
|
team:
|
||||||
- id: energy_researcher
|
- id: energy_researcher
|
||||||
role_context: Energy Researcher
|
role_context: Energy Researcher
|
||||||
@@ -70,7 +70,7 @@ helion:
|
|||||||
- id: systems_modeler
|
- id: systems_modeler
|
||||||
role_context: Systems Modeler
|
role_context: Systems Modeler
|
||||||
system_prompt_ref: roles/helion/systems_modeler.md
|
system_prompt_ref: roles/helion/systems_modeler.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: policy_analyst
|
- id: policy_analyst
|
||||||
role_context: Policy Analyst
|
role_context: Policy Analyst
|
||||||
system_prompt_ref: roles/helion/policy_analyst.md
|
system_prompt_ref: roles/helion/policy_analyst.md
|
||||||
@@ -78,7 +78,7 @@ helion:
|
|||||||
- id: risk_assessor
|
- id: risk_assessor
|
||||||
role_context: Risk Assessor
|
role_context: Risk Assessor
|
||||||
system_prompt_ref: roles/helion/risk_assessor.md
|
system_prompt_ref: roles/helion/risk_assessor.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: communicator
|
- id: communicator
|
||||||
role_context: Communicator
|
role_context: Communicator
|
||||||
system_prompt_ref: roles/helion/communicator.md
|
system_prompt_ref: roles/helion/communicator.md
|
||||||
@@ -92,12 +92,12 @@ helion:
|
|||||||
synthesis:
|
synthesis:
|
||||||
role_context: Executive Synthesis (CEO-mode)
|
role_context: Executive Synthesis (CEO-mode)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_synthesis.md
|
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_synthesis.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
team:
|
team:
|
||||||
- id: orchestrator_front_desk_router
|
- id: orchestrator_front_desk_router
|
||||||
role_context: Orchestrator (Front Desk / Router)
|
role_context: Orchestrator (Front Desk / Router)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_front_desk_router.md
|
system_prompt_ref: roles/helion/HELION_CORE/orchestrator_front_desk_router.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: knowledge_curator_rag_librarian
|
- id: knowledge_curator_rag_librarian
|
||||||
role_context: Knowledge Curator (L1–L3 RAG Librarian)
|
role_context: Knowledge Curator (L1–L3 RAG Librarian)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/knowledge_curator_rag_librarian.md
|
system_prompt_ref: roles/helion/HELION_CORE/knowledge_curator_rag_librarian.md
|
||||||
@@ -105,15 +105,15 @@ helion:
|
|||||||
- id: safety_anti_hallucination_gate
|
- id: safety_anti_hallucination_gate
|
||||||
role_context: Safety & Anti-Hallucination Gate
|
role_context: Safety & Anti-Hallucination Gate
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/safety_anti_hallucination_gate.md
|
system_prompt_ref: roles/helion/HELION_CORE/safety_anti_hallucination_gate.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: legal_compliance_gdpr_mica_aml_kyc
|
- id: legal_compliance_gdpr_mica_aml_kyc
|
||||||
role_context: Legal & Compliance (GDPR/MiCA/AML/KYC)
|
role_context: Legal & Compliance (GDPR/MiCA/AML/KYC)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/legal_compliance_gdpr_mica_aml_kyc.md
|
system_prompt_ref: roles/helion/HELION_CORE/legal_compliance_gdpr_mica_aml_kyc.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: security_anti_fraud_anti_fake
|
- id: security_anti_fraud_anti_fake
|
||||||
role_context: Security & Anti-Fraud / Anti-Fake
|
role_context: Security & Anti-Fraud / Anti-Fake
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/security_anti_fraud_anti_fake.md
|
system_prompt_ref: roles/helion/HELION_CORE/security_anti_fraud_anti_fake.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: energy_systems_engineer
|
- id: energy_systems_engineer
|
||||||
role_context: Energy Systems Engineer (GGU/BioMiner/SES)
|
role_context: Energy Systems Engineer (GGU/BioMiner/SES)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/energy_systems_engineer.md
|
system_prompt_ref: roles/helion/HELION_CORE/energy_systems_engineer.md
|
||||||
@@ -121,7 +121,7 @@ helion:
|
|||||||
- id: finance_roi_modeler
|
- id: finance_roi_modeler
|
||||||
role_context: Finance & ROI Modeler
|
role_context: Finance & ROI Modeler
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/finance_roi_modeler.md
|
system_prompt_ref: roles/helion/HELION_CORE/finance_roi_modeler.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: dao_guide_governance_onboarding
|
- id: dao_guide_governance_onboarding
|
||||||
role_context: DAO Guide (Governance & Onboarding)
|
role_context: DAO Guide (Governance & Onboarding)
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/dao_guide_governance_onboarding.md
|
system_prompt_ref: roles/helion/HELION_CORE/dao_guide_governance_onboarding.md
|
||||||
@@ -129,7 +129,7 @@ helion:
|
|||||||
- id: tokenization_rwa_nft_architect
|
- id: tokenization_rwa_nft_architect
|
||||||
role_context: Tokenization & RWA/NFT Architect
|
role_context: Tokenization & RWA/NFT Architect
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/tokenization_rwa_nft_architect.md
|
system_prompt_ref: roles/helion/HELION_CORE/tokenization_rwa_nft_architect.md
|
||||||
llm_profile: reasoning
|
llm_profile: science
|
||||||
- id: growth_soft_selling_cx
|
- id: growth_soft_selling_cx
|
||||||
role_context: Growth & Soft-Selling CX
|
role_context: Growth & Soft-Selling CX
|
||||||
system_prompt_ref: roles/helion/HELION_CORE/growth_soft_selling_cx.md
|
system_prompt_ref: roles/helion/HELION_CORE/growth_soft_selling_cx.md
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ logger = logging.getLogger(__name__)
|
|||||||
CREWAI_URL = os.getenv("CREWAI_URL", "http://dagi-staging-crewai-service:9010")
|
CREWAI_URL = os.getenv("CREWAI_URL", "http://dagi-staging-crewai-service:9010")
|
||||||
CREWAI_ENABLED = os.getenv("CREWAI_ENABLED", "true").lower() == "true"
|
CREWAI_ENABLED = os.getenv("CREWAI_ENABLED", "true").lower() == "true"
|
||||||
CREWAI_ORCHESTRATORS_ALWAYS = os.getenv("CREWAI_ORCHESTRATORS_ALWAYS", "true").lower() == "true"
|
CREWAI_ORCHESTRATORS_ALWAYS = os.getenv("CREWAI_ORCHESTRATORS_ALWAYS", "true").lower() == "true"
|
||||||
|
HELION_CREWAI_TEAM_LIMIT = int(os.getenv("HELION_CREWAI_TEAM_LIMIT", "3"))
|
||||||
|
|
||||||
CREWAI_AGENTS_PATH = os.getenv("CREWAI_AGENTS_PATH", "/config/crewai_agents.json")
|
CREWAI_AGENTS_PATH = os.getenv("CREWAI_AGENTS_PATH", "/config/crewai_agents.json")
|
||||||
FALLBACK_CREWAI_PATH = "/app/config/crewai_agents.json"
|
FALLBACK_CREWAI_PATH = "/app/config/crewai_agents.json"
|
||||||
@@ -90,6 +91,19 @@ def should_use_crewai(agent_id, prompt, agent_config, metadata=None, force_crewa
|
|||||||
if not team:
|
if not team:
|
||||||
return False, "agent_has_no_team"
|
return False, "agent_has_no_team"
|
||||||
|
|
||||||
|
metadata = metadata or {}
|
||||||
|
force_detailed = bool(metadata.get("force_detailed"))
|
||||||
|
requires_complex = bool(metadata.get("requires_complex_reasoning"))
|
||||||
|
|
||||||
|
# Helion policy: DeepSeek direct path by default; CrewAI only on-demand.
|
||||||
|
# This keeps first-touch replies fast and concise.
|
||||||
|
if agent_id == "helion":
|
||||||
|
prompt_lower = prompt.lower()
|
||||||
|
has_complexity = any(kw in prompt_lower for kw in COMPLEXITY_KEYWORDS)
|
||||||
|
if force_detailed or requires_complex or has_complexity:
|
||||||
|
return True, "helion_complex_or_detailed"
|
||||||
|
return False, "helion_direct_deepseek_first"
|
||||||
|
|
||||||
# Architecture mode: top-level orchestrators go through CrewAI API by default.
|
# Architecture mode: top-level orchestrators go through CrewAI API by default.
|
||||||
if CREWAI_ORCHESTRATORS_ALWAYS:
|
if CREWAI_ORCHESTRATORS_ALWAYS:
|
||||||
return True, "orchestrator_default_crewai"
|
return True, "orchestrator_default_crewai"
|
||||||
@@ -111,9 +125,15 @@ async def call_crewai(agent_id, task, context=None, team=None, profile=None):
|
|||||||
if not team:
|
if not team:
|
||||||
crewai_info = get_agent_crewai_info(agent_id)
|
crewai_info = get_agent_crewai_info(agent_id)
|
||||||
team = crewai_info.get("team", [])
|
team = crewai_info.get("team", [])
|
||||||
|
|
||||||
|
effective_context = context or {}
|
||||||
|
metadata = (effective_context.get("metadata", {}) or {})
|
||||||
|
force_detailed = bool(metadata.get("force_detailed"))
|
||||||
|
# Helion policy: limit CrewAI participants unless user requested detailed mode.
|
||||||
|
if agent_id == "helion" and not force_detailed and HELION_CREWAI_TEAM_LIMIT > 0 and len(team) > HELION_CREWAI_TEAM_LIMIT:
|
||||||
|
team = team[:HELION_CREWAI_TEAM_LIMIT]
|
||||||
|
|
||||||
async with httpx.AsyncClient(timeout=600.0) as client:
|
async with httpx.AsyncClient(timeout=600.0) as client:
|
||||||
effective_context = context or {}
|
|
||||||
effective_profile = profile or (effective_context.get("metadata", {}) or {}).get("crewai_profile")
|
effective_profile = profile or (effective_context.get("metadata", {}) or {}).get("crewai_profile")
|
||||||
if not effective_profile and agent_id == "clan":
|
if not effective_profile and agent_id == "clan":
|
||||||
effective_profile = "zhos_mvp"
|
effective_profile = "zhos_mvp"
|
||||||
|
|||||||
@@ -1412,6 +1412,17 @@ async def agent_infer(agent_id: str, request: InferRequest):
|
|||||||
if isinstance(row, dict):
|
if isinstance(row, dict):
|
||||||
logger.info(json.dumps(row, ensure_ascii=False))
|
logger.info(json.dumps(row, ensure_ascii=False))
|
||||||
logger.info(f"✅ CrewAI success for {agent_id}: {latency:.2f}s")
|
logger.info(f"✅ CrewAI success for {agent_id}: {latency:.2f}s")
|
||||||
|
final_response_text = crew_result["result"]
|
||||||
|
# Helion: keep first-touch answers short by default, even after CrewAI.
|
||||||
|
if (
|
||||||
|
agent_id == "helion"
|
||||||
|
and isinstance(final_response_text, str)
|
||||||
|
and effective_metadata.get("force_concise")
|
||||||
|
and not effective_metadata.get("force_detailed")
|
||||||
|
):
|
||||||
|
parts = re.split(r"(?<=[.!?])\s+", final_response_text.strip())
|
||||||
|
if len(parts) > 3:
|
||||||
|
final_response_text = " ".join(parts[:3]).strip()
|
||||||
|
|
||||||
# Store interaction in memory
|
# Store interaction in memory
|
||||||
if MEMORY_RETRIEVAL_AVAILABLE and memory_retrieval and chat_id and user_id:
|
if MEMORY_RETRIEVAL_AVAILABLE and memory_retrieval and chat_id and user_id:
|
||||||
@@ -1423,13 +1434,13 @@ async def agent_infer(agent_id: str, request: InferRequest):
|
|||||||
agent_id=request_agent_id,
|
agent_id=request_agent_id,
|
||||||
username=username,
|
username=username,
|
||||||
user_message=request.prompt,
|
user_message=request.prompt,
|
||||||
assistant_response=crew_result["result"]
|
assistant_response=final_response_text
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"⚠️ Memory storage failed: {e}")
|
logger.warning(f"⚠️ Memory storage failed: {e}")
|
||||||
|
|
||||||
return InferResponse(
|
return InferResponse(
|
||||||
response=crew_result["result"],
|
response=final_response_text,
|
||||||
model="crewai-" + agent_id,
|
model="crewai-" + agent_id,
|
||||||
backend="crewai",
|
backend="crewai",
|
||||||
tokens_used=0
|
tokens_used=0
|
||||||
|
|||||||
Reference in New Issue
Block a user