agentstack-cli 0.5.1rc2__tar.gz → 0.5.2__tar.gz
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.
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/PKG-INFO +1 -1
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/pyproject.toml +1 -1
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/__init__.py +19 -13
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/async_typer.py +8 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/agent.py +34 -17
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/build.py +2 -2
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/model.py +8 -5
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/__init__.py +19 -12
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/base_driver.py +24 -10
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/lima_driver.py +4 -3
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/wsl_driver.py +5 -1
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/user.py +2 -4
- agentstack_cli-0.5.2/src/agentstack_cli/data/helm-chart.tgz +0 -0
- agentstack_cli-0.5.1rc2/src/agentstack_cli/commands/mcp.py +0 -150
- agentstack_cli-0.5.1rc2/src/agentstack_cli/data/helm-chart.tgz +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/README.md +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/api.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/auth_manager.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/__init__.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/istio.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/self.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/server.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/configuration.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/console.py +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/data/.gitignore +0 -0
- {agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/utils.py +0 -0
|
@@ -10,7 +10,6 @@ import typer
|
|
|
10
10
|
|
|
11
11
|
import agentstack_cli.commands.agent
|
|
12
12
|
import agentstack_cli.commands.build
|
|
13
|
-
import agentstack_cli.commands.mcp
|
|
14
13
|
import agentstack_cli.commands.model
|
|
15
14
|
import agentstack_cli.commands.platform
|
|
16
15
|
import agentstack_cli.commands.self
|
|
@@ -29,14 +28,14 @@ Usage: agentstack [OPTIONS] COMMAND [ARGS]...
|
|
|
29
28
|
╭─ Getting Started ──────────────────────────────────────────────────────────╮
|
|
30
29
|
│ ui Launch the web interface │
|
|
31
30
|
│ list View all available agents │
|
|
31
|
+
│ info Show agent details │
|
|
32
32
|
│ run Run an agent interactively │
|
|
33
33
|
╰────────────────────────────────────────────────────────────────────────────╯
|
|
34
34
|
|
|
35
|
-
╭─ Agent Management
|
|
35
|
+
╭─ Agent Management [Admin only] ────────────────────────────────────────────╮
|
|
36
36
|
│ add Install an agent (Docker, GitHub) │
|
|
37
37
|
│ remove Uninstall an agent │
|
|
38
38
|
│ update Update an agent │
|
|
39
|
-
│ info Show agent details │
|
|
40
39
|
│ logs Stream agent execution logs │
|
|
41
40
|
│ env Manage agent environment variables │
|
|
42
41
|
│ build Build an agent remotely │
|
|
@@ -44,13 +43,13 @@ Usage: agentstack [OPTIONS] COMMAND [ARGS]...
|
|
|
44
43
|
╰────────────────────────────────────────────────────────────────────────────╯
|
|
45
44
|
|
|
46
45
|
╭─ Platform & Configuration ─────────────────────────────────────────────────╮
|
|
47
|
-
│ model Configure 15+ LLM providers
|
|
48
|
-
│ platform Start, stop, or delete local platform
|
|
46
|
+
│ model Configure 15+ LLM providers [Admin only] │
|
|
47
|
+
│ platform Start, stop, or delete local platform [Local only] │
|
|
49
48
|
│ server Connect to remote Agent Stack servers │
|
|
50
|
-
│ user Manage users and roles
|
|
49
|
+
│ user Manage users and roles [Admin only] │
|
|
51
50
|
│ self version Show Agent Stack CLI and Platform version │
|
|
52
|
-
│ self upgrade Upgrade Agent Stack CLI and Platform
|
|
53
|
-
│ self uninstall Uninstall Agent Stack CLI and Platform
|
|
51
|
+
│ self upgrade Upgrade Agent Stack CLI and Platform [Local only] │
|
|
52
|
+
│ self uninstall Uninstall Agent Stack CLI and Platform [Local only] │
|
|
54
53
|
╰────────────────────────────────────────────────────────────────────────────╯
|
|
55
54
|
|
|
56
55
|
╭─ Options ──────────────────────────────────────────────────────────────────╮
|
|
@@ -74,13 +73,20 @@ def main(
|
|
|
74
73
|
raise typer.Exit()
|
|
75
74
|
|
|
76
75
|
|
|
77
|
-
app.add_typer(agentstack_cli.commands.model.app, name="model", no_args_is_help=True, help="Manage model providers.")
|
|
78
|
-
app.add_typer(agentstack_cli.commands.agent.app, name="agent", no_args_is_help=True, help="Manage agents.")
|
|
79
76
|
app.add_typer(
|
|
80
|
-
agentstack_cli.commands.
|
|
77
|
+
agentstack_cli.commands.model.app, name="model", no_args_is_help=True, help="Manage model providers. [Admin only]"
|
|
81
78
|
)
|
|
82
79
|
app.add_typer(
|
|
83
|
-
agentstack_cli.commands.
|
|
80
|
+
agentstack_cli.commands.agent.app,
|
|
81
|
+
name="agent",
|
|
82
|
+
no_args_is_help=True,
|
|
83
|
+
help="Manage agents. Some commands are [Admin only].",
|
|
84
|
+
)
|
|
85
|
+
app.add_typer(
|
|
86
|
+
agentstack_cli.commands.platform.app,
|
|
87
|
+
name="platform",
|
|
88
|
+
no_args_is_help=True,
|
|
89
|
+
help="Manage Agent Stack platform. [Local only]",
|
|
84
90
|
)
|
|
85
91
|
app.add_typer(agentstack_cli.commands.build.app, name="", no_args_is_help=True, help="Build agent images.")
|
|
86
92
|
app.add_typer(
|
|
@@ -100,7 +106,7 @@ app.add_typer(
|
|
|
100
106
|
agentstack_cli.commands.user.app,
|
|
101
107
|
name="user",
|
|
102
108
|
no_args_is_help=True,
|
|
103
|
-
help="Manage users.",
|
|
109
|
+
help="Manage users. [Admin only]",
|
|
104
110
|
)
|
|
105
111
|
|
|
106
112
|
|
|
@@ -82,15 +82,23 @@ class AsyncTyper(typer.Typer):
|
|
|
82
82
|
else:
|
|
83
83
|
return f(*args, **kwargs)
|
|
84
84
|
except* Exception as ex:
|
|
85
|
+
is_permission_error = False
|
|
85
86
|
is_connect_error = False
|
|
86
87
|
for exc_type, message in extract_messages(ex):
|
|
87
88
|
err_console.print(format_error(exc_type, message))
|
|
88
89
|
is_connect_error = is_connect_error or exc_type in ["ConnectionError", "ConnectError"]
|
|
90
|
+
is_permission_error = is_permission_error or (
|
|
91
|
+
exc_type == "HTTPStatusError" and "403" in message
|
|
92
|
+
)
|
|
89
93
|
err_console.print()
|
|
90
94
|
if is_connect_error:
|
|
91
95
|
err_console.hint(
|
|
92
96
|
"Start the Agent Stack platform using: [green]agentstack platform start[/green]. If that does not help, run [green]agentstack platform delete[/green] to clean up, then [green]agentstack platform start[/green] again."
|
|
93
97
|
)
|
|
98
|
+
elif is_permission_error:
|
|
99
|
+
err_console.hint(
|
|
100
|
+
"This command requires higher permissions than your account currently has. Contact your administrator for assistance."
|
|
101
|
+
)
|
|
94
102
|
else:
|
|
95
103
|
err_console.hint(
|
|
96
104
|
"Are you having consistent problems? If so, try these troubleshooting steps: [green]agentstack platform delete[/green] to remove the platform, and [green]agentstack platform start[/green] to recreate it."
|
|
@@ -151,16 +151,32 @@ class ProviderUtils(BaseModel):
|
|
|
151
151
|
app = AsyncTyper()
|
|
152
152
|
|
|
153
153
|
processing_messages = [
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
154
|
+
"Asking agents...",
|
|
155
|
+
"Booting up bots...",
|
|
156
|
+
"Calibrating cognition...",
|
|
157
|
+
"Directing drones...",
|
|
158
|
+
"Engaging engines...",
|
|
159
|
+
"Fetching functions...",
|
|
160
|
+
"Gathering goals...",
|
|
161
|
+
"Hardening hypotheses...",
|
|
162
|
+
"Interpreting intentions...",
|
|
163
|
+
"Juggling judgements...",
|
|
164
|
+
"Kernelizing knowledge...",
|
|
165
|
+
"Loading logic...",
|
|
166
|
+
"Mobilizing models...",
|
|
167
|
+
"Nudging networks...",
|
|
168
|
+
"Optimizing outputs...",
|
|
169
|
+
"Prompting pipelines...",
|
|
170
|
+
"Quantizing queries...",
|
|
171
|
+
"Refining responses...",
|
|
172
|
+
"Scaling stacks...",
|
|
173
|
+
"Tuning transformers...",
|
|
174
|
+
"Unifying understandings...",
|
|
175
|
+
"Vectorizing values...",
|
|
176
|
+
"Wiring workflows...",
|
|
177
|
+
"Xecuting xperiments...",
|
|
178
|
+
"Yanking YAMLs...",
|
|
179
|
+
"Zipping zettabytes...",
|
|
164
180
|
]
|
|
165
181
|
|
|
166
182
|
configuration = Configuration()
|
|
@@ -175,7 +191,7 @@ async def add_agent(
|
|
|
175
191
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
176
192
|
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
177
193
|
) -> None:
|
|
178
|
-
"""Add a docker image or GitHub repository.
|
|
194
|
+
"""Add a docker image or GitHub repository. [Admin only]
|
|
179
195
|
|
|
180
196
|
This command supports a variety of GitHub URL formats for deploying agents:
|
|
181
197
|
|
|
@@ -260,7 +276,7 @@ async def update_agent(
|
|
|
260
276
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
261
277
|
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
262
278
|
) -> None:
|
|
263
|
-
"""Upgrade agent to a newer docker image or build from GitHub repository"""
|
|
279
|
+
"""Upgrade agent to a newer docker image or build from GitHub repository. [Admin only]"""
|
|
264
280
|
with verbosity(verbose):
|
|
265
281
|
async with configuration.use_platform_client():
|
|
266
282
|
providers = await Provider.list()
|
|
@@ -389,7 +405,7 @@ async def uninstall_agent(
|
|
|
389
405
|
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
390
406
|
all: typing.Annotated[bool, typer.Option("--all", "-a", help="Remove all agents without selection.")] = False,
|
|
391
407
|
) -> None:
|
|
392
|
-
"""Remove agent"""
|
|
408
|
+
"""Remove agent. [Admin only]"""
|
|
393
409
|
if search_path and all:
|
|
394
410
|
console.error(
|
|
395
411
|
"[bold]Cannot specify both --all and a search path."
|
|
@@ -440,7 +456,7 @@ async def stream_logs(
|
|
|
440
456
|
str, typer.Argument(..., help="Short ID, agent name or part of the provider location")
|
|
441
457
|
],
|
|
442
458
|
):
|
|
443
|
-
"""Stream agent provider logs"""
|
|
459
|
+
"""Stream agent provider logs. [Admin only]"""
|
|
444
460
|
announce_server_action(f"Streaming logs for '{search_path}' from")
|
|
445
461
|
async with configuration.use_platform_client():
|
|
446
462
|
provider = select_provider(search_path, await Provider.list()).id
|
|
@@ -1270,7 +1286,7 @@ async def add_env(
|
|
|
1270
1286
|
env: typing.Annotated[list[str], typer.Argument(help="Environment variables to pass to agent")],
|
|
1271
1287
|
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
1272
1288
|
) -> None:
|
|
1273
|
-
"""Store environment variables"""
|
|
1289
|
+
"""Store environment variables. [Admin only]"""
|
|
1274
1290
|
url = announce_server_action(f"Adding environment variables for '{search_path}' on")
|
|
1275
1291
|
await confirm_server_action("Apply these environment variable changes on", url=url, yes=yes)
|
|
1276
1292
|
env_vars = dict(parse_env_var(var) for var in env)
|
|
@@ -1286,7 +1302,7 @@ async def list_env(
|
|
|
1286
1302
|
str, typer.Argument(..., help="Short ID, agent name or part of the provider location")
|
|
1287
1303
|
],
|
|
1288
1304
|
):
|
|
1289
|
-
"""List stored environment variables"""
|
|
1305
|
+
"""List stored environment variables. [Admin only]"""
|
|
1290
1306
|
announce_server_action(f"Listing environment variables for '{search_path}' on")
|
|
1291
1307
|
async with configuration.use_platform_client():
|
|
1292
1308
|
provider = select_provider(search_path, await Provider.list())
|
|
@@ -1301,6 +1317,7 @@ async def remove_env(
|
|
|
1301
1317
|
env: typing.Annotated[list[str], typer.Argument(help="Environment variable(s) to remove")],
|
|
1302
1318
|
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
1303
1319
|
):
|
|
1320
|
+
"""Remove environment variable(s). [Admin only]"""
|
|
1304
1321
|
url = announce_server_action(f"Removing environment variables from '{search_path}' on")
|
|
1305
1322
|
await confirm_server_action("Remove the selected environment variables on", url=url, yes=yes)
|
|
1306
1323
|
async with configuration.use_platform_client():
|
|
@@ -1321,7 +1338,7 @@ async def list_feedback(
|
|
|
1321
1338
|
limit: typing.Annotated[int, typer.Option("--limit", help="Number of results per page [default: 50]")] = 50,
|
|
1322
1339
|
after_cursor: typing.Annotated[str | None, typer.Option("--after", help="Cursor for pagination")] = None,
|
|
1323
1340
|
):
|
|
1324
|
-
"""List your agent feedback"""
|
|
1341
|
+
"""List your agent feedback. [Admin only]"""
|
|
1325
1342
|
|
|
1326
1343
|
announce_server_action("Listing feedback on")
|
|
1327
1344
|
|
|
@@ -61,7 +61,7 @@ async def client_side_build(
|
|
|
61
61
|
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
62
62
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
63
63
|
):
|
|
64
|
-
"""Build agent locally using Docker."""
|
|
64
|
+
"""Build agent locally using Docker. [Local only]"""
|
|
65
65
|
with verbosity(verbose):
|
|
66
66
|
await run_command(["which", "docker"], "Checking docker")
|
|
67
67
|
image_id = "agentstack-agent-build-tmp:latest"
|
|
@@ -210,7 +210,7 @@ async def server_side_build(
|
|
|
210
210
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
211
211
|
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
212
212
|
):
|
|
213
|
-
"""Build agent from a GitHub repository in the platform."""
|
|
213
|
+
"""Build agent from a GitHub repository in the platform. [Admin only]"""
|
|
214
214
|
|
|
215
215
|
url = announce_server_action(f"Starting build for '{github_url}' on")
|
|
216
216
|
await confirm_server_action("Proceed with building this agent on", url=url, yes=yes)
|
|
@@ -379,6 +379,7 @@ async def _select_default_model(capability: ModelCapability) -> str | None:
|
|
|
379
379
|
|
|
380
380
|
@app.command("list")
|
|
381
381
|
async def list_models():
|
|
382
|
+
"""List all available models."""
|
|
382
383
|
announce_server_action("Listing models on")
|
|
383
384
|
async with configuration.use_platform_client():
|
|
384
385
|
config = await SystemConfiguration.get()
|
|
@@ -411,7 +412,7 @@ async def _reset_configuration(existing_providers: list[ModelProvider] | None =
|
|
|
411
412
|
await SystemConfiguration.update(default_embedding_model=None, default_llm_model=None)
|
|
412
413
|
|
|
413
414
|
|
|
414
|
-
@app.command("setup")
|
|
415
|
+
@app.command("setup", help="Interactive setup for LLM and embedding provider environment variables [Admin only]")
|
|
415
416
|
async def setup(
|
|
416
417
|
use_true_localhost: typing.Annotated[bool, typer.Option(hidden=True)] = False,
|
|
417
418
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
@@ -477,7 +478,7 @@ async def setup(
|
|
|
477
478
|
raise
|
|
478
479
|
|
|
479
480
|
|
|
480
|
-
@app.command("change | select | default")
|
|
481
|
+
@app.command("change | select | default", help="Change the default model [Admin only]")
|
|
481
482
|
async def select_default_model(
|
|
482
483
|
capability: typing.Annotated[
|
|
483
484
|
ModelCapability | None, typer.Argument(help="Which default model to change (llm/embedding)")
|
|
@@ -524,19 +525,21 @@ def _list_providers(providers: list[ModelProvider]):
|
|
|
524
525
|
|
|
525
526
|
@model_provider_app.command("list")
|
|
526
527
|
async def list_model_providers():
|
|
528
|
+
"""List all available model providers."""
|
|
527
529
|
announce_server_action("Listing model providers on")
|
|
528
530
|
async with configuration.use_platform_client():
|
|
529
531
|
providers = await ModelProvider.list()
|
|
530
532
|
_list_providers(providers)
|
|
531
533
|
|
|
532
534
|
|
|
533
|
-
@model_provider_app.command("add")
|
|
535
|
+
@model_provider_app.command("add", help="Add a new model provider [Admin only]")
|
|
534
536
|
@app.command("add")
|
|
535
537
|
async def add_provider(
|
|
536
538
|
capability: typing.Annotated[
|
|
537
539
|
ModelCapability | None, typer.Argument(help="Which default model to change (llm/embedding)")
|
|
538
540
|
] = None,
|
|
539
541
|
):
|
|
542
|
+
"""Add a new model provider. [Admin only]"""
|
|
540
543
|
announce_server_action("Adding provider for")
|
|
541
544
|
if not capability:
|
|
542
545
|
capability = await inquirer.select( # type: ignore
|
|
@@ -577,7 +580,7 @@ def _select_provider(providers: list[ModelProvider], search_path: str) -> ModelP
|
|
|
577
580
|
return selected_provider
|
|
578
581
|
|
|
579
582
|
|
|
580
|
-
@model_provider_app.command("remove | rm | delete")
|
|
583
|
+
@model_provider_app.command("remove | rm | delete", help="Remove a model provider [Admin only]")
|
|
581
584
|
@app.command("remove | rm | delete")
|
|
582
585
|
async def remove_provider(
|
|
583
586
|
search_path: typing.Annotated[
|
|
@@ -639,7 +642,7 @@ async def ensure_llm_provider():
|
|
|
639
642
|
if config.default_llm_model and not inconsistent:
|
|
640
643
|
return
|
|
641
644
|
|
|
642
|
-
console.print("[bold]Welcome to
|
|
645
|
+
console.print("[bold]Welcome to [red]Agent Stack[/red]![/bold]")
|
|
643
646
|
console.print("Let's start by configuring your LLM environment.\n")
|
|
644
647
|
try:
|
|
645
648
|
await setup()
|
{agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/__init__.py
RENAMED
|
@@ -57,7 +57,7 @@ def get_driver(vm_name: str = "agentstack") -> BaseDriver:
|
|
|
57
57
|
sys.exit(1)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
@app.command("start")
|
|
60
|
+
@app.command("start", help="Start Agent Stack platform. [Local only]")
|
|
61
61
|
async def start(
|
|
62
62
|
set_values_list: typing.Annotated[
|
|
63
63
|
list[str], typer.Option("--set", help="Set Helm chart values using <key>=<value> syntax", default_factory=list)
|
|
@@ -68,13 +68,19 @@ async def start(
|
|
|
68
68
|
"--import", help="Import an image from a local Docker CLI into Agent Stack platform", default_factory=list
|
|
69
69
|
),
|
|
70
70
|
],
|
|
71
|
+
pull_on_host: typing.Annotated[
|
|
72
|
+
bool,
|
|
73
|
+
typer.Option(
|
|
74
|
+
"--pull-on-host",
|
|
75
|
+
help="Pull images on host Docker daemon and import them instead of pulling inside the VM. Acts as a pull cache layer.",
|
|
76
|
+
),
|
|
77
|
+
] = False,
|
|
71
78
|
values_file: typing.Annotated[
|
|
72
79
|
pathlib.Path | None, typer.Option("-f", help="Set Helm chart values using yaml values file")
|
|
73
80
|
] = None,
|
|
74
81
|
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
75
82
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
76
83
|
):
|
|
77
|
-
"""Start Agent Stack platform."""
|
|
78
84
|
import agentstack_cli.commands.server
|
|
79
85
|
|
|
80
86
|
values_file_path = None
|
|
@@ -87,7 +93,12 @@ async def start(
|
|
|
87
93
|
driver = get_driver(vm_name=vm_name)
|
|
88
94
|
await driver.create_vm()
|
|
89
95
|
await driver.install_tools()
|
|
90
|
-
await driver.deploy(
|
|
96
|
+
await driver.deploy(
|
|
97
|
+
set_values_list=set_values_list,
|
|
98
|
+
values_file=values_file_path,
|
|
99
|
+
import_images=import_images,
|
|
100
|
+
pull_on_host=pull_on_host,
|
|
101
|
+
)
|
|
91
102
|
|
|
92
103
|
with console.status("Waiting for Agent Stack platform to be ready...", spinner="dots"):
|
|
93
104
|
timeout = datetime.timedelta(minutes=20)
|
|
@@ -124,12 +135,11 @@ async def start(
|
|
|
124
135
|
await agentstack_cli.commands.server.server_login("http://localhost:8333")
|
|
125
136
|
|
|
126
137
|
|
|
127
|
-
@app.command("stop")
|
|
138
|
+
@app.command("stop", help="Stop Agent Stack platform. [Local only]")
|
|
128
139
|
async def stop(
|
|
129
140
|
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
130
141
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
131
142
|
):
|
|
132
|
-
"""Stop Agent Stack platform."""
|
|
133
143
|
with verbosity(verbose):
|
|
134
144
|
driver = get_driver(vm_name=vm_name)
|
|
135
145
|
if not await driver.status():
|
|
@@ -139,40 +149,37 @@ async def stop(
|
|
|
139
149
|
console.success("Agent Stack platform stopped successfully.")
|
|
140
150
|
|
|
141
151
|
|
|
142
|
-
@app.command("delete")
|
|
152
|
+
@app.command("delete", help="Delete Agent Stack platform. [Local only]")
|
|
143
153
|
async def delete(
|
|
144
154
|
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
145
155
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
146
156
|
):
|
|
147
|
-
"""Delete Agent Stack platform."""
|
|
148
157
|
with verbosity(verbose):
|
|
149
158
|
driver = get_driver(vm_name=vm_name)
|
|
150
159
|
await driver.delete()
|
|
151
160
|
console.success("Agent Stack platform deleted successfully.")
|
|
152
161
|
|
|
153
162
|
|
|
154
|
-
@app.command("import")
|
|
163
|
+
@app.command("import", help="Import a local docker image into the Agent Stack platform. [Local only]")
|
|
155
164
|
async def import_image_cmd(
|
|
156
165
|
tag: typing.Annotated[str, typer.Argument(help="Docker image tag to import")],
|
|
157
166
|
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
158
167
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
159
168
|
):
|
|
160
|
-
"""Import a local docker image into the Agent Stack platform."""
|
|
161
169
|
with verbosity(verbose):
|
|
162
170
|
driver = get_driver(vm_name=vm_name)
|
|
163
171
|
if (await driver.status()) != "running":
|
|
164
172
|
console.error("Agent Stack platform is not running.")
|
|
165
173
|
sys.exit(1)
|
|
166
|
-
await driver.
|
|
174
|
+
await driver.import_images(tag)
|
|
167
175
|
|
|
168
176
|
|
|
169
|
-
@app.command("exec")
|
|
177
|
+
@app.command("exec", help="For debugging -- execute a command inside the Agent Stack platform VM. [Local only]")
|
|
170
178
|
async def exec_cmd(
|
|
171
179
|
command: typing.Annotated[list[str] | None, typer.Argument()] = None,
|
|
172
180
|
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
173
181
|
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
174
182
|
):
|
|
175
|
-
"""For debugging -- execute a command inside the Agent Stack platform VM."""
|
|
176
183
|
with verbosity(verbose, show_success_status=False):
|
|
177
184
|
driver = get_driver(vm_name=vm_name)
|
|
178
185
|
if (await driver.status()) != "running":
|
{agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/base_driver.py
RENAMED
|
@@ -15,6 +15,7 @@ from tenacity import AsyncRetrying, stop_after_attempt
|
|
|
15
15
|
|
|
16
16
|
import agentstack_cli.commands.platform.istio
|
|
17
17
|
from agentstack_cli.configuration import Configuration
|
|
18
|
+
from agentstack_cli.utils import run_command
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class BaseDriver(abc.ABC):
|
|
@@ -46,7 +47,7 @@ class BaseDriver(abc.ABC):
|
|
|
46
47
|
async def delete(self) -> None: ...
|
|
47
48
|
|
|
48
49
|
@abc.abstractmethod
|
|
49
|
-
async def
|
|
50
|
+
async def import_images(self, *tags: str) -> None: ...
|
|
50
51
|
|
|
51
52
|
@abc.abstractmethod
|
|
52
53
|
async def import_image_to_internal_registry(self, tag: str) -> None: ...
|
|
@@ -104,6 +105,7 @@ class BaseDriver(abc.ABC):
|
|
|
104
105
|
set_values_list: list[str],
|
|
105
106
|
values_file: pathlib.Path | None = None,
|
|
106
107
|
import_images: list[str] | None = None,
|
|
108
|
+
pull_on_host: bool = False,
|
|
107
109
|
) -> None:
|
|
108
110
|
await self.run_in_vm(
|
|
109
111
|
["sh", "-c", "mkdir -p /tmp/agentstack && cat >/tmp/agentstack/chart.tgz"],
|
|
@@ -140,22 +142,34 @@ class BaseDriver(abc.ABC):
|
|
|
140
142
|
"Listing necessary images",
|
|
141
143
|
)
|
|
142
144
|
).stdout.decode()
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
145
|
+
|
|
146
|
+
def canonify(tag: str) -> str:
|
|
147
|
+
return tag if "." in tag.split("/")[0] else f"docker.io/{tag}"
|
|
148
|
+
|
|
149
|
+
required_images = {canonify(typing.cast(str, yaml.safe_load(line))) for line in images_str.splitlines()}
|
|
150
|
+
images_to_import = {canonify(tag) for tag in import_images or []}
|
|
151
|
+
images_to_pull = required_images - images_to_import
|
|
152
|
+
|
|
153
|
+
if pull_on_host:
|
|
154
|
+
for image in images_to_pull:
|
|
155
|
+
await run_command(["docker", "pull", image], f"Pulling image {image} on host")
|
|
156
|
+
images_to_import = required_images
|
|
157
|
+
images_to_pull = set[str]()
|
|
158
|
+
|
|
159
|
+
if images_to_import:
|
|
160
|
+
await self.import_images(*images_to_import)
|
|
161
|
+
|
|
162
|
+
for image in images_to_pull:
|
|
149
163
|
async for attempt in AsyncRetrying(stop=stop_after_attempt(5)):
|
|
150
164
|
with attempt:
|
|
151
165
|
attempt_num = attempt.retry_state.attempt_number
|
|
152
|
-
image_id = image if "." in image.split("/")[0] else f"docker.io/{image}"
|
|
153
|
-
self.loaded_images.add(image_id)
|
|
154
166
|
await self.run_in_vm(
|
|
155
|
-
["k3s", "ctr", "image", "pull",
|
|
167
|
+
["k3s", "ctr", "image", "pull", image],
|
|
156
168
|
f"Pulling image {image}" + (f" (attempt {attempt_num})" if attempt_num > 1 else ""),
|
|
157
169
|
)
|
|
158
170
|
|
|
171
|
+
self.loaded_images = required_images
|
|
172
|
+
|
|
159
173
|
if any("auth.oidc.enabled=true" in value.lower() for value in set_values_list):
|
|
160
174
|
await agentstack_cli.commands.platform.istio.install(driver=self)
|
|
161
175
|
|
{agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/lima_driver.py
RENAMED
|
@@ -180,7 +180,7 @@ class LimaDriver(BaseDriver):
|
|
|
180
180
|
)
|
|
181
181
|
|
|
182
182
|
@typing.override
|
|
183
|
-
async def
|
|
183
|
+
async def import_images(self, *tags: str):
|
|
184
184
|
image_dir = anyio.Path("/tmp/agentstack")
|
|
185
185
|
await image_dir.mkdir(exist_ok=True, parents=True)
|
|
186
186
|
image_file = str(uuid.uuid4())
|
|
@@ -188,11 +188,12 @@ class LimaDriver(BaseDriver):
|
|
|
188
188
|
|
|
189
189
|
try:
|
|
190
190
|
await run_command(
|
|
191
|
-
["docker", "image", "save", "-o", str(image_path),
|
|
191
|
+
["docker", "image", "save", "-o", str(image_path), *tags],
|
|
192
|
+
f"Exporting image{'' if len(tags) == 1 else 's'} {', '.join(tags)} from Docker",
|
|
192
193
|
)
|
|
193
194
|
await self.run_in_vm(
|
|
194
195
|
["/bin/sh", "-c", f"k3s ctr images import /tmp/agentstack/{image_file}"],
|
|
195
|
-
f"Importing image {
|
|
196
|
+
f"Importing image{'' if len(tags) == 1 else 's'} {', '.join(tags)} into Agent Stack platform",
|
|
196
197
|
)
|
|
197
198
|
finally:
|
|
198
199
|
await image_path.unlink(missing_ok=True)
|
{agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/wsl_driver.py
RENAMED
|
@@ -131,7 +131,11 @@ class WSLDriver(BaseDriver):
|
|
|
131
131
|
set_values_list: list[str],
|
|
132
132
|
values_file: pathlib.Path | None = None,
|
|
133
133
|
import_images: list[str] | None = None,
|
|
134
|
+
pull_on_host: bool = False,
|
|
134
135
|
) -> None:
|
|
136
|
+
if pull_on_host:
|
|
137
|
+
raise NotImplementedError("Pulling on host is not supported on this platform.")
|
|
138
|
+
|
|
135
139
|
host_ip = (
|
|
136
140
|
(
|
|
137
141
|
await self.run_in_vm(
|
|
@@ -205,7 +209,7 @@ class WSLDriver(BaseDriver):
|
|
|
205
209
|
await run_command(["wsl.exe", "--unregister", self.vm_name], "Deleting Agent Stack platform", check=False)
|
|
206
210
|
|
|
207
211
|
@typing.override
|
|
208
|
-
async def
|
|
212
|
+
async def import_images(self, *tags: str) -> None:
|
|
209
213
|
raise NotImplementedError("Importing images is not supported on this platform.")
|
|
210
214
|
|
|
211
215
|
@typing.override
|
|
@@ -23,13 +23,12 @@ ROLE_DISPLAY = {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
@app.command("list")
|
|
26
|
+
@app.command("list", help="List platform users [Admin only]")
|
|
27
27
|
async def list_users(
|
|
28
28
|
email: typing.Annotated[str | None, typer.Option(help="Filter by email (case-insensitive partial match)")] = None,
|
|
29
29
|
limit: typing.Annotated[int, typer.Option(help="Results per page (1-100)")] = 40,
|
|
30
30
|
after: typing.Annotated[str | None, typer.Option(help="Pagination cursor (page_token)")] = None,
|
|
31
31
|
):
|
|
32
|
-
"""List platform users (admin only)."""
|
|
33
32
|
announce_server_action("Listing users on")
|
|
34
33
|
|
|
35
34
|
async with configuration.use_platform_client():
|
|
@@ -68,13 +67,12 @@ async def list_users(
|
|
|
68
67
|
console.print(f"\n[dim]Use --after {next_page_token} to see more[/dim]")
|
|
69
68
|
|
|
70
69
|
|
|
71
|
-
@app.command("set-role")
|
|
70
|
+
@app.command("set-role", help="Change user role [Admin only]")
|
|
72
71
|
async def set_role(
|
|
73
72
|
user_id: typing.Annotated[str, typer.Argument(help="User UUID")],
|
|
74
73
|
role: typing.Annotated[UserRole, typer.Argument(help="Target role (admin, developer, user)")],
|
|
75
74
|
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
76
75
|
):
|
|
77
|
-
"""Change user role (admin only)."""
|
|
78
76
|
url = announce_server_action(f"Changing user {user_id} to role '{role}' on")
|
|
79
77
|
await confirm_server_action("Proceed with role change on", url=url, yes=yes)
|
|
80
78
|
|
|
Binary file
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# Copyright 2025 © BeeAI a Series of LF Projects, LLC
|
|
2
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
import typing
|
|
5
|
-
from enum import StrEnum
|
|
6
|
-
|
|
7
|
-
import typer
|
|
8
|
-
from rich.table import Column
|
|
9
|
-
|
|
10
|
-
from agentstack_cli.api import api_request
|
|
11
|
-
from agentstack_cli.async_typer import AsyncTyper, console, create_table
|
|
12
|
-
from agentstack_cli.utils import announce_server_action, confirm_server_action, status
|
|
13
|
-
|
|
14
|
-
app = AsyncTyper()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Transport(StrEnum):
|
|
18
|
-
SSE = "sse"
|
|
19
|
-
STREAMABLE_HTTP = "streamable_http"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@app.command("add")
|
|
23
|
-
async def add_provider(
|
|
24
|
-
name: typing.Annotated[str, typer.Argument(help="Name for the MCP server")],
|
|
25
|
-
location: typing.Annotated[str, typer.Argument(help="Location of the MCP server")],
|
|
26
|
-
transport: typing.Annotated[
|
|
27
|
-
Transport, typer.Argument(help="Transport the MCP server uses")
|
|
28
|
-
] = Transport.STREAMABLE_HTTP,
|
|
29
|
-
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
30
|
-
) -> None:
|
|
31
|
-
"""Install discovered MCP server."""
|
|
32
|
-
|
|
33
|
-
url = announce_server_action(f"Registering MCP server '{name}' on")
|
|
34
|
-
await confirm_server_action("Proceed with registering this MCP server on", url=url, yes=yes)
|
|
35
|
-
with status("Registering server to platform"):
|
|
36
|
-
await api_request(
|
|
37
|
-
"POST", "mcp/providers", json={"name": name, "location": location, "transport": transport.value}
|
|
38
|
-
)
|
|
39
|
-
console.print("Registering server to platform [[green]DONE[/green]]")
|
|
40
|
-
await list_providers()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@app.command("list")
|
|
44
|
-
async def list_providers():
|
|
45
|
-
"""List MCP servers."""
|
|
46
|
-
|
|
47
|
-
announce_server_action("Listing MCP servers on")
|
|
48
|
-
providers = await api_request("GET", "mcp/providers")
|
|
49
|
-
assert providers
|
|
50
|
-
with create_table(
|
|
51
|
-
Column("Name"),
|
|
52
|
-
Column("Location"),
|
|
53
|
-
Column("Transport"),
|
|
54
|
-
Column("State"),
|
|
55
|
-
no_wrap=True,
|
|
56
|
-
) as table:
|
|
57
|
-
for provider in providers:
|
|
58
|
-
table.add_row(provider["name"], provider["location"], provider["transport"], provider["state"])
|
|
59
|
-
console.print()
|
|
60
|
-
console.print(table)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@app.command("remove | uninstall | rm | delete")
|
|
64
|
-
async def uninstall_provider(
|
|
65
|
-
name: typing.Annotated[str, typer.Argument(help="Name of the MCP provider to remove")],
|
|
66
|
-
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
67
|
-
) -> None:
|
|
68
|
-
"""Remove MCP server."""
|
|
69
|
-
url = announce_server_action(f"Removing MCP server '{name}' from")
|
|
70
|
-
await confirm_server_action("Proceed with removing this MCP server from", url=url, yes=yes)
|
|
71
|
-
provider = await _get_provider_by_name(name)
|
|
72
|
-
if provider:
|
|
73
|
-
await api_request("delete", f"mcp/providers/{provider['id']}")
|
|
74
|
-
else:
|
|
75
|
-
raise ValueError(f"Provider {name} not found")
|
|
76
|
-
await list_providers()
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
tool_app = AsyncTyper()
|
|
80
|
-
app.add_typer(tool_app, name="tool", no_args_is_help=True, help="Inspect tools.")
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@tool_app.command("list")
|
|
84
|
-
async def list_tools() -> None:
|
|
85
|
-
"""List tools."""
|
|
86
|
-
|
|
87
|
-
announce_server_action("Listing MCP tools on")
|
|
88
|
-
tools = await api_request("GET", "mcp/tools")
|
|
89
|
-
assert tools
|
|
90
|
-
with create_table(
|
|
91
|
-
Column("Name"),
|
|
92
|
-
Column("Description", max_width=30),
|
|
93
|
-
no_wrap=True,
|
|
94
|
-
) as table:
|
|
95
|
-
for tool in tools:
|
|
96
|
-
table.add_row(tool["name"], tool["description"])
|
|
97
|
-
console.print()
|
|
98
|
-
console.print(table)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
toolkit_app = AsyncTyper()
|
|
102
|
-
app.add_typer(toolkit_app, name="toolkit", no_args_is_help=True, help="Create toolkits.")
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@toolkit_app.command("create")
|
|
106
|
-
async def toolkit(
|
|
107
|
-
tools: typing.Annotated[list[str], typer.Argument(help="Tools to put in the toolkit")],
|
|
108
|
-
yes: typing.Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompts.")] = False,
|
|
109
|
-
) -> None:
|
|
110
|
-
"""Create a toolkit."""
|
|
111
|
-
|
|
112
|
-
url = announce_server_action("Creating MCP toolkit on")
|
|
113
|
-
await confirm_server_action("Proceed with creating this MCP toolkit on", url=url, yes=yes)
|
|
114
|
-
api_tools = await _get_tools_by_names(tools)
|
|
115
|
-
assert api_tools
|
|
116
|
-
toolkit = await api_request("POST", "mcp/toolkits", json={"tools": [tool["id"] for tool in api_tools]})
|
|
117
|
-
assert toolkit
|
|
118
|
-
with create_table(Column("Location"), Column("Transport"), Column("Expiration")) as table:
|
|
119
|
-
table.add_row(toolkit["location"], toolkit["transport"], toolkit["expires_at"])
|
|
120
|
-
console.print()
|
|
121
|
-
console.print(table)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
async def _get_provider_by_name(name: str):
|
|
125
|
-
providers = await api_request("GET", "mcp/providers")
|
|
126
|
-
assert providers
|
|
127
|
-
|
|
128
|
-
for provider in providers:
|
|
129
|
-
if provider["name"] == name:
|
|
130
|
-
return provider
|
|
131
|
-
|
|
132
|
-
raise ValueError(f"Provider {name} not found")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
async def _get_tools_by_names(names: list[str]) -> list[dict[str, typing.Any]]:
|
|
136
|
-
all_tools = await api_request("GET", "mcp/tools")
|
|
137
|
-
assert all_tools
|
|
138
|
-
|
|
139
|
-
tools = []
|
|
140
|
-
for name in names:
|
|
141
|
-
found = False
|
|
142
|
-
for tool in all_tools:
|
|
143
|
-
if tool["name"] == name:
|
|
144
|
-
tools.append(tool)
|
|
145
|
-
found = True
|
|
146
|
-
break
|
|
147
|
-
if not found:
|
|
148
|
-
raise ValueError(f"Tool {name} not found")
|
|
149
|
-
|
|
150
|
-
return tools
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentstack_cli-0.5.1rc2 → agentstack_cli-0.5.2}/src/agentstack_cli/commands/platform/istio.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|