diff --git a/ai-hub/app/app.py b/ai-hub/app/app.py index 405e4f1..dd55d05 100644 --- a/ai-hub/app/app.py +++ b/ai-hub/app/app.py @@ -151,7 +151,7 @@ if "deepseek" not in llm_providers and settings.DEEPSEEK_API_KEY: llm_providers["deepseek"] = {"api_key": settings.DEEPSEEK_API_KEY, "model": settings.DEEPSEEK_MODEL_NAME} if "gemini" not in llm_providers and settings.GEMINI_API_KEY: - llm_providers["gemini"] = {"api_key": settings.GEMINI_API_KEY, "model": settings.GEMINI_MODEL_NAME or "gemini-2.5-flash"} + llm_providers["gemini"] = {"api_key": settings.GEMINI_API_KEY, "model": settings.GEMINI_MODEL_NAME} changed = False for p_name, p_data in list(llm_providers.items()): diff --git a/ai-hub/app/config.py b/ai-hub/app/config.py index b17f0d0..2c04bf0 100644 --- a/ai-hub/app/config.py +++ b/ai-hub/app/config.py @@ -199,9 +199,7 @@ self.LLM_PROVIDERS[provider_id]["model"] = env_val for p_id in self.LLM_PROVIDERS: - model = self.LLM_PROVIDERS[p_id].get("model") or "" - if "gemini-1.5-flash" in model: - self.LLM_PROVIDERS[p_id]["model"] = "gemini-2.5-flash" + pass # Keep user-selected models as they are self.DEEPSEEK_API_KEY = self.LLM_PROVIDERS.get("deepseek", {}).get("api_key") or os.getenv("DEEPSEEK_API_KEY") self.GEMINI_API_KEY = self.LLM_PROVIDERS.get("gemini", {}).get("api_key") or os.getenv("GEMINI_API_KEY") self.OPENAI_API_KEY = self.LLM_PROVIDERS.get("openai", {}).get("api_key") or os.getenv("OPENAI_API_KEY") @@ -211,8 +209,6 @@ self.GEMINI_MODEL_NAME = self.LLM_PROVIDERS.get("gemini", {}).get("model") or \ get_from_yaml(["llm_providers", "gemini_model_name"]) or \ os.getenv("GEMINI_MODEL_NAME") - if self.GEMINI_MODEL_NAME and "gemini-1.5-flash" in self.GEMINI_MODEL_NAME: - self.GEMINI_MODEL_NAME = "gemini-2.5-flash" self.ACTIVE_LLM_PROVIDER = os.getenv("ACTIVE_LLM_PROVIDER") or \ get_from_yaml(["active_llm_provider"]) or \ diff --git a/ai-hub/app/core/orchestration/agent_loop.py b/ai-hub/app/core/orchestration/agent_loop.py index 7d6aa7c..77f3869 100644 --- a/ai-hub/app/core/orchestration/agent_loop.py +++ b/ai-hub/app/core/orchestration/agent_loop.py @@ -59,16 +59,10 @@ provider_name = getattr(agent_session, "provider_name", None) - # If not explicitly defined on session, fallback to smartest available + # If not explicitly defined on session, fallback to system default if not provider_name and user_service: from app.config import settings provider_name = settings.ACTIVE_LLM_PROVIDER - sys_prefs = user_service.get_system_settings(db) - providers = sys_prefs.get("llm", {}).get("providers", {}) - for best_choice in ["gemini", "deepseek", "openai", "anthropic"]: - if best_choice in providers and providers[best_choice].get("api_key"): - provider_name = best_choice - break # Area 4.2: Hippocampus (Scratchpad) Idempotency Check # We skip this for simple chat prompts, but for autonomous loops its vital diff --git a/ai-hub/app/core/orchestration/architect.py b/ai-hub/app/core/orchestration/architect.py index a8e7b61..9c8c63d 100644 --- a/ai-hub/app/core/orchestration/architect.py +++ b/ai-hub/app/core/orchestration/architect.py @@ -210,7 +210,11 @@ messages.append(self._format_assistant_msg(accumulated_content, accumulated_reasoning, processed_tc)) # Run parallel execution - executor = ToolExecutor(tool_service, user_id, db, sync_workspace_id, session_id) + # Run parallel execution + executor = ToolExecutor( + tool_service, user_id, db, sync_workspace_id, session_id, + provider_name=getattr(llm_provider, "provider_name", None) + ) async for event in executor.run_tools(processed_tc, safety, mesh_bridge): if "role" in event: # It's a tool result for history messages.append(event) diff --git a/ai-hub/app/core/orchestration/body.py b/ai-hub/app/core/orchestration/body.py index 9c441c6..bf26379 100644 --- a/ai-hub/app/core/orchestration/body.py +++ b/ai-hub/app/core/orchestration/body.py @@ -7,12 +7,13 @@ class ToolExecutor: """Handles parallel tool dispatching and event drainage.""" - def __init__(self, tool_service: Any, user_id: str, db: Any, sync_workspace_id: str, session_db_id: int): + def __init__(self, tool_service: Any, user_id: str, db: Any, sync_workspace_id: str, session_db_id: int, provider_name: Optional[str] = None): self.tool_service = tool_service self.user_id = user_id self.db = db self.sync_workspace_id = sync_workspace_id self.session_db_id = session_db_id + self.provider_name = provider_name self.event_queue = asyncio.Queue() async def _subagent_event_handler(self, event): @@ -39,7 +40,8 @@ user_id=self.user_id, session_id=self.sync_workspace_id, session_db_id=self.session_db_id, - on_event=self._subagent_event_handler + on_event=self._subagent_event_handler, + provider_name=self.provider_name ) ) tool_tasks.append((tc, task)) diff --git a/ai-hub/app/core/services/tool.py b/ai-hub/app/core/services/tool.py index 2c41d99..172d5e8 100644 --- a/ai-hub/app/core/services/tool.py +++ b/ai-hub/app/core/services/tool.py @@ -71,8 +71,10 @@ try: # Attempt to resolve the active user's model configuration dynamically to get exact context sizes user = db.query(models.User).filter(models.User.id == user_id).first() if db else None - m_name = "gemini-2.5-pro" + from app.config import settings + m_name = settings.ACTIVE_LLM_PROVIDER if user and user.preferences: + # User preference override m_name = user.preferences.get("llm_model", m_name) model_info = litellm.get_model_info(m_name) @@ -191,7 +193,7 @@ return tools - async def call_tool(self, tool_name: str, arguments: Dict[str, Any], db: Session = None, user_id: str = None, session_id: str = None, session_db_id: int = None, on_event = None) -> Any: + async def call_tool(self, tool_name: str, arguments: Dict[str, Any], db: Session = None, user_id: str = None, session_id: str = None, session_db_id: int = None, on_event = None, provider_name: str = None) -> Any: """ Executes a registered skill. """ @@ -275,12 +277,12 @@ setattr(self, k, v) fs_skill["files"] = [_DictObj(f) for f in fs_skill.get("files", [])] db_skill_mock = _DictObj(fs_skill) - return await self._execute_system_skill(db_skill_mock, arguments, user_id=user_id, db=db, session_id=session_id, session_db_id=session_db_id, on_event=on_event) + return await self._execute_system_skill(db_skill_mock, arguments, user_id=user_id, db=db, session_id=session_id, session_db_id=session_db_id, on_event=on_event, provider_name=provider_name) logger.error(f"Tool '{tool_name}' not found or handled yet.") return {"success": False, "error": "Tool not found"} - async def _execute_system_skill(self, skill: Any, args: Dict[str, Any], user_id: str = None, db: Session = None, session_id: str = None, session_db_id: int = None, on_event = None) -> Any: + async def _execute_system_skill(self, skill: Any, args: Dict[str, Any], user_id: str = None, db: Session = None, session_id: str = None, session_db_id: int = None, on_event = None, provider_name: str = None) -> Any: """Routes FS skill execution to a stateful SubAgent or Dynamic Plugin.""" from app.core.services.sub_agent import SubAgent from app.core.providers.factory import get_llm_provider @@ -310,9 +312,16 @@ if db and user_id: user = db.query(models.User).filter(models.User.id == user_id).first() if user: - # Use user's preferred model, or fallback to system default - p_name = user.preferences.get("llm_provider", "gemini") - m_name = user.preferences.get("llm_model", "") + # Preference priority: + # 1. Passed provider (inherited from parent agent loop) + # 2. User preference + # 3. System default + if provider_name: + p_name = provider_name.split("/")[0] if "/" in provider_name else provider_name + actual_m_name = provider_name.split("/")[1] if "/" in provider_name else "" + else: + p_name = user.preferences.get("llm_provider", "gemini") + actual_m_name = user.preferences.get("llm_model", "") # Fetch provider-specific keys from user or system defaults llm_prefs = user.preferences.get("llm", {}).get("providers", {}).get(p_name, {}) @@ -327,7 +336,11 @@ llm_prefs = merged api_key_override = llm_prefs.get("api_key") - actual_m_name = m_name or llm_prefs.get("model", "") + # actual_m_name is already set from provider_name or preferences above + # Fallback to provider default if still empty + if not actual_m_name: + actual_m_name = llm_prefs.get("model", "") + kwargs = {k: v for k, v in llm_prefs.items() if k not in ["api_key", "model"]} try: