sequence-base 0.3.17__tar.gz → 0.3.18__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.3.17 → sequence_base-0.3.18}/PKG-INFO +1 -1
  2. {sequence_base-0.3.17 → sequence_base-0.3.18}/pyproject.toml +1 -1
  3. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/constants/version.py +2 -1
  4. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/deployments.py +27 -7
  5. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/eval.py +65 -2
  6. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/policy.py +23 -4
  7. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ActRequest.json +1 -1
  8. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ActResponse.json +1 -1
  9. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ActionChunk.json +1 -1
  10. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ActionContract.json +1 -1
  11. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ActionStep.json +1 -1
  12. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/AdapterTransform.json +1 -1
  13. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/AddLocal.json +1 -1
  14. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Autoscaler.json +31 -1
  15. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/BenchmarkConditionSpec.json +1 -1
  16. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/BenchmarkRegisterRequest.json +1 -1
  17. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/BenchmarkSpec.json +2 -2
  18. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/BenchmarkStatusResponse.json +1 -1
  19. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/BootstrapResponse.json +1 -1
  20. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Camera.json +1 -1
  21. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ClampInfo.json +1 -1
  22. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/CodeBundle.json +1 -1
  23. sequence_base-0.3.18/sequence_base/schemas/Concurrency.json +65 -0
  24. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Conditions.json +1 -1
  25. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ConnectRequest.json +1 -1
  26. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ConnectResponse.json +1 -1
  27. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/DeploymentAccepted.json +1 -1
  28. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/DeploymentPolicy.json +1 -1
  29. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/DeploymentRequest.json +137 -17
  30. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/DeploymentStatusResponse.json +18 -1
  31. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Embodiment.json +1 -1
  32. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ErrorBody.json +1 -1
  33. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ErrorCodes.json +1 -1
  34. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Estimate.json +1 -1
  35. sequence_base-0.3.18/sequence_base/schemas/EvalDryRunResponse.json +185 -0
  36. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/EvalReport.json +2 -1
  37. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/EvalRequest.json +43 -13
  38. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/EvalResponse.json +56 -1
  39. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ImageFrame.json +1 -1
  40. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ImageSpec.json +1 -1
  41. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ImageStepAddLocal.json +1 -1
  42. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ImageStepApt.json +1 -1
  43. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ImageStepEnv.json +1 -1
  44. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ImageStepRun.json +1 -1
  45. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ImageStepUvPip.json +1 -1
  46. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/InferParam.json +1 -1
  47. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Lease.json +1 -1
  48. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/LossyTransform.json +1 -1
  49. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/MetricAgg.json +1 -1
  50. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Observation.json +1 -1
  51. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/ObservationContract.json +1 -1
  52. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/PolicyRegistration.json +85 -11
  53. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/PolicySpec.json +84 -10
  54. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Proprioception.json +1 -1
  55. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/RenderSpec.json +1 -1
  56. sequence_base-0.3.18/sequence_base/schemas/Resources.json +88 -0
  57. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/RolloutResult.json +1 -1
  58. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/SecretCreateRequest.json +1 -1
  59. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/SecretInfo.json +1 -1
  60. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/SecretRef.json +1 -1
  61. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/SeqFlags.json +1 -1
  62. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Step.json +1 -1
  63. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/SuiteAgg.json +1 -1
  64. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/TaskAgg.json +1 -1
  65. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Timeouts.json +1 -1
  66. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/UploadTarget.json +1 -1
  67. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/UsageReport.json +1 -1
  68. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/Variant.json +1 -1
  69. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/VolumeAttach.json +1 -1
  70. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/VolumeFile.json +1 -1
  71. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/VolumeInfo.json +1 -1
  72. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/VolumeMount.json +1 -1
  73. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/VolumeRef.json +1 -1
  74. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/VolumeUploadRequest.json +1 -1
  75. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/VolumeUploadResponse.json +1 -1
  76. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schemas/WarmingError.json +1 -1
  77. sequence_base-0.3.17/sequence_base/schemas/Concurrency.json +0 -21
  78. sequence_base-0.3.17/sequence_base/schemas/EvalDryRunResponse.json +0 -41
  79. sequence_base-0.3.17/sequence_base/schemas/Resources.json +0 -42
  80. {sequence_base-0.3.17 → sequence_base-0.3.18}/.gitignore +0 -0
  81. {sequence_base-0.3.17 → sequence_base-0.3.18}/README.md +0 -0
  82. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/__init__.py +0 -0
  83. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/auth.py +0 -0
  84. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/codec/__init__.py +0 -0
  85. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/codec/image.py +0 -0
  86. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/constants/__init__.py +0 -0
  87. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/constants/env.py +0 -0
  88. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/constants/headers.py +0 -0
  89. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/__init__.py +0 -0
  90. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/accounts.py +0 -0
  91. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/act.py +0 -0
  92. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/benchmarks.py +0 -0
  93. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/connect.py +0 -0
  94. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/errors.py +0 -0
  95. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/flags.py +0 -0
  96. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/io.py +0 -0
  97. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/templates.py +0 -0
  98. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/volumes.py +0 -0
  99. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/contract/wire.py +0 -0
  100. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/errors/__init__.py +0 -0
  101. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/errors/transport.py +0 -0
  102. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/obs/__init__.py +0 -0
  103. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/obs/log.py +0 -0
  104. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/obs/rid.py +0 -0
  105. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/presets/__init__.py +0 -0
  106. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/presets/robot_arm.py +0 -0
  107. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/schema_export.py +0 -0
  108. {sequence_base-0.3.17 → sequence_base-0.3.18}/sequence_base/telemetry/__init__.py +0 -0
  109. {sequence_base-0.3.17 → sequence_base-0.3.18}/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.17
3
+ Version: 0.3.18
4
4
  Summary: Shared foundation for the Sequences platform — wire contract, correlation, error taxonomy, constants. Used by the robot SDK, gateway, and container harness.
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: pydantic>=2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sequence-base"
3
- version = "0.3.17"
3
+ version = "0.3.18"
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
  # 3.10, not 3.11: `seq` (which imports this) must run on ROS 2 Humble's Python 3.10, and nothing here needs 3.11.
6
6
  # {2026-10-03 the full suite on CPython 3.10.20: "147 PASSED"; vermin --eval-annotations: "MINIMUM REQUIRED VERSIONS: 3.9"}
@@ -4,7 +4,8 @@
4
4
  # across deployments / repos can tell which version of a shape it is validating against. MUST change
5
5
  # whenever any shared wire shape changes (a field added / removed / retyped) — that is what makes
6
6
  # contract evolution mechanically detectable instead of eyeballed. Bump on any shape change.
7
- CONTRACT_VERSION = "0.4.14" # 0.4.13 -> 0.4.14: the /act wire is opaque (ActRequest.inputs / ActResponse.outputs); action / observation contracts optional + DeploymentPolicy/PolicySpec/ConnectResponse .io; the robot-arm types live in sequence_base.presets.robot_arm (contract.act / contract.io re-export them); ImageStepAddLocal (seq.Image.add_local_*); ActionSpace.JOINT_VELOCITY (pi0.5 DROID's joint velocities + gripper position)
7
+ CONTRACT_VERSION = "0.4.15" # 0.4.14 -> 0.4.15: limits count GPUs and CPU/memory are billed like Modal — Resources.cpu / memory_gb optional floats + cpu_limit / memory_limit_gb; Autoscaler.max_gpus / on_full / queue_timeout_s replace max_containers; Concurrency fields optional + replicas_per_gpu / gpus_per_replica; DeploymentStatusResponse.reason; EvalRequest.policy_instances / policy_gpu / benchmark_instances / benchmark_gpu / envs replace gpus / envs_per_gpu; EvalStatus.QUEUED; EvalCards / EvalQueue
8
+ # previous: 0.4.14 # 0.4.13 -> 0.4.14: the /act wire is opaque (ActRequest.inputs / ActResponse.outputs); action / observation contracts optional + DeploymentPolicy/PolicySpec/ConnectResponse .io; the robot-arm types live in sequence_base.presets.robot_arm (contract.act / contract.io re-export them); ImageStepAddLocal (seq.Image.add_local_*); ActionSpace.JOINT_VELOCITY (pi0.5 DROID's joint velocities + gripper position)
8
9
  # previous: 0.4.13 # 0.4.12 -> 0.4.13: template://<name>[@v<n>] — official template weights (parse_template); gs:// / s3:// / https:// still accepted until their removal
9
10
  # previous: 0.4.12 # 0.4.11 -> 0.4.12: one error definition — ErrorBody is every non-2xx body (detail, code, retryable, retry_after_s, request_id, hint, details), ErrorCode covers every case, ERRORS / ErrorCodes.json give each code its status, retryability, SDK class and CLI exit code
10
11
  # previous: 0.4.11 # 0.4.10 -> 0.4.11: weights in named parts (weights_name, extra_weights)
@@ -52,12 +52,24 @@ class Resources(BaseModel):
52
52
  model_config = ConfigDict(extra="forbid")
53
53
 
54
54
  gpu: list[str]
55
- cpu: int
56
- memory_gb: int
55
+ # Physical cores and GiB the worker requests, billed like Modal: per second, at the greater of the request and what
56
+ # it uses. None requests the minimum (0.125 cores, 0.125 GiB) and the worker may use more. A limit caps what it may
57
+ # use; None leaves it free to burst. {gs-plans/parallel/cpu-memory.md "4. 默认申请量照 Modal"}
58
+ cpu: float | None = Field(default=None, ge=0.125, le=64)
59
+ cpu_limit: float | None = Field(default=None, ge=0.125, le=128)
60
+ memory_gb: float | None = Field(default=None, ge=0.125, le=1024)
61
+ memory_limit_gb: float | None = Field(default=None, ge=0.125, le=1024)
57
62
  # Where the workers run (near the robots): one of the regions the platform offers. None: the platform picks.
58
63
  # {gs-plans/customization/policy.md "区域"}
59
64
  region: str | None = Field(default=None, max_length=32)
60
65
 
66
+ @model_validator(mode="after")
67
+ def _limits_cover_requests(self) -> "Resources":
68
+ for what, req, lim in (("cpu", self.cpu, self.cpu_limit), ("memory", self.memory_gb, self.memory_limit_gb)):
69
+ if req is not None and lim is not None and lim < req:
70
+ raise ValueError(f"the {what} limit must be at least the {what} request")
71
+ return self
72
+
61
73
 
62
74
  class Autoscaler(BaseModel):
63
75
  """How the deployment scales. Defaults mirror PolicySpec so an omitted block scales to zero."""
@@ -65,9 +77,18 @@ class Autoscaler(BaseModel):
65
77
  model_config = ConfigDict(extra="forbid")
66
78
 
67
79
  min_containers: int = 0
80
+ # Accepted and ignored: limits count GPUs (`max_gpus`). sequence-ai <= 0.28 still sends it and does not pin
81
+ # sequence-base, so removing it would break their deploys; it goes when no supported SDK sends it.
68
82
  max_containers: int | None = None
83
+ # The most GPUs this deployment may hold at once. None: no cap of its own — only the account's and the platform's
84
+ # GPU limits bound it. Limits count cards, never machines. {gs-plans/parallel/serving.md "1. 限制按卡数,不按台数"}
85
+ max_gpus: int | None = Field(default=None, ge=1, le=256)
69
86
  buffer_containers: int | None = None
70
87
  scaledown_window: int = 600
88
+ # When every slot is taken and no card is left: queue the new robot before its control loop starts, or refuse it at
89
+ # once; how long a queued robot waits before it is told why. {gs-plans/parallel/serving-queue.md "connect 的处理顺序"}
90
+ on_full: Literal["queue", "reject"] = "queue"
91
+ queue_timeout_s: int = Field(default=120, ge=5, le=3600)
71
92
 
72
93
 
73
94
  class Timeouts(BaseModel):
@@ -205,11 +226,8 @@ class DeploymentRequest(BaseModel):
205
226
  # both key and value; the gateway only stores the dump, no consumer needs dict lookup.
206
227
  volumes: list[VolumeAttach] = Field(default_factory=list)
207
228
  autoscaler: Autoscaler = Field(default_factory=Autoscaler)
208
- # An omitted @seq.concurrent must NOT send null: the gateway would then have no concurrency to scale by.
209
- # Materialize the spec default — contracts.md §2's example {"max_inputs": 1, "target_inputs": 1}, i.e.
210
- # one input per container — same discipline as `autoscaler`
211
- # (goal 13).
212
- concurrency: Concurrency = Field(default_factory=lambda: Concurrency(max_inputs=1, target_inputs=1))
229
+ # Every field optional: an omitted @seq.concurrent serves one robot session per model copy, one copy per card.
230
+ concurrency: Concurrency = Field(default_factory=Concurrency)
213
231
  timeouts: Timeouts | None = None
