agent-cli 0.67.1__py3-none-any.whl → 0.68.0__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.
@@ -1,6 +1,6 @@
1
1
  # This file was autogenerated by uv via the following command:
2
2
  # uv export --extra mlx-whisper --no-dev --no-emit-project --no-hashes
3
- annotated-doc==0.0.4
3
+ annotated-doc==0.0.4 ; platform_machine == 'arm64' and sys_platform == 'darwin'
4
4
  # via fastapi
5
5
  annotated-types==0.7.0
6
6
  # via pydantic
@@ -15,7 +15,7 @@ certifi==2026.1.4
15
15
  # httpx
16
16
  # requests
17
17
  # sentry-sdk
18
- charset-normalizer==3.4.4
18
+ charset-normalizer==3.4.4 ; platform_machine == 'arm64' and sys_platform == 'darwin'
19
19
  # via requests
20
20
  click==8.3.1
21
21
  # via
@@ -35,19 +35,19 @@ email-validator==2.3.0
35
35
  # via
36
36
  # fastapi
37
37
  # pydantic
38
- fastapi==0.128.0
38
+ fastapi==0.128.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
39
39
  # via agent-cli
40
- fastapi-cli==0.0.20
40
+ fastapi-cli==0.0.20 ; platform_machine == 'arm64' and sys_platform == 'darwin'
41
41
  # via fastapi
42
- fastapi-cloud-cli==0.10.1
42
+ fastapi-cloud-cli==0.10.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
43
43
  # via fastapi-cli
44
- fastar==0.8.0
44
+ fastar==0.8.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
45
45
  # via fastapi-cloud-cli
46
- filelock==3.20.3
46
+ filelock==3.20.3 ; platform_machine == 'arm64' and sys_platform == 'darwin'
47
47
  # via
48
48
  # huggingface-hub
49
49
  # torch
50
- fsspec==2026.1.0
50
+ fsspec==2026.1.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
51
51
  # via
52
52
  # huggingface-hub
53
53
  # torch
@@ -55,18 +55,18 @@ h11==0.16.0
55
55
  # via
56
56
  # httpcore
57
57
  # uvicorn
58
- hf-xet==1.2.0 ; platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
58
+ hf-xet==1.2.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
59
59
  # via huggingface-hub
60
60
  httpcore==1.0.9
61
61
  # via httpx
62
- httptools==0.7.1
62
+ httptools==0.7.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
63
63
  # via uvicorn
64
64
  httpx==0.28.1
65
65
  # via
66
66
  # agent-cli
67
67
  # fastapi
68
68
  # fastapi-cloud-cli
69
- huggingface-hub==0.36.0
69
+ huggingface-hub==0.36.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
70
70
  # via mlx-whisper
71
71
  idna==3.11
72
72
  # via
@@ -74,77 +74,38 @@ idna==3.11
74
74
  # email-validator
75
75
  # httpx
76
76
  # requests
77
- jinja2==3.1.6
77
+ jinja2==3.1.6 ; platform_machine == 'arm64' and sys_platform == 'darwin'
78
78
  # via
79
79
  # fastapi
80
80
  # torch
81
- llvmlite==0.46.0
81
+ llvmlite==0.46.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
82
82
  # via numba
83
83
  markdown-it-py==4.0.0
84
84
  # via rich
85
- markupsafe==3.0.3
85
+ markupsafe==3.0.3 ; platform_machine == 'arm64' and sys_platform == 'darwin'
86
86
  # via jinja2
87
87
  mdurl==0.1.2
88
88
  # via markdown-it-py
89
- mlx==0.30.3
89
+ mlx==0.30.3 ; platform_machine == 'arm64' and sys_platform == 'darwin'
90
90
  # via mlx-whisper
91
- mlx-metal==0.30.3 ; sys_platform == 'darwin'
91
+ mlx-metal==0.30.3 ; platform_machine == 'arm64' and sys_platform == 'darwin'
92
92
  # via mlx
93
- mlx-whisper==0.4.3
93
+ mlx-whisper==0.4.3 ; platform_machine == 'arm64' and sys_platform == 'darwin'
94
94
  # via agent-cli
95
- more-itertools==10.8.0
95
+ more-itertools==10.8.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
96
96
  # via mlx-whisper
97
- mpmath==1.3.0
97
+ mpmath==1.3.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
98
98
  # via sympy
