sequence-base 0.3.9__tar.gz → 0.3.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. {sequence_base-0.3.9 → sequence_base-0.3.12}/PKG-INFO +1 -1
  2. {sequence_base-0.3.9 → sequence_base-0.3.12}/pyproject.toml +1 -1
  3. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/codec/__init__.py +2 -2
  4. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/codec/image.py +34 -0
  5. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/constants/version.py +3 -4
  6. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/act.py +8 -0
  7. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/deployments.py +20 -9
  8. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/io.py +3 -0
  9. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/policy.py +48 -7
  10. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ActionChunk.json +1 -1
  11. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ActionContract.json +1 -1
  12. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ActionStep.json +1 -1
  13. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/AdapterTransform.json +1 -1
  14. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Autoscaler.json +1 -1
  15. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/BenchmarkConditionSpec.json +1 -1
  16. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/BenchmarkRegisterRequest.json +1 -1
  17. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/BenchmarkSpec.json +2 -2
  18. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/BenchmarkStatusResponse.json +1 -1
  19. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/BootstrapResponse.json +1 -1
  20. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Camera.json +14 -1
  21. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ClampInfo.json +1 -1
  22. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/CodeBundle.json +1 -1
  23. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Concurrency.json +1 -1
  24. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Conditions.json +1 -1
  25. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ConnectRequest.json +1 -1
  26. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ConnectResponse.json +14 -1
  27. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/DeploymentAccepted.json +1 -1
  28. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/DeploymentPolicy.json +14 -1
  29. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/DeploymentRequest.json +41 -1
  30. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/DeploymentStatusResponse.json +1 -1
  31. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Embodiment.json +14 -1
  32. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ErrorBody.json +1 -1
  33. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Estimate.json +1 -1
  34. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/EvalDryRunResponse.json +1 -1
  35. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/EvalReport.json +1 -1
  36. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/EvalRequest.json +1 -1
  37. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/EvalResponse.json +1 -1
  38. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ImageFrame.json +18 -1
  39. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ImageSpec.json +1 -1
  40. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ImageStepApt.json +1 -1
  41. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ImageStepEnv.json +1 -1
  42. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ImageStepRun.json +1 -1
  43. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ImageStepUvPip.json +1 -1
  44. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/InferParam.json +1 -1
  45. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Lease.json +1 -1
  46. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/LossyTransform.json +1 -1
  47. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/MetricAgg.json +1 -1
  48. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Observation.json +18 -1
  49. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/ObservationContract.json +14 -1
  50. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/PolicyRegistration.json +42 -2
  51. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/PolicySpec.json +41 -1
  52. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Proprioception.json +1 -1
  53. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/RenderSpec.json +1 -1
  54. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Resources.json +1 -1
  55. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/RolloutResult.json +1 -1
  56. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/SecretCreateRequest.json +1 -1
  57. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/SecretInfo.json +1 -1
  58. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/SecretRef.json +1 -1
  59. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/SeqFlags.json +1 -1
  60. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Step.json +1 -1
  61. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/SuiteAgg.json +1 -1
  62. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/TaskAgg.json +1 -1
  63. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Timeouts.json +1 -1
  64. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/UploadTarget.json +1 -1
  65. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/UsageReport.json +1 -1
  66. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/Variant.json +1 -1
  67. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/VolumeAttach.json +1 -1
  68. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/VolumeFile.json +1 -1
  69. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/VolumeInfo.json +1 -1
  70. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/VolumeMount.json +1 -1
  71. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/VolumeRef.json +1 -1
  72. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/VolumeUploadRequest.json +1 -1
  73. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/VolumeUploadResponse.json +1 -1
  74. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schemas/WarmingError.json +1 -1
  75. {sequence_base-0.3.9 → sequence_base-0.3.12}/tests/test_codec_roundtrip.py +32 -0
  76. {sequence_base-0.3.9 → sequence_base-0.3.12}/tests/test_contracts.py +15 -5
  77. sequence_base-0.3.12/tests/test_weights_parts.py +62 -0
  78. {sequence_base-0.3.9 → sequence_base-0.3.12}/.github/workflows/ci.yml +0 -0
  79. {sequence_base-0.3.9 → sequence_base-0.3.12}/.gitignore +0 -0
  80. {sequence_base-0.3.9 → sequence_base-0.3.12}/README.md +0 -0
  81. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/README.md +0 -0
  82. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/REVIEW.md +0 -0
  83. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/START.md +0 -0
  84. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/accounts.md +0 -0
  85. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/billing.md +0 -0
  86. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/build/BUILD_LOG.md +0 -0
  87. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/build/goal_sha256.json +0 -0
  88. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/build/gs-build-wave.js +0 -0
  89. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/build/gs-spec-goals.js +0 -0
  90. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/container.md +0 -0
  91. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/contracts.md +0 -0
  92. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/deploy/PLAN.md +0 -0
  93. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/deploy/PROD_REORG.md +0 -0
  94. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/deploy/SCHEMA_COMPAT.md +0 -0
  95. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/deploy/archive/sequences-gw.genseq-506918.20261001.yaml +0 -0
  96. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/eval.md +0 -0
  97. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/gateway.md +0 -0
  98. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/A1.yaml +0 -0
  99. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/A2.yaml +0 -0
  100. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/A3.yaml +0 -0
  101. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/C1.yaml +0 -0
  102. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/C2.yaml +0 -0
  103. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/C3.yaml +0 -0
  104. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/C4.yaml +0 -0
  105. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/C5.yaml +0 -0
  106. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/G1.yaml +0 -0
  107. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/G2.yaml +0 -0
  108. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/G3.yaml +0 -0
  109. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/G4.yaml +0 -0
  110. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/G5.yaml +0 -0
  111. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/O1.yaml +0 -0
  112. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/O2.yaml +0 -0
  113. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/O3.yaml +0 -0
  114. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/O4.yaml +0 -0
  115. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/O5.yaml +0 -0
  116. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/R1.yaml +0 -0
  117. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/R2.yaml +0 -0
  118. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/R3.yaml +0 -0
  119. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/S1.yaml +0 -0
  120. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/S2.yaml +0 -0
  121. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/S3.yaml +0 -0
  122. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/S4.yaml +0 -0
  123. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/S5.yaml +0 -0
  124. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/S6.yaml +0 -0
  125. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/V1-storage.md +0 -0
  126. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/V2-user-quotas.md +0 -0
  127. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/W0.1.yaml +0 -0
  128. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/goals/W0.2.yaml +0 -0
  129. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/README.md +0 -0
  130. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/architecture.md +0 -0
  131. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/connect.md +0 -0
  132. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/cost.md +0 -0
  133. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/custom-domain.md +0 -0
  134. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/debugging.md +0 -0
  135. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/goals.md +0 -0
  136. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/limits.md +0 -0
  137. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/plan.md +0 -0
  138. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/white-label.md +0 -0
  139. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/modal/wiring.md +0 -0
  140. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/observability.md +0 -0
  141. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/references.md +0 -0
  142. {sequence_base-0.3.9 → sequence_base-0.3.12}/docs/platform/sdk.md +0 -0
  143. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/__init__.py +0 -0
  144. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/auth.py +0 -0
  145. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/codec/resize.py +0 -0
  146. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/constants/__init__.py +0 -0
  147. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/constants/env.py +0 -0
  148. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/constants/headers.py +0 -0
  149. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/__init__.py +0 -0
  150. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/accounts.py +0 -0
  151. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/benchmarks.py +0 -0
  152. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/connect.py +0 -0
  153. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/errors.py +0 -0
  154. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/eval.py +0 -0
  155. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/flags.py +0 -0
  156. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/contract/volumes.py +0 -0
  157. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/errors/__init__.py +0 -0
  158. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/errors/transport.py +0 -0
  159. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/obs/__init__.py +0 -0
  160. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/obs/log.py +0 -0
  161. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/obs/rid.py +0 -0
  162. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/schema_export.py +0 -0
  163. {sequence_base-0.3.9 → sequence_base-0.3.12}/sequence_base/telemetry/__init__.py +0 -0
  164. {sequence_base-0.3.9 → sequence_base-0.3.12}/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.9
