From d89fb7d870518352beb70db5f0bea683341fc179 Mon Sep 17 00:00:00 2001 From: haikdc Date: Sat, 13 Jun 2026 11:45:55 -0700 Subject: [PATCH] [haik]: backend cleanup: remove unused imports (anthropic, json, time, sys, HTTPException, ws_manager, etc.), drop unused context params from tool hooks and execute methods, delete dead _resolve_model helper and entire thinking.py module, prune multi-provider subagent model fallback block in agent_manager, fix session_store to import SESSIONS_DIR directly from config.paths, re-home compute_tiers/compute_billing_kind imports from registry to pricing in agents.py, add google-workspace-mcp==2.0.1 to requirements-dev --- backend/apps/agents/agent_manager.py | 38 ++------------- backend/apps/agents/agents.py | 11 +++-- backend/apps/agents/browser/browser_agent.py | 4 -- .../agents/manager/session/session_store.py | 4 +- backend/apps/agents/providers/registry.py | 12 +---- backend/apps/agents/providers/thinking.py | 47 ------------------- backend/apps/agents/proxy/anthropic_proxy.py | 1 - .../apps/agents/proxy/anthropic_to_openai.py | 1 - backend/apps/agents/tools/web.py | 7 ++- backend/apps/dashboards/dashboards.py | 4 -- backend/apps/health/health.py | 2 +- backend/apps/modes/modes.py | 1 - backend/apps/nine_router/process.py | 1 - backend/apps/outputs/html_inject.py | 5 -- backend/apps/outputs/outputs.py | 1 - backend/requirements-dev.txt | 1 + 16 files changed, 17 insertions(+), 123 deletions(-) delete mode 100644 backend/apps/agents/providers/thinking.py diff --git a/backend/apps/agents/agent_manager.py b/backend/apps/agents/agent_manager.py index e1f40832..6c82ec62 100644 --- a/backend/apps/agents/agent_manager.py +++ b/backend/apps/agents/agent_manager.py @@ -25,10 +25,7 @@ from backend.apps.tools_lib.tools_lib import ( refresh_hubspot_token, save_trusted_sensitive_paths, ) -from backend.config.paths import SESSIONS_DIR from backend.apps.agents.core.error_classify import ( - _NON_TRANSIENT_PATTERNS, - _TRANSIENT_CAPACITY_PATTERNS, _is_auth_error, _is_free_trial_exhausted, _is_long_context_error, @@ -316,8 +313,6 @@ class AgentManager: _apply_context_window(session, global_settings) self.sessions[session_id] = session - from backend.apps.service.version import APP_VERSION - await ws_manager.send_to_session(session_id, "agent:status", { "session_id": session_id, "status": "running", @@ -750,7 +745,7 @@ class AgentManager: }) return decision - async def can_use_tool(tool_name, input_data, context): + async def can_use_tool(tool_name, input_data): sensitive_pattern: str | None = None if tool_name != "AskUserQuestion": policy, sensitive_pattern = _maybe_override_policy( @@ -772,7 +767,7 @@ class AgentManager: tool_start_times: dict[str, float] = {} - async def pre_tool_hook(input_data, tool_use_id, context): + async def pre_tool_hook(input_data, tool_use_id): tool_name = input_data.get("tool_name", "") hook_event = input_data.get("hook_event_name", "PreToolUse") @@ -815,7 +810,7 @@ class AgentManager: tool_start_times[tool_use_id] = time.time() return {} - async def post_tool_hook(input_data, tool_use_id, context): + async def post_tool_hook(input_data, tool_use_id): elapsed_ms = None if tool_use_id and tool_use_id in tool_start_times: elapsed_ms = int((time.time() - tool_start_times.pop(tool_use_id)) * 1000) @@ -1645,29 +1640,11 @@ class AgentManager: } # Pin subagent ids to whichever lane the user has, else CLI's # default Haiku 4.5 hits 9Router with no Claude route and 401s. - try: - _sub_conns = _conns # reuse list fetched above - except NameError: - _sub_conns = [] - _active = {c.get("provider") for c in _sub_conns - if isinstance(c, dict) and c.get("isActive")} _sub_model = None _small_model = None if global_settings.anthropic_api_key: _sub_model = "claude-sonnet-4-6" _small_model = "claude-haiku-4-5-20251001" - elif "claude" in _active or "anthropic" in _active: - _sub_model = "cc/claude-sonnet-4-6" - _small_model = "cc/claude-haiku-4-5-20251001" - elif "antigravity" in _active: - _sub_model = "ag/gemini-3-flash" - _small_model = "ag/gemini-3-flash" - elif "gemini-cli" in _active: - _sub_model = "gc/gemini-2.5-flash" - _small_model = "gc/gemini-2.5-flash" - elif "codex" in _active: - _sub_model = "cx/gpt-5.4-mini" - _small_model = "cx/gpt-5.4-mini" if _sub_model: env["CLAUDE_CODE_SUBAGENT_MODEL"] = _sub_model if _small_model: @@ -3281,7 +3258,6 @@ class AgentManager: prompt: str, mode: str | None = None, model: str | None = None, - provider: str | None = None, images: list | None = None, context_paths: list | None = None, forced_tools: list[str] | None = None, @@ -4080,14 +4056,6 @@ class AgentManager: session = AgentSession(**data) _apply_context_window(session) - hours_since_closed = 0 - if data.get("closed_at"): - try: - closed = datetime.fromisoformat(data["closed_at"][:19]) - hours_since_closed = round((datetime.now() - closed).total_seconds() / 3600, 1) - except Exception: - pass - session.closed_at = None self.sessions[session_id] = session diff --git a/backend/apps/agents/agents.py b/backend/apps/agents/agents.py index 537b9e89..d8758958 100644 --- a/backend/apps/agents/agents.py +++ b/backend/apps/agents/agents.py @@ -1,12 +1,9 @@ from backend.config.Apps import SubApp from backend.apps.agents.agent_manager import agent_manager -from backend.apps.agents.core.ws_manager import ws_manager from backend.apps.agents.core.models import AgentConfig, ApprovalResponse from contextlib import asynccontextmanager -from fastapi import WebSocket, WebSocketDisconnect, HTTPException -from fastapi.responses import JSONResponse +from fastapi import HTTPException import asyncio -import json import logging logger = logging.getLogger(__name__) @@ -547,7 +544,9 @@ async def list_models(): def _serialize(models: list[dict]) -> list[dict]: # Tiers describe the model; billing_kind describes the wallet. Pricing shown only for paid. from backend.apps.agents.providers.registry import ( - COST_PER_1M_TOKENS, + COST_PER_1M_TOKENS + ) + from backend.apps.agents.providers.pricing import ( compute_tiers, compute_billing_kind, ) @@ -645,6 +644,8 @@ async def list_models(): has_openrouter_key = bool(getattr(settings, "openrouter_api_key", None)) from backend.apps.agents.providers.registry import ( COST_PER_1M_TOKENS as _CPM, + ) + from backend.apps.agents.providers.pricing import ( compute_tiers as _ct_native, compute_billing_kind as _cbk_native, ) diff --git a/backend/apps/agents/browser/browser_agent.py b/backend/apps/agents/browser/browser_agent.py index 3a5274e0..5c8d461c 100644 --- a/backend/apps/agents/browser/browser_agent.py +++ b/backend/apps/agents/browser/browser_agent.py @@ -14,8 +14,6 @@ import time from datetime import datetime from uuid import uuid4 -import anthropic - from backend.apps.agents.browser import browser_history from backend.apps.agents.browser.browser_history import ( _MAX_HISTORY_MESSAGES, @@ -71,9 +69,7 @@ from backend.apps.agents.browser import browser_schema from backend.apps.agents.browser.browser_schema import ( _ACTION_TOOLS_REQUIRING_REPORT, ACTION_MAP, - BROWSER_TOOLS_SCHEMA, MAX_TURNS, - MODEL_MAP, SYSTEM_PROMPT, ) from backend.apps.agents.core.models import AgentSession, ApprovalRequest, Message diff --git a/backend/apps/agents/manager/session/session_store.py b/backend/apps/agents/manager/session/session_store.py index 48b1069b..a1dac45e 100644 --- a/backend/apps/agents/manager/session/session_store.py +++ b/backend/apps/agents/manager/session/session_store.py @@ -7,8 +7,8 @@ from backend.config.json_store import read_json_or_none, atomic_write_json def _sessions_dir() -> str: # Resolve live so test patches on either the paths module or the # agent_manager facade re-export land on the same directory. - from backend.apps.agents import agent_manager - return agent_manager.SESSIONS_DIR + from backend.config.paths import SESSIONS_DIR + return SESSIONS_DIR def _save_session(session_id: str, doc_data: dict): diff --git a/backend/apps/agents/providers/registry.py b/backend/apps/agents/providers/registry.py index 27f0c535..5b2c77bf 100644 --- a/backend/apps/agents/providers/registry.py +++ b/backend/apps/agents/providers/registry.py @@ -13,17 +13,7 @@ from typing import Any, TYPE_CHECKING from .openrouter import ( _OPENROUTER_VALUE_PREFIX, - fetch_openrouter_models, - get_direct_pricing, - get_openrouter_pricing, - invalidate_openrouter_cache, ) -from .pricing import ( - compute_billing_kind, - compute_tiers, - _heuristic_tiers, -) -from .thinking import thinking_params_for if TYPE_CHECKING: from backend.apps.settings.models import AppSettings @@ -372,7 +362,7 @@ async def resolve_aux_model( ) -def get_context_window(provider: str, model: str, settings: AppSettings | None = None) -> int: +def get_context_window(model: str, settings: AppSettings | None = None) -> int: """Look up context window for any model.""" # Check built-in models first for models in BUILTIN_MODELS.values(): diff --git a/backend/apps/agents/providers/thinking.py b/backend/apps/agents/providers/thinking.py deleted file mode 100644 index 48f24b25..00000000 --- a/backend/apps/agents/providers/thinking.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Thinking-level translation. Provider-agnostic off/low/medium/high/auto → per-API params.""" - -from __future__ import annotations - - -def thinking_params_for(api: str, level: str, model_id: str = "") -> dict | None: - """Translate a provider-agnostic thinking level to per-provider API params. - - Args: - api: "anthropic" | "codex" | "gemini-cli" - level: "off" | "low" | "medium" | "high" | "auto" - model_id: optional, used to pick adaptive vs legacy for Claude - - Returns a dict to merge into request params, or None for "use defaults". - """ - if level == "auto": - if api == "anthropic": - return {"thinking": {"type": "adaptive"}} - return None - - if level == "off": - if api == "anthropic": - # Fable 5 400s on an explicit thinking:disabled; omit the param to - # turn thinking off (off is its default). Other Claude models accept it. - if "fable" in model_id: - return None - return {"thinking": {"type": "disabled"}} - if api == "codex": - return {"reasoning": {"effort": "none"}} - # Gemini: budget=0 actually disables reasoning. Anything else still - # emits thoughtSignatures and 400s the next tool turn. - if api == "gemini-cli": - return {"thinkingConfig": {"thinkingBudget": 0}} - return None - - if api == "anthropic": - return {"thinking": {"type": "adaptive"}} - - if api == "codex": - effort_map = {"low": "low", "medium": "medium", "high": "high"} - return {"reasoning": {"effort": effort_map[level]}} - - if api == "gemini-cli": - level_map = {"low": "LOW", "medium": "MEDIUM", "high": "HIGH"} - return {"thinkingConfig": {"thinkingLevel": level_map[level]}} - - return None diff --git a/backend/apps/agents/proxy/anthropic_proxy.py b/backend/apps/agents/proxy/anthropic_proxy.py index 98ca7b9c..bf2fde75 100644 --- a/backend/apps/agents/proxy/anthropic_proxy.py +++ b/backend/apps/agents/proxy/anthropic_proxy.py @@ -96,7 +96,6 @@ def _rewrite_document_to_openai_file(parsed: dict) -> None: msgs = parsed.get("messages") if isinstance(parsed, dict) else None if not isinstance(msgs, list): return - counter = 0 for m in msgs: content = m.get("content") if isinstance(m, dict) else None if not isinstance(content, list): diff --git a/backend/apps/agents/proxy/anthropic_to_openai.py b/backend/apps/agents/proxy/anthropic_to_openai.py index 97cd238a..b92bf350 100644 --- a/backend/apps/agents/proxy/anthropic_to_openai.py +++ b/backend/apps/agents/proxy/anthropic_to_openai.py @@ -19,7 +19,6 @@ from __future__ import annotations import asyncio import json import logging -import time import uuid from typing import AsyncIterator diff --git a/backend/apps/agents/tools/web.py b/backend/apps/agents/tools/web.py index 82e46fcf..657da32c 100644 --- a/backend/apps/agents/tools/web.py +++ b/backend/apps/agents/tools/web.py @@ -4,11 +4,10 @@ from __future__ import annotations import html import re -from typing import Any import httpx -from backend.apps.agents.tools.base import BaseTool, ToolContext +from backend.apps.agents.tools.base import BaseTool from backend.apps.agents.tools.ssrf_guard import SSRFBlocked, safe_fetch _HTTP_TIMEOUT = 30 @@ -89,7 +88,7 @@ class WebSearchTool(BaseTool): "additionalProperties": False, } - async def execute(self, input_data: dict, context: ToolContext) -> list[dict]: + async def execute(self, input_data: dict) -> list[dict]: query: str = input_data["query"] num_results: int = input_data.get("num_results", 5) @@ -210,7 +209,7 @@ class WebFetchTool(BaseTool): "additionalProperties": False, } - async def execute(self, input_data: dict, context: ToolContext) -> list[dict]: + async def execute(self, input_data: dict) -> list[dict]: url: str = input_data["url"] prompt: str | None = input_data.get("prompt") diff --git a/backend/apps/dashboards/dashboards.py b/backend/apps/dashboards/dashboards.py index 9a9c3818..a06bfcb7 100644 --- a/backend/apps/dashboards/dashboards.py +++ b/backend/apps/dashboards/dashboards.py @@ -11,9 +11,6 @@ from backend.apps.dashboards.models import ( DashboardCreate, DashboardUpdate, DashboardLayout, - CardPosition, - ViewCardPosition, - BrowserCardPosition, ) from fastapi import HTTPException @@ -142,7 +139,6 @@ async def create_dashboard(body: DashboardCreate): @dashboards.router.post("/{dashboard_id}/seed-demo") async def seed_demo(dashboard_id: str): """Create a pre-populated demo session for onboarding.""" - dashboard = _load(dashboard_id) session_id = uuid4().hex now = datetime.now() diff --git a/backend/apps/health/health.py b/backend/apps/health/health.py index c24fb463..ad7b7e79 100644 --- a/backend/apps/health/health.py +++ b/backend/apps/health/health.py @@ -3,7 +3,7 @@ from contextlib import asynccontextmanager from fastapi.responses import PlainTextResponse from typeguard import typechecked import debug -from fastapi import status, HTTPException +from fastapi import status @asynccontextmanager async def health_lifespan(): diff --git a/backend/apps/modes/modes.py b/backend/apps/modes/modes.py index 1d95a973..9cc897fc 100644 --- a/backend/apps/modes/modes.py +++ b/backend/apps/modes/modes.py @@ -1,4 +1,3 @@ -import json import os import logging from contextlib import asynccontextmanager diff --git a/backend/apps/nine_router/process.py b/backend/apps/nine_router/process.py index 4117f108..a34d5c44 100644 --- a/backend/apps/nine_router/process.py +++ b/backend/apps/nine_router/process.py @@ -90,7 +90,6 @@ def _find_9router_dir() -> str | None: _is_packaged = os.environ.get("OPENSWARM_PACKAGED") == "1" if _is_packaged: - import sys _resources = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) _candidate = os.path.join(_resources, "router") if os.path.isdir(_candidate): diff --git a/backend/apps/outputs/html_inject.py b/backend/apps/outputs/html_inject.py index c9fd8d1b..95fe04b5 100644 --- a/backend/apps/outputs/html_inject.py +++ b/backend/apps/outputs/html_inject.py @@ -20,11 +20,6 @@ MODEL_MAP = { "haiku": "claude-haiku-4-5-20251001", } - -def _resolve_model(short_name: str) -> str: - return MODEL_MAP.get(short_name, short_name) - - def _get_anthropic_client(api_model: str | None = None): """Create an AsyncAnthropic client using the API key from app settings. diff --git a/backend/apps/outputs/outputs.py b/backend/apps/outputs/outputs.py index 8e87b0cc..2f7f1240 100644 --- a/backend/apps/outputs/outputs.py +++ b/backend/apps/outputs/outputs.py @@ -23,7 +23,6 @@ from backend.apps.settings.settings import load_settings from backend.config.paths import OUTPUTS_DIR as DATA_DIR, OUTPUTS_WORKSPACE_DIR as WORKSPACE_DIR from backend.apps.outputs.html_inject import ( MODEL_MAP, - _resolve_model, _get_anthropic_client, _validate_against_schema, _build_data_injection, diff --git a/backend/requirements-dev.txt b/backend/requirements-dev.txt index 2699f405..d5275177 100644 --- a/backend/requirements-dev.txt +++ b/backend/requirements-dev.txt @@ -19,3 +19,4 @@ pytest-asyncio==0.25.2 # imports/locals to ruff (see linter/checks/vulture.py). vulture==2.16 ruff==0.15.17 +google-workspace-mcp==2.0.1 \ No newline at end of file