agent-cli 0.70.5__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/__init__.py +5 -0
- agent_cli/__main__.py +6 -0
- agent_cli/_extras.json +14 -0
- agent_cli/_requirements/.gitkeep +0 -0
- agent_cli/_requirements/audio.txt +79 -0
- agent_cli/_requirements/faster-whisper.txt +215 -0
- agent_cli/_requirements/kokoro.txt +425 -0
- agent_cli/_requirements/llm.txt +183 -0
- agent_cli/_requirements/memory.txt +355 -0
- agent_cli/_requirements/mlx-whisper.txt +222 -0
- agent_cli/_requirements/piper.txt +176 -0
- agent_cli/_requirements/rag.txt +402 -0
- agent_cli/_requirements/server.txt +154 -0
- agent_cli/_requirements/speed.txt +77 -0
- agent_cli/_requirements/vad.txt +155 -0
- agent_cli/_requirements/wyoming.txt +71 -0
- agent_cli/_tools.py +368 -0
- agent_cli/agents/__init__.py +23 -0
- agent_cli/agents/_voice_agent_common.py +136 -0
- agent_cli/agents/assistant.py +383 -0
- agent_cli/agents/autocorrect.py +284 -0
- agent_cli/agents/chat.py +496 -0
- agent_cli/agents/memory/__init__.py +31 -0
- agent_cli/agents/memory/add.py +190 -0
- agent_cli/agents/memory/proxy.py +160 -0
- agent_cli/agents/rag_proxy.py +128 -0
- agent_cli/agents/speak.py +209 -0
- agent_cli/agents/transcribe.py +671 -0
- agent_cli/agents/transcribe_daemon.py +499 -0
- agent_cli/agents/voice_edit.py +291 -0
- agent_cli/api.py +22 -0
- agent_cli/cli.py +106 -0
- agent_cli/config.py +503 -0
- agent_cli/config_cmd.py +307 -0
- agent_cli/constants.py +27 -0
- agent_cli/core/__init__.py +1 -0
- agent_cli/core/audio.py +461 -0
- agent_cli/core/audio_format.py +299 -0
- agent_cli/core/chroma.py +88 -0
- agent_cli/core/deps.py +191 -0
- agent_cli/core/openai_proxy.py +139 -0
- agent_cli/core/process.py +195 -0
- agent_cli/core/reranker.py +120 -0
- agent_cli/core/sse.py +87 -0
- agent_cli/core/transcription_logger.py +70 -0
- agent_cli/core/utils.py +526 -0
- agent_cli/core/vad.py +175 -0
- agent_cli/core/watch.py +65 -0
- agent_cli/dev/__init__.py +14 -0
- agent_cli/dev/cli.py +1588 -0
- agent_cli/dev/coding_agents/__init__.py +19 -0
- agent_cli/dev/coding_agents/aider.py +24 -0
- agent_cli/dev/coding_agents/base.py +167 -0
- agent_cli/dev/coding_agents/claude.py +39 -0
- agent_cli/dev/coding_agents/codex.py +24 -0
- agent_cli/dev/coding_agents/continue_dev.py +15 -0
- agent_cli/dev/coding_agents/copilot.py +24 -0
- agent_cli/dev/coding_agents/cursor_agent.py +48 -0
- agent_cli/dev/coding_agents/gemini.py +28 -0
- agent_cli/dev/coding_agents/opencode.py +15 -0
- agent_cli/dev/coding_agents/registry.py +49 -0
- agent_cli/dev/editors/__init__.py +19 -0
- agent_cli/dev/editors/base.py +89 -0
- agent_cli/dev/editors/cursor.py +15 -0
- agent_cli/dev/editors/emacs.py +46 -0
- agent_cli/dev/editors/jetbrains.py +56 -0
- agent_cli/dev/editors/nano.py +31 -0
- agent_cli/dev/editors/neovim.py +33 -0
- agent_cli/dev/editors/registry.py +59 -0
- agent_cli/dev/editors/sublime.py +20 -0
- agent_cli/dev/editors/vim.py +42 -0
- agent_cli/dev/editors/vscode.py +15 -0
- agent_cli/dev/editors/zed.py +20 -0
- agent_cli/dev/project.py +568 -0
- agent_cli/dev/registry.py +52 -0
- agent_cli/dev/skill/SKILL.md +141 -0
- agent_cli/dev/skill/examples.md +571 -0
- agent_cli/dev/terminals/__init__.py +19 -0
- agent_cli/dev/terminals/apple_terminal.py +82 -0
- agent_cli/dev/terminals/base.py +56 -0
- agent_cli/dev/terminals/gnome.py +51 -0
- agent_cli/dev/terminals/iterm2.py +84 -0
- agent_cli/dev/terminals/kitty.py +77 -0
- agent_cli/dev/terminals/registry.py +48 -0
- agent_cli/dev/terminals/tmux.py +58 -0
- agent_cli/dev/terminals/warp.py +132 -0
- agent_cli/dev/terminals/zellij.py +78 -0
- agent_cli/dev/worktree.py +856 -0
- agent_cli/docs_gen.py +417 -0
- agent_cli/example-config.toml +185 -0
- agent_cli/install/__init__.py +5 -0
- agent_cli/install/common.py +89 -0
- agent_cli/install/extras.py +174 -0
- agent_cli/install/hotkeys.py +48 -0
- agent_cli/install/services.py +87 -0
- agent_cli/memory/__init__.py +7 -0
- agent_cli/memory/_files.py +250 -0
- agent_cli/memory/_filters.py +63 -0
- agent_cli/memory/_git.py +157 -0
- agent_cli/memory/_indexer.py +142 -0
- agent_cli/memory/_ingest.py +408 -0
- agent_cli/memory/_persistence.py +182 -0
- agent_cli/memory/_prompt.py +91 -0
- agent_cli/memory/_retrieval.py +294 -0
- agent_cli/memory/_store.py +169 -0
- agent_cli/memory/_streaming.py +44 -0
- agent_cli/memory/_tasks.py +48 -0
- agent_cli/memory/api.py +113 -0
- agent_cli/memory/client.py +272 -0
- agent_cli/memory/engine.py +361 -0
- agent_cli/memory/entities.py +43 -0
- agent_cli/memory/models.py +112 -0
- agent_cli/opts.py +433 -0
- agent_cli/py.typed +0 -0
- agent_cli/rag/__init__.py +3 -0
- agent_cli/rag/_indexer.py +67 -0
- agent_cli/rag/_indexing.py +226 -0
- agent_cli/rag/_prompt.py +30 -0
- agent_cli/rag/_retriever.py +156 -0
- agent_cli/rag/_store.py +48 -0
- agent_cli/rag/_utils.py +218 -0
- agent_cli/rag/api.py +175 -0
- agent_cli/rag/client.py +299 -0
- agent_cli/rag/engine.py +302 -0
- agent_cli/rag/models.py +55 -0
- agent_cli/scripts/.runtime/.gitkeep +0 -0
- agent_cli/scripts/__init__.py +1 -0
- agent_cli/scripts/check_plugin_skill_sync.py +50 -0
- agent_cli/scripts/linux-hotkeys/README.md +63 -0
- agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +45 -0
- agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +58 -0
- agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +58 -0
- agent_cli/scripts/macos-hotkeys/README.md +45 -0
- agent_cli/scripts/macos-hotkeys/skhd-config-example +5 -0
- agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +12 -0
- agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +37 -0
- agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +37 -0
- agent_cli/scripts/nvidia-asr-server/README.md +99 -0
- agent_cli/scripts/nvidia-asr-server/pyproject.toml +27 -0
- agent_cli/scripts/nvidia-asr-server/server.py +255 -0
- agent_cli/scripts/nvidia-asr-server/shell.nix +32 -0
- agent_cli/scripts/nvidia-asr-server/uv.lock +4654 -0
- agent_cli/scripts/run-openwakeword.sh +11 -0
- agent_cli/scripts/run-piper-windows.ps1 +30 -0
- agent_cli/scripts/run-piper.sh +24 -0
- agent_cli/scripts/run-whisper-linux.sh +40 -0
- agent_cli/scripts/run-whisper-macos.sh +6 -0
- agent_cli/scripts/run-whisper-windows.ps1 +51 -0
- agent_cli/scripts/run-whisper.sh +9 -0
- agent_cli/scripts/run_faster_whisper_server.py +136 -0
- agent_cli/scripts/setup-linux-hotkeys.sh +72 -0
- agent_cli/scripts/setup-linux.sh +108 -0
- agent_cli/scripts/setup-macos-hotkeys.sh +61 -0
- agent_cli/scripts/setup-macos.sh +76 -0
- agent_cli/scripts/setup-windows.ps1 +63 -0
- agent_cli/scripts/start-all-services-windows.ps1 +53 -0
- agent_cli/scripts/start-all-services.sh +178 -0
- agent_cli/scripts/sync_extras.py +138 -0
- agent_cli/server/__init__.py +3 -0
- agent_cli/server/cli.py +721 -0
- agent_cli/server/common.py +222 -0
- agent_cli/server/model_manager.py +288 -0
- agent_cli/server/model_registry.py +225 -0
- agent_cli/server/proxy/__init__.py +3 -0
- agent_cli/server/proxy/api.py +444 -0
- agent_cli/server/streaming.py +67 -0
- agent_cli/server/tts/__init__.py +3 -0
- agent_cli/server/tts/api.py +335 -0
- agent_cli/server/tts/backends/__init__.py +82 -0
- agent_cli/server/tts/backends/base.py +139 -0
- agent_cli/server/tts/backends/kokoro.py +403 -0
- agent_cli/server/tts/backends/piper.py +253 -0
- agent_cli/server/tts/model_manager.py +201 -0
- agent_cli/server/tts/model_registry.py +28 -0
- agent_cli/server/tts/wyoming_handler.py +249 -0
- agent_cli/server/whisper/__init__.py +3 -0
- agent_cli/server/whisper/api.py +413 -0
- agent_cli/server/whisper/backends/__init__.py +89 -0
- agent_cli/server/whisper/backends/base.py +97 -0
- agent_cli/server/whisper/backends/faster_whisper.py +225 -0
- agent_cli/server/whisper/backends/mlx.py +270 -0
- agent_cli/server/whisper/languages.py +116 -0
- agent_cli/server/whisper/model_manager.py +157 -0
- agent_cli/server/whisper/model_registry.py +28 -0
- agent_cli/server/whisper/wyoming_handler.py +203 -0
- agent_cli/services/__init__.py +343 -0
- agent_cli/services/_wyoming_utils.py +64 -0
- agent_cli/services/asr.py +506 -0
- agent_cli/services/llm.py +228 -0
- agent_cli/services/tts.py +450 -0
- agent_cli/services/wake_word.py +142 -0
- agent_cli-0.70.5.dist-info/METADATA +2118 -0
- agent_cli-0.70.5.dist-info/RECORD +196 -0
- agent_cli-0.70.5.dist-info/WHEEL +4 -0
- agent_cli-0.70.5.dist-info/entry_points.txt +4 -0
- agent_cli-0.70.5.dist-info/licenses/LICENSE +21 -0
agent_cli/opts.py
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"""Shared Typer options for the Agent CLI agents."""
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from typer.models import OptionInfo
|
|
9
|
+
|
|
10
|
+
from agent_cli.constants import DEFAULT_OPENAI_EMBEDDING_MODEL, DEFAULT_OPENAI_MODEL
|
|
11
|
+
|
|
12
|
+
LogLevel = Literal["debug", "info", "warning", "error"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def with_default(option: OptionInfo, default: str) -> OptionInfo:
|
|
16
|
+
"""Create a copy of a typer Option with a different default value."""
|
|
17
|
+
opt = copy.copy(option)
|
|
18
|
+
opt.default = default
|
|
19
|
+
return opt
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# --- Provider Selection ---
|
|
23
|
+
LLM_PROVIDER: str = typer.Option(
|
|
24
|
+
"ollama",
|
|
25
|
+
"--llm-provider",
|
|
26
|
+
envvar="LLM_PROVIDER",
|
|
27
|
+
help="The LLM provider to use ('ollama', 'openai', 'gemini').",
|
|
28
|
+
rich_help_panel="Provider Selection",
|
|
29
|
+
)
|
|
30
|
+
ASR_PROVIDER: str = typer.Option(
|
|
31
|
+
"wyoming",
|
|
32
|
+
"--asr-provider",
|
|
33
|
+
envvar="ASR_PROVIDER",
|
|
34
|
+
help="The ASR provider to use ('wyoming', 'openai', 'gemini').",
|
|
35
|
+
rich_help_panel="Provider Selection",
|
|
36
|
+
)
|
|
37
|
+
TTS_PROVIDER: str = typer.Option(
|
|
38
|
+
"wyoming",
|
|
39
|
+
"--tts-provider",
|
|
40
|
+
envvar="TTS_PROVIDER",
|
|
41
|
+
help="The TTS provider to use ('wyoming', 'openai', 'kokoro', 'gemini').",
|
|
42
|
+
rich_help_panel="Provider Selection",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# --- LLM Configuration ---
|
|
47
|
+
LLM: bool = typer.Option(
|
|
48
|
+
False, # noqa: FBT003
|
|
49
|
+
"--llm/--no-llm",
|
|
50
|
+
help="Use an LLM to process the transcript.",
|
|
51
|
+
rich_help_panel="LLM Configuration",
|
|
52
|
+
)
|
|
53
|
+
# Ollama (local service)
|
|
54
|
+
LLM_OLLAMA_MODEL: str = typer.Option(
|
|
55
|
+
"gemma3:4b",
|
|
56
|
+
"--llm-ollama-model",
|
|
57
|
+
envvar="LLM_OLLAMA_MODEL",
|
|
58
|
+
help="The Ollama model to use. Default is gemma3:4b.",
|
|
59
|
+
rich_help_panel="LLM: Ollama",
|
|
60
|
+
)
|
|
61
|
+
LLM_OLLAMA_HOST: str = typer.Option(
|
|
62
|
+
"http://localhost:11434",
|
|
63
|
+
"--llm-ollama-host",
|
|
64
|
+
envvar="LLM_OLLAMA_HOST",
|
|
65
|
+
help="The Ollama server host. Default is http://localhost:11434.",
|
|
66
|
+
rich_help_panel="LLM: Ollama",
|
|
67
|
+
)
|
|
68
|
+
# OpenAI
|
|
69
|
+
LLM_OPENAI_MODEL: str = typer.Option(
|
|
70
|
+
DEFAULT_OPENAI_MODEL,
|
|
71
|
+
"--llm-openai-model",
|
|
72
|
+
envvar="LLM_OPENAI_MODEL",
|
|
73
|
+
help="The OpenAI model to use for LLM tasks.",
|
|
74
|
+
rich_help_panel="LLM: OpenAI-compatible",
|
|
75
|
+
)
|
|
76
|
+
OPENAI_API_KEY: str | None = typer.Option(
|
|
77
|
+
None,
|
|
78
|
+
"--openai-api-key",
|
|
79
|
+
help="Your OpenAI API key. Can also be set with the OPENAI_API_KEY environment variable.",
|
|
80
|
+
envvar="OPENAI_API_KEY",
|
|
81
|
+
rich_help_panel="LLM: OpenAI-compatible",
|
|
82
|
+
)
|
|
83
|
+
OPENAI_BASE_URL: str | None = typer.Option(
|
|
84
|
+
None,
|
|
85
|
+
"--openai-base-url",
|
|
86
|
+
help="Custom base URL for OpenAI-compatible API (e.g., for llama-server: http://localhost:8080/v1).",
|
|
87
|
+
envvar="OPENAI_BASE_URL",
|
|
88
|
+
rich_help_panel="LLM: OpenAI-compatible",
|
|
89
|
+
)
|
|
90
|
+
# Gemini
|
|
91
|
+
LLM_GEMINI_MODEL: str = typer.Option(
|
|
92
|
+
"gemini-3-flash-preview",
|
|
93
|
+
"--llm-gemini-model",
|
|
94
|
+
envvar="LLM_GEMINI_MODEL",
|
|
95
|
+
help="The Gemini model to use for LLM tasks.",
|
|
96
|
+
rich_help_panel="LLM: Gemini",
|
|
97
|
+
)
|
|
98
|
+
GEMINI_API_KEY: str | None = typer.Option(
|
|
99
|
+
None,
|
|
100
|
+
"--gemini-api-key",
|
|
101
|
+
help="Your Gemini API key. Can also be set with the GEMINI_API_KEY environment variable.",
|
|
102
|
+
envvar="GEMINI_API_KEY",
|
|
103
|
+
rich_help_panel="LLM: Gemini",
|
|
104
|
+
)
|
|
105
|
+
EMBEDDING_MODEL: str = typer.Option(
|
|
106
|
+
DEFAULT_OPENAI_EMBEDDING_MODEL,
|
|
107
|
+
"--embedding-model",
|
|
108
|
+
help="Embedding model to use for vectorization.",
|
|
109
|
+
rich_help_panel="LLM Configuration",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# --- ASR (Audio) Configuration ---
|
|
113
|
+
# General ASR
|
|
114
|
+
INPUT_DEVICE_INDEX: int | None = typer.Option(
|
|
115
|
+
None,
|
|
116
|
+
"--input-device-index",
|
|
117
|
+
help="Index of the audio input device to use.",
|
|
118
|
+
rich_help_panel="Audio Input",
|
|
119
|
+
)
|
|
120
|
+
INPUT_DEVICE_NAME: str | None = typer.Option(
|
|
121
|
+
None,
|
|
122
|
+
"--input-device-name",
|
|
123
|
+
help="Device name keywords for partial matching.",
|
|
124
|
+
rich_help_panel="Audio Input",
|
|
125
|
+
)
|
|
126
|
+
LIST_DEVICES: bool = typer.Option(
|
|
127
|
+
False, # noqa: FBT003
|
|
128
|
+
"--list-devices",
|
|
129
|
+
help="List available audio input and output devices and exit.",
|
|
130
|
+
is_eager=True,
|
|
131
|
+
rich_help_panel="Audio Input",
|
|
132
|
+
)
|
|
133
|
+
# Wyoming (local service)
|
|
134
|
+
ASR_WYOMING_IP: str = typer.Option(
|
|
135
|
+
"localhost",
|
|
136
|
+
"--asr-wyoming-ip",
|
|
137
|
+
envvar="ASR_WYOMING_IP",
|
|
138
|
+
help="Wyoming ASR server IP address.",
|
|
139
|
+
rich_help_panel="Audio Input: Wyoming",
|
|
140
|
+
)
|
|
141
|
+
ASR_WYOMING_PORT: int = typer.Option(
|
|
142
|
+
10300,
|
|
143
|
+
"--asr-wyoming-port",
|
|
144
|
+
envvar="ASR_WYOMING_PORT",
|
|
145
|
+
help="Wyoming ASR server port.",
|
|
146
|
+
rich_help_panel="Audio Input: Wyoming",
|
|
147
|
+
)
|
|
148
|
+
# OpenAI
|
|
149
|
+
ASR_OPENAI_MODEL: str = typer.Option(
|
|
150
|
+
"whisper-1",
|
|
151
|
+
"--asr-openai-model",
|
|
152
|
+
envvar="ASR_OPENAI_MODEL",
|
|
153
|
+
help="The OpenAI model to use for ASR (transcription).",
|
|
154
|
+
rich_help_panel="Audio Input: OpenAI-compatible",
|
|
155
|
+
)
|
|
156
|
+
ASR_OPENAI_BASE_URL: str | None = typer.Option(
|
|
157
|
+
None,
|
|
158
|
+
"--asr-openai-base-url",
|
|
159
|
+
envvar="ASR_OPENAI_BASE_URL",
|
|
160
|
+
help="Custom base URL for OpenAI-compatible ASR API (e.g., for custom Whisper server: http://localhost:9898).",
|
|
161
|
+
rich_help_panel="Audio Input: OpenAI-compatible",
|
|
162
|
+
)
|
|
163
|
+
ASR_OPENAI_PROMPT: str | None = typer.Option(
|
|
164
|
+
None,
|
|
165
|
+
"--asr-openai-prompt",
|
|
166
|
+
envvar="ASR_OPENAI_PROMPT",
|
|
167
|
+
help="Custom prompt to guide transcription (optional).",
|
|
168
|
+
rich_help_panel="Audio Input: OpenAI-compatible",
|
|
169
|
+
)
|
|
170
|
+
# Gemini ASR
|
|
171
|
+
ASR_GEMINI_MODEL: str = typer.Option(
|
|
172
|
+
"gemini-3-flash-preview",
|
|
173
|
+
"--asr-gemini-model",
|
|
174
|
+
envvar="ASR_GEMINI_MODEL",
|
|
175
|
+
help="The Gemini model to use for ASR (transcription).",
|
|
176
|
+
rich_help_panel="Audio Input: Gemini",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# --- Wake Word Options ---
|
|
181
|
+
WAKE_SERVER_IP: str = typer.Option(
|
|
182
|
+
"localhost",
|
|
183
|
+
"--wake-server-ip",
|
|
184
|
+
help="Wyoming wake word server IP address.",
|
|
185
|
+
rich_help_panel="Wake Word",
|
|
186
|
+
)
|
|
187
|
+
WAKE_SERVER_PORT: int = typer.Option(
|
|
188
|
+
10400,
|
|
189
|
+
"--wake-server-port",
|
|
190
|
+
help="Wyoming wake word server port.",
|
|
191
|
+
rich_help_panel="Wake Word",
|
|
192
|
+
)
|
|
193
|
+
WAKE_WORD: str = typer.Option(
|
|
194
|
+
"ok_nabu",
|
|
195
|
+
"--wake-word",
|
|
196
|
+
help="Name of wake word to detect (e.g., 'ok_nabu', 'hey_jarvis').",
|
|
197
|
+
rich_help_panel="Wake Word",
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# --- TTS (Text-to-Speech) Configuration ---
|
|
202
|
+
# General TTS
|
|
203
|
+
ENABLE_TTS: bool = typer.Option(
|
|
204
|
+
False, # noqa: FBT003
|
|
205
|
+
"--tts/--no-tts",
|
|
206
|
+
help="Enable text-to-speech for responses.",
|
|
207
|
+
rich_help_panel="Audio Output",
|
|
208
|
+
)
|
|
209
|
+
TTS_SPEED: float = typer.Option(
|
|
210
|
+
1.0,
|
|
211
|
+
"--tts-speed",
|
|
212
|
+
help="Speech speed multiplier (1.0 = normal, 2.0 = twice as fast, 0.5 = half speed).",
|
|
213
|
+
rich_help_panel="Audio Output",
|
|
214
|
+
)
|
|
215
|
+
OUTPUT_DEVICE_INDEX: int | None = typer.Option(
|
|
216
|
+
None,
|
|
217
|
+
"--output-device-index",
|
|
218
|
+
help="Index of the audio output device to use for TTS.",
|
|
219
|
+
rich_help_panel="Audio Output",
|
|
220
|
+
)
|
|
221
|
+
OUTPUT_DEVICE_NAME: str | None = typer.Option(
|
|
222
|
+
None,
|
|
223
|
+
"--output-device-name",
|
|
224
|
+
help="Output device name keywords for partial matching.",
|
|
225
|
+
rich_help_panel="Audio Output",
|
|
226
|
+
)
|
|
227
|
+
# Wyoming (local service)
|
|
228
|
+
TTS_WYOMING_IP: str = typer.Option(
|
|
229
|
+
"localhost",
|
|
230
|
+
"--tts-wyoming-ip",
|
|
231
|
+
help="Wyoming TTS server IP address.",
|
|
232
|
+
rich_help_panel="Audio Output: Wyoming",
|
|
233
|
+
)
|
|
234
|
+
TTS_WYOMING_PORT: int = typer.Option(
|
|
235
|
+
10200,
|
|
236
|
+
"--tts-wyoming-port",
|
|
237
|
+
help="Wyoming TTS server port.",
|
|
238
|
+
rich_help_panel="Audio Output: Wyoming",
|
|
239
|
+
)
|
|
240
|
+
TTS_WYOMING_VOICE: str | None = typer.Option(
|
|
241
|
+
None,
|
|
242
|
+
"--tts-wyoming-voice",
|
|
243
|
+
help="Voice name to use for Wyoming TTS (e.g., 'en_US-lessac-medium').",
|
|
244
|
+
rich_help_panel="Audio Output: Wyoming",
|
|
245
|
+
)
|
|
246
|
+
TTS_WYOMING_LANGUAGE: str | None = typer.Option(
|
|
247
|
+
None,
|
|
248
|
+
"--tts-wyoming-language",
|
|
249
|
+
help="Language for Wyoming TTS (e.g., 'en_US').",
|
|
250
|
+
rich_help_panel="Audio Output: Wyoming",
|
|
251
|
+
)
|
|
252
|
+
TTS_WYOMING_SPEAKER: str | None = typer.Option(
|
|
253
|
+
None,
|
|
254
|
+
"--tts-wyoming-speaker",
|
|
255
|
+
help="Speaker name for Wyoming TTS voice.",
|
|
256
|
+
rich_help_panel="Audio Output: Wyoming",
|
|
257
|
+
)
|
|
258
|
+
# OpenAI
|
|
259
|
+
TTS_OPENAI_MODEL: str = typer.Option(
|
|
260
|
+
"tts-1",
|
|
261
|
+
"--tts-openai-model",
|
|
262
|
+
help="The OpenAI model to use for TTS.",
|
|
263
|
+
rich_help_panel="Audio Output: OpenAI-compatible",
|
|
264
|
+
)
|
|
265
|
+
TTS_OPENAI_VOICE: str = typer.Option(
|
|
266
|
+
"alloy",
|
|
267
|
+
"--tts-openai-voice",
|
|
268
|
+
help="The voice to use for OpenAI-compatible TTS.",
|
|
269
|
+
rich_help_panel="Audio Output: OpenAI-compatible",
|
|
270
|
+
)
|
|
271
|
+
TTS_OPENAI_BASE_URL: str | None = typer.Option(
|
|
272
|
+
None,
|
|
273
|
+
"--tts-openai-base-url",
|
|
274
|
+
help="Custom base URL for OpenAI-compatible TTS API (e.g., http://localhost:8000/v1 for a proxy).",
|
|
275
|
+
rich_help_panel="Audio Output: OpenAI-compatible",
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
# Kokoro
|
|
280
|
+
TTS_KOKORO_MODEL: str = typer.Option(
|
|
281
|
+
"kokoro",
|
|
282
|
+
"--tts-kokoro-model",
|
|
283
|
+
help="The Kokoro model to use for TTS.",
|
|
284
|
+
rich_help_panel="Audio Output: Kokoro",
|
|
285
|
+
)
|
|
286
|
+
TTS_KOKORO_VOICE: str = typer.Option(
|
|
287
|
+
"af_sky",
|
|
288
|
+
"--tts-kokoro-voice",
|
|
289
|
+
help="The voice to use for Kokoro TTS.",
|
|
290
|
+
rich_help_panel="Audio Output: Kokoro",
|
|
291
|
+
)
|
|
292
|
+
TTS_KOKORO_HOST: str = typer.Option(
|
|
293
|
+
"http://localhost:8880/v1",
|
|
294
|
+
"--tts-kokoro-host",
|
|
295
|
+
help="The base URL for the Kokoro API.",
|
|
296
|
+
rich_help_panel="Audio Output: Kokoro",
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# Gemini TTS
|
|
300
|
+
TTS_GEMINI_MODEL: str = typer.Option(
|
|
301
|
+
"gemini-2.5-flash-preview-tts",
|
|
302
|
+
"--tts-gemini-model",
|
|
303
|
+
help="The Gemini model to use for TTS.",
|
|
304
|
+
rich_help_panel="Audio Output: Gemini",
|
|
305
|
+
)
|
|
306
|
+
TTS_GEMINI_VOICE: str = typer.Option(
|
|
307
|
+
"Kore",
|
|
308
|
+
"--tts-gemini-voice",
|
|
309
|
+
help="The voice to use for Gemini TTS (e.g., 'Kore', 'Puck', 'Charon', 'Fenrir').",
|
|
310
|
+
rich_help_panel="Audio Output: Gemini",
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
# --- Process Management Options ---
|
|
315
|
+
STOP: bool = typer.Option(
|
|
316
|
+
False, # noqa: FBT003
|
|
317
|
+
"--stop",
|
|
318
|
+
help="Stop any running background process.",
|
|
319
|
+
rich_help_panel="Process Management",
|
|
320
|
+
)
|
|
321
|
+
STATUS: bool = typer.Option(
|
|
322
|
+
False, # noqa: FBT003
|
|
323
|
+
"--status",
|
|
324
|
+
help="Check if a background process is running.",
|
|
325
|
+
rich_help_panel="Process Management",
|
|
326
|
+
)
|
|
327
|
+
TOGGLE: bool = typer.Option(
|
|
328
|
+
False, # noqa: FBT003
|
|
329
|
+
"--toggle",
|
|
330
|
+
help="Toggle the background process on/off. "
|
|
331
|
+
"If the process is running, it will be stopped. "
|
|
332
|
+
"If the process is not running, it will be started.",
|
|
333
|
+
rich_help_panel="Process Management",
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# --- General Options ---
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _conf_callback(ctx: typer.Context, param: typer.CallbackParam, value: str) -> str: # noqa: ARG001
|
|
340
|
+
from agent_cli.cli import set_config_defaults # noqa: PLC0415
|
|
341
|
+
|
|
342
|
+
set_config_defaults(ctx, value)
|
|
343
|
+
return value
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
CONFIG_FILE: str | None = typer.Option(
|
|
347
|
+
None,
|
|
348
|
+
"--config",
|
|
349
|
+
help="Path to a TOML configuration file.",
|
|
350
|
+
is_eager=True,
|
|
351
|
+
callback=_conf_callback,
|
|
352
|
+
rich_help_panel="General Options",
|
|
353
|
+
)
|
|
354
|
+
PRINT_ARGS: bool = typer.Option(
|
|
355
|
+
False, # noqa: FBT003
|
|
356
|
+
"--print-args",
|
|
357
|
+
help="Print the command line arguments, including variables taken from the configuration file.",
|
|
358
|
+
is_eager=True,
|
|
359
|
+
rich_help_panel="General Options",
|
|
360
|
+
)
|
|
361
|
+
CLIPBOARD: bool = typer.Option(
|
|
362
|
+
True, # noqa: FBT003
|
|
363
|
+
"--clipboard/--no-clipboard",
|
|
364
|
+
help="Copy result to clipboard.",
|
|
365
|
+
rich_help_panel="General Options",
|
|
366
|
+
)
|
|
367
|
+
LOG_LEVEL: LogLevel = typer.Option(
|
|
368
|
+
"info",
|
|
369
|
+
"--log-level",
|
|
370
|
+
envvar="LOG_LEVEL",
|
|
371
|
+
help="Set logging level.",
|
|
372
|
+
case_sensitive=False,
|
|
373
|
+
rich_help_panel="General Options",
|
|
374
|
+
)
|
|
375
|
+
LOG_FILE: str | None = typer.Option(
|
|
376
|
+
None,
|
|
377
|
+
"--log-file",
|
|
378
|
+
help="Path to a file to write logs to.",
|
|
379
|
+
rich_help_panel="General Options",
|
|
380
|
+
)
|
|
381
|
+
QUIET: bool = typer.Option(
|
|
382
|
+
False, # noqa: FBT003
|
|
383
|
+
"-q",
|
|
384
|
+
"--quiet",
|
|
385
|
+
help="Suppress console output from rich.",
|
|
386
|
+
rich_help_panel="General Options",
|
|
387
|
+
)
|
|
388
|
+
JSON_OUTPUT: bool = typer.Option(
|
|
389
|
+
False, # noqa: FBT003
|
|
390
|
+
"--json",
|
|
391
|
+
help="Output result as JSON for automation. Implies --quiet and --no-clipboard.",
|
|
392
|
+
rich_help_panel="General Options",
|
|
393
|
+
)
|
|
394
|
+
SAVE_FILE: Path | None = typer.Option(
|
|
395
|
+
None,
|
|
396
|
+
"--save-file",
|
|
397
|
+
help="Save TTS response audio to WAV file.",
|
|
398
|
+
rich_help_panel="General Options",
|
|
399
|
+
)
|
|
400
|
+
TRANSCRIPTION_LOG: Path | None = typer.Option(
|
|
401
|
+
None,
|
|
402
|
+
"--transcription-log",
|
|
403
|
+
help="Path to log transcription results with timestamps, hostname, model, and raw output.",
|
|
404
|
+
rich_help_panel="General Options",
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
# --- Server Options ---
|
|
408
|
+
SERVER_HOST: str = typer.Option(
|
|
409
|
+
"0.0.0.0", # noqa: S104
|
|
410
|
+
"--host",
|
|
411
|
+
help="Host/IP to bind API servers to.",
|
|
412
|
+
rich_help_panel="Server Configuration",
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
# --- Transcribe Specific Options ---
|
|
416
|
+
FROM_FILE: Path | None = typer.Option(
|
|
417
|
+
None,
|
|
418
|
+
"--from-file",
|
|
419
|
+
help="Transcribe audio from a file (supports wav, mp3, m4a, ogg, flac, aac, webm). Requires ffmpeg for non-WAV formats with Wyoming provider.",
|
|
420
|
+
rich_help_panel="Audio Recovery",
|
|
421
|
+
)
|
|
422
|
+
LAST_RECORDING: int = typer.Option(
|
|
423
|
+
0,
|
|
424
|
+
"--last-recording",
|
|
425
|
+
help="Transcribe a saved recording. Use 1 for most recent, 2 for second-to-last, etc. Use 0 to disable (default).",
|
|
426
|
+
rich_help_panel="Audio Recovery",
|
|
427
|
+
)
|
|
428
|
+
SAVE_RECORDING: bool = typer.Option(
|
|
429
|
+
True, # noqa: FBT003
|
|
430
|
+
"--save-recording/--no-save-recording",
|
|
431
|
+
help="Save the audio recording to disk for recovery.",
|
|
432
|
+
rich_help_panel="Audio Recovery",
|
|
433
|
+
)
|
agent_cli/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""File watcher and indexing logic using watchfiles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from agent_cli.core.watch import watch_directory
|
|
9
|
+
from agent_cli.rag._indexing import index_file, remove_file
|
|
10
|
+
from agent_cli.rag._utils import should_ignore_path
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from chromadb import Collection
|
|
16
|
+
from watchfiles import Change
|
|
17
|
+
|
|
18
|
+
LOGGER = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def watch_docs(
|
|
22
|
+
collection: Collection,
|
|
23
|
+
docs_folder: Path,
|
|
24
|
+
file_hashes: dict[str, str],
|
|
25
|
+
file_mtimes: dict[str, float],
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Watch docs folder for changes and update index asynchronously."""
|
|
28
|
+
LOGGER.info("📁 Watching folder: %s", docs_folder)
|
|
29
|
+
|
|
30
|
+
await watch_directory(
|
|
31
|
+
docs_folder,
|
|
32
|
+
lambda change, path: _handle_change(
|
|
33
|
+
change,
|
|
34
|
+
path,
|
|
35
|
+
collection,
|
|
36
|
+
docs_folder,
|
|
37
|
+
file_hashes,
|
|
38
|
+
file_mtimes,
|
|
39
|
+
),
|
|
40
|
+
ignore_filter=should_ignore_path,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _handle_change(
|
|
45
|
+
change: Change,
|
|
46
|
+
file_path: Path,
|
|
47
|
+
collection: Collection,
|
|
48
|
+
docs_folder: Path,
|
|
49
|
+
file_hashes: dict[str, str],
|
|
50
|
+
file_mtimes: dict[str, float],
|
|
51
|
+
) -> None:
|
|
52
|
+
from watchfiles import Change # noqa: PLC0415
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
if change == Change.deleted:
|
|
56
|
+
LOGGER.info("[deleted] Removing from index: %s", file_path.name)
|
|
57
|
+
remove_file(collection, docs_folder, file_path, file_hashes, file_mtimes)
|
|
58
|
+
return
|
|
59
|
+
if change in {Change.added, Change.modified} and file_path.is_file():
|
|
60
|
+
action = "created" if change == Change.added else "modified"
|
|
61
|
+
LOGGER.info("[%s] Indexing: %s", action, file_path.name)
|
|
62
|
+
index_file(collection, docs_folder, file_path, file_hashes, file_mtimes)
|
|
63
|
+
except (OSError, UnicodeDecodeError):
|
|
64
|
+
LOGGER.warning("Watcher handler transient IO error for %s", file_path, exc_info=True)
|
|
65
|
+
except Exception:
|
|
66
|
+
LOGGER.exception("Watcher handler failed for %s", file_path)
|
|
67
|
+
raise
|