Preserve macOS app permissions via dynamic launcher, .env workspace path, and session/audio tools
This commit is contained in:
@@ -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)])
|
||||
|
||||
Reference in New Issue
Block a user