bxctl: chat --speaker NAME, the speaker on every turn of the chat
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
+23
-1
@@ -9,8 +9,9 @@ use bxcore::SessionId;
|
||||
pub const USAGE: &str = "\
|
||||
usage: bxctl <command> [options]
|
||||
|
||||
bxctl chat [--socket PATH] [--admin-socket PATH] [--session ID] [--say TEXT] [--no-thinking] [--json]
|
||||
bxctl chat [--socket PATH] [--admin-socket PATH] [--session ID] [--say TEXT] [--no-thinking] [--json] [--speaker NAME]
|
||||
Talk to loopd.
|
||||
With --speaker NAME (no spaces), the turns are NAME's and are synced to Honcho as that person.
|
||||
|
||||
bxctl approvals [--admin-socket PATH]
|
||||
List the approvals waiting for a decision.
|
||||
@@ -50,6 +51,9 @@ pub struct ChatOptions {
|
||||
pub show_thinking: bool,
|
||||
pub say: Option<String>,
|
||||
pub json: bool,
|
||||
/// Who is typing, from `--speaker`, sent on every turn (M5c spec, section 11). There is no
|
||||
/// default: without the flag it is `None`, and a turn without a speaker is not synced.
|
||||
pub speaker: Option<String>,
|
||||
}
|
||||
|
||||
impl ChatOptions {
|
||||
@@ -61,6 +65,7 @@ impl ChatOptions {
|
||||
show_thinking: true,
|
||||
say: None,
|
||||
json: false,
|
||||
speaker: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,6 +148,14 @@ fn parse_chat(args: &[String], home: &Path) -> Result<Command, UsageError> {
|
||||
"--admin-socket" => opts.admin_socket = PathBuf::from(value_at(args, i)?),
|
||||
"--session" => opts.session = Some(parse_session(&value_at(args, i)?)?),
|
||||
"--say" => opts.say = Some(value_at(args, i)?),
|
||||
// Given twice, it is refused rather than one of them chosen: the turns would be synced
|
||||
// as the wrong person.
|
||||
"--speaker" => {
|
||||
if opts.speaker.is_some() {
|
||||
return Err(UsageError);
|
||||
}
|
||||
opts.speaker = Some(parse_speaker(&value_at(args, i)?)?);
|
||||
}
|
||||
"--no-thinking" => {
|
||||
opts.show_thinking = false;
|
||||
i += 1;
|
||||
@@ -305,6 +318,15 @@ fn parse_session(value: &str) -> Result<SessionId, UsageError> {
|
||||
}
|
||||
}
|
||||
|
||||
// A speaker must be a name: not empty, and no whitespace or control character anywhere. The rest,
|
||||
// Honcho's pattern, is `memoryd`'s to check (M5c spec, section 3); a `.` is kept as it is.
|
||||
fn parse_speaker(value: &str) -> Result<String, UsageError> {
|
||||
if value.is_empty() || value.chars().any(|c| c.is_whitespace() || c.is_control()) {
|
||||
return Err(UsageError);
|
||||
}
|
||||
Ok(value.to_string())
|
||||
}
|
||||
|
||||
// A refuse reason must be present; its content is unvalidated on the client.
|
||||
fn verify_reason(reason: &str) -> Result<String, UsageError> {
|
||||
if reason.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user