simulo-interfaces 0.20.2__tar.gz → 0.22.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {simulo_interfaces-0.20.2/src/simulo_interfaces.egg-info → simulo_interfaces-0.22.0}/PKG-INFO +2 -2
  2. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/PYPI.md +1 -1
  3. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/pyproject.toml +1 -1
  4. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/__init__.py +18 -8
  5. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/__init__.py +11 -7
  6. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/asset.py +1 -1
  7. simulo_interfaces-0.22.0/src/simulo/interfaces/authoring/checkpoint.py +84 -0
  8. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/primitives.py +0 -2
  9. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/record.py +1 -1
  10. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/scene.py +1 -2
  11. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/terrain.py +2 -3
  12. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/world.py +4 -8
  13. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/ids.py +40 -20
  14. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/__init__.py +178 -97
  15. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/app.py +51 -9
  16. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/asset_catalog.py +10 -14
  17. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/callbacks.py +2 -2
  18. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/domain.py +3 -18
  19. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/enums.py +31 -24
  20. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/manifest.py +33 -23
  21. simulo_interfaces-0.20.2/src/simulo/interfaces/platform/policy_bundle.py → simulo_interfaces-0.22.0/src/simulo/interfaces/platform/onnx_bundle.py +137 -141
  22. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/outputs.py +62 -122
  23. simulo_interfaces-0.22.0/src/simulo/interfaces/platform/preview.py +85 -0
  24. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/runs.py +53 -10
  25. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/submit.py +209 -222
  26. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/systems.py +5 -3
  27. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/__init__.py +3 -5
  28. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/components.py +3 -3
  29. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/policy.py +3 -3
  30. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/task.py +6 -0
  31. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0/src/simulo_interfaces.egg-info}/PKG-INFO +2 -2
  32. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo_interfaces.egg-info/SOURCES.txt +3 -2
  33. simulo_interfaces-0.20.2/src/simulo/interfaces/runtime/scenario.py +0 -44
  34. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/MANIFEST.in +0 -0
  35. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/setup.cfg +0 -0
  36. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/actuator.py +0 -0
  37. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/entity.py +0 -0
  38. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/light.py +0 -0
  39. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/materials.py +0 -0
  40. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/physics.py +0 -0
  41. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/pose.py +0 -0
  42. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/prop.py +0 -0
  43. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/robot.py +0 -0
  44. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/sensor.py +0 -0
  45. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/authoring/visual.py +0 -0
  46. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/exceptions.py +0 -0
  47. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/_payload.py +0 -0
  48. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/asset.py +0 -0
  49. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/debug.py +0 -0
  50. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/job_events.py +0 -0
  51. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/runtime.py +0 -0
  52. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/platform/volume.py +0 -0
  53. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/py.typed +0 -0
  54. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/anomaly.py +0 -0
  55. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/env.py +0 -0
  56. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/player.py +0 -0
  57. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/tensors.py +0 -0
  58. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo/interfaces/runtime/trainer.py +0 -0
  59. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo_interfaces.egg-info/dependency_links.txt +0 -0
  60. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo_interfaces.egg-info/requires.txt +0 -0
  61. {simulo_interfaces-0.20.2 → simulo_interfaces-0.22.0}/src/simulo_interfaces.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulo-interfaces
3
- Version: 0.20.2
3
+ Version: 0.22.0
4
4
  Summary: Typed Python contracts for the Simulo cloud robotics SDK and managed simulation runtime.
5
5
  Author-email: Simulo Team <team@simulo.ai>
6
6
  License: BSD-3-Clause
