sequence-base 0.4.24__tar.gz → 0.4.25__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 (109) hide show
  1. {sequence_base-0.4.24 → sequence_base-0.4.25}/PKG-INFO +2 -1
  2. {sequence_base-0.4.24 → sequence_base-0.4.25}/pyproject.toml +2 -2
  3. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/__init__.py +2 -1
  4. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/constants/version.py +2 -1
  5. sequence_base-0.4.25/sequence_base/construct.py +103 -0
  6. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/__init__.py +2 -1
  7. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/benchmarks.py +6 -0
  8. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/deployments.py +6 -0
  9. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/policy.py +36 -2
  10. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ActRequest.json +1 -1
  11. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ActResponse.json +1 -1
  12. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ActionChunk.json +1 -1
  13. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ActionContract.json +1 -1
  14. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ActionStep.json +1 -1
  15. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/AdapterPair.json +1 -1
  16. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/AddLocal.json +1 -1
  17. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Autoscaler.json +1 -1
  18. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/BenchmarkConditionSpec.json +1 -1
  19. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/BenchmarkRegisterRequest.json +13 -1
  20. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/BenchmarkSpec.json +2 -2
  21. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/BenchmarkStatusResponse.json +1 -1
  22. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/BootstrapResponse.json +1 -1
  23. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Camera.json +1 -1
  24. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/CodeBundle.json +1 -1
  25. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Concurrency.json +1 -1
  26. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Conditions.json +1 -1
  27. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ConnectRequest.json +1 -1
  28. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ConnectResponse.json +1 -1
  29. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/DeploymentAccepted.json +1 -1
  30. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/DeploymentPolicy.json +1 -1
  31. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/DeploymentRequest.json +13 -1
  32. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/DeploymentStatusResponse.json +1 -1
  33. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Embodiment.json +1 -1
  34. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ErrorBody.json +1 -1
  35. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ErrorCodes.json +1 -1
  36. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Estimate.json +1 -1
  37. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/EvalDryRunResponse.json +1 -1
  38. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/EvalReport.json +1 -1
  39. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/EvalRequest.json +1 -1
  40. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/EvalResponse.json +1 -1
  41. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageFrame.json +1 -1
  42. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageSpec.json +1 -1
  43. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageStepAddLocal.json +1 -1
  44. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageStepApt.json +1 -1
  45. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageStepEnv.json +1 -1
  46. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageStepRun.json +1 -1
  47. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageStepTemplateFiles.json +1 -1
  48. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ImageStepUvPip.json +1 -1
  49. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/InferParam.json +1 -1
  50. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Lease.json +1 -1
  51. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/MetricAgg.json +1 -1
  52. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Observation.json +1 -1
  53. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ObservationContract.json +1 -1
  54. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/PolicyRegistration.json +48 -3
  55. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/PolicySpec.json +1 -1
  56. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Proprioception.json +1 -1
  57. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/RenderSpec.json +1 -1
  58. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/ReplaySpec.json +1 -1
  59. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Resources.json +1 -1
  60. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/RolloutResult.json +1 -1
  61. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/SecretCreateRequest.json +1 -1
  62. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/SecretInfo.json +1 -1
  63. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/SecretRef.json +1 -1
  64. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/SeqFlags.json +1 -1
  65. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Step.json +1 -1
  66. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/TaskAgg.json +1 -1
  67. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/TemplateFiles.json +1 -1
  68. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Timeouts.json +1 -1
  69. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/UploadTarget.json +1 -1
  70. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/Variant.json +1 -1
  71. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/VolumeFile.json +1 -1
  72. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/VolumeInfo.json +1 -1
  73. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/VolumeMount.json +1 -1
  74. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/VolumeRef.json +1 -1
  75. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/VolumeUploadRequest.json +1 -1
  76. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/VolumeUploadResponse.json +1 -1
  77. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schemas/WarmingError.json +1 -1
  78. {sequence_base-0.4.24 → sequence_base-0.4.25}/.gitignore +0 -0
  79. {sequence_base-0.4.24 → sequence_base-0.4.25}/README.md +0 -0
  80. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/auth.py +0 -0
  81. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/codec/__init__.py +0 -0
  82. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/codec/image.py +0 -0
  83. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/constants/__init__.py +0 -0
  84. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/constants/cards.py +0 -0
  85. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/constants/headers.py +0 -0
  86. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/constants/limits.py +0 -0
  87. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/accounts.py +0 -0
  88. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/act.py +0 -0
  89. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/adapters.py +0 -0
  90. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/connect.py +0 -0
  91. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/errors.py +0 -0
  92. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/eval.py +0 -0
  93. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/flags.py +0 -0
  94. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/io.py +0 -0
  95. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/templates.py +0 -0
  96. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/volumes.py +0 -0
  97. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/contract/wire.py +0 -0
  98. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/errors/__init__.py +0 -0
  99. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/errors/transport.py +0 -0
  100. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/msgpack_io.py +0 -0
  101. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/obs/__init__.py +0 -0
  102. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/obs/log.py +0 -0
  103. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/obs/rid.py +0 -0
  104. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/presets/__init__.py +0 -0
  105. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/presets/frames.py +0 -0
  106. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/presets/robot_arm.py +0 -0
  107. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/schema_export.py +0 -0
  108. {sequence_base-0.4.24 → sequence_base-0.4.25}/sequence_base/telemetry/__init__.py +0 -0
  109. {sequence_base-0.4.24 → sequence_base-0.4.25}/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.24
