wafer-cli 0.2.8__py3-none-any.whl → 0.2.10__py3-none-any.whl
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.
- wafer/GUIDE.md +18 -7
- wafer/api_client.py +4 -0
- wafer/auth.py +85 -0
- wafer/cli.py +2339 -404
- wafer/corpus.py +158 -32
- wafer/evaluate.py +1232 -201
- wafer/gpu_run.py +5 -1
- wafer/kernel_scope.py +554 -0
- wafer/nsys_analyze.py +903 -73
- wafer/nsys_profile.py +511 -0
- wafer/output.py +241 -0
- wafer/problems.py +357 -0
- wafer/skills/wafer-guide/SKILL.md +13 -0
- wafer/ssh_keys.py +261 -0
- wafer/target_lock.py +270 -0
- wafer/targets.py +490 -0
- wafer/targets_ops.py +718 -0
- wafer/wevin_cli.py +129 -18
- wafer/workspaces.py +282 -182
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.10.dist-info}/METADATA +1 -1
- wafer_cli-0.2.10.dist-info/RECORD +40 -0
- wafer_cli-0.2.8.dist-info/RECORD +0 -33
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.10.dist-info}/WHEEL +0 -0
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.10.dist-info}/entry_points.txt +0 -0
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.10.dist-info}/top_level.txt +0 -0
wafer/GUIDE.md
CHANGED
|
@@ -8,12 +8,17 @@ Run code on cloud GPUs instantly with workspaces:
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
wafer login # One-time auth
|
|
11
|
-
wafer workspaces create dev --gpu B200 # Create workspace
|
|
11
|
+
wafer workspaces create dev --gpu B200 # Create workspace (NVIDIA B200)
|
|
12
12
|
wafer workspaces exec dev -- python -c "import torch; print(torch.cuda.get_device_name(0))"
|
|
13
13
|
wafer workspaces sync dev ./my-project # Sync files
|
|
14
14
|
wafer workspaces exec dev -- python train.py
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
**Available GPUs:**
|
|
18
|
+
|
|
19
|
+
- `MI300X` - AMD Instinct MI300X (192GB HBM3, ROCm)
|
|
20
|
+
- `B200` - NVIDIA Blackwell B200 (180GB HBM3e, CUDA) - default
|
|
21
|
+
|
|
17
22
|
## Documentation Lookup
|
|
18
23
|
|
|
19
24
|
Answer GPU programming questions from indexed documentation.
|
|
@@ -83,13 +88,19 @@ wafer agent -t optimize-kernel \
|
|
|
83
88
|
|
|
84
89
|
Cloud GPU environments with no setup required.
|
|
85
90
|
|
|
91
|
+
**Available GPUs:**
|
|
92
|
+
|
|
93
|
+
- `MI300X` - AMD Instinct MI300X (192GB HBM3, ROCm)
|
|
94
|
+
- `B200` - NVIDIA Blackwell B200 (180GB HBM3e, CUDA) - default
|
|
95
|
+
|
|
86
96
|
```bash
|
|
87
|
-
wafer workspaces create dev --gpu B200 #
|
|
88
|
-
wafer workspaces
|
|
89
|
-
wafer workspaces
|
|
90
|
-
wafer workspaces
|
|
91
|
-
wafer workspaces
|
|
92
|
-
wafer workspaces
|
|
97
|
+
wafer workspaces create dev --gpu B200 --wait # NVIDIA B200
|
|
98
|
+
wafer workspaces create amd-dev --gpu MI300X # AMD MI300X
|
|
99
|
+
wafer workspaces list # List all
|
|
100
|
+
wafer workspaces sync dev ./project # Sync files
|
|
101
|
+
wafer workspaces exec dev -- ./run.sh # Run commands
|
|
102
|
+
wafer workspaces ssh dev # Interactive SSH
|
|
103
|
+
wafer workspaces delete dev # Cleanup
|
|
93
104
|
```
|
|
94
105
|
|
|
95
106
|
See `wafer workspaces --help` for details.
|
wafer/api_client.py
CHANGED
|
@@ -108,6 +108,7 @@ def run_command_stream(
|
|
|
108
108
|
upload_dir: Path | None = None,
|
|
109
109
|
workspace_id: str | None = None,
|
|
110
110
|
gpu_id: int | None = None,
|
|
111
|
+
gpu_count: int = 1,
|
|
111
112
|
docker_image: str | None = None,
|
|
112
113
|
docker_entrypoint: str | None = None,
|
|
113
114
|
pull_image: bool = False,
|
|
@@ -125,6 +126,7 @@ def run_command_stream(
|
|
|
125
126
|
upload_dir: Directory to upload (stateless mode)
|
|
126
127
|
workspace_id: Workspace ID from push (low-level mode)
|
|
127
128
|
gpu_id: GPU ID to use (optional)
|
|
129
|
+
gpu_count: Number of GPUs needed (1-8, default 1)
|
|
128
130
|
docker_image: Docker image override (optional)
|
|
129
131
|
docker_entrypoint: Docker entrypoint override (optional, e.g., "bash")
|
|
130
132
|
pull_image: Pull image if not available (optional, default False)
|
|
@@ -152,6 +154,8 @@ def run_command_stream(
|
|
|
152
154
|
|
|
153
155
|
if gpu_id is not None:
|
|
154
156
|
request_body["gpu_id"] = gpu_id
|
|
157
|
+
if gpu_count > 1:
|
|
158
|
+
request_body["gpu_count"] = gpu_count
|
|
155
159
|
if docker_image is not None:
|
|
156
160
|
request_body["docker_image"] = docker_image
|
|
157
161
|
if docker_entrypoint is not None:
|
wafer/auth.py
CHANGED
|
@@ -345,3 +345,88 @@ def browser_login(timeout: int = 120, port: int | None = None) -> tuple[str, str
|
|
|
345
345
|
|
|
346
346
|
server.server_close()
|
|
347
347
|
raise TimeoutError(f"No response within {timeout} seconds")
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def device_code_login(timeout: int = 600) -> tuple[str, str | None]:
|
|
351
|
+
"""Authenticate using state-based flow (no browser/port forwarding needed).
|
|
352
|
+
|
|
353
|
+
This is the SSH-friendly auth flow similar to GitHub CLI:
|
|
354
|
+
1. Request a state token from the API
|
|
355
|
+
2. Display the auth URL with state parameter
|
|
356
|
+
3. User visits URL on any device and signs in normally
|
|
357
|
+
4. Poll API until user completes authentication
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
timeout: Seconds to wait for authentication (default 600 = 10 minutes)
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Tuple of (access_token, refresh_token). refresh_token may be None.
|
|
364
|
+
|
|
365
|
+
Raises:
|
|
366
|
+
TimeoutError: If user doesn't authenticate within timeout
|
|
367
|
+
RuntimeError: If auth flow failed
|
|
368
|
+
"""
|
|
369
|
+
api_url = get_api_url()
|
|
370
|
+
|
|
371
|
+
# Request state and auth URL
|
|
372
|
+
with httpx.Client(timeout=10.0) as client:
|
|
373
|
+
response = client.post(f"{api_url}/v1/auth/cli-auth/start", json={})
|
|
374
|
+
response.raise_for_status()
|
|
375
|
+
data = response.json()
|
|
376
|
+
|
|
377
|
+
state = data["state"]
|
|
378
|
+
auth_url = data["auth_url"]
|
|
379
|
+
expires_in = data["expires_in"]
|
|
380
|
+
|
|
381
|
+
# Display instructions to user
|
|
382
|
+
print("\n" + "=" * 60)
|
|
383
|
+
print(" WAFER CLI - Authentication")
|
|
384
|
+
print("=" * 60)
|
|
385
|
+
print(f"\n Visit: {auth_url}")
|
|
386
|
+
print("\n Sign in with GitHub to complete authentication")
|
|
387
|
+
print("\n" + "=" * 60 + "\n")
|
|
388
|
+
|
|
389
|
+
# Poll for authentication
|
|
390
|
+
start = time.time()
|
|
391
|
+
poll_interval = 5 # Poll every 5 seconds
|
|
392
|
+
last_poll = 0.0
|
|
393
|
+
|
|
394
|
+
print("Waiting for authentication", end="", flush=True)
|
|
395
|
+
|
|
396
|
+
while time.time() - start < min(timeout, expires_in):
|
|
397
|
+
# Show progress dots
|
|
398
|
+
if time.time() - last_poll >= poll_interval:
|
|
399
|
+
print(".", end="", flush=True)
|
|
400
|
+
|
|
401
|
+
# Poll the API
|
|
402
|
+
with httpx.Client(timeout=10.0) as client:
|
|
403
|
+
try:
|
|
404
|
+
response = client.post(f"{api_url}/v1/auth/cli-auth/token", json={"state": state})
|
|
405
|
+
|
|
406
|
+
if response.status_code == 200:
|
|
407
|
+
# Success!
|
|
408
|
+
data = response.json()
|
|
409
|
+
print(f" {CHECK}\n")
|
|
410
|
+
return data["access_token"], data.get("refresh_token")
|
|
411
|
+
|
|
412
|
+
if response.status_code == 428:
|
|
413
|
+
# Still waiting
|
|
414
|
+
last_poll = time.time()
|
|
415
|
+
time.sleep(1)
|
|
416
|
+
continue
|
|
417
|
+
|
|
418
|
+
# Some other error
|
|
419
|
+
print(f" {CROSS}\n")
|
|
420
|
+
raise RuntimeError(f"CLI auth flow failed: {response.status_code} {response.text}")
|
|
421
|
+
|
|
422
|
+
except httpx.RequestError as e:
|
|
423
|
+
# Network error, retry
|
|
424
|
+
print("!", end="", flush=True)
|
|
425
|
+
last_poll = time.time()
|
|
426
|
+
time.sleep(1)
|
|
427
|
+
continue
|
|
428
|
+
|
|
429
|
+
time.sleep(0.5) # Small sleep to avoid busy loop
|
|
430
|
+
|
|
431
|
+
print(f" {CROSS}\n")
|
|
432
|
+
raise TimeoutError(f"Authentication not completed within {expires_in} seconds")
|