3
+ Version: 0.3.12
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.11
6
6
  Requires-Dist: pydantic>=2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sequence-base"
3
- version = "0.3.9"
3
+ version = "0.3.12"
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.11"
6
6
  dependencies = ["pydantic>=2.0"]
@@ -8,7 +8,7 @@ decodes, installs the light core and never imports this.
8
8
 
9
9
  from sequence_base.codec import encode, decode, ResizeSpec
10
10
  """
11
- from sequence_base.codec.image import DEFAULT_JPEG_QUALITY, decode, encode
11
+ from sequence_base.codec.image import DEFAULT_JPEG_QUALITY, decode, decode_depth, encode, encode_depth
12
12
  from sequence_base.codec.resize import (
13
13
  ASPECT_TOLERANCE_PX,
14
14
  MAX_UPLOAD_EDGE,
@@ -19,7 +19,7 @@ from sequence_base.codec.resize import (
19
19
  )
20
20
 
21
21
  __all__ = [
22
- "encode", "decode", "DEFAULT_JPEG_QUALITY",
22
+ "encode", "decode", "encode_depth", "decode_depth", "DEFAULT_JPEG_QUALITY",
23
23
  "ResizeSpec", "resize_with_pad", "refuse_wrong_aspect", "ratio_name",
24
24
  "MAX_UPLOAD_EDGE", "ASPECT_TOLERANCE_PX",
25
25
  ]
@@ -134,3 +134,37 @@ def decode(data: str) -> "Any":
134
134
 
135
135
  raw = base64.b64decode(data, validate=False)
136
136
  return np.asarray(Image.open(io.BytesIO(raw)).convert("RGB"), dtype=np.uint8)
137
+
138
+
139
+ # ── depth frames ─────────────────────────────────────────────────────────────────────────────────────────────────────
140
+ _DEPTH_UNITS = {"m": 1000.0, "mm": 1.0}
141
+
142
+
143
+ def encode_depth(depth: Any, *, unit: str = "m") -> str:
144
+ """A depth map -> the base64 16-bit PNG a depth frame (ImageFrame kind="depth") carries: millimetres as uint16, 0
145
+ where there is no reading (NaN, inf, <= 0), clipped at 65.535 m. `unit` is what the array holds: "m" (float metres,
146
+ the default) or "mm". Lossless, unlike the JPEG colour frames take — a depth error is a geometry error.
147
+ {gs-plans/customization/io-contract.md "深度图"} [CONFIDENCE: CONFIRMED 90% — uint16 millimetres is the layout
148
+ depth cameras and ROS depth images use]"""
149
+ import numpy as np
150
+ from PIL import Image
151
+
152
+ if unit not in _DEPTH_UNITS:
153
+ raise ValueError(f"unit must be one of {sorted(_DEPTH_UNITS)}, got {unit!r}")
154
+ arr = np.asarray(depth, dtype=np.float64)
155
+ if arr.ndim != 2:
156
+ raise ValueError(f"a depth map is HxW, got shape {arr.shape}")
157
+ mm = arr * _DEPTH_UNITS[unit]
158
+ mm = np.where(np.isfinite(mm) & (mm > 0), mm, 0.0)
159
+ buf = io.BytesIO()
160
+ Image.fromarray(np.clip(np.rint(mm), 0, 65535).astype(np.uint16)).save(buf, format="PNG")
161
+ return base64.b64encode(buf.getvalue()).decode()
162
+
163
+
164
+ def decode_depth(data: str) -> "Any":
165
+ """A depth frame's data -> HxW uint16 millimetres (0: no reading) — the worker's inverse of `encode_depth`."""
166
+ import numpy as np
167
+ from PIL import Image
168
+
169
+ raw = base64.b64decode(data, validate=False)
170
+ return np.asarray(Image.open(io.BytesIO(raw)), dtype=np.uint16)
@@ -1,12 +1,11 @@
1
- """Wire protocol version. Bump on a breaking change to contract / codec / telemetry shapes."""
2
-
3
- PROTOCOL_VERSION = "1"
1
+ """The shared wire contract's version."""
4
2
 
