|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
|
|
|
from collections.abc import Mapping
|
|
|
from dataclasses import dataclass, field
|
|
|
+from pathlib import Path
|
|
|
from typing import Any
|
|
|
|
|
|
from agent import wire_orchestration
|
|
|
@@ -14,9 +15,14 @@ from script_build_host.agents import (
|
|
|
ScriptBuildEvidenceProvider,
|
|
|
ScriptBuildValidationPolicy,
|
|
|
ScriptRoleRunConfigResolver,
|
|
|
+ SnapshotRoleSystemPromptResolver,
|
|
|
register_script_presets,
|
|
|
)
|
|
|
from script_build_host.agents.model_resolver import SnapshotModelManifestSource
|
|
|
+from script_build_host.agents.prompt_catalog import (
|
|
|
+ PHASE_TWO_PRESETS,
|
|
|
+ script_prompt_requests,
|
|
|
+)
|
|
|
from script_build_host.api import ApiSecurity, UploadedTopicGateway, create_app
|
|
|
from script_build_host.application.input_snapshot_service import ScriptInputSnapshotService
|
|
|
from script_build_host.application.mission_factory import ScriptMissionFactory
|
|
|
@@ -25,6 +31,14 @@ from script_build_host.application.mission_service import (
|
|
|
DirectionReconciler,
|
|
|
ScriptMissionService,
|
|
|
)
|
|
|
+from script_build_host.application.phase_two_boundary import ScriptPhaseTwoBoundaryVerifier
|
|
|
+from script_build_host.application.phase_two_candidates import PhaseTwoCandidateService
|
|
|
+from script_build_host.application.phase_two_inputs import (
|
|
|
+ AcceptedInputResolver,
|
|
|
+ ActiveFrontierResolver,
|
|
|
+ StoredTaskContractReader,
|
|
|
+)
|
|
|
+from script_build_host.application.phase_two_planning import PhaseTwoPlanningService
|
|
|
from script_build_host.domain.ports import (
|
|
|
BuildAuthorizer,
|
|
|
InputSnapshotRepository,
|
|
|
@@ -35,7 +49,9 @@ from script_build_host.domain.ports import (
|
|
|
RuntimeManifestProvider,
|
|
|
ScriptBusinessArtifactRepository,
|
|
|
)
|
|
|
+from script_build_host.domain.task_contracts import PhaseTwoLimits
|
|
|
from script_build_host.infrastructure.outbound import OutboundPolicy
|
|
|
+from script_build_host.infrastructure.task_contract_store import FileScriptTaskContractStore
|
|
|
from script_build_host.tools import LegacyScriptToolGateway, register_script_tools
|
|
|
from script_build_host.tools.gateway import ImageAdapter, RetrievalAdapter
|
|
|
|
|
|
@@ -64,6 +80,15 @@ class HostDependencies:
|
|
|
websocket_allowed_origins: tuple[str, ...] = ()
|
|
|
default_model_manifest: Mapping[str, object] = field(default_factory=dict)
|
|
|
default_datasource_manifest: Mapping[str, object] = field(default_factory=dict)
|
|
|
+ enabled_phase: int = 1
|
|
|
+ agent_data_root: Path | None = None
|
|
|
+ task_contract_store: Any = None
|
|
|
+ candidate_workspaces: Any = None
|
|
|
+ raw_artifact_store: Any = None
|
|
|
+ max_images: int = 8
|
|
|
+ max_image_bytes: int = 10 * 1024 * 1024
|
|
|
+ max_total_image_bytes: int = 25 * 1024 * 1024
|
|
|
+ phase_two_limits: PhaseTwoLimits = field(default_factory=PhaseTwoLimits)
|
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
|
@@ -72,6 +97,8 @@ class HostComposition:
|
|
|
coordinator: Any
|
|
|
mission_service: ScriptMissionService
|
|
|
tool_gateway: LegacyScriptToolGateway
|
|
|
+ phase_two_planning: PhaseTwoPlanningService
|
|
|
+ phase_two_candidates: PhaseTwoCandidateService
|
|
|
|
|
|
|
|
|
def compose_host(dependencies: HostDependencies) -> HostComposition:
|
|
|
@@ -91,6 +118,9 @@ def compose_host(dependencies: HostDependencies) -> HostComposition:
|
|
|
dependencies.bindings,
|
|
|
),
|
|
|
)
|
|
|
+ prompt_resolver = SnapshotRoleSystemPromptResolver(
|
|
|
+ dependencies.bindings, dependencies.input_snapshots
|
|
|
+ )
|
|
|
coordinator = wire_orchestration(
|
|
|
dependencies.runner,
|
|
|
dependencies.task_store,
|
|
|
@@ -101,7 +131,55 @@ def compose_host(dependencies: HostDependencies) -> HostComposition:
|
|
|
deterministic_validator=ScriptBuildDeterministicValidator(),
|
|
|
evidence_provider=evidence_provider,
|
|
|
role_run_config_resolver=model_resolver,
|
|
|
+ role_system_prompt_resolver=prompt_resolver,
|
|
|
+ )
|
|
|
+ contract_store = dependencies.task_contract_store
|
|
|
+ if contract_store is None:
|
|
|
+ data_root = dependencies.agent_data_root
|
|
|
+ if data_root is None:
|
|
|
+ artifact_root = getattr(dependencies.framework_artifact_store, "base_path", None)
|
|
|
+ if artifact_root is None:
|
|
|
+ raise RuntimeError(
|
|
|
+ "Host requires agent_data_root or an explicit task_contract_store"
|
|
|
+ )
|
|
|
+ data_root = Path(artifact_root)
|
|
|
+ contract_store = FileScriptTaskContractStore(Path(data_root))
|
|
|
+ contract_reader = StoredTaskContractReader(contract_store)
|
|
|
+ accepted_inputs = AcceptedInputResolver(
|
|
|
+ task_store=dependencies.task_store,
|
|
|
+ artifact_store=dependencies.framework_artifact_store,
|
|
|
+ artifacts=dependencies.business_artifacts,
|
|
|
+ contracts=contract_reader,
|
|
|
+ input_snapshots=dependencies.input_snapshots,
|
|
|
+ )
|
|
|
+ boundary_verifier = ScriptPhaseTwoBoundaryVerifier(
|
|
|
+ task_store=dependencies.task_store,
|
|
|
+ artifact_store=dependencies.framework_artifact_store,
|
|
|
+ artifacts=dependencies.business_artifacts,
|
|
|
+ bindings=dependencies.bindings,
|
|
|
+ accepted_inputs=accepted_inputs,
|
|
|
)
|
|
|
+ planning_service = PhaseTwoPlanningService(
|
|
|
+ coordinator=coordinator,
|
|
|
+ bindings=dependencies.bindings,
|
|
|
+ contracts=contract_store,
|
|
|
+ closure_gate=boundary_verifier,
|
|
|
+ limits=dependencies.phase_two_limits,
|
|
|
+ )
|
|
|
+ candidate_service = PhaseTwoCandidateService(
|
|
|
+ bindings=dependencies.bindings,
|
|
|
+ task_store=dependencies.task_store,
|
|
|
+ framework_artifact_store=dependencies.framework_artifact_store,
|
|
|
+ artifacts=dependencies.business_artifacts,
|
|
|
+ accepted_inputs=accepted_inputs,
|
|
|
+ active_frontier=ActiveFrontierResolver(),
|
|
|
+ workspaces=dependencies.candidate_workspaces,
|
|
|
+ raw_artifacts=dependencies.raw_artifact_store,
|
|
|
+ max_images=dependencies.max_images,
|
|
|
+ max_image_bytes=dependencies.max_image_bytes,
|
|
|
+ max_total_image_bytes=dependencies.max_total_image_bytes,
|
|
|
+ )
|
|
|
+ planning_service.workspace_lifecycle = candidate_service
|
|
|
transition_gate = BuildTransitionGate()
|
|
|
direction_reconciler = DirectionReconciler(
|
|
|
coordinator=coordinator,
|
|
|
@@ -122,7 +200,15 @@ def compose_host(dependencies: HostDependencies) -> HostComposition:
|
|
|
direction_reconciler=direction_reconciler,
|
|
|
transition_gate=transition_gate,
|
|
|
runtime_manifest_provider=dependencies.runtime_manifest_provider,
|
|
|
+ enabled_phase=dependencies.enabled_phase,
|
|
|
+ phase_two_prompt_requests=tuple(
|
|
|
+ item for item in script_prompt_requests() if item.preset in PHASE_TWO_PRESETS
|
|
|
+ ),
|
|
|
+ phase_two_required_presets=tuple(sorted(PHASE_TWO_PRESETS)),
|
|
|
+ phase_two_model_manifest=dict(dependencies.default_model_manifest),
|
|
|
+ phase_two_boundary_verifier=boundary_verifier,
|
|
|
)
|
|
|
+ planning_service.dispatch_guard = mission_service
|
|
|
gateway = LegacyScriptToolGateway(
|
|
|
bindings=dependencies.bindings,
|
|
|
snapshots=dependencies.input_snapshots,
|
|
|
@@ -131,6 +217,9 @@ def compose_host(dependencies: HostDependencies) -> HostComposition:
|
|
|
retrieval_adapters=dependencies.retrieval_adapters,
|
|
|
image_adapter=dependencies.image_adapter,
|
|
|
dispatch_guard=mission_service,
|
|
|
+ planner_tools=planning_service,
|
|
|
+ candidate_tools=candidate_service,
|
|
|
+ budget_guard=planning_service,
|
|
|
)
|
|
|
register_script_tools(dependencies.runner.tools, gateway)
|
|
|
security = ApiSecurity(
|
|
|
@@ -157,6 +246,8 @@ def compose_host(dependencies: HostDependencies) -> HostComposition:
|
|
|
coordinator=coordinator,
|
|
|
mission_service=mission_service,
|
|
|
tool_gateway=gateway,
|
|
|
+ phase_two_planning=planning_service,
|
|
|
+ phase_two_candidates=candidate_service,
|
|
|
)
|
|
|
|
|
|
|