3
+ Version: 0.4.25
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
@@ -12,3 +12,4 @@ Provides-Extra: test
12
12
  Requires-Dist: hypothesis>=6; extra == 'test'
13
13
  Requires-Dist: jsonschema>=4; extra == 'test'
14
14
  Requires-Dist: pytest; extra == 'test'
15
+ Requires-Dist: pyyaml; extra == 'test'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sequence-base"
3
- version = "0.4.24"
3
+ version = "0.4.25"
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"]
@@ -10,7 +10,7 @@ Changelog = "https://generalsequences.com/docs/changelog/"
10
10
 
11
11
  [project.optional-dependencies]
12
12
  codec = ["pillow>=10", "numpy>=1.26"]
13
- test = ["pytest", "jsonschema>=4", "hypothesis>=6"]
13
+ test = ["pytest", "jsonschema>=4", "hypothesis>=6", "pyyaml"]
14
14
 
15
15
  [build-system]
16
16
  requires = ["hatchling"]
@@ -76,6 +76,7 @@ from sequence_base.contract import (
76
76
  Lease,
77
77
  MetricAgg,
78
78
  Observation,
79
+ PolicyConstructor,
79
80
  PolicyRegistration,
80
81
  PolicySpec,
81
82
  Proprioception,
@@ -132,7 +133,7 @@ __all__ = [
132
133
  "SeqFlags", "ImageStepUvPip", "ImageStepApt", "ImageStepEnv", "ImageStepRun", "AddLocal", "ImageStepAddLocal",
133
134
  "FROZEN_PATH", "TemplateFiles", "ImageStepTemplateFiles", "ImageStep", "ImageSpec",
134
135
  "VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract", "Embodiment",
135
- "PolicySpec", "PolicyRegistration",
136
+ "PolicySpec", "PolicyRegistration", "PolicyConstructor",
136
137
 
137
138
  "MAX_CODE_BUNDLE_BYTES", "CodeBundle",
138
139
  "Resources", "Autoscaler", "Timeouts", "DeploymentPolicy", "InferParam", "DeploymentRequest",
@@ -4,7 +4,8 @@
4
4
 
5
5
 
6
6
 
7
- CONTRACT_VERSION = "0.5.21"
7
+ CONTRACT_VERSION = "0.5.22"
8
+
8
9
 
9
10
 
10
11
 
@@ -0,0 +1,103 @@
1
+ """
2
+ How a policy class that names its own methods is built (PolicyRegistration.constructor): its constructor - or the
3
+ factory it names - called with the arguments its decorator was given, once two forms in them are filled in.
4
+
5
+ In one sentence: a value {"$config": path, "$set": {...}} becomes the YAML or JSON file at `path` - from the folder of
6
+ the class's file - read where the policy runs, with `$set`'s keys laid over its top level → in every string,
7
+ "{weights}" becomes the weights directory and "{weights.<part>}" a named part's → `cls.<make>(*args, **kwargs)`, or
8
+ `cls(*args, **kwargs)` without a factory.
9
+
10
+ WHY a config file is read where the policy runs: it is part of the project (XPolicyLab's deploy.yml beside its
11
+ model.py) and goes up with it, so one copy - the one the policy runs with - is read, and "{weights}" in it means the
12
+ worker's directory.
13
+
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import os
19
+ import re
20
+ from typing import Any
21
+
22
+ __all__ = ["CONFIG_KEY", "SET_KEY", "ConstructError", "build", "config", "expand", "is_config", "read_config"]
23
+
24
+ CONFIG_KEY, SET_KEY = "$config", "$set"
25
+ _WEIGHTS = re.compile(r"\{weights(?:\.([A-Za-z_][A-Za-z0-9_-]*))?\}")
26
+
27
+
28
+ class ConstructError(ValueError):
29
+ """Arguments that cannot be filled in: a config file missing, unreadable or of another kind, or a weights
30
+ placeholder with no weights - or no such part - to fill it."""
31
+
32
+
33
+ def config(path: str, **overrides: Any) -> dict:
34
+ """A config file's contents with `overrides` laid over its top level, as the worker reads it (`seq.config`)."""
35
+ if not isinstance(path, str) or not path:
36
+ raise ConstructError("a config file is a path, from the folder of the class's file")
37
+ if os.path.isabs(path):
38
+ raise ConstructError(f"{path}: give a config file's path from the folder of the class's file - the policy runs "
39
+ "it where the upload puts it")
40
+ return {CONFIG_KEY: path, SET_KEY: dict(overrides)}
41
+
42
+
43
+ def is_config(value: Any) -> bool:
44
+ return isinstance(value, dict) and set(value) == {CONFIG_KEY, SET_KEY} and isinstance(value[CONFIG_KEY], str)
45
+
46
+
47
+ def read_config(path: str) -> Any:
48
+ """The YAML (.yml, .yaml) or JSON (.json) file at `path`."""
49
+ kind = os.path.splitext(path)[1].lower()
50
+ if kind not in (".json", ".yml", ".yaml"):
51
+ raise ConstructError(f"{path}: a config file is .json, .yml or .yaml")
52
+ if not os.path.isfile(path):
53
+ raise ConstructError(f"{path}: no such config file")
54
+ with open(path, encoding="utf-8") as f:
55
+ if kind == ".json":
56
+ return json.load(f)
57
+ try:
58
+ import yaml
59
+ except ImportError:
60
+ raise ConstructError(f"{path}: reading YAML needs pyyaml") from None
61
+ return yaml.safe_load(f)
62
+
63
+
64
+ def expand(value: Any, *, base_dir: str, weights: Any) -> Any:
65
+ """`value` with its config files read (from `base_dir`) and its weights placeholders filled from `weights` - the
66
+ weights directory, or {part: directory} for named parts, or None for a policy without weights."""
67
+ if is_config(value):
68
+ loaded = read_config(os.path.join(base_dir, value[CONFIG_KEY]))
69
+ if value[SET_KEY] and not isinstance(loaded, dict):
70
+ raise ConstructError(f"{value[CONFIG_KEY]} holds a {type(loaded).__name__}, which has no keys to set")
71
+ merged = {**loaded, **value[SET_KEY]} if isinstance(loaded, dict) else loaded
72
+ return expand(merged, base_dir=base_dir, weights=weights)
73
+ if isinstance(value, dict):
74
+ return {k: expand(v, base_dir=base_dir, weights=weights) for k, v in value.items()}
75
+ if isinstance(value, (list, tuple)):
76
+ return [expand(v, base_dir=base_dir, weights=weights) for v in value]
77
+ if isinstance(value, str):
78
+ return _WEIGHTS.sub(lambda m: _weights_of(m.group(1), weights), value)
79
+ return value
80
+
81
+
82
+ def _weights_of(part: str | None, weights: Any) -> str:
83
+ if weights is None:
84
+ raise ConstructError("{weights} names the weights directory, and this policy declares no weights=")
85
+ if isinstance(weights, dict):
86
+ if part is None:
87
+ raise ConstructError(f"its weights come in named parts ({', '.join(sorted(weights))}): name one, "
88
+ f"{{weights.<part>}}")
89
+ if part not in weights:
90
+ raise ConstructError(f"{{weights.{part}}}: its weights have no part {part!r} "
91
+ f"({', '.join(sorted(weights))})")
92
+ return str(weights[part])
93
+ if part is not None:
94
+ raise ConstructError(f"{{weights.{part}}} names a part, and its weights come whole: {{weights}}")
95
+ return str(weights)
96
+
97
+
98
+ def build(cls: type, constructor: Any, *, base_dir: str, weights: Any) -> Any:
99
+ """The instance `constructor` (a PolicyConstructor) makes of `cls`: `cls.<make>(*args, **kwargs)` or `cls(...)`."""
100
+ args = expand(list(constructor.args), base_dir=base_dir, weights=weights)
101
+ kwargs = expand(dict(constructor.kwargs), base_dir=base_dir, weights=weights)
102
+ make = getattr(cls, constructor.make) if constructor.make else cls
103
+ return make(*args, **kwargs)
@@ -34,6 +34,7 @@ from sequence_base.contract.policy import (
34
34
  FROZEN_PATH,
35
35
  TemplateFiles,
36
36
  ImageStepTemplateFiles,
37
+ PolicyConstructor,
37
38
  PolicyRegistration,
38
39
  PolicySpec,
39
40
  VolumeMount,
@@ -121,7 +122,7 @@ __all__ = [
121
122
  "ImageStepUvPip", "ImageStepApt", "ImageStepEnv", "ImageStepRun", "AddLocal", "ImageStepAddLocal",
122
123
  "TemplateFiles", "ImageStepTemplateFiles", "FROZEN_PATH", "ImageStep", "ImageSpec",
123
124
  "VolumeMount", "VolumeRef", "Concurrency", "ActionContract", "Camera", "ObservationContract", "Embodiment",
124
- "PolicySpec", "PolicyRegistration",
125
+ "PolicySpec", "PolicyRegistration", "PolicyConstructor",
125
126
 
126
127
  "MAX_CODE_BUNDLE_BYTES", "CodeBundle",
127
128
  "Resources", "Autoscaler", "Timeouts", "DeploymentPolicy", "InferParam", "DeploymentRequest",
@@ -210,6 +210,12 @@ class BenchmarkRegisterRequest(BaseModel):
210
210
  action_contract: ActionContract | None = None
211
211
 
212
212
 
213
+
214
+
215
+
216
+ freeze: bool | None = None
217
+
218
+
213
219
  secrets: list[SecretRef] = Field(default_factory=list)
214
220
 
215
221
 
@@ -296,6 +296,12 @@ class DeploymentRequest(BaseModel):
296
296
  weights_name: str | None = None
297
297
  extra_weights: dict[str, VolumeMount] | None = None
298
298
 
299
+
300
+
301
+
302
+
303
+ freeze: bool | None = None
304
+
299
305
  @field_validator("name")
300
306
  @classmethod
301
307
  def _name_is_a_slug(cls, v: str) -> str:
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  import re
12
12
 
13
- from typing import Literal
13
+ from typing import Any, Literal
14
14
 
15
15
  from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
16
16
 
@@ -357,10 +357,31 @@ def check_weights_parts(weights_name: str | None, extra: dict) -> None:
357
357
  raise ValueError(f"at most {MAX_WEIGHTS_PARTS} weights parts")
358
358
 
359
359
 
360
+ class PolicyConstructor(BaseModel):
361
+ """How the worker builds a policy class that names its own methods (`@seq.policy(infer="get_action", ...)`): its
362
+ own constructor, or the factory it names (`make`, e.g. LeRobot's `from_pretrained`), called with `args` and
363
+ `kwargs` where `@seq.load` would run - the replica's cold start, the weights on disk. The values are the user's own,
364
+ as JSON carries them, but for two forms the worker fills in first (sequence_base.construct.expand): a config file's
365
+ contents, `{"$config": <its path from the class's file>, "$set": {<keys laid over it>}}`, YAML or JSON, and in any
366
+ string `"{weights}"` (the weights directory) or `"{weights.<part>}"` (a named part's).
367
+ """
368
+
369
+ model_config = ConfigDict(extra="forbid")
370
+
371
+ make: str | None = Field(default=None, pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
372
+ description="a classmethod or staticmethod that returns the instance; None: the class")
373
+ args: list[Any] = Field(default_factory=list, description="positional arguments, in order")
374
+ kwargs: dict[str, Any] = Field(default_factory=dict, description="keyword arguments")
375
+
376
+
360
377
  class PolicyRegistration(BaseModel):
361
378
  """What the harness loader introspects: the spec, the SeqFlags→method-name bindings, and the
362
379
  `handler_ref` it importlib-loads the policy class from. From one of these the loader recovers which
363
- method is which lifecycle entrypoint (load / infer / on_episode / plan …)."""
380
+ method is which lifecycle entrypoint (load / infer / on_episode / plan …).
381
+
382
+ A class that names its own methods (`constructor` set) is built by its constructor or factory, so it binds no LOAD,
383
+ and its bindings name its own methods: INFER (what answers an act), and as declared OBSERVE (each observation an
384
+ act carries, before INFER is called with none), RESET (an episode's first act) and ON_EPISODE (its end)."""
364
385
 
365
386
  model_config = ConfigDict(extra="forbid")
366
387
 
@@ -374,3 +395,16 @@ class PolicyRegistration(BaseModel):
374
395
  plan_every_s: float | None = Field(
375
396
  default=None, gt=0, description="Seconds between @seq.plan calls; set iff a PLAN binding exists"
376
397
  )
398
+
399
+ constructor: PolicyConstructor | None = None
400
+
401
+ @model_validator(mode="after")
402
+ def _built_by_its_constructor(self) -> "PolicyRegistration":
403
+ if self.constructor is not None:
404
+ if SeqFlags.LOAD in self.bindings:
405
+ raise ValueError("a policy built by its constructor (constructor) has no @seq.load: its constructor is "
406
+ "its load")
407
+ if SeqFlags.INFER not in self.bindings:
408
+ raise ValueError("a policy built by its constructor (constructor) names the method that answers an act "
409
+ "(an INFER binding)")
410
+ return self
@@ -79,5 +79,5 @@
79
79
  ],
80
80
  "title": "ActRequest",
81
81
  "type": "object",
82
- "x-contract-version": "0.5.21"
82
+ "x-contract-version": "0.5.22"
83
83
  }
@@ -89,5 +89,5 @@
89
89
  ],
90
90
  "title": "ActResponse",
91
91
  "type": "object",
92
- "x-contract-version": "0.5.21"
92
+ "x-contract-version": "0.5.22"
93
93
  }
@@ -99,5 +99,5 @@
99
99
  ],
