fix(v3): config_resolver — remove dead engine param, add input validation
- Remove unused `engine` parameter from `_resolve_engine()` signature and call sites - Warn on unknown engine in `_has_api_key()` instead of silently returning True - Warn when budget value from profile is not in BUDGET_ENGINE_MAP - Validate `platforms` type in `_resolve_platforms()`, wrap non-list values Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,10 +9,13 @@ Missing API key → auto-downgrade to free alternative
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Base directory of the project (one level up from bots/)
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
@@ -107,10 +110,10 @@ class ConfigResolver:
|
||||
engine = self._load('config/engine.json')
|
||||
|
||||
resolved = {
|
||||
'writing': self._resolve_engine('writing', profile, engine),
|
||||
'tts': self._resolve_engine('tts', profile, engine),
|
||||
'video': self._resolve_engine('video', profile, engine),
|
||||
'image': self._resolve_engine('image', profile, engine),
|
||||
'writing': self._resolve_engine('writing', profile),
|
||||
'tts': self._resolve_engine('tts', profile),
|
||||
'video': self._resolve_engine('video', profile),
|
||||
'image': self._resolve_engine('image', profile),
|
||||
'platforms': self._resolve_platforms(profile),
|
||||
'budget': profile.get('budget', 'free'),
|
||||
'level': profile.get('level', 'beginner'),
|
||||
@@ -143,12 +146,17 @@ class ConfigResolver:
|
||||
env_var = ENGINE_API_KEY_MAP.get(engine_name)
|
||||
if env_var is None:
|
||||
# Unknown engine — treat as available (graceful degradation)
|
||||
logger.warning(
|
||||
"Unknown engine '%s': not in ENGINE_API_KEY_MAP or ENGINE_REGISTRY as local; "
|
||||
"treating as available.",
|
||||
engine_name,
|
||||
)
|
||||
return True
|
||||
|
||||
value = os.environ.get(env_var, '').strip()
|
||||
return len(value) > 0
|
||||
|
||||
def _resolve_engine(self, category: str, profile: dict, engine: dict) -> dict:
|
||||
def _resolve_engine(self, category: str, profile: dict) -> dict:
|
||||
"""
|
||||
Resolve the active engine for a category.
|
||||
|
||||
@@ -161,7 +169,13 @@ class ConfigResolver:
|
||||
Returns dict with 'provider' and 'auto_selected' flag.
|
||||
"""
|
||||
budget = profile.get('budget', 'free')
|
||||
candidate_list = BUDGET_ENGINE_MAP.get(budget, BUDGET_ENGINE_MAP['free']).get(category, [])
|
||||
if budget not in BUDGET_ENGINE_MAP:
|
||||
logger.warning(
|
||||
"Invalid budget value '%s' from profile; falling back to 'free'.",
|
||||
budget,
|
||||
)
|
||||
budget = 'free'
|
||||
candidate_list = BUDGET_ENGINE_MAP[budget].get(category, [])
|
||||
|
||||
# Determine user's preferred provider
|
||||
engines_section = profile.get('engines', {})
|
||||
@@ -193,7 +207,10 @@ class ConfigResolver:
|
||||
|
||||
def _resolve_platforms(self, profile: dict) -> list:
|
||||
"""Return the list of target publishing platforms from user profile."""
|
||||
return profile.get('platforms', [])
|
||||
platforms = profile.get('platforms', [])
|
||||
if not isinstance(platforms, list):
|
||||
return [str(platforms)] if platforms else []
|
||||
return platforms
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user