Preserve macOS app permissions via dynamic launcher, .env workspace path, and session/audio tools

This commit is contained in:
Adolfo Reyna
2026-08-11 21:15:37 -04:00
parent 583131221c
commit b5034b4b16
17 changed files with 1888 additions and 68 deletions
+22 -3
View File
@@ -82,6 +82,9 @@ say them:
- Use your available tools (listing directories, searching, reading files, shell execution) whenever the user asks about files, commands, CLI tools (such as Paseo), or workspace tasks.
- You can change your own voice! If the user asks to list available voices or switch voice, run `python bin/voice_tool.py list` or `python bin/voice_tool.py set <voice_name>` (voices: af_heart, af_bella, am_michael, am_fenrir, am_puck, bf_emma, bm_george, Moira, Daniel).
- You can change your AI model on the fly! If the user asks to list available models or change model, run `python bin/model_tool.py list` or `python bin/model_tool.py set <model_name>` (models: luna, gemma, deepseek, gpt-oss, sonnet, etc.).
- You can reset or start a fresh conversation session! If the user asks to start a fresh session, reset the conversation, or clear session context, run `python bin/session_tool.py reset`.
- You can switch Hermes agent profiles! If the user asks to list Hermes profiles or switch profile, run `python bin/profile_tool.py list` or `python bin/profile_tool.py set <profile_name>`.
- You can change the running microphone and speakers independently. For requests such as “use AirPods”, “switch to Mac speakers”, or “use the Mac default mic”, run `python bin/audio_tool.py list` then `python bin/audio_tool.py set input|output <device-name-or-index|default>`. Report the command result plainly; do not claim a device changed if the tool says it is unavailable.
- You can open files visually for the user in the Companion Web UI drawer! Run `python bin/web_tool.py show <filepath>`.
- You can open links or the Companion Web UI in the default browser! Run `python bin/web_tool.py open <url>`.
- Keep implementation details and tool activity silent in the spoken channel. The user can see technical progress in the logs or Companion Web UI; only speak the useful conversational response.
@@ -571,6 +574,21 @@ async def main() -> int:
logger.info(f"Created {workspace}")
logger.info(f"Workspace: {workspace}")
async def on_audio_device_event(snapshot) -> None:
"""Keep native route changes observable without touching conversation state."""
logger.info(
"Audio device event "
f"generation={snapshot.generation} reason={snapshot.reason.value} "
f"input={snapshot.default_input_uid!r} output={snapshot.default_output_uid!r}"
)
if not getattr(args, "no_web", False):
web_server.broadcast_event("audio_device", {
"generation": snapshot.generation,
"reason": snapshot.reason.value,
"input_uid": snapshot.default_input_uid,
"output_uid": snapshot.default_output_uid,
})
transport = SoundDeviceTransport(
SoundDeviceTransportParams(
audio_in_enabled=True,
@@ -579,7 +597,8 @@ async def main() -> int:
audio_out_sample_rate=TTS_SAMPLE_RATE,
input_device=as_device(args.input_device),
output_device=as_device(args.output_device),
)
),
device_event_sink=on_audio_device_event,
)
brain = None
@@ -603,7 +622,7 @@ async def main() -> int:
model_manager = ModelManager(workspace)
if not getattr(args, "no_web", False):
await web_server.start_server(workspace, port=getattr(args, "web_port", 8888))
web_server.set_managers(workspace, model_manager, voice_manager)
web_server.set_managers(workspace, model_manager, voice_manager, audio_controller=transport)
llm = build_llm(
args,
@@ -674,7 +693,7 @@ async def main() -> int:
await worker.queue_frames(frames)
if not getattr(args, "no_web", False):
web_server.set_managers(workspace, model_manager, voice_manager, input_callback=on_web_input)
web_server.set_managers(workspace, model_manager, voice_manager, input_callback=on_web_input, audio_controller=transport)
if args.greeting:
await worker.queue_frames([TTSSpeakFrame(args.greeting)])