sequence-base 0.4.25__tar.gz → 0.4.27__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.25 → sequence_base-0.4.27}/PKG-INFO +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/pyproject.toml +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/__init__.py +17 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/constants/limits.py +9 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/constants/version.py +3 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/__init__.py +10 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/connect.py +5 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/deployments.py +31 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/flags.py +4 -0
- sequence_base-0.4.27/sequence_base/contract/observe.py +65 -0
- sequence_base-0.4.27/sequence_base/contract/own_io.py +179 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/policy.py +137 -3
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/wire.py +5 -0
- sequence_base-0.4.27/sequence_base/episode.py +58 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/presets/robot_arm.py +30 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schema_export.py +13 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ActRequest.json +15 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ActResponse.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ActionChunk.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ActionContract.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ActionStep.json +1 -1
- sequence_base-0.4.27/sequence_base/schemas/Actions.json +51 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/AdapterPair.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/AddLocal.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Autoscaler.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/BenchmarkConditionSpec.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/BenchmarkRegisterRequest.json +92 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/BenchmarkSpec.json +98 -4
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/BenchmarkStatusResponse.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/BootstrapResponse.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Camera.json +51 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/CodeBundle.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Concurrency.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Conditions.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ConnectRequest.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ConnectResponse.json +259 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/DeploymentAccepted.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/DeploymentPolicy.json +299 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/DeploymentRequest.json +404 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/DeploymentStatusResponse.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Embodiment.json +51 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ErrorBody.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ErrorCodes.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Estimate.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/EvalDryRunResponse.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/EvalReport.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/EvalRequest.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/EvalResponse.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageFrame.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageSpec.json +92 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageStepAddLocal.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageStepApt.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageStepEnv.json +1 -1
- sequence_base-0.4.27/sequence_base/schemas/ImageStepProject.json +91 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageStepRun.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageStepTemplateFiles.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ImageStepUvPip.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/InferParam.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Lease.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/MetricAgg.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Observation.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ObservationContract.json +51 -1
- sequence_base-0.4.27/sequence_base/schemas/Observations.json +264 -0
- sequence_base-0.4.27/sequence_base/schemas/ObserveRequest.json +57 -0
- sequence_base-0.4.27/sequence_base/schemas/ObserveResponse.json +17 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/PolicyRegistration.json +397 -5
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/PolicySpec.json +390 -1
- sequence_base-0.4.27/sequence_base/schemas/Project.json +76 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Proprioception.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/RenderSpec.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/ReplaySpec.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Resources.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/RolloutResult.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/SecretCreateRequest.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/SecretInfo.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/SecretRef.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/SeqFlags.json +4 -2
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Step.json +1 -1
- sequence_base-0.4.27/sequence_base/schemas/Stream.json +193 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/TaskAgg.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/TemplateFiles.json +1 -1
- sequence_base-0.4.27/sequence_base/schemas/Tensors.json +14 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Timeouts.json +15 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/UploadTarget.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/Variant.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/VolumeFile.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/VolumeInfo.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/VolumeMount.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/VolumeRef.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/VolumeUploadRequest.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/VolumeUploadResponse.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/schemas/WarmingError.json +1 -1
- {sequence_base-0.4.25 → sequence_base-0.4.27}/.gitignore +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/README.md +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/auth.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/codec/__init__.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/codec/image.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/constants/__init__.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/constants/cards.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/constants/headers.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/construct.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/accounts.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/act.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/adapters.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/benchmarks.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/errors.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/eval.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/io.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/templates.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/contract/volumes.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/errors/__init__.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/errors/transport.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/msgpack_io.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/obs/__init__.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/obs/log.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/obs/rid.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/presets/__init__.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/presets/frames.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/sequence_base/telemetry/__init__.py +0 -0
- {sequence_base-0.4.25 → sequence_base-0.4.27}/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.4.
|
|
3
|
+
Version: 0.4.27
|
|
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.4.
|
|
3
|
+
version = "0.4.27"
|
|
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"]
|
|
@@ -21,9 +21,14 @@ from sequence_base.contract import (
|
|
|
21
21
|
FROZEN_PATH,
|
|
22
22
|
TemplateFiles,
|
|
23
23
|
ImageStepTemplateFiles,
|
|
24
|
+
Project,
|
|
25
|
+
ImageStepProject,
|
|
24
26
|
Camera,
|
|
25
27
|
Embodiment,
|
|
26
28
|
ObservationContract,
|
|
29
|
+
ObserveFrame,
|
|
30
|
+
ObserveRequest,
|
|
31
|
+
ObserveResponse,
|
|
27
32
|
MAX_CODE_BUNDLE_BYTES,
|
|
28
33
|
UploadTarget,
|
|
29
34
|
VolumeFile,
|
|
@@ -79,6 +84,10 @@ from sequence_base.contract import (
|
|
|
79
84
|
PolicyConstructor,
|
|
80
85
|
PolicyRegistration,
|
|
81
86
|
PolicySpec,
|
|
87
|
+
Observations,
|
|
88
|
+
Stream,
|
|
89
|
+
Actions,
|
|
90
|
+
Tensors,
|
|
82
91
|
Proprioception,
|
|
83
92
|
RenderSpec,
|
|
84
93
|
ReplaySpec,
|
|
@@ -118,6 +127,9 @@ from sequence_base.errors.transport import (
|
|
|
118
127
|
)
|
|
119
128
|
|
|
120
129
|
|
|
130
|
+
from sequence_base.episode import Episode
|
|
131
|
+
|
|
132
|
+
|
|
121
133
|
from sequence_base import auth
|
|
122
134
|
|
|
123
135
|
|
|
@@ -129,11 +141,13 @@ __all__ = [
|
|
|
129
141
|
|
|
130
142
|
"ImageFrame", "Proprioception", "Observation", "ActionSpace", "ActionStep", "ActionChunk",
|
|
131
143
|
"ActRequest", "ActResponse",
|
|
144
|
+
"ObserveFrame", "ObserveRequest", "ObserveResponse",
|
|
132
145
|
|
|
133
146
|
"SeqFlags", "ImageStepUvPip", "ImageStepApt", "ImageStepEnv", "ImageStepRun", "AddLocal", "ImageStepAddLocal",
|
|
134
|
-
"FROZEN_PATH", "TemplateFiles", "ImageStepTemplateFiles", "ImageStep", "ImageSpec",
|
|
147
|
+
"FROZEN_PATH", "TemplateFiles", "ImageStepTemplateFiles", "Project", "ImageStepProject", "ImageStep", "ImageSpec",
|
|
135
148
|
"VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract", "Embodiment",
|
|
136
149
|
"PolicySpec", "PolicyRegistration", "PolicyConstructor",
|
|
150
|
+
"Observations", "Stream", "Actions", "Tensors",
|
|
137
151
|
|
|
138
152
|
"MAX_CODE_BUNDLE_BYTES", "CodeBundle",
|
|
139
153
|
"Resources", "Autoscaler", "Timeouts", "DeploymentPolicy", "InferParam", "DeploymentRequest",
|
|
@@ -160,6 +174,8 @@ __all__ = [
|
|
|
160
174
|
|
|
161
175
|
"TransportUnavailable", "TransportWarming", "TransportRejected", "TransportOverloaded",
|
|
162
176
|
|
|
177
|
+
"Episode",
|
|
178
|
+
|
|
163
179
|
"auth",
|
|
164
180
|
]
|
|
165
181
|
|
|
@@ -15,6 +15,8 @@ from sequence_base.contract.act import (
|
|
|
15
15
|
|
|
16
16
|
from sequence_base.contract.wire import ActRequest, ActResponse
|
|
17
17
|
|
|
18
|
+
from sequence_base.contract.observe import ObserveFrame, ObserveRequest, ObserveResponse
|
|
19
|
+
|
|
18
20
|
|
|
19
21
|
from sequence_base.contract.flags import SeqFlags
|
|
20
22
|
from sequence_base.contract.policy import (
|
|
@@ -34,6 +36,8 @@ from sequence_base.contract.policy import (
|
|
|
34
36
|
FROZEN_PATH,
|
|
35
37
|
TemplateFiles,
|
|
36
38
|
ImageStepTemplateFiles,
|
|
39
|
+
ImageStepProject,
|
|
40
|
+
Project,
|
|
37
41
|
PolicyConstructor,
|
|
38
42
|
PolicyRegistration,
|
|
39
43
|
PolicySpec,
|
|
@@ -42,6 +46,9 @@ from sequence_base.contract.policy import (
|
|
|
42
46
|
)
|
|
43
47
|
|
|
44
48
|
|
|
49
|
+
from sequence_base.contract.own_io import Actions, Observations, Stream, Tensors
|
|
50
|
+
|
|
51
|
+
|
|
45
52
|
from sequence_base.contract.deployments import (
|
|
46
53
|
MAX_CODE_BUNDLE_BYTES,
|
|
47
54
|
Autoscaler,
|
|
@@ -117,12 +124,14 @@ __all__ = [
|
|
|
117
124
|
|
|
118
125
|
"ImageFrame", "Proprioception", "Observation", "ActionSpace", "ActionStep", "ActionChunk",
|
|
119
126
|
"ActRequest", "ActResponse",
|
|
127
|
+
"ObserveFrame", "ObserveRequest", "ObserveResponse",
|
|
120
128
|
|
|
121
129
|
"SeqFlags",
|
|
122
130
|
"ImageStepUvPip", "ImageStepApt", "ImageStepEnv", "ImageStepRun", "AddLocal", "ImageStepAddLocal",
|
|
123
|
-
"TemplateFiles", "ImageStepTemplateFiles", "FROZEN_PATH", "ImageStep", "ImageSpec",
|
|
131
|
+
"TemplateFiles", "ImageStepTemplateFiles", "Project", "ImageStepProject", "FROZEN_PATH", "ImageStep", "ImageSpec",
|
|
124
132
|
"VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract", "Embodiment",
|
|
125
133
|
"PolicySpec", "PolicyRegistration", "PolicyConstructor",
|
|
134
|
+
"Observations", "Stream", "Actions", "Tensors",
|
|
126
135
|
|
|
127
136
|
"MAX_CODE_BUNDLE_BYTES", "CodeBundle",
|
|
128
137
|
"Resources", "Autoscaler", "Timeouts", "DeploymentPolicy", "InferParam", "DeploymentRequest",
|
|
@@ -16,6 +16,7 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
|
16
16
|
|
|
17
17
|
from sequence_base.contract.errors import WarmingError
|
|
18
18
|
from sequence_base.contract.io import ActionContract, ObservationContract
|
|
19
|
+
from sequence_base.contract.own_io import Actions, Observations
|
|
19
20
|
|
|
20
21
|
__all__ = ["Lease", "ConnectRequest", "ConnectResponse", "WarmingError"]
|
|
21
22
|
|
|
@@ -57,3 +58,7 @@ class ConnectResponse(BaseModel):
|
|
|
57
58
|
embodiment: str | None = None
|
|
58
59
|
|
|
59
60
|
io: str | None = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
observations: Observations | None = None
|
|
64
|
+
actions: Actions | None = None
|
|
@@ -22,10 +22,12 @@ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_valida
|
|
|
22
22
|
|
|
23
23
|
from sequence_base.contract.accounts import SecretRef
|
|
24
24
|
from sequence_base.contract.io import Embodiment, ObservationContract
|
|
25
|
+
from sequence_base.contract.own_io import Actions, Observations, Tensors, check_own_io
|
|
25
26
|
from sequence_base.contract.policy import (
|
|
26
27
|
KIND_NAME,
|
|
27
28
|
ActionContract,
|
|
28
29
|
Concurrency,
|
|
30
|
+
Episodes,
|
|
29
31
|
ImageSpec,
|
|
30
32
|
VolumeMount,
|
|
31
33
|
)
|
|
@@ -105,6 +107,11 @@ class Timeouts(BaseModel):
|
|
|
105
107
|
startup: int = Field(..., ge=60, le=18000)
|
|
106
108
|
|
|
107
109
|
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
episode_idle: int | None = Field(default=None, ge=10, le=86400)
|
|
113
|
+
|
|
114
|
+
|
|
108
115
|
class InferParam(BaseModel):
|
|
109
116
|
"""One inference parameter the policy's `@seq.infer` declares — `def infer(self, obs, *, num_steps: int = 10)`
|
|
110
117
|
— with its type and default. An /act or an eval may set it; the worker passes only declared names, cast to
|
|
@@ -171,7 +178,12 @@ class DeploymentPolicy(BaseModel):
|
|
|
171
178
|
|
|
172
179
|
handler_ref: str
|
|
173
180
|
action: ActionContract | None = None
|
|
174
|
-
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
episodes: Episodes | None = None
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
streaming: bool = Field(default=False, exclude=True)
|
|
175
187
|
secrets: list[SecretRef] = Field(default_factory=list)
|
|
176
188
|
|
|
177
189
|
|
|
@@ -208,11 +220,29 @@ class DeploymentPolicy(BaseModel):
|
|
|
208
220
|
own_observations: Literal["latest", "since_last_act"] | None = None
|
|
209
221
|
own_actions: Literal["one", "steps"] | None = None
|
|
210
222
|
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
observations: Observations | None = None
|
|
226
|
+
actions: Actions | None = None
|
|
227
|
+
tensors: Tensors | None = None
|
|
228
|
+
|
|
229
|
+
@model_validator(mode="after")
|
|
230
|
+
def _episodes_of_streaming(self) -> "DeploymentPolicy":
|
|
231
|
+
|
|
232
|
+
if self.streaming and self.episodes not in (None, "own"):
|
|
233
|
+
raise ValueError(f"streaming is what a record from before contract 0.5.24 says; beside "
|
|
234
|
+
f"episodes={self.episodes!r}, leave it out")
|
|
235
|
+
if self.streaming:
|
|
236
|
+
self.episodes = "own"
|
|
237
|
+
self.streaming = self.episodes == "own"
|
|
238
|
+
return self
|
|
239
|
+
|
|
211
240
|
@model_validator(mode="after")
|
|
212
241
|
def _own_io(self) -> "DeploymentPolicy":
|
|
213
242
|
if (self.own_observations or self.own_actions) and (self.action or self.observation or self.embodiments):
|
|
214
243
|
raise ValueError("own_observations and own_actions are for a policy of its own inputs and outputs; this one "
|
|
215
244
|
"declares the robot-arm contract, where observation history and the action chunk say it")
|
|
245
|
+
check_own_io(self)
|
|
216
246
|
return self
|
|
217
247
|
|
|
218
248
|
@model_validator(mode="after")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The observation stream: a policy of its own inputs that reads every observation since its last act is sent each one as
|
|
3
|
+
the robot makes it, on a connection of its own (POST /observe), and an act carries only the newest.
|
|
4
|
+
|
|
5
|
+
In one sentence: the robot's SDK numbers each observation of an episode from 0 → posts them as they come, each post the
|
|
6
|
+
ones that came while the last was on its way (ObserveRequest) → the worker keeps them by episode and answers how far it
|
|
7
|
+
has every one (ObserveResponse.through) → an act carries the newest observation and its number (ActRequest.seq) → the
|
|
8
|
+
worker waits for the ones before it, STREAM_WAIT_S at most, and hands the policy {"observations": [...]}, oldest first,
|
|
9
|
+
the act's own last - what an eval's since_last_act sends in one act today.
|
|
10
|
+
|
|
11
|
+
WHY: an act was the only upload, so every frame between two acts waited for the next one - 24 frames, 1304 KB and a read
|
|
12
|
+
p50 of 425 ms from a robot at home. Sent as they are made, they
|
|
13
|
+
are on the worker before the act is.
|
|
14
|
+
|
|
15
|
+
What a policy declares of what it reads (its cameras, how many a second, when its upload falls behind) is plan 87's
|
|
16
|
+
first layer, which waits for the comparison of each part (the user's 69): the stream here is the transport alone, for
|
|
17
|
+
a policy that declares own_observations "since_last_act".
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
25
|
+
|
|
26
|
+
__all__ = ["FORMAT", "FRAMES_MISSING", "FRAMES_OVER_LIMIT", "ObserveFrame", "ObserveRequest", "ObserveResponse"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
FORMAT = "x-seq-observe/1"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
FRAMES_MISSING = "frames_missing"
|
|
36
|
+
FRAMES_OVER_LIMIT = "frames_over_limit"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ObserveFrame(BaseModel):
|
|
40
|
+
"""One observation of an episode: its number in it, from 0, and the inputs, as the policy's infer() takes one."""
|
|
41
|
+
|
|
42
|
+
model_config = ConfigDict(extra="forbid")
|
|
43
|
+
|
|
44
|
+
seq: int = Field(..., ge=0, description="The observation's number in its episode, from 0")
|
|
45
|
+
inputs: Any = Field(..., description="One observation, exactly as the robot's code built it")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ObserveRequest(BaseModel):
|
|
49
|
+
"""POST /observe: the observations of one episode that came since the last post, and the numbers the robot left out
|
|
50
|
+
on purpose, which the worker then does not wait for."""
|
|
51
|
+
|
|
52
|
+
model_config = ConfigDict(extra="forbid")
|
|
53
|
+
|
|
54
|
+
episode_id: str = Field(..., min_length=1, max_length=256)
|
|
55
|
+
frames: list[ObserveFrame] = Field(default_factory=list)
|
|
56
|
+
skipped: list[int] = Field(default_factory=list, description="Numbers left out on purpose, never to come")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ObserveResponse(BaseModel):
|
|
60
|
+
"""200 from POST /observe: the highest number up to which the worker holds every observation of the episode, or has
|
|
61
|
+
been told one is skipped (-1: none yet). A number sent again is answered the same, never kept twice."""
|
|
62
|
+
|
|
63
|
+
model_config = ConfigDict(extra="forbid")
|
|
64
|
+
|
|
65
|
+
through: int = Field(..., ge=-1)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""
|
|
2
|
+
What a policy of its own inputs and outputs declares (contract 0.5.24): which keys of an observation it reads and at
|
|
3
|
+
which steps, a camera's frames as it was trained to see them, which rows of its answer play and how fast, and whether
|
|
4
|
+
its inputs reach it as torch tensors. Each part is optional; a policy that declares none is sent and handed what it is
|
|
5
|
+
today.
|
|
6
|
+
|
|
7
|
+
In one sentence: `Observations` names the keys a policy reads, each a `Stream` - read at the act's step and the offsets
|
|
8
|
+
in `at` before it (a window the worker keeps), or handed every `every` steps since the last act (fed: the policy keeps
|
|
9
|
+
its own history) - counted in steps or seconds (`unit`) → the robot and the eval send, and a benchmark renders, only
|
|
10
|
+
those steps → infer is handed {"observations": [...], "steps": [...]}, oldest first, the act's own last; `Actions` says
|
|
11
|
+
which field of the answer holds the rows, how many a second they play (`hz`) and how many play before the next act
|
|
12
|
+
(`open_loop_horizon`), so a worker can time a copy's robots by them.
|
|
13
|
+
|
|
14
|
+
WHY by key and not by kind of input: every policy, benchmark and serving framework read for the user's 69 names its
|
|
15
|
+
inputs and gives each its own schedule - GR00T DROID reads its cameras at t and t-15 and its state at t alone - and what
|
|
16
|
+
breaks a policy is a frame fitted or encoded other than it was trained on, which a kind of input does not say and a
|
|
17
|
+
`Camera` does.
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import math
|
|
23
|
+
from typing import Any, Literal
|
|
24
|
+
|
|
25
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
26
|
+
|
|
27
|
+
from sequence_base.presets.robot_arm import Camera
|
|
28
|
+
|
|
29
|
+
__all__ = ["Actions", "MAX_STREAMS", "MAX_WINDOW", "Observations", "Stream", "Tensors", "check_own_io"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
MAX_STREAMS = 64
|
|
34
|
+
MAX_WINDOW = 256
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _counts(v: Any, what: str) -> None:
|
|
38
|
+
|
|
39
|
+
if isinstance(v, bool) or not isinstance(v, (int, float)) or not math.isfinite(v):
|
|
40
|
+
raise ValueError(f"{what} is a number of steps or seconds, got {v!r}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class Stream(BaseModel):
|
|
44
|
+
"""One key of the observation a policy reads. `at`: the offsets before the act's step it reads at each act, 0 the
|
|
45
|
+
act's own - a window the worker keeps, so the policy keeps none. `every`: handed every that many steps since its last
|
|
46
|
+
act, the act's own always among them - fed, the policy keeping its own history. Neither: the act's step alone.
|
|
47
|
+
`camera`: the key is a camera's frame, read at its width x height - fitted by `resize` and `filter` before it is sent
|
|
48
|
+
when both are declared, sent as `codec` says (unset: as the robot sent it), decoded in the replica to HWC uint8, or
|
|
49
|
+
CHW float in 0..1 for layout "chw_float", before the policy's code."""
|
|
50
|
+
|
|
51
|
+
model_config = ConfigDict(extra="forbid")
|
|
52
|
+
|
|
53
|
+
at: list[int | float] | None = Field(default=None, min_length=1, max_length=MAX_WINDOW,
|
|
54
|
+
description="offsets before the act's step, each 0 or below")
|
|
55
|
+
every: int | float | None = Field(default=None, gt=0, description="handed every this many steps since the last act")
|
|
56
|
+
camera: Camera | None = None
|
|
57
|
+
|
|
58
|
+
@field_validator("at", mode="before")
|
|
59
|
+
@classmethod
|
|
60
|
+
def _offsets_as_given(cls, v: Any) -> Any:
|
|
61
|
+
for x in v if isinstance(v, list) else ():
|
|
62
|
+
_counts(x, "an offset in at=")
|
|
63
|
+
return v
|
|
64
|
+
|
|
65
|
+
@field_validator("at")
|
|
66
|
+
@classmethod
|
|
67
|
+
def _window(cls, v: list[int | float] | None) -> list[int | float] | None:
|
|
68
|
+
if v is None:
|
|
69
|
+
return v
|
|
70
|
+
if any(x > 0 for x in v):
|
|
71
|
+
raise ValueError("at= holds offsets before the act's step: each 0 (the act's own) or below")
|
|
72
|
+
if len(set(v)) != len(v):
|
|
73
|
+
raise ValueError("at= names each offset once")
|
|
74
|
+
return sorted(v)
|
|
75
|
+
|
|
76
|
+
@field_validator("every", mode="before")
|
|
77
|
+
@classmethod
|
|
78
|
+
def _fed(cls, v: Any) -> Any:
|
|
79
|
+
if v is not None:
|
|
80
|
+
_counts(v, "every=")
|
|
81
|
+
return v
|
|
82
|
+
|
|
83
|
+
@model_validator(mode="after")
|
|
84
|
+
def _one_schedule(self) -> "Stream":
|
|
85
|
+
if self.at is not None and self.every is not None:
|
|
86
|
+
raise ValueError("a key is read at= offsets of each act (the worker keeps them) or every= so many steps "
|
|
87
|
+
"(the policy keeps them), not both")
|
|
88
|
+
return self
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class Observations(BaseModel):
|
|
92
|
+
"""What a policy of its own inputs reads of each observation, and when. `streams`: the keys it reads, each a Stream;
|
|
93
|
+
only these are sent. None: the whole observation, as the robot built it. `every`: the whole observation handed every
|
|
94
|
+
that many steps since the last act (fed, no keys named). `unit`: what `at` and `every` count - "steps", an episode's
|
|
95
|
+
control steps from 0 (one action played on a robot, one env step in an eval), or "seconds", taken to steps by the
|
|
96
|
+
robot's or the benchmark's control rate. `pad`: a window's step before the episode's first reads as its first
|
|
97
|
+
("repeat_first") or is left out ("drop"). `when_behind`: what the robot does when its upload falls behind - "wait",
|
|
98
|
+
losing none, or "drop_oldest". Declared, infer is handed {"observations": [...], "steps": [...]}: each observation
|
|
99
|
+
the keys read at its step, oldest first, the act's own last."""
|
|
100
|
+
|
|
101
|
+
model_config = ConfigDict(extra="forbid")
|
|
102
|
+
|
|
103
|
+
streams: dict[str, Stream] | None = Field(default=None, max_length=MAX_STREAMS)
|
|
104
|
+
every: int | float | None = Field(default=None, gt=0)
|
|
105
|
+
unit: Literal["steps", "seconds"] = "steps"
|
|
106
|
+
pad: Literal["repeat_first", "drop"] = "repeat_first"
|
|
107
|
+
when_behind: Literal["wait", "drop_oldest"] = "wait"
|
|
108
|
+
|
|
109
|
+
@field_validator("streams")
|
|
110
|
+
@classmethod
|
|
111
|
+
def _keys(cls, v: dict[str, Stream] | None) -> dict[str, Stream] | None:
|
|
112
|
+
for key in v or {}:
|
|
113
|
+
if not key or len(key) > 128 or key != key.strip():
|
|
114
|
+
raise ValueError(f"stream {key!r} is not a key of an observation: 1 to 128 characters, no blanks around")
|
|
115
|
+
return v
|
|
116
|
+
|
|
117
|
+
@field_validator("every", mode="before")
|
|
118
|
+
@classmethod
|
|
119
|
+
def _fed(cls, v: Any) -> Any:
|
|
120
|
+
if v is not None:
|
|
121
|
+
_counts(v, "every=")
|
|
122
|
+
return v
|
|
123
|
+
|
|
124
|
+
@model_validator(mode="after")
|
|
125
|
+
def _counted(self) -> "Observations":
|
|
126
|
+
if self.streams is not None and self.every is not None:
|
|
127
|
+
raise ValueError("Observations(every=...) hands the whole observation; with keys named, give each key its "
|
|
128
|
+
"own Stream(every=...)")
|
|
129
|
+
if self.unit == "steps":
|
|
130
|
+
named = [("every=", self.every)]
|
|
131
|
+
for key, stream in (self.streams or {}).items():
|
|
132
|
+
named += [(f"{key!r} every=", stream.every)] + [(f"{key!r} at=", x) for x in stream.at or []]
|
|
133
|
+
for what, x in named:
|
|
134
|
+
if x is not None and not isinstance(x, int):
|
|
135
|
+
raise ValueError(f"unit 'steps' counts whole steps and {what}{x!r} is not one; for a time, write "
|
|
136
|
+
"unit='seconds'")
|
|
137
|
+
return self
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class Actions(BaseModel):
|
|
141
|
+
"""Which rows of a policy's answer play. `key`: the answer's field that holds them (None: the answer itself) - a
|
|
142
|
+
list of rows or a 2-D array, played in order, `hz` rows a second, `open_loop_horizon` of them before the next act
|
|
143
|
+
(None: all). A shorter answer plays whole and the next act comes sooner; a longer one is cut there. With `hz` a worker
|
|
144
|
+
knows how long one answer plays (open_loop_horizon / hz) and a control period (1 / hz) and times a copy's robots by
|
|
145
|
+
them, as a robot-arm chunk's covers_seconds and control_frequency_hz do. Undeclared, an answer plays as the default
|
|
146
|
+
says: a dict or a 1-D list one action, a 2-D one row by row."""
|
|
147
|
+
|
|
148
|
+
model_config = ConfigDict(extra="forbid")
|
|
149
|
+
|
|
150
|
+
key: str | None = Field(default=None, min_length=1, max_length=128)
|
|
151
|
+
hz: float | None = Field(default=None, gt=0, le=1000)
|
|
152
|
+
open_loop_horizon: int | None = Field(default=None, ge=1, le=100_000)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class Tensors(BaseModel):
|
|
156
|
+
"""A policy's inputs reach its code as torch tensors on its device - a batch dimension first when `batch` - and the
|
|
157
|
+
tensors it answers with go back as arrays; float64 arrays arrive as float32. Converted in the replica, last before
|
|
158
|
+
the policy's code; how a camera's frame is laid out is its Stream's camera.layout."""
|
|
159
|
+
|
|
160
|
+
model_config = ConfigDict(extra="forbid")
|
|
161
|
+
|
|
162
|
+
batch: bool = True
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def check_own_io(spec: Any) -> None:
|
|
166
|
+
"""What PolicySpec and DeploymentPolicy both hold a policy's own-I/O declarations to: none beside the robot-arm
|
|
167
|
+
contract, which says what it reads and plays its own way, and the 0.5.24 ones (observations / actions / tensors)
|
|
168
|
+
not beside own_observations / own_actions, which they take over from."""
|
|
169
|
+
new = [name for name in ("observations", "actions", "tensors") if getattr(spec, name) is not None]
|
|
170
|
+
if not new:
|
|
171
|
+
return
|
|
172
|
+
if spec.action or spec.observation or spec.embodiments:
|
|
173
|
+
raise ValueError(f"{', '.join(new)} {'is' if len(new) == 1 else 'are'} for a policy of its own inputs and "
|
|
174
|
+
"outputs; this one declares the robot-arm contract, where observation history and the action "
|
|
175
|
+
"chunk say it")
|
|
176
|
+
old = [name for name in ("own_observations", "own_actions") if getattr(spec, name)]
|
|
177
|
+
if old:
|
|
178
|
+
raise ValueError(f"{', '.join(new)} and {', '.join(old)} say what a policy reads and plays two ways; declare "
|
|
179
|
+
"observations= and actions= alone")
|