envloop-cli 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.
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/PKG-INFO +32 -11
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/README.pypi.md +28 -8
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/agent_runs.py +8 -8
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/auth_cli.py +4 -1
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/cli.py +188 -88
- envloop_cli-0.3.0/envloop/cli_errors.py +248 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/cli_output.py +53 -20
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/client.py +119 -8
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/http.py +67 -13
- envloop_cli-0.3.0/envloop/job_logs.py +16 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/navigation_resources.py +105 -18
- envloop_cli-0.3.0/envloop/profile_secrets.py +27 -0
- envloop_cli-0.3.0/envloop/profile_updates.py +49 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/resource_cli.py +40 -38
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/resources.py +4 -2
- envloop_cli-0.3.0/envloop/sandbox.py +27 -0
- envloop_cli-0.3.0/envloop/train.py +68 -0
- envloop_cli-0.3.0/envloop/train_log_cli.py +97 -0
- envloop_cli-0.3.0/envloop/training/__init__.py +121 -0
- envloop_cli-0.3.0/envloop/training/service_client.py +108 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/pyproject.toml +4 -5
- envloop_cli-0.2.0/envloop/train.py +0 -51
- envloop_cli-0.2.0/envloop/training/__init__.py +0 -128
- envloop_cli-0.2.0/envloop/training/service_client.py +0 -40
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/.gitignore +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/__init__.py +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/auth_login.py +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/auth_workspace.py +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/config.py +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/lifecycle_cli.py +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/training/credentials.py +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/utils/__init__.py +0 -0
- {envloop_cli-0.2.0 → envloop_cli-0.3.0}/envloop/utils/logging.py +0 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: envloop-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: EnvLoop CLI and Python SDK for jobs, training, checkpoints and inference
|
|
5
5
|
Project-URL: Homepage, https://envloop.ai
|
|
6
6
|
Project-URL: Documentation, https://docs.envloop.ai
|
|
7
|
+
Project-URL: Repository, https://github.com/EnvLoop/envloop-cli
|
|
8
|
+
Project-URL: Issues, https://github.com/EnvLoop/envloop-cli/issues
|
|
7
9
|
Project-URL: Agent instructions, https://docs.envloop.ai/skill.md
|
|
8
10
|
Requires-Python: >=3.11
|
|
9
|
-
|
|
10
|
-
Requires-Dist: tinker==0.30.2; extra == 'train'
|
|
11
|
+
Requires-Dist: tinker==0.30.2
|
|
11
12
|
Description-Content-Type: text/markdown
|
|
12
13
|
|
|
13
|
-
# EnvLoop CLI and Python SDK
|
|
14
|
+
# envloop-cli: EnvLoop CLI and Python SDK
|
|
14
15
|
|
|
15
16
|
Install the public client to run agent Jobs, inspect Trials, manage training and
|
|
16
17
|
checkpoints, and deploy or call inference endpoints. The `el` and `envloop`
|
|
@@ -21,19 +22,17 @@ commands are equivalent. The Python import package is `envloop`.
|
|
|
21
22
|
Use a Python virtual environment:
|
|
22
23
|
|
|
23
24
|
```bash
|
|
24
|
-
python -m pip install envloop-cli
|
|
25
|
+
python -m pip install --upgrade envloop-cli
|
|
25
26
|
el --help
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
The standard installation includes training support:
|
|
29
30
|
|
|
30
31
|
```bash
|
|
31
|
-
python -m pip install 'envloop-cli[train]'
|
|
32
32
|
python -c 'from envloop import Client, training; print("EnvLoop SDK ready")'
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
The
|
|
36
|
-
training protocol client. You do not need a source checkout, GitHub account,
|
|
35
|
+
The package installs the training protocol client by default. You do not need a source checkout, GitHub account,
|
|
37
36
|
local execution backend, Docker, or a GPU to install the client.
|
|
38
37
|
|
|
39
38
|
## Connect
|
|
@@ -60,9 +59,11 @@ your secret manager. Public API access is scoped to the authorized project.
|
|
|
60
59
|
|
|
61
60
|
```bash
|
|
62
61
|
el job list --limit 5
|
|
63
|
-
el
|
|
62
|
+
el job list --type train --limit 5
|
|
63
|
+
el trail list --limit 5
|
|
64
|
+
el trail list --type train --job-id JOB_ID
|
|
64
65
|
el checkpoint list --limit 5
|
|
65
|
-
el
|
|
66
|
+
el job list --type inference
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
Query a returned Job ID with `el job get JOB_ID` and `el job result JOB_ID`.
|
|
@@ -76,12 +77,32 @@ from envloop import Client
|
|
|
76
77
|
|
|
77
78
|
with Client.remote() as client:
|
|
78
79
|
print(client.jobs.list(limit=5))
|
|
80
|
+
print(client.trials.list(type="train", limit=5))
|
|
79
81
|
```
|
|
80
82
|
|
|
81
83
|
Submitting work, training a model or starting inference can allocate billable
|
|
82
84
|
resources. Follow the task-specific guide and retain the outputs you need before
|
|
83
85
|
cleaning up temporary resources.
|
|
84
86
|
|
|
87
|
+
## Sandbox jobs
|
|
88
|
+
|
|
89
|
+
With a matching platform and a published `envhub/base` ANS Runner, submit a
|
|
90
|
+
Sandbox Job without a Dataset:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
el job submit --type sandbox --runner base --command 'python --version'
|
|
94
|
+
el job submit --type sandbox --runner base --image python:3.11 --wait
|
|
95
|
+
el job list --type sandbox
|
|
96
|
+
el job log JOB_ID --follow
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The platform resolves `base` to the registered `envhub/base@main` source ref and
|
|
100
|
+
freezes its immutable Revision. The Sandbox image defaults to `python:3.11`;
|
|
101
|
+
`--image` accepts an image name, tag or digest. The execution provider is configured
|
|
102
|
+
by the server. Job logs retain the actual captured output and collection metadata.
|
|
103
|
+
Failures include a code, readable explanation, HTTP status when available, and
|
|
104
|
+
recovery guidance without echoing arbitrary response bodies or credentials.
|
|
105
|
+
|
|
85
106
|
## Existing installations
|
|
86
107
|
|
|
87
108
|
This distribution provides both the CLI and the `envloop` import package. Use a
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# EnvLoop CLI and Python SDK
|
|
1
|
+
# envloop-cli: EnvLoop CLI and Python SDK
|
|
2
2
|
|
|
3
3
|
Install the public client to run agent Jobs, inspect Trials, manage training and
|
|
4
4
|
checkpoints, and deploy or call inference endpoints. The `el` and `envloop`
|
|
@@ -9,19 +9,17 @@ commands are equivalent. The Python import package is `envloop`.
|
|
|
9
9
|
Use a Python virtual environment:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
python -m pip install envloop-cli
|
|
12
|
+
python -m pip install --upgrade envloop-cli
|
|
13
13
|
el --help
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
The standard installation includes training support:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
python -m pip install 'envloop-cli[train]'
|
|
20
19
|
python -c 'from envloop import Client, training; print("EnvLoop SDK ready")'
|
|
21
20
|
```
|
|
22
21
|
|
|
23
|
-
The
|
|
24
|
-
training protocol client. You do not need a source checkout, GitHub account,
|
|
22
|
+
The package installs the training protocol client by default. You do not need a source checkout, GitHub account,
|
|
25
23
|
local execution backend, Docker, or a GPU to install the client.
|
|
26
24
|
|
|
27
25
|
## Connect
|
|
@@ -48,9 +46,11 @@ your secret manager. Public API access is scoped to the authorized project.
|
|
|
48
46
|
|
|
49
47
|
```bash
|
|
50
48
|
el job list --limit 5
|
|
51
|
-
el
|
|
49
|
+
el job list --type train --limit 5
|
|
50
|
+
el trail list --limit 5
|
|
51
|
+
el trail list --type train --job-id JOB_ID
|
|
52
52
|
el checkpoint list --limit 5
|
|
53
|
-
el
|
|
53
|
+
el job list --type inference
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Query a returned Job ID with `el job get JOB_ID` and `el job result JOB_ID`.
|
|
@@ -64,12 +64,32 @@ from envloop import Client
|
|
|
64
64
|
|
|
65
65
|
with Client.remote() as client:
|
|
66
66
|
print(client.jobs.list(limit=5))
|
|
67
|
+
print(client.trials.list(type="train", limit=5))
|
|
67
68
|
```
|
|
68
69
|
|
|
69
70
|
Submitting work, training a model or starting inference can allocate billable
|
|
70
71
|
resources. Follow the task-specific guide and retain the outputs you need before
|
|
71
72
|
cleaning up temporary resources.
|
|
72
73
|
|
|
74
|
+
## Sandbox jobs
|
|
75
|
+
|
|
76
|
+
With a matching platform and a published `envhub/base` ANS Runner, submit a
|
|
77
|
+
Sandbox Job without a Dataset:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
el job submit --type sandbox --runner base --command 'python --version'
|
|
81
|
+
el job submit --type sandbox --runner base --image python:3.11 --wait
|
|
82
|
+
el job list --type sandbox
|
|
83
|
+
el job log JOB_ID --follow
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The platform resolves `base` to the registered `envhub/base@main` source ref and
|
|
87
|
+
freezes its immutable Revision. The Sandbox image defaults to `python:3.11`;
|
|
88
|
+
`--image` accepts an image name, tag or digest. The execution provider is configured
|
|
89
|
+
by the server. Job logs retain the actual captured output and collection metadata.
|
|
90
|
+
Failures include a code, readable explanation, HTTP status when available, and
|
|
91
|
+
recovery guidance without echoing arbitrary response bodies or credentials.
|
|
92
|
+
|
|
73
93
|
## Existing installations
|
|
74
94
|
|
|
75
95
|
This distribution provides both the CLI and the `envloop` import package. Use a
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The platform stores no run object. Agents tag every Train Job they create with
|
|
4
4
|
``user_metadata`` (the RSI loop: ``rsi_run``, ``rsi_round``, ``rsi_checkpoint``...);
|
|
5
|
-
this module pages through ``GET /v1/
|
|
5
|
+
this module pages through ``GET /v1/job`` and derives runs from those tags,
|
|
6
6
|
using the same rules as the Console's agent runs page.
|
|
7
7
|
"""
|
|
8
8
|
|
|
@@ -19,8 +19,8 @@ KEYS = {
|
|
|
19
19
|
"checkpoint": ("agent_checkpoint", "rsi_checkpoint"),
|
|
20
20
|
}
|
|
21
21
|
RUN_KEYS = KEYS["run"] # first non-empty string wins
|
|
22
|
-
ACTIVE_STATUSES = frozenset({"LAUNCHING", "STARTING", "RUNNING", "RECOVERING"})
|
|
23
|
-
TERMINAL_STATUSES = frozenset({"SUCCEEDED", "FAILED", "CANCELLED"})
|
|
22
|
+
ACTIVE_STATUSES = frozenset({"LAUNCHING", "STARTING", "RUNNING", "RECOVERING", "queued", "pending", "starting", "running", "recovering", "cancelling"})
|
|
23
|
+
TERMINAL_STATUSES = frozenset({"SUCCEEDED", "FAILED", "CANCELLED", "completed", "failed", "cancelled"})
|
|
24
24
|
PAGE_LIMIT = 100 # the platform's maximum page size
|
|
25
25
|
|
|
26
26
|
|
|
@@ -70,7 +70,7 @@ def _round(job) -> int | None:
|
|
|
70
70
|
|
|
71
71
|
def _order(job):
|
|
72
72
|
# Creation order, as the platform pages jobs (newest first, reversed here).
|
|
73
|
-
return (str(job.get("created_at") or ""), str(job.get("train_job_id") or ""))
|
|
73
|
+
return (str(job.get("created_at") or ""), str(job.get("job_id") or job.get("train_job_id") or ""))
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
def _duration_sec(job) -> int | None:
|
|
@@ -97,7 +97,7 @@ def _checkpoint(job) -> dict | None:
|
|
|
97
97
|
def _job_view(job) -> dict:
|
|
98
98
|
metadata = _metadata(job)
|
|
99
99
|
return {
|
|
100
|
-
"train_job_id": job.get("train_job_id"),
|
|
100
|
+
"train_job_id": job.get("job_id") or job.get("train_job_id"),
|
|
101
101
|
"status": job.get("status"),
|
|
102
102
|
"round": _round(job),
|
|
103
103
|
"purpose": _field(job, "purpose"),
|
|
@@ -121,11 +121,11 @@ def _summary(run: str, jobs: list) -> dict:
|
|
|
121
121
|
status = "running"
|
|
122
122
|
else:
|
|
123
123
|
status = str(latest.get("status") or "unknown").lower()
|
|
124
|
-
succeeded = [job for job in jobs if job.get("status")
|
|
124
|
+
succeeded = [job for job in jobs if job.get("status") in {"SUCCEEDED", "completed"}]
|
|
125
125
|
latest_saved = next((job for job in reversed(jobs) if _checkpoint(job) is not None), None)
|
|
126
126
|
latest_checkpoint = _checkpoint(latest_saved) if latest_saved is not None else None
|
|
127
127
|
if latest_checkpoint is not None:
|
|
128
|
-
latest_checkpoint["train_job_id"] = latest_saved.get("train_job_id")
|
|
128
|
+
latest_checkpoint["train_job_id"] = latest_saved.get("job_id") or latest_saved.get("train_job_id")
|
|
129
129
|
rounds = [number for number in map(_round, jobs) if number is not None]
|
|
130
130
|
activity = [stamp for job in jobs if isinstance(stamp := job.get("updated_at") or job.get("created_at"), str)]
|
|
131
131
|
return {
|
|
@@ -172,7 +172,7 @@ class AgentRuns:
|
|
|
172
172
|
if observed_at is None:
|
|
173
173
|
observed_at = page.get("observed_at")
|
|
174
174
|
for job in page.get("items") or []:
|
|
175
|
-
job_id = job.get("train_job_id") if isinstance(job, dict) else None
|
|
175
|
+
job_id = job.get("job_id") or job.get("train_job_id") if isinstance(job, dict) else None
|
|
176
176
|
if not isinstance(job, dict) or job_id in ids:
|
|
177
177
|
continue
|
|
178
178
|
if job_id is not None:
|
|
@@ -277,9 +277,12 @@ def run_auth(args, parser):
|
|
|
277
277
|
config=False, environment=False).list_jobs(limit=1)
|
|
278
278
|
report["check"] = "access_confirmed" if connection.api_key else "reachable_anonymous"
|
|
279
279
|
except (ConfigError, RemoteError) as error:
|
|
280
|
+
from .cli_errors import format_error, safe_error_code
|
|
281
|
+
|
|
280
282
|
report["check"] = {401: "authentication_rejected", 403: "authorization_denied"}.get(
|
|
281
|
-
getattr(error, "status_code", None), error
|
|
283
|
+
getattr(error, "status_code", None), safe_error_code(error))
|
|
282
284
|
_print(report, args.json)
|
|
285
|
+
print(format_error(error, args=args, program=parser.prog), file=sys.stderr)
|
|
283
286
|
return 1
|
|
284
287
|
_print(report, getattr(args, "json", False))
|
|
285
288
|
return 0
|