simulo-interfaces 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {simulo_interfaces-0.2.0/src/simulo_interfaces.egg-info → simulo_interfaces-0.3.0}/PKG-INFO +1 -1
  2. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/pyproject.toml +1 -1
  3. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/__init__.py +4 -0
  4. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/runs.py +81 -1
  5. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/submit.py +5 -4
  6. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0/src/simulo_interfaces.egg-info}/PKG-INFO +1 -1
  7. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/MANIFEST.in +0 -0
  8. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/PYPI.md +0 -0
  9. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/setup.cfg +0 -0
  10. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/__init__.py +0 -0
  11. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/exceptions.py +0 -0
  12. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/ids.py +0 -0
  13. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/app.py +0 -0
  14. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/asset.py +0 -0
  15. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/callbacks.py +0 -0
  16. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/debug.py +0 -0
  17. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/domain.py +0 -0
  18. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/enums.py +0 -0
  19. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/runtime.py +0 -0
  20. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/platform/volume.py +0 -0
  21. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/py.typed +0 -0
  22. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/__init__.py +0 -0
  23. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/anomaly.py +0 -0
  24. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/components.py +0 -0
  25. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/env.py +0 -0
  26. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/player.py +0 -0
  27. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/policy.py +0 -0
  28. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/scenario.py +0 -0
  29. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/task.py +0 -0
  30. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/tensors.py +0 -0
  31. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo/interfaces/runtime/trainer.py +0 -0
  32. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo_interfaces.egg-info/SOURCES.txt +0 -0
  33. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo_interfaces.egg-info/dependency_links.txt +0 -0
  34. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo_interfaces.egg-info/requires.txt +0 -0
  35. {simulo_interfaces-0.2.0 → simulo_interfaces-0.3.0}/src/simulo_interfaces.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulo-interfaces
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Type contracts for the Simulo SDK. Installed automatically as a dependency of the simulo package.
5
5
  Author-email: Simulo Team <team@simulo.ai>
6
6
  License: BSD-3-Clause
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simulo-interfaces"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Type contracts for the Simulo SDK. Installed automatically as a dependency of the simulo package."
9
9
  readme = "PYPI.md"
10
10
  requires-python = ">=3.11"
@@ -14,12 +14,14 @@ from simulo.interfaces.platform.debug import DebugSessionProtocol, ReplaySession
14
14
  from simulo.interfaces.platform.domain import Checkpoint, Job, Package, Project, Resource, Tag, TrainedModel
15
15
  from simulo.interfaces.platform.enums import ArtifactKind, JobStatus, ResourceKind, ResumePolicy
16
16
  from simulo.interfaces.platform.runs import (
17
+ JOB_CANCEL_ROUTE_TEMPLATE,
17
18
  JOB_LOGS_ROUTE_TEMPLATE,
18
19
  JOB_RESULT_ROUTE_TEMPLATE,
19
20
  JOB_ROUTE_TEMPLATE,
20
21
  JOBS_API_DEFAULT_PORT,
21
22
  JOBS_ROUTE,
22
23
  LOG_CHUNK_MAX_BYTES,
24
+ LOG_TAIL_MAX_BYTES,
23
25
  TERMINAL_JOB_STATUSES,
24
26
  JobRecord,
25
27
  )