100
100
  "title": "ActionChunk",
101
101
  "type": "object",
102
- "x-contract-version": "0.5.21"
102
+ "x-contract-version": "0.5.22"
103
103
  }
@@ -84,5 +84,5 @@
84
84
  ],
85
85
  "title": "ActionContract",
86
86
  "type": "object",
87
- "x-contract-version": "0.5.21"
87
+ "x-contract-version": "0.5.22"
88
88
  }
@@ -19,5 +19,5 @@
19
19
  ],
20
20
  "title": "ActionStep",
21
21
  "type": "object",
22
- "x-contract-version": "0.5.21"
22
+ "x-contract-version": "0.5.22"
23
23
  }
@@ -17,5 +17,5 @@
17
17
  ],
18
18
  "title": "AdapterPair",
19
19
  "type": "object",
20
- "x-contract-version": "0.5.21"
20
+ "x-contract-version": "0.5.22"
21
21
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "AddLocal",
25
25
  "type": "object",
26
- "x-contract-version": "0.5.21"
26
+ "x-contract-version": "0.5.22"
27
27
  }
@@ -57,5 +57,5 @@
57
57
  },
58
58
  "title": "Autoscaler",
59
59
  "type": "object",
60
- "x-contract-version": "0.5.21"
60
+ "x-contract-version": "0.5.22"
61
61
  }