214
232
  # Weights in several named parts: `weights` is the first and `weights_name` its name; `extra_weights` the others,
215
233
  # each provisioned like `weights`. @seq.load then receives {name: directory}. Both None (and absent from the wire):
@@ -283,3 +301,5 @@ class DeploymentStatusResponse(BaseModel):
283
301
  status: DeploymentState
284
302
  model: str
285
303
  error: str | None = Field(default=None, description="Build-failure reason; set only when FAILED")
304
+ # Why a deployment that was serving was marked FAILED: its workers kept dying of the same cause.
305
+ reason: Literal["gpu_out_of_memory", "host_out_of_memory", "crashed"] | None = None
@@ -20,6 +20,10 @@ __all__ = [
20
20
  "Estimate",
21
21
  "EvalResponse",
22
22
  "EvalDryRunResponse",
23
+ "CardSide",
24
+ "CardInUse",
25
+ "EvalCards",
26
+ "EvalQueue",
23
27
  "RolloutResult",
24
28
  "EvalStatus",
25
29
  "SuiteAgg",
@@ -42,8 +46,15 @@ class EvalRequest(BaseModel):
42
46
  benchmark: str
43
47
  suite: str | None = None
44
48
  trials: int | None = None
45
- gpus: int | None = None
46
- envs_per_gpu: int | None = None
49
+ # How the eval is laid out, written by the user and never derived: how many policy machines and on which card
50
+ # (default: one, on the deployment's declared card), how many benchmark machines and on which card (default: one,
51
+ # on the benchmark's declared card), and how many environments each benchmark machine runs (default: the
52
+ # benchmark author's `envs=`, else 1). {gs-plans/parallel/eval.md "1. 两边写法对齐"}
53
+ policy_instances: int = Field(default=1, ge=1, le=64)
54
+ policy_gpu: str | None = Field(default=None, max_length=32)
55
+ benchmark_instances: int = Field(default=1, ge=1, le=64)
56
+ benchmark_gpu: str | None = Field(default=None, max_length=32)
57
+ envs: int | None = Field(default=None, ge=1, le=100000)
47
58
  vlm_max_concurrency: int | None = None
48
59
  adapter: str | None = None
49
60
  compare: str | None = Field(default=None, description="Another model id to compare against")
@@ -90,6 +101,56 @@ class EvalResponse(BaseModel):
90
101
  gpus_granted: int
91
102
  estimate: Estimate
92
103
  clamped_by: ClampInfo | None = None
104
+ # Set when the account was short of GPUs: the eval waits (up to its timeout) instead of being refused.
105
+ queue: EvalQueue | None = None
106
+
107
+
108
+ class CardSide(BaseModel):
109
+ """One side of an eval's machines: how many, on which card, and how many GPUs each holds."""
110
+
111
+ model_config = ConfigDict(extra="forbid")
112
+
113
+ instances: int
114
+ gpu: str
115
+ cards_each: int
116
+
117
+
118
+ class CardInUse(BaseModel):
119
+ """The account's GPUs held now, serving and evals apart; None when it could not be read."""
120
+
121
+ model_config = ConfigDict(extra="forbid")
122
+
123
+ serving: int | None = None
124
+ eval: int | None = None
125
+
126
+
127
+ class EvalCards(BaseModel):
128
+ """The dry-run's card report — the same checks a real submit runs, without starting or charging anything.
129
+ {gs-plans/parallel/eval.md "4. 预演里卡的部分"}"""
130
+
131
+ model_config = ConfigDict(extra="forbid")
132
+
133
+ policy: CardSide
134
+ benchmark: CardSide
135
+ total: int
136
+ limit: int
137
+ in_use: CardInUse
138
+ available: int | None = None
139
+ short: int = 0
140
+ reason: Literal["gpu_limit_reached", "gpu_busy", "gpu_low_stock"] | None = None
141
+ would_queue: bool = False
142
+ queue_timeout_s: int = 600
143
+
144
+
145
+ class EvalQueue(BaseModel):
146
+ """An eval waiting for the account's GPUs: what it needs, what is free, how long it has waited, when it gives up."""
147
+
148
+ model_config = ConfigDict(extra="forbid")
149
+
150
+ cards: int
151
+ available: int | None = None
152
+ waited_s: float = 0
153
+ gives_up_at: str | None = None
93
154
 
94
155
 
95
156
  class EvalDryRunResponse(BaseModel):
@@ -98,6 +159,7 @@ class EvalDryRunResponse(BaseModel):
98
159
  model_config = ConfigDict(extra="forbid")
99
160
 
100
161
  estimate: Estimate
162
+ cards: EvalCards | None = None
101
163
 
102
164
 
103
165
  class RolloutResult(BaseModel):
@@ -124,6 +186,7 @@ class EvalStatus(str, Enum):
124
186
  """Restricted enum — same discipline as DeploymentState (not a free string)."""
125
187
 
126
188
  PENDING = "pending"
189
+ QUEUED = "queued"
127
190
  RUNNING = "running"
128
191
  COMPLETED = "completed"
129
192
  FAILED = "failed"
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  import re
12
12
 
13
- from typing import Any
13
+ from typing import Any, Literal
14
14
 
15
15
  from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
16
16
 
@@ -153,12 +153,26 @@ class VolumeRef(BaseModel):
153
153
 
154
154
 
155
155
  class Concurrency(BaseModel):
156
- """How many inputs one container serves at once: the most it takes, and the level it scales to hold. Both required."""
156
+ """How one worker serves robots, every field optional. `replicas_per_gpu` model copies share each card (each copy is
157
+ its own process and serves one control loop); `gpus_per_replica` cards make one copy (None: every card of the
158
+ worker). A worker's slots = cards // gpus_per_replica × replicas_per_gpu. `target_inputs` is how many robot sessions
159
+ a worker holds before another starts, `max_inputs` the most it takes while a new one boots — both default to the
160
+ slots. {gs-plans/parallel/serving.md "2. 一台 worker 里" / "3. 一台 worker 多张卡"}"""
157
161
 
158
162
  model_config = ConfigDict(extra="forbid")
159
163
 
160
- max_inputs: int
161
- target_inputs: int
164
+ max_inputs: int | None = Field(default=None, ge=1, le=1024)
165
+ target_inputs: int | None = Field(default=None, ge=1, le=1024)
166
+ replicas_per_gpu: int | None = Field(default=None, ge=1, le=64)
167
+ gpus_per_replica: int | None = Field(default=None, ge=1, le=256)
168
+
169
+ @model_validator(mode="after")
170
+ def _consistent(self) -> "Concurrency":
171
+ if self.max_inputs is not None and self.target_inputs is not None and self.max_inputs < self.target_inputs:
172
+ raise ValueError("max_inputs must be at least target_inputs")
173
+ if (self.gpus_per_replica or 1) > 1 and (self.replicas_per_gpu or 1) > 1:
174
+ raise ValueError("a copy that spans several cards is one copy per card group: replicas_per_gpu must be 1")
175
+ return self
162
176
 
163
177
 
164
178
  class PolicySpec(BaseModel):
@@ -176,9 +190,14 @@ class PolicySpec(BaseModel):
176
190
  volumes: dict[str, VolumeRef] = Field(default_factory=dict)
177
191
  secrets: list[SecretRef] = Field(default_factory=list)
178
192
  min_containers: int = 0
193
+ # Accepted and ignored: limits count GPUs (`max_gpus`). sequence-ai <= 0.28 still sends it and does not pin
194
+ # sequence-base, so removing it would break their deploys; it goes when no supported SDK sends it.
179
195
  max_containers: int | None = None
196
+ max_gpus: int | None = Field(default=None, ge=1, le=256)
180
197
  buffer_containers: int | None = None
181
198
  scaledown_window: int = 600
199
+ on_full: Literal["queue", "reject"] = "queue"
200
+ queue_timeout_s: int = Field(default=120, ge=5, le=3600)
182
201
  concurrency: Concurrency | None = None
183
202
  streaming: bool = False
184
203
  frames_per_chunk: int | None = None
@@ -65,5 +65,5 @@
65
65
  ],
66
66
  "title": "ActRequest",
67
67
  "type": "object",
68
- "x-contract-version": "0.4.14"
68
+ "x-contract-version": "0.4.15"
69
69
  }
@@ -75,5 +75,5 @@
75
75
  ],
76
76
  "title": "ActResponse",
77
77
  "type": "object",
78
- "x-contract-version": "0.4.14"
78
+ "x-contract-version": "0.4.15"
79
79
  }
@@ -99,5 +99,5 @@
99
99
  ],
100
100
  "title": "ActionChunk",
101
101
  "type": "object",
102
- "x-contract-version": "0.4.14"
102
+ "x-contract-version": "0.4.15"
103
103
  }
@@ -100,5 +100,5 @@
100
100
  ],
101
101
  "title": "ActionContract",
102
102
  "type": "object",
103
- "x-contract-version": "0.4.14"
103
+ "x-contract-version": "0.4.15"
104
104
  }
@@ -19,5 +19,5 @@
19
19
  ],
20
20
  "title": "ActionStep",
21
21
  "type": "object",
22
- "x-contract-version": "0.4.14"
22
+ "x-contract-version": "0.4.15"
23
23
  }
@@ -38,5 +38,5 @@
38
38
  ],
39
39
  "title": "AdapterTransform",
40
40
  "type": "object",