@@ -75,9 +77,11 @@ __all__ = [
75
77
  "JOBS_API_DEFAULT_PORT",
76
78
  "JOBS_ROUTE",
77
79
  "JOB_ROUTE_TEMPLATE",
80
+ "JOB_CANCEL_ROUTE_TEMPLATE",
78
81
  "JOB_LOGS_ROUTE_TEMPLATE",
79
82
  "JOB_RESULT_ROUTE_TEMPLATE",
80
83
  "LOG_CHUNK_MAX_BYTES",
84
+ "LOG_TAIL_MAX_BYTES",
81
85
  # submit / worker / recordings wire contract (PR-0)
82
86
  "PACKAGES_ROUTE",
83
87
  "PACKAGE_ARCHIVE_ROUTE_TEMPLATE",
@@ -37,8 +37,50 @@ HTTP API shape (all responses JSON; all timestamps ISO 8601 UTC, e.g.
37
37
  ``next_offset == offset``; the accompanying ``status`` tells the client
38
38
  whether more output may still arrive (poll while the status is
39
39
  non-terminal, stop once it is in :data:`TERMINAL_JOB_STATUSES`).
40
+
41
+ **Tail semantics (optional, additive):** ``?tail_bytes=K`` (``0 <= K <=``
42
+ :data:`LOG_TAIL_MAX_BYTES`; ``offset`` must be omitted or 0, otherwise the
43
+ request is ambiguous and answers 422 — the control plane's code is
44
+ ``tail_bytes_conflicts_with_offset``; clients need only the status)
45
+ asks the server to start the read near the END of the stream instead of at
46
+ ``offset``: the server computes ``start = max(0, total_len - K)`` and
47
+ returns the chunk from there, adding ``"start_offset": start`` to the
48
+ response. ``start_offset`` is present ONLY when tail was honored — its
49
+ absence tells a tail-requesting client it is talking to an older server
50
+ that ignored the (undeclared) parameter and answered from offset 0, so the
51
+ client can degrade to full history instead of mis-trimming. ``tail_bytes=0``
52
+ is the "seek to end-of-log" primitive: an empty ``chunk`` with
53
+ ``next_offset == start_offset == total_len``. After one tail response the
54
+ client resumes normal offset paging from ``next_offset`` (never sending
55
+ ``tail_bytes`` again), so a tail-following client never drains the full
56
+ history. ``start`` is a byte position and may land mid-line or mid-UTF-8
57
+ sequence; a line-oriented client trims its first partial line client-side
58
+ (``simulo logs --follow`` requests a generous byte window for its line
59
+ count and does exactly that).
40
60
  * ``GET /v1/jobs/{job_id}/result`` — the job's result JSON object. 404 (code
41
61
  ``result_not_available``) until the job has completed successfully.
62
+ * ``POST /v1/jobs/{job_id}/cancel`` — request cancellation of a queued or
63
+ running job (no request body). Semantics by current status:
64
+
65
+ - ``queued`` → the job transitions to terminal ``cancelled`` immediately
66
+ (it can never be claimed afterwards). 200::
67
+
68
+ {"job_id": "...", "status": "cancelled"}
69
+
70
+ - ``running`` → cancellation is REQUESTED; the executor observes it on its
71
+ next heartbeat, stops the job, and reports terminal ``cancelled``
72
+ (existing ``best.pt``/``latest.pt`` checkpoints are uploaded first —
73
+ cancel never vaporizes training progress; partial recordings are
74
+ dropped). Idempotent: repeat requests return the same 202::
75
+
76
+ {"job_id": "...", "status": "running", "cancel_requested": true}
77
+
78
+ A ``running`` job whose executor is provably gone (expired lease, no
79
+ active claim) transitions directly to ``cancelled`` → 200 as above.
80
+ - terminal (``completed``/``failed``/``cancelled``) → 409, code
81
+ ``job_not_running``, with the job's actual status in the human message.
82
+ - unknown/cross-tenant/malformed id → 404 ``job_not_found`` (never 403 —
83
+ anti-enumeration, same as every other per-job route).
42
84
 
43
85
  **Scoping (evolves toward the cloud):** every route above is UNSCOPED locally
44
86
  — there is no project/org filter because the local stand-in has exactly one
@@ -77,10 +119,48 @@ JOB_ROUTE_TEMPLATE = "/v1/jobs/{job_id}"
77
119
  JOB_LOGS_ROUTE_TEMPLATE = "/v1/jobs/{job_id}/logs"
78
120
  #: ``GET`` — the result JSON of a successfully completed job. ``.format(job_id=...)``.
79
121
  JOB_RESULT_ROUTE_TEMPLATE = "/v1/jobs/{job_id}/result"
122
+ #: ``POST`` — cancel a queued/running job (no body). ``.format(job_id=...)``.
123
+ #: 200 terminal ``cancelled`` (queued, or running with a provably-dead
124
+ #: executor); 202 ``{"cancel_requested": true}`` (running — the executor
125
+ #: stops it within one heartbeat interval); 409 ``job_not_running``
126
+ #: (already terminal); 404 ``job_not_found``. Full semantics in the module
127
+ #: docstring above.
128
+ JOB_CANCEL_ROUTE_TEMPLATE = "/v1/jobs/{job_id}/cancel"
80
129
 
81
130
  #: Upper bound on the log bytes a single ``/logs`` response carries. The server
82
131
  #: may return fewer bytes (never more); clients keep reading from ``next_offset``.
83
- LOG_CHUNK_MAX_BYTES = 64 * 1024
132
+ #: This is a server-side response-size POLICY value, not a structural wire
133
+ #: shape — clients are not expected to depend on the exact number (they
134
+ #: read ``chunk``/``next_offset`` generically and loop until caught up), so
135
+ #: it is safe to raise without breaking already-published clients reading
136
+ #: OFFSET responses. **Rollout order caveat (added with tail semantics):**
137
+ #: :data:`LOG_TAIL_MAX_BYTES` is DERIVED from this constant (``4x``), so
138
+ #: raising this ALSO raises what a new client may send as ``?tail_bytes=``.
139
+ #: A server that has not yet picked up the raised bound still enforces its
140
+ #: OLD, smaller ``le=`` cap on that query param and answers 422 — a hard
141
+ #: rejection the client's tail-degradation path does not cover (that path
142
+ #: handles an old server IGNORING the unknown param, not one REJECTING an
143
+ #: in-range-for-the-client-but-out-of-range-for-the-server value). Deploy
144
+ #: every server before shipping a `simulo-interfaces` release that raises
145
+ #: this constant. Bumped
146
+ #: 64 KiB -> 256 KiB (simulo-control-plane PR6, 2026-07-11): a poll-cadence
147
+ #: rate limit sized against the OLD 64 KiB cap could still 429 mid-drain on
148
+ #: a large/fast-growing log because a no-sleep catch-up loop bursts through
149
+ #: it; see that PR's `jobs/routes.py::_LOGS_POLL_RATE` docstring for the
150
+ #: exact math. No PyPI republish accompanies this source change — no
151
+ #: published thin-client version reads this constant at runtime; it takes
152
+ #: effect for whichever `simulo-interfaces` version ships next.
153
+ LOG_CHUNK_MAX_BYTES = 256 * 1024
154
+
155
+ #: Upper bound on ``?tail_bytes=`` (the "start this many bytes before the end"
156
+ #: request parameter — see the module docstring's tail semantics). A tail
157
+ #: window is a REQUEST-side positioning value, not a response-size promise:
158
+ #: the response is still capped at :data:`LOG_CHUNK_MAX_BYTES`, and a window
159
+ #: larger than one response chunk arrives across normal offset pages. 4x the
160
+ #: response cap comfortably covers the CLI's default (50 lines x ~200
161
+ #: bytes/line ≈ 10 KiB) and any plausible ``--tail N`` while keeping the
162
+ #: server's tail scan bounded. Values above this cap answer 422.
163
+ LOG_TAIL_MAX_BYTES = 4 * LOG_CHUNK_MAX_BYTES
84
164
 
85
165
  #: Statuses after which a job's log stream and record no longer change. A log
86
166
  #: follower drains the remaining bytes and stops once the status is terminal.
@@ -344,10 +344,11 @@ MAX_PACKAGE_BYTES = 64 * 1024 * 1024 # 64 MiB
344
344
  #: (``POST`` :data:`WORKER_JOB_LOGS_ROUTE_TEMPLATE` body) — the write-side cap, 1 MiB.
345
345
  #:
346
346
  #: **Not the same constant as** ``simulo.interfaces.platform.runs.LOG_CHUNK_MAX_BYTES``
347
- #: (64 KiB) that is the pre-existing **client** read-side cap on a single
348
- #: ``GET .../logs?offset=N`` response (``runs.py``). Both are now re-exported
349
- #: from ``simulo.interfaces.platform``, so importing the wrong one silently
350
- #: changes behavior by 16x: a worker that POSTs up to ``runs.LOG_CHUNK_MAX_BYTES``
347
+ #: (256 KiB as of 2026-07-11 see that constant's docstring) that is the
348
+ #: pre-existing **client** read-side cap on a single ``GET .../logs?offset=N``
349
+ #: response (``runs.py``). Both are now re-exported from
350
+ #: ``simulo.interfaces.platform``, so importing the wrong one silently
351
+ #: changes behavior by 4x: a worker that POSTs up to ``runs.LOG_CHUNK_MAX_BYTES``
351
352
  #: per call under-uses its allowance; a client GET that budgeted for this
352
353
  #: (larger) constant would be surprised the server never returns that much.
353
354
  MAX_LOG_CHUNK_BYTES = 1 * 1024 * 1024 # 1 MiB
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simulo-interfaces
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Type contracts for the Simulo SDK. Installed automatically as a dependency of the simulo package.
5
5
  Author-email: Simulo Team <team@simulo.ai>
6
6
  License: BSD-3-Clause