@@ -50,5 +50,5 @@
50
50
  ],
51
51
  "title": "BenchmarkConditionSpec",
52
52
  "type": "object",
53
- "x-contract-version": "0.5.21"
53
+ "x-contract-version": "0.5.22"
54
54
  }
@@ -809,6 +809,18 @@
809
809
  "default": null,
810
810
  "title": "Envs"
811
811
  },
812
+ "freeze": {
813
+ "anyOf": [
814
+ {
815
+ "type": "boolean"
816
+ },
817
+ {
818
+ "type": "null"
819
+ }
820
+ ],
821
+ "default": null,
822
+ "title": "Freeze"
823
+ },
812
824
  "gpu": {
813
825
  "anyOf": [
814
826
  {
@@ -974,5 +986,5 @@
974
986
  ],
975
987
  "title": "BenchmarkRegisterRequest",
976
988
  "type": "object",
977
- "x-contract-version": "0.5.21"
989
+ "x-contract-version": "0.5.22"
978
990
  }
@@ -379,7 +379,7 @@
379
379
  ],
380
380
  "title": "SeqFlags",
381
381
  "type": "integer",
382
- "x-contract-version": "0.5.21",
382
+ "x-contract-version": "0.5.22",
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.21"
631
+ "x-contract-version": "0.5.22"
632
632
  }
@@ -40,5 +40,5 @@
40
40
  ],
41
41
  "title": "BenchmarkStatusResponse",
42
42
  "type": "object",
43
- "x-contract-version": "0.5.21"
43
+ "x-contract-version": "0.5.22"
44
44
  }
@@ -79,5 +79,5 @@
79
79
  ],
80
80
  "title": "BootstrapResponse",
81
81
  "type": "object",
82
- "x-contract-version": "0.5.21"
82
+ "x-contract-version": "0.5.22"
83
83
  }
@@ -72,5 +72,5 @@
72
72
  ],
73
73
  "title": "Camera",
74
74
  "type": "object",
75
- "x-contract-version": "0.5.21"
75
+ "x-contract-version": "0.5.22"
76
76
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "CodeBundle",
25
25
  "type": "object",
26
- "x-contract-version": "0.5.21"
26
+ "x-contract-version": "0.5.22"
27
27
  }
@@ -96,5 +96,5 @@
96
96
  },
97
97
  "title": "Concurrency",
98
98
  "type": "object",
99
- "x-contract-version": "0.5.21"
99
+ "x-contract-version": "0.5.22"
100
100
  }
@@ -55,5 +55,5 @@
55
55
  ],
56
56
  "title": "Conditions",
57
57
  "type": "object",
58
- "x-contract-version": "0.5.21"
58
+ "x-contract-version": "0.5.22"
59
59
  }
@@ -25,5 +25,5 @@
25
25
  ],
26
26
  "title": "ConnectRequest",
27
27
  "type": "object",
28
- "x-contract-version": "0.5.21"
28
+ "x-contract-version": "0.5.22"
29
29
  }
@@ -310,5 +310,5 @@
310
310
  ],
311
311
  "title": "ConnectResponse",
312
312
  "type": "object",
313
- "x-contract-version": "0.5.21"
313
+ "x-contract-version": "0.5.22"
314
314
  }
@@ -18,5 +18,5 @@
18
18
  ],
19
19
  "title": "DeploymentAccepted",
20
20
  "type": "object",
21
- "x-contract-version": "0.5.21"
21
+ "x-contract-version": "0.5.22"
22
22
  }
@@ -531,5 +531,5 @@
531
531
  ],
532
532
  "title": "DeploymentPolicy",
533
533
  "type": "object",
534
- "x-contract-version": "0.5.21"
534
+ "x-contract-version": "0.5.22"
535
535
  }
@@ -1128,6 +1128,18 @@
1128
1128
  "default": null,
1129
1129
  "title": "Extra Weights"
1130
1130
  },
1131
+ "freeze": {
1132
+ "anyOf": [
1133
+ {
1134
+ "type": "boolean"
1135
+ },
1136
+ {
1137
+ "type": "null"
1138
+ }
1139
+ ],
1140
+ "default": null,
1141
+ "title": "Freeze"
1142
+ },
1131
1143
  "image": {
1132
1144
  "$ref": "#/$defs/ImageSpec"
1133
1145
  },
@@ -1195,5 +1207,5 @@
1195
1207
  ],
1196
1208
  "title": "DeploymentRequest",
1197
1209
  "type": "object",
1198
- "x-contract-version": "0.5.21"
1210
+ "x-contract-version": "0.5.22"
1199
1211
  }
