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.
Files changed (196) hide show
  1. agent_cli/__init__.py +5 -0
  2. agent_cli/__main__.py +6 -0
  3. agent_cli/_extras.json +14 -0
  4. agent_cli/_requirements/.gitkeep +0 -0
  5. agent_cli/_requirements/audio.txt +79 -0
  6. agent_cli/_requirements/faster-whisper.txt +215 -0
  7. agent_cli/_requirements/kokoro.txt +425 -0
  8. agent_cli/_requirements/llm.txt +183 -0
  9. agent_cli/_requirements/memory.txt +355 -0
  10. agent_cli/_requirements/mlx-whisper.txt +222 -0
  11. agent_cli/_requirements/piper.txt +176 -0
  12. agent_cli/_requirements/rag.txt +402 -0
  13. agent_cli/_requirements/server.txt +154 -0
  14. agent_cli/_requirements/speed.txt +77 -0
  15. agent_cli/_requirements/vad.txt +155 -0
  16. agent_cli/_requirements/wyoming.txt +71 -0
  17. agent_cli/_tools.py +368 -0
  18. agent_cli/agents/__init__.py +23 -0
  19. agent_cli/agents/_voice_agent_common.py +136 -0
  20. agent_cli/agents/assistant.py +383 -0
  21. agent_cli/agents/autocorrect.py +284 -0
  22. agent_cli/agents/chat.py +496 -0
  23. agent_cli/agents/memory/__init__.py +31 -0
  24. agent_cli/agents/memory/add.py +190 -0
  25. agent_cli/agents/memory/proxy.py +160 -0
  26. agent_cli/agents/rag_proxy.py +128 -0
  27. agent_cli/agents/speak.py +209 -0
  28. agent_cli/agents/transcribe.py +671 -0
  29. agent_cli/agents/transcribe_daemon.py +499 -0
  30. agent_cli/agents/voice_edit.py +291 -0
  31. agent_cli/api.py +22 -0
  32. agent_cli/cli.py +106 -0
  33. agent_cli/config.py +503 -0
  34. agent_cli/config_cmd.py +307 -0
  35. agent_cli/constants.py +27 -0
  36. agent_cli/core/__init__.py +1 -0
  37. agent_cli/core/audio.py +461 -0
  38. agent_cli/core/audio_format.py +299 -0
  39. agent_cli/core/chroma.py +88 -0
  40. agent_cli/core/deps.py +191 -0
  41. agent_cli/core/openai_proxy.py +139 -0
  42. agent_cli/core/process.py +195 -0
  43. agent_cli/core/reranker.py +120 -0
  44. agent_cli/core/sse.py +87 -0
  45. agent_cli/core/transcription_logger.py +70 -0
  46. agent_cli/core/utils.py +526 -0
  47. agent_cli/core/vad.py +175 -0
  48. agent_cli/core/watch.py +65 -0
  49. agent_cli/dev/__init__.py +14 -0
  50. agent_cli/dev/cli.py +1588 -0
  51. agent_cli/dev/coding_agents/__init__.py +19 -0
  52. agent_cli/dev/coding_agents/aider.py +24 -0
  53. agent_cli/dev/coding_agents/base.py +167 -0
  54. agent_cli/dev/coding_agents/claude.py +39 -0
  55. agent_cli/dev/coding_agents/codex.py +24 -0
  56. agent_cli/dev/coding_agents/continue_dev.py +15 -0
  57. agent_cli/dev/coding_agents/copilot.py +24 -0
  58. agent_cli/dev/coding_agents/cursor_agent.py +48 -0
  59. agent_cli/dev/coding_agents/gemini.py +28 -0
  60. agent_cli/dev/coding_agents/opencode.py +15 -0
  61. agent_cli/dev/coding_agents/registry.py +49 -0
  62. agent_cli/dev/editors/__init__.py +19 -0
  63. agent_cli/dev/editors/base.py +89 -0
  64. agent_cli/dev/editors/cursor.py +15 -0
  65. agent_cli/dev/editors/emacs.py +46 -0
  66. agent_cli/dev/editors/jetbrains.py +56 -0
  67. agent_cli/dev/editors/nano.py +31 -0
  68. agent_cli/dev/editors/neovim.py +33 -0
  69. agent_cli/dev/editors/registry.py +59 -0
  70. agent_cli/dev/editors/sublime.py +20 -0
  71. agent_cli/dev/editors/vim.py +42 -0
  72. agent_cli/dev/editors/vscode.py +15 -0
  73. agent_cli/dev/editors/zed.py +20 -0
  74. agent_cli/dev/project.py +568 -0
  75. agent_cli/dev/registry.py +52 -0
  76. agent_cli/dev/skill/SKILL.md +141 -0
  77. agent_cli/dev/skill/examples.md +571 -0
  78. agent_cli/dev/terminals/__init__.py +19 -0
  79. agent_cli/dev/terminals/apple_terminal.py +82 -0
  80. agent_cli/dev/terminals/base.py +56 -0
  81. agent_cli/dev/terminals/gnome.py +51 -0
  82. agent_cli/dev/terminals/iterm2.py +84 -0
  83. agent_cli/dev/terminals/kitty.py +77 -0
  84. agent_cli/dev/terminals/registry.py +48 -0
  85. agent_cli/dev/terminals/tmux.py +58 -0
  86. agent_cli/dev/terminals/warp.py +132 -0
  87. agent_cli/dev/terminals/zellij.py +78 -0
  88. agent_cli/dev/worktree.py +856 -0
  89. agent_cli/docs_gen.py +417 -0
  90. agent_cli/example-config.toml +185 -0
  91. agent_cli/install/__init__.py +5 -0
  92. agent_cli/install/common.py +89 -0
  93. agent_cli/install/extras.py +174 -0
  94. agent_cli/install/hotkeys.py +48 -0
  95. agent_cli/install/services.py +87 -0
  96. agent_cli/memory/__init__.py +7 -0
  97. agent_cli/memory/_files.py +250 -0
  98. agent_cli/memory/_filters.py +63 -0
  99. agent_cli/memory/_git.py +157 -0
  100. agent_cli/memory/_indexer.py +142 -0
  101. agent_cli/memory/_ingest.py +408 -0
  102. agent_cli/memory/_persistence.py +182 -0
  103. agent_cli/memory/_prompt.py +91 -0
  104. agent_cli/memory/_retrieval.py +294 -0
  105. agent_cli/memory/_store.py +169 -0
  106. agent_cli/memory/_streaming.py +44 -0
  107. agent_cli/memory/_tasks.py +48 -0
  108. agent_cli/memory/api.py +113 -0
  109. agent_cli/memory/client.py +272 -0
  110. agent_cli/memory/engine.py +361 -0
  111. agent_cli/memory/entities.py +43 -0
  112. agent_cli/memory/models.py +112 -0
  113. agent_cli/opts.py +433 -0
  114. agent_cli/py.typed +0 -0
  115. agent_cli/rag/__init__.py +3 -0
  116. agent_cli/rag/_indexer.py +67 -0
  117. agent_cli/rag/_indexing.py +226 -0
  118. agent_cli/rag/_prompt.py +30 -0
  119. agent_cli/rag/_retriever.py +156 -0
  120. agent_cli/rag/_store.py +48 -0
  121. agent_cli/rag/_utils.py +218 -0
  122. agent_cli/rag/api.py +175 -0
  123. agent_cli/rag/client.py +299 -0
  124. agent_cli/rag/engine.py +302 -0
  125. agent_cli/rag/models.py +55 -0
  126. agent_cli/scripts/.runtime/.gitkeep +0 -0
  127. agent_cli/scripts/__init__.py +1 -0
  128. agent_cli/scripts/check_plugin_skill_sync.py +50 -0
  129. agent_cli/scripts/linux-hotkeys/README.md +63 -0
  130. agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +45 -0
  131. agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +58 -0
  132. agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +58 -0
  133. agent_cli/scripts/macos-hotkeys/README.md +45 -0
  134. agent_cli/scripts/macos-hotkeys/skhd-config-example +5 -0
  135. agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +12 -0
  136. agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +37 -0
  137. agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +37 -0
  138. agent_cli/scripts/nvidia-asr-server/README.md +99 -0
  139. agent_cli/scripts/nvidia-asr-server/pyproject.toml +27 -0
  140. agent_cli/scripts/nvidia-asr-server/server.py +255 -0
  141. agent_cli/scripts/nvidia-asr-server/shell.nix +32 -0
  142. agent_cli/scripts/nvidia-asr-server/uv.lock +4654 -0
  143. agent_cli/scripts/run-openwakeword.sh +11 -0
  144. agent_cli/scripts/run-piper-windows.ps1 +30 -0
  145. agent_cli/scripts/run-piper.sh +24 -0
  146. agent_cli/scripts/run-whisper-linux.sh +40 -0
  147. agent_cli/scripts/run-whisper-macos.sh +6 -0
  148. agent_cli/scripts/run-whisper-windows.ps1 +51 -0
  149. agent_cli/scripts/run-whisper.sh +9 -0
  150. agent_cli/scripts/run_faster_whisper_server.py +136 -0
  151. agent_cli/scripts/setup-linux-hotkeys.sh +72 -0
  152. agent_cli/scripts/setup-linux.sh +108 -0
  153. agent_cli/scripts/setup-macos-hotkeys.sh +61 -0
  154. agent_cli/scripts/setup-macos.sh +76 -0
  155. agent_cli/scripts/setup-windows.ps1 +63 -0
  156. agent_cli/scripts/start-all-services-windows.ps1 +53 -0
  157. agent_cli/scripts/start-all-services.sh +178 -0
  158. agent_cli/scripts/sync_extras.py +138 -0
  159. agent_cli/server/__init__.py +3 -0
  160. agent_cli/server/cli.py +721 -0
  161. agent_cli/server/common.py +222 -0
  162. agent_cli/server/model_manager.py +288 -0
  163. agent_cli/server/model_registry.py +225 -0
  164. agent_cli/server/proxy/__init__.py +3 -0
  165. agent_cli/server/proxy/api.py +444 -0
  166. agent_cli/server/streaming.py +67 -0
  167. agent_cli/server/tts/__init__.py +3 -0
  168. agent_cli/server/tts/api.py +335 -0
  169. agent_cli/server/tts/backends/__init__.py +82 -0
  170. agent_cli/server/tts/backends/base.py +139 -0
  171. agent_cli/server/tts/backends/kokoro.py +403 -0
  172. agent_cli/server/tts/backends/piper.py +253 -0
  173. agent_cli/server/tts/model_manager.py +201 -0
  174. agent_cli/server/tts/model_registry.py +28 -0
  175. agent_cli/server/tts/wyoming_handler.py +249 -0
  176. agent_cli/server/whisper/__init__.py +3 -0
  177. agent_cli/server/whisper/api.py +413 -0
  178. agent_cli/server/whisper/backends/__init__.py +89 -0
  179. agent_cli/server/whisper/backends/base.py +97 -0
  180. agent_cli/server/whisper/backends/faster_whisper.py +225 -0
  181. agent_cli/server/whisper/backends/mlx.py +270 -0
  182. agent_cli/server/whisper/languages.py +116 -0
  183. agent_cli/server/whisper/model_manager.py +157 -0
  184. agent_cli/server/whisper/model_registry.py +28 -0
  185. agent_cli/server/whisper/wyoming_handler.py +203 -0
  186. agent_cli/services/__init__.py +343 -0
  187. agent_cli/services/_wyoming_utils.py +64 -0
  188. agent_cli/services/asr.py +506 -0
  189. agent_cli/services/llm.py +228 -0
  190. agent_cli/services/tts.py +450 -0
  191. agent_cli/services/wake_word.py +142 -0
  192. agent_cli-0.70.5.dist-info/METADATA +2118 -0
  193. agent_cli-0.70.5.dist-info/RECORD +196 -0
  194. agent_cli-0.70.5.dist-info/WHEEL +4 -0
  195. agent_cli-0.70.5.dist-info/entry_points.txt +4 -0
  196. agent_cli-0.70.5.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,63 @@
