diff --git a/loopx/chat_automation_cadence_api.py b/loopx/chat/automation_cadence_api.py similarity index 99% rename from loopx/chat_automation_cadence_api.py rename to loopx/chat/automation_cadence_api.py index 062a3b352c..986681b078 100644 --- a/loopx/chat_automation_cadence_api.py +++ b/loopx/chat/automation_cadence_api.py @@ -7,12 +7,12 @@ from typing import Any from urllib.parse import parse_qs, urlparse -from .control_plane.effect_runtime import ( +from ..control_plane.effect_runtime import ( EffectRuntimeConflict, EffectRuntimeRejected, effect_runtime_result, ) -from .control_plane.quota.automation_cadence_readback import ( +from ..control_plane.quota.automation_cadence_readback import ( automation_cadence_readback, ) diff --git a/loopx/chat_goal_configuration_api.py b/loopx/chat/goal_configuration_api.py similarity index 96% rename from loopx/chat_goal_configuration_api.py rename to loopx/chat/goal_configuration_api.py index 92f98d4489..5bb47de3dc 100644 --- a/loopx/chat_goal_configuration_api.py +++ b/loopx/chat/goal_configuration_api.py @@ -5,26 +5,26 @@ from typing import Any, Protocol from urllib.parse import parse_qs, urlparse -from .capabilities.configuration_inspection import ( +from ..capabilities.configuration_inspection import ( GOAL_CONFIGURATION_INSPECTION_SCHEMA, inspect_machine_namespaces, project_goal_configuration as _public_goal_configuration, ) -from .capabilities.multi_subagent import ( +from ..capabilities.multi_subagent import ( apply_codex_subagent_capacity, plan_codex_subagent_capacity, public_codex_host_capacity, ) -from .configuration_transaction import ( +from ..configuration_transaction import ( build_configuration_update_plan, configuration_payload_revision, require_expected_configuration_plan_revision, ) -from .control_plane.goals.configure_goal_service import ( +from ..control_plane.goals.configure_goal_service import ( configure_goal_with_global_sync, read_goal_configuration_with_source_route, ) -from .orchestration import subagent_model_configuration_options +from ..orchestration import subagent_model_configuration_options CHAT_GOAL_CONFIGURATION_PATH = "/api/chat/goal-configuration" CHAT_GOAL_CONFIGURATION_PREVIEW_PATH = f"{CHAT_GOAL_CONFIGURATION_PATH}/preview" @@ -145,7 +145,7 @@ def _change_quality_options(config: Mapping[str, Any]) -> dict[str, Any]: def _progress_review_options(config: Mapping[str, Any]) -> dict[str, Any]: - from .capabilities.progress_review.policy import ( + from ..capabilities.progress_review.policy import ( normalize_progress_review_contract_revision, normalize_progress_review_drift_threshold, normalize_progress_review_mode, @@ -248,8 +248,8 @@ def _goal_capability_options( if capability_id == "goal_capability_organization": return {"capability_improvement_configuration": config} if capability_id == "todo_replan_cadence": - from .capabilities.todo_replan_cadence.machine_defaults import normalize_replan_cadence_configuration - from .control_plane.work_items.stride_policy_codec import normalize_stride_strategy + from ..capabilities.todo_replan_cadence.machine_defaults import normalize_replan_cadence_configuration + from ..control_plane.work_items.stride_policy_codec import normalize_stride_strategy horizon = {"clear_execution_planning_horizon_goal": True} if "planning_horizon_goal" in config: if not isinstance(config["planning_horizon_goal"], bool): @@ -272,7 +272,7 @@ def _goal_capability_options( return {option: cadence["count"], **horizon, **({"execution_stride_strategy": cadence["stride_strategy"]} if "stride_strategy" in cadence else {})} if capability_id == "periodic_report": - from .capabilities.periodic_report.goal_configuration import normalize_configuration + from ..capabilities.periodic_report.goal_configuration import normalize_configuration # Validate the payload before the Session guard reads native sources. return {"periodic_report_configuration": normalize_configuration(config)} if capability_id == "reward_memory": @@ -314,7 +314,7 @@ def _goal_capability_options( if capability_id == "explore_harness": return _explore_harness_options(config) if capability_id == "pull_request_review": - from .capabilities.pr_review_queue.goal_configuration import normalize_configuration + from ..capabilities.pr_review_queue.goal_configuration import normalize_configuration return {"pull_request_review_configuration": normalize_configuration(config)} if capability_id == "change_quality_qualification": return _change_quality_options(config) @@ -445,7 +445,7 @@ def _goal_configuration_readback_matches( capability_id: str, actual: object, desired: object, applied: Mapping[str, Any] ) -> bool: if capability_id == "reward_memory" and isinstance(actual, Mapping) and isinstance(desired, Mapping): - from .capabilities.reward_memory.configuration import reward_memory_configuration_readback_matches + from ..capabilities.reward_memory.configuration import reward_memory_configuration_readback_matches return reward_memory_configuration_readback_matches(actual, desired, applied) return actual == desired @@ -472,8 +472,8 @@ def _goal_configuration_inspect(self) -> None: result, machine_namespaces=self._goal_configuration_machine_namespaces(), ) - from .agent_registry import load_goal_from_registry - from .capabilities.progress_review.context import external_progress_review_context + from ..agent_registry import load_goal_from_registry + from ..capabilities.progress_review.context import external_progress_review_context goal = load_goal_from_registry(self.server.registry_path, goal_ids[0].strip()) observation = external_progress_review_context(goal or {}, getattr(self.server, "runtime_root", None)) if observation is not None: @@ -681,7 +681,7 @@ def _goal_configuration_update(self, *, execute: bool) -> None: options = _goal_capability_options(capability_id, configuration) machine_namespaces = self._goal_configuration_machine_namespaces() from contextlib import nullcontext - from .capabilities.native_chat.steward_reports import session_report_configuration_guard + from ..capabilities.native_chat.steward_reports import session_report_configuration_guard controller = getattr(self.server, "runtime_controller", None) guard = (session_report_configuration_guard(controller, goal_id, configuration) if capability_id == "periodic_report" and controller is not None else nullcontext()) diff --git a/loopx/chat_machine_configuration_api.py b/loopx/chat/machine_configuration_api.py similarity index 97% rename from loopx/chat_machine_configuration_api.py rename to loopx/chat/machine_configuration_api.py index 7d51a5b407..2e00ba36b0 100644 --- a/loopx/chat_machine_configuration_api.py +++ b/loopx/chat/machine_configuration_api.py @@ -4,12 +4,12 @@ from pathlib import Path from typing import Any, Protocol, cast -from .capabilities.configuration_ui import build_capability_configuration_catalog -from .configuration_catalog import build_configuration_capability_descriptors -from .capabilities.machine_configuration.builtins import ( +from ..capabilities.configuration_ui import build_capability_configuration_catalog +from ..configuration_catalog import build_configuration_capability_descriptors +from ..capabilities.machine_configuration.builtins import ( build_builtin_machine_configuration_registry, ) -from .capabilities.machine_configuration.contract import ( +from ..capabilities.machine_configuration.contract import ( MACHINE_CONFIGURATION_SCHEMA, MachineConfigurationRegistry, machine_configuration_revision, @@ -17,7 +17,7 @@ normalize_machine_configuration, remove_machine_configuration_namespace, ) -from .capabilities.machine_configuration.store import ( +from ..capabilities.machine_configuration.store import ( configure_machine_configuration, inspect_machine_configuration, read_stored_machine_configuration, diff --git a/loopx/presentation/configuration_api.py b/loopx/presentation/configuration_api.py index d01c3b3eb3..7faaf63c6e 100644 --- a/loopx/presentation/configuration_api.py +++ b/loopx/presentation/configuration_api.py @@ -12,13 +12,13 @@ from . import request_control_api as request_api from . import goal_storage_api as storage_api from ..chat import usage_statistics_api as usage_api -from .. import chat_goal_configuration_api as goal_api +from ..chat import goal_configuration_api as goal_api from . import goal_direction_api as direction_api from . import decision_context_api as context_api from . import content_media_api as media_api -from .. import chat_machine_configuration_api as machine_api +from ..chat import machine_configuration_api as machine_api from .. import chat_operator_provider_api as operator_api -from .. import chat_automation_cadence_api as cadence_api +from ..chat import automation_cadence_api as cadence_api class ChatConfigurationRequestMixin( diff --git a/tests/architecture/top_level_module_budget.json b/tests/architecture/top_level_module_budget.json index 114a6aca20..2f596b7889 100644 --- a/tests/architecture/top_level_module_budget.json +++ b/tests/architecture/top_level_module_budget.json @@ -1,6 +1,6 @@ { "schema": "loopx_top_level_module_budget_v0", "baseline_commit": "a4483aaece5bc74ec3f969fd067229487022401b", - "max_top_level_modules": 139, + "max_top_level_modules": 136, "allowlist": ["__init__.py", "entrypoint.py", "cli.py"] } diff --git a/tests/capabilities/test_capability_improvement.py b/tests/capabilities/test_capability_improvement.py index b966494c26..8258f3d3f6 100644 --- a/tests/capabilities/test_capability_improvement.py +++ b/tests/capabilities/test_capability_improvement.py @@ -8,7 +8,7 @@ import pytest from loopx.capabilities.goal_capability_organization.goal_configuration import configuration_summary -from loopx.chat_goal_configuration_api import ( +from loopx.chat.goal_configuration_api import ( CHAT_GOAL_CONFIGURATION_PREVIEW_PATH, GoalConfigurationRequestMixin, ) from loopx.configure_goal import configure_goal diff --git a/tests/capabilities/test_explore_machine_defaults.py b/tests/capabilities/test_explore_machine_defaults.py index 479ce188e8..37d359b94c 100644 --- a/tests/capabilities/test_explore_machine_defaults.py +++ b/tests/capabilities/test_explore_machine_defaults.py @@ -24,7 +24,7 @@ from loopx.capabilities.configuration_inspection import inspect_machine_namespaces, project_goal_configuration from loopx.capabilities.machine_configuration.builtins import build_builtin_machine_configuration_registry from loopx.capabilities.machine_configuration.store import configure_machine_configuration -from loopx.chat_goal_configuration_api import _goal_capability_options +from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.configure_goal import configure_goal from loopx.control_plane.coordination.goal_storage_initialization import initialize_goal_storage_target from loopx.history import collect_history diff --git a/tests/capabilities/test_explore_turn_context.py b/tests/capabilities/test_explore_turn_context.py index 311f86be03..9dbd596072 100644 --- a/tests/capabilities/test_explore_turn_context.py +++ b/tests/capabilities/test_explore_turn_context.py @@ -18,7 +18,7 @@ explore_result_log_path, ) from loopx.configure_goal import configure_goal -from loopx.chat_goal_configuration_api import _goal_capability_options +from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.control_plane.effect_runtime import ( effect_runtime_result, EffectRuntimeRejected, diff --git a/tests/capabilities/test_goal_capability_inspection.py b/tests/capabilities/test_goal_capability_inspection.py index 1e5dd164b4..8123d711df 100644 --- a/tests/capabilities/test_goal_capability_inspection.py +++ b/tests/capabilities/test_goal_capability_inspection.py @@ -10,7 +10,7 @@ inspect_goal_capabilities, render_goal_capabilities, ) -from loopx.chat_goal_configuration_api import GoalConfigurationRequestMixin +from loopx.chat.goal_configuration_api import GoalConfigurationRequestMixin from loopx.cli import main diff --git a/tests/capabilities/test_machine_configuration_goal_defaults.py b/tests/capabilities/test_machine_configuration_goal_defaults.py index 2f940ae05d..795a31bf5a 100644 --- a/tests/capabilities/test_machine_configuration_goal_defaults.py +++ b/tests/capabilities/test_machine_configuration_goal_defaults.py @@ -249,7 +249,7 @@ def test_goal_overrides_win_and_clearing_restores_live_machine_defaults( def test_effective_turn_machine_default_migration_and_override_readback(tmp_path: Path) -> None: """An explicit unit switch preserves v0 storage until apply and is reversible.""" - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.capabilities.goal_inspection import inspect_goal_capabilities _repo, registry_path, runtime_root = _fixture(tmp_path) @@ -354,7 +354,7 @@ def test_product_default_and_namespace_removal_use_six_settled_turns(tmp_path, m def test_stride_version_inherits_and_rolls_back(tmp_path: Path) -> None: - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.capabilities.goal_inspection import inspect_goal_capabilities _repo, registry_path, runtime_root = _fixture(tmp_path) @@ -414,7 +414,7 @@ def test_stride_version_inherits_and_rolls_back(tmp_path: Path) -> None: def test_goal_stride_only_uses_live_review_interval(tmp_path: Path) -> None: - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.capabilities.goal_inspection import inspect_goal_capabilities _repo, registry_path, runtime_root = _fixture(tmp_path) @@ -509,7 +509,7 @@ def test_stride_configuration_rejects_unsupported_or_ambiguous_versions(schema_v def test_horizon_goal_defaults_on_with_explicit_overrides_and_clear(tmp_path): - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.capabilities.goal_inspection import inspect_goal_capabilities _repo, registry_path, runtime_root = _fixture(tmp_path) diff --git a/tests/capabilities/test_periodic_report_cadence.py b/tests/capabilities/test_periodic_report_cadence.py index 7fdb06cf9e..b7cf3fea0f 100644 --- a/tests/capabilities/test_periodic_report_cadence.py +++ b/tests/capabilities/test_periodic_report_cadence.py @@ -114,7 +114,7 @@ def test_timezone_conflict_is_not_silently_reinterpreted(): def test_configure_goal_persists_and_clears_schedule(tmp_path): import json from loopx.configure_goal import configure_goal - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.capabilities.periodic_report.machine_defaults import resolve_goal_periodic_report_subscription registry = tmp_path / "registry.json" registry.write_text(json.dumps({"goals": [{"id": "example", "repo": str(tmp_path), diff --git a/tests/capabilities/test_pr_review_configuration.py b/tests/capabilities/test_pr_review_configuration.py index 3f08fa6ad6..f5046933b6 100644 --- a/tests/capabilities/test_pr_review_configuration.py +++ b/tests/capabilities/test_pr_review_configuration.py @@ -8,7 +8,7 @@ from loopx.cli import main from loopx.configure_goal import configure_goal -from loopx.chat_goal_configuration_api import _goal_capability_options +from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.capabilities.pr_review_queue.goal_configuration import ( apply_change, configuration_summary, diff --git a/tests/capabilities/test_progress_review.py b/tests/capabilities/test_progress_review.py index 7f45e2ce97..119af83382 100644 --- a/tests/capabilities/test_progress_review.py +++ b/tests/capabilities/test_progress_review.py @@ -272,7 +272,7 @@ def test_catalog_registers_the_default_off_capability() -> None: import io # noqa: E402 from contextlib import redirect_stdout # noqa: E402 -from loopx.chat_goal_configuration_api import _goal_capability_options # noqa: E402 +from loopx.chat.goal_configuration_api import _goal_capability_options # noqa: E402 from loopx.cli import main as cli_main # noqa: E402 from loopx.configure_goal import configure_goal # noqa: E402 from loopx.configuration_catalog import build_goal_configuration_catalog # noqa: E402 diff --git a/tests/capabilities/test_reward_memory_agent_bindings.py b/tests/capabilities/test_reward_memory_agent_bindings.py index fa4dd27731..6c17d0fca7 100644 --- a/tests/capabilities/test_reward_memory_agent_bindings.py +++ b/tests/capabilities/test_reward_memory_agent_bindings.py @@ -188,7 +188,7 @@ def test_wrong_target_mixed_scope_and_failed_preflight_cannot_commit(independent def test_editor_api_preserves_target_and_rejects_ambiguous_off_requests(): - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options assert _goal_capability_options("reward_memory", {"agent_id": "writer", "enabled": False}) == { "reward_memory_agent_id": "writer", "clear_reward_memory_config": True} enabled = _goal_capability_options("reward_memory", {"agent_id": "writer", "enabled": True, "config_path": ".loopx/config/writer.json"}) @@ -259,7 +259,7 @@ def test_pending_settlement_cannot_follow_a_replacement_binding(independent): def test_editor_readback_accepts_verified_activation_and_keeps_partial_write_fact(independent): - from loopx.chat_goal_configuration_api import GoalConfigurationRequestMixin + from loopx.chat.goal_configuration_api import GoalConfigurationRequestMixin registry, _, _ = independent preview = enable_writer(registry, execute=False) desired = preview["feature_summary"]["reward_memory"] @@ -321,7 +321,7 @@ def test_app_stage_resolves_the_registered_file_when_projection_omits_private_pa def test_committed_binding_with_unavailable_readback_is_partial_not_rollback(independent): - from loopx.chat_goal_configuration_api import GoalConfigurationRequestMixin + from loopx.chat.goal_configuration_api import GoalConfigurationRequestMixin registry, _, _ = independent applied = enable_writer(registry) class Unavailable(GoalConfigurationRequestMixin): diff --git a/tests/control_plane/test_subagent_model_configuration.py b/tests/control_plane/test_subagent_model_configuration.py index efd05add29..69f6045f07 100644 --- a/tests/control_plane/test_subagent_model_configuration.py +++ b/tests/control_plane/test_subagent_model_configuration.py @@ -221,7 +221,7 @@ def test_unconfigured_shape_and_unrecognized_model_availability() -> None: def test_capability_editor_model_roundtrip_and_clear(registry: Path) -> None: - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options for config, expected in [ ( @@ -249,7 +249,7 @@ def test_capability_editor_model_roundtrip_and_clear(registry: Path) -> None: def test_capability_editor_requests_one_click_codex_capacity_alignment() -> None: - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options options = _goal_capability_options( "multi_subagent", @@ -265,7 +265,7 @@ def test_capability_editor_requests_one_click_codex_capacity_alignment() -> None {"model": "example", "reasoning_effort": True}, ]) def test_capability_model_rejects_non_string_inputs(config: dict) -> None: - from loopx.chat_goal_configuration_api import _goal_capability_options + from loopx.chat.goal_configuration_api import _goal_capability_options with pytest.raises(ValueError, match="must be strings"): _goal_capability_options("multi_subagent", {"enabled": False, **config}) diff --git a/tests/control_plane/test_todo_replan_cadence.py b/tests/control_plane/test_todo_replan_cadence.py index bec3e50323..6413a6f91b 100644 --- a/tests/control_plane/test_todo_replan_cadence.py +++ b/tests/control_plane/test_todo_replan_cadence.py @@ -5,7 +5,7 @@ import pytest -from loopx.chat_goal_configuration_api import _goal_capability_options +from loopx.chat.goal_configuration_api import _goal_capability_options from loopx.configure_goal import configure_goal from loopx.control_plane.goals.goal_frontier.outcome_continuity import ( acceptance_gaps_from_todo_completion_checkpoint, diff --git a/tests/test_chat_automation_cadence_api.py b/tests/test_chat_automation_cadence_api.py index 16f397b544..9d4ac2f0ff 100644 --- a/tests/test_chat_automation_cadence_api.py +++ b/tests/test_chat_automation_cadence_api.py @@ -11,7 +11,7 @@ import pytest -from loopx import chat_automation_cadence_api +from loopx.chat import automation_cadence_api as chat_automation_cadence_api from loopx.chat_server import ChatHTTPServer, ChatRequestHandler from loopx.control_plane.effect_runtime import ( EffectRuntimeConflict, diff --git a/tests/test_chat_goal_configuration_api.py b/tests/test_chat_goal_configuration_api.py index 5d3504a11a..3470a06b84 100644 --- a/tests/test_chat_goal_configuration_api.py +++ b/tests/test_chat_goal_configuration_api.py @@ -7,7 +7,7 @@ import pytest -from loopx.chat_goal_configuration_api import ( +from loopx.chat.goal_configuration_api import ( CHAT_GOAL_CONFIGURATION_APPLY_PATH, CHAT_GOAL_CONFIGURATION_PATH, CHAT_GOAL_CONFIGURATION_PREVIEW_PATH, diff --git a/tests/test_chat_internal_module_layout.py b/tests/test_chat_internal_module_layout.py index c3c1914cc0..6a4132ba82 100644 --- a/tests/test_chat_internal_module_layout.py +++ b/tests/test_chat_internal_module_layout.py @@ -6,7 +6,10 @@ from pathlib import Path import loopx.chat as public_chat +from loopx.chat.automation_cadence_api import AutomationCadenceRequestMixin from loopx.chat.event_cache import ChatEventCache +from loopx.chat.goal_configuration_api import GoalConfigurationRequestMixin +from loopx.chat.machine_configuration_api import MachineConfigurationRequestMixin from loopx.chat.monitor_actions import ChatMonitorActionMixin from loopx.chat.todo_actions import ChatTodoActionMixin from loopx.chat.todo_detail import TodoDetailRequestMixin @@ -17,7 +20,16 @@ def test_chat_internal_helpers_load_below_the_public_chat_namespace() -> None: namespace_root = Path(public_chat.__file__).with_suffix("").resolve() assert [Path(entry).resolve() for entry in public_chat.__path__] == [namespace_root] + assert ( + AutomationCadenceRequestMixin.__module__ + == "loopx.chat.automation_cadence_api" + ) assert ChatEventCache.__module__ == "loopx.chat.event_cache" + assert GoalConfigurationRequestMixin.__module__ == "loopx.chat.goal_configuration_api" + assert ( + MachineConfigurationRequestMixin.__module__ + == "loopx.chat.machine_configuration_api" + ) assert ChatMonitorActionMixin.__module__ == "loopx.chat.monitor_actions" assert ChatTodoActionMixin.__module__ == "loopx.chat.todo_actions" assert TodoDetailRequestMixin.__module__ == "loopx.chat.todo_detail" @@ -28,6 +40,9 @@ def test_chat_internal_helpers_load_below_the_public_chat_namespace() -> None: def test_chat_internal_helpers_have_no_top_level_compatibility_shims() -> None: for old_module in ( "loopx.chat_event_cache", + "loopx.chat_automation_cadence_api", + "loopx.chat_goal_configuration_api", + "loopx.chat_machine_configuration_api", "loopx.chat_monitor_actions", "loopx.chat_todo_actions", "loopx.chat_todo_detail", diff --git a/tests/test_chat_machine_configuration_api.py b/tests/test_chat_machine_configuration_api.py index f6948d870e..f8c673bb36 100644 --- a/tests/test_chat_machine_configuration_api.py +++ b/tests/test_chat_machine_configuration_api.py @@ -18,7 +18,7 @@ configure_machine_configuration, read_machine_configuration, ) -from loopx.chat_machine_configuration_api import ( +from loopx.chat.machine_configuration_api import ( CHAT_MACHINE_CONFIGURATION_APPLY_PATH, CHAT_MACHINE_CONFIGURATION_PATH, CHAT_MACHINE_CONFIGURATION_PREVIEW_PATH, @@ -604,6 +604,7 @@ def test_the_steward_executor_namespace_is_editable_and_read_back( "executor_reasoning_effort", ] assert capability["configuration_editor"]["fields"][1]["options"] == [ + "antigravity", "codex", "dsh", ]