99
- networkx==3.6.1
99
+ networkx==3.6.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
100
100
  # via torch
101
- numba==0.63.1
101
+ numba==0.63.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
102
102
  # via mlx-whisper
103
- numpy==2.3.5
103
+ numpy==2.3.5 ; platform_machine == 'arm64' and sys_platform == 'darwin'
104
104
  # via
105
105
  # mlx-whisper
106
106
  # numba
107
107
  # scipy
108
- nvidia-cublas-cu12==12.8.4.1 ; platform_machine == 'x86_64' and sys_platform == 'linux'
109
- # via
110
- # nvidia-cudnn-cu12
111
- # nvidia-cusolver-cu12
112
- # torch
113
- nvidia-cuda-cupti-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
114
- # via torch
115
- nvidia-cuda-nvrtc-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux'
116
- # via torch
117
- nvidia-cuda-runtime-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
118
- # via torch
119
- nvidia-cudnn-cu12==9.10.2.21 ; platform_machine == 'x86_64' and sys_platform == 'linux'
120
- # via torch
121
- nvidia-cufft-cu12==11.3.3.83 ; platform_machine == 'x86_64' and sys_platform == 'linux'
122
- # via torch
123
- nvidia-cufile-cu12==1.13.1.3 ; platform_machine == 'x86_64' and sys_platform == 'linux'
124
- # via torch
125
- nvidia-curand-cu12==10.3.9.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
126
- # via torch
127
- nvidia-cusolver-cu12==11.7.3.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
128
- # via torch
129
- nvidia-cusparse-cu12==12.5.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux'
130
- # via
131
- # nvidia-cusolver-cu12
132
- # torch
133
- nvidia-cusparselt-cu12==0.7.1 ; platform_machine == 'x86_64' and sys_platform == 'linux'
134
- # via torch
135
- nvidia-nccl-cu12==2.27.5 ; platform_machine == 'x86_64' and sys_platform == 'linux'
136
- # via torch
137
- nvidia-nvjitlink-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux'
138
- # via
139
- # nvidia-cufft-cu12
140
- # nvidia-cusolver-cu12
141
- # nvidia-cusparse-cu12
142
- # torch
143
- nvidia-nvshmem-cu12==3.3.20 ; platform_machine == 'x86_64' and sys_platform == 'linux'
144
- # via torch
145
- nvidia-nvtx-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
146
- # via torch
147
- packaging==25.0
108
+ packaging==25.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
148
109
  # via huggingface-hub
149
110
  psutil==7.2.1 ; sys_platform == 'win32'
150
111
  # via agent-cli
@@ -157,9 +118,9 @@ pydantic==2.12.5
157
118
  # pydantic-settings
158
119
  pydantic-core==2.41.5
159
120
  # via pydantic
160
- pydantic-extra-types==2.11.0
121
+ pydantic-extra-types==2.11.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
161
122
  # via fastapi
162
- pydantic-settings==2.12.0
123
+ pydantic-settings==2.12.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
163
124
  # via fastapi
164
125
  pygments==2.19.2
165
126
  # via rich
@@ -170,15 +131,15 @@ python-dotenv==1.2.1
170
131
  # dotenv
171
132
  # pydantic-settings
172
133
  # uvicorn
173
- python-multipart==0.0.21
134
+ python-multipart==0.0.21 ; platform_machine == 'arm64' and sys_platform == 'darwin'
174
135
  # via fastapi
175
- pyyaml==6.0.3
136
+ pyyaml==6.0.3 ; platform_machine == 'arm64' and sys_platform == 'darwin'
176
137
  # via
177
138
  # huggingface-hub
178
139
  # uvicorn
179
- regex==2026.1.15
140
+ regex==2026.1.15 ; platform_machine == 'arm64' and sys_platform == 'darwin'
180
141
  # via tiktoken
181
- requests==2.32.5
142
+ requests==2.32.5 ; platform_machine == 'arm64' and sys_platform == 'darwin'
182
143
  # via
183
144
  # huggingface-hub
184
145
  # tiktoken
@@ -187,36 +148,34 @@ rich==14.2.0
187
148
  # agent-cli
188
149
  # rich-toolkit
189
150
  # typer
190
- rich-toolkit==0.17.1
151
+ rich-toolkit==0.17.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
191
152
  # via
