agent-cli 0.70.5__py3-none-any.whl → 0.72.1__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.
- agent_cli/_extras.json +2 -2
- agent_cli/_requirements/memory.txt +14 -1
- agent_cli/_requirements/rag.txt +14 -1
- agent_cli/_requirements/vad.txt +1 -85
- agent_cli/agents/assistant.py +23 -27
- agent_cli/agents/autocorrect.py +29 -3
- agent_cli/agents/chat.py +44 -14
- agent_cli/agents/memory/__init__.py +19 -1
- agent_cli/agents/memory/add.py +3 -3
- agent_cli/agents/memory/proxy.py +20 -11
- agent_cli/agents/rag_proxy.py +42 -10
- agent_cli/agents/speak.py +22 -2
- agent_cli/agents/transcribe.py +20 -2
- agent_cli/agents/transcribe_daemon.py +33 -21
- agent_cli/agents/voice_edit.py +17 -9
- agent_cli/cli.py +25 -2
- agent_cli/config_cmd.py +30 -11
- agent_cli/core/deps.py +6 -3
- agent_cli/core/vad.py +6 -24
- agent_cli/dev/cli.py +295 -65
- agent_cli/docs_gen.py +18 -8
- agent_cli/install/extras.py +44 -13
- agent_cli/install/hotkeys.py +22 -11
- agent_cli/install/services.py +54 -14
- agent_cli/opts.py +25 -21
- agent_cli/server/cli.py +121 -47
- {agent_cli-0.70.5.dist-info → agent_cli-0.72.1.dist-info}/METADATA +466 -195
- {agent_cli-0.70.5.dist-info → agent_cli-0.72.1.dist-info}/RECORD +31 -31
- {agent_cli-0.70.5.dist-info → agent_cli-0.72.1.dist-info}/WHEEL +0 -0
- {agent_cli-0.70.5.dist-info → agent_cli-0.72.1.dist-info}/entry_points.txt +0 -0
- {agent_cli-0.70.5.dist-info → agent_cli-0.72.1.dist-info}/licenses/LICENSE +0 -0
agent_cli/install/extras.py
CHANGED
|
@@ -14,7 +14,7 @@ import typer
|
|
|
14
14
|
|
|
15
15
|
from agent_cli.cli import app
|
|
16
16
|
from agent_cli.core.deps import EXTRAS as _EXTRAS_META
|
|
17
|
-
from agent_cli.core.utils import console, print_error_message
|
|
17
|
+
from agent_cli.core.utils import console, err_console, print_error_message
|
|
18
18
|
|
|
19
19
|
# Extract descriptions from the centralized EXTRAS metadata
|
|
20
20
|
EXTRAS: dict[str, str] = {name: desc for name, (desc, _) in _EXTRAS_META.items()}
|
|
@@ -69,7 +69,8 @@ def _install_via_uv_tool(extras: list[str], *, quiet: bool = False) -> bool:
|
|
|
69
69
|
cmd = ["uv", "tool", "install", package_spec, "--force", "--python", python_version]
|
|
70
70
|
if quiet:
|
|
71
71
|
cmd.append("-q")
|
|
72
|
-
|
|
72
|
+
# Use stderr for status messages so they don't pollute stdout (e.g., for hotkey notifications)
|
|
73
|
+
err_console.print(f"Running: [cyan]{' '.join(cmd)}[/]")
|
|
73
74
|
result = subprocess.run(cmd, check=False)
|
|
74
75
|
return result.returncode == 0
|
|
75
76
|
|
|
@@ -118,29 +119,59 @@ def install_extras_programmatic(extras: list[str], *, quiet: bool = False) -> bo
|
|
|
118
119
|
valid = [e for e in extras if e in available]
|
|
119
120
|
invalid = [e for e in extras if e not in available]
|
|
120
121
|
if invalid:
|
|
121
|
-
|
|
122
|
+
# Use stderr so warning doesn't pollute stdout (e.g., for hotkey notifications)
|
|
123
|
+
err_console.print(f"[yellow]Unknown extras (skipped): {', '.join(invalid)}[/]")
|
|
122
124
|
return bool(valid) and _install_extras_impl(valid, quiet=quiet)
|
|
123
125
|
|
|
124
126
|
|
|
125
127
|
@app.command("install-extras", rich_help_panel="Installation", no_args_is_help=True)
|
|
126
128
|
def install_extras(
|
|
127
|
-
extras: Annotated[
|
|
129
|
+
extras: Annotated[
|
|
130
|
+
list[str] | None,
|
|
131
|
+
typer.Argument(
|
|
132
|
+
help="Extras to install: `rag`, `memory`, `vad`, `audio`, `piper`, `kokoro`, "
|
|
133
|
+
"`faster-whisper`, `mlx-whisper`, `wyoming`, `server`, `speed`, `llm`",
|
|
134
|
+
),
|
|
135
|
+
] = None,
|
|
128
136
|
list_extras: Annotated[
|
|
129
137
|
bool,
|
|
130
|
-
typer.Option(
|
|
138
|
+
typer.Option(
|
|
139
|
+
"--list",
|
|
140
|
+
"-l",
|
|
141
|
+
help="Show available extras with descriptions (what each one enables)",
|
|
142
|
+
),
|
|
131
143
|
] = False,
|
|
132
144
|
all_extras: Annotated[
|
|
133
145
|
bool,
|
|
134
|
-
typer.Option("--all", "-a", help="Install all available extras"),
|
|
146
|
+
typer.Option("--all", "-a", help="Install all available extras at once"),
|
|
135
147
|
] = False,
|
|
136
148
|
) -> None:
|
|
137
|
-
"""Install optional
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
149
|
+
"""Install optional dependencies with pinned, compatible versions.
|
|
150
|
+
|
|
151
|
+
Many agent-cli features require optional dependencies. This command installs
|
|
152
|
+
them with version pinning to ensure compatibility. Dependencies persist
|
|
153
|
+
across `uv tool upgrade` when installed via `uv tool`.
|
|
154
|
+
|
|
155
|
+
**Available extras:**
|
|
156
|
+
- `rag` - RAG proxy server (ChromaDB, embeddings)
|
|
157
|
+
- `memory` - Long-term memory proxy (ChromaDB)
|
|
158
|
+
- `vad` - Voice Activity Detection (silero-vad)
|
|
159
|
+
- `audio` - Local audio recording/playback
|
|
160
|
+
- `piper` - Local Piper TTS engine
|
|
161
|
+
- `kokoro` - Kokoro neural TTS engine
|
|
162
|
+
- `faster-whisper` - Whisper ASR for CUDA/CPU
|
|
163
|
+
- `mlx-whisper` - Whisper ASR for Apple Silicon
|
|
164
|
+
- `wyoming` - Wyoming protocol for ASR/TTS servers
|
|
165
|
+
- `server` - FastAPI server components
|
|
166
|
+
- `speed` - Audio speed adjustment
|
|
167
|
+
- `llm` - LLM framework (pydantic-ai)
|
|
168
|
+
|
|
169
|
+
**Examples:**
|
|
170
|
+
|
|
171
|
+
agent-cli install-extras rag # Install RAG dependencies
|
|
172
|
+
agent-cli install-extras memory vad # Install multiple extras
|
|
173
|
+
agent-cli install-extras --list # Show available extras
|
|
174
|
+
agent-cli install-extras --all # Install all extras
|
|
144
175
|
|
|
145
176
|
"""
|
|
146
177
|
available = _available_extras()
|
agent_cli/install/hotkeys.py
CHANGED
|
@@ -13,20 +13,31 @@ from agent_cli.install.common import execute_installation_script, get_platform_s
|
|
|
13
13
|
def install_hotkeys() -> None:
|
|
14
14
|
"""Install system-wide hotkeys for agent-cli commands.
|
|
15
15
|
|
|
16
|
-
Sets up
|
|
16
|
+
Sets up three global hotkeys:
|
|
17
17
|
|
|
18
|
-
macOS
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
| Hotkey (macOS / Linux) | Action |
|
|
19
|
+
|-------------------------|-------------------------------------------------|
|
|
20
|
+
| Cmd/Super + Shift + R | Toggle voice transcription (start/stop) |
|
|
21
|
+
| Cmd/Super + Shift + A | Autocorrect clipboard text (grammar/spelling) |
|
|
22
|
+
| Cmd/Super + Shift + V | Voice edit clipboard text (voice commands) |
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
- Super+Shift+R: Toggle voice transcription
|
|
25
|
-
- Super+Shift+A: Autocorrect clipboard text
|
|
26
|
-
- Super+Shift+V: Voice edit clipboard text
|
|
24
|
+
**macOS** (fully automatic):
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
1. Installs `skhd` (hotkey daemon) and `terminal-notifier` via Homebrew
|
|
27
|
+
2. Creates config at `~/.config/skhd/skhdrc`
|
|
28
|
+
3. Starts skhd as a background service
|
|
29
|
+
4. May require Accessibility permissions: System Settings → Privacy & Security → Accessibility → enable 'skhd'
|
|
30
|
+
|
|
31
|
+
**Linux** (manual DE configuration):
|
|
32
|
+
|
|
33
|
+
1. Installs `libnotify` for notifications (if missing)
|
|
34
|
+
2. Prints binding instructions for your desktop environment
|
|
35
|
+
3. You manually add hotkeys pointing to the installed scripts
|
|
36
|
+
|
|
37
|
+
Supported Linux DEs: Hyprland, Sway, i3, GNOME, KDE, XFCE.
|
|
38
|
+
|
|
39
|
+
**Customizing hotkeys** (macOS): Edit `~/.config/skhd/skhdrc` and restart skhd:
|
|
40
|
+
`skhd --restart-service`
|
|
30
41
|
"""
|
|
31
42
|
script_name = get_platform_script("setup-macos-hotkeys.sh", "setup-linux-hotkeys.sh")
|
|
32
43
|
system = platform.system().lower()
|
agent_cli/install/services.py
CHANGED
|
@@ -20,13 +20,31 @@ from agent_cli.install.common import (
|
|
|
20
20
|
def install_services() -> None:
|
|
21
21
|
"""Install all required services (Ollama, Whisper, Piper, OpenWakeWord).
|
|
22
22
|
|
|
23
|
-
This command installs:
|
|
24
|
-
- Ollama (local LLM server)
|
|
25
|
-
- Wyoming Faster Whisper (speech-to-text)
|
|
26
|
-
- Wyoming Piper (text-to-speech)
|
|
27
|
-
- Wyoming OpenWakeWord (wake word detection)
|
|
23
|
+
This command installs the following services:
|
|
28
24
|
|
|
29
|
-
|
|
25
|
+
- **Ollama** - Local LLM server for text processing
|
|
26
|
+
- **Wyoming Faster Whisper** - Speech-to-text transcription
|
|
27
|
+
- **Wyoming Piper** - Text-to-speech synthesis
|
|
28
|
+
- **Wyoming OpenWakeWord** - Wake word detection ("ok nabu", etc.)
|
|
29
|
+
|
|
30
|
+
The appropriate installation method is used based on your operating system
|
|
31
|
+
(Homebrew on macOS, apt/pip on Linux).
|
|
32
|
+
|
|
33
|
+
**Requirements:**
|
|
34
|
+
|
|
35
|
+
- macOS: Homebrew must be installed
|
|
36
|
+
- Linux: Requires sudo access for system packages
|
|
37
|
+
|
|
38
|
+
**Examples:**
|
|
39
|
+
|
|
40
|
+
Install all services:
|
|
41
|
+
`agent-cli install-services`
|
|
42
|
+
|
|
43
|
+
**After installation:**
|
|
44
|
+
|
|
45
|
+
1. Start the services: `agent-cli start-services`
|
|
46
|
+
2. Test transcription: `agent-cli transcribe --list-devices`
|
|
47
|
+
3. Set up hotkeys (optional): `agent-cli install-hotkeys`
|
|
30
48
|
"""
|
|
31
49
|
script_name = get_platform_script("setup-macos.sh", "setup-linux.sh")
|
|
32
50
|
|
|
@@ -46,19 +64,41 @@ def start_services(
|
|
|
46
64
|
attach: bool = typer.Option(
|
|
47
65
|
True, # noqa: FBT003
|
|
48
66
|
"--attach/--no-attach",
|
|
49
|
-
help=
|
|
67
|
+
help=(
|
|
68
|
+
"Attach to the Zellij session after starting. "
|
|
69
|
+
"With `--no-attach`, services start in background and you can "
|
|
70
|
+
"reattach later with `zellij attach agent-cli`"
|
|
71
|
+
),
|
|
50
72
|
),
|
|
51
73
|
) -> None:
|
|
52
74
|
"""Start all agent-cli services in a Zellij session.
|
|
53
75
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
- Wyoming
|
|
58
|
-
- Wyoming
|
|
76
|
+
Starts these services, each in its own Zellij pane:
|
|
77
|
+
|
|
78
|
+
- **Ollama** - LLM server (port 11434)
|
|
79
|
+
- **Wyoming Whisper** - Speech-to-text (port 10300)
|
|
80
|
+
- **Wyoming Piper** - Text-to-speech (port 10200)
|
|
81
|
+
- **Wyoming OpenWakeWord** - Wake word detection (port 10400)
|
|
82
|
+
|
|
83
|
+
Services run in a Zellij terminal multiplexer session named `agent-cli`.
|
|
84
|
+
If a session already exists, the command attaches to it instead of
|
|
85
|
+
starting new services.
|
|
86
|
+
|
|
87
|
+
**Keyboard shortcuts:**
|
|
88
|
+
- `Ctrl-O d` - Detach (keeps services running in background)
|
|
89
|
+
- `Ctrl-Q` - Quit (stops all services)
|
|
90
|
+
- `Alt + arrows` - Navigate between panes
|
|
91
|
+
|
|
92
|
+
**Examples:**
|
|
93
|
+
|
|
94
|
+
Start services and attach:
|
|
95
|
+
`agent-cli start-services`
|
|
96
|
+
|
|
97
|
+
Start in background (for scripts or automation):
|
|
98
|
+
`agent-cli start-services --no-attach`
|
|
59
99
|
|
|
60
|
-
|
|
61
|
-
|
|
100
|
+
Reattach to running services:
|
|
101
|
+
`zellij attach agent-cli`
|
|
62
102
|
"""
|
|
63
103
|
try:
|
|
64
104
|
script_path = get_script_path("start-all-services.sh")
|
agent_cli/opts.py
CHANGED
|
@@ -47,7 +47,8 @@ TTS_PROVIDER: str = typer.Option(
|
|
|
47
47
|
LLM: bool = typer.Option(
|
|
48
48
|
False, # noqa: FBT003
|
|
49
49
|
"--llm/--no-llm",
|
|
50
|
-
help="
|
|
50
|
+
help="Clean up transcript with LLM: fix errors, add punctuation, remove filler words. "
|
|
51
|
+
"Uses `--extra-instructions` if set (via CLI or config file).",
|
|
51
52
|
rich_help_panel="LLM Configuration",
|
|
52
53
|
)
|
|
53
54
|
# Ollama (local service)
|
|
@@ -114,19 +115,19 @@ EMBEDDING_MODEL: str = typer.Option(
|
|
|
114
115
|
INPUT_DEVICE_INDEX: int | None = typer.Option(
|
|
115
116
|
None,
|
|
116
117
|
"--input-device-index",
|
|
117
|
-
help="
|
|
118
|
+
help="Audio input device index (see `--list-devices`). Uses system default if omitted.",
|
|
118
119
|
rich_help_panel="Audio Input",
|
|
119
120
|
)
|
|
120
121
|
INPUT_DEVICE_NAME: str | None = typer.Option(
|
|
121
122
|
None,
|
|
122
123
|
"--input-device-name",
|
|
123
|
-
help="
|
|
124
|
+
help="Select input device by name substring (e.g., `MacBook` or `USB`).",
|
|
124
125
|
rich_help_panel="Audio Input",
|
|
125
126
|
)
|
|
126
127
|
LIST_DEVICES: bool = typer.Option(
|
|
127
128
|
False, # noqa: FBT003
|
|
128
129
|
"--list-devices",
|
|
129
|
-
help="List available audio
|
|
130
|
+
help="List available audio devices with their indices and exit.",
|
|
130
131
|
is_eager=True,
|
|
131
132
|
rich_help_panel="Audio Input",
|
|
132
133
|
)
|
|
@@ -181,7 +182,7 @@ ASR_GEMINI_MODEL: str = typer.Option(
|
|
|
181
182
|
WAKE_SERVER_IP: str = typer.Option(
|
|
182
183
|
"localhost",
|
|
183
184
|
"--wake-server-ip",
|
|
184
|
-
help="Wyoming wake word server IP
|
|
185
|
+
help="Wyoming wake word server IP (requires wyoming-openwakeword or similar).",
|
|
185
186
|
rich_help_panel="Wake Word",
|
|
186
187
|
)
|
|
187
188
|
WAKE_SERVER_PORT: int = typer.Option(
|
|
@@ -193,7 +194,7 @@ WAKE_SERVER_PORT: int = typer.Option(
|
|
|
193
194
|
WAKE_WORD: str = typer.Option(
|
|
194
195
|
"ok_nabu",
|
|
195
196
|
"--wake-word",
|
|
196
|
-
help="
|
|
197
|
+
help="Wake word to detect. Common options: `ok_nabu`, `hey_jarvis`, `alexa`. Must match a model loaded in your wake word server.",
|
|
197
198
|
rich_help_panel="Wake Word",
|
|
198
199
|
)
|
|
199
200
|
|
|
@@ -215,13 +216,13 @@ TTS_SPEED: float = typer.Option(
|
|
|
215
216
|
OUTPUT_DEVICE_INDEX: int | None = typer.Option(
|
|
216
217
|
None,
|
|
217
218
|
"--output-device-index",
|
|
218
|
-
help="
|
|
219
|
+
help="Audio output device index (see `--list-devices` for available devices).",
|
|
219
220
|
rich_help_panel="Audio Output",
|
|
220
221
|
)
|
|
221
222
|
OUTPUT_DEVICE_NAME: str | None = typer.Option(
|
|
222
223
|
None,
|
|
223
224
|
"--output-device-name",
|
|
224
|
-
help="
|
|
225
|
+
help="Partial match on device name (e.g., 'speakers', 'headphones').",
|
|
225
226
|
rich_help_panel="Audio Output",
|
|
226
227
|
)
|
|
227
228
|
# Wyoming (local service)
|
|
@@ -265,7 +266,7 @@ TTS_OPENAI_MODEL: str = typer.Option(
|
|
|
265
266
|
TTS_OPENAI_VOICE: str = typer.Option(
|
|
266
267
|
"alloy",
|
|
267
268
|
"--tts-openai-voice",
|
|
268
|
-
help="
|
|
269
|
+
help="Voice for OpenAI TTS (alloy, echo, fable, onyx, nova, shimmer).",
|
|
269
270
|
rich_help_panel="Audio Output: OpenAI-compatible",
|
|
270
271
|
)
|
|
271
272
|
TTS_OPENAI_BASE_URL: str | None = typer.Option(
|
|
@@ -315,21 +316,19 @@ TTS_GEMINI_VOICE: str = typer.Option(
|
|
|
315
316
|
STOP: bool = typer.Option(
|
|
316
317
|
False, # noqa: FBT003
|
|
317
318
|
"--stop",
|
|
318
|
-
help="Stop any running
|
|
319
|
+
help="Stop any running instance of this command.",
|
|
319
320
|
rich_help_panel="Process Management",
|
|
320
321
|
)
|
|
321
322
|
STATUS: bool = typer.Option(
|
|
322
323
|
False, # noqa: FBT003
|
|
323
324
|
"--status",
|
|
324
|
-
help="Check if
|
|
325
|
+
help="Check if an instance is currently running.",
|
|
325
326
|
rich_help_panel="Process Management",
|
|
326
327
|
)
|
|
327
328
|
TOGGLE: bool = typer.Option(
|
|
328
329
|
False, # noqa: FBT003
|
|
329
330
|
"--toggle",
|
|
330
|
-
help="
|
|
331
|
-
"If the process is running, it will be stopped. "
|
|
332
|
-
"If the process is not running, it will be started.",
|
|
331
|
+
help="Start if not running, stop if running. Ideal for hotkey binding.",
|
|
333
332
|
rich_help_panel="Process Management",
|
|
334
333
|
)
|
|
335
334
|
|
|
@@ -365,13 +364,14 @@ CLIPBOARD: bool = typer.Option(
|
|
|
365
364
|
rich_help_panel="General Options",
|
|
366
365
|
)
|
|
367
366
|
LOG_LEVEL: LogLevel = typer.Option(
|
|
368
|
-
"
|
|
367
|
+
"warning",
|
|
369
368
|
"--log-level",
|
|
370
369
|
envvar="LOG_LEVEL",
|
|
371
370
|
help="Set logging level.",
|
|
372
371
|
case_sensitive=False,
|
|
373
372
|
rich_help_panel="General Options",
|
|
374
373
|
)
|
|
374
|
+
SERVER_LOG_LEVEL: LogLevel = with_default(LOG_LEVEL, "info")
|
|
375
375
|
LOG_FILE: str | None = typer.Option(
|
|
376
376
|
None,
|
|
377
377
|
"--log-file",
|
|
@@ -388,19 +388,20 @@ QUIET: bool = typer.Option(
|
|
|
388
388
|
JSON_OUTPUT: bool = typer.Option(
|
|
389
389
|
False, # noqa: FBT003
|
|
390
390
|
"--json",
|
|
391
|
-
help="Output result as JSON
|
|
391
|
+
help="Output result as JSON (implies `--quiet` and `--no-clipboard`).",
|
|
392
392
|
rich_help_panel="General Options",
|
|
393
393
|
)
|
|
394
394
|
SAVE_FILE: Path | None = typer.Option(
|
|
395
395
|
None,
|
|
396
396
|
"--save-file",
|
|
397
|
-
help="Save
|
|
397
|
+
help="Save audio to WAV file instead of playing through speakers.",
|
|
398
398
|
rich_help_panel="General Options",
|
|
399
399
|
)
|
|
400
400
|
TRANSCRIPTION_LOG: Path | None = typer.Option(
|
|
401
401
|
None,
|
|
402
402
|
"--transcription-log",
|
|
403
|
-
help="
|
|
403
|
+
help="Append transcripts to JSONL file (timestamp, hostname, model, raw/processed text). "
|
|
404
|
+
"Recent entries provide context for LLM cleanup.",
|
|
404
405
|
rich_help_panel="General Options",
|
|
405
406
|
)
|
|
406
407
|
|
|
@@ -416,18 +417,21 @@ SERVER_HOST: str = typer.Option(
|
|
|
416
417
|
FROM_FILE: Path | None = typer.Option(
|
|
417
418
|
None,
|
|
418
419
|
"--from-file",
|
|
419
|
-
help="Transcribe
|
|
420
|
+
help="Transcribe from audio file instead of microphone. "
|
|
421
|
+
"Supports wav, mp3, m4a, ogg, flac, aac, webm. "
|
|
422
|
+
"Requires `ffmpeg` for non-WAV formats with Wyoming.",
|
|
420
423
|
rich_help_panel="Audio Recovery",
|
|
421
424
|
)
|
|
422
425
|
LAST_RECORDING: int = typer.Option(
|
|
423
426
|
0,
|
|
424
427
|
"--last-recording",
|
|
425
|
-
help="
|
|
428
|
+
help="Re-transcribe a saved recording (1=most recent, 2=second-to-last, etc). "
|
|
429
|
+
"Useful after connection failures or to retry with different options.",
|
|
426
430
|
rich_help_panel="Audio Recovery",
|
|
427
431
|
)
|
|
428
432
|
SAVE_RECORDING: bool = typer.Option(
|
|
429
433
|
True, # noqa: FBT003
|
|
430
434
|
"--save-recording/--no-save-recording",
|
|
431
|
-
help="Save
|
|
435
|
+
help="Save recordings to ~/.cache/agent-cli/ for `--last-recording` recovery.",
|
|
432
436
|
rich_help_panel="Audio Recovery",
|
|
433
437
|
)
|