@@ -58,5 +58,5 @@
58
58
  ],
59
59
  "title": "DeploymentStatusResponse",
60
60
  "type": "object",
61
- "x-contract-version": "0.5.21"
61
+ "x-contract-version": "0.5.22"
62
62
  }
@@ -235,5 +235,5 @@
235
235
  ],
236
236
  "title": "Embodiment",
237
237
  "type": "object",
238
- "x-contract-version": "0.5.21"
238
+ "x-contract-version": "0.5.22"
239
239
  }
@@ -94,5 +94,5 @@
94
94
  ],
95
95
  "title": "ErrorBody",
96
96
  "type": "object",
97
- "x-contract-version": "0.5.21"
97
+ "x-contract-version": "0.5.22"
98
98
  }
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "title": "ErrorCode",
24
24
  "type": "string",
25
- "x-contract-version": "0.5.21",
25
+ "x-contract-version": "0.5.22",
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.21"
63
+ "x-contract-version": "0.5.22"
64
64
  }
@@ -240,5 +240,5 @@
240
240
  ],
241
241
  "title": "EvalDryRunResponse",
242
242
  "type": "object",
243
- "x-contract-version": "0.5.21"
243
+ "x-contract-version": "0.5.22"
244
244
  }
@@ -432,5 +432,5 @@
432
432
  ],
433
433
  "title": "EvalReport",
434
434
  "type": "object",
435
- "x-contract-version": "0.5.21"
435
+ "x-contract-version": "0.5.22"
436
436
  }
@@ -318,5 +318,5 @@
318
318
  },
319
319
  "title": "EvalRequest",
320
320
  "type": "object",
321
- "x-contract-version": "0.5.21"
321
+ "x-contract-version": "0.5.22"
322
322
  }
@@ -153,5 +153,5 @@
153
153
  ],
154
154
  "title": "EvalResponse",
155
155
  "type": "object",
156
- "x-contract-version": "0.5.21"
156
+ "x-contract-version": "0.5.22"
157
157
  }
@@ -49,5 +49,5 @@
49
49
  ],
50
50
  "title": "ImageFrame",
51
51
  "type": "object",
52
- "x-contract-version": "0.5.21"
52
+ "x-contract-version": "0.5.22"
53
53
  }
@@ -257,5 +257,5 @@
257
257
  },
258
258
  "title": "ImageSpec",
259
259
  "type": "object",
260
- "x-contract-version": "0.5.21"
260
+ "x-contract-version": "0.5.22"
261
261
  }
@@ -38,5 +38,5 @@
38
38
  ],
39
39
  "title": "ImageStepAddLocal",
40
40
  "type": "object",
41
- "x-contract-version": "0.5.21"
41
+ "x-contract-version": "0.5.22"
42
42
  }
@@ -14,5 +14,5 @@
14
14
  ],
15
15
  "title": "ImageStepApt",
16
16
  "type": "object",
17
- "x-contract-version": "0.5.21"
17
+ "x-contract-version": "0.5.22"
18
18
  }
@@ -14,5 +14,5 @@
14
14
  ],
15
15
  "title": "ImageStepEnv",
16
16
  "type": "object",
17
- "x-contract-version": "0.5.21"
17
+ "x-contract-version": "0.5.22"
18
18
  }
@@ -46,5 +46,5 @@
46
46
  ],
47
47
  "title": "ImageStepRun",
48
48
  "type": "object",
49
- "x-contract-version": "0.5.21"
49
+ "x-contract-version": "0.5.22"
50
50
  }
@@ -37,5 +37,5 @@
37
37
  ],
38
38
  "title": "ImageStepTemplateFiles",
39
39
  "type": "object",
40
- "x-contract-version": "0.5.21"
40
+ "x-contract-version": "0.5.22"
41
41
  }
@@ -14,5 +14,5 @@
14
14
  ],
15
15
  "title": "ImageStepUvPip",
16
16
  "type": "object",
17
- "x-contract-version": "0.5.21"
17
+ "x-contract-version": "0.5.22"
18
18
  }
@@ -99,5 +99,5 @@
99
99
  ],
100
100
  "title": "InferParam",
101
101
  "type": "object",
102
- "x-contract-version": "0.5.21"
102
+ "x-contract-version": "0.5.22"
103
103
  }
@@ -24,5 +24,5 @@
24
24
  ],
25
25
  "title": "Lease",
26
26
  "type": "object",
27
- "x-contract-version": "0.5.21"
27
+ "x-contract-version": "0.5.22"
28
28
  }
@@ -51,5 +51,5 @@
51
51
  ],
52
52
  "title": "MetricAgg",
53
53
  "type": "object",
54
- "x-contract-version": "0.5.21"
54
+ "x-contract-version": "0.5.22"
55
55
  }
@@ -169,5 +169,5 @@
169
169
  ],
170
170
  "title": "Observation",
171
171
  "type": "object",
172
- "x-contract-version": "0.5.21"
172
+ "x-contract-version": "0.5.22"
173
173
  }
@@ -120,5 +120,5 @@
120
120
  },
121
121
  "title": "ObservationContract",