192
153
  # fastapi-cli
193
154
  # fastapi-cloud-cli
194
- rignore==0.7.6
155
+ rignore==0.7.6 ; platform_machine == 'arm64' and sys_platform == 'darwin'
195
156
  # via fastapi-cloud-cli
196
- scipy==1.17.0
157
+ scipy==1.17.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
197
158
  # via mlx-whisper
198
- sentry-sdk==2.49.0
159
+ sentry-sdk==2.49.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
199
160
  # via fastapi-cloud-cli
200
161
  setproctitle==1.3.7
201
162
  # via agent-cli
202
- setuptools==80.9.0 ; python_full_version >= '3.12'
163
+ setuptools==80.9.0 ; python_full_version >= '3.12' and platform_machine == 'arm64' and sys_platform == 'darwin'
203
164
  # via torch
204
165
  shellingham==1.5.4
205
166
  # via typer
206
- starlette==0.50.0
167
+ starlette==0.50.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
207
168
  # via fastapi
208
- sympy==1.14.0
169
+ sympy==1.14.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
209
170
  # via torch
210
- tiktoken==0.12.0
171
+ tiktoken==0.12.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
211
172
  # via mlx-whisper
212
- torch==2.9.1
173
+ torch==2.9.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
213
174
  # via mlx-whisper
214
- tqdm==4.67.1
175
+ tqdm==4.67.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
215
176
  # via
216
177
  # huggingface-hub
217
178
  # mlx-whisper
218
- triton==3.5.1 ; platform_machine == 'x86_64' and sys_platform == 'linux'
219
- # via torch
220
179
  typer==0.21.1
221
180
  # via
222
181
  # agent-cli
@@ -239,18 +198,18 @@ typing-inspection==0.4.2
239
198
  # via
240
199
  # pydantic
241
200
  # pydantic-settings
242
- urllib3==2.3.0
201
+ urllib3==2.3.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
243
202
  # via
244
203
  # requests
245
204
  # sentry-sdk
246
- uvicorn==0.40.0
205
+ uvicorn==0.40.0 ; platform_machine == 'arm64' and sys_platform == 'darwin'
247
206
  # via
248
207
  # fastapi
249
208
  # fastapi-cli
250
209
  # fastapi-cloud-cli
251
- uvloop==0.22.1 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'
210
+ uvloop==0.22.1 ; platform_machine == 'arm64' and platform_python_implementation != 'PyPy' and sys_platform == 'darwin'
252
211
  # via uvicorn
253
- watchfiles==1.1.1
212
+ watchfiles==1.1.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
254
213
  # via uvicorn
255
- websockets==15.0.1
214
+ websockets==15.0.1 ; platform_machine == 'arm64' and sys_platform == 'darwin'
256
215
  # via uvicorn
agent_cli/core/deps.py CHANGED
@@ -4,19 +4,29 @@ from __future__ import annotations
4
4
 
5
5
  import functools
6
6
  import json
7
+ import os
7
8
  from importlib.util import find_spec
8
9
  from pathlib import Path
9
10
  from typing import TYPE_CHECKING, TypeVar
10
11
 
11
12
  import typer
12
13
 
13
- from agent_cli.core.utils import print_error_message
14
+ from agent_cli.config import load_config
15
+ from agent_cli.core.utils import console, print_error_message
14
16
 
15
17
  if TYPE_CHECKING:
16
18
  from collections.abc import Callable
17
19
 
18
20
  F = TypeVar("F", bound="Callable[..., object]")
19
21
 
22
+
23
+ def _get_auto_install_setting() -> bool:
24
+ """Check if auto-install is enabled (default: True)."""
25
+ if os.environ.get("AGENT_CLI_NO_AUTO_INSTALL", "").lower() in ("1", "true", "yes"):
26
+ return False
27
+ return load_config().get("settings", {}).get("auto_install_extras", True)
28
+
29
+
20
30
  # Load extras from JSON file
21
31
  _EXTRAS_FILE = Path(__file__).parent.parent / "_extras.json"
