llamactl 0.3.0a20__py3-none-any.whl → 0.3.0a21__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.
@@ -21,6 +21,13 @@ from llama_deploy.cli.auth.client import (
21
21
  from llama_deploy.cli.config._config import ConfigManager
22
22
  from llama_deploy.cli.config.auth_service import AuthService
23
23
  from llama_deploy.cli.config.env_service import service
24
+ from llama_deploy.cli.styles import (
25
+ ACTIVE_INDICATOR,
26
+ HEADER_COLOR,
27
+ MUTED_COL,
28
+ PRIMARY_COL,
29
+ WARNING,
30
+ )
24
31
  from llama_deploy.core.client.manage_client import (
25
32
  ControlPlaneClient,
26
33
  )
@@ -86,7 +93,7 @@ def create_api_key_profile(
86
93
  projects, auth_svc.env.requires_auth
87
94
  )
88
95
  if not selected_project_id:
89
- rprint("[yellow]No project selected[/yellow]")
96
+ rprint(f"[{WARNING}]No project selected[/]")
90
97
  return
91
98
 
92
99
  # Create and set profile
@@ -125,18 +132,21 @@ def list_profiles() -> None:
125
132
  current = auth_svc.get_current_profile()
126
133
 
127
134
  if not profiles:
128
- rprint("[yellow]No profiles found[/yellow]")
129
- rprint("Create one with: [cyan]llamactl auth token[/cyan]")
135
+ rprint(f"[{WARNING}]No profiles found[/]")
136
+ if auth_svc.env.requires_auth:
137
+ rprint("Create one with: [cyan]llamactl auth login[/cyan]")
138
+ else:
139
+ rprint("Create one with: [cyan]llamactl auth token[/cyan]")
130
140
  return
131
141
 
132
- table = Table(show_edge=False, box=None, header_style="bold cornflower_blue")
133
- table.add_column(" Name")
134
- table.add_column("Active Project", style="grey46")
142
+ table = Table(show_edge=False, box=None, header_style=f"bold {HEADER_COLOR}")
143
+ table.add_column(" Name", style=PRIMARY_COL)
144
+ table.add_column("Active Project", style=MUTED_COL)
135
145
 
136
146
  for profile in profiles:
137
147
  text = Text()
138
148
  if profile == current:
139
- text.append("* ", style="magenta")
149
+ text.append("* ", style=ACTIVE_INDICATOR)
140
150
  else:
141
151
  text.append(" ")
142
152
  text.append(profile.name)
@@ -183,7 +193,7 @@ def switch_profile(name: str | None, interactive: bool) -> None:
183
193
  try:
184
194
  selected_auth = _select_profile(auth_svc, name, interactive)
185
195
  if not selected_auth:
186
- rprint("[yellow]No profile selected[/yellow]")
196
+ rprint(f"[{WARNING}]No profile selected[/]")
187
197
  return
188
198
 
189
199
  auth_svc.set_current_profile(selected_auth.name)
@@ -204,7 +214,7 @@ def delete_profile(name: str | None, interactive: bool) -> None:
204
214
  auth_svc = service.current_auth_service()
205
215
  auth = _select_profile(auth_svc, name, interactive)
206
216
  if not auth:
207
- rprint("[yellow]No profile selected[/yellow]")
217
+ rprint(f"[{WARNING}]No profile selected[/]")
208
218
  return
209
219
 
210
220
  if asyncio.run(auth_svc.delete_profile(auth.name)):
@@ -270,7 +280,7 @@ def change_project(project_id: str | None, interactive: bool) -> None:
270
280
  projects = _list_projects(auth_svc)
271
281
 
272
282
  if not projects:
273
- rprint("[yellow]No projects found[/yellow]")
283
+ rprint(f"[{WARNING}]No projects found[/]")
274
284
  return
275
285
  result = questionary.select(
276
286
  "Select a project",
@@ -296,9 +306,9 @@ def change_project(project_id: str | None, interactive: bool) -> None:
296
306
  )
297
307
  name = selected_project.project_name if selected_project else result
298
308
  auth_svc.set_project(profile.name, result)
299
- rprint(f"Set active project to [bold cornflower_blue]{name}[/]")
309
+ rprint(f"Set active project to [bold {PRIMARY_COL}]{name}[/]")
300
310
  else:
301
- rprint("[yellow]No project selected[/yellow]")
311
+ rprint(f"[{WARNING}]No project selected[/]")
302
312
  except Exception as e:
303
313
  rprint(f"[red]Error: {e}[/red]")
304
314
  raise click.Abort()
@@ -614,7 +624,7 @@ def _select_profile(
614
624
  profiles = auth_svc.list_profiles()
615
625
 
616
626
  if not profiles:
617
- rprint("[yellow]No profiles found[/yellow]")
627
+ rprint(f"[{WARNING}]No profiles found[/]")
618
628
  return None
619
629
 
620
630
  choices = []
@@ -11,6 +11,7 @@ import asyncio
11
11
  import click
12
12
  import questionary
13
13
  from llama_deploy.cli.commands.auth import validate_authenticated_profile
14
+ from llama_deploy.cli.styles import HEADER_COLOR, MUTED_COL, PRIMARY_COL, WARNING
14
15
  from llama_deploy.core.schema.deployments import DeploymentUpdate
15
16
  from rich import print as rprint
16
17
  from rich.table import Table
@@ -52,15 +53,15 @@ def list_deployments(interactive: bool) -> None:
52
53
 
53
54
  if not deployments:
54
55
  rprint(
55
- f"[yellow]No deployments found for project {client.project_id}[/yellow]"
56
+ f"[{WARNING}]No deployments found for project {client.project_id}[/]"
56
57
  )
57
58
  return
58
59
 
59
- table = Table(show_edge=False, box=None, header_style="bold cornflower_blue")
60
- table.add_column("Name")
61
- table.add_column("Status", style="grey46")
62
- table.add_column("URL", style="grey46")
63
- table.add_column("Repository", style="grey46")
60
+ table = Table(show_edge=False, box=None, header_style=f"bold {HEADER_COLOR}")
61
+ table.add_column("Name", style=PRIMARY_COL)
62
+ table.add_column("Status", style=MUTED_COL)
63
+ table.add_column("URL", style=MUTED_COL)
64
+ table.add_column("Repository", style=MUTED_COL)
64
65
 
65
66
  for deployment in deployments:
66
67
  name = deployment.id
@@ -96,7 +97,7 @@ def get_deployment(deployment_id: str | None, interactive: bool) -> None:
96
97
 
97
98
  deployment_id = select_deployment(deployment_id)
98
99
  if not deployment_id:
99
- rprint("[yellow]No deployment selected[/yellow]")
100
+ rprint(f"[{WARNING}]No deployment selected[/]")
100
101
  return
101
102
  if interactive:
102
103
  monitor_deployment_screen(deployment_id)
@@ -104,9 +105,9 @@ def get_deployment(deployment_id: str | None, interactive: bool) -> None:
104
105
 
105
106
  deployment = asyncio.run(client.get_deployment(deployment_id))
106
107
 
107
- table = Table(show_edge=False, box=None, header_style="bold cornflower_blue")
108
- table.add_column("Property", style="grey46", justify="right")
109
- table.add_column("Value")
108
+ table = Table(show_edge=False, box=None, header_style=f"bold {HEADER_COLOR}")
109
+ table.add_column("Property", style=MUTED_COL, justify="right")
110
+ table.add_column("Value", style=PRIMARY_COL)
110
111
 
111
112
  table.add_row("ID", Text(deployment.id))
112
113
  table.add_row("Project ID", Text(deployment.project_id))
@@ -148,7 +149,7 @@ def create_deployment(
148
149
  # Use interactive creation
149
150
  deployment_form = create_deployment_form()
150
151
  if deployment_form is None:
151
- rprint("[yellow]Cancelled[/yellow]")
152
+ rprint(f"[{WARNING}]Cancelled[/]")
152
153
  return
153
154
 
154
155
  rprint(
@@ -168,12 +169,12 @@ def delete_deployment(deployment_id: str | None, interactive: bool) -> None:
168
169
 
169
170
  deployment_id = select_deployment(deployment_id, interactive=interactive)
170
171
  if not deployment_id:
171
- rprint("[yellow]No deployment selected[/yellow]")
172
+ rprint(f"[{WARNING}]No deployment selected[/]")
172
173
  return
173
174
 
174
175
  if interactive:
175
176
  if not confirm_action(f"Delete deployment '{deployment_id}'?"):
176
- rprint("[yellow]Cancelled[/yellow]")
177
+ rprint(f"[{WARNING}]Cancelled[/]")
177
178
  return
178
179
 
179
180
  asyncio.run(client.delete_deployment(deployment_id))
@@ -196,7 +197,7 @@ def edit_deployment(deployment_id: str | None, interactive: bool) -> None:
196
197
 
197
198
  deployment_id = select_deployment(deployment_id, interactive=interactive)
198
199
  if not deployment_id:
199
- rprint("[yellow]No deployment selected[/yellow]")
200
+ rprint(f"[{WARNING}]No deployment selected[/]")
200
201
  return
201
202
 
202
203
  # Get current deployment details
@@ -205,7 +206,7 @@ def edit_deployment(deployment_id: str | None, interactive: bool) -> None:
205
206
  # Use the interactive edit form
206
207
  updated_deployment = edit_deployment_form(current_deployment)
207
208
  if updated_deployment is None:
208
- rprint("[yellow]Cancelled[/yellow]")
209
+ rprint(f"[{WARNING}]Cancelled[/]")
209
210
  return
210
211
 
211
212
  rprint(
@@ -227,7 +228,7 @@ def refresh_deployment(deployment_id: str | None, interactive: bool) -> None:
227
228
  try:
228
229
  deployment_id = select_deployment(deployment_id)
229
230
  if not deployment_id:
230
- rprint("[yellow]No deployment selected[/yellow]")
231
+ rprint(f"[{WARNING}]No deployment selected[/]")
231
232
  return
232
233
 
233
234
  # Get current deployment details to show what we're refreshing
@@ -282,7 +283,7 @@ def select_deployment(
282
283
  deployments = asyncio.run(client.list_deployments())
283
284
 
284
285
  if not deployments:
285
- rprint(f"[yellow]No deployments found for project {client.project_id}[/yellow]")
286
+ rprint(f"[{WARNING}]No deployments found for project {client.project_id}[/]")
286
287
  return None
287
288
 
288
289
  choices = []
@@ -3,6 +3,13 @@ from importlib import metadata as importlib_metadata
3
3
  import click
4
4
  import questionary
5
5
  from llama_deploy.cli.config.schema import Environment
6
+ from llama_deploy.cli.styles import (
7
+ ACTIVE_INDICATOR,
8
+ HEADER_COLOR,
9
+ MUTED_COL,
10
+ PRIMARY_COL,
11
+ WARNING,
12
+ )
6
13
  from packaging import version as packaging_version
7
14
  from rich import print as rprint
8
15
  from rich.table import Table
@@ -32,23 +39,21 @@ def list_environments_cmd() -> None:
32
39
  current_env = service.get_current_environment()
33
40
 
34
41
  if not envs:
35
- rprint("[yellow]No environments found[/yellow]")
42
+ rprint(f"[{WARNING}]No environments found[/]")
36
43
  return
37
44
 
38
- table = Table(show_edge=False, box=None, header_style="bold cornflower_blue")
39
- table.add_column(" API URL")
40
- table.add_column("Requires Auth")
45
+ table = Table(show_edge=False, box=None, header_style=f"bold {HEADER_COLOR}")
46
+ table.add_column(" API URL", style=PRIMARY_COL)
47
+ table.add_column("Requires Auth", style=MUTED_COL)
41
48
 
42
49
  for env in envs:
43
50
  text = Text()
44
51
  if env == current_env:
45
- text.append("* ", style="magenta")
52
+ text.append("* ", style=ACTIVE_INDICATOR)
46
53
  else:
47
54
  text.append(" ")
48
55
  text.append(env.api_url)
49
- table.add_row(
50
- text, Text("true" if env.requires_auth else "false", style="grey46")
51
- )
56
+ table.add_row(text, Text("true" if env.requires_auth else "false"))
52
57
 
53
58
  console.print(table)
54
59
  except Exception as e:
@@ -70,7 +75,7 @@ def add_environment_cmd(api_url: str | None, interactive: bool) -> None:
70
75
  "Enter control plane API URL", default=current_env.api_url
71
76
  ).ask()
72
77
  if not entered:
73
- rprint("[yellow]No environment entered[/yellow]")
78
+ rprint(f"[{WARNING}]No environment entered[/]")
74
79
  return
75
80
  api_url = entered.strip()
76
81
 
@@ -102,7 +107,7 @@ def delete_environment_cmd(api_url: str | None, interactive: bool) -> None:
102
107
  )
103
108
 
104
109
  if not result:
105
- rprint("[yellow]No environment selected[/yellow]")
110
+ rprint(f"[{WARNING}]No environment selected[/]")
106
111
  return
107
112
  api_url = result.api_url
108
113
 
@@ -133,13 +138,13 @@ def switch_environment_cmd(api_url: str | None, interactive: bool) -> None:
133
138
  "Select environment",
134
139
  )
135
140
  if not result:
136
- rprint("[yellow]No environment selected[/yellow]")
141
+ rprint(f"[{WARNING}]No environment selected[/]")
137
142
  return
138
143
  selected_url = result.api_url
139
144
 
140
145
  if not selected_url:
141
146
  if interactive:
142
- rprint("[yellow]No environment selected[/yellow]")
147
+ rprint(f"[{WARNING}]No environment selected[/]")
143
148
  return
144
149
  raise click.ClickException("API URL is required when not interactive")
145
150
 
@@ -150,7 +155,7 @@ def switch_environment_cmd(api_url: str | None, interactive: bool) -> None:
150
155
  try:
151
156
  env = service.auto_update_env(env)
152
157
  except Exception as e:
153
- rprint(f"[yellow]Failed to resolve environment: {e}[/yellow]")
158
+ rprint(f"[{WARNING}]Failed to resolve environment: {e}[/]")
154
159
  return
155
160
  service.current_auth_service().select_any_profile()
156
161
  rprint(f"[green]Switched to environment[/green] {env.api_url}")
@@ -176,7 +181,7 @@ def _maybe_warn_min_version(min_required: str | None) -> None:
176
181
  try:
177
182
  if packaging_version.parse(current) < packaging_version.parse(min_required):
178
183
  rprint(
179
- f"[yellow]Warning:[/yellow] This environment requires llamactl >= [bold]{min_required}[/bold], you have [bold]{current}[/bold]."
184
+ f"[{WARNING}]Warning:[/] This environment requires llamactl >= [bold]{min_required}[/bold], you have [bold]{current}[/bold]."
180
185
  )
181
186
  except Exception:
182
187
  # If packaging is not available or parsing fails, skip strict comparison
@@ -1,3 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
1
4
  import os
2
5
  import shutil
3
6
  import subprocess
@@ -10,7 +13,11 @@ import questionary
10
13
  from click.exceptions import Exit
11
14
  from llama_deploy.cli.app import app
12
15
  from llama_deploy.cli.options import global_options
16
+ from llama_deploy.cli.styles import HEADER_COLOR_HEX
13
17
  from rich import print as rprint
18
+ from vibe_llama.scaffold import create_scaffold
19
+ from vibe_llama.scaffold.scaffold import ProjectName
20
+ from vibe_llama.sdk import VibeLlamaStarter
14
21
 
15
22
 
16
23
  @dataclass
@@ -18,21 +25,82 @@ class TemplateOption:
18
25
  id: str
19
26
  name: str
20
27
  description: str
21
- git_url: str
28
+ source: VibeLlamaTemplate | GithubTemplateRepo
29
+ llama_cloud: bool
30
+
22
31
 
32
+ @dataclass
33
+ class VibeLlamaTemplate:
34
+ name: ProjectName
23
35
 
24
- options = [
36
+
37
+ @dataclass
38
+ class GithubTemplateRepo:
39
+ url: str
40
+
41
+
42
+ ui_options = [
25
43
  TemplateOption(
26
44
  id="basic-ui",
27
45
  name="Basic UI",
28
46
  description="A basic starter workflow with a React Vite UI",
29
- git_url="https://github.com/run-llama/template-workflow-basic-ui",
47
+ source=GithubTemplateRepo(
48
+ url="https://github.com/run-llama/template-workflow-basic-ui"
49
+ ),
50
+ llama_cloud=False,
30
51
  ),
31
52
  TemplateOption(
32
53
  id="extraction-review",
33
54
  name="Extraction Agent with Review UI",
34
55
  description="Extract data from documents using a custom schema and Llama Cloud. Includes a UI to review and correct the results",
35
- git_url="https://github.com/run-llama/template-workflow-data-extraction",
56
+ source=GithubTemplateRepo(
57
+ url="https://github.com/run-llama/template-workflow-data-extraction"
58
+ ),
59
+ llama_cloud=True,
60
+ ),
61
+ ]
62
+ headless_options = [
63
+ TemplateOption(
64
+ id="basic",
65
+ name="Basic Workflow",
66
+ description="A base example that showcases usage patterns for workflows",
67
+ source=VibeLlamaTemplate(name="basic"),
68
+ llama_cloud=False,
69
+ ),
70
+ TemplateOption(
71
+ id="document_parsing",
72
+ name="Document Parser",
73
+ description="A workflow that, using LlamaParse, parses unstructured documents and returns their raw text content",
74
+ source=VibeLlamaTemplate(name="document_parsing"),
75
+ llama_cloud=True,
76
+ ),
77
+ TemplateOption(
78
+ id="human_in_the_loop",
79
+ name="Human in the Loop",
80
+ description="A workflow showcasing how to use human in the loop with LlamaIndex workflows",
81
+ source=VibeLlamaTemplate(name="human_in_the_loop"),
82
+ llama_cloud=False,
83
+ ),
84
+ TemplateOption(
85
+ id="invoice_extraction",
86
+ name="Invoice Extraction",
87
+ description="A workflow that, given an invoice, extracts several key details using LlamaExtract",
88
+ source=VibeLlamaTemplate(name="invoice_extraction"),
89
+ llama_cloud=True,
90
+ ),
91
+ TemplateOption(
92
+ id="rag",
93
+ name="RAG",
94
+ description="A workflow that embeds, indexes and queries your documents on the fly, providing you with a simple RAG pipeline",
95
+ source=VibeLlamaTemplate(name="rag"),
96
+ llama_cloud=False,
97
+ ),
98
+ TemplateOption(
99
+ id="web_scraping",
100
+ name="Web Scraping",
101
+ description="A workflow that, given several urls, scrapes and summarizes their content using Google's Gemini API",
102
+ source=VibeLlamaTemplate(name="web_scraping"),
103
+ llama_cloud=False,
36
104
  ),
37
105
  ]
38
106
 
@@ -45,7 +113,7 @@ options = [
45
113
  )
46
114
  @click.option(
47
115
  "--template",
48
- type=click.Choice([o.id for o in options]),
116
+ type=click.Choice([o.id for o in ui_options]),
49
117
  help="The template to use for the new app",
50
118
  )
51
119
  @click.option(
@@ -76,12 +144,29 @@ def init(
76
144
 
77
145
  def _create(template: str | None, dir: Path | None, force: bool) -> None:
78
146
  if template is None:
147
+ rprint(
148
+ "[bold]Select a template to start from.[/bold] Either with javascript frontend UI, or just a python workflow that can be used as an API."
149
+ )
79
150
  template = questionary.select(
80
- "Choose a template",
81
- choices=[
151
+ "",
152
+ choices=[questionary.Separator("------------ With UI -------------")]
153
+ + [
154
+ questionary.Choice(title=o.name, value=o.id, description=o.description)
155
+ for o in ui_options
156
+ ]
157
+ + [
158
+ questionary.Separator(" "),
159
+ questionary.Separator("--- Headless Workflows (No UI) ---"),
160
+ ]
161
+ + [
82
162
  questionary.Choice(title=o.name, value=o.id, description=o.description)
83
- for o in options
163
+ for o in headless_options
84
164
  ],
165
+ style=questionary.Style(
166
+ [
167
+ ("separator", f"fg:{HEADER_COLOR_HEX}"),
168
+ ]
169
+ ),
85
170
  ).ask()
86
171
  if template is None:
87
172
  rprint("No template selected")
@@ -94,7 +179,9 @@ def _create(template: str | None, dir: Path | None, force: bool) -> None:
94
179
  rprint("No directory provided")
95
180
  raise Exit(1)
96
181
  dir = Path(dir_str)
97
- resolved_template = next((o for o in options if o.id == template), None)
182
+ resolved_template: TemplateOption | None = next(
183
+ (o for o in ui_options + headless_options if o.id == template), None
184
+ )
98
185
  if resolved_template is None:
99
186
  rprint(f"Template {template} not found")
100
187
  raise Exit(1)
@@ -107,35 +194,51 @@ def _create(template: str | None, dir: Path | None, force: bool) -> None:
107
194
  raise Exit(1)
108
195
  else:
109
196
  shutil.rmtree(dir, ignore_errors=True)
110
- copier.run_copy(
111
- resolved_template.git_url,
112
- dir,
113
- quiet=True,
114
- )
197
+
198
+ if isinstance(resolved_template.source, GithubTemplateRepo):
199
+ copier.run_copy(
200
+ resolved_template.source.url,
201
+ dir,
202
+ quiet=True,
203
+ )
204
+ else:
205
+ asyncio.run(create_scaffold(resolved_template.source.name, str(dir)))
115
206
  # Initialize git repository if git is available
116
- is_git_initialized = False
207
+ has_git = False
117
208
  try:
118
209
  subprocess.run(["git", "--version"], check=True, capture_output=True)
210
+ has_git = True
211
+ except subprocess.CalledProcessError:
212
+ pass
119
213
 
120
- # Change to the new directory and initialize git repo
121
- original_cwd = Path.cwd()
122
- os.chdir(dir)
123
-
124
- try:
125
- subprocess.run(["git", "init"], check=True, capture_output=True)
126
- subprocess.run(["git", "add", "."], check=True, capture_output=True)
127
- subprocess.run(
128
- ["git", "commit", "-m", "Initial commit"],
129
- check=True,
130
- capture_output=True,
131
- )
132
- is_git_initialized = True
133
- finally:
134
- os.chdir(original_cwd)
214
+ # Change to the new directory and initialize git repo
215
+ original_cwd = Path.cwd()
216
+ os.chdir(dir)
135
217
 
136
- except (subprocess.CalledProcessError, FileNotFoundError):
137
- # Git not available or failed - continue without git initialization
138
- pass
218
+ try:
219
+ # Dump in a bunch of docs for AI agents
220
+ vibe_llama_starter = VibeLlamaStarter(
221
+ agents=["OpenAI Codex CLI"], # AGENTS.md, supported by Cursor,
222
+ services=["LlamaIndex", "llama-index-workflows"]
223
+ + (["LlamaCloud Services"] if resolved_template.llama_cloud else []),
224
+ )
225
+ asyncio.run(vibe_llama_starter.write_instructions(overwrite=True))
226
+ # Create symlink for Claude.md to point to AGENTS.md
227
+ for alternate in ["CLAUDE.md", "GEMINI.md"]: # don't support AGENTS.md (yet?)
228
+ claude_path = Path(alternate) # not supported yet
229
+ agents_path = Path("AGENTS.md")
230
+ if agents_path.exists() and not claude_path.exists():
231
+ claude_path.symlink_to("AGENTS.md")
232
+ if has_git:
233
+ subprocess.run(["git", "init"], check=True, capture_output=True)
234
+ subprocess.run(["git", "add", "."], check=True, capture_output=True)
235
+ subprocess.run(
236
+ ["git", "commit", "-m", "Initial commit"],
237
+ check=True,
238
+ capture_output=True,
239
+ )
240
+ finally:
241
+ os.chdir(original_cwd)
139
242
 
140
243
  rprint(
141
244
  f"Successfully created [blue]{dir}[/] using the [blue]{resolved_template.name}[/] template! 🎉 🦙 💾"
@@ -146,7 +249,7 @@ def _create(template: str | None, dir: Path | None, force: bool) -> None:
146
249
  rprint(" [orange3]uvx[/] llamactl serve")
147
250
  rprint("")
148
251
  rprint("[bold]To deploy:[/]")
149
- if not is_git_initialized:
252
+ if has_git:
150
253
  rprint(" [orange3]git[/] init")
151
254
  rprint(" [orange3]git[/] add .")
152
255
  rprint(" [orange3]git[/] commit -m 'Initial commit'")
@@ -13,6 +13,7 @@ from llama_deploy.cli.commands.auth import validate_authenticated_profile
13
13
  from llama_deploy.cli.config.env_service import service
14
14
  from llama_deploy.cli.config.schema import Auth
15
15
  from llama_deploy.cli.options import interactive_option
16
+ from llama_deploy.cli.styles import WARNING
16
17
  from llama_deploy.core.config import DEFAULT_DEPLOYMENT_FILE_PATH
17
18
  from llama_deploy.core.deployment_config import (
18
19
  read_deployment_config_from_git_root_or_cwd,
@@ -182,7 +183,7 @@ def _maybe_inject_llama_cloud_credentials(
182
183
  env = service.get_current_environment()
183
184
  if not env.requires_auth:
184
185
  rprint(
185
- "[yellow]Warning: This app requires Llama Cloud authentication, and no LLAMA_CLOUD_API_KEY is present. The app may not work.[/yellow]"
186
+ f"[{WARNING}]Warning: This app requires Llama Cloud authentication, and no LLAMA_CLOUD_API_KEY is present. The app may not work.[/]"
186
187
  )
187
188
  return
188
189
 
@@ -204,11 +205,11 @@ def _maybe_inject_llama_cloud_credentials(
204
205
  _set_env_vars_from_profile(authed)
205
206
  return
206
207
  rprint(
207
- "[yellow]Warning: No Llama Cloud credentials configured. The app may not work.[/yellow]"
208
+ f"[{WARNING}]Warning: No Llama Cloud credentials configured. The app may not work.[/]"
208
209
  )
209
210
  return
210
211
 
211
212
  # Non-interactive session
212
213
  rprint(
213
- "[yellow]Warning: LLAMA_CLOUD_API_KEY is not set and no logged-in profile was found. The app may not work.[/yellow]"
214
+ f"[{WARNING}]Warning: LLAMA_CLOUD_API_KEY is not set and no logged-in profile was found. The app may not work.[/]"
214
215
  )
llama_deploy/cli/env.py CHANGED
@@ -4,6 +4,7 @@ from io import StringIO
4
4
  from typing import Dict
5
5
 
6
6
  from dotenv import dotenv_values
7
+ from llama_deploy.cli.styles import WARNING
7
8
  from rich import print as rprint
8
9
 
9
10
 
@@ -26,6 +27,6 @@ def load_env_secrets_from_string(env_content: str) -> Dict[str, str]:
26
27
  return {k: str(v) for k, v in secrets.items() if v is not None}
27
28
  except Exception as e:
28
29
  rprint(
29
- f"[yellow]Warning: Could not parse environment variables from string: {e}[/yellow]"
30
+ f"[{WARNING}]Warning: Could not parse environment variables from string: {e}[/]"
30
31
  )
31
32
  return {}
@@ -0,0 +1,10 @@
1
+ # A place to centralize design tokens to simplify tweaking the appearance of the CLI
2
+ # See https://rich.readthedocs.io/en/stable/appendix/colors.html
3
+
4
+
5
+ HEADER_COLOR = "cornflower_blue"
6
+ HEADER_COLOR_HEX = "#5f87ff"
7
+ PRIMARY_COL = "default"
8
+ MUTED_COL = "grey46"
9
+ WARNING = "yellow"
10
+ ACTIVE_INDICATOR = "magenta"
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: llamactl
3
- Version: 0.3.0a20
3
+ Version: 0.3.0a21
4
4
  Summary: A command-line interface for managing LlamaDeploy projects and deployments
5
5
  Author: Adrian Lyjak
6
6
  Author-email: Adrian Lyjak <adrianlyjak@gmail.com>
7
7
  License: MIT
8
- Requires-Dist: llama-deploy-core[client]>=0.3.0a20,<0.4.0
9
- Requires-Dist: llama-deploy-appserver>=0.3.0a20,<0.4.0
8
+ Requires-Dist: llama-deploy-core[client]>=0.3.0a21,<0.4.0
9
+ Requires-Dist: llama-deploy-appserver>=0.3.0a21,<0.4.0
10
10
  Requires-Dist: httpx>=0.24.0,<1.0.0
11
11
  Requires-Dist: rich>=13.0.0
12
12
  Requires-Dist: questionary>=2.0.0
@@ -17,6 +17,7 @@ Requires-Dist: textual>=6.0.0
17
17
  Requires-Dist: aiohttp>=3.12.14
18
18
  Requires-Dist: copier>=9.9.0
19
19
  Requires-Dist: pyjwt[crypto]>=2.10.1
20
+ Requires-Dist: vibe-llama>=0.4.2,<0.5.0
20
21
  Requires-Python: >=3.11, <4
21
22
  Description-Content-Type: text/markdown
22
23
 
@@ -3,11 +3,11 @@ llama_deploy/cli/app.py,sha256=9170e4f506c482522bd745eb1cdb700a198cfcfd7204c168c
3
3
  llama_deploy/cli/auth/client.py,sha256=0673e2fdc71e8cf1f6d79a64e39596e608dc0257b7dddfebcc38e13e1545a2a8,11670
4
4
  llama_deploy/cli/client.py,sha256=f4053b5183224cff55c1393e78887d1af2597219135379a851b742c676adc154,1727
5
5
  llama_deploy/cli/commands/aliased_group.py,sha256=bc41007c97b7b93981217dbd4d4591df2b6c9412a2d9ed045b0ec5655ed285f2,1066
6
- llama_deploy/cli/commands/auth.py,sha256=b35aac3367ae7713effbccb0f4ab816b104edfce5125905183340d4eb13ef821,21864
7
- llama_deploy/cli/commands/deployment.py,sha256=15582d7e4da7b9afeb3ab7e36f74f2ae6d1ae9f21515698bcd176f850317374d,9779
8
- llama_deploy/cli/commands/env.py,sha256=e0b96b9f4e7921b4370ad5f8bc0a2bfb19b705e73004f72c37c9bed28a208e0d,6702
9
- llama_deploy/cli/commands/init.py,sha256=51b2de1e35ff34bc15c9dfec72fbad08aaf528c334df168896d36458a4e9401c,6307
10
- llama_deploy/cli/commands/serve.py,sha256=39b380ca2040d9a3a308bccec911a192316b600d4cdfbcf7a8f0231c20bb8229,7289
6
+ llama_deploy/cli/commands/auth.py,sha256=d15d9c234b98f2e7a8c1be1adb111fbae64a2f5bc39b6dd610000a287bf1a132,22141
7
+ llama_deploy/cli/commands/deployment.py,sha256=46339e09135521c46ff90235ccf765c37b1a161cec11d92e92a54ceac6528b01,9883
8
+ llama_deploy/cli/commands/env.py,sha256=36cb1b0abb9e3d1c5546d3e8a3c4c7839c4d6c2abf75763e39efb08376b3eae9,6808
9
+ llama_deploy/cli/commands/init.py,sha256=46f9fcdc43880edbd2f244b4c80d5cc5d387a6f8d7407c182f5995c46e41c851,10153
10
+ llama_deploy/cli/commands/serve.py,sha256=ce08f0ec9c183d4a6f43ee10468b1bbd10edf4af3f2b3311cc1e54c3f4384528,7327
11
11
  llama_deploy/cli/config/_config.py,sha256=654a4b6d06542e3503edab7023fc1c3148de510b3e3f6194e28cd4bd3e7c029a,14230
12
12
  llama_deploy/cli/config/_migrations.py,sha256=37055641970e1ea41abc583f270dc8a9dab03076224a02cd5fb08bbab2b9259f,2333
13
13
  llama_deploy/cli/config/auth_service.py,sha256=8a61110e18c752bbec5fbca23cd5d35d4ec232a4371f8c8291ba07ad83d30c6c,5208
@@ -17,11 +17,12 @@ llama_deploy/cli/config/migrations/0002_add_auth_fields.sql,sha256=31bd109e5fa0a
17
17
  llama_deploy/cli/config/migrations/__init__.py,sha256=a092bdd1eba7041e69db0a9594941821a6337018f90d7e231d651195a9db0a69,151
18
18
  llama_deploy/cli/config/schema.py,sha256=bd7b68eacd8a242c7f6fbccd176970425eeed504f593838d228a73ea75d73770,1542
19
19
  llama_deploy/cli/debug.py,sha256=e85a72d473bbe1645eb31772f7349bde703d45704166f767385895c440afc762,496
20
- llama_deploy/cli/env.py,sha256=6ebc24579815b3787829c81fd5bb9f31698a06e62c0128a788559f962b33a7af,1016
20
+ llama_deploy/cli/env.py,sha256=d4b83c1f12e07f90893fcc7388d769de37dc2b41d345eb6bc2041c39b4fb2c31,1057
21
21
  llama_deploy/cli/interactive_prompts/session_utils.py,sha256=b996f2eddf70d6c49636c4797d246d212fce0950fe7e9a3f59cf6a1bf7ae26f5,1142
22
22
  llama_deploy/cli/interactive_prompts/utils.py,sha256=594cc2a242cc3405d66d0e26a60647496cc5fcb4ce7d0500a4cfec4888c9a0fa,516
23
23
  llama_deploy/cli/options.py,sha256=62ee7286c3305ddb4b597783d19e854284d79bf9384800045f15b934dc245c1d,1298
24
24
  llama_deploy/cli/py.typed,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
25
+ llama_deploy/cli/styles.py,sha256=15901fb567b0d10470f56a06d863819c4ed00a9f90b2a8c46b4bc2fb1dbdf6c3,307
25
26
  llama_deploy/cli/textual/deployment_form.py,sha256=61ff18bceaba810b40d68aac104969b92870316a7025ba839242c1e0b6bde397,23677
26
27
  llama_deploy/cli/textual/deployment_help.py,sha256=91094f9c460421bae75bc705c02c64a9ec464a7e92dd2eb5de365cfd5b08a9a7,2463
27
28
  llama_deploy/cli/textual/deployment_monitor.py,sha256=86b2545eeee9ef4ff9c8bec0ee5c8eefd54373d2200da5906a886fb614e763cd,16723
@@ -30,7 +31,7 @@ llama_deploy/cli/textual/github_callback_server.py,sha256=3111cc45b3ff2632255a37
30
31
  llama_deploy/cli/textual/llama_loader.py,sha256=33cb32a46dd40bcf889c553e44f2672c410e26bd1d4b17aa6cca6d0a5d59c2c4,1468
31
32
  llama_deploy/cli/textual/secrets_form.py,sha256=df6699de29d2bc2cbcaddd41ad2495ce0e622cdccaadbc8369a6ee09a9e79d34,7251
32
33
  llama_deploy/cli/textual/styles.tcss,sha256=c8fa0eec00a97fa6907d223faaad82c6add1ea3f60009f1630be19282ea77e3b,3271
33
- llamactl-0.3.0a20.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
34
- llamactl-0.3.0a20.dist-info/entry_points.txt,sha256=b67e1eb64305058751a651a80f2d2268b5f7046732268421e796f64d4697f83c,52
35
- llamactl-0.3.0a20.dist-info/METADATA,sha256=3b8f1e3007775a3a07c1d4805e2cf92b5bc89f639290b7631d3ba076a424623d,3221
36
- llamactl-0.3.0a20.dist-info/RECORD,,
34
+ llamactl-0.3.0a21.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
35
+ llamactl-0.3.0a21.dist-info/entry_points.txt,sha256=b67e1eb64305058751a651a80f2d2268b5f7046732268421e796f64d4697f83c,52
36
+ llamactl-0.3.0a21.dist-info/METADATA,sha256=d0896ee39584b3582f370e9e099b1ea5083c53c93f18f5e1c87cad3eb3f0190b,3261
37
+ llamactl-0.3.0a21.dist-info/RECORD,,