5
3
  # The single version stamped into every exported JSON Schema (as `x-contract-version`), so a consumer
6
4
  # across deployments / repos can tell which version of a shape it is validating against. MUST change
7
5
  # whenever any shared wire shape changes (a field added / removed / retyped) — that is what makes
8
6
  # contract evolution mechanically detectable instead of eyeballed. Bump on any shape change.
9
- CONTRACT_VERSION = "0.4.8" # 0.4.7 -> 0.4.8: ImageSpec.python, ImageStepRun.secrets, Resources.region, DeploymentRequest/BenchmarkRegisterRequest.image_context
7
+ CONTRACT_VERSION = "0.4.11" # 0.4.10 -> 0.4.11: weights in named parts (weights_name, extra_weights)
8
+ # previous: 0.4.8 # 0.4.7 -> 0.4.8: ImageSpec.python, ImageStepRun.secrets, Resources.region, DeploymentRequest/BenchmarkRegisterRequest.image_context
10
9
  # previous: 0.4.7 # 0.4.6 -> 0.4.7: ActionContract.bounds / max_delta / on_violation (action limits)
11
10
  # previous: 0.4.6 # 0.4.5 -> 0.4.6: InferParam + DeploymentPolicy.params; EvalRequest.params / variants / record; BenchmarkRegisterRequest.gpu