1
+ # PowerShell script to set up agent-cli services on Windows
2
+ # Run with: powershell -ExecutionPolicy Bypass -File scripts/setup-windows.ps1
3
+
4
+ $ErrorActionPreference = "Stop"
5
+
6
+ Write-Host "🚀 Setting up agent-cli services on Windows..." -ForegroundColor Cyan
7
+
8
+ # Create .runtime directory
9
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
10
+ $RuntimeDir = Join-Path $ScriptDir ".runtime"
11
+ if (-not (Test-Path $RuntimeDir)) {
12
+ New-Item -ItemType Directory -Path $RuntimeDir | Out-Null
13
+ }
14
+
15
+ # Check if uv is installed
16
+ if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
17
+ Write-Host "📦 Installing uv..." -ForegroundColor Yellow
18
+ Invoke-RestMethod https://astral.sh/uv/install.ps1 | Invoke-Expression
19
+ # Refresh PATH
20
+ $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
21
+ } else {
22
+ Write-Host "✅ uv is already installed" -ForegroundColor Green
23
+ }
24
+
25
+ # Check if Ollama is installed
26
+ Write-Host "🧠 Checking Ollama..." -ForegroundColor Yellow
27
+ if (-not (Get-Command ollama -ErrorAction SilentlyContinue)) {
28
+ Write-Host "📦 Ollama is not installed." -ForegroundColor Red
29
+ Write-Host ""
30
+ Write-Host "Please download and install Ollama from:" -ForegroundColor Yellow
31
+ Write-Host " https://ollama.com/download/windows" -ForegroundColor Cyan
32
+ Write-Host ""
33
+ Write-Host "After installing, run this script again." -ForegroundColor Yellow
34
+ exit 1
35
+ } else {
36
+ Write-Host "✅ Ollama is already installed" -ForegroundColor Green
37
+ }
38
+
39
+ # Install agent-cli
40
+ Write-Host "🤖 Installing/upgrading agent-cli..." -ForegroundColor Yellow
41
+ uv tool install --upgrade agent-cli
42
+
43
+ # Preload default Ollama model
44
+ Write-Host "⬇️ Preloading default Ollama model (gemma3:4b)..." -ForegroundColor Yellow
45
+ Write-Host "⏳ This may take a few minutes depending on your internet connection..." -ForegroundColor Gray
46
+ ollama pull gemma3:4b
47
+
48
+ Write-Host ""
49
+ Write-Host "✅ Setup complete!" -ForegroundColor Green
50
+ Write-Host ""
51
+ Write-Host "You can now run the services:" -ForegroundColor Cyan
52
+ Write-Host ""
53
+ Write-Host "Option 1 - Run all services at once:" -ForegroundColor White
54
+ Write-Host " .\scripts\start-all-services-windows.ps1" -ForegroundColor Gray
55
+ Write-Host ""
56
+ Write-Host "Option 2 - Run services individually:" -ForegroundColor White
57
+ Write-Host " 1. Ollama: ollama serve (or it runs automatically as a service)" -ForegroundColor Gray
58
+ Write-Host " 2. Whisper: .\scripts\run-whisper-windows.ps1" -ForegroundColor Gray
59
+ Write-Host " 3. Piper: .\scripts\run-piper-windows.ps1" -ForegroundColor Gray
60
+ Write-Host ""
61
+ Write-Host "📝 Note: Scripts use uvx to run without needing virtual environments." -ForegroundColor Yellow
62
+ Write-Host "For GPU acceleration, make sure NVIDIA drivers and CUDA 12 are installed." -ForegroundColor Yellow
63
+ Write-Host "🎉 agent-cli has been installed and is ready to use!" -ForegroundColor Green
@@ -0,0 +1,53 @@
1
+ # PowerShell script to start all agent-cli services on Windows
2
+ # Run with: powershell -ExecutionPolicy Bypass -File scripts/start-all-services-windows.ps1
3
+
4
+ $ErrorActionPreference = "Stop"
5
+
6
+ Write-Host "🚀 Starting all agent-cli services..." -ForegroundColor Cyan
7
+
8
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
9
+
10
+ # Check if Windows Terminal is available for a nicer experience
11
+ $UseWindowsTerminal = $false
12
+ if (Get-Command wt -ErrorAction SilentlyContinue) {
13
+ $UseWindowsTerminal = $true
14
+ }
15
+
16
+ if ($UseWindowsTerminal) {
17
+ Write-Host "📺 Using Windows Terminal for multi-tab view..." -ForegroundColor Green
18
+
19
+ # Start Windows Terminal with multiple tabs
20
+ wt --title "agent-cli services" `
21
+ new-tab --title "Ollama" powershell -NoExit -Command "ollama serve" `; `
22
+ new-tab --title "Whisper" powershell -NoExit -ExecutionPolicy Bypass -File "$ScriptDir\run-whisper-windows.ps1" `; `
23
+ new-tab --title "Piper" powershell -NoExit -ExecutionPolicy Bypass -File "$ScriptDir\run-piper-windows.ps1"
24
+
25
+ Write-Host ""
26
+ Write-Host "✅ Services started in Windows Terminal tabs!" -ForegroundColor Green
27
+ Write-Host ""
28
+ Write-Host "📝 Tips:" -ForegroundColor Yellow
29
+ Write-Host " - Switch tabs with Ctrl+Tab" -ForegroundColor Gray
30
+ Write-Host " - Close all: Close the Windows Terminal window" -ForegroundColor Gray
31
+ } else {
32
+ Write-Host "📺 Opening services in separate PowerShell windows..." -ForegroundColor Yellow
33
+
34
+ # Start each service in a new PowerShell window
35
+ Start-Process powershell -ArgumentList "-NoExit", "-Command", "Write-Host 'Ollama' -ForegroundColor Cyan; ollama serve"
36
+ Start-Process powershell -ArgumentList "-NoExit", "-ExecutionPolicy", "Bypass", "-File", "$ScriptDir\run-whisper-windows.ps1"
37
+ Start-Process powershell -ArgumentList "-NoExit", "-ExecutionPolicy", "Bypass", "-File", "$ScriptDir\run-piper-windows.ps1"
38
+
39
+ Write-Host ""
40
+ Write-Host "✅ Services started in separate windows!" -ForegroundColor Green
41
+ Write-Host ""
42
+ Write-Host "📝 Note: Install Windows Terminal for a better multi-tab experience:" -ForegroundColor Yellow
43
+ Write-Host " winget install Microsoft.WindowsTerminal" -ForegroundColor Gray
44
+ }
45
+
46
+ Write-Host ""
47
+ Write-Host "🔌 Service ports:" -ForegroundColor Cyan
48
+ Write-Host " - Ollama: http://localhost:11434" -ForegroundColor Gray
49
+ Write-Host " - Whisper: tcp://localhost:10300" -ForegroundColor Gray
50
+ Write-Host " - Piper: tcp://localhost:10200" -ForegroundColor Gray
51
+ Write-Host ""
52
+ Write-Host "🎉 You can now use agent-cli!" -ForegroundColor Green
53
+ Write-Host " agent-cli transcribe" -ForegroundColor Gray
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Check if zellij is installed
4
+ if ! command -v zellij &> /dev/null; then
5
+ echo "📺 Zellij not found. Installing..."
6
+ uvx dotbins get zellij-org/zellij
7
+ export PATH="$HOME/.local/bin:$PATH"
8
+ fi
9
+
10
+ # Get the current directory
11
+ SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
12
+
13
+ # Help text for zellij panes
14
+ HELP_TEXT='╔═══════════════════════════════════════════════════════════════════╗
15
+ ║ Agent CLI Services ║
16
+ ╠═══════════════════════════════════════════════════════════════════╣
17
+ ║ ║
18
+ ║ 🔴 IMPORTANT: ║
19
+ ║ • Ctrl-O d → Detach (keeps services running in background!) ║
20
+ ║ • Ctrl-Q → Quit (STOPS all services!) ║
21
+ ║ ║
22
+ ║ To reattach later: $ zellij attach agent-cli ║
23
+ ║ ║
24
+ ╠═══════════════════════════════════════════════════════════════════╣
25
+ ║ ║
26
+ ║ Services Running: ║
27
+ ║ • Ollama (LLM) - Port 11434 ║
28
+ ║ • Whisper (STT) - Port 10300 ║
29
+ ║ • Piper (TTS) - Port 10200 ║
30
+ ║ • OpenWakeWord - Port 10400 ║
31
+ ║ ║
32
+ ║ Navigation: ║
33
+ ║ • Alt + ← → ↑ ↓ - Move between panes ║
34
+ ║ • Ctrl-F - Toggle this help ║
35
+ ║ • q - Close this help ║
36
+ ║ ║
37
+ ╚═══════════════════════════════════════════════════════════════════╝'
38
+
39
+ # On macOS, check if services are running via brew/launchd
40
+ OLLAMA_BREW_SERVICE=false
41
+ WHISPER_LAUNCHD=false
42
+ if [ "$(uname -s)" = "Darwin" ]; then
43
+ # Check if Ollama is running as a brew service
44
+ if launchctl list homebrew.mxcl.ollama &>/dev/null; then
45
+ OLLAMA_BREW_SERVICE=true
46
+ fi
47
+ # Check if Whisper is running as a launchd service (ARM only)
48
+ if [ "$(uname -m)" = "arm64" ]; then
49
+ if launchctl list com.wyoming_mlx_whisper &>/dev/null; then
50
+ WHISPER_LAUNCHD=true
51
+ fi
52
+ fi
53
+ fi
54
+
55
+ # Create .runtime directory
56
+ mkdir -p "$SCRIPTS_DIR/.runtime"
57
+
58
+ # Generate Ollama pane based on whether brew service is running
59
+ if [ "$OLLAMA_BREW_SERVICE" = true ]; then
60
+ OLLAMA_PANE=" pane {
61
+ name \"Ollama (brew service)\"
62
+ command \"sh\"
63
+ args \"-c\" \"echo '🧠 Ollama is running as a brew background service'; echo ''; echo 'To view status:'; echo ' brew services info ollama'; echo ''; echo 'To stop:'; echo ' brew services stop ollama'; echo ''; echo 'To restart:'; echo ' brew services restart ollama'; echo ''; read -r\"
64
+ }"
65
+ else
66
+ OLLAMA_PANE=" pane {
67
+ name \"Ollama\"
68
+ command \"ollama\"
69
+ args \"serve\"
70
+ }"
71
+ fi
72
+
73
+ # Generate Whisper pane command based on whether launchd service is running
74
+ if [ "$WHISPER_LAUNCHD" = true ]; then
75
+ WHISPER_PANE=" pane {
76
+ name \"Whisper (launchd)\"
77
+ command \"sh\"
78
+ args \"-c\" \"echo '🎤 Whisper is running as a background launchd service'; echo ''; echo 'Service: com.wyoming_mlx_whisper'; echo 'Logs: ~/Library/Logs/wyoming-mlx-whisper/'; echo ''; echo 'To view logs:'; echo ' tail -f ~/Library/Logs/wyoming-mlx-whisper/wyoming-mlx-whisper.out'; echo ''; echo 'To uninstall:'; echo ' curl -fsSL https://raw.githubusercontent.com/basnijholt/wyoming-mlx-whisper/main/scripts/uninstall_service.sh | bash'; echo ''; read -r\"
79
+ }"
80
+ else
81
+ WHISPER_PANE=" pane {
82
+ name \"Whisper\"
83
+ cwd \"$SCRIPTS_DIR\"
84
+ command \"./run-whisper.sh\"
85
+ }"
86
+ fi
87
+
88
+ BOTTOM_PANES=" pane split_direction=\"horizontal\" {
89
+ $WHISPER_PANE
90
+ pane split_direction=\"horizontal\" {
91
+ pane {
92
+ name \"Piper\"
93
+ cwd \"$SCRIPTS_DIR\"
94
+ command \"./run-piper.sh\"
95
+ }
96
+ pane {
97
+ name \"OpenWakeWord\"
98
+ cwd \"$SCRIPTS_DIR\"
99
+ command \"./run-openwakeword.sh\"
100
+ }
101
+ }
102
+ }"
103
+
104
+ TOP_PANES=" pane split_direction=\"horizontal\" {
105
+ $OLLAMA_PANE
106
+ pane {
107
+ name \"Help\"
108
+ command \"sh\"
109
+ args \"-c\" \"echo '$HELP_TEXT' | less\"
110
+ }
111
+ }"
112
+
113
+ cat > "$SCRIPTS_DIR/.runtime/agent-cli-layout.kdl" << EOF
114
+ session_name "agent-cli"
115
+
116
+ layout {
117
+ pane split_direction="vertical" {
118
+ $TOP_PANES
119
+ $BOTTOM_PANES
120
+ }
121
+
122
+ floating_panes {
123
+ pane {
124
+ name "Help"
125
+ x "10%"
126
+ y "10%"
127
+ width "80%"
128
+ height "80%"
129
+ command "sh"
130
+ close_on_exit true
131
+ args "-c" "echo '$HELP_TEXT' | less"
132
+ }
133
+ }
134
+ }
135
+ EOF
136
+
137
+ # Function to show common usage instructions
138
+ show_usage() {
139
+ echo "❌ Use 'Ctrl-Q' to quit Zellij"
140
+ echo "🔌 Use 'Ctrl-O d' to detach from the session"
141
+ echo "🔗 Use 'zellij attach agent-cli' to reattach"
142
+ }
143
+
144
+ # Function to start a new Zellij session
145
+ start_new_session() {
146
+ if [ "$AGENT_CLI_NO_ATTACH" = "true" ]; then
147
+ # Start detached
148
+ zellij --session agent-cli --layout "$SCRIPTS_DIR/.runtime/agent-cli-layout.kdl" &
149
+ sleep 1 # Give it a moment to start
150
+ echo "✅ Session 'agent-cli' started in background. Use 'zellij attach agent-cli' to view."
151
+ else
152
+ show_usage
153
+ # Start zellij with layout file - session name is specified in the layout
154
+ zellij --layout "$SCRIPTS_DIR/.runtime/agent-cli-layout.kdl"
155
+ fi
156
+ }
157
+
158
+ # Check if agent-cli session already exists and is running
159
+ # Case 1: Session exists but has exited - clean it up and start fresh
160
+ if zellij list-sessions 2>/dev/null | grep "agent-cli" | grep -q "EXITED"; then
161
+ echo "🧹 Found exited session 'agent-cli'. Cleaning up..."
162
+ zellij delete-session agent-cli
163
+ echo "🆕 Starting fresh services in Zellij..."
164
+ start_new_session
165
+ # Case 2: Session exists and is running - attach to it if requested
166
+ elif zellij list-sessions 2>/dev/null | grep -q "agent-cli"; then
167
+ if [ "$AGENT_CLI_NO_ATTACH" = "true" ]; then
168
+ echo "✅ Session 'agent-cli' is already running. Not attaching as requested."
169
+ else
170
+ echo "🔗 Session 'agent-cli' already exists and is running. Attaching..."
171
+ show_usage
172
+ zellij attach agent-cli
173
+ fi
174
+ # Case 3: No session exists - create a new one
175
+ else
176
+ echo "🚀 Starting all services in Zellij..."
177
+ start_new_session
178
+ fi
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env python3
2
+ """Generate _extras.json from pyproject.toml.
3
+
4
+ This script parses the optional-dependencies in pyproject.toml and generates
5
+ the agent_cli/_extras.json file with package-to-import mappings.
6
+
7
+ Usage:
8
+ python scripts/sync_extras.py
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import re
15
+ import sys
16
+ import tomllib
17
+ from pathlib import Path
18
+
19
+ REPO_ROOT = Path(__file__).parent.parent
20
+ PYPROJECT = REPO_ROOT / "pyproject.toml"
21
+ EXTRAS_FILE = REPO_ROOT / "agent_cli" / "_extras.json"
22
+
23
+ # Extras to skip (dev/test dependencies, not runtime installable)
24
+ SKIP_EXTRAS = {"dev", "test"}
25
+
26
+ # Manual mapping of extra name -> (description, list of import names)
27
+ # Import names should be the Python module name (how you import it)
28
+ # Bundle extras (voice, cloud, full) have empty import lists since they just install other extras
29
+ EXTRA_METADATA: dict[str, tuple[str, list[str]]] = {
30
+ # Provider extras (base dependencies now optional)
31
+ "audio": ("Audio recording/playback", ["sounddevice"]),
32
+ "wyoming": ("Wyoming protocol support", ["wyoming"]),
33
+ "openai": ("OpenAI API provider", ["openai"]),
34
+ "gemini": ("Google Gemini provider", ["google.genai"]),
35
+ "llm": ("LLM framework (pydantic-ai)", ["pydantic_ai"]),
36
+ # Feature extras
37
+ "rag": ("RAG proxy (ChromaDB, embeddings)", ["chromadb"]),
38
+ "memory": ("Long-term memory proxy", ["chromadb", "yaml"]),
39
+ "vad": ("Voice Activity Detection (silero-vad)", ["silero_vad"]),
40
+ "whisper": ("Local Whisper ASR (faster-whisper)", ["faster_whisper"]),
41
+ "whisper-mlx": ("MLX Whisper for Apple Silicon", ["mlx_whisper"]),
42
+ "tts": ("Local Piper TTS", ["piper"]),
43
+ "tts-kokoro": ("Kokoro neural TTS", ["kokoro"]),
44
+ "server": ("FastAPI server components", ["fastapi"]),
45
+ "speed": ("Audio speed adjustment (audiostretchy)", ["audiostretchy"]),
46
+ }
47
+
48
+
49
+ def get_extras_from_pyproject() -> set[str]:
50
+ """Parse optional-dependencies from pyproject.toml."""
51
+ with PYPROJECT.open("rb") as f:
52
+ data = tomllib.load(f)
53
+ all_extras = set(data.get("project", {}).get("optional-dependencies", {}).keys())
54
+ return all_extras - SKIP_EXTRAS
55
+
56
+
57
+ def extract_package_name(dep: str) -> str:
58
+ """Extract the package name from a dependency specification.
59
+
60
+ Examples:
61
+ "chromadb>=0.4.22" -> "chromadb"
62
+ "pydantic-ai-slim[openai,duckduckgo]" -> "pydantic-ai-slim"
63
+ 'mlx-whisper>=0.4.0; sys_platform == "darwin"' -> "mlx-whisper"
64
+
65
+ """
66
+ # Remove markers (;...) and extras ([...])
67
+ dep = re.split(r"[;\[]", dep)[0]
68
+ # Remove version specifiers
69
+ dep = re.split(r"[<>=!~]", dep)[0]
70
+ return dep.strip()
71
+
72
+
73
+ def package_to_import_name(package: str) -> str:
74
+ """Convert a package name to its Python import name.
75
+
76
+ Examples:
77
+ "google-genai" -> "google.genai"
78
+ "pydantic-ai-slim" -> "pydantic_ai"
79
+ "silero-vad" -> "silero_vad"
80
+ "faster-whisper" -> "faster_whisper"
81
+
82
+ """
83
+ # Special cases where the import name differs significantly
84
+ special_cases = {
85
+ "google-genai": "google.genai",
86
+ "pydantic-ai-slim": "pydantic_ai",
87
+ "silero-vad": "silero_vad",
88
+ "faster-whisper": "faster_whisper",
89
+ "mlx-whisper": "mlx_whisper",
90
+ "piper-tts": "piper",
91
+ "huggingface-hub": "huggingface_hub",
92
+ "fastapi": "fastapi",
93
+ "audiostretchy": "audiostretchy",
94
+ }
95
+ if package in special_cases:
96
+ return special_cases[package]
97
+ # Default: replace hyphens with underscores
98
+ return package.replace("-", "_")
99
+
100
+
101
+ def generate_extras_json(extras: set[str]) -> dict[str, list]:
102
+ """Generate the content for _extras.json."""
103
+ result = {}
104
+ for extra in sorted(extras):
105
+ if extra in EXTRA_METADATA:
106
+ desc, imports = EXTRA_METADATA[extra]
107
+ result[extra] = [desc, imports]
108
+ else:
109
+ # Unknown extra - add a placeholder
110
+ result[extra] = ["TODO: add description", []]
111
+ return result
112
+
113
+
114
+ def check_missing_metadata(extras: set[str]) -> list[str]:
115
+ """Check for extras that don't have metadata defined."""
116
+ return [e for e in extras if e not in EXTRA_METADATA]
117
+
118
+
119
+ def main() -> int:
120
+ """Generate _extras.json from pyproject.toml."""
121
+ extras = get_extras_from_pyproject()
122
+
123
+ # Check for missing metadata
124
+ missing = check_missing_metadata(extras)
125
+ if missing:
126
+ print(f"Warning: The following extras need metadata in EXTRA_METADATA: {missing}")
127
+ print("Please update EXTRA_METADATA in scripts/sync_extras.py")
128
+
129
+ # Generate the file
130
+ content = generate_extras_json(extras)
131
+ EXTRAS_FILE.write_text(json.dumps(content, indent=2) + "\n")
132
+ print(f"Generated {EXTRAS_FILE}")
133
+
134
+ return 0
135
+
136
+
137
+ if __name__ == "__main__":
138
+ sys.exit(main())
@@ -0,0 +1,3 @@
1
+ """Server module for agent-cli."""
2
+
3
+ from __future__ import annotations