diff --git a/PhyAgentOS/plugins/perception_plugins/sam3_open_vocab.py b/PhyAgentOS/plugins/perception_plugins/sam3_open_vocab.py index 465751f8..28153770 100644 --- a/PhyAgentOS/plugins/perception_plugins/sam3_open_vocab.py +++ b/PhyAgentOS/plugins/perception_plugins/sam3_open_vocab.py @@ -3,9 +3,9 @@ from __future__ import annotations from PhyAgentOS.plugins.perception_plugins.base import BasePerceptionPlugin +from PhyAgentOS.runtime.errors import SchemaValidationError from PhyAgentOS.runtime.perception.sensor_frame import SensorFrame from PhyAgentOS.runtime.schemas.perception import EnvironmentDelta -from PhyAgentOS.runtime.watchdog.errors import SchemaValidationError class SAM3OpenVocabPlugin(BasePerceptionPlugin): diff --git a/PhyAgentOS/plugins/perception_plugins/yolo_seg.py b/PhyAgentOS/plugins/perception_plugins/yolo_seg.py index ae87490d..020f7648 100644 --- a/PhyAgentOS/plugins/perception_plugins/yolo_seg.py +++ b/PhyAgentOS/plugins/perception_plugins/yolo_seg.py @@ -3,9 +3,9 @@ from __future__ import annotations from PhyAgentOS.plugins.perception_plugins.base import BasePerceptionPlugin +from PhyAgentOS.runtime.errors import SchemaValidationError from PhyAgentOS.runtime.perception.sensor_frame import SensorFrame from PhyAgentOS.runtime.schemas.perception import EnvironmentDelta -from PhyAgentOS.runtime.watchdog.errors import SchemaValidationError class YOLOSegPlugin(BasePerceptionPlugin): diff --git a/PhyAgentOS/runtime/adapters/behavior1k/target_adapter.py b/PhyAgentOS/runtime/adapters/behavior1k/target_adapter.py index dbb4176a..d9fa36af 100644 --- a/PhyAgentOS/runtime/adapters/behavior1k/target_adapter.py +++ b/PhyAgentOS/runtime/adapters/behavior1k/target_adapter.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.base import BaseTargetAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class Behavior1kTargetAdapter(BaseTargetAdapter): diff --git a/PhyAgentOS/runtime/adapters/bridges.py b/PhyAgentOS/runtime/adapters/bridges.py index cbc9d81d..75431523 100644 --- a/PhyAgentOS/runtime/adapters/bridges.py +++ b/PhyAgentOS/runtime/adapters/bridges.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.base import BaseActionBridge -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class SafetyClampBridge(BaseActionBridge): diff --git a/PhyAgentOS/runtime/adapters/factory.py b/PhyAgentOS/runtime/adapters/factory.py index 2f41acce..15fc067f 100644 --- a/PhyAgentOS/runtime/adapters/factory.py +++ b/PhyAgentOS/runtime/adapters/factory.py @@ -5,19 +5,23 @@ from collections.abc import Callable from typing import Any -from PhyAgentOS.runtime.adapters.bridges import SafetyClampBridge from PhyAgentOS.runtime.adapters.behavior1k.target_adapter import Behavior1kTargetAdapter +from PhyAgentOS.runtime.adapters.bridges import SafetyClampBridge from PhyAgentOS.runtime.adapters.go2.target_adapter import Go2BuiltinTargetAdapter from PhyAgentOS.runtime.adapters.isaacsim.target_adapter import IsaacSimTargetAdapter from PhyAgentOS.runtime.adapters.libero.target_adapter import LiberoTargetAdapter from PhyAgentOS.runtime.adapters.openpi.b1k_dummy_policy_adapter import Behavior1kDummyPolicyAdapter -from PhyAgentOS.runtime.adapters.openpi.b1k_openpi_policy_adapter import Behavior1kOpenPIPolicyAdapter +from PhyAgentOS.runtime.adapters.openpi.b1k_openpi_policy_adapter import ( + Behavior1kOpenPIPolicyAdapter, +) from PhyAgentOS.runtime.adapters.openpi.dummy_openpi_adapter import DummyOpenPIAdapter -from PhyAgentOS.runtime.adapters.openpi.pipergo2_isaac_policy_adapter import PiperGo2IsaacPolicyAdapter from PhyAgentOS.runtime.adapters.openpi.pi05_policy_adapter import OpenPIPi05Adapter +from PhyAgentOS.runtime.adapters.openpi.pipergo2_isaac_policy_adapter import ( + PiperGo2IsaacPolicyAdapter, +) from PhyAgentOS.runtime.adapters.target_dummy import DummySimTargetAdapter +from PhyAgentOS.runtime.errors import AdapterError from PhyAgentOS.runtime.schemas.adapter_plan import AdapterPlan -from PhyAgentOS.runtime.watchdog.errors import AdapterError AdapterFactory = Callable[[], Any] diff --git a/PhyAgentOS/runtime/adapters/go2/target_adapter.py b/PhyAgentOS/runtime/adapters/go2/target_adapter.py index 1d011bae..d3f90eef 100644 --- a/PhyAgentOS/runtime/adapters/go2/target_adapter.py +++ b/PhyAgentOS/runtime/adapters/go2/target_adapter.py @@ -5,7 +5,7 @@ from typing import Any from PhyAgentOS.runtime.adapters.base import BaseTargetAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class Go2BuiltinTargetAdapter(BaseTargetAdapter): diff --git a/PhyAgentOS/runtime/adapters/isaacsim/target_adapter.py b/PhyAgentOS/runtime/adapters/isaacsim/target_adapter.py index d3e115ef..36d1a569 100644 --- a/PhyAgentOS/runtime/adapters/isaacsim/target_adapter.py +++ b/PhyAgentOS/runtime/adapters/isaacsim/target_adapter.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.base import BaseTargetAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class IsaacSimTargetAdapter(BaseTargetAdapter): diff --git a/PhyAgentOS/runtime/adapters/libero/target_adapter.py b/PhyAgentOS/runtime/adapters/libero/target_adapter.py index 1e25ede5..d05e43e9 100644 --- a/PhyAgentOS/runtime/adapters/libero/target_adapter.py +++ b/PhyAgentOS/runtime/adapters/libero/target_adapter.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.base import BaseTargetAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class LiberoTargetAdapter(BaseTargetAdapter): diff --git a/PhyAgentOS/runtime/adapters/openpi/b1k_dummy_policy_adapter.py b/PhyAgentOS/runtime/adapters/openpi/b1k_dummy_policy_adapter.py index ada352e9..de525fc9 100644 --- a/PhyAgentOS/runtime/adapters/openpi/b1k_dummy_policy_adapter.py +++ b/PhyAgentOS/runtime/adapters/openpi/b1k_dummy_policy_adapter.py @@ -8,7 +8,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.openpi.base_openpi_adapter import BaseOpenPIAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class Behavior1kDummyPolicyAdapter(BaseOpenPIAdapter): diff --git a/PhyAgentOS/runtime/adapters/openpi/b1k_openpi_policy_adapter.py b/PhyAgentOS/runtime/adapters/openpi/b1k_openpi_policy_adapter.py index d667cccf..f4399f5b 100644 --- a/PhyAgentOS/runtime/adapters/openpi/b1k_openpi_policy_adapter.py +++ b/PhyAgentOS/runtime/adapters/openpi/b1k_openpi_policy_adapter.py @@ -14,7 +14,7 @@ RIGHT_WRIST_RGB_KEY, ) from PhyAgentOS.runtime.adapters.openpi.base_openpi_adapter import BaseOpenPIAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class Behavior1kOpenPIPolicyAdapter(BaseOpenPIAdapter): diff --git a/PhyAgentOS/runtime/adapters/openpi/base_openpi_adapter.py b/PhyAgentOS/runtime/adapters/openpi/base_openpi_adapter.py index f0341a50..90938123 100644 --- a/PhyAgentOS/runtime/adapters/openpi/base_openpi_adapter.py +++ b/PhyAgentOS/runtime/adapters/openpi/base_openpi_adapter.py @@ -8,7 +8,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.base import BasePolicyAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class BaseOpenPIAdapter(BasePolicyAdapter): diff --git a/PhyAgentOS/runtime/adapters/openpi/dummy_openpi_adapter.py b/PhyAgentOS/runtime/adapters/openpi/dummy_openpi_adapter.py index 195a526f..c0112898 100644 --- a/PhyAgentOS/runtime/adapters/openpi/dummy_openpi_adapter.py +++ b/PhyAgentOS/runtime/adapters/openpi/dummy_openpi_adapter.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.openpi.base_openpi_adapter import BaseOpenPIAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class DummyOpenPIAdapter(BaseOpenPIAdapter): diff --git a/PhyAgentOS/runtime/adapters/openpi/pi05_policy_adapter.py b/PhyAgentOS/runtime/adapters/openpi/pi05_policy_adapter.py index 88eaa37d..e45f84ce 100644 --- a/PhyAgentOS/runtime/adapters/openpi/pi05_policy_adapter.py +++ b/PhyAgentOS/runtime/adapters/openpi/pi05_policy_adapter.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.openpi.base_openpi_adapter import BaseOpenPIAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class OpenPIPi05Adapter(BaseOpenPIAdapter): diff --git a/PhyAgentOS/runtime/adapters/openpi/pipergo2_isaac_policy_adapter.py b/PhyAgentOS/runtime/adapters/openpi/pipergo2_isaac_policy_adapter.py index 0febd90f..4563c360 100644 --- a/PhyAgentOS/runtime/adapters/openpi/pipergo2_isaac_policy_adapter.py +++ b/PhyAgentOS/runtime/adapters/openpi/pipergo2_isaac_policy_adapter.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.openpi.base_openpi_adapter import BaseOpenPIAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class PiperGo2IsaacPolicyAdapter(BaseOpenPIAdapter): diff --git a/PhyAgentOS/runtime/adapters/target_dummy.py b/PhyAgentOS/runtime/adapters/target_dummy.py index c7a9a7e4..4a4c36fa 100644 --- a/PhyAgentOS/runtime/adapters/target_dummy.py +++ b/PhyAgentOS/runtime/adapters/target_dummy.py @@ -7,7 +7,7 @@ import numpy as np from PhyAgentOS.runtime.adapters.base import BaseTargetAdapter -from PhyAgentOS.runtime.watchdog.errors import AdapterError +from PhyAgentOS.runtime.errors import AdapterError class DummySimTargetAdapter(BaseTargetAdapter): diff --git a/PhyAgentOS/runtime/communication/target_ws_client.py b/PhyAgentOS/runtime/communication/target_ws_client.py index f2f119a9..2805a0fa 100644 --- a/PhyAgentOS/runtime/communication/target_ws_client.py +++ b/PhyAgentOS/runtime/communication/target_ws_client.py @@ -8,7 +8,7 @@ from PhyAgentOS.runtime.communication.envelope import RuntimeEnvelope from PhyAgentOS.runtime.communication.msgpack_codec import decode_msgpack, encode_msgpack -from PhyAgentOS.runtime.watchdog.errors import TargetConnectionError, TargetProtocolError +from PhyAgentOS.runtime.errors import TargetConnectionError, TargetProtocolError class TargetWSClient: diff --git a/PhyAgentOS/runtime/errors.py b/PhyAgentOS/runtime/errors.py new file mode 100644 index 00000000..28821035 --- /dev/null +++ b/PhyAgentOS/runtime/errors.py @@ -0,0 +1,110 @@ +"""Runtime shared exception types and failure mapping (neutral base module). + +All lower-level runtime modules (Target / Policy / Adapter / Perception / +Communication / Perception Plugin, etc.) import shared exception types from +here, avoiding a dependency inversion where the Session orchestration layer +(watchdog) is treated as a common base package. +""" + +from __future__ import annotations + +__all__ = [ + "RuntimeErrorBase", + "SchemaValidationError", + "TargetBuildError", + "TargetResetError", + "TargetStepError", + "TargetConnectionError", + "TargetProtocolError", + "AdapterError", + "PolicyClientError", + "PolicyConnectionError", + "PolicyTimeoutError", + "PolicyProtocolError", + "SessionTimeoutError", + "error_code_for", + "terminal_status_for", +] + + +class RuntimeErrorBase(Exception): # noqa: N818 - historical public API name, kept for compatibility + """Base class for recoverable runtime v2 failures.""" + + +class SchemaValidationError(RuntimeErrorBase): + pass + + +class TargetBuildError(RuntimeErrorBase): + pass + + +class TargetResetError(RuntimeErrorBase): + pass + + +class TargetStepError(RuntimeErrorBase): + pass + + +class TargetConnectionError(RuntimeErrorBase): + pass + + +class TargetProtocolError(RuntimeErrorBase): + pass + + +class AdapterError(RuntimeErrorBase): + pass + + +class PolicyClientError(RuntimeErrorBase): + pass + + +class PolicyConnectionError(PolicyClientError): + pass + + +class PolicyTimeoutError(PolicyClientError): + pass + + +class PolicyProtocolError(PolicyClientError): + pass + + +class SessionTimeoutError(RuntimeErrorBase): + pass + + +def error_code_for(exc: Exception) -> str: + """Return the protocol error code for an exception.""" + mapping = { + SchemaValidationError: "SCHEMA_VALIDATION", + TargetBuildError: "TARGET_BUILD", + TargetResetError: "TARGET_RESET", + TargetStepError: "TARGET_STEP", + TargetConnectionError: "TARGET_CONNECTION", + TargetProtocolError: "TARGET_PROTOCOL", + AdapterError: "ADAPTER", + PolicyTimeoutError: "POLICY_TIMEOUT", + PolicyProtocolError: "POLICY_PROTOCOL", + PolicyConnectionError: "POLICY_CONNECTION", + PolicyClientError: "POLICY_CLIENT", + SessionTimeoutError: "SESSION_TIMEOUT", + } + for cls, code in mapping.items(): + if isinstance(exc, cls): + return code + return "RUNTIME_ERROR" + + +def terminal_status_for(exc: Exception) -> str: + """Return the terminal session status for an exception.""" + if isinstance(exc, SchemaValidationError): + return "rejected" + if isinstance(exc, SessionTimeoutError): + return "timed_out" + return "failed" diff --git a/PhyAgentOS/runtime/perception/config_resolver.py b/PhyAgentOS/runtime/perception/config_resolver.py index f9995e02..74699ce1 100644 --- a/PhyAgentOS/runtime/perception/config_resolver.py +++ b/PhyAgentOS/runtime/perception/config_resolver.py @@ -8,6 +8,7 @@ import yaml from pydantic import BaseModel, Field, ValidationError +from PhyAgentOS.runtime.errors import SchemaValidationError from PhyAgentOS.runtime.schemas.perception import ( PerceptionConfigDocument, PerceptionModelSpec, @@ -15,7 +16,6 @@ PerceptionPluginCandidate, ) from PhyAgentOS.runtime.schemas.sensor_config import SensorConfigDocument, SensorSpec -from PhyAgentOS.runtime.watchdog.errors import SchemaValidationError from PhyAgentOS.runtime.watchdog.scheduler import ScheduledSession diff --git a/PhyAgentOS/runtime/perception/perception_runtime.py b/PhyAgentOS/runtime/perception/perception_runtime.py index a1a78f11..b5e5a209 100644 --- a/PhyAgentOS/runtime/perception/perception_runtime.py +++ b/PhyAgentOS/runtime/perception/perception_runtime.py @@ -6,12 +6,15 @@ from time import perf_counter from uuid import uuid4 -from PhyAgentOS.runtime.perception.config_resolver import PerceptionConfigResolver, ResolvedPerceptionPlan +from PhyAgentOS.runtime.errors import SchemaValidationError +from PhyAgentOS.runtime.perception.config_resolver import ( + PerceptionConfigResolver, + ResolvedPerceptionPlan, +) from PhyAgentOS.runtime.perception.environment_writer import EnvironmentWriter from PhyAgentOS.runtime.perception.plugin_pipeline import PerceptionPluginPipeline from PhyAgentOS.runtime.perception.preflight import PerceptionPreflightChecker from PhyAgentOS.runtime.perception.sensor_frame_builder import SensorFrameBuilder -from PhyAgentOS.runtime.watchdog.errors import SchemaValidationError from PhyAgentOS.runtime.watchdog.scheduler import ScheduledSession diff --git a/PhyAgentOS/runtime/perception/plugin_pipeline.py b/PhyAgentOS/runtime/perception/plugin_pipeline.py index 3b5aa230..752ee8ba 100644 --- a/PhyAgentOS/runtime/perception/plugin_pipeline.py +++ b/PhyAgentOS/runtime/perception/plugin_pipeline.py @@ -9,11 +9,10 @@ from PhyAgentOS.plugins.perception_plugins.dummy_segmenter import DummySegmenter from PhyAgentOS.plugins.perception_plugins.rgbd_object_builder import RGBDObjectBuilder from PhyAgentOS.plugins.perception_plugins.sim_oracle import SimOraclePlugin +from PhyAgentOS.runtime.errors import SchemaValidationError from PhyAgentOS.runtime.perception.config_resolver import ResolvedPerceptionPlan from PhyAgentOS.runtime.perception.sensor_frame import SensorFrame from PhyAgentOS.runtime.schemas.perception import EnvironmentDelta -from PhyAgentOS.runtime.watchdog.errors import SchemaValidationError - _BUILTIN_PLUGINS: dict[str, type[BasePerceptionPlugin]] = { "dummy_segmenter": DummySegmenter, diff --git a/PhyAgentOS/runtime/perception/preflight.py b/PhyAgentOS/runtime/perception/preflight.py index a73cfb53..96956011 100644 --- a/PhyAgentOS/runtime/perception/preflight.py +++ b/PhyAgentOS/runtime/perception/preflight.py @@ -7,6 +7,7 @@ import httpx +from PhyAgentOS.runtime.errors import SchemaValidationError from PhyAgentOS.runtime.perception.config_resolver import ( PerceptionConfigResolver, ResolvedPerceptionPlan, @@ -14,7 +15,6 @@ ) from PhyAgentOS.runtime.perception.diagnostics import PreflightResult from PhyAgentOS.runtime.schemas.perception import PerceptionModelSpec -from PhyAgentOS.runtime.watchdog.errors import SchemaValidationError class PerceptionPreflightError(SchemaValidationError): diff --git a/PhyAgentOS/runtime/perception/sensor_frame_builder.py b/PhyAgentOS/runtime/perception/sensor_frame_builder.py index d777d397..0ccaee16 100644 --- a/PhyAgentOS/runtime/perception/sensor_frame_builder.py +++ b/PhyAgentOS/runtime/perception/sensor_frame_builder.py @@ -6,9 +6,9 @@ import numpy as np +from PhyAgentOS.runtime.errors import SchemaValidationError from PhyAgentOS.runtime.perception.config_resolver import ResolvedPerceptionPlan, sensor_by_id from PhyAgentOS.runtime.perception.sensor_frame import SensorFrame -from PhyAgentOS.runtime.watchdog.errors import SchemaValidationError class SensorFrameBuilder: diff --git a/PhyAgentOS/runtime/policy/b1k_websocket_client.py b/PhyAgentOS/runtime/policy/b1k_websocket_client.py index c3acf3a3..76dc17c2 100644 --- a/PhyAgentOS/runtime/policy/b1k_websocket_client.py +++ b/PhyAgentOS/runtime/policy/b1k_websocket_client.py @@ -16,13 +16,13 @@ import requests import websocket -from PhyAgentOS.runtime.policy.base_client import BasePolicyClient -from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb -from PhyAgentOS.runtime.watchdog.errors import ( +from PhyAgentOS.runtime.errors import ( PolicyConnectionError, PolicyProtocolError, PolicyTimeoutError, ) +from PhyAgentOS.runtime.policy.base_client import BasePolicyClient +from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb class Behavior1kWebsocketPolicyClient(BasePolicyClient): diff --git a/PhyAgentOS/runtime/policy/factory.py b/PhyAgentOS/runtime/policy/factory.py index 0ba99bac..d9d6f2e0 100644 --- a/PhyAgentOS/runtime/policy/factory.py +++ b/PhyAgentOS/runtime/policy/factory.py @@ -4,11 +4,11 @@ from urllib.parse import urlparse -from PhyAgentOS.runtime.policy.base_client import BasePolicyClient +from PhyAgentOS.runtime.errors import PolicyConnectionError from PhyAgentOS.runtime.policy.b1k_websocket_client import Behavior1kWebsocketPolicyClient +from PhyAgentOS.runtime.policy.base_client import BasePolicyClient from PhyAgentOS.runtime.policy.dummy_client import DummyPolicyClient from PhyAgentOS.runtime.policy.openpi.client import OpenPIClientPolicyWrapper -from PhyAgentOS.runtime.watchdog.errors import PolicyConnectionError def parse_policy_endpoint(endpoint: str) -> tuple[str, str, int]: diff --git a/PhyAgentOS/runtime/policy/openpi/client.py b/PhyAgentOS/runtime/policy/openpi/client.py index 6ca9b53a..8fdc0600 100644 --- a/PhyAgentOS/runtime/policy/openpi/client.py +++ b/PhyAgentOS/runtime/policy/openpi/client.py @@ -9,13 +9,13 @@ import numpy as np import websocket -from PhyAgentOS.runtime.policy.base_client import BasePolicyClient -from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb -from PhyAgentOS.runtime.watchdog.errors import ( +from PhyAgentOS.runtime.errors import ( PolicyConnectionError, PolicyProtocolError, PolicyTimeoutError, ) +from PhyAgentOS.runtime.policy.base_client import BasePolicyClient +from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb class OpenPIClientPolicyWrapper(BasePolicyClient): diff --git a/PhyAgentOS/runtime/policy/openpi/lerobot_pi0_server.py b/PhyAgentOS/runtime/policy/openpi/lerobot_pi0_server.py index cebce7b3..f53d4071 100644 --- a/PhyAgentOS/runtime/policy/openpi/lerobot_pi0_server.py +++ b/PhyAgentOS/runtime/policy/openpi/lerobot_pi0_server.py @@ -13,9 +13,8 @@ import numpy as np +from PhyAgentOS.runtime.errors import PolicyProtocolError from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb -from PhyAgentOS.runtime.watchdog.errors import PolicyProtocolError - WEBSOCKET_KEEPALIVE_DISABLED = { "ping_interval": None, diff --git a/PhyAgentOS/runtime/policy/openpi/native_openpi_server.py b/PhyAgentOS/runtime/policy/openpi/native_openpi_server.py index e5613dbf..e75b74f7 100644 --- a/PhyAgentOS/runtime/policy/openpi/native_openpi_server.py +++ b/PhyAgentOS/runtime/policy/openpi/native_openpi_server.py @@ -18,9 +18,8 @@ import numpy as np +from PhyAgentOS.runtime.errors import PolicyProtocolError from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb -from PhyAgentOS.runtime.watchdog.errors import PolicyProtocolError - _DEFAULT_LIBERO_CHECKPOINTS = { "pi0_libero": "gs://openpi-assets/checkpoints/pi0_libero", diff --git a/PhyAgentOS/runtime/policy/openvla/libero_server.py b/PhyAgentOS/runtime/policy/openvla/libero_server.py index 7b96df6f..d662681d 100644 --- a/PhyAgentOS/runtime/policy/openvla/libero_server.py +++ b/PhyAgentOS/runtime/policy/openvla/libero_server.py @@ -8,10 +8,10 @@ import json import logging import os -from pathlib import Path import random import time import traceback +from pathlib import Path from typing import Any import numpy as np @@ -20,9 +20,8 @@ os.environ.setdefault("USE_FLAX", "0") os.environ.setdefault("TRANSFORMERS_NO_TF", "1") +from PhyAgentOS.runtime.errors import PolicyProtocolError from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb -from PhyAgentOS.runtime.watchdog.errors import PolicyProtocolError - OFFICIAL_OPENVLA_CENTER_CROP_AREA = 0.9 OFFICIAL_OPENVLA_SEED = 7 diff --git a/PhyAgentOS/runtime/policy/xvla/libero_server.py b/PhyAgentOS/runtime/policy/xvla/libero_server.py index 7897351b..ce64f3d0 100644 --- a/PhyAgentOS/runtime/policy/xvla/libero_server.py +++ b/PhyAgentOS/runtime/policy/xvla/libero_server.py @@ -17,8 +17,8 @@ os.environ.setdefault("USE_FLAX", "0") os.environ.setdefault("TRANSFORMERS_NO_TF", "1") +from PhyAgentOS.runtime.errors import PolicyProtocolError from PhyAgentOS.runtime.policy.msgpack_numpy import packb, unpackb -from PhyAgentOS.runtime.watchdog.errors import PolicyProtocolError class XVLALiberoPolicy: diff --git a/PhyAgentOS/runtime/sessions/session_runner.py b/PhyAgentOS/runtime/sessions/session_runner.py index a5195a3d..60095fdd 100644 --- a/PhyAgentOS/runtime/sessions/session_runner.py +++ b/PhyAgentOS/runtime/sessions/session_runner.py @@ -6,15 +6,22 @@ from uuid import uuid4 from PhyAgentOS.runtime.adapters.factory import build_adapter_stack +from PhyAgentOS.runtime.errors import PolicyProtocolError from PhyAgentOS.runtime.perception.config_resolver import ResolvedPerceptionPlan from PhyAgentOS.runtime.perception.perception_runtime import PerceptionRuntime from PhyAgentOS.runtime.policy.base_client import BasePolicyClient -from PhyAgentOS.runtime.schemas import AdapterPlan, SessionResult, SessionSpec, SkillRuntimeSpec, TargetSpec, TargetToolManifest +from PhyAgentOS.runtime.schemas import ( + AdapterPlan, + SessionResult, + SessionSpec, + SkillRuntimeSpec, + TargetSpec, + TargetToolManifest, +) from PhyAgentOS.runtime.sessions.models import SessionState, SkillContext, SkillRuntimeResult from PhyAgentOS.runtime.sessions.target_session_handle import TargetSessionHandle from PhyAgentOS.runtime.skillruntime.builtin import BuiltinSkillRuntime from PhyAgentOS.runtime.skillruntime.policy import PolicySkillRuntime -from PhyAgentOS.runtime.watchdog.errors import PolicyProtocolError class SessionRunner: diff --git a/PhyAgentOS/runtime/skillruntime/builtin/command_sim.py b/PhyAgentOS/runtime/skillruntime/builtin/command_sim.py index 9f2eeee6..67c4a516 100644 --- a/PhyAgentOS/runtime/skillruntime/builtin/command_sim.py +++ b/PhyAgentOS/runtime/skillruntime/builtin/command_sim.py @@ -5,10 +5,10 @@ import time from typing import Any +from PhyAgentOS.runtime.errors import AdapterError from PhyAgentOS.runtime.schemas import AdapterPlan from PhyAgentOS.runtime.sessions.models import SkillContext, SkillRuntimeResult from PhyAgentOS.runtime.skillruntime.builtin.base import BuiltinSkillRuntime -from PhyAgentOS.runtime.watchdog.errors import AdapterError class CommandSimSkillRuntime(BuiltinSkillRuntime): diff --git a/PhyAgentOS/runtime/skillruntime/builtin/libero_benchmark.py b/PhyAgentOS/runtime/skillruntime/builtin/libero_benchmark.py index bf1e9c31..06f8b3cb 100644 --- a/PhyAgentOS/runtime/skillruntime/builtin/libero_benchmark.py +++ b/PhyAgentOS/runtime/skillruntime/builtin/libero_benchmark.py @@ -2,18 +2,18 @@ from __future__ import annotations -import time import base64 import hashlib import hmac import json -from urllib.parse import urlparse +import time from typing import Any +from urllib.parse import urlparse +from PhyAgentOS.runtime.errors import AdapterError from PhyAgentOS.runtime.schemas import AdapterPlan, BenchmarkJobRequest from PhyAgentOS.runtime.sessions.models import SkillContext, SkillRuntimeResult from PhyAgentOS.runtime.skillruntime.builtin.base import BuiltinSkillRuntime -from PhyAgentOS.runtime.watchdog.errors import AdapterError class LiberoBenchmarkSkillRuntime(BuiltinSkillRuntime): diff --git a/PhyAgentOS/runtime/skillruntime/policy/openpi.py b/PhyAgentOS/runtime/skillruntime/policy/openpi.py index a54c3530..ee585d59 100644 --- a/PhyAgentOS/runtime/skillruntime/policy/openpi.py +++ b/PhyAgentOS/runtime/skillruntime/policy/openpi.py @@ -5,11 +5,11 @@ from statistics import mean from PhyAgentOS.runtime.adapters.factory import build_policy_adapter +from PhyAgentOS.runtime.errors import PolicyProtocolError from PhyAgentOS.runtime.policy.base_client import BasePolicyClient from PhyAgentOS.runtime.schemas import AdapterPlan from PhyAgentOS.runtime.sessions.models import EnvironmentRequest, SkillContext, SkillRuntimeResult from PhyAgentOS.runtime.skillruntime.policy.base import PolicySkillRuntime -from PhyAgentOS.runtime.watchdog.errors import PolicyProtocolError class OpenPISkillRuntime(PolicySkillRuntime): diff --git a/PhyAgentOS/runtime/targets/factory.py b/PhyAgentOS/runtime/targets/factory.py index 9477b333..a7095101 100644 --- a/PhyAgentOS/runtime/targets/factory.py +++ b/PhyAgentOS/runtime/targets/factory.py @@ -6,6 +6,7 @@ from urllib.parse import urlparse from PhyAgentOS.runtime.communication.target_ws_client import TargetWSClient +from PhyAgentOS.runtime.errors import TargetBuildError from PhyAgentOS.runtime.schemas import TargetSpec from PhyAgentOS.runtime.targets.base import BaseRolloutTarget from PhyAgentOS.runtime.targets.local.dummy_sim_target import DummySimTarget @@ -13,7 +14,6 @@ from PhyAgentOS.runtime.targets.remote.isaacsim.proxy import IsaacSimRemoteTargetProxy from PhyAgentOS.runtime.targets.remote.libero.proxy import LiberoRemoteTargetProxy from PhyAgentOS.runtime.targets.remote.proxy import RemoteTargetProxy -from PhyAgentOS.runtime.watchdog.errors import TargetBuildError LocalTargetFactory = Callable[[TargetSpec], BaseRolloutTarget] RemoteTargetFactory = Callable[[TargetSpec, TargetWSClient], BaseRolloutTarget] diff --git a/PhyAgentOS/runtime/targets/local/dummy_sim_target.py b/PhyAgentOS/runtime/targets/local/dummy_sim_target.py index d7c5166b..e5d8c188 100644 --- a/PhyAgentOS/runtime/targets/local/dummy_sim_target.py +++ b/PhyAgentOS/runtime/targets/local/dummy_sim_target.py @@ -6,8 +6,8 @@ import numpy as np +from PhyAgentOS.runtime.errors import TargetStepError from PhyAgentOS.runtime.targets.local.base import BaseLocalTarget -from PhyAgentOS.runtime.watchdog.errors import TargetStepError class DummySimTarget(BaseLocalTarget): diff --git a/PhyAgentOS/runtime/targets/remote/behavior1k/proxy.py b/PhyAgentOS/runtime/targets/remote/behavior1k/proxy.py index 5b29236d..8b3a2a7b 100644 --- a/PhyAgentOS/runtime/targets/remote/behavior1k/proxy.py +++ b/PhyAgentOS/runtime/targets/remote/behavior1k/proxy.py @@ -7,9 +7,8 @@ import numpy as np from PhyAgentOS.runtime.communication.target_ws_client import TargetWSClient +from PhyAgentOS.runtime.errors import TargetProtocolError from PhyAgentOS.runtime.targets.remote.proxy import RemoteTargetProxy -from PhyAgentOS.runtime.watchdog.errors import TargetProtocolError - BEHAVIOR1K_DEFAULT_CONFIG = { "task_name": "turning_on_radio", diff --git a/PhyAgentOS/runtime/targets/remote/isaacsim/proxy.py b/PhyAgentOS/runtime/targets/remote/isaacsim/proxy.py index 6a5d2d30..93450b1a 100644 --- a/PhyAgentOS/runtime/targets/remote/isaacsim/proxy.py +++ b/PhyAgentOS/runtime/targets/remote/isaacsim/proxy.py @@ -7,9 +7,8 @@ import numpy as np from PhyAgentOS.runtime.communication.target_ws_client import TargetWSClient +from PhyAgentOS.runtime.errors import TargetProtocolError from PhyAgentOS.runtime.targets.remote.proxy import RemoteTargetProxy -from PhyAgentOS.runtime.watchdog.errors import TargetProtocolError - ISAAC_DEFAULT_CONFIG = { "robot_id": "", diff --git a/PhyAgentOS/runtime/targets/remote/libero/proxy.py b/PhyAgentOS/runtime/targets/remote/libero/proxy.py index 6b680be0..2213e985 100644 --- a/PhyAgentOS/runtime/targets/remote/libero/proxy.py +++ b/PhyAgentOS/runtime/targets/remote/libero/proxy.py @@ -7,9 +7,8 @@ import numpy as np from PhyAgentOS.runtime.communication.target_ws_client import TargetWSClient +from PhyAgentOS.runtime.errors import TargetProtocolError from PhyAgentOS.runtime.targets.remote.proxy import RemoteTargetProxy -from PhyAgentOS.runtime.watchdog.errors import TargetProtocolError - LIBERO_DEFAULT_CONFIG = { "benchmark_name": "libero_spatial", diff --git a/PhyAgentOS/runtime/watchdog/errors.py b/PhyAgentOS/runtime/watchdog/errors.py index a91136bc..2b280bff 100644 --- a/PhyAgentOS/runtime/watchdog/errors.py +++ b/PhyAgentOS/runtime/watchdog/errors.py @@ -1,86 +1,46 @@ -"""Runtime watchdog error hierarchy and failure mapping.""" +"""Compatibility shim: re-exports shared exception types from the neutral base module. -from __future__ import annotations - - -class RuntimeErrorBase(Exception): - """Base class for recoverable runtime v2 failures.""" - - -class SchemaValidationError(RuntimeErrorBase): - pass - - -class TargetBuildError(RuntimeErrorBase): - pass - - -class TargetResetError(RuntimeErrorBase): - pass - - -class TargetStepError(RuntimeErrorBase): - pass - - -class TargetConnectionError(RuntimeErrorBase): - pass - - -class TargetProtocolError(RuntimeErrorBase): - pass - - -class AdapterError(RuntimeErrorBase): - pass - - -class PolicyClientError(RuntimeErrorBase): - pass - - -class PolicyConnectionError(PolicyClientError): - pass - - -class PolicyTimeoutError(PolicyClientError): - pass - - -class PolicyProtocolError(PolicyClientError): - pass - - -class SessionTimeoutError(RuntimeErrorBase): - pass - - -def error_code_for(exc: Exception) -> str: - """Return the protocol error code for an exception.""" - mapping = { - SchemaValidationError: "SCHEMA_VALIDATION", - TargetBuildError: "TARGET_BUILD", - TargetResetError: "TARGET_RESET", - TargetStepError: "TARGET_STEP", - TargetConnectionError: "TARGET_CONNECTION", - TargetProtocolError: "TARGET_PROTOCOL", - AdapterError: "ADAPTER", - PolicyTimeoutError: "POLICY_TIMEOUT", - PolicyProtocolError: "POLICY_PROTOCOL", - PolicyConnectionError: "POLICY_CONNECTION", - PolicyClientError: "POLICY_CLIENT", - SessionTimeoutError: "SESSION_TIMEOUT", - } - for cls, code in mapping.items(): - if isinstance(exc, cls): - return code - return "RUNTIME_ERROR" +Since the issue #83 fix, shared exception types live in +``PhyAgentOS.runtime.errors``. This module is kept only for backward +compatibility - legacy callers may still use +``from PhyAgentOS.runtime.watchdog.errors import X``, but new code should +import directly from ``PhyAgentOS.runtime.errors``. +""" +from __future__ import annotations -def terminal_status_for(exc: Exception) -> str: - """Return the terminal session status for an exception.""" - if isinstance(exc, SchemaValidationError): - return "rejected" - if isinstance(exc, SessionTimeoutError): - return "timed_out" - return "failed" +from PhyAgentOS.runtime.errors import ( + AdapterError, + PolicyClientError, + PolicyConnectionError, + PolicyProtocolError, + PolicyTimeoutError, + RuntimeErrorBase, + SchemaValidationError, + SessionTimeoutError, + TargetBuildError, + TargetConnectionError, + TargetProtocolError, + TargetResetError, + TargetStepError, + error_code_for, + terminal_status_for, +) + +__all__ = [ + "RuntimeErrorBase", + "SchemaValidationError", + "TargetBuildError", + "TargetResetError", + "TargetStepError", + "TargetConnectionError", + "TargetProtocolError", + "AdapterError", + "PolicyClientError", + "PolicyConnectionError", + "PolicyTimeoutError", + "PolicyProtocolError", + "SessionTimeoutError", + "error_code_for", + "terminal_status_for", +] diff --git a/tests/runtime/test_runtime_errors.py b/tests/runtime/test_runtime_errors.py new file mode 100644 index 00000000..00b44d7d --- /dev/null +++ b/tests/runtime/test_runtime_errors.py @@ -0,0 +1,126 @@ +"""Tests for the PhyAgentOS.runtime.errors shared exception module. + +Verifies the goal of issue #83: shared exception types are moved from the +watchdog orchestration layer into the neutral ``runtime.errors`` base module, +while ``watchdog.errors`` stays as a compatibility layer preserving backward +compatibility (same objects, ``is`` equality). +""" + +from __future__ import annotations + +import pytest + +from PhyAgentOS.runtime.errors import ( + AdapterError, + PolicyClientError, + PolicyConnectionError, + PolicyProtocolError, + PolicyTimeoutError, + RuntimeErrorBase, + SchemaValidationError, + SessionTimeoutError, + TargetBuildError, + TargetConnectionError, + TargetProtocolError, + TargetResetError, + TargetStepError, + error_code_for, + terminal_status_for, +) + + +# --------------------------------------------------------------------------- +# Exception hierarchy +# --------------------------------------------------------------------------- +def test_all_exceptions_share_runtime_error_base() -> None: + for exc_cls in ( + SchemaValidationError, + TargetBuildError, + TargetResetError, + TargetStepError, + TargetConnectionError, + TargetProtocolError, + AdapterError, + PolicyClientError, + SessionTimeoutError, + ): + assert issubclass(exc_cls, RuntimeErrorBase) + + +def test_policy_exceptions_have_policy_client_base() -> None: + for exc_cls in (PolicyConnectionError, PolicyTimeoutError, PolicyProtocolError): + assert issubclass(exc_cls, PolicyClientError) + + +# --------------------------------------------------------------------------- +# error_code_for mapping +# --------------------------------------------------------------------------- +@pytest.mark.parametrize( + ("exc", "expected_code"), + [ + (SchemaValidationError(), "SCHEMA_VALIDATION"), + (TargetBuildError(), "TARGET_BUILD"), + (TargetResetError(), "TARGET_RESET"), + (TargetStepError(), "TARGET_STEP"), + (TargetConnectionError(), "TARGET_CONNECTION"), + (TargetProtocolError(), "TARGET_PROTOCOL"), + (AdapterError(), "ADAPTER"), + (PolicyTimeoutError(), "POLICY_TIMEOUT"), + (PolicyProtocolError(), "POLICY_PROTOCOL"), + (PolicyConnectionError(), "POLICY_CONNECTION"), + (PolicyClientError(), "POLICY_CLIENT"), + (SessionTimeoutError(), "SESSION_TIMEOUT"), + ], +) +def test_error_code_for_known_exceptions(exc: Exception, expected_code: str) -> None: + assert error_code_for(exc) == expected_code + + +def test_error_code_for_subclass_uses_most_specific_code() -> None: + # A subclass must match its own code, not PolicyClientError's POLICY_CLIENT + assert error_code_for(PolicyTimeoutError()) == "POLICY_TIMEOUT" + assert error_code_for(PolicyConnectionError()) == "POLICY_CONNECTION" + + +def test_error_code_for_unknown_exception_returns_runtime_error() -> None: + assert error_code_for(ValueError("boom")) == "RUNTIME_ERROR" + + +# --------------------------------------------------------------------------- +# terminal_status_for mapping +# --------------------------------------------------------------------------- +@pytest.mark.parametrize( + ("exc", "expected_status"), + [ + (SchemaValidationError(), "rejected"), + (SessionTimeoutError(), "timed_out"), + (TargetStepError(), "failed"), + (PolicyProtocolError(), "failed"), + (ValueError("boom"), "failed"), + ], +) +def test_terminal_status_for(exc: Exception, expected_status: str) -> None: + assert terminal_status_for(exc) == expected_status + + +# --------------------------------------------------------------------------- +# Compatibility layer: watchdog.errors must expose the same objects as runtime.errors +# --------------------------------------------------------------------------- +def test_watchdog_errors_re_exports_same_objects() -> None: + from PhyAgentOS.runtime.watchdog import errors as watchdog_errors + + assert watchdog_errors.RuntimeErrorBase is RuntimeErrorBase + assert watchdog_errors.SchemaValidationError is SchemaValidationError + assert watchdog_errors.TargetBuildError is TargetBuildError + assert watchdog_errors.TargetResetError is TargetResetError + assert watchdog_errors.TargetStepError is TargetStepError + assert watchdog_errors.TargetConnectionError is TargetConnectionError + assert watchdog_errors.TargetProtocolError is TargetProtocolError + assert watchdog_errors.AdapterError is AdapterError + assert watchdog_errors.PolicyClientError is PolicyClientError + assert watchdog_errors.PolicyConnectionError is PolicyConnectionError + assert watchdog_errors.PolicyTimeoutError is PolicyTimeoutError + assert watchdog_errors.PolicyProtocolError is PolicyProtocolError + assert watchdog_errors.SessionTimeoutError is SessionTimeoutError + assert watchdog_errors.error_code_for is error_code_for + assert watchdog_errors.terminal_status_for is terminal_status_for