Skip to content

Commit 57cfa0e

Browse files
authored
Merge branch 'main' into add/startup-wizard
2 parents 4a10394 + e57453d commit 57cfa0e

54 files changed

Lines changed: 3739 additions & 12648 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/transformerlab-cli/SKILL.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ lab job download JOB_ID --file "*.csv" -o ./results
102102

103103
## Creating Tasks
104104

105+
### Scaffold a new task with `lab task init`
106+
107+
**When the user asks to create, initialize, or start a new task, always use `lab task init`** rather than writing `task.yaml` / `main.py` by hand. It scaffolds both files with sensible defaults in the current directory so the user has a working starting point.
108+
109+
```bash
110+
mkdir my-task && cd my-task
111+
lab task init # writes task.yaml + main.py with defaults (skips existing files)
112+
lab task init --interactive # prompts for name, CPUs, memory, setup, and run command
113+
```
114+
115+
- Default mode is non-interactive. It creates `task.yaml` (with `name`, `resources: {cpus: 2, memory: 4}`, and `run: python main.py`) and a starter `main.py`. Existing files are skipped, not overwritten.
116+
- `--interactive` writes only `task.yaml` (no `main.py`) and prompts for each field. In this mode `task.yaml` will prompt before overwrite.
117+
- After init, edit `main.py`, customize `task.yaml`, then run `lab task add .` to upload it.
118+
105119
### task.yaml Structure
106120

107121
Full docs: https://lab.cloud/for-teams/running-a-task/task-yaml-structure
@@ -291,6 +305,7 @@ This applies to launching jobs, fetching logs, checking cluster status, and ever
291305
| `lab version` | Show CLI version | No |
292306
| `lab task list` | List tasks in current experiment | Yes |
293307
| `lab task info <id>` | Get task details | Yes |
308+
| `lab task init` | Scaffold `task.yaml` + `main.py` in the current directory (`--interactive` to prompt) | No |
294309
| `lab task add [dir]` | Add task from directory or `--from-git` URL (`--no-interactive`, `--dry-run`) | Yes |
295310
| `lab task delete <id>` | Delete a task (`--no-interactive` to skip confirmation) | Yes |
296311
| `lab task queue <id>` | Queue task on compute provider | Yes |