41
- "x-contract-version": "0.4.14"
41
+ "x-contract-version": "0.4.15"
42
42
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "AddLocal",
25
25
  "type": "object",
26
- "x-contract-version": "0.4.14"
26
+ "x-contract-version": "0.4.15"
27
27
  }
@@ -26,11 +26,41 @@
26
26
  "default": null,
27
27
  "title": "Max Containers"
28
28
  },
29
+ "max_gpus": {
30
+ "anyOf": [
31
+ {
32
+ "maximum": 256,
33
+ "minimum": 1,
34
+ "type": "integer"
35
+ },
36
+ {
37
+ "type": "null"
38
+ }
39
+ ],
40
+ "default": null,
41
+ "title": "Max Gpus"
42
+ },
29
43
  "min_containers": {
30
44
  "default": 0,
31
45
  "title": "Min Containers",
32
46
  "type": "integer"
33
47
  },
48
+ "on_full": {
49
+ "default": "queue",
50
+ "enum": [
51
+ "queue",
52
+ "reject"
53
+ ],
54
+ "title": "On Full",
55
+ "type": "string"
56
+ },
57
+ "queue_timeout_s": {
58
+ "default": 120,
59
+ "maximum": 3600,
60
+ "minimum": 5,
61
+ "title": "Queue Timeout S",
62
+ "type": "integer"
63
+ },
34
64
  "scaledown_window": {
35
65
  "default": 600,
36
66
  "title": "Scaledown Window",
@@ -39,5 +69,5 @@
39
69
  },
40
70
  "title": "Autoscaler",
41
71
  "type": "object",
42
- "x-contract-version": "0.4.14"
72
+ "x-contract-version": "0.4.15"
43
73
  }
@@ -62,5 +62,5 @@
62
62
  ],
63
63
  "title": "BenchmarkConditionSpec",
64
64
  "type": "object",
65
- "x-contract-version": "0.4.14"
65
+ "x-contract-version": "0.4.15"
66
66
  }
@@ -681,5 +681,5 @@
681
681
  ],
682
682
  "title": "BenchmarkRegisterRequest",
683
683
  "type": "object",
684
- "x-contract-version": "0.4.14"
684
+ "x-contract-version": "0.4.15"
685
685
  }
@@ -277,7 +277,7 @@
277
277
  ],
278
278
  "title": "SeqFlags",
279
279
  "type": "integer",
280
- "x-contract-version": "0.4.14",
280
+ "x-contract-version": "0.4.15",
281
281
  "x-flag-names": {
282
282
  "CHECK": 65536,
283
283
  "INFER": 16,
@@ -467,5 +467,5 @@
467
467
  ],
468
468
  "title": "BenchmarkSpec",
469
469
  "type": "object",
470
- "x-contract-version": "0.4.14"
470
+ "x-contract-version": "0.4.15"
471
471
  }
@@ -40,5 +40,5 @@
40
40
  ],
41
41
  "title": "BenchmarkStatusResponse",
42
42
  "type": "object",
43
- "x-contract-version": "0.4.14"
43
+ "x-contract-version": "0.4.15"
44
44
  }
@@ -72,5 +72,5 @@
72
72
  ],
73
73
  "title": "BootstrapResponse",
