Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src-tauri/crates/berd-call/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ complete `berd-call session` options. The call keeps its control port, stream,
blocking policy, mute state, and input-during-TTS policy; the stream emits a lifecycle row because
transcript cursors restart with the new session.

`berd-call settings --spokesperson true|false`, or Spokesperson in the menu bar,
restarts the call the same way in the other mode. Agents keep their current
voice, options only the other mode takes are left out, and in a `--stream live`
call the Spokesperson comes back with `--allow-direct-agent-speech`.

This crate owns the neutral PCM output contract and backend-neutral TTS stream
used by Berd, plus the April ONNX runtime and text chunking used by Berd's native
voice commands. It also owns the concrete Parakeet model loader and complete
Expand Down
9 changes: 7 additions & 2 deletions src-tauri/crates/berd-call/src/cli_help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,18 @@ Usage:
berd-call settings [--port PORT] --tts JSON
berd-call settings [--port PORT] --input-during-tts allow|suppress
berd-call settings [--port PORT] --muted true|false
berd-call settings [--port PORT] --spokesperson true|false
berd-call settings [--port PORT] --restart [session options]

The setting applies to subsequent speak calls. In a call started with
--allow-direct-agent-speech, --voice and --rate change the agents' voice, and
--spokesperson-voice and --spokesperson-rate change the Spokesperson's (an
OpenAI realtime voice, 0.25 to 1.5). Non-blocking delivery requires
a call started with --stream or --codex. Successful delivery produces no notification."#;
OpenAI realtime voice, 0.25 to 1.5). --spokesperson turns the Spokesperson on
or off, restarting the call's session in the other mode with the same voice;
options only the other mode takes are dropped, and in a call started with
--stream live, agents keep their own voice beside the Spokesperson's.
Non-blocking delivery requires a call started with --stream or --codex.
Successful delivery produces no notification."#;

const STATUS_HELP: &str = r#"Inspect the active local voice call.

Expand Down
10 changes: 10 additions & 0 deletions src-tauri/crates/berd-call/src/host_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub(crate) trait HostControl: Send + Sync + 'static {
) -> Result<Value, String>;
fn set_muted(&self, muted: bool) -> Result<Value, String>;
fn restart(&self, session_arguments: Vec<String>) -> Result<Value, String>;
/// Restarts the call's session with the Spokesperson on or off.
fn set_spokesperson_mode(&self, on: bool) -> Result<Value, String>;
}

pub(crate) struct ControlServer {
Expand Down Expand Up @@ -154,6 +156,9 @@ pub(crate) enum ControlRequest {
#[serde(rename = "sessionArguments")]
session_arguments: Vec<String>,
},
SpokespersonMode {
on: bool,
},
}

#[derive(Deserialize, Serialize)]
Expand Down Expand Up @@ -204,6 +209,7 @@ pub(crate) fn begin_request(port: u16, request: ControlRequest) -> Result<Pendin
| ControlRequest::Voice { .. }
| ControlRequest::Spokesperson { .. }
| ControlRequest::Restart { .. }
| ControlRequest::SpokespersonMode { .. }
) {
None
} else {
Expand Down Expand Up @@ -273,6 +279,7 @@ fn handle_connection(mut stream: TcpStream, control: &dyn HostControl) -> Result
ControlRequest::InputDuringTts { policy } => control.set_input_during_tts(policy),
ControlRequest::Muted { muted } => control.set_muted(muted),
ControlRequest::Restart { session_arguments } => control.restart(session_arguments),
ControlRequest::SpokespersonMode { on } => control.set_spokesperson_mode(on),
},
);
let response = match result {
Expand Down Expand Up @@ -416,6 +423,9 @@ mod tests {
fn restart(&self, session_arguments: Vec<String>) -> Result<Value, String> {
Ok(json!({"sessionArguments": session_arguments}))
}
fn set_spokesperson_mode(&self, on: bool) -> Result<Value, String> {
Ok(json!({"spokesperson": on}))
}
fn status(&self) -> Result<Value, String> {
Ok(json!({"running": !self.stopped.load(Ordering::SeqCst)}))
}
Expand Down
Loading
Loading