@@ -47,7 +47,7 @@ Requires-Dist: twine>=5.1; extra == "release"
47
47
  shared by the [Simulo SDK](https://pypi.org/project/simulo/) and its managed
48
48
  cloud robotics simulation runtime. It defines protocols, enums, identifiers,
49
49
  and dataclasses for robot-learning tasks, environments, policies, trainers,
50
- applications, jobs, assets, checkpoints, and trained models.
50
+ applications, jobs, assets, policies, checkpoints, and policy exports.
51
51
 
52
52
  ## Install Simulo
53
53
 
@@ -4,7 +4,7 @@
4
4
  shared by the [Simulo SDK](https://pypi.org/project/simulo/) and its managed
5
5
  cloud robotics simulation runtime. It defines protocols, enums, identifiers,
6
6
  and dataclasses for robot-learning tasks, environments, policies, trainers,
7
- applications, jobs, assets, checkpoints, and trained models.
7
+ applications, jobs, assets, policies, checkpoints, and policy exports.
8
8
 
9
9
  ## Install Simulo
10
10
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simulo-interfaces"
7
- version = "0.20.2"
7
+ version = "0.22.0"
8
8
  description = "Typed Python contracts for the Simulo cloud robotics SDK and managed simulation runtime."
9
9
  readme = "PYPI.md"
10
10
  requires-python = ">=3.11"
@@ -5,11 +5,11 @@ torch / numpy / gymnasium / Isaac / AWS / HTTP / DB installed. Two parts:
5
5
 
6
6
  * **Part A — ``simulo.interfaces.runtime``**: tensor-library-agnostic structural
7
7
  Protocols mirroring the ``simulo.core`` runtime surface (Task, Policy,
8
- Trainer, Player, LearningEnv, Scenario, and the observation/reward/termination
8
+ Trainer, Player, LearningEnv, and the observation/reward/termination
9
9
  components).
10
10
  * **Part B — ``simulo.interfaces.platform``**: platform/workspace domain
11
11
  contracts — wire-stable enums, frozen domain dataclasses (Project, Package,
12
- Job, Resource, Checkpoint, TrainedModel, Tag), and the cloud-execution
12
+ Job, Resource, Checkpoint, Tag), and the cloud-execution
13
13
  Protocols (App, Runtime, Asset, Volume, callbacks, and
14
14
  debug/replay/visualization sessions).
15
15
 
@@ -19,6 +19,7 @@ namespace that ``simulo-backend`` also contributes to; it ships NO
19
19
  """
20
20
 
21
21
  from simulo.interfaces import platform, runtime
22
+ from simulo.interfaces.authoring import PolicyCheckpoint
22
23
  from simulo.interfaces.exceptions import (
23
24
  ContractViolationError,
24
25
  ImportResolutionError,
@@ -29,29 +30,36 @@ from simulo.interfaces.exceptions import (
29
30
  )
30
31
  from simulo.interfaces.ids import (
31
32
  CheckpointId,
33
+ CheckpointRefIsJobError,
32
34
  Digest,
33
35
  JobId,
34
36
  JobPublicId,
35
- ModelPublicId,
36
37
  OrganizationId,
37
38
  OutputPublicId,
38
39
  PackageId,
40
+ PolicyPublicId,
39
41
  ProjectId,
40
42
  RecordingPublicId,
41
43
  ResourceId,
42
44
  ResourceUri,
43
45
  TagId,
44
- TrainedModelId,
46
+ checkpoint_ref_is_job_hint,
47
+ parse_checkpoint_ref,
45
48
  parse_job_public_id,
46
- parse_model_public_id,
47
49
  parse_output_public_id,
48
50
  parse_recording_public_id,
51
+ policy_id_for_job,
49
52
  )
53
+ from simulo.interfaces.platform.enums import JobType
54
+ from simulo.interfaces.runtime import PolicyNetworkProtocol
50
55
 
51
56
  __all__ = [
52
57
  # subpackages
53
58
  "platform",
54
59
  "runtime",
60
+ "JobType",
61
+ "PolicyCheckpoint",
62
+ "PolicyNetworkProtocol",
55
63
  # exception hierarchy
56
64
  "SimuloError",
57
65
  "ContractViolationError",
@@ -65,16 +73,18 @@ __all__ = [
65
73
  "PackageId",
66
74
  "JobId",
67
75
  "JobPublicId",
68
- "ModelPublicId",
76
+ "PolicyPublicId",
69
77
  "RecordingPublicId",
70
78
  "OutputPublicId",
71
79
  "parse_job_public_id",
72
- "parse_model_public_id",
80
+ "parse_checkpoint_ref",
81
+ "policy_id_for_job",
82
+ "checkpoint_ref_is_job_hint",
83
+ "CheckpointRefIsJobError",
73
84
  "parse_recording_public_id",
74
85
  "parse_output_public_id",
75
86
  "ResourceId",
76
87
  "CheckpointId",
77
- "TrainedModelId",
78
88
  "TagId",
79
89
  "ResourceUri",
80
90
  "Digest",
@@ -41,13 +41,14 @@ waves add the remaining RELOCATE-classified types and MIRROR Protocols.
41
41
  **R-C3 is the hard constraint on everything that lands here:** no module in
42
42
  this package — or anywhere else in ``simulo-interfaces`` — may import
43
43
  ``simulo.core``, ``simulo.backend``, or the thin client's private internal
44
- package, at import time or at call time (the ``Scene`` trap: zero torch
45
- imports, but call-time imports of torch-coupled ``core`` modules deep inside a
46
- method body). Guarded by ``tests/test_no_core_dependency.py`` in this package —
47
- both a static import-statement guard and a runtime ``sys.modules`` check that
48
- imports every submodule AND instantiates/calls the relocated API, because the
49
- static guard alone cannot see ``from simulo import core``, dynamic access, or a
50
- call-time-only import buried in a method body.
44
+ package at import time. Calls must remain dependency-free too (the ``Scene``
45
+ trap), with one explicit execution-only bridge: ``PolicyCheckpoint.load()``
46
+ lazily imports ``simulo.core.policy.load_policy_network`` inside a job and
47
+ raises the documented submit-time error when the backend is absent. Guarded by
48
+ ``tests/test_no_core_dependency.py`` in this package — both a static
49
+ import-statement guard and isolated runtime checks that exercise the relocated
50
+ API, prove ordinary imports remain backend-free, and prove the loader fails
51
+ clearly in a submit-only installation.
51
52
 
52
53
  Two relocation mechanisms select which types land here and how (see the derived
53
54
  plan for the full worked example and rejected alternatives):
@@ -87,6 +88,7 @@ docstring, is the source of truth for what lands here and when.
87
88
 
88
89
  from simulo.interfaces.authoring.actuator import ActuatorProtocol
89
90
  from simulo.interfaces.authoring.asset import AssetSource, URDFAsset, USDAsset
91
+ from simulo.interfaces.authoring.checkpoint import PolicyCheckpoint
90
92
  from simulo.interfaces.authoring.entity import AssetEntity, Entity
91
93
  from simulo.interfaces.authoring.light import DistantLight, DomeLight, Light, LightConfig
92
94
  from simulo.interfaces.authoring.materials import Material, SurfaceMaterial
@@ -171,6 +173,8 @@ __all__ = [
171
173
  # record (RELOCATED Wave C4 — the MCAP recording config; its helper
172
174
  # functions stay importable from ``simulo.interfaces.authoring.record``)
173
175
  "RecordConfig",
176
+ # injected policy input (dependency-free; loading is deferred to execution)
177
+ "PolicyCheckpoint",
174
178
  # visual
175
179
  "VisualMarkerBase",
176
180
  "AxesMarker",
@@ -40,7 +40,7 @@ class USDAsset(AssetSource):
40
40
  """USD file asset.
41
41
 
42
42
  Attributes:
43
- path: Path to USD file (supports file://, nucleus:// schemes). The
43
+ path: Path to a local or supported remote USD file. The
44
44
  legacy simulo:// path alias is REMOVED — 'simulo/...' is a catalog
45
45
  ref ([publisher/]kind/name[:vN], 'simulo' = the global-catalog
46
46
  publisher), resolved through
@@ -0,0 +1,84 @@
1
+ """Dependency-free handle for a policy checkpoint injected into a job."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from dataclasses import dataclass
7
+ from importlib import import_module
8
+ from pathlib import Path
9
+ from typing import Any, cast
10
+
11
+ from simulo.interfaces.runtime.policy import PolicyNetworkProtocol
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class PolicyCheckpoint:
16
+ """A resolved policy checkpoint supplied to a play or evaluation job.
17
+
18
+ The contract contains only standard-library values. Loading the policy is
19
+ deliberately deferred until execution, where ``simulo-backend`` provides
20
+ the concrete policy-network loader.
21
+ """
22
+
23
+ checkpoint: str
24
+ policy_id: str
25
+ kind: str
26
+ path: Path
27
+ meta: Mapping[str, Any]
28
+
29
+ @property
30
+ def iteration(self) -> int:
31
+ """Training iteration stored in the checkpoint sidecar."""
32
+
33
+ return cast(int, self.meta["completed_iterations"])
34
+
35
+ @property
36
+ def max_iterations(self) -> int:
37
+ """Configured training limit stored in the checkpoint sidecar."""
38
+
39
+ return cast(int, self.meta["max_iterations"])
40
+
41
+ @property
42
+ def reward(self) -> float | None:
43
+ """Best-checkpoint reward, or ``None`` when the sidecar has none."""
44
+
45
+ return cast(float | None, self.meta.get("reward"))
46
+
47
+ @property
48
+ def obs_dim(self) -> int:
49
+ """Observation width used to train the checkpoint."""
50
+
51
+ return cast(int, self.meta["obs_dim"])
52
+
53
+ @property
54
+ def act_dim(self) -> int:
55
+ """Action width produced by the checkpoint."""
56
+
57
+ return cast(int, self.meta["act_dim"])
58
+
59
+ @property
60
+ def task_name(self) -> str:
61
+ """Name of the task class used for training, if the sidecar has it."""
62
+
63
+ return cast(str, self.meta.get("task_name", "unknown"))
64
+
65
+ @property
66
+ def task_digest(self) -> str:
67
+ """Digest of the file that defined the training task, if available."""
68
+
69
+ return cast(str, self.meta.get("task_digest", "unknown"))
70
+
71
+ def load(self, device: str = "cuda") -> PolicyNetworkProtocol:
72
+ """Load the checkpoint as a policy network inside a Simulo job."""
73
+
74
+ try:
75
+ policy_module = import_module("simulo.core.policy")
76
+ except ImportError as exc:
77
+ raise RuntimeError(
78
+ "PolicyCheckpoint.load() runs inside a job on Simulo; it is not available at submit."
79
+ ) from exc
80
+ loader = getattr(policy_module, "load_policy_network")
81
+ return cast(PolicyNetworkProtocol, loader(self, device=device))
82
+
83
+
84
+ __all__ = ["PolicyCheckpoint"]
@@ -100,8 +100,6 @@ class Transform:
100
100
  scene.add(t2, at="/World/Origin2")
101
101
  ```
102
102
 
103
- Backend Mapping:
104
- IsaacLab: Maps to Xform prim with translation
105
103
  """
106
104
 
107
105
  def __init__(
@@ -194,7 +194,7 @@ class RecordConfig:
194
194
  mitigation depends on the tri-state.
195
195
  """
196
196
 
197
- output_path: Union[str, "os.PathLike[str]", Path]
197
+ output_path: Optional[Union[str, "os.PathLike[str]", Path]] = None
198
198
 
199
199
  # Identity
200
200
  run_id: Optional[str] = None
@@ -5,8 +5,7 @@ the ``Scene`` implementation itself stays in the backend package — it is the
5
5
  backend adapter (it writes backend-private state and drives engine-private
6
6
  methods when the simulation flushes), so its *implementation* cannot live in a
7
7
  zero-dependency package. What CAN live here is its declared public surface:
8
- these Protocols name exactly what authoring code — a ``build(scene)`` method in
9
- a task or scenario — may rely on.
8
+ these Protocols name exactly what a task's ``build(scene)`` method may rely on.
10
9
 
11
10
  The backend's concrete ``Scene`` / ``SceneGroup`` classes explicitly inherit
12
11
  these Protocols (nominal conformance, the same pattern the ``runtime``
@@ -87,7 +87,7 @@ class RoughTerrain(TerrainConfig):
87
87
 
88
88
  This terrain type generates a grid of sub-terrains with various
89
89
  difficulty levels, suitable for curriculum learning in locomotion
90
- tasks. Equivalent to IsaacLab's TerrainImporterCfg with TerrainGeneratorCfg.
90
+ tasks.
91
91
 
92
92
  Attributes:
93
93
  num_rows: Number of terrain rows (sub-terrain grid rows)
@@ -104,7 +104,7 @@ class RoughTerrain(TerrainConfig):
104
104
  ```python
105
105
  import simulo
106
106
 
107
- # Create rough terrain matching IsaacLab's H1 configuration
107
+ # Create a rough terrain configuration
108
108
  terrain = simulo.Terrain.rough(
109
109
  name="terrain",
110
110
  num_rows=10,
@@ -254,7 +254,6 @@ class Terrain:
254
254
 
255
255
  This creates a grid of sub-terrains with varying difficulty,
256
256
  suitable for curriculum learning in locomotion tasks.
257
- Equivalent to IsaacLab's TerrainGeneratorCfg with TerrainImporterCfg.
258
257
 
259
258
  Args:
260
259
  name: Terrain name
@@ -28,9 +28,7 @@ class USDWorld:
28
28
  Attributes:
29
29
  name: World name
30
30
  pose: Pose in space (usually identity for USD scenes)
31
- path: Path to USD file. Supports:
32
- - Local paths: "/path/to/scene.usd"
33
- - Nucleus paths: "nucleus://Isaac/Environments/..."
31
+ path: Path to a local or supported remote USD file.
34
32
  A catalog world (USD Asset Catalogs) is referenced via
35
33
  simulo.Asset.from_registry("simulo/world/<name>:v1") and mounted
36
34
  like any other asset — a "simulo://" path scheme is not
@@ -43,7 +41,7 @@ class USDWorld:
43
41
  # Load warehouse for inference
44
42
  warehouse = simulo.World.usd(
45
43
  name="warehouse",
46
- path="nucleus://Isaac/Environments/Simple_Warehouse/warehouse.usd",
44
+ path="/path/to/warehouse.usd",
47
45
  )
48
46
  scene.add(warehouse, at="/World", per_environment=False)
49
47
  ```
@@ -80,9 +78,7 @@ class World:
80
78
 
81
79
  Args:
82
80
  name: World name
83
- path: Path to USD file. Supports:
84
- - Local paths: "/path/to/scene.usd"
85
- - Nucleus paths: "nucleus://Isaac/Environments/..."
81
+ path: Path to a local or supported remote USD file.
86
82
  pose: Pose in space (usually identity for USD scenes)
87
83
  spawn_origin: Position (x, y, z) where robot should spawn
88
84
 
@@ -94,7 +90,7 @@ class World:
94
90
  # Inference in warehouse
95
91
  warehouse = simulo.World.usd(
96
92
  name="warehouse",
97
- path="nucleus://Isaac/Environments/Simple_Warehouse/warehouse.usd",
93
+ path="/path/to/warehouse.usd",
98
94
  spawn_origin=(0, 0, 0),
99
95
  )
100
96
  scene.add(warehouse, at="/World", per_environment=False)
@@ -31,7 +31,7 @@ AssetVersionId = NewType("AssetVersionId", str) # one immutable asset version (
31
31
  OutputId = NewType("OutputId", str) # a job-produced output in the /outputs projection (Plan B)
32
32
 
33
33
  JobPublicId = NewType("JobPublicId", str)
34
- ModelPublicId = NewType("ModelPublicId", str)
34
+ PolicyPublicId = NewType("PolicyPublicId", str)
35
35
  RecordingPublicId = NewType("RecordingPublicId", str)
36
36
  OutputPublicId = NewType("OutputPublicId", str)
37
37
 
@@ -43,9 +43,10 @@ _ASCII_LOWERCASE_TRANSLATION = str.maketrans(
43
43
  _JOB_STEM_PATTERN = r"[a-z]{3,10}-[a-z]{3,10}-[0-9a-hjkmnp-tv-z]{6}"
44
44
  _CANONICAL_CHILD_COUNTER_PATTERN = r"(?:(?!0000)[0-9]{4}|[1-9][0-9]{4,})"
45
45
  _JOB_PUBLIC_ID_RE = re.compile(rf"job_{_JOB_STEM_PATTERN}\Z")
46
- _MODEL_PUBLIC_ID_RE = re.compile(rf"mdl_{_JOB_STEM_PATTERN}-{_CANONICAL_CHILD_COUNTER_PATTERN}\Z")
47
46
  _RECORDING_PUBLIC_ID_RE = re.compile(rf"rec_{_JOB_STEM_PATTERN}-{_CANONICAL_CHILD_COUNTER_PATTERN}\Z")
48
47
  _OUTPUT_PUBLIC_ID_RE = re.compile(rf"out_{_JOB_STEM_PATTERN}-{_CANONICAL_CHILD_COUNTER_PATTERN}\Z")
48
+ _POLICY_CHECKPOINT_REF_RE = re.compile(rf"policy_({_JOB_STEM_PATTERN}):(best|latest)\Z")
49
+ _JOB_CHECKPOINT_REF_RE = re.compile(rf"job_({_JOB_STEM_PATTERN}):(best|latest)\Z")
49
50
  _MAX_JOB_PUBLIC_ID_LENGTH = 32
50
51
  _MAX_CHILD_PUBLIC_ID_LENGTH = 64
51
52
 
@@ -81,24 +82,6 @@ def parse_job_public_id(value: str) -> JobPublicId:
81
82
  )
82
83
 
83
84
 
84
- def parse_model_public_id(value: str) -> ModelPublicId:
85
- """Return a canonical Model ID such as ``mdl_quiet-cedar-7k3m4q-0001``.
86
-
87
- Only outer ASCII whitespace is trimmed and only ASCII ``A-Z`` is
88
- lowercased. Matching is exact and non-ASCII input is rejected. Counters
89
- use exactly four digits through ``9999`` and expand unpadded at ``10000``.
90
- """
91
-
92
- return ModelPublicId(
93
- _parse_public_id(
94
- value,
95
- parser="parse_model_public_id",
96
- pattern=_MODEL_PUBLIC_ID_RE,
97
- max_length=_MAX_CHILD_PUBLIC_ID_LENGTH,
98
- )
99
- )
100
-
101
-
102
85
  def parse_recording_public_id(value: str) -> RecordingPublicId:
103
86
  """Return a Recording ID such as ``rec_quiet-cedar-7k3m4q-0001``.
104
87
 
@@ -133,3 +116,40 @@ def parse_output_public_id(value: str) -> OutputPublicId:
133
116
  max_length=_MAX_CHILD_PUBLIC_ID_LENGTH,
134
117
  )
135
118
  )
119
+
120
+
121
+ class CheckpointRefIsJobError(ValueError):
122
+ """A checkpoint reference used a job ID where a policy ID is required."""
123
+
124
+ def __init__(self, stem: str, kind: str) -> None:
125
+ self.stem = stem
126
+ self.kind = kind
127
+ super().__init__(checkpoint_ref_is_job_hint(stem, kind))
128
+
129
+
130
+ def checkpoint_ref_is_job_hint(stem: str, kind: str) -> str:
131
+ """Format Rule 10's actionable job-reference correction."""
132
+
133
+ return f"job_{stem} is a job; did you mean policy_{stem}:{kind}?"
134
+
135
+
136
+ def policy_id_for_job(value: str) -> PolicyPublicId:
137
+ """Return the policy ID for one canonical public job ID."""
138
+
139
+ job_id = parse_job_public_id(value)
140
+ return PolicyPublicId(f"policy_{str(job_id).removeprefix('job_')}")
141
+
142
+
143
+ def parse_checkpoint_ref(value: str) -> tuple[PolicyPublicId, str]:
144
+ """Parse a normalized ``policy_<stem>:best|latest`` checkpoint reference."""
145
+
146
+ normalized = _normalize_public_id(value, parser="parse_checkpoint_ref")
147
+ match = _POLICY_CHECKPOINT_REF_RE.fullmatch(normalized)
148
+ if match is not None:
149
+ stem, kind = match.groups()
150
+ return PolicyPublicId(f"policy_{stem}"), kind
151
+ job_match = _JOB_CHECKPOINT_REF_RE.fullmatch(normalized)
152
+ if job_match is not None:
153
+ stem, kind = job_match.groups()
154
+ raise CheckpointRefIsJobError(stem, kind)
155
+ raise ValueError("parse_checkpoint_ref() requires policy_<stem>:best or policy_<stem>:latest.")