agent-cli 0.70.2__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.
Files changed (35) hide show
  1. agent_cli/_extras.json +4 -3
  2. agent_cli/_requirements/memory.txt +14 -1
  3. agent_cli/_requirements/rag.txt +14 -1
  4. agent_cli/_requirements/vad.txt +1 -85
  5. agent_cli/_requirements/wyoming.txt +71 -0
  6. agent_cli/agents/assistant.py +24 -28
  7. agent_cli/agents/autocorrect.py +30 -4
  8. agent_cli/agents/chat.py +45 -15
  9. agent_cli/agents/memory/__init__.py +19 -1
  10. agent_cli/agents/memory/add.py +3 -3
  11. agent_cli/agents/memory/proxy.py +20 -11
  12. agent_cli/agents/rag_proxy.py +42 -10
  13. agent_cli/agents/speak.py +23 -3
  14. agent_cli/agents/transcribe.py +21 -3
  15. agent_cli/agents/transcribe_daemon.py +34 -22
  16. agent_cli/agents/voice_edit.py +18 -10
  17. agent_cli/cli.py +25 -2
  18. agent_cli/config_cmd.py +30 -11
  19. agent_cli/core/deps.py +6 -3
  20. agent_cli/core/transcription_logger.py +1 -1
  21. agent_cli/core/vad.py +6 -24
  22. agent_cli/dev/cli.py +295 -65
  23. agent_cli/docs_gen.py +18 -8
  24. agent_cli/install/extras.py +44 -13
  25. agent_cli/install/hotkeys.py +22 -11
  26. agent_cli/install/services.py +54 -14
  27. agent_cli/opts.py +43 -22
  28. agent_cli/server/cli.py +128 -62
  29. agent_cli/server/proxy/api.py +77 -19
  30. agent_cli/services/__init__.py +46 -5
  31. {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/METADATA +627 -246
  32. {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/RECORD +35 -34
  33. {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/WHEEL +0 -0
  34. {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/entry_points.txt +0 -0
  35. {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/licenses/LICENSE +0 -0
@@ -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
- console.print(f"Running: [cyan]{' '.join(cmd)}[/]")
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
- console.print(f"[yellow]Unknown extras (skipped): {', '.join(invalid)}[/]")
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[list[str] | None, typer.Argument(help="Extras to install")] = None,
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("--list", "-l", help="List available extras"),
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 extras (rag, memory, vad, etc.) with pinned versions.
138
-
139
- Examples:
140
- - `agent-cli install-extras rag` # Install RAG dependencies
141
- - `agent-cli install-extras memory vad` # Install multiple extras
142
- - `agent-cli install-extras --list` # Show available extras
143
- - `agent-cli install-extras --all` # Install all extras
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()
@@ -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 the following hotkeys:
16
+ Sets up three global hotkeys:
17
17
 
18
- macOS:
19
- - Cmd+Shift+R: Toggle voice transcription
20
- - Cmd+Shift+A: Autocorrect clipboard text
21
- - Cmd+Shift+V: Voice edit clipboard text
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
- Linux:
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
- Note: On macOS, you may need to grant Accessibility permissions to skhd
29
- in System Settings Privacy & Security → Accessibility.
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()
@@ -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
- The appropriate installation method is used based on your operating system.
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="Attach to Zellij session after starting",
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
- This starts:
55
- - Ollama (LLM server)
56
- - Wyoming Faster Whisper (speech-to-text)
57
- - Wyoming Piper (text-to-speech)
58
- - Wyoming OpenWakeWord (wake word detection)
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
- Services run in a Zellij terminal multiplexer session named 'agent-cli'.
61
- Use Ctrl-Q to quit or Ctrl-O d to detach from the session.
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
@@ -2,12 +2,15 @@
2
2
 
3
3
  import copy
4
4
  from pathlib import Path
5
+ from typing import Literal
5
6
 
6
7
  import typer
7
8
  from typer.models import OptionInfo
8
9
 
9
10
  from agent_cli.constants import DEFAULT_OPENAI_EMBEDDING_MODEL, DEFAULT_OPENAI_MODEL
10
11
 
12
+ LogLevel = Literal["debug", "info", "warning", "error"]
13
+
11
14
 
12
15
  def with_default(option: OptionInfo, default: str) -> OptionInfo:
13
16
  """Create a copy of a typer Option with a different default value."""
@@ -20,18 +23,21 @@ def with_default(option: OptionInfo, default: str) -> OptionInfo:
20
23
  LLM_PROVIDER: str = typer.Option(
21
24
  "ollama",
22
25
  "--llm-provider",
26
+ envvar="LLM_PROVIDER",
23
27
  help="The LLM provider to use ('ollama', 'openai', 'gemini').",
24
28
  rich_help_panel="Provider Selection",
25
29
  )
26
30
  ASR_PROVIDER: str = typer.Option(
27
31
  "wyoming",
28
32
  "--asr-provider",
33
+ envvar="ASR_PROVIDER",
29
34
  help="The ASR provider to use ('wyoming', 'openai', 'gemini').",
30
35
  rich_help_panel="Provider Selection",
31
36
  )
32
37
  TTS_PROVIDER: str = typer.Option(
33
38
  "wyoming",
34
39
  "--tts-provider",
40
+ envvar="TTS_PROVIDER",
35
41
  help="The TTS provider to use ('wyoming', 'openai', 'kokoro', 'gemini').",
36
42
  rich_help_panel="Provider Selection",
37
43
  )
@@ -41,19 +47,22 @@ TTS_PROVIDER: str = typer.Option(
41
47
  LLM: bool = typer.Option(
42
48
  False, # noqa: FBT003
43
49
  "--llm/--no-llm",
44
- help="Use an LLM to process the transcript.",
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).",
45
52
  rich_help_panel="LLM Configuration",
46
53
  )
47
54
  # Ollama (local service)
48
55
  LLM_OLLAMA_MODEL: str = typer.Option(
49
56
  "gemma3:4b",
50
57
  "--llm-ollama-model",
58
+ envvar="LLM_OLLAMA_MODEL",
51
59
  help="The Ollama model to use. Default is gemma3:4b.",
52
60
  rich_help_panel="LLM: Ollama",
53
61
  )
54
62
  LLM_OLLAMA_HOST: str = typer.Option(
55
63
  "http://localhost:11434",
56
64
  "--llm-ollama-host",
65
+ envvar="LLM_OLLAMA_HOST",
57
66
  help="The Ollama server host. Default is http://localhost:11434.",
58
67
  rich_help_panel="LLM: Ollama",
59
68
  )
@@ -61,6 +70,7 @@ LLM_OLLAMA_HOST: str = typer.Option(
61
70
  LLM_OPENAI_MODEL: str = typer.Option(
62
71
  DEFAULT_OPENAI_MODEL,
63
72
  "--llm-openai-model",
73
+ envvar="LLM_OPENAI_MODEL",
64
74
  help="The OpenAI model to use for LLM tasks.",
65
75
  rich_help_panel="LLM: OpenAI-compatible",
66
76
  )
@@ -82,6 +92,7 @@ OPENAI_BASE_URL: str | None = typer.Option(
82
92
  LLM_GEMINI_MODEL: str = typer.Option(
83
93
  "gemini-3-flash-preview",
84
94
  "--llm-gemini-model",
95
+ envvar="LLM_GEMINI_MODEL",
85
96
  help="The Gemini model to use for LLM tasks.",
86
97
  rich_help_panel="LLM: Gemini",
87
98
  )
@@ -104,19 +115,19 @@ EMBEDDING_MODEL: str = typer.Option(
104
115
  INPUT_DEVICE_INDEX: int | None = typer.Option(
105
116
  None,
106
117
  "--input-device-index",
107
- help="Index of the audio input device to use.",
118
+ help="Audio input device index (see `--list-devices`). Uses system default if omitted.",
108
119
  rich_help_panel="Audio Input",
109
120
  )
110
121
  INPUT_DEVICE_NAME: str | None = typer.Option(
111
122
  None,
112
123
  "--input-device-name",
113
- help="Device name keywords for partial matching.",
124
+ help="Select input device by name substring (e.g., `MacBook` or `USB`).",
114
125
  rich_help_panel="Audio Input",
115
126
  )
116
127
  LIST_DEVICES: bool = typer.Option(
117
128
  False, # noqa: FBT003
118
129
  "--list-devices",
119
- help="List available audio input and output devices and exit.",
130
+ help="List available audio devices with their indices and exit.",
120
131
  is_eager=True,
121
132
  rich_help_panel="Audio Input",
122
133
  )
@@ -124,12 +135,14 @@ LIST_DEVICES: bool = typer.Option(
124
135
  ASR_WYOMING_IP: str = typer.Option(
125
136
  "localhost",
126
137
  "--asr-wyoming-ip",
138
+ envvar="ASR_WYOMING_IP",
127
139
  help="Wyoming ASR server IP address.",
128
140
  rich_help_panel="Audio Input: Wyoming",
129
141
  )
130
142
  ASR_WYOMING_PORT: int = typer.Option(
131
143
  10300,
132
144
  "--asr-wyoming-port",
145
+ envvar="ASR_WYOMING_PORT",
133
146
  help="Wyoming ASR server port.",
134
147
  rich_help_panel="Audio Input: Wyoming",
135
148
  )
@@ -137,18 +150,21 @@ ASR_WYOMING_PORT: int = typer.Option(
137
150
  ASR_OPENAI_MODEL: str = typer.Option(
138
151
  "whisper-1",
139
152
  "--asr-openai-model",
153
+ envvar="ASR_OPENAI_MODEL",
140
154
  help="The OpenAI model to use for ASR (transcription).",
141
155
  rich_help_panel="Audio Input: OpenAI-compatible",
142
156
  )
143
157
  ASR_OPENAI_BASE_URL: str | None = typer.Option(
144
158
  None,
145
159
  "--asr-openai-base-url",
160
+ envvar="ASR_OPENAI_BASE_URL",
146
161
  help="Custom base URL for OpenAI-compatible ASR API (e.g., for custom Whisper server: http://localhost:9898).",
147
162
  rich_help_panel="Audio Input: OpenAI-compatible",
148
163
  )
149
164
  ASR_OPENAI_PROMPT: str | None = typer.Option(
150
165
  None,
151
166
  "--asr-openai-prompt",
167
+ envvar="ASR_OPENAI_PROMPT",
152
168
  help="Custom prompt to guide transcription (optional).",
153
169
  rich_help_panel="Audio Input: OpenAI-compatible",
154
170
  )
@@ -156,6 +172,7 @@ ASR_OPENAI_PROMPT: str | None = typer.Option(
156
172
  ASR_GEMINI_MODEL: str = typer.Option(
157
173
  "gemini-3-flash-preview",
158
174
  "--asr-gemini-model",
175
+ envvar="ASR_GEMINI_MODEL",
159
176
  help="The Gemini model to use for ASR (transcription).",
160
177
  rich_help_panel="Audio Input: Gemini",
161
178
  )
@@ -165,7 +182,7 @@ ASR_GEMINI_MODEL: str = typer.Option(
165
182
  WAKE_SERVER_IP: str = typer.Option(
166
183
  "localhost",
167
184
  "--wake-server-ip",
168
- help="Wyoming wake word server IP address.",
185
+ help="Wyoming wake word server IP (requires wyoming-openwakeword or similar).",
169
186
  rich_help_panel="Wake Word",
170
187
  )
171
188
  WAKE_SERVER_PORT: int = typer.Option(
@@ -177,7 +194,7 @@ WAKE_SERVER_PORT: int = typer.Option(
177
194
  WAKE_WORD: str = typer.Option(
178
195
  "ok_nabu",
179
196
  "--wake-word",
180
- help="Name of wake word to detect (e.g., 'ok_nabu', 'hey_jarvis').",
197
+ help="Wake word to detect. Common options: `ok_nabu`, `hey_jarvis`, `alexa`. Must match a model loaded in your wake word server.",
181
198
  rich_help_panel="Wake Word",
182
199
  )
183
200
 
@@ -199,13 +216,13 @@ TTS_SPEED: float = typer.Option(
199
216
  OUTPUT_DEVICE_INDEX: int | None = typer.Option(
200
217
  None,
201
218
  "--output-device-index",
202
- help="Index of the audio output device to use for TTS.",
219
+ help="Audio output device index (see `--list-devices` for available devices).",
203
220
  rich_help_panel="Audio Output",
204
221
  )
205
222
  OUTPUT_DEVICE_NAME: str | None = typer.Option(
206
223
  None,
207
224
  "--output-device-name",
208
- help="Output device name keywords for partial matching.",
225
+ help="Partial match on device name (e.g., 'speakers', 'headphones').",
209
226
  rich_help_panel="Audio Output",
210
227
  )
211
228
  # Wyoming (local service)
@@ -249,7 +266,7 @@ TTS_OPENAI_MODEL: str = typer.Option(
249
266
  TTS_OPENAI_VOICE: str = typer.Option(
250
267
  "alloy",
251
268
  "--tts-openai-voice",
252
- help="The voice to use for OpenAI-compatible TTS.",
269
+ help="Voice for OpenAI TTS (alloy, echo, fable, onyx, nova, shimmer).",
253
270
  rich_help_panel="Audio Output: OpenAI-compatible",
254
271
  )
255
272
  TTS_OPENAI_BASE_URL: str | None = typer.Option(
@@ -299,21 +316,19 @@ TTS_GEMINI_VOICE: str = typer.Option(
299
316
  STOP: bool = typer.Option(
300
317
  False, # noqa: FBT003
301
318
  "--stop",
302
- help="Stop any running background process.",
319
+ help="Stop any running instance of this command.",
303
320
  rich_help_panel="Process Management",
304
321
  )
305
322
  STATUS: bool = typer.Option(
306
323
  False, # noqa: FBT003
307
324
  "--status",
308
- help="Check if a background process is running.",
325
+ help="Check if an instance is currently running.",
309
326
  rich_help_panel="Process Management",
310
327
  )
311
328
  TOGGLE: bool = typer.Option(
312
329
  False, # noqa: FBT003
313
330
  "--toggle",
314
- help="Toggle the background process on/off. "
315
- "If the process is running, it will be stopped. "
316
- "If the process is not running, it will be started.",
331
+ help="Start if not running, stop if running. Ideal for hotkey binding.",
317
332
  rich_help_panel="Process Management",
318
333
  )
319
334
 
@@ -348,13 +363,15 @@ CLIPBOARD: bool = typer.Option(
348
363
  help="Copy result to clipboard.",
349
364
  rich_help_panel="General Options",
350
365
  )
351
- LOG_LEVEL: str = typer.Option(
352
- "WARNING",
366
+ LOG_LEVEL: LogLevel = typer.Option(
367
+ "warning",
353
368
  "--log-level",
369
+ envvar="LOG_LEVEL",
354
370
  help="Set logging level.",
355
371
  case_sensitive=False,
356
372
  rich_help_panel="General Options",
357
373
  )
374
+ SERVER_LOG_LEVEL: LogLevel = with_default(LOG_LEVEL, "info")
358
375
  LOG_FILE: str | None = typer.Option(
359
376
  None,
360
377
  "--log-file",
@@ -371,19 +388,20 @@ QUIET: bool = typer.Option(
371
388
  JSON_OUTPUT: bool = typer.Option(
372
389
  False, # noqa: FBT003
373
390
  "--json",
374
- help="Output result as JSON for automation. Implies --quiet and --no-clipboard.",
391
+ help="Output result as JSON (implies `--quiet` and `--no-clipboard`).",
375
392
  rich_help_panel="General Options",
376
393
  )
377
394
  SAVE_FILE: Path | None = typer.Option(
378
395
  None,
379
396
  "--save-file",
380
- help="Save TTS response audio to WAV file.",
397
+ help="Save audio to WAV file instead of playing through speakers.",
381
398
  rich_help_panel="General Options",
382
399
  )
383
400
  TRANSCRIPTION_LOG: Path | None = typer.Option(
384
401
  None,
385
402
  "--transcription-log",
386
- help="Path to log transcription results with timestamps, hostname, model, and raw output.",
403
+ help="Append transcripts to JSONL file (timestamp, hostname, model, raw/processed text). "
404
+ "Recent entries provide context for LLM cleanup.",
387
405
  rich_help_panel="General Options",
388
406
  )
389
407
 
@@ -399,18 +417,21 @@ SERVER_HOST: str = typer.Option(
399
417
  FROM_FILE: Path | None = typer.Option(
400
418
  None,
401
419
  "--from-file",
402
- help="Transcribe audio from a file (supports wav, mp3, m4a, ogg, flac, aac, webm). Requires ffmpeg for non-WAV formats with Wyoming provider.",
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.",
403
423
  rich_help_panel="Audio Recovery",
404
424
  )
405
425
  LAST_RECORDING: int = typer.Option(
406
426
  0,
407
427
  "--last-recording",
408
- help="Transcribe a saved recording. Use 1 for most recent, 2 for second-to-last, etc. Use 0 to disable (default).",
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.",
409
430
  rich_help_panel="Audio Recovery",
410
431
  )
411
432
  SAVE_RECORDING: bool = typer.Option(
412
433
  True, # noqa: FBT003
413
434
  "--save-recording/--no-save-recording",
414
- help="Save the audio recording to disk for recovery.",
435
+ help="Save recordings to ~/.cache/agent-cli/ for `--last-recording` recovery.",
415
436
  rich_help_panel="Audio Recovery",
416
437
  )