sequence-base 0.4.33__tar.gz → 0.5.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.
- {sequence_base-0.4.33 → sequence_base-0.5.0}/PKG-INFO +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/pyproject.toml +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/__init__.py +9 -8
- sequence_base-0.5.0/sequence_base/constants/cards.py +38 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/constants/version.py +4 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/__init__.py +40 -10
- sequence_base-0.5.0/sequence_base/contract/benchmarks.py +194 -0
- sequence_base-0.5.0/sequence_base/contract/connect.py +123 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/deployments.py +41 -25
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/eval.py +29 -32
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/flags.py +3 -4
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/own_io.py +14 -47
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/policy.py +105 -34
- sequence_base-0.5.0/sequence_base/contract/settings.py +357 -0
- sequence_base-0.5.0/sequence_base/contract/team.py +185 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/wire.py +9 -7
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/presets/robot_arm.py +9 -7
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schema_export.py +35 -13
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ActRequest.json +1 -15
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ActResponse.json +1 -15
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ActionChunk.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ActionContract.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ActionStep.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/AdapterPair.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/AddLocal.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Autoscaler.json +2 -23
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/BenchmarkRegisterRequest.json +35 -358
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/BenchmarkSpec.json +63 -129
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/BenchmarkStatusResponse.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/BootstrapResponse.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Camera.json +3 -3
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/CodeBundle.json +1 -1
- sequence_base-0.5.0/sequence_base/schemas/Concurrency.json +113 -0
- sequence_base-0.5.0/sequence_base/schemas/ConnectRequest.json +54 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ConnectResponse.json +95 -218
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/DeploymentAccepted.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/DeploymentPolicy.json +61 -237
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/DeploymentRequest.json +81 -265
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/DeploymentStatusResponse.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ErrorBody.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ErrorCodes.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Estimate.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/EvalDryRunResponse.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/EvalReport.json +14 -29
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/EvalRequest.json +5 -41
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/EvalResponse.json +1 -1
- sequence_base-0.5.0/sequence_base/schemas/GroupObservation.json +41 -0
- sequence_base-0.5.0/sequence_base/schemas/GroupObserve.json +13 -0
- sequence_base-0.5.0/sequence_base/schemas/GroupObserved.json +16 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageFrame.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageSpec.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageStepAddLocal.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageStepApt.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageStepEnv.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageStepProject.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageStepRun.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageStepTemplateFiles.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ImageStepUvPip.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/InferParam.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Lease.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/MetricAgg.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Observation.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ObservationContract.json +3 -3
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Observations.json +3 -3
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ObserveRequest.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ObserveResponse.json +1 -1
- sequence_base-0.5.0/sequence_base/schemas/PlanAppend.json +13 -0
- sequence_base-0.5.0/sequence_base/schemas/PlanAppended.json +28 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/PolicyRegistration.json +87 -256
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/PolicySpec.json +81 -253
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Project.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Proprioception.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/ReplaySpec.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Resources.json +1 -1
- sequence_base-0.5.0/sequence_base/schemas/RolloutResult.json +90 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/SecretCreateRequest.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/SecretInfo.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/SecretRef.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/SeqFlags.json +4 -2
- sequence_base-0.5.0/sequence_base/schemas/SettingsChange.json +56 -0
- sequence_base-0.5.0/sequence_base/schemas/SettingsChanged.json +137 -0
- sequence_base-0.5.0/sequence_base/schemas/SettingsView.json +402 -0
- sequence_base-0.5.0/sequence_base/schemas/Standby.json +92 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Stream.json +3 -3
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/TaskAgg.json +1 -1
- sequence_base-0.5.0/sequence_base/schemas/TeamGroup.json +120 -0
- sequence_base-0.5.0/sequence_base/schemas/TeamGroups.json +135 -0
- sequence_base-0.5.0/sequence_base/schemas/TeamGroupsRequest.json +21 -0
- sequence_base-0.5.0/sequence_base/schemas/TeamMember.json +39 -0
- sequence_base-0.5.0/sequence_base/schemas/TeamPlans.json +51 -0
- sequence_base-0.5.0/sequence_base/schemas/TeamPlansWritten.json +30 -0
- sequence_base-0.5.0/sequence_base/schemas/TeamSpec.json +22 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/TemplateFiles.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Tensors.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/Timeouts.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/UploadTarget.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/VolumeFile.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/VolumeInfo.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/VolumeMount.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/VolumeRef.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/VolumeUploadRequest.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/VolumeUploadResponse.json +1 -1
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/schemas/WarmingError.json +1 -1
- sequence_base-0.4.33/sequence_base/constants/cards.py +0 -16
- sequence_base-0.4.33/sequence_base/contract/benchmarks.py +0 -288
- sequence_base-0.4.33/sequence_base/contract/connect.py +0 -74
- sequence_base-0.4.33/sequence_base/schemas/Actions.json +0 -63
- sequence_base-0.4.33/sequence_base/schemas/BenchmarkConditionSpec.json +0 -54
- sequence_base-0.4.33/sequence_base/schemas/Concurrency.json +0 -100
- sequence_base-0.4.33/sequence_base/schemas/Conditions.json +0 -59
- sequence_base-0.4.33/sequence_base/schemas/ConnectRequest.json +0 -16
- sequence_base-0.4.33/sequence_base/schemas/RenderSpec.json +0 -40
- sequence_base-0.4.33/sequence_base/schemas/RolloutResult.json +0 -59
- sequence_base-0.4.33/sequence_base/schemas/Step.json +0 -86
- sequence_base-0.4.33/sequence_base/schemas/Variant.json +0 -24
- {sequence_base-0.4.33 → sequence_base-0.5.0}/.gitignore +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/README.md +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/auth.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/by_name.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/codec/__init__.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/codec/image.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/codec/marked.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/constants/__init__.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/constants/headers.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/constants/limits.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/construct.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/accounts.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/act.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/adapters.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/errors.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/io.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/obs_schedule.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/observe.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/retired.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/templates.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/contract/volumes.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/episode.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/errors/__init__.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/errors/transport.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/msgpack_io.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/obs/__init__.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/obs/log.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/obs/rid.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/presets/__init__.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/presets/frames.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/telemetry/__init__.py +0 -0
- {sequence_base-0.4.33 → sequence_base-0.5.0}/sequence_base/telemetry/events.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sequence-base
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Shared foundation for the Sequences platform — wire contract, correlation, error taxonomy, constants. Used by the robot SDK, gateway, and container harness.
|
|
5
5
|
Project-URL: Changelog, https://generalsequences.com/docs/changelog/
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sequence-base"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "Shared foundation for the Sequences platform — wire contract, correlation, error taxonomy, constants. Used by the robot SDK, gateway, and container harness."
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = ["pydantic>=2.0"]
|
|
@@ -37,6 +37,11 @@ from sequence_base.contract import (
|
|
|
37
37
|
parse_vol,
|
|
38
38
|
TEMPLATE_SCHEME,
|
|
39
39
|
parse_template,
|
|
40
|
+
SETTINGS,
|
|
41
|
+
Setting,
|
|
42
|
+
SettingsChange,
|
|
43
|
+
SettingsView,
|
|
44
|
+
SettingsChanged,
|
|
40
45
|
AdapterPair,
|
|
41
46
|
parse_pairs,
|
|
42
47
|
ActionChunk,
|
|
@@ -44,14 +49,12 @@ from sequence_base.contract import (
|
|
|
44
49
|
ActionSpace,
|
|
45
50
|
ActionStep,
|
|
46
51
|
Autoscaler,
|
|
47
|
-
BenchmarkConditionSpec,
|
|
48
52
|
BenchmarkRegisterRequest,
|
|
49
53
|
BenchmarkStatusResponse,
|
|
50
54
|
BenchmarkSpec,
|
|
51
55
|
BootstrapResponse,
|
|
52
56
|
CodeBundle,
|
|
53
57
|
Concurrency,
|
|
54
|
-
Conditions,
|
|
55
58
|
ConnectRequest,
|
|
56
59
|
ConnectResponse,
|
|
57
60
|
DeploymentAccepted,
|
|
@@ -85,10 +88,8 @@ from sequence_base.contract import (
|
|
|
85
88
|
PolicySpec,
|
|
86
89
|
Observations,
|
|
87
90
|
Stream,
|
|
88
|
-
Actions,
|
|
89
91
|
Tensors,
|
|
90
92
|
Proprioception,
|
|
91
|
-
RenderSpec,
|
|
92
93
|
ReplaySpec,
|
|
93
94
|
Resources,
|
|
94
95
|
RolloutResult,
|
|
@@ -96,10 +97,8 @@ from sequence_base.contract import (
|
|
|
96
97
|
SecretInfo,
|
|
97
98
|
SecretRef,
|
|
98
99
|
SeqFlags,
|
|
99
|
-
Step,
|
|
100
100
|
TaskAgg,
|
|
101
101
|
Timeouts,
|
|
102
|
-
Variant,
|
|
103
102
|
VolumeMount,
|
|
104
103
|
VolumeRef,
|
|
105
104
|
WarmingError,
|
|
@@ -146,7 +145,7 @@ __all__ = [
|
|
|
146
145
|
"FROZEN_PATH", "TemplateFiles", "ImageStepTemplateFiles", "Project", "ImageStepProject", "ImageStep", "ImageSpec",
|
|
147
146
|
"VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract",
|
|
148
147
|
"PolicySpec", "PolicyRegistration", "PolicyConstructor",
|
|
149
|
-
"Observations", "Stream", "
|
|
148
|
+
"Observations", "Stream", "Tensors",
|
|
150
149
|
|
|
151
150
|
"MAX_CODE_BUNDLE_BYTES", "CodeBundle",
|
|
152
151
|
"Resources", "Autoscaler", "Timeouts", "DeploymentPolicy", "InferParam", "DeploymentRequest",
|
|
@@ -154,7 +153,7 @@ __all__ = [
|
|
|
154
153
|
|
|
155
154
|
"Lease", "ConnectRequest", "ConnectResponse",
|
|
156
155
|
|
|
157
|
-
"
|
|
156
|
+
"ReplaySpec", "BenchmarkSpec", "BenchmarkRegisterRequest", "BenchmarkStatusResponse",
|
|
158
157
|
"EvalRequest", "Estimate", "EvalResponse", "EvalDryRunResponse", "RolloutResult",
|
|
159
158
|
"EvalStatus", "TaskAgg", "MetricAgg", "EvalReport",
|
|
160
159
|
|
|
@@ -162,6 +161,8 @@ __all__ = [
|
|
|
162
161
|
|
|
163
162
|
"VolumeFile", "VolumeUploadRequest", "UploadTarget", "VolumeUploadResponse", "VolumeInfo", "parse_vol",
|
|
164
163
|
|
|
164
|
+
"SETTINGS", "Setting", "SettingsChange", "SettingsView", "SettingsChanged",
|
|
165
|
+
|
|
165
166
|
"TEMPLATE_SCHEME", "parse_template",
|
|
166
167
|
|
|
167
168
|
"AdapterPair", "parse_pairs",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""The cards a benchmark machine may run on, defined once here: the SDK refuses any other before a benchmark registers
|
|
2
|
+
(and `seq validate` offline, so the list is a constant, not a read), the gateway at registration and at an eval, and
|
|
3
|
+
the harness at the machine it starts - one list where each kept its own.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Both cards have RT cores, video encoders, EGL and Vulkan, so a benchmark only picks cheaper or faster; one that names a
|
|
7
|
+
card simulates on it (registration checks). CPU physics is the author's explicit choice, gpu="cpu": CPU machines, one
|
|
8
|
+
environment per core
|
|
9
|
+
.
|
|
10
|
+
|
|
11
|
+
A deployment's or a benchmark's driver is named here too, beside its card: DRIVER.
|
|
12
|
+
"""
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
BENCHMARK_GPUS = ("L4", "RTX-PRO-6000")
|
|
16
|
+
|
|
17
|
+
DEFAULT_BENCHMARK_GPU = "L4"
|
|
18
|
+
|
|
19
|
+
BENCHMARK_CPU = "cpu"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
DRIVER = r"^[1-9][0-9]{2}$"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def driver_major(version: str | None) -> str | None:
|
|
30
|
+
"""The major version of a driver as nvidia-smi says it ("580.178.04" -> "580"); None for anything that is not one."""
|
|
31
|
+
head = (version or "").strip().split(".", 1)[0]
|
|
32
|
+
return head if re.fullmatch(DRIVER, head) else None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def check_driver(driver: str | None, card: str | None) -> None:
|
|
36
|
+
"""A driver is a GPU's: one named beside gpu="cpu" is refused."""
|
|
37
|
+
if driver is not None and (card or "").strip().lower() == BENCHMARK_CPU:
|
|
38
|
+
raise ValueError('driver= names a GPU driver: a gpu="cpu" machine has none')
|
|
@@ -45,7 +45,7 @@ from sequence_base.contract.policy import (
|
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
from sequence_base.contract.own_io import
|
|
48
|
+
from sequence_base.contract.own_io import Observations, Stream, Tensors
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
from sequence_base.contract.deployments import (
|
|
@@ -63,19 +63,14 @@ from sequence_base.contract.deployments import (
|
|
|
63
63
|
)
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
from sequence_base.contract.connect import ConnectRequest, ConnectResponse, Lease
|
|
66
|
+
from sequence_base.contract.connect import ConnectRequest, ConnectResponse, Lease, Standby
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
from sequence_base.contract.benchmarks import (
|
|
70
|
-
BenchmarkConditionSpec,
|
|
71
70
|
BenchmarkRegisterRequest,
|
|
72
71
|
BenchmarkStatusResponse,
|
|
73
72
|
BenchmarkSpec,
|
|
74
|
-
Conditions,
|
|
75
|
-
RenderSpec,
|
|
76
73
|
ReplaySpec,
|
|
77
|
-
Step,
|
|
78
|
-
Variant,
|
|
79
74
|
)
|
|
80
75
|
from sequence_base.contract.eval import (
|
|
81
76
|
Estimate,
|
|
@@ -117,6 +112,35 @@ from sequence_base.contract.volumes import (
|
|
|
117
112
|
)
|
|
118
113
|
|
|
119
114
|
|
|
115
|
+
from sequence_base.contract.settings import (
|
|
116
|
+
SETTINGS,
|
|
117
|
+
Applied,
|
|
118
|
+
Setting,
|
|
119
|
+
SettingChanged,
|
|
120
|
+
SettingState,
|
|
121
|
+
SettingsChange,
|
|
122
|
+
SettingsChanged,
|
|
123
|
+
SettingsView,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
from sequence_base.contract.team import (
|
|
128
|
+
TEAM_DEFAULT_GROUP,
|
|
129
|
+
GroupObservation,
|
|
130
|
+
GroupObserve,
|
|
131
|
+
GroupObserved,
|
|
132
|
+
PlanAppend,
|
|
133
|
+
PlanAppended,
|
|
134
|
+
TeamGroup,
|
|
135
|
+
TeamGroups,
|
|
136
|
+
TeamGroupsRequest,
|
|
137
|
+
TeamMember,
|
|
138
|
+
TeamPlans,
|
|
139
|
+
TeamPlansWritten,
|
|
140
|
+
TeamSpec,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
120
144
|
from sequence_base.contract.errors import ERRORS, ErrorBody, ErrorCode, ErrorSpec, WarmingError, code_for_status
|
|
121
145
|
|
|
122
146
|
__all__ = [
|
|
@@ -130,15 +154,15 @@ __all__ = [
|
|
|
130
154
|
"TemplateFiles", "ImageStepTemplateFiles", "Project", "ImageStepProject", "FROZEN_PATH", "ImageStep", "ImageSpec",
|
|
131
155
|
"VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract",
|
|
132
156
|
"PolicySpec", "PolicyRegistration", "PolicyConstructor",
|
|
133
|
-
"Observations", "Stream", "
|
|
157
|
+
"Observations", "Stream", "Tensors",
|
|
134
158
|
|
|
135
159
|
"MAX_CODE_BUNDLE_BYTES", "CodeBundle",
|
|
136
160
|
"Resources", "Autoscaler", "Timeouts", "DeploymentPolicy", "InferParam", "DeploymentRequest",
|
|
137
161
|
"DeploymentAccepted", "DeploymentState", "DeploymentStatusResponse",
|
|
138
162
|
|
|
139
|
-
"Lease", "ConnectRequest", "ConnectResponse",
|
|
163
|
+
"Lease", "ConnectRequest", "ConnectResponse", "Standby",
|
|
140
164
|
|
|
141
|
-
"
|
|
165
|
+
"ReplaySpec", "BenchmarkSpec", "BenchmarkRegisterRequest", "BenchmarkStatusResponse",
|
|
142
166
|
"EvalRequest", "Estimate", "EvalResponse", "EvalDryRunResponse", "RolloutResult",
|
|
143
167
|
"EvalStatus", "TaskAgg", "MetricAgg", "EvalReport",
|
|
144
168
|
|
|
@@ -147,6 +171,12 @@ __all__ = [
|
|
|
147
171
|
"MAX_FILES", "MAX_UPLOAD_BYTES", "VolumeFile", "VolumeUploadRequest", "UploadTarget", "VolumeUploadResponse",
|
|
148
172
|
"VolumeInfo", "check_volume_name", "parse_vol",
|
|
149
173
|
|
|
174
|
+
"SETTINGS", "Setting", "SettingsChange", "Applied", "SettingState", "SettingsView", "SettingChanged",
|
|
175
|
+
"SettingsChanged",
|
|
176
|
+
|
|
177
|
+
"TEAM_DEFAULT_GROUP", "TeamSpec", "TeamGroupsRequest", "GroupObservation", "TeamMember", "TeamGroup", "TeamGroups",
|
|
178
|
+
"TeamPlans", "TeamPlansWritten", "PlanAppend", "PlanAppended", "GroupObserve", "GroupObserved",
|
|
179
|
+
|
|
150
180
|
"TEMPLATE_SCHEME", "parse_template",
|
|
151
181
|
|
|
152
182
|
"AdapterPair", "parse_pairs",
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contract 5 (registration half) - a benchmark is the env you already have, run as it is: a short class of yours marks
|
|
3
|
+
three methods - @seq.setup builds this eval's worlds after the machine's snapshot, @seq.reset starts an episode of a task
|
|
4
|
+
at a seed, @seq.step plays one action and says what came of it - and declares its tasks, its seeds and how long an episode
|
|
5
|
+
may run. The platform reads none of its observations or actions: they go to the policy, and come from it, as a robot's
|
|
6
|
+
do. The eval *run* wire types (RolloutResult, EvalReport, ...) live in contract/eval.py.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Literal
|
|
13
|
+
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
15
|
+
|
|
16
|
+
from sequence_base.constants.cards import DRIVER, check_driver
|
|
17
|
+
from sequence_base.constants.limits import MAX_ENVS, TASK_DESCRIPTION_MAX
|
|
18
|
+
from sequence_base.contract.accounts import SecretRef
|
|
19
|
+
from sequence_base.contract.deployments import CodeBundle, DeploymentState, InferParam
|
|
20
|
+
from sequence_base.contract.flags import BENCHMARK_BINDABLE, SeqFlags
|
|
21
|
+
from sequence_base.contract.policy import KIND_NAME, ImageSpec, VolumeRef
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"ReplaySpec",
|
|
25
|
+
"BenchmarkSpec",
|
|
26
|
+
"BenchmarkRegisterRequest",
|
|
27
|
+
"BenchmarkStatusResponse",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
TASK_NAME = r"^[A-Za-z0-9][A-Za-z0-9._/:-]{0,127}$"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _check_tasks(tasks: dict, seeds: list, max_seconds) -> None:
|
|
35
|
+
import re as _re
|
|
36
|
+
|
|
37
|
+
if not tasks:
|
|
38
|
+
raise ValueError("tasks names at least one task: {name: description}")
|
|
39
|
+
for name, text in tasks.items():
|
|
40
|
+
if not _re.match(TASK_NAME, name):
|
|
41
|
+
raise ValueError(f"task {name!r}: 1-128 letters, digits, '.', '_', '/', ':' or '-', starting with a letter "
|
|
42
|
+
"or digit")
|
|
43
|
+
if len(text or "") > TASK_DESCRIPTION_MAX:
|
|
44
|
+
raise ValueError(f"tasks[{name!r}] is {len(text)} characters: at most {TASK_DESCRIPTION_MAX}")
|
|
45
|
+
if not seeds:
|
|
46
|
+
raise ValueError("seeds names at least one seed")
|
|
47
|
+
if len(set(seeds)) != len(seeds):
|
|
48
|
+
raise ValueError("seeds names each seed once")
|
|
49
|
+
limits = max_seconds if isinstance(max_seconds, dict) else {"": max_seconds}
|
|
50
|
+
for task, limit in limits.items():
|
|
51
|
+
if task and task not in tasks:
|
|
52
|
+
raise ValueError(f"max_seconds names {task!r}, which is not one of its tasks")
|
|
53
|
+
if not limit > 0:
|
|
54
|
+
raise ValueError(f"max_seconds{'[' + repr(task) + ']' if task else ''} must be above 0 s, not {limit!r}")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ReplaySpec(BaseModel):
|
|
58
|
+
"""a.k.a. `seq.Replay` — declares that the platform records the eval's 3D replay: each step every node's world
|
|
59
|
+
transform, drawn in the owner's browser after the eval. `engine` picks the platform's
|
|
60
|
+
adapter that reads the simulation's state ("mujoco", "sapien", "isaac"); "own" means the benchmark hands the frames itself
|
|
61
|
+
(`seq.replay.scene` / `seq.replay.frame`); None takes the benchmark's own `engine`. `state` names the benchmark
|
|
62
|
+
method an adapter calls for the engine's state of an env (or of a batched benchmark's slots), `looks` the one that
|
|
63
|
+
says what the adapter cannot read - a colour or a visibility each episode sets. Whether an eval records it is the
|
|
64
|
+
eval's `replay` ("3d" by default, "none")."""
|
|
65
|
+
|
|
66
|
+
model_config = ConfigDict(extra="forbid")
|
|
67
|
+
|
|
68
|
+
engine: Literal["mujoco", "sapien", "isaac", "own"] | None = Field(
|
|
69
|
+
None, description="The adapter that reads the simulation: 'mujoco' (incl. MuJoCo Warp), 'sapien', 'isaac', or "
|
|
70
|
+
"'own' (the benchmark hands frames itself); None: the benchmark's engine")
|
|
71
|
+
state: str | None = Field(None, pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
|
|
72
|
+
description="The benchmark method an adapter calls for an env's (or slots') engine state")
|
|
73
|
+
looks: str | None = Field(None, pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
|
|
74
|
+
description="The benchmark method that says each episode's colours or visibility")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class BenchmarkSpec(BaseModel):
|
|
78
|
+
"""What `@seq.benchmark(...)` and its marked methods add up to, as an eval runs it. `bindings` names the methods:
|
|
79
|
+
RESET and STEP always, SETUP when it builds its worlds after the machine's snapshot - which a vectorized env, one
|
|
80
|
+
stepping `worlds` worlds a call (@seq.concurrent(sizes=[N]) on its step), always does. `max_seconds` is an episode's
|
|
81
|
+
time on the robot's clock, the same for every task or {task: seconds}; `assets` are versioned scene volumes mounted
|
|
82
|
+
at /assets; `secrets` by name."""
|
|
83
|
+
|
|
84
|
+
model_config = ConfigDict(extra="forbid")
|
|
85
|
+
|
|
86
|
+
name: str
|
|
87
|
+
image: ImageSpec
|
|
88
|
+
tasks: dict[str, str] = Field(..., description="Each task's name and what it asks of the robot, shown beside it")
|
|
89
|
+
seeds: list[int] = Field(..., description="The seeds an episode starts at; trial k of a task runs seeds[k % len]")
|
|
90
|
+
max_seconds: float | dict[str, float] = Field(..., description="An episode's time limit, or {task: seconds}")
|
|
91
|
+
handler_ref: str
|
|
92
|
+
bindings: dict[SeqFlags, str] = Field(..., description="SETUP / RESET / STEP -> method name")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
worlds: int | None = Field(default=None, ge=1, le=MAX_ENVS)
|
|
96
|
+
|
|
97
|
+
gpu: str | None = None
|
|
98
|
+
|
|
99
|
+
driver: str | None = Field(default=None, pattern=DRIVER)
|
|
100
|
+
assets: list[VolumeRef] = Field(default_factory=list)
|
|
101
|
+
|
|
102
|
+
replay: ReplaySpec | None = None
|
|
103
|
+
cpu: int | None = None
|
|
104
|
+
memory_gb: int | None = None
|
|
105
|
+
secrets: list[SecretRef] = Field(default_factory=list)
|
|
106
|
+
|
|
107
|
+
engine: str | None = Field(default=None, pattern=KIND_NAME)
|
|
108
|
+
|
|
109
|
+
@model_validator(mode="after")
|
|
110
|
+
def _tasks(self) -> "BenchmarkSpec":
|
|
111
|
+
_check_tasks(self.tasks, self.seeds, self.max_seconds)
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
@model_validator(mode="after")
|
|
115
|
+
def _bindings(self) -> "BenchmarkSpec":
|
|
116
|
+
bad = set(self.bindings) - set(BENCHMARK_BINDABLE)
|
|
117
|
+
if bad:
|
|
118
|
+
names = ", ".join(sorted(f.name or str(f.value) for f in bad))
|
|
119
|
+
raise ValueError(f"a benchmark marks @seq.setup, @seq.reset and @seq.step only; got {names}")
|
|
120
|
+
missing = [f.name for f in (SeqFlags.RESET, SeqFlags.STEP) if f not in self.bindings]
|
|
121
|
+
if missing:
|
|
122
|
+
raise ValueError(f"a benchmark marks @seq.reset and @seq.step; {', '.join(missing).lower()} is missing")
|
|
123
|
+
if self.worlds is not None and SeqFlags.SETUP not in self.bindings:
|
|
124
|
+
raise ValueError("a vectorized benchmark (@seq.concurrent on its step) builds its worlds in @seq.setup")
|
|
125
|
+
return self
|
|
126
|
+
|
|
127
|
+
@model_validator(mode="after")
|
|
128
|
+
def _driver_of_a_card(self) -> "BenchmarkSpec":
|
|
129
|
+
check_driver(self.driver, self.gpu)
|
|
130
|
+
return self
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class BenchmarkRegisterRequest(BaseModel):
|
|
134
|
+
"""POST /v1/benchmarks - what `seq benchmark register` sends: the declaration, the code, and the parameters its
|
|
135
|
+
@seq.setup takes beside worlds and policy (each settable by an eval's --param, with its type)."""
|
|
136
|
+
|
|
137
|
+
model_config = ConfigDict(extra="forbid")
|
|
138
|
+
|
|
139
|
+
name: str
|
|
140
|
+
image: ImageSpec
|
|
141
|
+
tasks: dict[str, str]
|
|
142
|
+
seeds: list[int]
|
|
143
|
+
max_seconds: float | dict[str, float]
|
|
144
|
+
handler_ref: str
|
|
145
|
+
worlds: int | None = Field(default=None, ge=1, le=MAX_ENVS)
|
|
146
|
+
assets: list[VolumeRef] = Field(default_factory=list)
|
|
147
|
+
replay: ReplaySpec | None = None
|
|
148
|
+
cpu: int | None = None
|
|
149
|
+
memory_gb: int | None = None
|
|
150
|
+
|
|
151
|
+
code: CodeBundle | None = None
|
|
152
|
+
|
|
153
|
+
freeze: bool | None = None
|
|
154
|
+
secrets: list[SecretRef] = Field(default_factory=list)
|
|
155
|
+
gpu: str | None = Field(default=None, max_length=32)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
driver: str | None = Field(default=None, pattern=DRIVER,
|
|
159
|
+
description='The NVIDIA driver its card must have, by major version: "580"')
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
params: dict[str, InferParam] | None = Field(default=None, max_length=32)
|
|
163
|
+
|
|
164
|
+
image_context: CodeBundle | None = None
|
|
165
|
+
engine: str | None = Field(default=None, pattern=KIND_NAME)
|
|
166
|
+
|
|
167
|
+
@model_validator(mode="after")
|
|
168
|
+
def _tasks(self) -> "BenchmarkRegisterRequest":
|
|
169
|
+
_check_tasks(self.tasks, self.seeds, self.max_seconds)
|
|
170
|
+
return self
|
|
171
|
+
|
|
172
|
+
@model_validator(mode="after")
|
|
173
|
+
def _param_names(self) -> "BenchmarkRegisterRequest":
|
|
174
|
+
for name in self.params or {}:
|
|
175
|
+
if not name.isidentifier() or name.startswith("_") or name in ("worlds", "policy"):
|
|
176
|
+
raise ValueError(f"setup parameter {name!r} is not a public Python identifier other than worlds and "
|
|
177
|
+
"policy")
|
|
178
|
+
return self
|
|
179
|
+
|
|
180
|
+
@model_validator(mode="after")
|
|
181
|
+
def _driver_of_a_card(self) -> "BenchmarkRegisterRequest":
|
|
182
|
+
check_driver(self.driver, self.gpu)
|
|
183
|
+
return self
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class BenchmarkStatusResponse(BaseModel):
|
|
187
|
+
"""GET /v1/benchmarks/{name} — the build state of a registered benchmark (same lifecycle as a deployment:
|
|
188
|
+
building → ready | failed), with the failure reason when failed."""
|
|
189
|
+
|
|
190
|
+
model_config = ConfigDict(extra="forbid")
|
|
191
|
+
|
|
192
|
+
name: str
|
|
193
|
+
status: DeploymentState
|
|
194
|
+
error: str | None = None
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contract 3 — connect / lease (client → gateway; control plane, first call + renewal).
|
|
3
|
+
|
|
4
|
+
Control plane / data plane split: `connect(model)` goes through the gateway once (admission → acquire →
|
|
5
|
+
ensure worker up) and hands back the *direct* coordinates the client then uses to hit the worker's
|
|
6
|
+
`/act` without the gateway in the hot path (contract 4). The cold-start fallback is a defined wire body,
|
|
7
|
+
not an HTTP header alone — a 503 returns `WarmingError` (contract/errors.py), so `503 + Retry-After`
|
|
8
|
+
and the warming ETA are typed and checkable.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import Any, Literal
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from sequence_base.contract.errors import WarmingError
|
|
19
|
+
from sequence_base.contract.own_io import Observations
|
|
20
|
+
from sequence_base.contract.retired import dropped
|
|
21
|
+
from sequence_base.contract.team import check_name
|
|
22
|
+
|
|
23
|
+
__all__ = ["Lease", "ConnectRequest", "ConnectResponse", "Standby", "WarmingError"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Lease(BaseModel):
|
|
27
|
+
"""A time-boxed grant of the direct coordinates. Renewed before `expires_at`; `epoch` is the
|
|
28
|
+
worker/secret generation — a client holding a stale epoch against a new worker gets 401 and must
|
|
29
|
+
re-connect."""
|
|
30
|
+
|
|
31
|
+
model_config = ConfigDict(extra="forbid")
|
|
32
|
+
|
|
33
|
+
ttl_s: int
|
|
34
|
+
expires_at: datetime
|
|
35
|
+
epoch: int = Field(..., description="Worker/secret generation counter; rolls on worker change")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ConnectRequest(BaseModel):
|
|
39
|
+
model_config = ConfigDict(extra="forbid")
|
|
40
|
+
|
|
41
|
+
model: str = Field(..., description="Deployment name to connect to")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
standby: bool = Field(default=False, description="this SDK keeps a standby connection and switches to it")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
switched: bool = Field(default=False, description="this robot just switched to the standby copy it was handed")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
team: str | None = Field(default=None, description="the team this robot joins, by name")
|
|
55
|
+
group: str | None = Field(default=None, description="its group in that team; None: the default group")
|
|
56
|
+
|
|
57
|
+
@model_validator(mode="before")
|
|
58
|
+
@classmethod
|
|
59
|
+
def _retired(cls, data: Any) -> Any:
|
|
60
|
+
return dropped(data, "embodiment")
|
|
61
|
+
|
|
62
|
+
@model_validator(mode="after")
|
|
63
|
+
def _a_group_is_a_teams(self) -> "ConnectRequest":
|
|
64
|
+
if self.team is not None:
|
|
65
|
+
check_name(self.team, "team")
|
|
66
|
+
if self.group is not None:
|
|
67
|
+
if self.team is None:
|
|
68
|
+
raise ValueError("a group is a team's: say the team too")
|
|
69
|
+
check_name(self.group, "group")
|
|
70
|
+
return self
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Standby(BaseModel):
|
|
74
|
+
"""The standby copy a connect hands a robot whose SDK keeps one (ConnectRequest.standby): another worker of the
|
|
75
|
+
deployment, on another machine, holding a place for it - no seat: its acts go there only once the copy it is on
|
|
76
|
+
cannot be reached, and its next connect says it switched. Its coordinates as the primary's are: where to send, how to
|
|
77
|
+
check its certificate (pinned by cert_fingerprint, or "public" for tls_name, masked as the primary's) and the bearer
|
|
78
|
+
and lease its acts carry."""
|
|
79
|
+
|
|
80
|
+
model_config = ConfigDict(extra="forbid")
|
|
81
|
+
|
|
82
|
+
worker_url: str = Field(..., description="The standby worker's direct URL")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
cert_fingerprint: str | None = Field(..., description="Its certificate's fingerprint the SDK pins; null where "
|
|
86
|
+
"tls is public")
|
|
87
|
+
direct_secret: str = Field(..., description="Bearer for its /act; valid within its lease")
|
|
88
|
+
tls: Literal["pinned", "public"] = Field(default="pinned", description="how its certificate is checked")
|
|
89
|
+
tls_name: str | None = Field(default=None, description="the name a public certificate is checked for, masked")
|
|
90
|
+
lease: Lease
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ConnectResponse(BaseModel):
|
|
94
|
+
"""200 — the full set of coordinates for a direct worker connection.
|
|
95
|
+
|
|
96
|
+
`direct_secret` is a plaintext platform-minted bearer for the worker's `/act`; it is on the
|
|
97
|
+
allow-list of fields permitted to carry a secret value in the down direction (contract 6 / goal 15)."""
|
|
98
|
+
|
|
99
|
+
model_config = ConfigDict(extra="forbid")
|
|
100
|
+
|
|
101
|
+
worker_url: str = Field(..., description="Worker static-IP direct URL, e.g. https://<ip>:8080")
|
|
102
|
+
cert_fingerprint: str = Field(..., description="Self-signed cert fingerprint the SDK pins")
|
|
103
|
+
direct_secret: str = Field(..., description="Bearer for the worker /act; valid within the lease")
|
|
104
|
+
lease: Lease
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
hz: float | None = Field(default=None, gt=0, le=1000)
|
|
108
|
+
action_chunk_len: int | None = Field(default=None, ge=1, le=100_000)
|
|
109
|
+
action_chunk_exec_len: int | None = Field(default=None, ge=1, le=100_000)
|
|
110
|
+
|
|
111
|
+
io: str | None = None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
observations: Observations | None = None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
standby: Standby | None = None
|
|
118
|
+
|
|
119
|
+
@model_validator(mode="before")
|
|
120
|
+
@classmethod
|
|
121
|
+
def _retired(cls, data: Any) -> Any:
|
|
122
|
+
|
|
123
|
+
return dropped(data, "embodiment", "feedback", "action", "observation", "actions")
|