.agents/skills/transformerlab-cli/references/commands.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,17 @@ Get details for a specific task.
9898
{"id": 1, "name": "my-task", "type": "TRAINING", "config": {...}, ...}
9999
```
100100

101+
### `task init`
102+
103+
Scaffold a new task in the current directory. **Prefer this over writing `task.yaml` by hand.** Does not require an experiment to be set.
104+
105+
| Option | Description |
106+
|---|---|
107+
| (default, no flag) | Non-interactive. Creates `task.yaml` with defaults (`name` = folder name, `cpus: 2`, `memory: 4`, `run: python main.py`) and a starter `main.py`. Existing files are skipped, not overwritten. |
108+
| `--interactive` | Prompts for task name, CPUs, memory, accelerators, setup, and run command. Writes only `task.yaml` (no `main.py`). Prompts before overwriting an existing `task.yaml`. |
109+
110+
**JSON output (default):** `{"created": ["task.yaml", "main.py"], "skipped": [], "path": "/abs/dir"}`
111+
101112
### `task add [directory]`
102113

103114
Add a new task from a local directory containing `task.yaml`, or from a Git repository.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Gallery Channel Bundles
2+
3+
on:
4+
pull_request:
5+
branches: ["main"]
6+
paths:
7+
- "api/transformerlab/galleries/src/**"
8+
- "api/transformerlab/galleries/combine_subset_galleries.py"
9+
push:
10+
branches: ["main"]
11+
paths:
12+
- "api/transformerlab/galleries/src/**"
13+
- "api/transformerlab/galleries/combine_subset_galleries.py"
14+
15+
jobs:
16+
verify-bundle-updated:
17+
runs-on: ubuntu-latest
18+
defaults:
19+
run:
20+
working-directory: api
21+
steps:
22+
- uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0
25+
- name: Set up Python 3.11
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: "3.11"
29+
- name: Require stable/beta bundle update for source changes
30+
shell: bash
31+
run: |
32+
if [ "${{ github.event_name }}" = "pull_request" ]; then
33+
BASE_SHA="${{ github.event.pull_request.base.sha }}"
34+
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
35+
else
36+
BASE_SHA="${{ github.event.before }}"
37+
HEAD_SHA="${{ github.sha }}"
38+
fi
39+
40+
CHANGED="$(git diff --name-only "${BASE_SHA}" "${HEAD_SHA}")"
41+
echo "Changed files between ${BASE_SHA} and ${HEAD_SHA}:"
42+
printf '%s\n' "${CHANGED}"
43+
44+
if printf '%s\n' "${CHANGED}" | grep -E '^api/transformerlab/galleries/channels/(stable|beta)/latest/' > /dev/null; then
45+
echo "Bundle update detected under stable/beta latest."
46+
exit 0
47+
fi
48+
49+
echo "ERROR: galleries/src changed, but no stable/beta bundle update was committed."
50+
echo "Update either:"
51+
echo " - api/transformerlab/galleries/channels/stable/latest/*"
52+
echo " - api/transformerlab/galleries/channels/beta/latest/*"
53+
exit 1

api/test/shared/test_galleries.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from transformerlab.shared import galleries
2+
3+
4+
def test_channel_manifests_reject_too_new_min_version():
5+
manifest = {
6+
"channel": "stable",
7+
"min_supported_app_version": "0.30.0",
8+
}
9+
10+
assert galleries.is_manifest_version_compatible(manifest, "0.27.0") is False
11+
12+
13+
def test_channel_manifests_accept_matching_version_range():
14+
manifest = {
15+
"channel": "stable",
16+
"min_supported_app_version": "0.20.0",
17+
"max_supported_app_version": "0.29.0",
18+
}
19+
20+
assert galleries.is_manifest_version_compatible(manifest, "0.27.0") is True
21+
22+
23+
def test_only_selected_galleries_use_channel_fetch():
24+
assert galleries.should_use_channel_bundle(galleries.TASKS_GALLERY_FILE) is True
25+
assert galleries.should_use_channel_bundle(galleries.INTERACTIVE_GALLERY_FILE) is True
26+
assert galleries.should_use_channel_bundle(galleries.ANNOUNCEMENTS_GALLERY_FILE) is True
27+
assert galleries.should_use_channel_bundle(galleries.TEAM_TASKS_GALLERY_FILE) is False
28+
29+
30+
def test_local_channel_path_uses_selected_channel(monkeypatch, tmp_path):
31+
monkeypatch.setattr(galleries.dirs, "GALLERIES_LOCAL_FALLBACK_DIR", str(tmp_path))
32+
monkeypatch.setenv("TLAB_GALLERY_CHANNEL", "beta")
33+
channel_file = tmp_path / "channels" / "beta" / "latest" / galleries.TASKS_GALLERY_FILE
34+
channel_file.parent.mkdir(parents=True, exist_ok=True)
35+
channel_file.write_text("[]", encoding="utf-8")
36+
37+
resolved = galleries.get_local_gallery_path(galleries.TASKS_GALLERY_FILE)
38+
assert resolved.endswith("channels/beta/latest/task-gallery.json")

api/test/test_disk_space_utils.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Tests for disk_space_utils.parse_disk_space_gb."""
2+
3+
import pytest
4+
5+
from transformerlab.shared.disk_space_utils import parse_disk_space_gb
6+
7+
8+
@pytest.mark.parametrize(
9+
("raw", "expected"),
10+
[
11+
(None, None),
12+
("", None),
13+
(" ", None),
14+
(0, None),
15+
(-1, None),
16+
(50, 50),
17+
("50", 50),
18+
("100GB", 100),
19+
("100gb", 100),
20+
("100 g", 100),
21+
(" 200 GB ", 200),
22+
("100G", 100),
23+
("not-a-number", None),
24+
("12.5", None),
25+
(True, None),
26+
],
27+
)
28+
def test_parse_disk_space_gb(raw, expected):
29+
assert parse_disk_space_gb(raw) == expected

0 commit comments

Comments
 (0)