"""Protocol v3 composition root. This is the only layer joining adapters.""" from __future__ import annotations from dataclasses import dataclass import shutil from app.cad_agent.adapters.artifact_store import FileArtifactStore from app.cad_agent.adapters.event_publisher import IdempotentInProcessPublisher from app.cad_agent.adapters.runtime import ProfileCadRuntime from app.cad_agent.adapters.review_gateway import RenderedReviewGateway from app.cad_agent.adapters.sqlite_repository import SqliteTaskRepository from app.cad_agent.adapters.structured_llm import StructuredModelGateway from app.cad_agent.adapters.verifier import RegistryVerifierExecutor from app.cad_agent.application.action_handlers import ActionCommandHandler from app.cad_agent.application.outbox import OutboxDispatcher from app.cad_agent.application.requirements import RequirementsCommandHandler from app.cad_agent.application.workflow import ModelIdentity, WorkflowConfig, WorkflowCoordinator from app.cad_agent.domain.verifier_registry import default_registry from app.settings import Settings @dataclass(frozen=True, slots=True) class V3Services: repository: SqliteTaskRepository artifacts: FileArtifactStore workflow: WorkflowCoordinator models: StructuredModelGateway outbox: OutboxDispatcher def compose_v3(settings: Settings) -> V3Services: repository = SqliteTaskRepository(settings.task_root.parent / "autonomous-cad-v3.sqlite3") if repository.protocol_reset and settings.task_root.exists(): # Protocol 3.1 has no valid interpretation for structured-only task # artifacts, so clear that task root together with its old database. shutil.rmtree(settings.task_root) artifacts = FileArtifactStore(settings.task_root) runtime = ProfileCadRuntime(settings) registry = default_registry() verifier = RegistryVerifierExecutor(registry) requirements = RequirementsCommandHandler(repository, artifacts, registry) actions = ActionCommandHandler(repository, artifacts, runtime, verifier) fallbacks = tuple( ModelIdentity(provider.id, model.id) for provider in settings.providers if provider.configured for model in provider.models[:1] ) models = StructuredModelGateway(settings) outbox = OutboxDispatcher(repository, IdempotentInProcessPublisher()) workflow = WorkflowCoordinator( WorkflowConfig( max_turns=max(8, settings.agent_tool_calls_per_cycle * 8), format_error_limit=settings.agent_format_error_repeat_limit, author_fallbacks=fallbacks, ), repository, artifacts, runtime, models, RenderedReviewGateway(models), requirements, actions, ) return V3Services(repository, artifacts, workflow, models, outbox)