sequence-base 0.4.22__tar.gz → 0.4.23__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 (108) hide show
  1. {sequence_base-0.4.22 → sequence_base-0.4.23}/PKG-INFO +1 -1
  2. {sequence_base-0.4.22 → sequence_base-0.4.23}/pyproject.toml +1 -1
  3. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/constants/version.py +2 -1
  4. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/policy.py +14 -0
  5. sequence_base-0.4.23/sequence_base/msgpack_io.py +328 -0
  6. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ActRequest.json +1 -1
  7. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ActResponse.json +1 -1
  8. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ActionChunk.json +1 -1
  9. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ActionContract.json +1 -1
  10. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ActionStep.json +1 -1
  11. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/AdapterPair.json +1 -1
  12. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/AddLocal.json +1 -1
  13. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Autoscaler.json +1 -1
  14. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/BenchmarkConditionSpec.json +1 -1
  15. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/BenchmarkRegisterRequest.json +1 -1
  16. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/BenchmarkSpec.json +2 -2
  17. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/BenchmarkStatusResponse.json +1 -1
  18. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/BootstrapResponse.json +1 -1
  19. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Camera.json +1 -1
  20. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/CodeBundle.json +1 -1
  21. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Concurrency.json +1 -1
  22. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Conditions.json +1 -1
  23. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ConnectRequest.json +1 -1
  24. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ConnectResponse.json +1 -1
  25. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/DeploymentAccepted.json +1 -1
  26. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/DeploymentPolicy.json +1 -1
  27. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/DeploymentRequest.json +1 -1
  28. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/DeploymentStatusResponse.json +1 -1
  29. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Embodiment.json +1 -1
  30. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ErrorBody.json +1 -1
  31. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ErrorCodes.json +1 -1
  32. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Estimate.json +1 -1
  33. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/EvalDryRunResponse.json +1 -1
  34. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/EvalReport.json +1 -1
  35. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/EvalRequest.json +1 -1
  36. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/EvalResponse.json +1 -1
  37. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageFrame.json +1 -1
  38. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageSpec.json +1 -1
  39. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageStepAddLocal.json +1 -1
  40. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageStepApt.json +1 -1
  41. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageStepEnv.json +1 -1
  42. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageStepRun.json +1 -1
  43. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageStepTemplateFiles.json +1 -1
  44. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ImageStepUvPip.json +1 -1
  45. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/InferParam.json +1 -1
  46. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Lease.json +1 -1
  47. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/MetricAgg.json +1 -1
  48. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Observation.json +1 -1
  49. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ObservationContract.json +1 -1
  50. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/PolicyRegistration.json +34 -2
  51. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/PolicySpec.json +33 -1
  52. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Proprioception.json +1 -1
  53. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/RenderSpec.json +1 -1
  54. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/ReplaySpec.json +1 -1
  55. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Resources.json +1 -1
  56. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/RolloutResult.json +1 -1
  57. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/SecretCreateRequest.json +1 -1
  58. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/SecretInfo.json +1 -1
  59. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/SecretRef.json +1 -1
  60. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/SeqFlags.json +1 -1
  61. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Step.json +1 -1
  62. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/TaskAgg.json +1 -1
  63. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/TemplateFiles.json +1 -1
  64. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Timeouts.json +1 -1
  65. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/UploadTarget.json +1 -1
  66. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/Variant.json +1 -1
  67. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/VolumeFile.json +1 -1
  68. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/VolumeInfo.json +1 -1
  69. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/VolumeMount.json +1 -1
  70. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/VolumeRef.json +1 -1
  71. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/VolumeUploadRequest.json +1 -1
  72. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/VolumeUploadResponse.json +1 -1
  73. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schemas/WarmingError.json +1 -1
  74. {sequence_base-0.4.22 → sequence_base-0.4.23}/.gitignore +0 -0
  75. {sequence_base-0.4.22 → sequence_base-0.4.23}/README.md +0 -0
  76. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/__init__.py +0 -0
  77. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/auth.py +0 -0
  78. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/codec/__init__.py +0 -0
  79. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/codec/image.py +0 -0
  80. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/constants/__init__.py +0 -0
  81. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/constants/cards.py +0 -0
  82. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/constants/headers.py +0 -0
  83. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/constants/limits.py +0 -0
  84. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/__init__.py +0 -0
  85. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/accounts.py +0 -0
  86. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/act.py +0 -0
  87. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/adapters.py +0 -0
  88. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/benchmarks.py +0 -0
  89. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/connect.py +0 -0
  90. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/deployments.py +0 -0
  91. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/errors.py +0 -0
  92. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/eval.py +0 -0
  93. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/flags.py +0 -0
  94. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/io.py +0 -0
  95. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/templates.py +0 -0
  96. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/volumes.py +0 -0
  97. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/contract/wire.py +0 -0
  98. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/errors/__init__.py +0 -0
  99. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/errors/transport.py +0 -0
  100. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/obs/__init__.py +0 -0
  101. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/obs/log.py +0 -0
  102. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/obs/rid.py +0 -0
  103. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/presets/__init__.py +0 -0
  104. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/presets/frames.py +0 -0
  105. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/presets/robot_arm.py +0 -0
  106. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/schema_export.py +0 -0
  107. {sequence_base-0.4.22 → sequence_base-0.4.23}/sequence_base/telemetry/__init__.py +0 -0
  108. {sequence_base-0.4.22 → sequence_base-0.4.23}/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.22
