sequence-base 0.3.28__tar.gz → 0.4.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.3.28 → sequence_base-0.4.0}/PKG-INFO +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/README.md +4 -5
- {sequence_base-0.3.28 → sequence_base-0.4.0}/pyproject.toml +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/__init__.py +24 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/codec/image.py +16 -1
- sequence_base-0.4.0/sequence_base/constants/version.py +30 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/__init__.py +21 -3
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/accounts.py +11 -17
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/benchmarks.py +32 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/connect.py +3 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/deployments.py +48 -19
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/errors.py +6 -7
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/eval.py +32 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/flags.py +16 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/policy.py +51 -6
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/templates.py +2 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/volumes.py +5 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/wire.py +2 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/errors/transport.py +2 -4
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/obs/rid.py +2 -3
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/presets/robot_arm.py +28 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schema_export.py +13 -3
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ActRequest.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ActResponse.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ActionChunk.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ActionContract.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ActionStep.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/AdapterTransform.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/AddLocal.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Autoscaler.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/BenchmarkConditionSpec.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/BenchmarkRegisterRequest.json +2 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/BenchmarkSpec.json +3 -3
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/BenchmarkStatusResponse.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/BootstrapResponse.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Camera.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ClampInfo.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/CodeBundle.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Concurrency.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Conditions.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ConnectRequest.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ConnectResponse.json +1 -20
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/DeploymentAccepted.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/DeploymentPolicy.json +2 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/DeploymentRequest.json +3 -3
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/DeploymentStatusResponse.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Embodiment.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ErrorBody.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ErrorCodes.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Estimate.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/EvalDryRunResponse.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/EvalReport.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/EvalRequest.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/EvalResponse.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ImageFrame.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ImageSpec.json +2 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ImageStepAddLocal.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ImageStepApt.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ImageStepEnv.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ImageStepRun.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ImageStepUvPip.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/InferParam.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Lease.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/LossyTransform.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/MetricAgg.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Observation.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/ObservationContract.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/PolicyRegistration.json +3 -3
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/PolicySpec.json +2 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Proprioception.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/RenderSpec.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Resources.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/RolloutResult.json +2 -2
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/SecretCreateRequest.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/SecretInfo.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/SecretRef.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/SeqFlags.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Step.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/SuiteAgg.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/TaskAgg.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Timeouts.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/UploadTarget.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/Variant.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/VolumeAttach.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/VolumeFile.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/VolumeInfo.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/VolumeMount.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/VolumeRef.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/VolumeUploadRequest.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/VolumeUploadResponse.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/schemas/WarmingError.json +1 -1
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/telemetry/events.py +7 -4
- sequence_base-0.3.28/sequence_base/constants/env.py +0 -7
- sequence_base-0.3.28/sequence_base/constants/version.py +0 -3
- sequence_base-0.3.28/sequence_base/schemas/UsageReport.json +0 -38
- {sequence_base-0.3.28 → sequence_base-0.4.0}/.gitignore +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/auth.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/codec/__init__.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/constants/__init__.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/constants/headers.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/act.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/contract/io.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/errors/__init__.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/obs/__init__.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/obs/log.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/presets/__init__.py +0 -0
- {sequence_base-0.3.28 → sequence_base-0.4.0}/sequence_base/telemetry/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sequence-base
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: pydantic>=2.0
|
|
@@ -14,13 +14,12 @@ from sequence_base import TransportWarming, TransportOverloaded # error taxonom
|
|
|
14
14
|
```
|
|
15
15
|
sequence_base/
|
|
16
16
|
contract/ act.py — Observation / ActionChunk / ImageFrame / Proprioception / ActionSpace / ActionStep
|
|
17
|
-
|
|
17
|
+
· sdk + gateway + container
|
|
18
18
|
obs/ rid.py (HEADER, new_rid, clean) · log.py (log, Timer) · sdk + gateway + container
|
|
19
19
|
errors/ transport.py (Warming / Rejected / Overloaded / Unavailable) · gateway + container
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
telemetry/ [P1] events.py — container→gateway event shapes
|
|
20
|
+
constants/ headers.py · version.py · all three
|
|
21
|
+
codec/ [P1] image.py (encode/decode) — sdk encodes, container decodes; MUST match
|
|
22
|
+
telemetry/ [P1] events.py — the cold-start Stage vocabulary a worker logs
|
|
24
23
|
```
|
|
25
24
|
|
|
26
25
|
## The one rule for what goes in here
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sequence-base"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.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"]
|
|
@@ -11,6 +11,8 @@ defined once so they cannot drift. Import from here; never redefine.
|
|
|
11
11
|
Only shared-by-≥2-and-drifts-if-duplicated things live here. Model-specific, provider-specific, and
|
|
12
12
|
catalogue values stay in container / gateway / spec.py.
|
|
13
13
|
"""
|
|
14
|
+
|
|
15
|
+
|
|
14
16
|
from sequence_base.contract import (
|
|
15
17
|
ActRequest,
|
|
16
18
|
ActResponse,
|
|
@@ -87,7 +89,6 @@ from sequence_base.contract import (
|
|
|
87
89
|
SuiteAgg,
|
|
88
90
|
TaskAgg,
|
|
89
91
|
Timeouts,
|
|
90
|
-
UsageReport,
|
|
91
92
|
Variant,
|
|
92
93
|
VolumeAttach,
|
|
93
94
|
VolumeMount,
|
|
@@ -96,11 +97,14 @@ from sequence_base.contract import (
|
|
|
96
97
|
code_for_status,
|
|
97
98
|
)
|
|
98
99
|
|
|
100
|
+
|
|
99
101
|
from sequence_base.constants.version import CONTRACT_VERSION
|
|
100
102
|
|
|
103
|
+
|
|
101
104
|
from sequence_base.obs.log import Timer, enabled, log
|
|
102
105
|
from sequence_base.obs.rid import HEADER, clean, new_rid
|
|
103
106
|
|
|
107
|
+
|
|
104
108
|
from sequence_base.errors.transport import (
|
|
105
109
|
TransportOverloaded,
|
|
106
110
|
TransportRejected,
|
|
@@ -108,35 +112,53 @@ from sequence_base.errors.transport import (
|
|
|
108
112
|
TransportWarming,
|
|
109
113
|
)
|
|
110
114
|
|
|
115
|
+
|
|
111
116
|
from sequence_base import auth
|
|
112
117
|
|
|
113
118
|
|
|
114
119
|
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
115
123
|
__all__ = [
|
|
124
|
+
|
|
116
125
|
"ImageFrame", "Proprioception", "Observation", "ActionSpace", "ActionStep", "ActionChunk",
|
|
117
126
|
"ActRequest", "ActResponse",
|
|
127
|
+
|
|
118
128
|
"SeqFlags", "ImageStepUvPip", "ImageStepApt", "ImageStepEnv", "ImageStepRun", "AddLocal", "ImageStepAddLocal",
|
|
119
129
|
"ImageStep", "ImageSpec",
|
|
120
130
|
"VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract", "Embodiment",
|
|
121
131
|
"PolicySpec", "PolicyRegistration",
|
|
132
|
+
|
|
122
133
|
"MAX_CODE_BUNDLE_BYTES", "CodeBundle",
|
|
123
134
|
"Resources", "Autoscaler", "Timeouts", "VolumeAttach", "DeploymentPolicy", "InferParam", "DeploymentRequest",
|
|
124
135
|
"DeploymentAccepted", "DeploymentState", "DeploymentStatusResponse",
|
|
136
|
+
|
|
125
137
|
"Lease", "ConnectRequest", "ConnectResponse",
|
|
138
|
+
|
|
126
139
|
"Variant", "Conditions", "RenderSpec", "Step", "BenchmarkSpec", "BenchmarkConditionSpec", "BenchmarkRegisterRequest", "BenchmarkStatusResponse",
|
|
127
140
|
"EvalRequest", "ClampInfo", "Estimate", "EvalResponse", "EvalDryRunResponse", "RolloutResult",
|
|
128
141
|
"EvalStatus", "SuiteAgg", "TaskAgg", "MetricAgg", "LossyTransform", "EvalReport",
|
|
129
142
|
"AdapterKind", "AdapterTransform",
|
|
130
|
-
|
|
143
|
+
|
|
144
|
+
"SecretRef", "SecretCreateRequest", "SecretInfo", "BootstrapResponse",
|
|
145
|
+
|
|
131
146
|
"VolumeFile", "VolumeUploadRequest", "UploadTarget", "VolumeUploadResponse", "VolumeInfo", "parse_vol",
|
|
147
|
+
|
|
132
148
|
"TEMPLATE_SCHEME", "parse_template",
|
|
149
|
+
|
|
133
150
|
"ErrorCode", "ErrorBody", "WarmingError", "ERRORS", "ErrorSpec", "code_for_status", "CONTRACT_VERSION",
|
|
151
|
+
|
|
134
152
|
"HEADER", "new_rid", "clean", "log", "Timer", "enabled",
|
|
153
|
+
|
|
135
154
|
"TransportUnavailable", "TransportWarming", "TransportRejected", "TransportOverloaded",
|
|
155
|
+
|
|
136
156
|
"auth",
|
|
137
157
|
]
|
|
138
158
|
|
|
139
159
|
try:
|
|
160
|
+
|
|
161
|
+
|
|
140
162
|
from importlib.metadata import PackageNotFoundError, version as _version
|
|
141
163
|
|
|
142
164
|
__version__ = _version("sequence-base")
|
|
@@ -16,8 +16,19 @@ import io
|
|
|
16
16
|
from typing import Any
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
19
25
|
DEFAULT_JPEG_QUALITY = 95
|
|
20
26
|
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
21
32
|
MAX_UPLOAD_EDGE = 640
|
|
22
33
|
|
|
23
34
|
|
|
@@ -48,6 +59,8 @@ def encode(frame: Any, *, quality: int = DEFAULT_JPEG_QUALITY) -> str:
|
|
|
48
59
|
img = img.convert("RGB")
|
|
49
60
|
if max(img.size) > MAX_UPLOAD_EDGE:
|
|
50
61
|
scale = MAX_UPLOAD_EDGE / max(img.size)
|
|
62
|
+
|
|
63
|
+
|
|
51
64
|
img = img.resize((max(1, round(img.width * scale)),
|
|
52
65
|
max(1, round(img.height * scale))), Image.LANCZOS)
|
|
53
66
|
|
|
@@ -72,6 +85,7 @@ def decode(data: str) -> "Any":
|
|
|
72
85
|
return np.asarray(Image.open(io.BytesIO(raw)).convert("RGB"), dtype=np.uint8)
|
|
73
86
|
|
|
74
87
|
|
|
88
|
+
|
|
75
89
|
_DEPTH_UNITS = {"m": 1000.0, "mm": 1.0}
|
|
76
90
|
|
|
77
91
|
|
|
@@ -79,7 +93,8 @@ def encode_depth(depth: Any, *, unit: str = "m") -> str:
|
|
|
79
93
|
"""A depth map -> the base64 16-bit PNG a depth frame (ImageFrame kind="depth") carries: millimetres as uint16, 0
|
|
80
94
|
where there is no reading (NaN, inf, <= 0), clipped at 65.535 m. `unit` is what the array holds: "m" (float metres,
|
|
81
95
|
the default) or "mm". Lossless, unlike the JPEG colour frames take — a depth error is a geometry error.
|
|
82
|
-
|
|
96
|
+
|
|
97
|
+
"""
|
|
83
98
|
import numpy as np
|
|
84
99
|
from PIL import Image
|
|
85
100
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
The shared wire contract — one definition per shape, imported (never redeclared) by the SDK, gateway,
|
|
3
|
-
and container harness. Grouped by
|
|
3
|
+
and container harness. Grouped by contract number.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from sequence_base.contract.act import (
|
|
6
7
|
ActionChunk,
|
|
7
8
|
ActionSpace,
|
|
@@ -11,8 +12,10 @@ from sequence_base.contract.act import (
|
|
|
11
12
|
Proprioception,
|
|
12
13
|
)
|
|
13
14
|
|
|
15
|
+
|
|
14
16
|
from sequence_base.contract.wire import ActRequest, ActResponse
|
|
15
17
|
|
|
18
|
+
|
|
16
19
|
from sequence_base.contract.flags import SeqFlags
|
|
17
20
|
from sequence_base.contract.policy import (
|
|
18
21
|
Camera,
|
|
@@ -34,6 +37,7 @@ from sequence_base.contract.policy import (
|
|
|
34
37
|
VolumeRef,
|
|
35
38
|
)
|
|
36
39
|
|
|
40
|
+
|
|
37
41
|
from sequence_base.contract.deployments import (
|
|
38
42
|
MAX_CODE_BUNDLE_BYTES,
|
|
39
43
|
Autoscaler,
|
|
@@ -49,8 +53,10 @@ from sequence_base.contract.deployments import (
|
|
|
49
53
|
VolumeAttach,
|
|
50
54
|
)
|
|
51
55
|
|
|
56
|
+
|
|
52
57
|
from sequence_base.contract.connect import ConnectRequest, ConnectResponse, Lease
|
|
53
58
|
|
|
59
|
+
|
|
54
60
|
from sequence_base.contract.benchmarks import (
|
|
55
61
|
BenchmarkConditionSpec,
|
|
56
62
|
BenchmarkRegisterRequest,
|
|
@@ -78,16 +84,18 @@ from sequence_base.contract.eval import (
|
|
|
78
84
|
TaskAgg,
|
|
79
85
|
)
|
|
80
86
|
|
|
87
|
+
|
|
81
88
|
from sequence_base.contract.accounts import (
|
|
82
89
|
BootstrapResponse,
|
|
83
90
|
SecretCreateRequest,
|
|
84
91
|
SecretInfo,
|
|
85
92
|
SecretRef,
|
|
86
|
-
UsageReport,
|
|
87
93
|
)
|
|
88
94
|
|
|
95
|
+
|
|
89
96
|
from sequence_base.contract.templates import TEMPLATE_SCHEME, parse_template
|
|
90
97
|
|
|
98
|
+
|
|
91
99
|
from sequence_base.contract.volumes import (
|
|
92
100
|
MAX_FILES,
|
|
93
101
|
MAX_UPLOAD_BYTES,
|
|
@@ -100,27 +108,37 @@ from sequence_base.contract.volumes import (
|
|
|
100
108
|
parse_vol,
|
|
101
109
|
)
|
|
102
110
|
|
|
111
|
+
|
|
103
112
|
from sequence_base.contract.errors import ERRORS, ErrorBody, ErrorCode, ErrorSpec, WarmingError, code_for_status
|
|
104
113
|
|
|
105
114
|
__all__ = [
|
|
115
|
+
|
|
106
116
|
"ImageFrame", "Proprioception", "Observation", "ActionSpace", "ActionStep", "ActionChunk",
|
|
107
117
|
"ActRequest", "ActResponse",
|
|
118
|
+
|
|
108
119
|
"SeqFlags",
|
|
109
120
|
"ImageStepUvPip", "ImageStepApt", "ImageStepEnv", "ImageStepRun", "AddLocal", "ImageStepAddLocal", "ImageStep",
|
|
110
121
|
"ImageSpec",
|
|
111
122
|
"VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract", "Embodiment",
|
|
112
123
|
"PolicySpec", "PolicyRegistration",
|
|
124
|
+
|
|
113
125
|
"MAX_CODE_BUNDLE_BYTES", "CodeBundle",
|
|
114
126
|
"Resources", "Autoscaler", "Timeouts", "VolumeAttach", "DeploymentPolicy", "InferParam", "DeploymentRequest",
|
|
115
127
|
"DeploymentAccepted", "DeploymentState", "DeploymentStatusResponse",
|
|
128
|
+
|
|
116
129
|
"Lease", "ConnectRequest", "ConnectResponse",
|
|
130
|
+
|
|
117
131
|
"Variant", "Conditions", "RenderSpec", "Step", "BenchmarkSpec", "BenchmarkConditionSpec", "BenchmarkRegisterRequest", "BenchmarkStatusResponse",
|
|
118
132
|
"EvalRequest", "ClampInfo", "Estimate", "EvalResponse", "EvalDryRunResponse", "RolloutResult",
|
|
119
133
|
"EvalStatus", "SuiteAgg", "TaskAgg", "MetricAgg", "LossyTransform", "EvalReport",
|
|
120
134
|
"AdapterKind", "AdapterTransform",
|
|
121
|
-
|
|
135
|
+
|
|
136
|
+
"SecretRef", "SecretCreateRequest", "SecretInfo", "BootstrapResponse",
|
|
137
|
+
|
|
122
138
|
"MAX_FILES", "MAX_UPLOAD_BYTES", "VolumeFile", "VolumeUploadRequest", "UploadTarget", "VolumeUploadResponse",
|
|
123
139
|
"VolumeInfo", "check_volume_name", "parse_vol",
|
|
140
|
+
|
|
124
141
|
"TEMPLATE_SCHEME", "parse_template",
|
|
142
|
+
|
|
125
143
|
"ErrorCode", "ErrorBody", "WarmingError", "ERRORS", "ErrorSpec", "code_for_status",
|
|
126
144
|
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Contract 6 — accounts / secret / billing wire types
|
|
2
|
+
Contract 6 — accounts / secret / billing wire types.
|
|
3
3
|
|
|
4
4
|
Secret-leak rule, mechanically checkable (goal 15). Two kinds of secret:
|
|
5
5
|
(a) platform-minted — `direct_secret`, TLS private key. May appear in the DOWN direction only:
|
|
@@ -7,8 +7,7 @@ Secret-leak rule, mechanically checkable (goal 15). Two kinds of secret:
|
|
|
7
7
|
(b) user Secret-Manager values. May appear in the WRITE direction only:
|
|
8
8
|
SecretCreateRequest.env, BootstrapResponse.env (injected into the worker subprocess).
|
|
9
9
|
These four fields are the entire allow-list for carrying a plaintext secret value. Everything returned
|
|
10
|
-
to a client
|
|
11
|
-
eval report, /act response) exposes only names / env_keys — never a value-bearing field.
|
|
10
|
+
to a client or written to a report/log (SecretRef, SecretInfo, eval report, /act response) exposes only names / env_keys — never a value-bearing field.
|
|
12
11
|
"""
|
|
13
12
|
from __future__ import annotations
|
|
14
13
|
|
|
@@ -23,7 +22,6 @@ __all__ = [
|
|
|
23
22
|
"SecretCreateRequest",
|
|
24
23
|
"SecretInfo",
|
|
25
24
|
"BootstrapResponse",
|
|
26
|
-
"UsageReport",
|
|
27
25
|
]
|
|
28
26
|
|
|
29
27
|
|
|
@@ -40,6 +38,8 @@ class SecretCreateRequest(BaseModel):
|
|
|
40
38
|
"""POST /v1/secrets — one name = one group of env values (e.g. planner = {PLANNER_API_KEY}).
|
|
41
39
|
`env` carries plaintext values; this is the WRITE-direction allow-list field (goal 15)."""
|
|
42
40
|
|
|
41
|
+
|
|
42
|
+
|
|
43
43
|
model_config = ConfigDict(extra="forbid", hide_input_in_errors=True)
|
|
44
44
|
|
|
45
45
|
name: str
|
|
@@ -49,6 +49,10 @@ class SecretCreateRequest(BaseModel):
|
|
|
49
49
|
class SecretInfo(BaseModel):
|
|
50
50
|
"""GET /v1/secrets element — metadata only, NO values. Exposes `env_keys`, not `env`."""
|
|
51
51
|
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
52
56
|
model_config = ConfigDict(extra="forbid", hide_input_in_errors=True)
|
|
53
57
|
|
|
54
58
|
name: str
|
|
@@ -61,24 +65,14 @@ class BootstrapResponse(BaseModel):
|
|
|
61
65
|
"""What a worker receives when it starts — everything it needs to serve direct TLS `/act`. `direct_secret` + `tls_key` are DOWN-direction platform secrets; `env` is the
|
|
62
66
|
WRITE-direction injection of the policy's declared user secrets into its subprocess (goal 15)."""
|
|
63
67
|
|
|
68
|
+
|
|
69
|
+
|
|
64
70
|
model_config = ConfigDict(extra="forbid", hide_input_in_errors=True)
|
|
65
71
|
|
|
66
72
|
direct_secret: str = Field(..., description="Platform-minted bearer the worker's guard checks")
|
|
67
73
|
tls_key: str = Field(..., description="Self-signed TLS private key (down-direction platform secret)")
|
|
68
74
|
tls_cert: str = Field(..., description="Self-signed TLS certificate (public)")
|
|
69
75
|
env: dict[str, str] = Field(..., description="Policy's user secrets, expanded ENV_KEY → value")
|
|
76
|
+
|
|
70
77
|
weights_uri: str | None = None
|
|
71
78
|
lease: Lease
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class UsageReport(BaseModel):
|
|
75
|
-
"""A worker's metering report, sent as it serves. Carries counts only, no secrets.
|
|
76
|
-
This usage shape is defined here (sequence-base) once, so gateway and worker cannot drift."""
|
|
77
|
-
|
|
78
|
-
model_config = ConfigDict(extra="forbid")
|
|
79
|
-
|
|
80
|
-
deployment_id: str
|
|
81
|
-
window_start: datetime
|
|
82
|
-
window_end: datetime
|
|
83
|
-
requests: int
|
|
84
|
-
controlled_seconds: float
|
|
@@ -60,6 +60,10 @@ class RenderSpec(BaseModel):
|
|
|
60
60
|
|
|
61
61
|
camera: str = Field(..., description="Which camera to pull frames from, e.g. 'wrist' / 'agentview'")
|
|
62
62
|
fps: int = 30
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
63
67
|
flip: Literal["vertical", "horizontal", "both"] | None = Field(
|
|
64
68
|
None, description="'vertical': rows reversed (upside down); 'horizontal': mirrored; 'both': turned 180°; "
|
|
65
69
|
"None: as drawn")
|
|
@@ -99,16 +103,20 @@ class BenchmarkSpec(BaseModel):
|
|
|
99
103
|
handler_ref: str
|
|
100
104
|
bindings: dict[SeqFlags, str] = Field(..., description="SETUP / RESET / CHECK / SCORE (+ OBSERVE / STEP) → method name")
|
|
101
105
|
gpu: str | list[str] | None = None
|
|
106
|
+
|
|
102
107
|
envs: int | None = Field(default=None, ge=1, le=65536)
|
|
103
108
|
assets: list[VolumeRef] = Field(default_factory=list)
|
|
104
109
|
render: RenderSpec | None = None
|
|
105
110
|
cpu: int | None = None
|
|
106
111
|
memory_gb: int | None = None
|
|
107
112
|
secrets: list[SecretRef] = Field(default_factory=list)
|
|
113
|
+
|
|
108
114
|
engine: str | None = Field(default=None, pattern=KIND_NAME)
|
|
109
115
|
|
|
110
116
|
@model_validator(mode="after")
|
|
111
117
|
def _bindings_only_benchmark_hooks(self) -> "BenchmarkSpec":
|
|
118
|
+
|
|
119
|
+
|
|
112
120
|
bad = set(self.bindings) - set(BENCHMARK_BINDABLE)
|
|
113
121
|
if bad:
|
|
114
122
|
names = ", ".join(sorted(f.name or str(f.value) for f in bad))
|
|
@@ -152,19 +160,43 @@ class BenchmarkRegisterRequest(BaseModel):
|
|
|
152
160
|
render: RenderSpec | None = None
|
|
153
161
|
cpu: int | None = None
|
|
154
162
|
memory_gb: int | None = None
|
|
163
|
+
|
|
164
|
+
|
|
155
165
|
code: CodeBundle | None = None
|
|
166
|
+
|
|
167
|
+
|
|
156
168
|
suite_of: dict[str, str] = Field(default_factory=dict)
|
|
169
|
+
|
|
170
|
+
|
|
157
171
|
action_contract: ActionContract | None = None
|
|
172
|
+
|
|
173
|
+
|
|
158
174
|
secrets: list[SecretRef] = Field(default_factory=list)
|
|
175
|
+
|
|
176
|
+
|
|
159
177
|
score: bool = False
|
|
178
|
+
|
|
179
|
+
|
|
160
180
|
condition_list: list[BenchmarkConditionSpec] | None = Field(default=None, max_length=5000)
|
|
181
|
+
|
|
161
182
|
timeout_s: float | None = Field(default=None, gt=0)
|
|
183
|
+
|
|
162
184
|
default_adapter_ref: str | None = None
|
|
185
|
+
|
|
186
|
+
|
|
163
187
|
gpu: str | None = Field(default=None, max_length=32)
|
|
188
|
+
|
|
164
189
|
envs: int | None = Field(default=None, ge=1, le=65536)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
165
193
|
params: dict[str, InferParam] | None = Field(default=None, max_length=32)
|
|
194
|
+
|
|
166
195
|
batched: bool = False
|
|
196
|
+
|
|
167
197
|
image_context: CodeBundle | None = None
|
|
198
|
+
|
|
199
|
+
|
|
168
200
|
engine: str | None = Field(default=None, pattern=KIND_NAME)
|
|
169
201
|
|
|
170
202
|
@model_validator(mode="after")
|
|
@@ -13,6 +13,7 @@ from datetime import datetime
|
|
|
13
13
|
|
|
14
14
|
from pydantic import BaseModel, ConfigDict, Field
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
from sequence_base.contract.errors import WarmingError
|
|
17
18
|
from sequence_base.contract.io import ActionContract, ObservationContract
|
|
18
19
|
|
|
@@ -50,9 +51,9 @@ class ConnectResponse(BaseModel):
|
|
|
50
51
|
cert_fingerprint: str = Field(..., description="Self-signed cert fingerprint the SDK pins")
|
|
51
52
|
direct_secret: str = Field(..., description="Bearer for the worker /act; valid within the lease")
|
|
52
53
|
lease: Lease
|
|
53
|
-
|
|
54
|
-
warming_eta_s: int | None = Field(default=None, description="Seconds until warm, when warming")
|
|
54
|
+
|
|
55
55
|
action: ActionContract | None = None
|
|
56
56
|
observation: ObservationContract | None = None
|
|
57
57
|
embodiment: str | None = None
|
|
58
|
+
|
|
58
59
|
io: str | None = None
|
|
@@ -21,8 +21,6 @@ from typing import Literal
|
|
|
21
21
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
22
22
|
|
|
23
23
|
from sequence_base.contract.accounts import SecretRef
|
|
24
|
-
from sequence_base.contract.templates import TEMPLATE_SCHEME, parse_template
|
|
25
|
-
from sequence_base.contract.volumes import VOL_SCHEME, parse_vol
|
|
26
24
|
from sequence_base.contract.io import Embodiment, ObservationContract
|
|
27
25
|
from sequence_base.contract.policy import (
|
|
28
26
|
KIND_NAME,
|
|
@@ -53,10 +51,15 @@ class Resources(BaseModel):
|
|
|
53
51
|
model_config = ConfigDict(extra="forbid")
|
|
54
52
|
|
|
55
53
|
gpu: list[str]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
56
57
|
cpu: float | None = Field(default=None, ge=0.125, le=64)
|
|
57
58
|
cpu_limit: float | None = Field(default=None, ge=0.125, le=128)
|
|
58
59
|
memory_gb: float | None = Field(default=None, ge=0.125, le=1024)
|
|
59
60
|
memory_limit_gb: float | None = Field(default=None, ge=0.125, le=1024)
|
|
61
|
+
|
|
62
|
+
|
|
60
63
|
region: str | None = Field(default=None, max_length=32)
|
|
61
64
|
|
|
62
65
|
@model_validator(mode="after")
|
|
@@ -73,10 +76,16 @@ class Autoscaler(BaseModel):
|
|
|
73
76
|
model_config = ConfigDict(extra="forbid")
|
|
74
77
|
|
|
75
78
|
min_containers: int = 0
|
|
79
|
+
|
|
80
|
+
|
|
76
81
|
max_containers: int | None = None
|
|
82
|
+
|
|
83
|
+
|
|
77
84
|
max_gpus: int | None = Field(default=None, ge=1, le=256)
|
|
78
85
|
buffer_containers: int | None = None
|
|
79
86
|
scaledown_window: int = 600
|
|
87
|
+
|
|
88
|
+
|
|
80
89
|
on_full: Literal["queue", "reject"] = "queue"
|
|
81
90
|
queue_timeout_s: int = Field(default=120, ge=5, le=3600)
|
|
82
91
|
|
|
@@ -160,9 +169,9 @@ class DeploymentPolicy(BaseModel):
|
|
|
160
169
|
to nothing and its inputs / outputs pass through the worker untouched.
|
|
161
170
|
|
|
162
171
|
`secrets` carries the policy's declared secret BUNDLES BY NAME ONLY (list[SecretRef]) — the gateway
|
|
163
|
-
validates each name exists and belongs to the deployer at submit time
|
|
172
|
+
validates each name exists and belongs to the deployer at submit time, and the
|
|
164
173
|
worker bootstrap fetches the matching env group by name. A secret VALUE never travels here: SecretRef is
|
|
165
|
-
name-only, so this field cannot carry one
|
|
174
|
+
name-only, so this field cannot carry one. Defaults to `[]` so a policy with no secrets is
|
|
166
175
|
unaffected."""
|
|
167
176
|
|
|
168
177
|
model_config = ConfigDict(extra="forbid")
|
|
@@ -172,12 +181,28 @@ class DeploymentPolicy(BaseModel):
|
|
|
172
181
|
streaming: bool = False
|
|
173
182
|
frames_per_chunk: int | None = None
|
|
174
183
|
secrets: list[SecretRef] = Field(default_factory=list)
|
|
184
|
+
|
|
185
|
+
|
|
175
186
|
observation: ObservationContract | None = None
|
|
176
187
|
embodiments: dict[str, Embodiment] | None = None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
177
192
|
action_declared: bool | None = None
|
|
193
|
+
|
|
194
|
+
|
|
178
195
|
io: str | None = Field(default=None, max_length=4000)
|
|
196
|
+
|
|
197
|
+
|
|
179
198
|
family: str | None = Field(default=None, pattern=KIND_NAME)
|
|
199
|
+
|
|
200
|
+
|
|
180
201
|
params: dict[str, InferParam] | None = Field(default=None, max_length=32)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
181
206
|
models: list[str] | None = Field(default=None, max_length=16)
|
|
182
207
|
|
|
183
208
|
@model_validator(mode="after")
|
|
@@ -185,6 +210,7 @@ class DeploymentPolicy(BaseModel):
|
|
|
185
210
|
for name in self.params or {}:
|
|
186
211
|
if not name.isidentifier() or name.startswith("_"):
|
|
187
212
|
raise ValueError(f"inference parameter {name!r} is not a public Python identifier")
|
|
213
|
+
|
|
188
214
|
for model in self.models or []:
|
|
189
215
|
if not model or model != model.strip() or "/" not in model:
|
|
190
216
|
raise ValueError(f"policy model {model!r} is not a catalogue id (accounts/sequences/models/<name>)")
|
|
@@ -240,15 +266,26 @@ class DeploymentRequest(BaseModel):
|
|
|
240
266
|
|
|
241
267
|
name: str
|
|
242
268
|
image: ImageSpec
|
|
269
|
+
|
|
243
270
|
weights: VolumeMount | None = None
|
|
244
271
|
resources: Resources
|
|
245
272
|
policy: DeploymentPolicy
|
|
273
|
+
|
|
274
|
+
|
|
246
275
|
code: CodeBundle | None = None
|
|
276
|
+
|
|
277
|
+
|
|
247
278
|
image_context: CodeBundle | None = None
|
|
279
|
+
|
|
280
|
+
|
|
248
281
|
volumes: list[VolumeAttach] = Field(default_factory=list)
|
|
249
282
|
autoscaler: Autoscaler = Field(default_factory=Autoscaler)
|
|
283
|
+
|
|
250
284
|
concurrency: Concurrency = Field(default_factory=Concurrency)
|
|
251
285
|
timeouts: Timeouts | None = None
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
252
289
|
weights_name: str | None = None
|
|
253
290
|
extra_weights: dict[str, VolumeMount] | None = None
|
|
254
291
|
|
|
@@ -265,9 +302,10 @@ class DeploymentRequest(BaseModel):
|
|
|
265
302
|
|
|
266
303
|
@model_validator(mode="after")
|
|
267
304
|
def _weights_have_an_origin(self) -> "DeploymentRequest":
|
|
268
|
-
"""The checkpoint the build provisions: an official template://, an hf:// repo or an
|
|
269
|
-
|
|
270
|
-
|
|
305
|
+
"""The checkpoint the build provisions, when there is one: an official template://, an hf:// repo or an
|
|
306
|
+
uploaded vol:// volume, never empty. PolicySpec already enforces this for SDK-authored deploys; this holds it
|
|
307
|
+
for any POSTed body."""
|
|
308
|
+
from sequence_base.contract.policy import check_weights_parts, check_weights_uri
|
|
271
309
|
|
|
272
310
|
if self.weights is None:
|
|
273
311
|
if self.weights_name or self.extra_weights:
|
|
@@ -276,22 +314,12 @@ class DeploymentRequest(BaseModel):
|
|
|
276
314
|
check_weights_parts(self.weights_name, dict(self.extra_weights or {}))
|
|
277
315
|
for what, ref in [("weights.uri", self.weights)] + [(f"extra_weights[{n!r}].uri", r)
|
|
278
316
|
for n, r in (self.extra_weights or {}).items()]:
|
|
279
|
-
|
|
280
|
-
if uri.startswith(TEMPLATE_SCHEME):
|
|
281
|
-
parse_template(uri)
|
|
282
|
-
continue
|
|
283
|
-
if uri.startswith(VOL_SCHEME):
|
|
284
|
-
parse_vol(uri)
|
|
285
|
-
continue
|
|
286
|
-
if not any(uri.startswith(s) and len(uri) > len(s) for s in _WEIGHTS_SCHEMES):
|
|
287
|
-
raise ValueError(f"{what} must be a template://<name> official template, an hf://org/model repo or "
|
|
288
|
-
"a vol://<name> volume (gs://, s3:// and https:// are still accepted until they "
|
|
289
|
-
"are removed)")
|
|
317
|
+
check_weights_uri(ref.uri.strip(), what)
|
|
290
318
|
return self
|
|
291
319
|
|
|
292
320
|
|
|
321
|
+
|
|
293
322
|
_NAME = re.compile(r"[A-Za-z0-9][A-Za-z0-9._-]{0,63}")
|
|
294
|
-
_WEIGHTS_SCHEMES = ("gs://", "hf://", "s3://", "https://")
|
|
295
323
|
|
|
296
324
|
|
|
297
325
|
class DeploymentAccepted(BaseModel):
|
|
@@ -320,4 +348,5 @@ class DeploymentStatusResponse(BaseModel):
|
|
|
320
348
|
status: DeploymentState
|
|
321
349
|
model: str
|
|
322
350
|
error: str | None = Field(default=None, description="Build-failure reason; set only when FAILED")
|
|
351
|
+
|
|
323
352
|
reason: Literal["gpu_out_of_memory", "host_out_of_memory", "crashed"] | None = None
|
|
@@ -7,6 +7,7 @@ the `seq` CLI exit code. The gateway and the worker harness import it; the SDK,
|
|
|
7
7
|
this package on a robot, carries a generated copy that a test compares against `ErrorCodes.json`.
|
|
8
8
|
That is what makes the same situation surface the same way at every entry point.
|
|
9
9
|
|
|
10
|
+
|
|
10
11
|
Distinct from `sequence_base.errors.transport`, which is the internal exception taxonomy the gateway
|
|
11
12
|
and harness raise before a response is built.
|
|
12
13
|
"""
|
|
@@ -48,6 +49,8 @@ class ErrorSpec(NamedTuple):
|
|
|
48
49
|
exit_code: int
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
|
|
53
|
+
|
|
51
54
|
ERRORS: dict[ErrorCode, ErrorSpec] = {
|
|
52
55
|
ErrorCode.INVALID_REQUEST: ErrorSpec(400, False, "InvalidRequest", 2),
|
|
53
56
|
ErrorCode.PAYLOAD_TOO_LARGE: ErrorSpec(413, False, "InvalidRequest", 2),
|
|
@@ -68,6 +71,7 @@ ERRORS: dict[ErrorCode, ErrorSpec] = {
|
|
|
68
71
|
ErrorCode.DEPENDENCY_MISSING: ErrorSpec(424, False, "InternalError", 1),
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
|
|
71
75
|
_CODE_FOR_STATUS: dict[int, ErrorCode] = {
|
|
72
76
|
400: ErrorCode.INVALID_REQUEST, 401: ErrorCode.UNAUTHENTICATED, 402: ErrorCode.INSUFFICIENT_CREDIT,
|
|
73
77
|
403: ErrorCode.FORBIDDEN, 404: ErrorCode.NOT_FOUND, 405: ErrorCode.INVALID_REQUEST,
|
|
@@ -103,15 +107,10 @@ class ErrorBody(BaseModel):
|
|
|
103
107
|
@model_validator(mode="before")
|
|
104
108
|
@classmethod
|
|
105
109
|
def _retryable_from_table(cls, data: Any) -> Any:
|
|
110
|
+
|
|
111
|
+
|
|
106
112
|
if not isinstance(data, dict):
|
|
107
113
|
return data
|
|
108
|
-
if "message" in data and "detail" not in data:
|
|
109
|
-
data = {k: v for k, v in data.items() if k != "message"} | {"detail": data["message"]}
|
|
110
|
-
if "eta_s" in data:
|
|
111
|
-
eta = data["eta_s"]
|
|
112
|
-
data = {k: v for k, v in data.items() if k != "eta_s"}
|
|
113
|
-
if eta is not None:
|
|
114
|
-
data["details"] = {**data.get("details", {}), "eta_s": eta}
|
|
115
114
|
code = data.get("code")
|
|
116
115
|
if code is None:
|
|
117
116
|
default = cls.model_fields["code"].default
|