12
11
  # previous: 0.4.5 # 0.4.4 -> 0.4.5: BenchmarkRegisterRequest.condition_list / timeout_s / default_adapter_ref (+ BenchmarkConditionSpec); EvalRequest.tasks / max_usd / rerun_of
@@ -10,6 +10,8 @@ from __future__ import annotations
10
10
 
11
11
  from enum import Enum
12
12
 
13
+ from typing import Literal
14
+
13
15
  from pydantic import BaseModel, ConfigDict, Field
14
16
 
15
17
 
@@ -25,6 +27,12 @@ class ImageFrame(BaseModel):
25
27
  data: str = Field(..., description="Base64-encoded image (PNG or JPEG). URLs are not fetched.")
26
28
  timestamp_ms: int | None = Field(default=None,
27
29
  description="Orders multiple frames of a view; array order used when omitted")
30
+ # What the frame holds: colour (the default — sent without this field, so a worker older than depth frames still
31
+ # accepts it) or depth: a 16-bit PNG of millimetres, 0 where the sensor read nothing (codec.encode_depth /
32
+ # decode_depth). A depth frame shares its camera's view name. {gs-plans/customization/io-contract.md
33
+ # "深度图作为 IMAGEFRAME.KIND: RGB | DEPTH"}
34
+ kind: Literal["rgb", "depth"] | None = Field(
35
+ default=None, description="rgb (the default) or depth: a 16-bit PNG of millimetres, 0 where there is no reading")
28
36
 
29
37
 
30
38
  class Proprioception(BaseModel):
@@ -206,6 +206,11 @@ class DeploymentRequest(BaseModel):
206
206
  # (goal 13).
207
207
  concurrency: Concurrency = Field(default_factory=lambda: Concurrency(max_inputs=1, target_inputs=1))
208
208
  timeouts: Timeouts | None = None
209
+ # Weights in several named parts: `weights` is the first and `weights_name` its name; `extra_weights` the others,
210
+ # each provisioned like `weights`. @seq.load then receives {name: directory}. Both None (and absent from the wire):
211
+ # one weights path, as before. {gs-plans/customization/options.md "多份权重文件(BASE + LORA …)"}
212
+ weights_name: str | None = None
213
+ extra_weights: dict[str, VolumeMount] | None = None
209
214
 
210
215
  @field_validator("name")
211
216
  @classmethod
@@ -220,22 +225,28 @@ class DeploymentRequest(BaseModel):
220
225
 
221
226
  @model_validator(mode="after")
222
227
  def _weights_have_an_origin(self) -> "DeploymentRequest":
223
- """The checkpoint the build provisions: a gs:// prefix, an hf:// repo or an uploaded vol:// volume, never
228
+ """The checkpoint the build provisions: a gs:// or s3:// prefix, an https:// file, an hf:// repo or an uploaded
229
+ vol:// volume, never
224
230
  empty. PolicySpec already enforces this for SDK-authored deploys; this holds it for any POSTed body."""
225
- uri = self.weights.uri.strip()
226
- if uri.startswith(VOL_SCHEME):
227
- parse_vol(uri)
228
- return self
229
- if not any(uri.startswith(s) and len(uri) > len(s) for s in _WEIGHTS_SCHEMES):
230
- raise ValueError("weights.uri must be a gs://bucket/prefix, an hf://org/model repo or a "
231
- "vol://<name> volume")
231
+ from sequence_base.contract.policy import check_weights_parts
232
+
233
+ check_weights_parts(self.weights_name, dict(self.extra_weights or {}))
234
+ for what, ref in [("weights.uri", self.weights)] + [(f"extra_weights[{n!r}].uri", r)
235
+ for n, r in (self.extra_weights or {}).items()]:
236
+ uri = ref.uri.strip()
237
+ if uri.startswith(VOL_SCHEME):
238
+ parse_vol(uri)
239
+ continue
240
+ if not any(uri.startswith(s) and len(uri) > len(s) for s in _WEIGHTS_SCHEMES):
241
+ raise ValueError(f"{what} must be a gs://bucket/prefix, an s3://bucket/prefix, an https:// URL, an "
242
+ "hf://org/model repo or a vol://<name> volume")
232
243
  return self
233
244
 
234
245
 
235
246
  # A deployment name: what `connect(model=...)` and the console address. {DeploymentRequest._name_is_a_slug}
236
247
  _NAME = re.compile(r"[A-Za-z0-9][A-Za-z0-9._-]{0,63}")
237
248
  # The origins the build knows how to provision weights from.
238
- _WEIGHTS_SCHEMES = ("gs://", "hf://")
249
+ _WEIGHTS_SCHEMES = ("gs://", "hf://", "s3://", "https://")
239
250
 
240
251
 
241
252
  class DeploymentAccepted(BaseModel):
@@ -66,6 +66,9 @@ class Camera(BaseModel):
66
66
 
67
67
  width: int = Field(..., gt=0, le=8192)
68
68
  height: int = Field(..., gt=0, le=8192)
69
+ # The view also sends a depth frame (ImageFrame kind=depth, same view name) the policy reads; the worker refuses an
70
+ # observation without it. Unset (not False) by default, so a contract without depth is the one it always was.
71
+ depth: bool | None = Field(default=None, description="the view also sends a depth frame (ImageFrame kind=depth)")
69
72
 
70
73
 
71
74
  class ObservationContract(BaseModel):
@@ -8,6 +8,8 @@ Every shape here forbids unknown fields and pins exact field types — no `Optio
8
8
  """