3
+ Version: 0.4.23
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.22"
3
+ version = "0.4.23"
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"]
@@ -4,7 +4,8 @@
4
4
 
5
5
 
6
6
 
7
- CONTRACT_VERSION = "0.5.19"
7
+ CONTRACT_VERSION = "0.5.20"
8
+
8
9
 
9
10
 
10
11
 
@@ -281,6 +281,13 @@ class PolicySpec(BaseModel):
281
281
 
282
282
  family: str | None = Field(default=None, pattern=KIND_NAME)
283
283
 
284
+
285
+
286
+
287
+
288
+ own_observations: Literal["latest", "since_last_act"] | None = None
289
+ own_actions: Literal["one", "steps"] | None = None
290
+
284
291
  @field_validator("weights")
285
292
  @classmethod
286
293
  def _weights_scheme(cls, v: str | None) -> str | None:
@@ -295,6 +302,13 @@ class PolicySpec(BaseModel):
295
302
  check_weights_uri(uri, f"weights[{name!r}]")
296
303
  return self
297
304
 
305
+ @model_validator(mode="after")
306
+ def _own_io(self) -> "PolicySpec":
307
+ if (self.own_observations or self.own_actions) and (self.action or self.observation or self.embodiments):
308
+ raise ValueError("own_observations and own_actions are for a policy of its own inputs and outputs; this one "
309
+ "declares the robot-arm contract, where observation history and the action chunk say it")
310
+ return self
311
+
298
312
 
299
313
 
300
314
  WEIGHTS_PART_NAME = re.compile(r"[a-z][a-z0-9_-]{0,31}")
@@ -0,0 +1,328 @@
1
+ """
2
+ An act as msgpack (application/x-seq-msgpack, version 1): an own-I/O envelope with its bytes as bytes and its numpy
3
+ arrays as their raw data, where JSON carries bytes as base64 - a third more on the wire - and arrays as lists of numbers.
4
+ Written in plain Python, so neither a worker nor a client installs a msgpack package for it.
5
+
6
+ In one sentence: a client takes the act's envelope ({"inputs", "seed", "episode_id", "params", ...}) → `pack` writes it
7
+ as msgpack, each numpy array as the map msgpack-numpy writes ({"nd": True, "type", "kind", "shape", "data"}) → a worker
8
+ that names FORMAT among its formats `unpack`s it back to the same dict, arrays as arrays, and serves it as it serves a
9
+ JSON act; an answer asked for in msgpack (Accept: MEDIA_TYPE) comes back the same way.
10
+
11
+ WHY a media type of its own: a worker reads a body that is not JSON as the policy's own inputs and hands it on
12
+ untouched - an `application/msgpack` body included, which some policies decode themselves - so a client sends this
13
+ type only to a worker that says it reads it.
14
+ WHY both array layouts are read: the two ecosystems that send numpy over msgpack write arrays differently -
15
+ msgpack-numpy as {"nd", "type", "kind", "shape", "data"}, openpi as {"__ndarray__", "data", "dtype", "shape"} - and a
16
+ policy's own client may use either. {XPolicyLab 5d0be14 client_server/ws/protocol/codec.py "msgpack_numpy.encode";
17
+ openpi-client msgpack_numpy.py "{b\"__ndarray__\": True, b\"data\": obj.tobytes(), b\"dtype\": obj.dtype.str"}
18
+ WHY no array that holds objects: msgpack-numpy writes one with pickle, and reading that back runs code the sender chose;
19
+ a dtype that holds objects, a structured one and every msgpack extension type are refused, so nothing read here runs
20
+ anything.
21
+
22
+ body = msgpack_io.pack(envelope) # MsgpackError: something msgpack cannot carry
23
+ envelope = msgpack_io.unpack(body) # MsgpackError: not one msgpack value, or one this refuses
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import struct
28
+ from typing import Any
29
+
30
+ __all__ = ["FORMAT", "MAX_DEPTH", "MEDIA_TYPE", "MsgpackError", "pack", "unpack"]
31
+
32
+ MEDIA_TYPE = "application/x-seq-msgpack"
33
+
34
+ FORMAT = "x-seq-msgpack/1"
35
+
36
+ MAX_DEPTH = 64
37
+
38
+
39
+ class MsgpackError(ValueError):
40
+ """A value msgpack cannot carry (packing), or a body that is not exactly one msgpack value this reads (unpacking)."""
41
+
42
+
43
+
44
+ def pack(obj: Any) -> bytes:
45
+ """`obj` as msgpack: None, bools, ints (-2**63 to 2**64 - 1), floats, str, bytes, lists and tuples, dicts (keys
46
+ str, bytes or int), numpy arrays and scalars - as msgpack-numpy writes them - inside any of those."""
47
+ out: list[bytes] = []
48
+ _pack(obj, out, 0)
49
+ return b"".join(out)
50
+
51
+
52
+ def _pack(obj: Any, out: list, depth: int) -> None:
53
+ if depth > MAX_DEPTH:
54
+ raise MsgpackError(f"nested deeper than {MAX_DEPTH} levels")
55
+ if obj is None:
56
+ out.append(b"\xc0")
57
+ elif obj is True:
58
+ out.append(b"\xc3")
59
+ elif obj is False:
60
+ out.append(b"\xc2")
61
+ elif isinstance(obj, int):
62
+ _pack_int(obj, out)
63
+ elif isinstance(obj, float):
64
+ out.append(struct.pack(">Bd", 0xCB, obj))
65
+ elif isinstance(obj, str):
66
+ try:
67
+ raw = obj.encode("utf-8")
68
+ except UnicodeEncodeError as exc:
69
+ raise MsgpackError(f"a string that is not UTF-8: {exc.reason}") from None
70
+ _pack_head(len(raw), out, fix=(0xA0, 31), sizes=((0xD9, ">BB", 0xFF), (0xDA, ">BH", 0xFFFF),
71
+ (0xDB, ">BI", 0xFFFFFFFF)), what="string")
72
+ out.append(raw)
73
+ elif isinstance(obj, (bytes, bytearray, memoryview)):
74
+ raw = bytes(obj)
75
+ _pack_head(len(raw), out, fix=None, sizes=((0xC4, ">BB", 0xFF), (0xC5, ">BH", 0xFFFF),
76
+ (0xC6, ">BI", 0xFFFFFFFF)), what="bytes")
77
+ out.append(raw)
78
+ elif isinstance(obj, (list, tuple)):
79
+ _pack_head(len(obj), out, fix=(0x90, 15), sizes=((0xDC, ">BH", 0xFFFF), (0xDD, ">BI", 0xFFFFFFFF)),
80
+ what="list")
81
+ for item in obj:
82
+ _pack(item, out, depth + 1)
83
+ elif isinstance(obj, dict):
84
+ _pack_head(len(obj), out, fix=(0x80, 15), sizes=((0xDE, ">BH", 0xFFFF), (0xDF, ">BI", 0xFFFFFFFF)),
85
+ what="dict")
86
+ for key, value in obj.items():
87
+ if not isinstance(key, (str, bytes, int)) or isinstance(key, bool):
88
+ raise MsgpackError(f"a dict key that is not str, bytes or int: {type(key).__name__}")
89
+ _pack(key, out, depth + 1)
90
+ _pack(value, out, depth + 1)
91
+ else:
92
+ arr = _numpy_map(obj)
93
+ if arr is None:
94
+ raise MsgpackError(f"{type(obj).__name__} cannot be sent as msgpack (JSON values, bytes and numpy arrays "
95
+ "can)")
96
+ _pack(arr, out, depth)
97
+
98
+
99
+ def _pack_int(n: int, out: list) -> None:
100
+ if 0 <= n <= 0x7F:
101
+ out.append(bytes((n,)))
102
+ elif -32 <= n < 0:
103
+ out.append(struct.pack(">b", n))
104
+ elif n > 0:
105
+ for code, fmt, top in ((0xCC, ">BB", 0xFF), (0xCD, ">BH", 0xFFFF), (0xCE, ">BI", 0xFFFFFFFF),
106
+ (0xCF, ">BQ", 0xFFFFFFFFFFFFFFFF)):
107
+ if n <= top:
108
+ out.append(struct.pack(fmt, code, n))
109
+ return
110
+ raise MsgpackError(f"an int past msgpack's 64 bits: {n}")
111
+ else:
112
+ for code, fmt, low in ((0xD0, ">Bb", -0x80), (0xD1, ">Bh", -0x8000), (0xD2, ">Bi", -0x80000000),
113
+ (0xD3, ">Bq", -0x8000000000000000)):
114
+ if n >= low:
115
+ out.append(struct.pack(fmt, code, n))
116
+ return
117
+ raise MsgpackError(f"an int past msgpack's 64 bits: {n}")
118
+
119
+
120
+ def _pack_head(n: int, out: list, *, fix: tuple | None, sizes: tuple, what: str) -> None:
121
+ if fix is not None and n <= fix[1]:
122
+ out.append(bytes((fix[0] | n,)))
123
+ return
124
+ for code, fmt, top in sizes:
125
+ if n <= top:
126
+ out.append(struct.pack(fmt, code, n))
127
+ return
128
+ raise MsgpackError(f"a {what} of {n}: past msgpack's 32-bit lengths")
129
+
130
+
131
+ def _numpy_map(obj: Any) -> dict | None:
132
+ """A numpy array or scalar as the map msgpack-numpy writes it, or None for anything else (numpy not imported by
133
+ whoever made `obj` means it holds none)."""
134
+ import sys
135
+
136
+ np = sys.modules.get("numpy")
137
+ if np is None:
138
+ return None
139
+ if isinstance(obj, np.ndarray):
140
+ _readable_dtype(obj.dtype)
141
+ return {b"nd": True, b"type": obj.dtype.str, b"kind": b"", b"shape": list(obj.shape),
142
+ b"data": np.ascontiguousarray(obj).tobytes()}
143
+ if isinstance(obj, (np.bool_, np.number)):
144
+ _readable_dtype(obj.dtype)
145
+ return {b"nd": False, b"type": obj.dtype.str, b"data": np.asarray(obj).tobytes()}
146
+ return None
147
+
148
+
149
+ def _readable_dtype(dtype) -> None:
150
+ if dtype.hasobject or dtype.kind in ("O", "V"):
151
+ raise MsgpackError(f"a numpy array of dtype {dtype} is not carried: only plain numeric, bool and string dtypes "
152
+ "are")
153
+
154
+
155
+
156
+ def unpack(data: bytes) -> Any:
157
+ """The one msgpack value `data` holds, numpy arrays (msgpack-numpy's or openpi's layout) back as read-only arrays.
158
+ MsgpackError: truncated, more than one value, an extension type, nested past MAX_DEPTH, a length past the body, or
159
+ an array whose dtype holds objects."""
160
+ view = memoryview(bytes(data)) if not isinstance(data, bytes) else memoryview(data)
161
+ value, at = _Reader(view).read(0, 0)
162
+ if at != len(view):
163
+ raise MsgpackError(f"{len(view) - at} bytes follow the msgpack value")
164
+ return value
165
+
166
+
167
+ class _Reader:
168
+ __slots__ = ("buf", "size")
169
+
170
+ def __init__(self, buf: memoryview) -> None:
171
+ self.buf, self.size = buf, len(buf)
172
+
173
+ def _take(self, at: int, n: int) -> int:
174
+ if n < 0 or at + n > self.size:
175
+ raise MsgpackError(f"the body ends inside a value: {n} bytes asked for at {at} of {self.size}")
176
+ return at + n
177
+
178
+ def _unpack(self, fmt: str, at: int) -> tuple:
179
+ end = self._take(at, struct.calcsize(fmt))
180
+ return struct.unpack_from(fmt, self.buf, at), end
181
+
182
+ def read(self, at: int, depth: int) -> tuple[Any, int]:
183
+ if depth > MAX_DEPTH:
184
+ raise MsgpackError(f"nested deeper than {MAX_DEPTH} levels")
185
+ self._take(at, 1)
186
+ code = self.buf[at]
187
+ at += 1
188
+ if code <= 0x7F:
189
+ return code, at
190
+ if code >= 0xE0:
191
+ return code - 0x100, at
192
+ if 0xA0 <= code <= 0xBF:
193
+ return self._str(at, code & 0x1F)
194
+ if 0x90 <= code <= 0x9F:
195
+ return self._list(at, code & 0x0F, depth)
196
+ if 0x80 <= code <= 0x8F:
197
+ return self._map(at, code & 0x0F, depth)
198
+ if code == 0xC0:
199
+ return None, at
200
+ if code == 0xC2:
201
+ return False, at
202
+ if code == 0xC3:
203
+ return True, at
204
+ fixed = _FIXED.get(code)
205
+ if fixed is not None:
206
+ (value,), end = self._unpack(fixed, at)
207
+ return value, end
208
+ sized = _SIZED.get(code)
209
+ if sized is not None:
210
+ kind, fmt = sized
211
+ (n,), at = self._unpack(fmt, at)
212
+ if kind == "str":
213
+ return self._str(at, n)
214
+ if kind == "bin":
215
+ end = self._take(at, n)
216
+ return bytes(self.buf[at:end]), end
217
+ if kind == "list":
218
+ return self._list(at, n, depth)
219
+ return self._map(at, n, depth)
220
+ if code in _EXT or code == 0xC1:
221
+ raise MsgpackError(f"msgpack type 0x{code:02x} is not read here (extension types and the unused code)")
222
+ raise MsgpackError(f"not a msgpack type: 0x{code:02x}")
223
+
224
+ def _str(self, at: int, n: int) -> tuple[str, int]:
225
+ end = self._take(at, n)
226
+ try:
227
+ return str(self.buf[at:end], "utf-8"), end
228
+ except UnicodeDecodeError:
229
+ raise MsgpackError("a string that is not UTF-8") from None
230
+
231
+ def _list(self, at: int, n: int, depth: int) -> tuple[list, int]:
232
+ if n > self.size - at:
233
+ raise MsgpackError(f"a list of {n} items where {self.size - at} bytes are left")
234
+ out = []
235
+ for _ in range(n):
236
+ value, at = self.read(at, depth + 1)
237
+ out.append(value)
238
+ return out, at
239
+
240
+ def _map(self, at: int, n: int, depth: int) -> tuple[Any, int]:
241
+ if 2 * n > self.size - at:
242
+ raise MsgpackError(f"a map of {n} entries where {self.size - at} bytes are left")
243
+ out: dict = {}
244
+ for _ in range(n):
245
+ key, at = self.read(at, depth + 1)
246
+ value, at = self.read(at, depth + 1)
247
+ try:
248
+ out[key] = value
249
+ except TypeError:
250
+ raise MsgpackError(f"a map key that cannot be a dict key: {type(key).__name__}") from None
251
+ return _array_of(out), at
252
+
253
+
254
+ _FIXED = {0xCA: ">f", 0xCB: ">d", 0xCC: ">B", 0xCD: ">H", 0xCE: ">I", 0xCF: ">Q", 0xD0: ">b", 0xD1: ">h", 0xD2: ">i",
255
+ 0xD3: ">q"}
256
+ _SIZED = {0xD9: ("str", ">B"), 0xDA: ("str", ">H"), 0xDB: ("str", ">I"), 0xC4: ("bin", ">B"), 0xC5: ("bin", ">H"),
257
+ 0xC6: ("bin", ">I"), 0xDC: ("list", ">H"), 0xDD: ("list", ">I"), 0xDE: ("map", ">H"), 0xDF: ("map", ">I")}
258
+ _EXT = {0xC7, 0xC8, 0xC9, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8}
259
+
260
+
261
+ def _field(m: dict, name: str):
262
+ """A field of an array's map, its key as msgpack-numpy writes it (bytes) or as a packer without bin types does."""
263
+ return m[name.encode()] if name.encode() in m else m.get(name)
264
+
265
+
266
+ def _text(value) -> str:
267
+ return value.decode("ascii", "replace") if isinstance(value, bytes) else str(value)
268
+
269
+
270
+ def _array_of(m: dict) -> Any:
271
+ """`m` as the numpy array or scalar it stands for when it has every field of one in msgpack-numpy's or openpi's
272
+ layout, else `m` as it is - a dict of the user's that happens to hold a key "nd" stays a dict."""
273
+ nd, openpi, generic = _field(m, "nd"), _field(m, "__ndarray__"), _field(m, "__npgeneric__")
274
+ has = lambda *names: all(n.encode() in m or n in m for n in names)
275
+ if nd is True and has("type", "shape", "data"):
276
+ _dtype(_field(m, "type"))
277
+ if _field(m, "kind") not in (None, b"", ""):
278
+ raise MsgpackError("a structured numpy array is not carried: only plain numeric, bool and string dtypes "
279
+ "are")
280
+ return _array(_field(m, "type"), _field(m, "shape"), _field(m, "data"))
281
+ if openpi is True and has("dtype", "shape", "data"):
282
+ return _array(_field(m, "dtype"), _field(m, "shape"), _field(m, "data"))
283
+ if nd is False and has("type", "data"):
284
+ dtype, data = _dtype(_field(m, "type")), _field(m, "data")
285
+ if not isinstance(data, bytes) or len(data) != dtype.itemsize:
286
+ raise MsgpackError(f"a numpy {dtype} scalar whose data is not {dtype.itemsize} bytes")
287
+ return _numpy().frombuffer(data, dtype=dtype, count=1)[0]
288
+ if generic is True and has("dtype", "data"):
289
+ dtype, value = _dtype(_field(m, "dtype")), _field(m, "data")
290
+ if not isinstance(value, (bool, int, float, str, bytes)):
291
+ raise MsgpackError("a numpy scalar's map whose data is not a plain value")
292
+ return dtype.type(value)
293
+ return m
294
+
295
+
296
+ def _array(descr, shape, data):
297
+ dtype = _dtype(descr)
298
+ if not isinstance(shape, list) or not all(isinstance(d, int) and not isinstance(d, bool) and d >= 0
299
+ for d in shape) or not isinstance(data, bytes):
300
+ raise MsgpackError("a numpy array's map without a shape of non-negative ints or its data as bytes")
301
+ count = 1
302
+ for d in shape:
303
+ count *= d
304
+ if len(data) != count * dtype.itemsize:
305
+ raise MsgpackError(f"a numpy array of shape {shape} and dtype {dtype} is {count * dtype.itemsize} bytes; its "
306
+ f"data is {len(data)}")
307
+ return _numpy().frombuffer(data, dtype=dtype, count=count).reshape(shape)
308
+
309
+
310
+ def _numpy():
311
+ try:
312
+ import numpy
313
+ except ImportError:
314
+ raise MsgpackError("this body holds numpy arrays, and numpy is not installed here") from None
315
+ return numpy
316
+
317
+
318
+ def _dtype(descr):
319
+ np = _numpy()
320
+ if not isinstance(descr, (str, bytes)):
321
+ raise MsgpackError("a numpy array's dtype is not a type string: a structured array is not carried, only "
322
+ "plain numeric, bool and string dtypes are")
323
+ try:
324
+ dtype = np.dtype(_text(descr))
325
+ except TypeError:
326
+ raise MsgpackError(f"not a numpy dtype: {_text(descr)!r}") from None
327
+ _readable_dtype(dtype)
328
+ return dtype
@@ -79,5 +79,5 @@
79
79
  ],
80
80
  "title": "ActRequest",
81
81
  "type": "object",
82
- "x-contract-version": "0.5.19"
82
+ "x-contract-version": "0.5.20"
83
83
  }
@@ -89,5 +89,5 @@
89
89
  ],
90
90
  "title": "ActResponse",
91
91
  "type": "object",
92
- "x-contract-version": "0.5.19"
92
+ "x-contract-version": "0.5.20"
93
93
  }
@@ -99,5 +99,5 @@
99
99
  ],
100
100
  "title": "ActionChunk",
101
101
  "type": "object",
102
- "x-contract-version": "0.5.19"
102
+ "x-contract-version": "0.5.20"
103
103
  }
@@ -84,5 +84,5 @@
84
84
  ],
85
85
  "title": "ActionContract",
86
86
  "type": "object",
87
- "x-contract-version": "0.5.19"
87
+ "x-contract-version": "0.5.20"
88
88
  }
@@ -19,5 +19,5 @@
19
19
  ],
20
20
  "title": "ActionStep",
21
21
  "type": "object",
22
- "x-contract-version": "0.5.19"
22
+ "x-contract-version": "0.5.20"
23
23
  }
@@ -17,5 +17,5 @@
17
17
  ],
18
18
  "title": "AdapterPair",
19
19
  "type": "object",
20
- "x-contract-version": "0.5.19"
20
+ "x-contract-version": "0.5.20"
21
21
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "AddLocal",
25
25
  "type": "object",
26
- "x-contract-version": "0.5.19"
26
+ "x-contract-version": "0.5.20"
27
27
  }
@@ -57,5 +57,5 @@
57
57
  },
58
58
  "title": "Autoscaler",
59
59
  "type": "object",
60
- "x-contract-version": "0.5.19"
60
+ "x-contract-version": "0.5.20"
61
61
  }
@@ -50,5 +50,5 @@
50
50
  ],
51
51
  "title": "BenchmarkConditionSpec",
52
52
  "type": "object",
53
- "x-contract-version": "0.5.19"
53
+ "x-contract-version": "0.5.20"
54
54
  }
@@ -974,5 +974,5 @@
974
974
  ],
975
975
  "title": "BenchmarkRegisterRequest",
976
976
  "type": "object",
977
- "x-contract-version": "0.5.19"
977
+ "x-contract-version": "0.5.20"
978
978
  }
@@ -379,7 +379,7 @@
379
379
  ],
380
380
  "title": "SeqFlags",
381
381
  "type": "integer",
382
- "x-contract-version": "0.5.19",
382
+ "x-contract-version": "0.5.20",
383
383
  "x-flag-names": {
384
384
  "CHECK": 65536,
385
385
  "INFER": 16,
@@ -628,5 +628,5 @@
628
628
  ],
629
629
  "title": "BenchmarkSpec",
630
630
  "type": "object",
631
- "x-contract-version": "0.5.19"
631
+ "x-contract-version": "0.5.20"
632
632
  }
@@ -40,5 +40,5 @@
40
40
  ],
41
41
  "title": "BenchmarkStatusResponse",
42
42
  "type": "object",
43
- "x-contract-version": "0.5.19"
43
+ "x-contract-version": "0.5.20"
44
44
  }
@@ -79,5 +79,5 @@
79
79
  ],
80
80
  "title": "BootstrapResponse",
81
81
  "type": "object",
82
- "x-contract-version": "0.5.19"
82
+ "x-contract-version": "0.5.20"
83
83
  }
@@ -72,5 +72,5 @@
72
72
  ],
73
73
  "title": "Camera",
74
74
  "type": "object",
75
- "x-contract-version": "0.5.19"
75
+ "x-contract-version": "0.5.20"
76
76
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "CodeBundle",
25
25
  "type": "object",
26
- "x-contract-version": "0.5.19"
26
+ "x-contract-version": "0.5.20"
27
27
  }
@@ -96,5 +96,5 @@
96
96
  },
97
97
  "title": "Concurrency",
98
98
  "type": "object",
99
- "x-contract-version": "0.5.19"
99
+ "x-contract-version": "0.5.20"
100
100
  }
