feat: add llama stack rm and llama stack list commands

This commit is contained in:
Abhishek koserwal 2025-05-13 13:41:33 +05:30 committed by Abhishek koserwal
parent d8712c4242
commit c482dfb5f7
4 changed files with 93 additions and 67 deletions

View file

@ -339,6 +339,48 @@ INFO: Application startup complete.
INFO: Uvicorn running on http://['::', '0.0.0.0']:8321 (Press CTRL+C to quit)
INFO: 2401:db00:35c:2d2b:face:0:c9:0:54678 - "GET /models/list HTTP/1.1" 200 OK
```
### Listing Distributions
Using the list command, you can view all existing Llama Stack distributions, including stacks built from templates, from scratch, or using custom configuration files.
```
llama stack list -h
usage: llama stack list [-h]
list the build stacks
options:
-h, --help show this help message and exit
```
Example Usage
```
llama stack list
```
### Removing a Distribution
Use the remove command to delete a distribution you've previously built.
```
llama stack rm -h
usage: llama stack rm [-h] [--all] [name]
Remove the build stack
positional arguments:
name Name of the stack to delete (default: None)
options:
-h, --help show this help message and exit
--all, -a Delete all stacks (use with caution) (default: False)
```
Example
```
llama stack rm llamastack-test
```
To keep your environment organized and avoid clutter, consider using `llama stack list` to review old or unused distributions and `llama stack rm <name>` to delete them when theyre no longer needed.
### Troubleshooting

View file

@ -6,15 +6,15 @@
import argparse
from pathlib import Path
from typing import Dict
from llama_stack.cli.subcommand import Subcommand
from llama_stack.cli.table import print_table
class StackListBuilds(Subcommand):
"""List built stacks in .llama/distributions directory"""
"""List built stacks in .llama/distributions directory"""
def __init__(self, subparsers: argparse._SubParsersAction):
def __init__(self, subparsers: argparse._SubParsersAction):
super().__init__()
self.parser = subparsers.add_parser(
"list",
@ -24,47 +24,33 @@ class StackListBuilds(Subcommand):
)
self._add_arguments()
self.parser.set_defaults(func=self._list_stack_command)
def _add_arguments(self):
self.parser.add_argument(
"--verbose",
"-v",
action="store_true",
help="Show additional details about each stack",
)
def _get_distribution_dirs(self) -> Dict[str, Path]:
def _get_distribution_dirs(self) -> dict[str, Path]:
"""Return a dictionary of distribution names and their paths"""
distributions = {}
dist_dir = Path.home() / ".llama" / "distributions"
if dist_dir.exists():
for stack_dir in dist_dir.iterdir():
if stack_dir.is_dir():
distributions[stack_dir.name] = stack_dir
return distributions
def _list_stack_command(self, args: argparse.Namespace) -> None:
def _list_stack_command(self, args: argparse.Namespace) -> None:
distributions = self._get_distribution_dirs()
if not distributions:
print("No stacks found in ~/.llama/distributions")
return
headers = ["Stack Name", "Path"]
if args.verbose:
headers.extend(["Build Config", "Run Config"])
headers.extend(["Build Config", "Run Config"])
rows = []
for name, path in distributions.items():
row = [name, str(path)]
if args.verbose:
# Check for build and run config files
build_config = "Yes" if (path / f"{name}-build.yaml").exists() else "No"
run_config = "Yes" if (path / f"{name}-run.yaml").exists() else "No"
row.extend([build_config, run_config])
# Check for build and run config files
build_config = "Yes" if (path / f"{name}-build.yaml").exists() else "No"
run_config = "Yes" if (path / f"{name}-run.yaml").exists() else "No"
row.extend([build_config, run_config])
rows.append(row)
print_table(rows, headers, separate_rows=True)
print_table(rows, headers, separate_rows=True)

View file

@ -5,18 +5,20 @@
# the root directory of this source tree.
import argparse
from pathlib import Path
import shutil
from typing import Dict
import sys
from pathlib import Path
from termcolor import cprint
from llama_stack.cli.subcommand import Subcommand
from llama_stack.cli.table import print_table
class StackRemove(Subcommand):
"""Remove the build stack"""
"""Remove the build stack"""
def __init__(self, subparsers: argparse._SubParsersAction):
def __init__(self, subparsers: argparse._SubParsersAction):
super().__init__()
self.parser = subparsers.add_parser(
"rm",
@ -27,25 +29,13 @@ class StackRemove(Subcommand):
self._add_arguments()
self.parser.set_defaults(func=self._remove_stack_build_command)
def _add_arguments(self) -> None:
def _add_arguments(self) -> None:
self.parser.add_argument(
"name",
type=str,
nargs="?",
help="Name of the stack to delete",
)
self.parser.add_argument(
"--list",
"-l",
action="store_true",
help="List available stacks before deletion",
)
self.parser.add_argument(
"--force",
"-f",
action="store_true",
help="Force deletion without confirmation",
)
self.parser.add_argument(
"--all",
"-a",
@ -53,18 +43,18 @@ class StackRemove(Subcommand):
help="Delete all stacks (use with caution)",
)
def _get_distribution_dirs(self) -> Dict[str, Path]:
def _get_distribution_dirs(self) -> dict[str, Path]:
"""Return a dictionary of distribution names and their paths"""
distributions = {}
dist_dir = Path.home() / ".llama" / "distributions"
if dist_dir.exists():
for stack_dir in dist_dir.iterdir():
if stack_dir.is_dir():
distributions[stack_dir.name] = stack_dir
return distributions
def _list_stacks(self) -> None:
def _list_stacks(self) -> None:
"""Display available stacks in a table"""
distributions = self._get_distribution_dirs()
if not distributions:
@ -75,44 +65,52 @@ class StackRemove(Subcommand):
rows = [[name, str(path)] for name, path in distributions.items()]
print_table(rows, headers, separate_rows=True)
def _remove_stack_build_command(self, args: argparse.Namespace) -> None:
def _remove_stack_build_command(self, args: argparse.Namespace) -> None:
distributions = self._get_distribution_dirs()
if args.all:
if not args.force:
confirm = input("Are you sure you want to delete ALL stacks? [y/N] ").lower()
if confirm != 'y':
print("Deletion cancelled.")
return
confirm = input("Are you sure you want to delete ALL stacks? [yes-i-really-want/N] ").lower()
if confirm != "yes-i-really-want":
print("Deletion cancelled.")
return
for name, path in distributions.items():
try:
shutil.rmtree(path)
print(f"Deleted stack: {name}")
except Exception as e:
print(f"Failed to delete stack {name}: {e}")
return
cprint(
f"Failed to delete stack {name}: {e}",
color="red",
)
sys.exit(2)
if args.list or not args.name:
if not args.name:
self._list_stacks()
if not args.name:
return
if args.name not in distributions:
self._list_stacks()
print(f"Stack not found: {args.name}")
cprint(
f"Stack not found: {args.name}",
color="red",
)
return
stack_path = distributions[args.name]
if not args.force:
confirm = input(f"Are you sure you want to delete stack '{args.name}'? [y/N] ").lower()
if confirm != 'y':
print("Deletion cancelled.")
return
confirm = input(f"Are you sure you want to delete stack '{args.name}'? [y/N] ").lower()
if confirm != "y":
print("Deletion cancelled.")
return
try:
shutil.rmtree(stack_path)
print(f"Successfully deleted stack: {args.name}")
except Exception as e:
print(f"Failed to delete stack {args.name}: {e}")
cprint(
f"Failed to delete stack {args.name}: {e}",
color="red",
)
sys.exit(2)

View file

@ -14,8 +14,8 @@ from llama_stack.cli.subcommand import Subcommand
from .build import StackBuild
from .list_apis import StackListApis
from .list_providers import StackListProviders
from .run import StackRun
from .remove import StackRemove
from .run import StackRun
class StackParser(Subcommand):