9
9
  from __future__ import annotations
10
10
 
11
+ import re
12
+
11
13
  from typing import Any
12
14
 
13
15
  from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
@@ -150,18 +152,57 @@ class PolicySpec(BaseModel):
150
152
  # What the policy reads (None: undeclared — an older SDK); per-robot contracts when one model drives several.
151
153
  observation: ObservationContract | None = None
152
154
  embodiments: dict[str, Embodiment] | None = None
155
+ # Weights in several named parts (`weights={"base": "hf://…", "lora": "vol://…"}`): `weights` is the first part and
156
+ # `weights_name` its name; `extra_weights` are the others, each provisioned on its own, and @seq.load receives
157
+ # {name: directory}. Both None: one weights path, as before. {gs-plans/customization/options.md "多份权重文件"}
158
+ weights_name: str | None = None
159
+ extra_weights: dict[str, str] | None = None
153
160
 
154
161
  @field_validator("weights")
155
162
  @classmethod
156
163
  def _weights_scheme(cls, v: str) -> str:
157
- # vol:// is a volume the owner uploaded (contract 7); the gateway resolves it per owner at deploy.
158
- if v.startswith("vol://"):
159
- from sequence_base.contract.volumes import parse_vol
160
- parse_vol(v)
161
- return v
162
- if not (v.startswith("gs://") or v.startswith("hf://")):
163
- raise ValueError("weights must be a gs://, hf:// or vol:// URI")
164
+ return check_weights_uri(v, "weights")
165
+
166
+ @model_validator(mode="after")
167
+ def _weights_parts(self) -> "PolicySpec":
168
+ check_weights_parts(self.weights_name, {k: v for k, v in (self.extra_weights or {}).items()})
169
+ for name, uri in (self.extra_weights or {}).items():
170
+ check_weights_uri(uri, f"weights[{name!r}]")
171
+ return self
172
+
173
+
174
+ # A weights part's name: what @seq.load is handed it under, and a directory name on the worker.
175
+ WEIGHTS_PART_NAME = re.compile(r"[a-z][a-z0-9_-]{0,31}")
176
+ MAX_WEIGHTS_PARTS = 8
177
+
178
+
179
+ def check_weights_uri(v: str, what: str = "weights") -> str:
180
+ """A weights origin the build can provision: gs://, s3://, https://, hf:// or an uploaded vol:// volume."""
181
+ # vol:// is a volume the owner uploaded (contract 7); the gateway resolves it per owner at deploy.
182
+ if v.startswith("vol://"):
183
+ from sequence_base.contract.volumes import parse_vol
184
+ parse_vol(v)
164
185
  return v