122
122
  "type": "object",
123
- "x-contract-version": "0.5.21"
123
+ "x-contract-version": "0.5.22"
124
124
  }
@@ -553,6 +553,40 @@
553
553
  "title": "ObservationContract",
554
554
  "type": "object"
555
555
  },
556
+ "PolicyConstructor": {
557
+ "additionalProperties": false,
558
+ "description": "How the worker builds a policy class that names its own methods (`@seq.policy(infer=\"get_action\", ...)`): its\nown constructor, or the factory it names (`make`, e.g. LeRobot's `from_pretrained`), called with `args` and\n`kwargs` where `@seq.load` would run - the replica's cold start, the weights on disk. The values are the user's own,\nas JSON carries them, but for two forms the worker fills in first (sequence_base.construct.expand): a config file's\ncontents, `{\"$config\": <its path from the class's file>, \"$set\": {<keys laid over it>}}`, YAML or JSON, and in any\nstring `\"{weights}\"` (the weights directory) or `\"{weights.<part>}\"` (a named part's).",
559
+ "properties": {
560
+ "args": {
561
+ "description": "positional arguments, in order",
562
+ "items": {},
563
+ "title": "Args",
564
+ "type": "array"
565
+ },
566
+ "kwargs": {
567
+ "additionalProperties": true,
568
+ "description": "keyword arguments",
569
+ "title": "Kwargs",
570
+ "type": "object"
571
+ },
572
+ "make": {
573
+ "anyOf": [
574
+ {
575
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
576
+ "type": "string"
577
+ },
578
+ {
579
+ "type": "null"
580
+ }
581
+ ],
582
+ "default": null,
583
+ "description": "a classmethod or staticmethod that returns the instance; None: the class",
584
+ "title": "Make"
585
+ }
586
+ },
587
+ "title": "PolicyConstructor",
588
+ "type": "object"
589
+ },
556
590
  "PolicySpec": {
557
591
  "additionalProperties": false,
558
592
  "description": "What `@seq.policy(...)` accrues — a policy's complete infra declaration, losslessly. `action` /\n`observation` / `embodiments` are optional (contract 0.4.14): a policy that declares none defines its I/O in its own\ncode, and the platform passes it through.",
@@ -822,7 +856,7 @@
822
856
  ],
823
857
  "title": "SeqFlags",
824
858
  "type": "integer",
825
- "x-contract-version": "0.5.21",
859
+ "x-contract-version": "0.5.22",
826
860
  "x-flag-names": {
827
861
  "CHECK": 65536,
828
862
  "INFER": 16,
@@ -865,7 +899,7 @@
865
899
  }
866
900
  },
867
901
  "additionalProperties": false,
868
- "description": "What the harness loader introspects: the spec, the SeqFlags→method-name bindings, and the\n`handler_ref` it importlib-loads the policy class from. From one of these the loader recovers which\nmethod is which lifecycle entrypoint (load / infer / on_episode / plan …).",
902
+ "description": "What the harness loader introspects: the spec, the SeqFlags→method-name bindings, and the\n`handler_ref` it importlib-loads the policy class from. From one of these the loader recovers which\nmethod is which lifecycle entrypoint (load / infer / on_episode / plan …).\n\nA class that names its own methods (`constructor` set) is built by its constructor or factory, so it binds no LOAD,\nand its bindings name its own methods: INFER (what answers an act), and as declared OBSERVE (each observation an\nact carries, before INFER is called with none), RESET (an episode's first act) and ON_EPISODE (its end).",
869
903
  "properties": {
870
904
  "bindings": {
871
905
  "additionalProperties": {
@@ -892,6 +926,17 @@
892
926
  "title": "Bindings",
893
927
  "type": "object"
894
928
  },
929
+ "constructor": {
930
+ "anyOf": [
931
+ {
932
+ "$ref": "#/$defs/PolicyConstructor"
933
+ },
934
+ {
935
+ "type": "null"
936
+ }
937
+ ],
938
+ "default": null
939
+ },
895
940
  "handler_ref": {
896
941
  "description": "\"module.path:ClassName\" for importlib load",
897
942
  "title": "Handler Ref",
@@ -922,5 +967,5 @@
922
967
  ],
923
968
  "title": "PolicyRegistration",
924
969
  "type": "object",
925
- "x-contract-version": "0.5.21"
970
+ "x-contract-version": "0.5.22"
926
971
  }
@@ -827,5 +827,5 @@
827
827
  ],
828
828
  "title": "PolicySpec",
829
829
  "type": "object",
830
- "x-contract-version": "0.5.21"
830
+ "x-contract-version": "0.5.22"
831
831
  }
@@ -68,5 +68,5 @@
68
68
  },
69
69
  "title": "Proprioception",
70
70
  "type": "object",
71
- "x-contract-version": "0.5.21"
71
+ "x-contract-version": "0.5.22"
72
72
  }
@@ -36,5 +36,5 @@
36
36
  ],
37
37
  "title": "RenderSpec",
38
38
  "type": "object",
