diff --git a/src/autocoder/__init__.py b/src/autocoder/__init__.py index c148dc05..5dcfb3ab 100644 --- a/src/autocoder/__init__.py +++ b/src/autocoder/__init__.py @@ -4,20 +4,31 @@ A powerful autonomous coding system with parallel agents, web UI, and MCP tools. """ -__version__ = "0.1.0" +from __future__ import annotations + +import importlib +from typing import TYPE_CHECKING, Any -# Core system exports -from autocoder.core.orchestrator import Orchestrator, create_orchestrator -from autocoder.core.gatekeeper import Gatekeeper -from autocoder.core.worktree_manager import WorktreeManager -from autocoder.core.knowledge_base import KnowledgeBase, get_knowledge_base -from autocoder.core.model_settings import ModelSettings, ModelPreset, get_full_model_id -from autocoder.core.test_framework_detector import TestFrameworkDetector -from autocoder.core.database import Database, get_database +__version__ = "0.1.0" -# Agent exports -from autocoder.agent.agent import run_autonomous_agent -from autocoder.agent.client import ClaudeSDKClient +_LAZY_EXPORTS: dict[str, tuple[str, str]] = { + # Core system + "Orchestrator": ("autocoder.core.orchestrator", "Orchestrator"), + "create_orchestrator": ("autocoder.core.orchestrator", "create_orchestrator"), + "Gatekeeper": ("autocoder.core.gatekeeper", "Gatekeeper"), + "WorktreeManager": ("autocoder.core.worktree_manager", "WorktreeManager"), + "KnowledgeBase": ("autocoder.core.knowledge_base", "KnowledgeBase"), + "get_knowledge_base": ("autocoder.core.knowledge_base", "get_knowledge_base"), + "ModelSettings": ("autocoder.core.model_settings", "ModelSettings"), + "ModelPreset": ("autocoder.core.model_settings", "ModelPreset"), + "get_full_model_id": ("autocoder.core.model_settings", "get_full_model_id"), + "TestFrameworkDetector": ("autocoder.core.test_framework_detector", "TestFrameworkDetector"), + "Database": ("autocoder.core.database", "Database"), + "get_database": ("autocoder.core.database", "get_database"), + # Agent + "run_autonomous_agent": ("autocoder.agent.agent", "run_autonomous_agent"), + "ClaudeSDKClient": ("autocoder.agent.client", "ClaudeSDKClient"), +} __all__ = [ # Core system @@ -37,3 +48,37 @@ "run_autonomous_agent", "ClaudeSDKClient", ] + +if TYPE_CHECKING: + from autocoder.agent.agent import run_autonomous_agent as run_autonomous_agent + from autocoder.agent.client import ClaudeSDKClient as ClaudeSDKClient + from autocoder.core.database import Database as Database + from autocoder.core.database import get_database as get_database + from autocoder.core.gatekeeper import Gatekeeper as Gatekeeper + from autocoder.core.knowledge_base import KnowledgeBase as KnowledgeBase + from autocoder.core.knowledge_base import get_knowledge_base as get_knowledge_base + from autocoder.core.model_settings import ModelPreset as ModelPreset + from autocoder.core.model_settings import ModelSettings as ModelSettings + from autocoder.core.model_settings import get_full_model_id as get_full_model_id + from autocoder.core.orchestrator import Orchestrator as Orchestrator + from autocoder.core.orchestrator import create_orchestrator as create_orchestrator + from autocoder.core.test_framework_detector import ( + TestFrameworkDetector as TestFrameworkDetector, + ) + from autocoder.core.worktree_manager import WorktreeManager as WorktreeManager + + +def __getattr__(name: str) -> Any: + spec = _LAZY_EXPORTS.get(name) + if not spec: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + module_name, attr_name = spec + module = importlib.import_module(module_name) + value = getattr(module, attr_name) + globals()[name] = value # Cache for future access + return value + + +def __dir__() -> list[str]: + return sorted(list(globals().keys()) + list(_LAZY_EXPORTS.keys())) diff --git a/src/autocoder/core/__init__.py b/src/autocoder/core/__init__.py index e96dd962..7044d068 100644 --- a/src/autocoder/core/__init__.py +++ b/src/autocoder/core/__init__.py @@ -11,13 +11,25 @@ - Database: SQLite database wrapper """ -from autocoder.core.orchestrator import Orchestrator, create_orchestrator -from autocoder.core.gatekeeper import Gatekeeper -from autocoder.core.worktree_manager import WorktreeManager -from autocoder.core.knowledge_base import KnowledgeBase, get_knowledge_base -from autocoder.core.model_settings import ModelSettings, ModelPreset, get_full_model_id -from autocoder.core.test_framework_detector import TestFrameworkDetector -from autocoder.core.database import Database, get_database +from __future__ import annotations + +import importlib +from typing import TYPE_CHECKING, Any + +_LAZY_EXPORTS: dict[str, tuple[str, str]] = { + "Orchestrator": ("autocoder.core.orchestrator", "Orchestrator"), + "create_orchestrator": ("autocoder.core.orchestrator", "create_orchestrator"), + "Gatekeeper": ("autocoder.core.gatekeeper", "Gatekeeper"), + "WorktreeManager": ("autocoder.core.worktree_manager", "WorktreeManager"), + "KnowledgeBase": ("autocoder.core.knowledge_base", "KnowledgeBase"), + "get_knowledge_base": ("autocoder.core.knowledge_base", "get_knowledge_base"), + "ModelSettings": ("autocoder.core.model_settings", "ModelSettings"), + "ModelPreset": ("autocoder.core.model_settings", "ModelPreset"), + "get_full_model_id": ("autocoder.core.model_settings", "get_full_model_id"), + "TestFrameworkDetector": ("autocoder.core.test_framework_detector", "TestFrameworkDetector"), + "Database": ("autocoder.core.database", "Database"), + "get_database": ("autocoder.core.database", "get_database"), +} __all__ = [ "Orchestrator", @@ -33,3 +45,35 @@ "Database", "get_database", ] + +if TYPE_CHECKING: + from autocoder.core.database import Database as Database + from autocoder.core.database import get_database as get_database + from autocoder.core.gatekeeper import Gatekeeper as Gatekeeper + from autocoder.core.knowledge_base import KnowledgeBase as KnowledgeBase + from autocoder.core.knowledge_base import get_knowledge_base as get_knowledge_base + from autocoder.core.model_settings import ModelPreset as ModelPreset + from autocoder.core.model_settings import ModelSettings as ModelSettings + from autocoder.core.model_settings import get_full_model_id as get_full_model_id + from autocoder.core.orchestrator import Orchestrator as Orchestrator + from autocoder.core.orchestrator import create_orchestrator as create_orchestrator + from autocoder.core.test_framework_detector import ( + TestFrameworkDetector as TestFrameworkDetector, + ) + from autocoder.core.worktree_manager import WorktreeManager as WorktreeManager + + +def __getattr__(name: str) -> Any: + spec = _LAZY_EXPORTS.get(name) + if not spec: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + module_name, attr_name = spec + module = importlib.import_module(module_name) + value = getattr(module, attr_name) + globals()[name] = value # Cache for future access + return value + + +def __dir__() -> list[str]: + return sorted(list(globals().keys()) + list(_LAZY_EXPORTS.keys())) diff --git a/ui/src/lib/api.ts b/ui/src/lib/api.ts index 41f27d69..bed9f4a4 100644 --- a/ui/src/lib/api.ts +++ b/ui/src/lib/api.ts @@ -61,10 +61,19 @@ async function fetchJSON(url: string, options?: RequestInit): Promise { if (!response.ok) { const payload = await response.json().catch(() => ({ detail: 'Unknown error' })) const detail = (payload as any)?.detail ?? payload + const detailMessage = + detail && + typeof detail === 'object' && + typeof (detail as any)?.message === 'string' && + (detail as any).message.trim() + ? String((detail as any).message) + : null const message = typeof detail === 'string' ? detail - : typeof (payload as any)?.message === 'string' + : detailMessage + ? detailMessage + : typeof (payload as any)?.message === 'string' ? (payload as any).message : JSON.stringify(detail, null, 2)