186
+ # s3:// (the author's own bucket, or any S3-compatible store) and https:// (one file or archive at a URL):
187
+ # {gs-plans/customization/README.md P2 "S3:// / HTTPS:// 权重"}
188
+ if not v.startswith(("gs://", "hf://", "s3://", "https://")):
189
+ raise ValueError(f"{what} must be a gs://, s3://, https://, hf:// or vol:// URI")
190
+ return v
191
+
192
+
193
+ def check_weights_parts(weights_name: str | None, extra: dict) -> None:
194
+ """Named weights parts: lowercase names, at most MAX_WEIGHTS_PARTS in all, none twice; extras need a named first part."""
195
+ names = ([weights_name] if weights_name else []) + list(extra)
196
+ for n in names:
197
+ if not isinstance(n, str) or not WEIGHTS_PART_NAME.fullmatch(n):
198
+ raise ValueError(f"a weights part's name is 1-32 lowercase letters, digits, '_' or '-', starting with a "
199
+ f"letter: {n!r}")
200
+ if extra and not weights_name:
201
+ raise ValueError("extra weights need the first part named too (weights_name)")
202
+ if len(names) != len(set(names)):
203
+ raise ValueError("each weights part needs its own name")
204
+ if len(names) > MAX_WEIGHTS_PARTS:
205
+ raise ValueError(f"at most {MAX_WEIGHTS_PARTS} weights parts")
165
206
 
166
207
 
167
208
  class PolicyRegistration(BaseModel):
@@ -98,5 +98,5 @@
98
98
  ],
99
99
  "title": "ActionChunk",
100
100
  "type": "object",
101
- "x-contract-version": "0.4.8"
101
+ "x-contract-version": "0.4.11"
102
102
  }
@@ -99,5 +99,5 @@
99
99
  ],
100
100
  "title": "ActionContract",
101
101
  "type": "object",
102
- "x-contract-version": "0.4.8"
102
+ "x-contract-version": "0.4.11"
103
103
  }
@@ -19,5 +19,5 @@
19
19
  ],
20
20
  "title": "ActionStep",
21
21
  "type": "object",
22
- "x-contract-version": "0.4.8"
22
+ "x-contract-version": "0.4.11"
23
23
  }
@@ -38,5 +38,5 @@
38
38
  ],
39
39
  "title": "AdapterTransform",
40
40
  "type": "object",
41
- "x-contract-version": "0.4.8"
41
+ "x-contract-version": "0.4.11"
42
42
  }
@@ -39,5 +39,5 @@
39
39
  },
40
40
  "title": "Autoscaler",
41
41
  "type": "object",
42
- "x-contract-version": "0.4.8"
42
+ "x-contract-version": "0.4.11"
43
43
  }
@@ -62,5 +62,5 @@
62
62
  ],
63
63
  "title": "BenchmarkConditionSpec",
64
64
  "type": "object",
65
- "x-contract-version": "0.4.8"
65
+ "x-contract-version": "0.4.11"
66
66
  }
@@ -638,5 +638,5 @@
638
638
  ],
639
639
  "title": "BenchmarkRegisterRequest",
640
640
  "type": "object",
641
- "x-contract-version": "0.4.8"
641
+ "x-contract-version": "0.4.11"
642
642
  }
@@ -235,7 +235,7 @@
235
235
  ],
236
236
  "title": "SeqFlags",
237
237
  "type": "integer",
238
- "x-contract-version": "0.4.8",
238
+ "x-contract-version": "0.4.11",
239
239
  "x-flag-names": {
240
240
  "CHECK": 65536,
241
241
  "INFER": 16,
@@ -425,5 +425,5 @@
425
425
  ],
426
426
  "title": "BenchmarkSpec",
427
427
  "type": "object",
428
- "x-contract-version": "0.4.8"
428
+ "x-contract-version": "0.4.11"
429
429
  }
@@ -40,5 +40,5 @@
40
40
  ],
41
41
  "title": "BenchmarkStatusResponse",
42
42
  "type": "object",
43
- "x-contract-version": "0.4.8"
43
+ "x-contract-version": "0.4.11"
44
44
  }
@@ -72,5 +72,5 @@
72
72
  ],
73
73
  "title": "BootstrapResponse",
74
74
  "type": "object",
75
- "x-contract-version": "0.4.8"
75
+ "x-contract-version": "0.4.11"
76
76
  }
@@ -2,6 +2,19 @@
2
2
  "additionalProperties": false,
3
3
  "description": "One camera view a policy reads: the size it expects. Informational at the worker (the policy resizes);\nthe client resizes and letterboxes to it before sending, so the bytes on the wire are what is used.",
