Skip to content

Commit 61614c3

Browse files
committed
feat(cli): enhance hardware command to display availability status
Add formatted table output for hardware options showing: - Hardware ID - GPU type, count, and memory - Availability status with color-coded indicators - Pricing information Changes: - Add format_hardware_table() function for formatted table display - Update fetch_and_print_hardware_options() to use new table format - Show availability column only when model is specified - Color-coded status: green (available), red (unavailable), yellow (insufficient) Resolves: MLE-2935
1 parent f6ff8d4 commit 61614c3

File tree

1 file changed

+63
-6
lines changed

1 file changed

+63
-6
lines changed

src/together/cli/api/endpoints.py

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import json
44
import sys
55
from functools import wraps
6-
from typing import Any, Callable, Dict, List, Literal, TypeVar, Union
6+
from typing import Any, Callable, Dict, List, Literal, Sequence, TypeVar, Union
77

88
import click
99

1010
from together import Together
1111
from together.error import InvalidRequestError
1212
from together.types import DedicatedEndpoint, ListEndpoint
13+
from together.types.endpoints import HardwareWithStatus
1314

1415

1516
def print_endpoint(
@@ -258,28 +259,84 @@ def hardware(client: Together, model: str | None, json: bool, available: bool) -
258259
fetch_and_print_hardware_options(client, model, json, available)
259260

260261

262+
def format_hardware_table(
263+
hardware_options: Sequence[HardwareWithStatus],
264+
show_availability: bool = True,
265+
) -> None:
266+
"""Print hardware options in a formatted table."""
267+
if not hardware_options:
268+
click.echo(" No hardware options found.", err=True)
269+
return
270+
271+
# Calculate column widths
272+
id_width = max(len(h.id) for h in hardware_options)
273+
id_width = max(id_width, len("HARDWARE ID"))
274+
275+
# Print header
276+
if show_availability:
277+
header = f" {'HARDWARE ID':<{id_width}} {'GPU':<12} {'COUNT':<5} {'MEMORY':<8} {'STATUS':<12} {'PRICE':<12}"
278+
separator = f" {'-' * id_width} {'-' * 12} {'-' * 5} {'-' * 8} {'-' * 12} {'-' * 12}"
279+
else:
280+
header = f" {'HARDWARE ID':<{id_width}} {'GPU':<12} {'COUNT':<5} {'MEMORY':<8} {'PRICE':<12}"
281+
separator = f" {'-' * id_width} {'-' * 12} {'-' * 5} {'-' * 8} {'-' * 12}"
282+
283+
click.echo(header, err=True)
284+
click.echo(separator, err=True)
285+
286+
# Print each hardware option
287+
for hw in hardware_options:
288+
gpu_type = hw.specs.gpu_type if hw.specs else "N/A"
289+
gpu_count = str(hw.specs.gpu_count) if hw.specs else "N/A"
290+
gpu_memory = f"{int(hw.specs.gpu_memory)}GB" if hw.specs else "N/A"
291+
price = f"${hw.pricing.cents_per_minute / 100:.2f}/min" if hw.pricing else "N/A"
292+
293+
if show_availability:
294+
if hw.availability:
295+
status = hw.availability.status
296+
# Add visual indicators for status
297+
if status == "available":
298+
status_display = click.style("✓ available", fg="green")
299+
elif status == "unavailable":
300+
status_display = click.style("✗ unavailable", fg="red")
301+
else: # insufficient
302+
status_display = click.style("⚠ insufficient", fg="yellow")
303+
else:
304+
status_display = "—"
305+
306+
row = f" {hw.id:<{id_width}} {gpu_type:<12} {gpu_count:<5} {gpu_memory:<8} {status_display:<23} {price:<12}"
307+
else:
308+
row = f" {hw.id:<{id_width}} {gpu_type:<12} {gpu_count:<5} {gpu_memory:<8} {price:<12}"
309+
310+
click.echo(row, err=True)
311+
312+
261313
def fetch_and_print_hardware_options(
262314
client: Together, model: str | None, print_json: bool, available: bool
263315
) -> None:
264316
"""Print hardware options for a model."""
265-
266-
message = "Available hardware options:" if available else "All hardware options:"
267-
click.echo(message, err=True)
268317
hardware_options = client.endpoints.list_hardware(model)
318+
269319
if available:
270320
hardware_options = [
271321
hardware
272322
for hardware in hardware_options
273323
if hardware.availability is not None
274324
and hardware.availability.status == "available"
275325
]
326+
message = f"Available hardware options for model '{model}':" if model else "Available hardware options:"
327+
else:
328+
message = f"Hardware options for model '{model}':" if model else "All hardware options:"
329+
330+
click.echo(message, err=True)
331+
click.echo("", err=True)
276332

277333
if print_json:
278334
json_output = [hardware.model_dump() for hardware in hardware_options]
279335
click.echo(json.dumps(json_output, indent=2))
280336
else:
281-
for hardware in hardware_options:
282-
click.echo(f" {hardware.id}", err=True)
337+
# Show availability column only when model is specified (availability info is only returned with model filter)
338+
show_availability = model is not None
339+
format_hardware_table(hardware_options, show_availability=show_availability)
283340

284341

285342
@endpoints.command()

0 commit comments

Comments
 (0)