diff --git a/src/api_hooks.py b/src/api_hooks.py index a5bdfbf7..a895e02e 100644 --- a/src/api_hooks.py +++ b/src/api_hooks.py @@ -9,13 +9,54 @@ import uuid # TODO(Ed): Eliminate these? from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler -from typing import Any +from typing import Any, Callable from dataclasses import dataclass from src.module_loader import _require_warmed from src.result_types import ErrorInfo, ErrorKind, Result from src.type_aliases import JsonValue +# Pydantic proxies moved from src.models.py in +# post_module_taxonomy_de_cruft_20260627 Phase 4 (FR7). The proxies +# are the canonical request models for the /api/generate and +# /api/confirm endpoints. The API hook subsystem (this module) is +# the natural owner; models.py is a data-class shim. +def _create_generate_request() -> type: + from src.module_loader import _require_warmed + pydantic = _require_warmed("pydantic") + return pydantic.create_model( + "GenerateRequest", + prompt=(str, ...), + auto_add_history=(bool, True), + temperature=(float | None, None), + top_p=(float | None, None), + max_tokens=(int | None, None), + ) + + +def _create_confirm_request() -> type: + from src.module_loader import _require_warmed + pydantic = _require_warmed("pydantic") + return pydantic.create_model( + "ConfirmRequest", + approved=(bool, ...), + script=(str | None, None), + ) + + +_PYDANTIC_CLASS_FACTORIES: dict[str, callable] = { + "GenerateRequest": _create_generate_request, + "ConfirmRequest": _create_confirm_request, +} + + +def __getattr__(name: str) -> Any: + if name in _PYDANTIC_CLASS_FACTORIES: + cls = _PYDANTIC_CLASS_FACTORIES[name]() + globals()[name] = cls + return cls + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + @dataclass(frozen=True) class WebSocketMessage: diff --git a/src/app_controller.py b/src/app_controller.py index 701de4b9..5b7b2202 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -51,7 +51,7 @@ from src.result_types import Result, ErrorInfo, ErrorKind, OK from src.context_presets import ContextPresetManager from src.file_cache import ASTParser from src.io_pool import make_io_pool -from src.models import GenerateRequest, ConfirmRequest +from src.api_hooks import GenerateRequest, ConfirmRequest from src.warmup import WarmupManager from src.type_aliases import ( CommsLog, diff --git a/src/gui_2.py b/src/gui_2.py index 392864e6..bd1b1769 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -111,7 +111,7 @@ from src import session_logger from src import log_registry # from src import log_pruner from src import models -from src.models import GenerateRequest, ConfirmRequest +from src.api_hooks import GenerateRequest, ConfirmRequest from src.ai_client import DEFAULT_TOOL_CATEGORIES from src import mcp_client from src import markdown_helper diff --git a/src/models.py b/src/models.py index 135008c6..1808372f 100644 --- a/src/models.py +++ b/src/models.py @@ -1,32 +1,19 @@ """ -Models - Pydantic proxies + DEFAULT_TOOL_CATEGORIES only. +Models - legacy Metadata alias only. Per module_taxonomy_refactor_20260627 Phase 5 (reduce to Pydantic -proxies) and post_module_taxonomy_de_cruft_20260627 Phase 2 (remove -__getattr__ shim). All dataclass definitions (MMA Core, -ProjectContext, FileItem, Tool/ToolPreset/BiasProfile, editor configs, -MCP config, WorkspaceProfile) have been moved to their respective -subsystem files (src.mma, src.project, src.project_files, -src.tool_presets, src.tool_bias, src.external_editor, src.mcp_client, -src.workspace_manager, src.personas). +proxies) and post_module_taxonomy_de_cruft_20260627 Phases 2-4 (de-cruft +removals). All dataclass definitions, DEFAULT_TOOL_CATEGORIES, the +__getattr__ shim, and the Pydantic proxies have been moved out. -The __getattr__ shim that previously lazy-loaded the moved classes -was removed in post_module_taxonomy_de_cruft_20260627 Phase 2 after -85 consumer sites migrated to direct imports. The remaining -__getattr__ entries are: - - PROVIDERS (lazy load from src.ai_client; moved in Phase 3) - - GenerateRequest + ConfirmRequest (Pydantic proxies; moved in Phase 4) +Remaining content: + - The legacy 'Metadata = TrackMetadata' alias for tests that import + 'from src.models import Metadata' expecting the dataclass + - The PROVIDERS lazy __getattr__ (loads from src.ai_client on first + access; required to break a startup-speedup circular import) -Architecture: - - DEFAULT_TOOL_CATEGORIES is the ONLY non-Pydantic constant kept here. - It groups the canonical tool list for the UI's category filter. - (Moved to src.ai_client in Phase 3.) - - _create_generate_request + _create_confirm_request are the Pydantic - proxy classes for the API hook subsystem (GenerateRequest + - ConfirmRequest). (Moved to src.api_hooks in Phase 4.) - - The legacy 'Metadata = TrackMetadata' alias is preserved for - `from src.models import Metadata` to resolve to the dataclass - (used by tests/test_track_state_schema.py). +Phase 4 of this track has moved the Pydantic proxies to src.api_hooks.py. +The file is now ~40 lines. """ from __future__ import annotations @@ -44,41 +31,8 @@ from src.mma import TrackMetadata Metadata = TrackMetadata # noqa: F401 — legacy class name re-export -def _create_generate_request() -> type: - from src.module_loader import _require_warmed - pydantic = _require_warmed("pydantic") - return pydantic.create_model( - "GenerateRequest", - prompt=(str, ...), - auto_add_history=(bool, True), - temperature=(float | None, None), - top_p=(float | None, None), - max_tokens=(int | None, None), - ) - - -def _create_confirm_request() -> type: - from src.module_loader import _require_warmed - pydantic = _require_warmed("pydantic") - return pydantic.create_model( - "ConfirmRequest", - approved=(bool, ...), - script=(str | None, None), - ) - - -_PYDANTIC_CLASS_FACTORIES: dict[str, callable] = { - "GenerateRequest": _create_generate_request, - "ConfirmRequest": _create_confirm_request, -} - - def __getattr__(name: str) -> Any: if name == "PROVIDERS": from src import ai_client return ai_client.PROVIDERS - if name in _PYDANTIC_CLASS_FACTORIES: - cls = _PYDANTIC_CLASS_FACTORIES[name]() - globals()[name] = cls - return cls raise AttributeError(f"module {__name__!r} has no attribute {name!r}")