4
4
  "properties": {
5
+ "depth": {
6
+ "anyOf": [
7
+ {
8
+ "type": "boolean"
9
+ },
10
+ {
11
+ "type": "null"
12
+ }
13
+ ],
14
+ "default": null,
15
+ "description": "the view also sends a depth frame (ImageFrame kind=depth)",
16
+ "title": "Depth"
17
+ },
5
18
  "height": {
6
19
  "exclusiveMinimum": 0,
7
20
  "maximum": 8192,
@@ -21,5 +34,5 @@
21
34
  ],
22
35
  "title": "Camera",
23
36
  "type": "object",
24
- "x-contract-version": "0.4.8"
37
+ "x-contract-version": "0.4.11"
25
38
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "ClampInfo",
25
25
  "type": "object",
26
- "x-contract-version": "0.4.8"
26
+ "x-contract-version": "0.4.11"
27
27
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "CodeBundle",
25
25
  "type": "object",
26
- "x-contract-version": "0.4.8"
26
+ "x-contract-version": "0.4.11"
27
27
  }
@@ -17,5 +17,5 @@
17
17
  ],
18
18
  "title": "Concurrency",
19
19
  "type": "object",
20
- "x-contract-version": "0.4.8"
20
+ "x-contract-version": "0.4.11"
21
21
  }
@@ -55,5 +55,5 @@
55
55
  ],
56
56
  "title": "Conditions",
57
57
  "type": "object",
58
- "x-contract-version": "0.4.8"
58
+ "x-contract-version": "0.4.11"
59
59
  }
@@ -25,5 +25,5 @@
25
25
  ],
26
26
  "title": "ConnectRequest",
27
27
  "type": "object",
28
- "x-contract-version": "0.4.8"
28
+ "x-contract-version": "0.4.11"
29
29
  }
@@ -104,6 +104,19 @@
104
104
  "additionalProperties": false,
105
105
  "description": "One camera view a policy reads: the size it expects. Informational at the worker (the policy resizes);\nthe client resizes and letterboxes to it before sending, so the bytes on the wire are what is used.",
106
106
  "properties": {
107
+ "depth": {
108
+ "anyOf": [
109
+ {
110
+ "type": "boolean"
111
+ },
112
+ {
113
+ "type": "null"
114
+ }
115
+ ],
116
+ "default": null,
117
+ "description": "the view also sends a depth frame (ImageFrame kind=depth)",
118
+ "title": "Depth"
119
+ },
107
120
  "height": {
108
121
  "exclusiveMinimum": 0,
109
122
  "maximum": 8192,
@@ -281,5 +294,5 @@
281
294
  ],
282
295
  "title": "ConnectResponse",
283
296
  "type": "object",
284
- "x-contract-version": "0.4.8"
297
+ "x-contract-version": "0.4.11"
285
298
  }
@@ -18,5 +18,5 @@
18
18
  ],
19
19
  "title": "DeploymentAccepted",
20
20
  "type": "object",
21
- "x-contract-version": "0.4.8"
21
+ "x-contract-version": "0.4.11"
22
22
  }
@@ -104,6 +104,19 @@
104
104
  "additionalProperties": false,
105
105
  "description": "One camera view a policy reads: the size it expects. Informational at the worker (the policy resizes);\nthe client resizes and letterboxes to it before sending, so the bytes on the wire are what is used.",
106
106
  "properties": {
107
+ "depth": {
108
+ "anyOf": [
109
+ {
110
+ "type": "boolean"
111
+ },
112
+ {
113
+ "type": "null"
114
+ }
115
+ ],
116
+ "default": null,
117
+ "description": "the view also sends a depth frame (ImageFrame kind=depth)",
118
+ "title": "Depth"
119
+ },
107
120
  "height": {
108
121
  "exclusiveMinimum": 0,
109
122
  "maximum": 8192,
@@ -353,5 +366,5 @@
353
366
  ],
354
367
  "title": "DeploymentPolicy",
355
368
  "type": "object",
356
- "x-contract-version": "0.4.8"
369
+ "x-contract-version": "0.4.11"
357
370
  }
@@ -146,6 +146,19 @@
146
146
  "additionalProperties": false,
147
147
  "description": "One camera view a policy reads: the size it expects. Informational at the worker (the policy resizes);\nthe client resizes and letterboxes to it before sending, so the bytes on the wire are what is used.",