22
32
  EXTRAS: dict[str, tuple[str, list[str]]] = {
@@ -44,95 +54,137 @@ def check_extra_installed(extra: str) -> bool:
44
54
  return any(check_extra_installed(e) for e in extra.split("|"))
45
55
 
46
56
  if extra not in EXTRAS:
47
- return True # Unknown extra, assume OK
57
+ return False # Unknown extra, trigger install attempt to surface error
48
58
  _, packages = EXTRAS[extra]
49
59
 
50
60
  # All packages must be installed
51
61
  return all(_check_package_installed(pkg) for pkg in packages)
52
62
 
53
63
 
64
+ def _format_extra_item(extra: str) -> str:
65
+ """Format a single extra as a list item with description."""
66
+ desc, _ = EXTRAS.get(extra, ("", []))
67
+ if desc:
68
+ return f" - '{extra}' ({desc})"
69
+ return f" - '{extra}'"
70
+
71
+
72
+ def _format_install_commands(extras: list[str]) -> list[str]:
73
+ """Format install commands for one or more extras."""
74
+ combined = ",".join(extras)
75
+ extras_args = " ".join(extras)
76
+ return [
77
+ "Install with:",
78
+ f' [bold cyan]uv tool install -p 3.13 "agent-cli\\[{combined}]"[/bold cyan]',
79
+ " # or",
80
+ f" [bold cyan]agent-cli install-extras {extras_args}[/bold cyan]",
81
+ ]
82
+
83
+
54
84
  def get_install_hint(extra: str) -> str:
55
- """Get install command hint for an extra.
85
+ """Get install command hint for a single extra.
56
86
 
57
87
  Supports `|` syntax for alternatives: "piper|kokoro" shows both options.
58
88
  """
59
89
  # Handle "extra1|extra2" syntax - show all options
60
90
  if "|" in extra:
61
91
  alternatives = extra.split("|")
62
- options = []
63
- for alt in alternatives:
64
- desc, _ = EXTRAS.get(alt, ("", []))
65
- options.append((alt, desc))
66
-
67
92
  lines = ["This command requires one of:"]
68
- for alt, desc in options:
69
- if desc:
70
- lines.append(f" - '{alt}' ({desc})")
71
- else:
72
- lines.append(f" - '{alt}'")
93
+ lines.extend(_format_extra_item(alt) for alt in alternatives)
73
94
  lines.append("")
74
95
  lines.append("Install one with:")
75
- for alt, _ in options:
76
- lines.append(f' uv tool install "agent-cli[{alt}]" -p 3.13')
96
+ lines.extend(
97
+ f' [bold cyan]uv tool install -p 3.13 "agent-cli\\[{alt}]"[/bold cyan]'
98
+ for alt in alternatives
99
+ )
77
100
  lines.append(" # or")
78
- for alt, _ in options:
79
- lines.append(f" agent-cli install-extras {alt}")
101
+ lines.extend(
102
+ f" [bold cyan]agent-cli install-extras {alt}[/bold cyan]" for alt in alternatives
103
+ )
80
104
  return "\n".join(lines)
81
105
 
82
106
  desc, _ = EXTRAS.get(extra, ("", []))
83
- lines = [
84
- f"This command requires the '{extra}' extra",
85
- ]
107
+ header = f"This command requires the '{extra}' extra"
86
108
  if desc:
87
- lines[0] += f" ({desc})"
88
- lines[0] += "."
109
+ header += f" ({desc})"
110
+ header += "."
111
+
112
+ lines = [header, ""]
113
+ lines.extend(_format_install_commands([extra]))
114
+ return "\n".join(lines)
115
+
116
+
117
+ def get_combined_install_hint(extras: list[str]) -> str:
118
+ """Get a combined install hint for multiple missing extras."""
119
+ if len(extras) == 1:
120
+ return get_install_hint(extras[0])
121
+
122
+ lines = ["This command requires the following extras:"]
123
+ lines.extend(_format_extra_item(extra) for extra in extras)
89
124
  lines.append("")
90
- lines.append("Install with:")
91
- lines.append(f' uv tool install "agent-cli[{extra}]" -p 3.13')
92
- lines.append(" # or")
93
- lines.append(f" agent-cli install-extras {extra}")
125
+ lines.extend(_format_install_commands(extras))
94
126
  return "\n".join(lines)
95
127
 
96
128
 
97
- def requires_extras(*extras: str) -> Callable[[F], F]:
98
- """Decorator to declare required extras for a command.
129
+ def _try_auto_install(missing: list[str]) -> bool:
130
+ """Attempt to auto-install missing extras. Returns True if successful."""
131
+ from agent_cli.install.extras import install_extras_programmatic # noqa: PLC0415
132
+
133
+ # Flatten alternatives (e.g., "piper|kokoro" -> just pick the first one)
134
+ extras_to_install = []
135
+ for extra in missing:
136
+ if "|" in extra:
137
+ # For alternatives, install the first option
138
+ extras_to_install.append(extra.split("|")[0])
139
+ else:
140
+ extras_to_install.append(extra)
99
141
 
100
- When a required extra is missing, the decorator prints a helpful error
101
- message and exits with code 1.
142
+ console.print(
143
+ f"[yellow]Auto-installing missing extras: {', '.join(extras_to_install)}[/]",
144
+ )
145
+ return install_extras_programmatic(extras_to_install)
102
146
 
103
- The decorator stores the required extras on the function for test validation.
104
147
 
105
- Process management flags (--stop, --status, --toggle) skip the dependency
106
- check since they just manage running processes without using the actual
107
- dependencies.
148
+ def _check_and_install_extras(extras: tuple[str, ...]) -> list[str]:
149
+ """Check for missing extras and attempt auto-install. Returns list of still-missing."""
150
+ missing = [e for e in extras if not check_extra_installed(e)]
151
+ if not missing:
152
+ return []
108
153
 
109
- Example:
110
- @app.command("rag-proxy")
111
- @requires_extras("rag")
112
- def rag_proxy(...):
113
- ...
154
+ if not _get_auto_install_setting():
155
+ print_error_message(get_combined_install_hint(missing))
156
+ return missing
157
+
158
+ if not _try_auto_install(missing):
159
+ print_error_message("Auto-install failed.\n" + get_combined_install_hint(missing))
160
+ return missing
161
+
162
+ console.print("[green]Installation complete![/]")
163
+ still_missing = [e for e in extras if not check_extra_installed(e)]
164
+ if still_missing:
165
+ print_error_message(
166
+ "Auto-install completed but some dependencies are still missing.\n"
167
+ + get_combined_install_hint(still_missing),
168
+ )
169
+ return still_missing
170
+
171
+
172
+ def requires_extras(*extras: str) -> Callable[[F], F]:
173
+ """Decorator to declare required extras for a command.
114
174
 
175
+ Auto-installs missing extras by default. Disable via AGENT_CLI_NO_AUTO_INSTALL=1
176
+ or config [settings] auto_install_extras = false.
115
177
  """
116
178
 
117
179
  def decorator(func: F) -> F:
118
- # Store extras on function for test introspection
119
180
  func._required_extras = extras # type: ignore[attr-defined]
120
181
 
121
182
  @functools.wraps(func)
122
183
  def wrapper(*args: object, **kwargs: object) -> object:
123
- # Skip dependency check for process management and info operations
124
- # These don't need the actual dependencies, just manage processes or list info
125
- if any(kwargs.get(flag) for flag in ("stop", "status", "toggle", "list_devices")):
126
- return func(*args, **kwargs)
127
-
128
- missing = [e for e in extras if not check_extra_installed(e)]
129
- if missing:
130
- for extra in missing:
131
- print_error_message(get_install_hint(extra))
184
+ if _check_and_install_extras(extras):
132
185
  raise typer.Exit(1)
133
186
  return func(*args, **kwargs)
134
187
 
135
- # Preserve the extras on wrapper too
136
188
  wrapper._required_extras = extras # type: ignore[attr-defined]
137
189
  return wrapper # type: ignore[return-value]
138
190
 
agent_cli/core/utils.py CHANGED
@@ -211,8 +211,8 @@ def print_output_panel(
211
211
 
212
212
 
213
213
  def print_error_message(message: str, suggestion: str | None = None) -> None:
214
- """Prints an error message in a panel."""
215
- error_text = Text(message)
214
+ """Prints an error message in a panel with rich markup support."""
215
+ error_text = Text.from_markup(message)
216
216
  if suggestion:
217
217
  error_text.append("\n\n")
218
218
  error_text.append(suggestion)
@@ -86,6 +86,38 @@ def _install_cmd() -> list[str]:
86
86
  return cmd
87
87
 
88
88
 
89
+ def _install_extras_impl(extras: list[str], *, quiet: bool = False) -> bool:
90
+ """Install extras. Returns True on success, False on failure."""
91
+ if _is_uv_tool_install():
92
+ current_extras = _get_current_uv_tool_extras()
93
+ new_extras = sorted(set(current_extras) | set(extras))
94
+ return _install_via_uv_tool(new_extras)
95
+
96
+ cmd = _install_cmd()
97
+ for extra in extras:
98
+ req_file = _requirements_path(extra)
99
+ if not quiet:
100
+ console.print(f"Installing [cyan]{extra}[/]...")
101
+ result = subprocess.run(
102
+ [*cmd, "-r", str(req_file)],
103
+ check=False,
104
+ capture_output=quiet,
105
+ )
106
+ if result.returncode != 0:
107
+ return False
108
+ return True
109
+
110
+
111
+ def install_extras_programmatic(extras: list[str], *, quiet: bool = False) -> bool:
112
+ """Install extras programmatically (for auto-install feature)."""
113
+ available = _available_extras()
114
+ valid = [e for e in extras if e in available]
115
+ invalid = [e for e in extras if e not in available]
116
+ if invalid:
117
+ console.print(f"[yellow]Unknown extras (skipped): {', '.join(invalid)}[/]")
118
+ return bool(valid) and _install_extras_impl(valid, quiet=quiet)
119
+
120
+
89
121
  @app.command("install-extras", rich_help_panel="Installation")
90
122
  def install_extras(
91
123
  extras: Annotated[list[str] | None, typer.Argument(help="Extras to install")] = None,
@@ -128,25 +160,11 @@ def install_extras(
128
160
  print_error_message(f"Unknown extras: {invalid}. Use --list to see available.")
129
161
  raise typer.Exit(1)
130
162
 
131
- # If running from uv tool install, reinstall with extras to persist them
163
+ if not _install_extras_impl(extras):
164
+ print_error_message("Failed to install extras")
165
+ raise typer.Exit(1)
166
+
132
167
  if _is_uv_tool_install():
133
- current_extras = _get_current_uv_tool_extras()
134
- new_extras = sorted(set(current_extras) | set(extras))
135
- if not _install_via_uv_tool(new_extras):
136
- print_error_message("Failed to reinstall via uv tool")
137
- raise typer.Exit(1)
138
168
  console.print("[green]Done! Extras will persist across uv tool upgrade.[/]")
139
- return
140
-
141
- # Standard pip/uv pip install for non-tool environments
142
- cmd = _install_cmd()
143
-
144
- for extra in extras:
145
- req_file = _requirements_path(extra)
146
- console.print(f"Installing [cyan]{extra}[/]...")
147
- result = subprocess.run([*cmd, "-r", str(req_file)], check=False)
148
- if result.returncode != 0:
149
- print_error_message(f"Failed to install '{extra}'")
150
- raise typer.Exit(1)
151
-
152
- console.print("[green]Done![/]")
169
+ else:
170
+ console.print("[green]Done![/]")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-cli
3
- Version: 0.67.1
3
+ Version: 0.68.0
4
4
  Summary: A suite of AI-powered command-line tools for text correction, audio transcription, and voice assistance.
5
5
  Project-URL: Homepage, https://github.com/basnijholt/agent-cli
6
6
  Author-email: Bas Nijholt <bas@nijho.lt>
@@ -52,8 +52,8 @@ Requires-Dist: pyyaml>=6.0.0; extra == 'memory'
52
52
  Requires-Dist: transformers>=4.30.0; extra == 'memory'
53
53
  Requires-Dist: watchfiles>=0.21.0; extra == 'memory'
54
54
  Provides-Extra: mlx-whisper
55
- Requires-Dist: fastapi[standard]; extra == 'mlx-whisper'
56
- Requires-Dist: mlx-whisper>=0.4.0; extra == 'mlx-whisper'
55
+ Requires-Dist: fastapi[standard]; (sys_platform == 'darwin' and platform_machine == 'arm64') and extra == 'mlx-whisper'
56
+ Requires-Dist: mlx-whisper>=0.4.0; (sys_platform == 'darwin' and platform_machine == 'arm64') and extra == 'mlx-whisper'
57
57
  Provides-Extra: piper
58
58
  Requires-Dist: fastapi[standard]; extra == 'piper'
59
59
  Requires-Dist: piper-tts>=1.2.0; extra == 'piper'
@@ -459,7 +459,14 @@ All necessary scripts are bundled with the package, so you can run these command
459
459
 
460
460
  #### Installing Optional Extras
461
461
 
462
- Some features require additional Python dependencies. Use `install-extras` to install them with pinned versions:
462
+ Some features require additional Python dependencies. By default, **agent-cli will auto-install missing extras** when you run a command that needs them. To disable this, set `AGENT_CLI_NO_AUTO_INSTALL=1` or add to your config file:
463
+
464
+ ```toml
465
+ [settings]
466
+ auto_install_extras = false
467
+ ```
468
+
469
+ You can also manually install extras with `install-extras`:
463
470
 
464
471
  ```bash
465
472
  # List available extras
@@ -17,7 +17,7 @@ agent_cli/_requirements/faster-whisper.txt,sha256=QP8akE33gcjpHmim1zcbuPOvcOAxBG
17
17
  agent_cli/_requirements/kokoro.txt,sha256=XzvT9FvzWvMQK_ClanO0DJoyo7kqcfoCeenTT_KA3R0,8868
18
18
  agent_cli/_requirements/llm.txt,sha256=06gG3fOiye0R7bDNj2h4YmAt6WuOi1HUtuW_BBjcKMY,3459
19
19
  agent_cli/_requirements/memory.txt,sha256=RmUGuRKJvXXL1nVCZCGOKy6zvbqyzUikx5zHymk1fok,7152
20
- agent_cli/_requirements/mlx-whisper.txt,sha256=gOlprOn5sKtrBbVK0tWnzc-CkGzII_X2URa2vpY5cr0,6090
20
+ agent_cli/_requirements/mlx-whisper.txt,sha256=EsCSvS0ydvCJO6FzffROhjkieNNqaGHDI2iUSCTSN_o,6626
21
21
  agent_cli/_requirements/piper.txt,sha256=LGm1gQopXgpDbgjTyWJpWYwEjjHSb86DDn48qoHnZgU,3332
22
22
  agent_cli/_requirements/rag.txt,sha256=5zDS0BtxcB0Ig8zw8IXWTMzgTmSTNj0MMzR9G9olrIc,8127
23
23
  agent_cli/_requirements/server.txt,sha256=k4ALhN4oR2e4amz4_1lQ2_hxB6MXg5LaGtlfn5EOc-s,2881
@@ -40,13 +40,13 @@ agent_cli/core/__init__.py,sha256=c_knH7u9QgjsfMIil9NP4bVizHawLUMYoQWU4H9vMlQ,46
40
40
  agent_cli/core/audio.py,sha256=43FpYe2Wu_BYK9xJ_55V4xHjHJeFwQ5aM-CQzlTryt8,15168
41
41
  agent_cli/core/audio_format.py,sha256=zk3qlYMAlKYPz1enrjihQQspl_C218v1Rbcm7Uktlew,8773
42
42
  agent_cli/core/chroma.py,sha256=Vb_ny7SzAIL9SCEGlYgYOqsdG9BgusFGMj0RUzb6W90,2728
43
- agent_cli/core/deps.py,sha256=duZEIAJwx_faJr0E2yGn-UJDb8t1uEBcx6MEYNK7TDc,4587
43
+ agent_cli/core/deps.py,sha256=58zyHSJdzIAkJ0gZ7-snrASy8Ro9NePZmElch13r-SQ,6429
44
44
  agent_cli/core/openai_proxy.py,sha256=f2kqxk6bAOeN7gOzU0JnyS-RYtXUcK5Gbsa_pBmlCv0,4470
45
45
  agent_cli/core/process.py,sha256=Zay6beX4JUbkBHr6xbJxwVBjVFDABmRHQCXVPQH93r8,5916
46
46
  agent_cli/core/reranker.py,sha256=Qv5ASGUdseLzI6eQRfNeQY-Lvv4SOgLOu56CpwmszDM,3779
47
47
  agent_cli/core/sse.py,sha256=SddiWjHh7DENb1wmvf3wDvX-OhbaC61EceFwQxmDUEo,2232
48
48
  agent_cli/core/transcription_logger.py,sha256=PVVfQK0leoB9JwUu5jYAhyRDBVq9exiPC0_KNXV8ggY,2057
49
- agent_cli/core/utils.py,sha256=MHttXeGiM9qGUNxK0s6vAHthh033TDjaruqocdtMMFY,16802
49
+ agent_cli/core/utils.py,sha256=CrydXrpnD3nRX8zfN5i_17Qu2OhZxfor33mtptfRwho,16839
50
50
  agent_cli/core/vad.py,sha256=67-EBjY-pTOf61VhrjVdDXgaNIBwWFFFccYth_1rQmg,6569
51
51
  agent_cli/core/watch.py,sha256=MKgGxxMe0yLlu78-XXqO4ferCpu_ljNr4MAzOMDsuuo,1951
52
52
  agent_cli/dev/__init__.py,sha256=doTYiUFEBpnOxsQA69HQP9AA4QHBN0DjuHSTGRq5Xbg,551
@@ -91,7 +91,7 @@ agent_cli/dev/terminals/warp.py,sha256=j-Jvz_BbWYC3QfLrvl4CbDh03c9OGRFmuCzjyB2ud
91
91
  agent_cli/dev/terminals/zellij.py,sha256=GnQnopimb9XH67CZGHjnbVWpVSWhaLCATGJizCT5TkY,2321
92
92
  agent_cli/install/__init__.py,sha256=JQPrOrtdNd1Y1NmQDkb3Nmm1qdyn3kPjhQwy9D8ryjI,124
93
93
  agent_cli/install/common.py,sha256=WvnmcjnFTW0d1HZrKVGzj5Tg3q8Txk_ZOdc4a1MBFWI,3121
94
- agent_cli/install/extras.py,sha256=ZknvNHXQDlg4K9Wn1Bs7tYQxx5T5wyQKi_Kea-aB1gU,5161
94
+ agent_cli/install/extras.py,sha256=BPIlMdDeUo-tsKb_9Ttx3799YsIV_yup79ESFNpoJ1o,5731
95
95
  agent_cli/install/hotkeys.py,sha256=bwGoPeEKK6VI-IrKU8Q0RLMW9smkDNU7CdqD3Nbsd-w,1626
96
96
  agent_cli/install/services.py,sha256=2s_7ThxaElKCuomBYTn4Z36TF_o_arNeyJ4f8Wh4jEI,2912
97
97
  agent_cli/memory/__init__.py,sha256=8XNpVzP-qjF8o49A_eXsH_Rbp_FmxTIcknnvxq7vHms,162
@@ -188,8 +188,8 @@ agent_cli/services/asr.py,sha256=aRaCLVCygsJ15qyQEPECOZsdSrnlLPbyY4RwAqY0qIw,172
188
188
  agent_cli/services/llm.py,sha256=Kwdo6pbMYI9oykF-RBe1iaL3KsYrNWTLdRSioewmsGQ,7199
189
189
  agent_cli/services/tts.py,sha256=NX5Qnq7ddLI3mwm3nzhbR3zB1Os4Ip4sSVSjDZDTBcI,14855
190
190
  agent_cli/services/wake_word.py,sha256=JFJ1SA22H4yko9DXiQ1t7fcoxeALLAe3iBrLs0z8rX4,4664
191
- agent_cli-0.67.1.dist-info/METADATA,sha256=wPs9-vLbAOlNEt0t87KYdgyLbSWgqIHphbzOA-lN67k,155674
192
- agent_cli-0.67.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
193
- agent_cli-0.67.1.dist-info/entry_points.txt,sha256=FUv-fB2atLsPUk_RT4zqnZl1coz4_XHFwRALOKOF38s,97
194
- agent_cli-0.67.1.dist-info/licenses/LICENSE,sha256=majJU6S9kC8R8bW39NVBHyv32Dq50FL6TDxECG2WVts,1068
195
- agent_cli-0.67.1.dist-info/RECORD,,
191
+ agent_cli-0.68.0.dist-info/METADATA,sha256=0eWIbitl8b9hqUg_Fh8fjJNd2UJ91_qZDYdynfh60GU,156032
192
+ agent_cli-0.68.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
193
+ agent_cli-0.68.0.dist-info/entry_points.txt,sha256=FUv-fB2atLsPUk_RT4zqnZl1coz4_XHFwRALOKOF38s,97
194
+ agent_cli-0.68.0.dist-info/licenses/LICENSE,sha256=majJU6S9kC8R8bW39NVBHyv32Dq50FL6TDxECG2WVts,1068
195
+ agent_cli-0.68.0.dist-info/RECORD,,