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: 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 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 ### Troubleshooting

View file

@ -6,15 +6,15 @@
import argparse import argparse
from pathlib import Path from pathlib import Path
from typing import Dict
from llama_stack.cli.subcommand import Subcommand from llama_stack.cli.subcommand import Subcommand
from llama_stack.cli.table import print_table from llama_stack.cli.table import print_table
class StackListBuilds(Subcommand): 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__() super().__init__()
self.parser = subparsers.add_parser( self.parser = subparsers.add_parser(
"list", "list",
@ -24,47 +24,33 @@ class StackListBuilds(Subcommand):
) )
self._add_arguments() self._add_arguments()
self.parser.set_defaults(func=self._list_stack_command) 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""" """Return a dictionary of distribution names and their paths"""
distributions = {} distributions = {}
dist_dir = Path.home() / ".llama" / "distributions" dist_dir = Path.home() / ".llama" / "distributions"
if dist_dir.exists(): if dist_dir.exists():
for stack_dir in dist_dir.iterdir(): for stack_dir in dist_dir.iterdir():
if stack_dir.is_dir(): if stack_dir.is_dir():
distributions[stack_dir.name] = stack_dir distributions[stack_dir.name] = stack_dir
return distributions 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() distributions = self._get_distribution_dirs()
if not distributions: if not distributions:
print("No stacks found in ~/.llama/distributions") print("No stacks found in ~/.llama/distributions")
return return
headers = ["Stack Name", "Path"] headers = ["Stack Name", "Path"]
if args.verbose: headers.extend(["Build Config", "Run Config"])
headers.extend(["Build Config", "Run Config"])
rows = [] rows = []
for name, path in distributions.items(): for name, path in distributions.items():
row = [name, str(path)] row = [name, str(path)]
# Check for build and run config files
if args.verbose: build_config = "Yes" if (path / f"{name}-build.yaml").exists() else "No"
# Check for build and run config files run_config = "Yes" if (path / f"{name}-run.yaml").exists() else "No"
build_config = "Yes" if (path / f"{name}-build.yaml").exists() else "No" row.extend([build_config, run_config])
run_config = "Yes" if (path / f"{name}-run.yaml").exists() else "No"
row.extend([build_config, run_config])
rows.append(row) 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. # the root directory of this source tree.
import argparse import argparse
from pathlib import Path
import shutil 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.subcommand import Subcommand
from llama_stack.cli.table import print_table from llama_stack.cli.table import print_table
class StackRemove(Subcommand): 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__() super().__init__()
self.parser = subparsers.add_parser( self.parser = subparsers.add_parser(
"rm", "rm",
@ -27,25 +29,13 @@ class StackRemove(Subcommand):
self._add_arguments() self._add_arguments()
self.parser.set_defaults(func=self._remove_stack_build_command) self.parser.set_defaults(func=self._remove_stack_build_command)
def _add_arguments(self) -> None: def _add_arguments(self) -> None:
self.parser.add_argument( self.parser.add_argument(
"name", "name",
type=str, type=str,
nargs="?", nargs="?",
help="Name of the stack to delete", 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( self.parser.add_argument(
"--all", "--all",
"-a", "-a",
@ -53,18 +43,18 @@ class StackRemove(Subcommand):
help="Delete all stacks (use with caution)", 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""" """Return a dictionary of distribution names and their paths"""
distributions = {} distributions = {}
dist_dir = Path.home() / ".llama" / "distributions" dist_dir = Path.home() / ".llama" / "distributions"
if dist_dir.exists(): if dist_dir.exists():
for stack_dir in dist_dir.iterdir(): for stack_dir in dist_dir.iterdir():
if stack_dir.is_dir(): if stack_dir.is_dir():
distributions[stack_dir.name] = stack_dir distributions[stack_dir.name] = stack_dir
return distributions return distributions
def _list_stacks(self) -> None: def _list_stacks(self) -> None:
"""Display available stacks in a table""" """Display available stacks in a table"""
distributions = self._get_distribution_dirs() distributions = self._get_distribution_dirs()
if not distributions: if not distributions:
@ -75,44 +65,52 @@ class StackRemove(Subcommand):
rows = [[name, str(path)] for name, path in distributions.items()] rows = [[name, str(path)] for name, path in distributions.items()]
print_table(rows, headers, separate_rows=True) 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() distributions = self._get_distribution_dirs()
if args.all: if args.all:
if not args.force: confirm = input("Are you sure you want to delete ALL stacks? [yes-i-really-want/N] ").lower()
confirm = input("Are you sure you want to delete ALL stacks? [y/N] ").lower() if confirm != "yes-i-really-want":
if confirm != 'y': print("Deletion cancelled.")
print("Deletion cancelled.") return
return
for name, path in distributions.items(): for name, path in distributions.items():
try: try:
shutil.rmtree(path) shutil.rmtree(path)
print(f"Deleted stack: {name}") print(f"Deleted stack: {name}")
except Exception as e: except Exception as e:
print(f"Failed to delete stack {name}: {e}") cprint(
return 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() self._list_stacks()
if not args.name: if not args.name:
return return
if args.name not in distributions: if args.name not in distributions:
self._list_stacks() self._list_stacks()
print(f"Stack not found: {args.name}") cprint(
f"Stack not found: {args.name}",
color="red",
)
return return
stack_path = distributions[args.name] 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()
confirm = input(f"Are you sure you want to delete stack '{args.name}'? [y/N] ").lower() if confirm != "y":
if confirm != 'y': print("Deletion cancelled.")
print("Deletion cancelled.") return
return
try: try:
shutil.rmtree(stack_path) shutil.rmtree(stack_path)
print(f"Successfully deleted stack: {args.name}") print(f"Successfully deleted stack: {args.name}")
except Exception as e: 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 .build import StackBuild
from .list_apis import StackListApis from .list_apis import StackListApis
from .list_providers import StackListProviders from .list_providers import StackListProviders
from .run import StackRun
from .remove import StackRemove from .remove import StackRemove
from .run import StackRun
class StackParser(Subcommand): class StackParser(Subcommand):