148
148
  "properties": {
149
+ "depth": {
150
+ "anyOf": [
151
+ {
152
+ "type": "boolean"
153
+ },
154
+ {
155
+ "type": "null"
156
+ }
157
+ ],
158
+ "default": null,
159
+ "description": "the view also sends a depth frame (ImageFrame kind=depth)",
160
+ "title": "Depth"
161
+ },
149
162
  "height": {
150
163
  "exclusiveMinimum": 0,
151
164
  "maximum": 8192,
@@ -716,6 +729,21 @@
716
729
  "concurrency": {
717
730
  "$ref": "#/$defs/Concurrency"
718
731
  },
732
+ "extra_weights": {
733
+ "anyOf": [
734
+ {
735
+ "additionalProperties": {
736
+ "$ref": "#/$defs/VolumeMount"
737
+ },
738
+ "type": "object"
739
+ },
740
+ {
741
+ "type": "null"
742
+ }
743
+ ],
744
+ "default": null,
745
+ "title": "Extra Weights"
746
+ },
719
747
  "image": {
720
748
  "$ref": "#/$defs/ImageSpec"
721
749
  },
@@ -760,6 +788,18 @@
760
788
  },
761
789
  "weights": {
762
790
  "$ref": "#/$defs/VolumeMount"
791
+ },
792
+ "weights_name": {
793
+ "anyOf": [
794
+ {
795
+ "type": "string"
796
+ },
797
+ {
798
+ "type": "null"
799
+ }
800
+ ],
801
+ "default": null,
802
+ "title": "Weights Name"
763
803
  }
764
804
  },
765
805
  "required": [
@@ -771,5 +811,5 @@
771
811
  ],
772
812
  "title": "DeploymentRequest",
773
813
  "type": "object",
774
- "x-contract-version": "0.4.8"
814
+ "x-contract-version": "0.4.11"
775
815
  }
@@ -41,5 +41,5 @@
41
41
  ],
42
42
  "title": "DeploymentStatusResponse",
43
43
  "type": "object",
44
- "x-contract-version": "0.4.8"
44
+ "x-contract-version": "0.4.11"
45
45
  }
@@ -104,6 +104,19 @@
104
104
  "additionalProperties": false,
105
105
  "description": "One camera view a policy reads: the size it expects. Informational at the worker (the policy resizes);\nthe client resizes and letterboxes to it before sending, so the bytes on the wire are what is used.",
106
106
  "properties": {
107
+ "depth": {
108
+ "anyOf": [
109
+ {
110
+ "type": "boolean"
111
+ },
112
+ {
113
+ "type": "null"
114
+ }
115
+ ],
116
+ "default": null,
117
+ "description": "the view also sends a depth frame (ImageFrame kind=depth)",
118
+ "title": "Depth"
119
+ },
107
120
  "height": {
108
121
  "exclusiveMinimum": 0,
109
122
  "maximum": 8192,
@@ -199,5 +212,5 @@
199
212
  ],
200
213
  "title": "Embodiment",
201
214
  "type": "object",
202
- "x-contract-version": "0.4.8"
215
+ "x-contract-version": "0.4.11"
203
216
  }
@@ -28,5 +28,5 @@
28
28
  ],
29
29
  "title": "ErrorBody",
30
30
  "type": "object",
31
- "x-contract-version": "0.4.8"
31
+ "x-contract-version": "0.4.11"
32
32
  }
@@ -21,5 +21,5 @@
21
21
  ],
22
22
  "title": "Estimate",
23
23
  "type": "object",
24
- "x-contract-version": "0.4.8"
24
+ "x-contract-version": "0.4.11"
25
25
  }
@@ -37,5 +37,5 @@
37
37
  ],
38
38
  "title": "EvalDryRunResponse",
39
39
  "type": "object",
40
- "x-contract-version": "0.4.8"
40
+ "x-contract-version": "0.4.11"
41
41
  }
@@ -183,5 +183,5 @@
183
183
  ],
184
184
  "title": "EvalReport",
185
185
  "type": "object",
186
- "x-contract-version": "0.4.8"
186
+ "x-contract-version": "0.4.11"
187
187
  }
@@ -213,5 +213,5 @@
213
213
  ],
214
214
  "title": "EvalRequest",
215
215
  "type": "object",
216
- "x-contract-version": "0.4.8"
216
+ "x-contract-version": "0.4.11"
217
217
  }
@@ -84,5 +84,5 @@
84
84
  ],
85
85
  "title": "EvalResponse",
86
86
  "type": "object",
87
- "x-contract-version": "0.4.8"
87
+ "x-contract-version": "0.4.11"
88
88
  }