PITCHFIGHT_AI / core /model_router.py
Aspectgg's picture
Update UI
8c81e76
Raw
History Blame Contribute Delete
29.1 kB
"""Central model routing layer for PitchFight AI.
Routes task requests to the correct model client based on model_mode.
All model calls are backend-only. Frontend never calls this layer directly.
Supported mode keys:
premium_nvidia — NVIDIA Nemotron 3 Nano Omni 30B-A3B (default)
openbmb_omni — MiniCPM-o 4.5 (Phase 9)
tiny_minicpm — MiniCPM5-1B (Phase 9)
vision_deck — MiniCPM-V 4.6 (Phase 10)
whisper_fallback — faster-whisper transcription (Phase 7)
"""
from __future__ import annotations
import logging
import os
from typing import Any
from dotenv import load_dotenv
from core import nvidia_client
from core import minicpm_client
from core import vision_client
from core import transcription_client
load_dotenv()
logger = logging.getLogger(__name__)
SUPPORTED_MODES = {
"premium_nvidia",
"openbmb_omni",
"tiny_minicpm",
"vision_deck",
"whisper_fallback",
}
_FALLBACK_OPPONENT_MESSAGE = (
"Your answer lacked specificity. "
"What concrete proof — a metric, a test result, or a user quote — "
"can you give me right now to back that claim?"
)
_FALLBACK_SCORECARD: dict[str, Any] = {
"overall": 0,
"scores": {},
"best_answer": "Model scoring unavailable.",
"weakest_answer": "",
"improved_answer": "",
"improved_pitch": "",
"top_3_questions": [],
"_fallback": True,
}
def get_default_model_mode() -> str:
"""Return the configured default model mode."""
mode = os.getenv("DEFAULT_MODEL_MODE", "premium_nvidia").strip()
return mode if mode in SUPPORTED_MODES else "premium_nvidia"
def get_model_health() -> dict[str, Any]:
"""Return health status for all model clients (no keys exposed)."""
return {
"default_mode": get_default_model_mode(),
"supported_modes": sorted(SUPPORTED_MODES),
"providers": {
"nvidia": nvidia_client.health_check(),
"minicpm": minicpm_client.health_check(),
"vision": vision_client.health_check(),
"transcription": transcription_client.health_check(),
},
}
def _resolve_mode(model_mode: str | None) -> str:
"""Validate and return a mode key, falling back to default if invalid."""
if model_mode and model_mode in SUPPORTED_MODES:
return model_mode
default = get_default_model_mode()
if model_mode and model_mode not in SUPPORTED_MODES:
logger.warning(
"Unknown model_mode '%s', falling back to '%s'", model_mode, default
)
return default
def generate_opponent_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
persona: str | None = None,
attack_tag: str | None = None,
) -> dict[str, Any]:
"""Route an opponent-turn request to the correct model client.
Returns a result dict:
ok — bool, True on success
model_mode — the mode key used
provider — which provider was called
content — the model's text response
error — None on success, error description on failure
"""
mode = _resolve_mode(model_mode)
if mode == "premium_nvidia":
return _call_nvidia_opponent(messages, mode)
if mode in ("openbmb_omni", "tiny_minicpm"):
return _placeholder_result(
mode,
"openbmb",
f"OpenBMB mode '{mode}' is planned for Phase 9.",
)
if mode == "vision_deck":
return _placeholder_result(
mode,
"openbmb",
"Vision/deck mode is planned for Phase 10.",
)
if mode == "whisper_fallback":
return _placeholder_result(
mode,
"local",
"Whisper fallback is planned for Phase 7.",
)
return _placeholder_result(mode, "unknown", f"Unsupported mode: {mode}")
def generate_scorecard_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
"""Route a scorecard-generation request to the correct model client."""
mode = _resolve_mode(model_mode)
if mode == "premium_nvidia":
return _call_nvidia_scorecard(messages, mode)
return _placeholder_result(
mode,
"mock",
f"Scorecard via '{mode}' is not yet implemented. Using mock scorecard.",
)
def generate_scoring_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
"""Route a dimension-scoring-only request (mode=scorecard_scoring).
Nemotron judges all 6 dimensions from actual Q&A. Returns scores + best/weakest only.
Coaching fields (improved_answer, improved_pitch, top_3_questions) are NOT included.
"""
mode = _resolve_mode(model_mode)
if mode == "premium_nvidia":
try:
content = nvidia_client.generate_nemotron_response(
messages, mode="scorecard_scoring"
)
return {"ok": True, "model_mode": mode, "provider": "nvidia", "content": content, "error": None}
except RuntimeError as exc:
logger.warning("NVIDIA scoring call failed: %s", exc)
return {"ok": False, "model_mode": mode, "provider": "nvidia", "content": "", "error": str(exc)}
return _placeholder_result(mode, "mock", f"Scoring via '{mode}' not implemented.")
def generate_scoring_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
"""Repair a broken scoring-only JSON response (mode=scorecard_scoring_repair)."""
mode = _resolve_mode(model_mode)
if mode != "premium_nvidia":
return _placeholder_result(mode, "mock", "Scoring repair only for premium_nvidia.")
repair_messages = [
{
"role": "system",
"content": (
"You are a JSON formatter. Convert the input into the exact schema below. "
"Return ONLY valid JSON. First character must be { last must be }. "
"No markdown. No explanation.\n\n"
"REQUIRED SCHEMA:\n"
'{"scores":{"clarity":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"problem_understanding":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"market_awareness":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"differentiation":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"business_model":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"objection_handling":{"score":0,"reason":"","quote":"","signals_used":[]}},'
'"best_answer":"","weakest_answer":"","why_weak":""}'
),
},
{
"role": "user",
"content": "Convert this text into the JSON schema. Output JSON only:\n\n" + raw_bad_content[:4000],
},
]
try:
content = nvidia_client.generate_nemotron_response(repair_messages, mode="scorecard_scoring_repair")
return {"ok": True, "model_mode": mode, "provider": "nvidia", "content": content, "error": None}
except RuntimeError as exc:
logger.warning("NVIDIA scoring repair call failed: %s", exc)
return {"ok": False, "model_mode": mode, "provider": "nvidia", "content": "", "error": str(exc)}
def generate_full_scorecard_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
"""Route a full Nemotron scoring request (mode=scorecard_full).
Nemotron judges all 6 dimensions from the actual Q&A conversation.
Returns the full scorecard JSON including scores + coaching + score_explanation.
"""
mode = _resolve_mode(model_mode)
if mode == "premium_nvidia":
try:
content = nvidia_client.generate_nemotron_response(
messages, mode="scorecard_full"
)
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA full scorecard call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
}
return _placeholder_result(mode, "mock", f"Full scorecard via '{mode}' not implemented.")
def generate_full_scorecard_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
"""Repair a broken full scorecard JSON using mode=scorecard_full_repair."""
mode = _resolve_mode(model_mode)
if mode != "premium_nvidia":
return _placeholder_result(mode, "mock", "Full scorecard repair only for premium_nvidia.")
repair_messages = [
{
"role": "system",
"content": (
"You are a JSON formatter. Convert the input into the exact schema below. "
"Return ONLY valid JSON. First character must be { last must be }. "
"No markdown. No explanation. No preface.\n\n"
"REQUIRED SCHEMA (fill all fields, use 0 for missing scores, empty string for text):\n"
'{"scores":{"clarity":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"problem_understanding":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"market_awareness":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"differentiation":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"business_model":{"score":0,"reason":"","quote":"","signals_used":[]},'
'"objection_handling":{"score":0,"reason":"","quote":"","signals_used":[]}},'
'"best_answer":"","weakest_answer":"","why_weak":"",'
'"improved_answer":"","improved_pitch":"","top_3_questions":["","",""],'
'"score_explanation":{"why_you_scored_this":"","what_stopped_80":"",'
'"answer_to_retry":{"round":null,"attack_tag":"","dimension":"","original_answer":"",'
'"why_it_hurt":"","retry_advice":"","sample_stronger_answer":""},'
'"estimated_score_if_fixed":{"current_overall":0,"estimated_new_overall":0,"reason":""}}}'
),
},
{
"role": "user",
"content": "Convert this text into the JSON schema. Output JSON only:\n\n" + raw_bad_content[:5000],
},
]
try:
content = nvidia_client.generate_nemotron_response(
repair_messages, mode="scorecard_full_repair"
)
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA full scorecard repair call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
}
def generate_coaching_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
"""Route a coaching-JSON request to Nemotron (mode=scorecard_coaching).
Nemotron generates only: improved_answer, improved_pitch, top_3_questions.
Thinking is OFF for this mode — direct JSON output is faster and more reliable.
"""
mode = _resolve_mode(model_mode)
if mode == "premium_nvidia":
try:
content = nvidia_client.generate_nemotron_response(
messages, mode="scorecard_coaching"
)
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA coaching call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
}
return _placeholder_result(mode, "mock", f"Coaching via '{mode}' not implemented.")
def generate_coaching_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
"""Repair a non-JSON coaching response into valid JSON (mode=scorecard_coaching_repair)."""
mode = _resolve_mode(model_mode)
if mode != "premium_nvidia":
return _placeholder_result(mode, "mock", "Coaching repair only available for premium_nvidia.")
repair_messages = [
{
"role": "system",
"content": (
"You are a JSON formatter. Convert the input text into the exact JSON schema below. "
"Return ONLY valid JSON. First character must be { and last must be }. "
"No markdown. No explanation. No preface.\n\n"
"REQUIRED SCHEMA:\n"
'{"improved_answer":"","improved_pitch":"","top_3_questions":["","",""],'
'"score_explanation":{"why_you_scored_this":"","what_stopped_80":"",'
'"answer_to_retry":{"round":null,"attack_tag":"","dimension":"","original_answer":"",'
'"why_it_hurt":"","retry_advice":"","sample_stronger_answer":""},'
'"estimated_score_if_fixed":{"current_overall":0,"estimated_new_overall":0,"reason":""}}}'
),
},
{
"role": "user",
"content": (
"Convert this text into the JSON schema. Output JSON only:\n\n"
+ raw_bad_content[:4000]
),
},
]
try:
content = nvidia_client.generate_nemotron_response(
repair_messages, mode="scorecard_coaching_repair"
)
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA coaching repair call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
}
def generate_scorecard_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
"""Ask Nemotron to repair a non-JSON scorecard response into valid JSON.
Called when the primary scorecard call returns content that cannot be parsed.
Uses temperature=0.0 and mode='scorecard_repair' for a deterministic rewrite.
Voice mode note:
Input is model text output — no source-specific changes needed.
"""
mode = _resolve_mode(model_mode)
if mode != "premium_nvidia":
return _placeholder_result(mode, "mock", "Repair only available for premium_nvidia.")
repair_messages = [
{
"role": "system",
"content": (
"You are a JSON formatter. "
"Convert the input text into the exact JSON schema shown below. "
"Return ONLY valid JSON. The first character must be { and the last must be }. "
"No markdown. No explanation. No preface. No chain-of-thought. "
"Fill every field. Use 0 for missing scores. Use empty string for missing text.\n\n"
"REQUIRED SCHEMA:\n"
'{\n'
' "overall": 0,\n'
' "scores": {\n'
' "clarity": {"score": 0, "reason": "", "quote": "", "signals_used": []},\n'
' "problem_understanding": {"score": 0, "reason": "", "quote": "", "signals_used": []},\n'
' "market_awareness": {"score": 0, "reason": "", "quote": "", "signals_used": []},\n'
' "differentiation": {"score": 0, "reason": "", "quote": "", "signals_used": []},\n'
' "business_model": {"score": 0, "reason": "", "quote": "", "signals_used": []},\n'
' "objection_handling": {"score": 0, "reason": "", "quote": "", "signals_used": []}\n'
' },\n'
' "best_answer": "",\n'
' "weakest_answer": "",\n'
' "why_weak": "",\n'
' "improved_answer": "",\n'
' "improved_pitch": "",\n'
' "top_3_questions": ["", "", ""]\n'
"}"
),
},
{
"role": "user",
"content": (
"Convert this text into the JSON schema. "
"Extract scores and reasoning from the text below. "
"Output JSON only:\n\n"
+ raw_bad_content[:6000]
),
},
]
try:
content = nvidia_client.generate_nemotron_response(
repair_messages,
mode="scorecard_repair",
)
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA scorecard repair call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
}
def generate_retry_comparison_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
"""Route a retry answer comparison request (mode=retry_comparison)."""
mode = _resolve_mode(model_mode)
if mode == "premium_nvidia":
try:
content = nvidia_client.generate_nemotron_response(
messages, mode="retry_comparison"
)
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA retry comparison call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
}
return _placeholder_result(mode, "mock", f"Retry comparison via '{mode}' not implemented.")
def generate_retry_comparison_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
"""Repair a broken retry comparison JSON (mode=retry_comparison_repair)."""
mode = _resolve_mode(model_mode)
if mode != "premium_nvidia":
return _placeholder_result(mode, "mock", "Retry comparison repair only for premium_nvidia.")
repair_messages = [
{
"role": "system",
"content": (
"You are a JSON formatter. Convert the input into the exact schema below. "
"Return ONLY valid JSON. First character must be { last must be }.\n\n"
"REQUIRED SCHEMA:\n"
'{"comparison":{"old_answer_summary":"","new_answer_summary":"","what_improved":"",'
'"still_missing":"","specific_tip":"","estimated_dimension_before":0,'
'"estimated_dimension_after":0,"estimated_overall_lift":0,'
'"verdict":"improved|slightly_improved|needs_more_work"},'
'"next_practice_prompt":""}'
),
},
{
"role": "user",
"content": "Convert this text into the JSON schema. Output JSON only:\n\n" + raw_bad_content[:4000],
},
]
try:
content = nvidia_client.generate_nemotron_response(
repair_messages, mode="retry_comparison_repair"
)
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA retry comparison repair call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
}
def _call_nvidia_json_mode(
messages: list[dict[str, str]],
nemotron_mode: str,
model_mode: str | None,
label: str,
) -> dict[str, Any]:
mode = _resolve_mode(model_mode)
if mode != "premium_nvidia":
return _placeholder_result(mode, "mock", f"{label} only for premium_nvidia.")
try:
content = nvidia_client.generate_nemotron_response(messages, mode=nemotron_mode)
return {"ok": True, "model_mode": mode, "provider": "nvidia", "content": content, "error": None}
except RuntimeError as exc:
logger.warning("NVIDIA %s call failed: %s", label, exc)
return {"ok": False, "model_mode": mode, "provider": "nvidia", "content": "", "error": str(exc)}
def _call_nvidia_repair_mode(
repair_messages: list[dict[str, str]],
nemotron_mode: str,
model_mode: str | None,
label: str,
) -> dict[str, Any]:
mode = _resolve_mode(model_mode)
if mode != "premium_nvidia":
return _placeholder_result(mode, "mock", f"{label} repair only for premium_nvidia.")
try:
content = nvidia_client.generate_nemotron_response(repair_messages, mode=nemotron_mode)
return {"ok": True, "model_mode": mode, "provider": "nvidia", "content": content, "error": None}
except RuntimeError as exc:
logger.warning("NVIDIA %s repair failed: %s", label, exc)
return {"ok": False, "model_mode": mode, "provider": "nvidia", "content": "", "error": str(exc)}
def generate_structure_pitch_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
"""Extract structured startup_context from free-form pitch text."""
return _call_nvidia_json_mode(messages, "structure_pitch", model_mode, "structure pitch")
def generate_structure_pitch_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
repair_messages = [
{
"role": "system",
"content": (
"Convert input to JSON. Return ONLY valid JSON.\n"
'{"startup_context":{"name":"","problem":"","target_users":"",'
'"solution":"","why_ai":"","traction":"","competitors":"","ask":""},'
'"missing_fields":[],"confidence":"low","brief_summary":""}'
),
},
{"role": "user", "content": "Output JSON only:\n\n" + raw_bad_content[:4000]},
]
return _call_nvidia_repair_mode(
repair_messages, "structure_pitch_repair", model_mode, "structure pitch"
)
def generate_deal_verdict_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
return _call_nvidia_json_mode(messages, "deal_verdict", model_mode, "deal verdict")
def generate_deal_verdict_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
repair_messages = [
{
"role": "system",
"content": (
"Convert input to JSON. Return ONLY valid JSON.\n"
'{"judge_reaction":"","deal_opening_offer":"","why_this_verdict":"","next_step_label":""}'
),
},
{"role": "user", "content": "Output JSON only:\n\n" + raw_bad_content[:4000]},
]
return _call_nvidia_repair_mode(repair_messages, "deal_verdict_repair", model_mode, "deal verdict")
def generate_deal_round_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
mode = _resolve_mode(model_mode)
if mode == "premium_nvidia":
try:
content = nvidia_client.generate_nemotron_response(messages, mode="deal_round")
return {"ok": True, "model_mode": mode, "provider": "nvidia", "content": content, "error": None}
except RuntimeError as exc:
logger.warning("NVIDIA deal round call failed: %s", exc)
return {"ok": False, "model_mode": mode, "provider": "nvidia", "content": "", "error": str(exc)}
return _placeholder_result(mode, "mock", f"Deal round via '{mode}' not implemented.")
def generate_deal_scoring_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
"""Route a deal dimension-scoring request (mode=deal_scorecard_scoring).
Nemotron judges all 6 deal dimensions semantically from the negotiation transcript.
Returns scores + deal_outcome + best_move + weakest_move only (no coaching text).
"""
return _call_nvidia_json_mode(messages, "deal_scorecard_scoring", model_mode, "deal scorecard scoring")
def generate_deal_scoring_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
"""Repair a broken deal scoring JSON (mode=deal_scorecard_scoring_repair)."""
repair_messages = [
{
"role": "system",
"content": (
"You are a JSON formatter. Convert the input into the exact schema below. "
"Return ONLY valid JSON. First character must be { last must be }. "
"No markdown. No reasoning. No array.\n\n"
"REQUIRED SCHEMA:\n"
'{"scores":{"anchoring":{"score":0,"reason":"","quote":""},'
'"evidence":{"score":0,"reason":"","quote":""},'
'"concession_control":{"score":0,"reason":"","quote":""},'
'"alternatives":{"score":0,"reason":"","quote":""},'
'"value_articulation":{"score":0,"reason":"","quote":""},'
'"closing":{"score":0,"reason":"","quote":""}},'
'"deal_outcome":"balanced","best_move":"","weakest_move":""}'
),
},
{"role": "user", "content": "Output JSON only:\n\n" + raw_bad_content[:4000]},
]
return _call_nvidia_repair_mode(
repair_messages, "deal_scorecard_scoring_repair", model_mode, "deal scorecard scoring"
)
def generate_deal_scorecard_coaching_response(
messages: list[dict[str, str]],
model_mode: str | None = None,
) -> dict[str, Any]:
return _call_nvidia_json_mode(messages, "deal_scorecard_coaching", model_mode, "deal scorecard coaching")
def generate_deal_scorecard_repair_response(
raw_bad_content: str,
model_mode: str | None = None,
) -> dict[str, Any]:
repair_messages = [
{
"role": "system",
"content": (
"Convert input to JSON. Return ONLY valid JSON.\n"
'{"deal_outcome_summary":"","best_move":"","weakest_move":"",'
'"improved_response":"","top_3_prep_points":["","",""],'
'"combined_summary":"","next_best_action":""}'
),
},
{"role": "user", "content": "Output JSON only:\n\n" + raw_bad_content[:5000]},
]
return _call_nvidia_repair_mode(repair_messages, "deal_scorecard_repair", model_mode, "deal scorecard")
# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------
def _call_nvidia_opponent(messages: list[dict], mode: str) -> dict[str, Any]:
try:
content = nvidia_client.generate_nemotron_response(messages, mode="opponent")
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA opponent call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": _FALLBACK_OPPONENT_MESSAGE,
"error": str(exc),
}
def _call_nvidia_scorecard(messages: list[dict], mode: str) -> dict[str, Any]:
try:
content = nvidia_client.generate_nemotron_response(messages, mode="scorecard")
return {
"ok": True,
"model_mode": mode,
"provider": "nvidia",
"content": content,
"error": None,
}
except RuntimeError as exc:
logger.warning("NVIDIA scorecard call failed: %s", exc)
return {
"ok": False,
"model_mode": mode,
"provider": "nvidia",
"content": "",
"error": str(exc),
"fallback_scorecard": _FALLBACK_SCORECARD,
}
def _placeholder_result(mode: str, provider: str, message: str) -> dict[str, Any]:
return {
"ok": False,
"model_mode": mode,
"provider": provider,
"content": _FALLBACK_OPPONENT_MESSAGE,
"error": message,
}