@@ -55,5 +55,5 @@
55
55
  ],
56
56
  "title": "Conditions",
57
57
  "type": "object",
58
- "x-contract-version": "0.5.19"
58
+ "x-contract-version": "0.5.20"
59
59
  }
@@ -25,5 +25,5 @@
25
25
  ],
26
26
  "title": "ConnectRequest",
27
27
  "type": "object",
28
- "x-contract-version": "0.5.19"
28
+ "x-contract-version": "0.5.20"
29
29
  }
@@ -310,5 +310,5 @@
310
310
  ],
311
311
  "title": "ConnectResponse",
312
312
  "type": "object",
313
- "x-contract-version": "0.5.19"
313
+ "x-contract-version": "0.5.20"
314
314
  }
@@ -18,5 +18,5 @@
18
18
  ],
19
19
  "title": "DeploymentAccepted",
20
20
  "type": "object",
21
- "x-contract-version": "0.5.19"
21
+ "x-contract-version": "0.5.20"
22
22
  }
@@ -499,5 +499,5 @@
499
499
  ],
500
500
  "title": "DeploymentPolicy",
501
501
  "type": "object",
502
- "x-contract-version": "0.5.19"
502
+ "x-contract-version": "0.5.20"
503
503
  }
@@ -1163,5 +1163,5 @@
1163
1163
  ],