39
- "x-contract-version": "0.5.21"
39
+ "x-contract-version": "0.5.22"
40
40
  }
@@ -52,5 +52,5 @@
52
52
  },
53
53
  "title": "ReplaySpec",
54
54
  "type": "object",
55
- "x-contract-version": "0.5.21"
55
+ "x-contract-version": "0.5.22"
56
56
  }
@@ -86,5 +86,5 @@
86
86
  ],
87
87
  "title": "Resources",
88
88
  "type": "object",
89
- "x-contract-version": "0.5.21"
89
+ "x-contract-version": "0.5.22"
90
90
  }
@@ -55,5 +55,5 @@
55
55
  ],
56
56
  "title": "RolloutResult",
57
57
  "type": "object",
58
- "x-contract-version": "0.5.21"
58
+ "x-contract-version": "0.5.22"
59
59
  }
@@ -21,5 +21,5 @@
21
21
  ],
22
22
  "title": "SecretCreateRequest",
23
23
  "type": "object",
24
- "x-contract-version": "0.5.21"
24
+ "x-contract-version": "0.5.22"
25
25
  }
@@ -40,5 +40,5 @@
40
40
  ],
41
41
  "title": "SecretInfo",
42
42
  "type": "object",
43
- "x-contract-version": "0.5.21"
43
+ "x-contract-version": "0.5.22"
44
44
  }
@@ -12,5 +12,5 @@
12
12
  ],
13
13
  "title": "SecretRef",
14
14
  "type": "object",
15
- "x-contract-version": "0.5.21"
15
+ "x-contract-version": "0.5.22"
16
16
  }
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "title": "SeqFlags",
19
19
  "type": "integer",
20
- "x-contract-version": "0.5.21",
20
+ "x-contract-version": "0.5.22",
21
21
  "x-flag-names": {
22
22
  "CHECK": 65536,
23
23
  "INFER": 16,
@@ -82,5 +82,5 @@
82
82
  ],
83
83
  "title": "Step",
84
84
  "type": "object",
85
- "x-contract-version": "0.5.21"
85
+ "x-contract-version": "0.5.22"
86
86
  }
@@ -22,5 +22,5 @@
22
22
  ],
23
23
  "title": "TaskAgg",
24
24
  "type": "object",
25
- "x-contract-version": "0.5.21"
25
+ "x-contract-version": "0.5.22"
26
26
  }
@@ -22,5 +22,5 @@
22
22
  ],
23
23
  "title": "TemplateFiles",
24
24
  "type": "object",
25
- "x-contract-version": "0.5.21"
25
+ "x-contract-version": "0.5.22"
26
26
  }
@@ -20,5 +20,5 @@
20
20
  ],
21
21
  "title": "Timeouts",
22
22
  "type": "object",
23
- "x-contract-version": "0.5.21"
23
+ "x-contract-version": "0.5.22"
24
24
  }
@@ -24,5 +24,5 @@
24
24
  ],
25
25
  "title": "UploadTarget",
26
26
  "type": "object",
27
- "x-contract-version": "0.5.21"
27
+ "x-contract-version": "0.5.22"
28
28
  }
@@ -20,5 +20,5 @@
20
20
  ],
21
21
  "title": "Variant",
22
22
  "type": "object",
23
- "x-contract-version": "0.5.21"
23
+ "x-contract-version": "0.5.22"
24
24
  }
@@ -25,5 +25,5 @@
25
25
  ],
26
26
  "title": "VolumeFile",
27
27
  "type": "object",
28
- "x-contract-version": "0.5.21"
28
+ "x-contract-version": "0.5.22"
29
29
  }
@@ -68,5 +68,5 @@
68
68
  ],
69
69
  "title": "VolumeInfo",
70
70
  "type": "object",
71
- "x-contract-version": "0.5.21"
71
+ "x-contract-version": "0.5.22"
72
72
  }
@@ -17,5 +17,5 @@
17
17
  ],
18
18
  "title": "VolumeMount",
19
19
  "type": "object",
20
- "x-contract-version": "0.5.21"
20
+ "x-contract-version": "0.5.22"
21
21
  }
@@ -24,5 +24,5 @@
24
24
  ],
25
25
  "title": "VolumeRef",
26
26
  "type": "object",
27
- "x-contract-version": "0.5.21"
27
+ "x-contract-version": "0.5.22"
28
28
  }
@@ -56,5 +56,5 @@
56
56
  ],
57
57
  "title": "VolumeUploadRequest",
58
58
  "type": "object",
59
- "x-contract-version": "0.5.21"
59
+ "x-contract-version": "0.5.22"
60
60
  }
@@ -65,5 +65,5 @@
65
65
  ],
66
66
  "title": "VolumeUploadResponse",
67
67
  "type": "object",
68
- "x-contract-version": "0.5.21"
68
+ "x-contract-version": "0.5.22"
69
69
  }
@@ -86,5 +86,5 @@
86
86
  ],
87
87
  "title": "WarmingError",
88
88
  "type": "object",
89
- "x-contract-version": "0.5.21"
89
+ "x-contract-version": "0.5.22"
90
90
  }
File without changes