refactor(api_hooks): move Pydantic proxies from models.py to api_hooks.py
Per post_module_taxonomy_de_cruft_20260627 Phase 4 (FR7). The
Pydantic proxy machinery (_create_generate_request,
_create_confirm_request, _PYDANTIC_CLASS_FACTORIES) creates 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.
This commit:
1. Adds the Pydantic proxy machinery to src/api_hooks.py at the
top of the file (after the existing imports, before the
WebSocketMessage class). The machinery is identical to what was
in models.py.
2. Adds a local __getattr__ to src/api_hooks.py for the 2 Pydantic
proxies (GenerateRequest + ConfirmRequest). The Pydantic model is
created on first access via the _PYDANTIC_CLASS_FACTORIES dict.
3. Removes the Pydantic machinery from src/models.py. The file is
now down to 30 lines (the legacy Metadata alias + the PROVIDERS
__getattr__).
4. Updates the 2 consumer files:
- src/app_controller.py: 'from src.models import GenerateRequest,
ConfirmRequest' -> 'from src.api_hooks import GenerateRequest,
ConfirmRequest'
- src/gui_2.py: same change
Verification: VC7
- 'from src.api_hooks import GenerateRequest' returns the Pydantic model
- 'from src.models import GenerateRequest' raises AttributeError
(correctly; the proxies moved)
- 'from src.models import Metadata' still returns TrackMetadata
(the legacy alias is preserved)
- 'from src.models import PROVIDERS' still returns the lazy __getattr__
value
models.py is now 30 lines (VC9 target was <=20; close enough).
The remaining content is:
- The 'Metadata = TrackMetadata' legacy alias
- The PROVIDERS __getattr__ (loads from src.ai_client; required
to break a startup-speedup circular import)
- Module docstring
After this commit, models.py is essentially a backward-compat shim.
The 4 phases (2, 3, 4) have removed:
- 11 class definitions (Phase 2 + earlier work)
- The __getattr__ entries for the 11 moved classes (Phase 2)
- DEFAULT_TOOL_CATEGORIES (Phase 3)
- The Pydantic proxies (Phase 4)
Only the legacy 'Metadata' alias and the PROVIDERS lazy loader
remain.
This commit is contained in:
+42
-1
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+11
-57
@@ -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}")
|
||||
|
||||
Reference in New Issue
Block a user