1164
1164
  "title": "DeploymentRequest",
1165
1165
  "type": "object",
1166
- "x-contract-version": "0.5.19"
1166
+ "x-contract-version": "0.5.20"
1167
1167
  }
@@ -58,5 +58,5 @@
58
58
  ],
59
59
  "title": "DeploymentStatusResponse",
60
60
  "type": "object",
61
- "x-contract-version": "0.5.19"
61
+ "x-contract-version": "0.5.20"
62
62
  }
@@ -235,5 +235,5 @@
235
235
  ],
236
236
  "title": "Embodiment",
237
237
  "type": "object",
238
- "x-contract-version": "0.5.19"
238
+ "x-contract-version": "0.5.20"
239
239
  }
@@ -94,5 +94,5 @@
94
94
  ],
95
95
  "title": "ErrorBody",
96
96
  "type": "object",
97
- "x-contract-version": "0.5.19"
97
+ "x-contract-version": "0.5.20"
98
98
  }
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "title": "ErrorCode",
24
24
  "type": "string",
25
- "x-contract-version": "0.5.19",
25
+ "x-contract-version": "0.5.20",
26
26
  "x-errors": {
27
27
  "budget_exhausted": {
28
28
  "exit_code": 6,
@@ -60,5 +60,5 @@
60
60
  ],
61
61
  "title": "Estimate",
62
62
  "type": "object",
63
- "x-contract-version": "0.5.19"
63
+ "x-contract-version": "0.5.20"
64
64
  }
@@ -240,5 +240,5 @@
240
240
  ],
241
241
  "title": "EvalDryRunResponse",
242
242
  "type": "object",
243
- "x-contract-version": "0.5.19"
243
+ "x-contract-version": "0.5.20"
244
244
  }
@@ -432,5 +432,5 @@
432
432
  ],
433
433
  "title": "EvalReport",
434
434
  "type": "object",
435
- "x-contract-version": "0.5.19"
435
+ "x-contract-version": "0.5.20"
436
436
  }
@@ -318,5 +318,5 @@
318
318
  },
319
319
  "title": "EvalRequest",
320
320
  "type": "object",
321
- "x-contract-version": "0.5.19"
321
+ "x-contract-version": "0.5.20"
322
322
  }
@@ -153,5 +153,5 @@
153
153
  ],
154
154
  "title": "EvalResponse",
155
155
  "type": "object",
156
- "x-contract-version": "0.5.19"
156
+ "x-contract-version": "0.5.20"
157
157
  }