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?
|
# TODO(Ed): Eliminate these?
|
||||||
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
|
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
|
||||||
from typing import Any
|
from typing import Any, Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from src.module_loader import _require_warmed
|
from src.module_loader import _require_warmed
|
||||||
from src.result_types import ErrorInfo, ErrorKind, Result
|
from src.result_types import ErrorInfo, ErrorKind, Result
|
||||||
from src.type_aliases import JsonValue
|
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)
|
@dataclass(frozen=True)
|
||||||
class WebSocketMessage:
|
class WebSocketMessage:
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ from src.result_types import Result, ErrorInfo, ErrorKind, OK
|
|||||||
from src.context_presets import ContextPresetManager
|
from src.context_presets import ContextPresetManager
|
||||||
from src.file_cache import ASTParser
|
from src.file_cache import ASTParser
|
||||||
from src.io_pool import make_io_pool
|
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.warmup import WarmupManager
|
||||||
from src.type_aliases import (
|
from src.type_aliases import (
|
||||||
CommsLog,
|
CommsLog,
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ from src import session_logger
|
|||||||
from src import log_registry
|
from src import log_registry
|
||||||
# from src import log_pruner
|
# from src import log_pruner
|
||||||
from src import models
|
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.ai_client import DEFAULT_TOOL_CATEGORIES
|
||||||
from src import mcp_client
|
from src import mcp_client
|
||||||
from src import markdown_helper
|
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
|
Per module_taxonomy_refactor_20260627 Phase 5 (reduce to Pydantic
|
||||||
proxies) and post_module_taxonomy_de_cruft_20260627 Phase 2 (remove
|
proxies) and post_module_taxonomy_de_cruft_20260627 Phases 2-4 (de-cruft
|
||||||
__getattr__ shim). All dataclass definitions (MMA Core,
|
removals). All dataclass definitions, DEFAULT_TOOL_CATEGORIES, the
|
||||||
ProjectContext, FileItem, Tool/ToolPreset/BiasProfile, editor configs,
|
__getattr__ shim, and the Pydantic proxies have been moved out.
|
||||||
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).
|
|
||||||
|
|
||||||
The __getattr__ shim that previously lazy-loaded the moved classes
|
Remaining content:
|
||||||
was removed in post_module_taxonomy_de_cruft_20260627 Phase 2 after
|
- The legacy 'Metadata = TrackMetadata' alias for tests that import
|
||||||
85 consumer sites migrated to direct imports. The remaining
|
'from src.models import Metadata' expecting the dataclass
|
||||||
__getattr__ entries are:
|
- The PROVIDERS lazy __getattr__ (loads from src.ai_client on first
|
||||||
- PROVIDERS (lazy load from src.ai_client; moved in Phase 3)
|
access; required to break a startup-speedup circular import)
|
||||||
- GenerateRequest + ConfirmRequest (Pydantic proxies; moved in Phase 4)
|
|
||||||
|
|
||||||
Architecture:
|
Phase 4 of this track has moved the Pydantic proxies to src.api_hooks.py.
|
||||||
- DEFAULT_TOOL_CATEGORIES is the ONLY non-Pydantic constant kept here.
|
The file is now ~40 lines.
|
||||||
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).
|
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -44,41 +31,8 @@ from src.mma import TrackMetadata
|
|||||||
Metadata = TrackMetadata # noqa: F401 — legacy class name re-export
|
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:
|
def __getattr__(name: str) -> Any:
|
||||||
if name == "PROVIDERS":
|
if name == "PROVIDERS":
|
||||||
from src import ai_client
|
from src import ai_client
|
||||||
return ai_client.PROVIDERS
|
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}")
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||||
|
|||||||
Reference in New Issue
Block a user