74
74
  "type": "object",
75
- "x-contract-version": "0.4.14"
75
+ "x-contract-version": "0.4.15"
76
76
  }
@@ -34,5 +34,5 @@
34
34
  ],
35
35
  "title": "Camera",
36
36
  "type": "object",
37
- "x-contract-version": "0.4.14"
37
+ "x-contract-version": "0.4.15"
38
38
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "ClampInfo",
25
25
  "type": "object",
26
- "x-contract-version": "0.4.14"
26
+ "x-contract-version": "0.4.15"
27
27
  }
@@ -23,5 +23,5 @@
23
23
  ],
24
24
  "title": "CodeBundle",
25
25
  "type": "object",
26
- "x-contract-version": "0.4.14"
26
+ "x-contract-version": "0.4.15"
27
27
  }
@@ -0,0 +1,65 @@
1
+ {
2
+ "additionalProperties": false,
3
+ "description": "How one worker serves robots, every field optional. `replicas_per_gpu` model copies share each card (each copy is\nits own process and serves one control loop); `gpus_per_replica` cards make one copy (None: every card of the\nworker). A worker's slots = cards // gpus_per_replica × replicas_per_gpu. `target_inputs` is how many robot sessions\na worker holds before another starts, `max_inputs` the most it takes while a new one boots — both default to the\nslots. {gs-plans/parallel/serving.md \"2. 一台 worker 里\" / \"3. 一台 worker 多张卡\"}",
4
+ "properties": {
5
+ "gpus_per_replica": {
6
+ "anyOf": [
7
+ {
8
+ "maximum": 256,
9
+ "minimum": 1,
10
+ "type": "integer"
11
+ },
12
+ {
13
+ "type": "null"
14
+ }
15
+ ],
16
+ "default": null,
17
+ "title": "Gpus Per Replica"
18
+ },
19
+ "max_inputs": {
20
+ "anyOf": [
21
+ {
22
+ "maximum": 1024,
23
+ "minimum": 1,
24
+ "type": "integer"
25
+ },
26
+ {
27
+ "type": "null"
28
+ }
29
+ ],
30
+ "default": null,
31
+ "title": "Max Inputs"
32
+ },
33
+ "replicas_per_gpu": {
34
+ "anyOf": [
35
+ {
36
+ "maximum": 64,
37
+ "minimum": 1,
38
+ "type": "integer"
39
+ },
40
+ {
41
+ "type": "null"
42
+ }
43
+ ],
44
+ "default": null,
45
+ "title": "Replicas Per Gpu"
46
+ },
47
+ "target_inputs": {
48
+ "anyOf": [
49
+ {
50
+ "maximum": 1024,
51
+ "minimum": 1,
52
+ "type": "integer"
53
+ },
54
+ {
55
+ "type": "null"
56
+ }
57
+ ],
58
+ "default": null,
59
+ "title": "Target Inputs"
60
+ }
61
+ },
62
+ "title": "Concurrency",
63
+ "type": "object",
64
+ "x-contract-version": "0.4.15"
65
+ }
@@ -55,5 +55,5 @@
55
55
  ],
56
56
  "title": "Conditions",
57
57
  "type": "object",
58
- "x-contract-version": "0.4.14"
58
+ "x-contract-version": "0.4.15"
59
59
  }
@@ -25,5 +25,5 @@
25
25
  ],
26
26
  "title": "ConnectRequest",
27
27
  "type": "object",
28
- "x-contract-version": "0.4.14"
28
+ "x-contract-version": "0.4.15"
29
29
  }
@@ -307,5 +307,5 @@
307
307
  ],
308
308
  "title": "ConnectResponse",
309
309
  "type": "object",
310
- "x-contract-version": "0.4.14"
310
+ "x-contract-version": "0.4.15"
311
311
  }
@@ -18,5 +18,5 @@
18
18
  ],
19
19
  "title": "DeploymentAccepted",
20
20
  "type": "object",
21
- "x-contract-version": "0.4.14"
21
+ "x-contract-version": "0.4.15"
22
22
  }
@@ -387,5 +387,5 @@
387
387
  ],
388
388
  "title": "DeploymentPolicy",
389
389
  "type": "object",
390
- "x-contract-version": "0.4.14"
390
+ "x-contract-version": "0.4.15"
391
391
  }