Initial commit
This commit is contained in:
35
src/controller/cfg/common/generic_setting.rs
Normal file
35
src/controller/cfg/common/generic_setting.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use crate::{entity::MessageContext, strings, Bot};
|
||||
|
||||
pub async fn handle_get<T>(
|
||||
bot: &Bot,
|
||||
message_context: &MessageContext,
|
||||
value: &Option<T>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
match value {
|
||||
Some(value) => {
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::cfg::value_currently_set_to(value),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
None => {
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::cfg::value_currently_unset(),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
1
src/controller/cfg/common/mod.rs
Normal file
1
src/controller/cfg/common/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub(super) mod generic_setting;
|
||||
74
src/controller/cfg/controller_type.rs
Normal file
74
src/controller/cfg/controller_type.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use crate::{
|
||||
agent::{AgentPurpose, PublicIdentifier},
|
||||
entity::roomconfig::{
|
||||
SpeechToTextFlowType, TextGenerationAutoUsage, TextGenerationPrefixRequirementType,
|
||||
TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SettingsStorageSource {
|
||||
Room,
|
||||
Global,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ConfigControllerType {
|
||||
Help,
|
||||
|
||||
Status,
|
||||
|
||||
SettingsRelated(SettingsStorageSource, ConfigSettingRelatedControllerType),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ConfigSettingRelatedControllerType {
|
||||
GetHandler(AgentPurpose),
|
||||
SetHandler(AgentPurpose, Option<PublicIdentifier>),
|
||||
|
||||
TextGeneration(ConfigTextGenerationSettingRelatedControllerType),
|
||||
SpeechToText(ConfigSpeechToTextSettingRelatedControllerType),
|
||||
TextToSpeech(ConfigTextToSpeechSettingRelatedControllerType),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ConfigTextGenerationSettingRelatedControllerType {
|
||||
GetContextManagementEnabled,
|
||||
SetContextManagementEnabled(Option<bool>),
|
||||
|
||||
GetPrefixRequirementType,
|
||||
SetPrefixRequirementType(Option<TextGenerationPrefixRequirementType>),
|
||||
|
||||
GetAutoUsage,
|
||||
SetAutoUsage(Option<TextGenerationAutoUsage>),
|
||||
|
||||
GetPromptOverride,
|
||||
SetPromptOverride(Option<String>),
|
||||
|
||||
GetTemperatureOverride,
|
||||
SetTemperatureOverride(Option<f32>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ConfigSpeechToTextSettingRelatedControllerType {
|
||||
GetFlowType,
|
||||
SetFlowType(Option<SpeechToTextFlowType>),
|
||||
|
||||
GetLanguage,
|
||||
SetLanguage(Option<String>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ConfigTextToSpeechSettingRelatedControllerType {
|
||||
GetBotMessagesFlowType,
|
||||
SetBotMessagesFlowType(Option<TextToSpeechBotMessagesFlowType>),
|
||||
|
||||
GetUserMessagesFlowType,
|
||||
SetUserMessagesFlowType(Option<TextToSpeechUserMessagesFlowType>),
|
||||
|
||||
GetSpeedOverride,
|
||||
SetSpeedOverride(Option<f32>),
|
||||
|
||||
GetVoiceOverride,
|
||||
SetVoiceOverride(Option<String>),
|
||||
}
|
||||
141
src/controller/cfg/determination/mod.rs
Normal file
141
src/controller/cfg/determination/mod.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
mod speech_to_text;
|
||||
mod text_generation;
|
||||
mod text_to_speech;
|
||||
|
||||
use crate::{
|
||||
agent::{AgentPurpose, PublicIdentifier},
|
||||
controller::ControllerType,
|
||||
strings,
|
||||
};
|
||||
|
||||
use super::controller_type::{
|
||||
ConfigControllerType, ConfigSettingRelatedControllerType, SettingsStorageSource,
|
||||
};
|
||||
|
||||
pub fn determine_controller(text: &str) -> ControllerType {
|
||||
if text.starts_with("status") {
|
||||
return ControllerType::Config(ConfigControllerType::Status);
|
||||
}
|
||||
|
||||
// Someone pasted our instructions verbatim.
|
||||
if text.strip_prefix("CONFIG_TYPE").is_some() {
|
||||
return ControllerType::Error(strings::cfg::error_config_type_not_replaced());
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("room ") {
|
||||
return match do_determine_controller(remaining_text.trim()) {
|
||||
Ok(handler) => ControllerType::Config(ConfigControllerType::SettingsRelated(
|
||||
SettingsStorageSource::Room,
|
||||
handler,
|
||||
)),
|
||||
Err(controller_type) => controller_type,
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("global ") {
|
||||
return match do_determine_controller(remaining_text.trim()) {
|
||||
Ok(handler) => ControllerType::Config(ConfigControllerType::SettingsRelated(
|
||||
SettingsStorageSource::Global,
|
||||
handler,
|
||||
)),
|
||||
Err(controller_type) => controller_type,
|
||||
};
|
||||
}
|
||||
|
||||
ControllerType::Config(ConfigControllerType::Help)
|
||||
}
|
||||
|
||||
fn do_determine_controller(
|
||||
text: &str,
|
||||
) -> Result<ConfigSettingRelatedControllerType, ControllerType> {
|
||||
if let Some(purpose_str) = text.strip_prefix("handler") {
|
||||
let purpose_str = purpose_str.trim();
|
||||
|
||||
if purpose_str.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_invocation_incorrect_more_values_expected().to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
let Some(purpose) = AgentPurpose::from_str(purpose_str) else {
|
||||
return Err(ControllerType::Error(
|
||||
strings::agent::purpose_unrecognized(purpose_str).to_owned(),
|
||||
));
|
||||
};
|
||||
|
||||
return Ok(ConfigSettingRelatedControllerType::GetHandler(purpose));
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("set-handler") {
|
||||
// Something like:
|
||||
// - `PURPOSE ID`
|
||||
// - `PURPOSE`
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_invocation_incorrect_more_values_expected().to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
// This will be None if we're just dealing with `PURPOSE` and lack an `ID`.
|
||||
// In such cases, the whole thing is the purpose string.
|
||||
let parts = remaining_text.split_once(' ');
|
||||
|
||||
let (purpose_str, agent_id_string_option) = if let Some(parts) = parts {
|
||||
(parts.0, Some(parts.1.to_owned()))
|
||||
} else {
|
||||
(remaining_text, None)
|
||||
};
|
||||
|
||||
let Some(purpose) = AgentPurpose::from_str(purpose_str) else {
|
||||
return Err(ControllerType::Error(
|
||||
strings::agent::purpose_unrecognized(purpose_str).to_owned(),
|
||||
));
|
||||
};
|
||||
|
||||
let agent_identifier = match agent_id_string_option {
|
||||
Some(agent_id_string) => {
|
||||
let Some(agent_identifier) = PublicIdentifier::from_str(&agent_id_string) else {
|
||||
return Err(ControllerType::Error(
|
||||
strings::agent::invalid_id_generic().to_owned(),
|
||||
));
|
||||
};
|
||||
|
||||
Some(agent_identifier)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
return Ok(ConfigSettingRelatedControllerType::SetHandler(
|
||||
purpose,
|
||||
agent_identifier,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("text-generation") {
|
||||
return match text_generation::determine(remaining_text.trim()) {
|
||||
Ok(handler) => Ok(ConfigSettingRelatedControllerType::TextGeneration(handler)),
|
||||
Err(controller_type) => Err(controller_type),
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("text-to-speech") {
|
||||
return match text_to_speech::determine(remaining_text.trim()) {
|
||||
Ok(handler) => Ok(ConfigSettingRelatedControllerType::TextToSpeech(handler)),
|
||||
Err(controller_type) => Err(controller_type),
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("speech-to-text") {
|
||||
return match speech_to_text::determine(remaining_text.trim()) {
|
||||
Ok(handler) => Ok(ConfigSettingRelatedControllerType::SpeechToText(handler)),
|
||||
Err(controller_type) => Err(controller_type),
|
||||
};
|
||||
}
|
||||
|
||||
Err(ControllerType::Unknown)
|
||||
}
|
||||
87
src/controller/cfg/determination/speech_to_text/mod.rs
Normal file
87
src/controller/cfg/determination/speech_to_text/mod.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::{controller::ControllerType, entity::roomconfig::SpeechToTextFlowType, strings};
|
||||
|
||||
use super::super::controller_type::ConfigSpeechToTextSettingRelatedControllerType;
|
||||
|
||||
pub(super) fn determine(
|
||||
text: &str,
|
||||
) -> Result<ConfigSpeechToTextSettingRelatedControllerType, ControllerType> {
|
||||
// Flow Type
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("flow-type") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"flow-type",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigSpeechToTextSettingRelatedControllerType::GetFlowType);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-flow-type") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
let value_choice = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let value_choice = SpeechToTextFlowType::from_str(&value_string.to_lowercase());
|
||||
|
||||
if value_choice.is_none() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_unrecognized(&value_string).to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
value_choice
|
||||
};
|
||||
|
||||
return Ok(ConfigSpeechToTextSettingRelatedControllerType::SetFlowType(
|
||||
value_choice,
|
||||
));
|
||||
}
|
||||
|
||||
// Language
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("language") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text("language", remaining_text)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigSpeechToTextSettingRelatedControllerType::GetLanguage);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-language") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
let value_string = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
if value_string.len() != 2 {
|
||||
return Err(ControllerType::Error(
|
||||
strings::speech_to_text::language_code_invalid(&value_string).to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
Some(value_string)
|
||||
};
|
||||
|
||||
return Ok(ConfigSpeechToTextSettingRelatedControllerType::SetLanguage(
|
||||
value_string,
|
||||
));
|
||||
}
|
||||
|
||||
Err(ControllerType::Unknown)
|
||||
}
|
||||
136
src/controller/cfg/determination/speech_to_text/tests.rs
Normal file
136
src/controller/cfg/determination/speech_to_text/tests.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
#[test]
|
||||
fn determine_controller_other() {
|
||||
use super::ConfigSpeechToTextSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigSpeechToTextSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![TestCase {
|
||||
name: "Unknown",
|
||||
input: "whatever",
|
||||
expected: Err(ControllerType::Unknown),
|
||||
}];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_flow_type() {
|
||||
use super::ConfigSpeechToTextSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
use crate::entity::roomconfig::SpeechToTextFlowType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigSpeechToTextSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "flow-type getter ok",
|
||||
input: "flow-type",
|
||||
expected: Ok(ConfigSpeechToTextSettingRelatedControllerType::GetFlowType),
|
||||
},
|
||||
TestCase {
|
||||
name: "flow-type getter extra args",
|
||||
input: "flow-type some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"flow-type",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "flow-type setter",
|
||||
input: "set-flow-type transcribe_and_generate_text",
|
||||
expected: Ok(ConfigSpeechToTextSettingRelatedControllerType::SetFlowType(
|
||||
Some(SpeechToTextFlowType::TranscribeAndGenerateText),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "flow-type setter",
|
||||
input: "set-flow-type unknown-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_unrecognized("unknown-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "flow-type unsetter",
|
||||
input: "set-flow-type",
|
||||
expected: Ok(ConfigSpeechToTextSettingRelatedControllerType::SetFlowType(
|
||||
None,
|
||||
)),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_language() {
|
||||
use super::ConfigSpeechToTextSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigSpeechToTextSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "language getter ok",
|
||||
input: "language",
|
||||
expected: Ok(ConfigSpeechToTextSettingRelatedControllerType::GetLanguage),
|
||||
},
|
||||
TestCase {
|
||||
name: "language getter extra args",
|
||||
input: "language some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"language",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "language setter 2-letter code (ja)",
|
||||
input: "set-language ja",
|
||||
expected: Ok(ConfigSpeechToTextSettingRelatedControllerType::SetLanguage(
|
||||
Some("ja".to_owned()),
|
||||
)),
|
||||
},
|
||||
// OpenAI does not support 3-letter codes, so we won't be allowing it either
|
||||
TestCase {
|
||||
name: "language setter 3-letter code (jpn) fails",
|
||||
input: "set-language jpn",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::speech_to_text::language_code_invalid("jpn"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "language unsetter",
|
||||
input: "set-language",
|
||||
expected: Ok(ConfigSpeechToTextSettingRelatedControllerType::SetLanguage(
|
||||
None,
|
||||
)),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
212
src/controller/cfg/determination/tests.rs
Normal file
212
src/controller/cfg/determination/tests.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
#[test]
|
||||
fn determine_controller() {
|
||||
use super::super::controller_type;
|
||||
use crate::agent::{AgentPurpose, PublicIdentifier};
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: super::ControllerType,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "Top-level is help",
|
||||
input: "",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::Help),
|
||||
},
|
||||
TestCase {
|
||||
name: "unknown commands is help",
|
||||
input: "whatever",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::Help),
|
||||
},
|
||||
|
||||
TestCase {
|
||||
name: "Status",
|
||||
input: "status",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::Status),
|
||||
},
|
||||
|
||||
|
||||
TestCase {
|
||||
name: "per-room handler getter - catch-all",
|
||||
input: "room handler catch-all",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::GetHandler(AgentPurpose::CatchAll),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler getter - text-generation",
|
||||
input: "room handler text-generation",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::GetHandler(AgentPurpose::TextGeneration),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler getter - invalid purpose",
|
||||
input: "room handler invalid-purpose-here",
|
||||
expected: super::ControllerType::Error(
|
||||
crate::strings::agent::purpose_unrecognized("invalid-purpose-here").to_owned()
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler getter - invalid purpose with spaces",
|
||||
input: "room handler invalid purpose here",
|
||||
expected: super::ControllerType::Error(
|
||||
crate::strings::agent::purpose_unrecognized("invalid purpose here").to_owned()
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler setter - too few values",
|
||||
input: "room set-handler",
|
||||
expected: super::ControllerType::Error(
|
||||
crate::strings::cfg::configuration_invocation_incorrect_more_values_expected().to_owned()
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler setter - catch-all",
|
||||
input: "room set-handler catch-all static/agent-id",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::SetHandler(AgentPurpose::CatchAll, Some(
|
||||
PublicIdentifier::Static("agent-id".to_owned())
|
||||
)),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler setter - catch-all with bare agent id",
|
||||
input: "room set-handler catch-all agent-id",
|
||||
expected: super::ControllerType::Error(
|
||||
crate::strings::agent::invalid_id_generic().to_owned()
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler setter - catch-all unsetter",
|
||||
input: "room set-handler catch-all",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::SetHandler(AgentPurpose::CatchAll, None),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler setter - text-generation",
|
||||
input: "room set-handler text-generation room-local/agent-id",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::SetHandler(AgentPurpose::TextGeneration, Some(
|
||||
PublicIdentifier::DynamicRoomLocal("agent-id".to_owned())
|
||||
)),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room handler setter - too many values",
|
||||
input: "room set-handler text-generation agent-id more values here",
|
||||
expected: super::ControllerType::Error(
|
||||
crate::strings::agent::invalid_id_generic().to_owned()
|
||||
),
|
||||
},
|
||||
|
||||
// We have few global handler test cases. We've exercised the per-room handlers enough.
|
||||
// These share the same code path, so we don't need to test all the permutations again.
|
||||
TestCase {
|
||||
name: "global handler getter - catch-all",
|
||||
input: "global handler catch-all",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Global,
|
||||
controller_type::ConfigSettingRelatedControllerType::GetHandler(AgentPurpose::CatchAll),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "global handler setter - text-generation with global agent",
|
||||
input: "global set-handler text-generation global/agent-id",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Global,
|
||||
controller_type::ConfigSettingRelatedControllerType::SetHandler(AgentPurpose::TextGeneration, Some(
|
||||
PublicIdentifier::DynamicGlobal("agent-id".to_owned())
|
||||
)),
|
||||
)),
|
||||
},
|
||||
// This test case passes, even though the handler function will subsequently reject using room-local agents for global handlers.
|
||||
TestCase {
|
||||
name: "global handler setter - text-generation with room-local agent",
|
||||
input: "global set-handler text-generation room-local/agent-id",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Global,
|
||||
controller_type::ConfigSettingRelatedControllerType::SetHandler(AgentPurpose::TextGeneration, Some(
|
||||
PublicIdentifier::DynamicRoomLocal("agent-id".to_owned())
|
||||
)),
|
||||
)),
|
||||
},
|
||||
|
||||
// We'll only test one handler per sub-category to ensure proper routing is done here.
|
||||
// Extensive tests for each sub-category are done in their respective modules.
|
||||
|
||||
TestCase {
|
||||
name: "per-room text-generation/context-management-enabled getter",
|
||||
input: "room text-generation context-management-enabled",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::TextGeneration(
|
||||
controller_type::ConfigTextGenerationSettingRelatedControllerType::GetContextManagementEnabled,
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "global text-generation/context-management-enabled getter",
|
||||
input: "global text-generation context-management-enabled",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Global,
|
||||
controller_type::ConfigSettingRelatedControllerType::TextGeneration(
|
||||
controller_type::ConfigTextGenerationSettingRelatedControllerType::GetContextManagementEnabled,
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room text-to-speech/speed-override getter",
|
||||
input: "room text-to-speech speed-override",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::TextToSpeech(
|
||||
controller_type::ConfigTextToSpeechSettingRelatedControllerType::GetSpeedOverride,
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "global text-to-speech/speed-override getter",
|
||||
input: "global text-to-speech speed-override",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Global,
|
||||
controller_type::ConfigSettingRelatedControllerType::TextToSpeech(
|
||||
controller_type::ConfigTextToSpeechSettingRelatedControllerType::GetSpeedOverride,
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "room speech-to-text/flow-type getter",
|
||||
input: "room speech-to-text flow-type",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::SpeechToText(
|
||||
controller_type::ConfigSpeechToTextSettingRelatedControllerType::GetFlowType,
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "global speech-to-text/flow-type getter",
|
||||
input: "global speech-to-text flow-type",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Global,
|
||||
controller_type::ConfigSettingRelatedControllerType::SpeechToText(
|
||||
controller_type::ConfigSpeechToTextSettingRelatedControllerType::GetFlowType,
|
||||
),
|
||||
)),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine_controller(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
201
src/controller/cfg/determination/text_generation/mod.rs
Normal file
201
src/controller/cfg/determination/text_generation/mod.rs
Normal file
@@ -0,0 +1,201 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::{
|
||||
controller::ControllerType,
|
||||
entity::roomconfig::{TextGenerationAutoUsage, TextGenerationPrefixRequirementType},
|
||||
strings,
|
||||
};
|
||||
|
||||
use super::super::controller_type::ConfigTextGenerationSettingRelatedControllerType;
|
||||
|
||||
pub(super) fn determine(
|
||||
text: &str,
|
||||
) -> Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType> {
|
||||
if let Some(remaining_text) = text.strip_prefix("context-management-enabled") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"context-management-enabled",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::GetContextManagementEnabled);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-context-management-enabled") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
let value_opt = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let value_string_lowercase = value_string.to_lowercase();
|
||||
Some(match value_string_lowercase.as_str() {
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_unrecognized(&value_string).to_owned(),
|
||||
));
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
return Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetContextManagementEnabled(
|
||||
value_opt,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("prefix-requirement-type") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"prefix-requirement-type",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::GetPrefixRequirementType);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-prefix-requirement-type") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
let value_choice = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let value_choice =
|
||||
TextGenerationPrefixRequirementType::from_str(&value_string.to_lowercase());
|
||||
|
||||
if value_choice.is_none() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_unrecognized(&value_string).to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
value_choice
|
||||
};
|
||||
|
||||
return Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPrefixRequirementType(
|
||||
value_choice,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("auto-usage") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"auto-usage",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::GetAutoUsage);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-auto-usage") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
let value_choice = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let value_choice = TextGenerationAutoUsage::from_str(&value_string.to_lowercase());
|
||||
|
||||
if value_choice.is_none() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_unrecognized(&value_string).to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
value_choice
|
||||
};
|
||||
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::SetAutoUsage(value_choice));
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("prompt-override") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"prompt-override",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::GetPromptOverride);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-prompt-override") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
if value_string.is_empty() {
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::SetPromptOverride(None));
|
||||
}
|
||||
|
||||
return Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPromptOverride(Some(value_string)),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("temperature-override") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"temperature-override",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::GetTemperatureOverride);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-temperature-override") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
if value_string.is_empty() {
|
||||
return Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetTemperatureOverride(None),
|
||||
);
|
||||
}
|
||||
|
||||
let value_f32 = value_string.parse::<f32>();
|
||||
|
||||
let Ok(value_f32) = value_f32 else {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_not_f32(&value_string).to_owned(),
|
||||
));
|
||||
};
|
||||
|
||||
return Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetTemperatureOverride(Some(
|
||||
value_f32,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Err(ControllerType::Unknown)
|
||||
}
|
||||
332
src/controller/cfg/determination/text_generation/tests.rs
Normal file
332
src/controller/cfg/determination/text_generation/tests.rs
Normal file
@@ -0,0 +1,332 @@
|
||||
#[test]
|
||||
fn determine_controller_other() {
|
||||
use super::ConfigTextGenerationSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![TestCase {
|
||||
name: "Unknown",
|
||||
input: "whatever",
|
||||
expected: Err(ControllerType::Unknown),
|
||||
}];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_context_management() {
|
||||
use super::ConfigTextGenerationSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "context-management-enabled getter ok",
|
||||
input: "context-management-enabled",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetContextManagementEnabled,
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "context-management-enabled getter extra args",
|
||||
input: "context-management-enabled some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"context-management-enabled",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "context-management-enabled setter",
|
||||
input: "set-context-management-enabled true",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetContextManagementEnabled(
|
||||
Some(true),
|
||||
),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "context-management-enabled setter uppercase",
|
||||
input: "set-context-management-enabled TRUE",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetContextManagementEnabled(
|
||||
Some(true),
|
||||
),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "context-management-enabled setter non-bool",
|
||||
input: "set-context-management-enabled non-Bool-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_unrecognized("non-Bool-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "context-management-enabled unsetter",
|
||||
input: "set-context-management-enabled",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetContextManagementEnabled(None),
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_prefix_requirement_type() {
|
||||
use super::ConfigTextGenerationSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
use crate::entity::roomconfig::TextGenerationPrefixRequirementType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "prefix-requirement-type getter ok",
|
||||
input: "prefix-requirement-type",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetPrefixRequirementType,
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "prefix-requirement-type getter extra args",
|
||||
input: "prefix-requirement-type some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"prefix-requirement-type",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "prefix-requirement-type setter (command_prefix)",
|
||||
input: "set-prefix-requirement-type command_prefix",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPrefixRequirementType(Some(
|
||||
TextGenerationPrefixRequirementType::CommandPrefix,
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "prefix-requirement-type setter (no)",
|
||||
input: "set-prefix-requirement-type no",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPrefixRequirementType(Some(
|
||||
TextGenerationPrefixRequirementType::No,
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "prefix-requirement-type setter",
|
||||
input: "set-prefix-requirement-type unknown-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_unrecognized("unknown-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "prefix-requirement-type unsetter",
|
||||
input: "set-prefix-requirement-type",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPrefixRequirementType(None),
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_auto_usage() {
|
||||
use super::ConfigTextGenerationSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
use crate::entity::roomconfig::TextGenerationAutoUsage;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "auto-usage getter ok",
|
||||
input: "auto-usage",
|
||||
expected: Ok(ConfigTextGenerationSettingRelatedControllerType::GetAutoUsage),
|
||||
},
|
||||
TestCase {
|
||||
name: "auto-usage getter extra args",
|
||||
input: "auto-usage some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"auto-usage",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "auto-usage setter",
|
||||
input: "set-auto-usage only_for_voice",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetAutoUsage(Some(
|
||||
TextGenerationAutoUsage::OnlyForVoice,
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "auto-usage setter",
|
||||
input: "set-auto-usage unknown-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_unrecognized("unknown-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "auto-usage unsetter",
|
||||
input: "set-auto-usage",
|
||||
expected: Ok(ConfigTextGenerationSettingRelatedControllerType::SetAutoUsage(None)),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_prompt_override() {
|
||||
use super::ConfigTextGenerationSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "prompt-override getter ok",
|
||||
input: "prompt-override",
|
||||
expected: Ok(ConfigTextGenerationSettingRelatedControllerType::GetPromptOverride),
|
||||
},
|
||||
TestCase {
|
||||
name: "prompt-override getter extra args",
|
||||
input: "prompt-override some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"prompt-override",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "prompt-override setter with multiple words",
|
||||
input: "set-prompt-override Hello! You are a bot",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPromptOverride(Some(
|
||||
"Hello! You are a bot".to_owned(),
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "prompt-override setter with multi-line",
|
||||
input: "set-prompt-override Hello!\n\nYou are a bot",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPromptOverride(Some(
|
||||
"Hello!\n\nYou are a bot".to_owned(),
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "prompt-override unsetter",
|
||||
input: "set-prompt-override",
|
||||
expected: Ok(ConfigTextGenerationSettingRelatedControllerType::SetPromptOverride(None)),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_temperature_override() {
|
||||
use super::ConfigTextGenerationSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "temperature-override getter ok",
|
||||
input: "temperature-override",
|
||||
expected: Ok(ConfigTextGenerationSettingRelatedControllerType::GetTemperatureOverride),
|
||||
},
|
||||
TestCase {
|
||||
name: "temperature-override getter extra args",
|
||||
input: "temperature-override some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"temperature-override",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "temperature-override setter",
|
||||
input: "set-temperature-override 0.5",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetTemperatureOverride(Some(0.5)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "temperature-override setter",
|
||||
input: "set-temperature-override unknown-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_not_f32("unknown-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "temperature-override unsetter",
|
||||
input: "set-temperature-override",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetTemperatureOverride(None),
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
158
src/controller/cfg/determination/text_to_speech/mod.rs
Normal file
158
src/controller/cfg/determination/text_to_speech/mod.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::{
|
||||
controller::ControllerType,
|
||||
entity::roomconfig::{TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType},
|
||||
strings,
|
||||
};
|
||||
|
||||
use super::super::controller_type::ConfigTextToSpeechSettingRelatedControllerType;
|
||||
|
||||
pub(super) fn determine(
|
||||
text: &str,
|
||||
) -> Result<ConfigTextToSpeechSettingRelatedControllerType, ControllerType> {
|
||||
if let Some(remaining_text) = text.strip_prefix("bot-msgs-flow-type") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"bot-msgs-flow-type",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextToSpeechSettingRelatedControllerType::GetBotMessagesFlowType);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-bot-msgs-flow-type") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
let value_choice = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let value_choice =
|
||||
TextToSpeechBotMessagesFlowType::from_str(&value_string.to_lowercase());
|
||||
|
||||
if value_choice.is_none() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_unrecognized(&value_string).to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
value_choice
|
||||
};
|
||||
|
||||
return Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetBotMessagesFlowType(value_choice),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("user-msgs-flow-type") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"user-msgs-flow-type",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextToSpeechSettingRelatedControllerType::GetUserMessagesFlowType);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-user-msgs-flow-type") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
let value_choice = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let value_choice =
|
||||
TextToSpeechUserMessagesFlowType::from_str(&value_string.to_lowercase());
|
||||
|
||||
if value_choice.is_none() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_unrecognized(&value_string).to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
value_choice
|
||||
};
|
||||
|
||||
return Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetUserMessagesFlowType(value_choice),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("speed-override") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"speed-override",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextToSpeechSettingRelatedControllerType::GetSpeedOverride);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-speed-override") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
if value_string.is_empty() {
|
||||
return Ok(ConfigTextToSpeechSettingRelatedControllerType::SetSpeedOverride(None));
|
||||
}
|
||||
|
||||
let value_f32 = value_string.parse::<f32>();
|
||||
|
||||
let Ok(value_f32) = value_f32 else {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_value_not_f32(&value_string).to_owned(),
|
||||
));
|
||||
};
|
||||
|
||||
return Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetSpeedOverride(Some(value_f32)),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("voice-override") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"voice-override",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextToSpeechSettingRelatedControllerType::GetVoiceOverride);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-voice-override") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
|
||||
if value_string.is_empty() {
|
||||
return Ok(ConfigTextToSpeechSettingRelatedControllerType::SetVoiceOverride(None));
|
||||
}
|
||||
|
||||
return Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetVoiceOverride(Some(value_string)),
|
||||
);
|
||||
}
|
||||
|
||||
Err(ControllerType::Unknown)
|
||||
}
|
||||
252
src/controller/cfg/determination/text_to_speech/tests.rs
Normal file
252
src/controller/cfg/determination/text_to_speech/tests.rs
Normal file
@@ -0,0 +1,252 @@
|
||||
#[test]
|
||||
fn determine_controller_other() {
|
||||
use super::ConfigTextToSpeechSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextToSpeechSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![TestCase {
|
||||
name: "Unknown",
|
||||
input: "whatever",
|
||||
expected: Err(ControllerType::Unknown),
|
||||
}];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_bot_msgs_flow_type() {
|
||||
use super::ConfigTextToSpeechSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
use crate::entity::roomconfig::TextToSpeechBotMessagesFlowType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextToSpeechSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "bot-msgs-flow-type getter ok",
|
||||
input: "bot-msgs-flow-type",
|
||||
expected: Ok(ConfigTextToSpeechSettingRelatedControllerType::GetBotMessagesFlowType),
|
||||
},
|
||||
TestCase {
|
||||
name: "bot-msgs-flow-type getter extra args",
|
||||
input: "bot-msgs-flow-type some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"bot-msgs-flow-type",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "bot-msgs-flow-type setter",
|
||||
input: "set-bot-msgs-flow-type only_for_voice",
|
||||
expected: Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetBotMessagesFlowType(Some(
|
||||
TextToSpeechBotMessagesFlowType::OnlyForVoice,
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "bot-msgs-flow-type setter",
|
||||
input: "set-bot-msgs-flow-type unknown-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_unrecognized("unknown-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "bot-msgs-flow-type unsetter",
|
||||
input: "set-bot-msgs-flow-type",
|
||||
expected: Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetBotMessagesFlowType(None),
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_user_msgs_flow_type() {
|
||||
use super::ConfigTextToSpeechSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
use crate::entity::roomconfig::TextToSpeechUserMessagesFlowType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextToSpeechSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "user-msgs-flow-type getter ok",
|
||||
input: "user-msgs-flow-type",
|
||||
expected: Ok(ConfigTextToSpeechSettingRelatedControllerType::GetUserMessagesFlowType),
|
||||
},
|
||||
TestCase {
|
||||
name: "user-msgs-flow-type getter extra args",
|
||||
input: "user-msgs-flow-type some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"user-msgs-flow-type",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "user-msgs-flow-type setter",
|
||||
input: "set-user-msgs-flow-type on_demand",
|
||||
expected: Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetUserMessagesFlowType(Some(
|
||||
TextToSpeechUserMessagesFlowType::OnDemand,
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "user-msgs-flow-type setter",
|
||||
input: "set-user-msgs-flow-type unknown-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_unrecognized("unknown-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "user-msgs-flow-type unsetter",
|
||||
input: "set-user-msgs-flow-type",
|
||||
expected: Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetUserMessagesFlowType(None),
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_speed_override() {
|
||||
use super::ConfigTextToSpeechSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextToSpeechSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "speed-override getter ok",
|
||||
input: "speed-override",
|
||||
expected: Ok(ConfigTextToSpeechSettingRelatedControllerType::GetSpeedOverride),
|
||||
},
|
||||
TestCase {
|
||||
name: "speed-override getter extra args",
|
||||
input: "speed-override some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"speed-override",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "speed-override setter",
|
||||
input: "set-speed-override 0.5",
|
||||
expected: Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetSpeedOverride(Some(0.5)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "speed-override setter",
|
||||
input: "set-speed-override unknown-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_not_f32("unknown-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "speed-override unsetter",
|
||||
input: "set-speed-override",
|
||||
expected: Ok(ConfigTextToSpeechSettingRelatedControllerType::SetSpeedOverride(None)),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_voice_override() {
|
||||
use super::ConfigTextToSpeechSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextToSpeechSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "voice-override getter ok",
|
||||
input: "voice-override",
|
||||
expected: Ok(ConfigTextToSpeechSettingRelatedControllerType::GetVoiceOverride),
|
||||
},
|
||||
TestCase {
|
||||
name: "voice-override getter extra args",
|
||||
input: "voice-override some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"voice-override",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "voice-override setter",
|
||||
input: "set-voice-override alex",
|
||||
expected: Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetVoiceOverride(Some(
|
||||
"alex".to_owned(),
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "voice-override setter preserves case",
|
||||
input: "set-voice-override Alex",
|
||||
expected: Ok(
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetVoiceOverride(Some(
|
||||
"Alex".to_owned(),
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "voice-override unsetter",
|
||||
input: "set-voice-override",
|
||||
expected: Ok(ConfigTextToSpeechSettingRelatedControllerType::SetVoiceOverride(None)),
|
||||
},
|
||||
];
|
||||
|
||||
for test_case in test_cases {
|
||||
let result = super::determine(test_case.input);
|
||||
assert_eq!(result, test_case.expected, "Test case: {}", test_case.name);
|
||||
}
|
||||
}
|
||||
124
src/controller/cfg/dispatching/mod.rs
Normal file
124
src/controller/cfg/dispatching/mod.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
use crate::strings;
|
||||
use crate::{entity::MessageContext, Bot};
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use super::controller_type::{
|
||||
ConfigControllerType, ConfigSettingRelatedControllerType, SettingsStorageSource,
|
||||
};
|
||||
|
||||
mod speech_to_text;
|
||||
mod text_generation;
|
||||
mod text_to_speech;
|
||||
|
||||
pub async fn dispatch_controller(
|
||||
handler: &ConfigControllerType,
|
||||
message_context: &MessageContext,
|
||||
bot: &Bot,
|
||||
) -> anyhow::Result<()> {
|
||||
// Anyone can access Help and Status.
|
||||
// Settings-related access checks are done in dispatch_config_related_handler().
|
||||
|
||||
match handler {
|
||||
ConfigControllerType::Help => super::help::handle(bot, message_context).await,
|
||||
ConfigControllerType::Status => super::status::handle(bot, message_context).await,
|
||||
ConfigControllerType::SettingsRelated(config_type, config_related_handler) => {
|
||||
dispatch_config_related_handler(
|
||||
config_type,
|
||||
config_related_handler,
|
||||
message_context,
|
||||
bot,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn dispatch_config_related_handler(
|
||||
config_type: &SettingsStorageSource,
|
||||
handler: &ConfigSettingRelatedControllerType,
|
||||
message_context: &MessageContext,
|
||||
bot: &Bot,
|
||||
) -> anyhow::Result<()> {
|
||||
if let SettingsStorageSource::Global = config_type {
|
||||
if !message_context.sender_can_manage_global_config()? {
|
||||
bot.messaging()
|
||||
.send_error_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::global_config::no_permissions_to_administrate(),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let room_settings = match config_type {
|
||||
SettingsStorageSource::Room => &message_context.room_config().settings,
|
||||
SettingsStorageSource::Global => &message_context.global_config().fallback_room_settings,
|
||||
};
|
||||
|
||||
match handler {
|
||||
ConfigSettingRelatedControllerType::GetHandler(purpose) => match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
super::room_config::handler::handle_get(bot, message_context, *purpose).await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
super::global_config::handler::handle_get(bot, message_context, *purpose).await
|
||||
}
|
||||
},
|
||||
ConfigSettingRelatedControllerType::SetHandler(purpose, agent_identifier) => {
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
super::room_config::handler::handle_set(
|
||||
bot,
|
||||
bot.room_config_manager(),
|
||||
message_context,
|
||||
*purpose,
|
||||
agent_identifier,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
super::global_config::handler::handle_set(
|
||||
bot,
|
||||
bot.global_config_manager(),
|
||||
message_context,
|
||||
*purpose,
|
||||
agent_identifier,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigSettingRelatedControllerType::TextGeneration(controller_type) => {
|
||||
text_generation::dispatch(
|
||||
controller_type,
|
||||
message_context,
|
||||
bot,
|
||||
room_settings,
|
||||
config_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
ConfigSettingRelatedControllerType::SpeechToText(controller_type) => {
|
||||
speech_to_text::dispatch(
|
||||
controller_type,
|
||||
message_context,
|
||||
bot,
|
||||
room_settings,
|
||||
config_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
ConfigSettingRelatedControllerType::TextToSpeech(controller_type) => {
|
||||
text_to_speech::dispatch(
|
||||
controller_type,
|
||||
message_context,
|
||||
bot,
|
||||
room_settings,
|
||||
config_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
78
src/controller/cfg/dispatching/speech_to_text.rs
Normal file
78
src/controller/cfg/dispatching/speech_to_text.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use crate::entity::roomconfig::{RoomSettings, SpeechToTextFlowType};
|
||||
use crate::{entity::MessageContext, Bot};
|
||||
|
||||
use super::super::controller_type::{
|
||||
ConfigSpeechToTextSettingRelatedControllerType, SettingsStorageSource,
|
||||
};
|
||||
|
||||
use super::super::common::generic_setting::handle_get as setting_get;
|
||||
|
||||
use super::super::global_config::generic_setting::handle_set as global_setting_set;
|
||||
|
||||
use super::super::room_config::generic_setting::handle_set as room_setting_set;
|
||||
|
||||
pub(super) async fn dispatch(
|
||||
handler: &ConfigSpeechToTextSettingRelatedControllerType,
|
||||
message_context: &MessageContext,
|
||||
bot: &Bot,
|
||||
room_settings: &RoomSettings,
|
||||
config_type: &SettingsStorageSource,
|
||||
) -> anyhow::Result<()> {
|
||||
match handler {
|
||||
ConfigSpeechToTextSettingRelatedControllerType::GetFlowType => {
|
||||
let value = &room_settings.speech_to_text.flow_type;
|
||||
setting_get::<SpeechToTextFlowType>(bot, message_context, value).await
|
||||
}
|
||||
ConfigSpeechToTextSettingRelatedControllerType::SetFlowType(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.speech_to_text.flow_type = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<SpeechToTextFlowType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<SpeechToTextFlowType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigSpeechToTextSettingRelatedControllerType::GetLanguage => {
|
||||
let value = &room_settings.speech_to_text.language;
|
||||
setting_get::<String>(bot, message_context, value).await
|
||||
}
|
||||
ConfigSpeechToTextSettingRelatedControllerType::SetLanguage(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let value_setter = value.clone();
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.speech_to_text.language = value_setter;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<String>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<String>(bot, message_context, &value, setter_callback)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
155
src/controller/cfg/dispatching/text_generation.rs
Normal file
155
src/controller/cfg/dispatching/text_generation.rs
Normal file
@@ -0,0 +1,155 @@
|
||||
use crate::entity::roomconfig::{
|
||||
RoomSettings, TextGenerationAutoUsage, TextGenerationPrefixRequirementType,
|
||||
};
|
||||
use crate::{entity::MessageContext, Bot};
|
||||
|
||||
use super::super::controller_type::{
|
||||
ConfigTextGenerationSettingRelatedControllerType, SettingsStorageSource,
|
||||
};
|
||||
|
||||
use super::super::common::generic_setting::handle_get as setting_get;
|
||||
|
||||
use super::super::global_config::generic_setting::handle_set as global_setting_set;
|
||||
|
||||
use super::super::room_config::generic_setting::handle_set as room_setting_set;
|
||||
|
||||
pub(super) async fn dispatch(
|
||||
handler: &ConfigTextGenerationSettingRelatedControllerType,
|
||||
message_context: &MessageContext,
|
||||
bot: &Bot,
|
||||
room_settings: &RoomSettings,
|
||||
config_type: &SettingsStorageSource,
|
||||
) -> anyhow::Result<()> {
|
||||
match handler {
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetContextManagementEnabled => {
|
||||
let value = &room_settings.text_generation.context_management_enabled;
|
||||
setting_get::<bool>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetContextManagementEnabled(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_generation.context_management_enabled = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<bool>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<bool>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetPrefixRequirementType => {
|
||||
let value = &room_settings.text_generation.prefix_requirement_type;
|
||||
setting_get::<TextGenerationPrefixRequirementType>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPrefixRequirementType(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_generation.prefix_requirement_type = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<TextGenerationPrefixRequirementType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<TextGenerationPrefixRequirementType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetAutoUsage => {
|
||||
let value = &room_settings.text_generation.auto_usage;
|
||||
setting_get::<TextGenerationAutoUsage>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetAutoUsage(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_generation.auto_usage = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<TextGenerationAutoUsage>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<TextGenerationAutoUsage>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetPromptOverride => {
|
||||
let value = &room_settings.text_generation.prompt_override;
|
||||
setting_get::<String>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetPromptOverride(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let value_setter = value.clone();
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_generation.prompt_override = value_setter;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<String>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<String>(bot, message_context, &value, setter_callback)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetTemperatureOverride => {
|
||||
let value = &room_settings.text_generation.temperature_override;
|
||||
setting_get::<f32>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetTemperatureOverride(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_generation.temperature_override = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<f32>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<f32>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
134
src/controller/cfg/dispatching/text_to_speech.rs
Normal file
134
src/controller/cfg/dispatching/text_to_speech.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
use crate::entity::roomconfig::{
|
||||
RoomSettings, TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType,
|
||||
};
|
||||
use crate::{entity::MessageContext, Bot};
|
||||
|
||||
use super::super::controller_type::{
|
||||
ConfigTextToSpeechSettingRelatedControllerType, SettingsStorageSource,
|
||||
};
|
||||
|
||||
use super::super::common::generic_setting::handle_get as setting_get;
|
||||
|
||||
use super::super::global_config::generic_setting::handle_set as global_setting_set;
|
||||
|
||||
use super::super::room_config::generic_setting::handle_set as room_setting_set;
|
||||
|
||||
pub(super) async fn dispatch(
|
||||
handler: &ConfigTextToSpeechSettingRelatedControllerType,
|
||||
message_context: &MessageContext,
|
||||
bot: &Bot,
|
||||
room_settings: &RoomSettings,
|
||||
config_type: &SettingsStorageSource,
|
||||
) -> anyhow::Result<()> {
|
||||
match handler {
|
||||
ConfigTextToSpeechSettingRelatedControllerType::GetBotMessagesFlowType => {
|
||||
let value = &room_settings.text_to_speech.bot_msgs_flow_type;
|
||||
setting_get::<TextToSpeechBotMessagesFlowType>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetBotMessagesFlowType(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_to_speech.bot_msgs_flow_type = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<TextToSpeechBotMessagesFlowType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<TextToSpeechBotMessagesFlowType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextToSpeechSettingRelatedControllerType::GetUserMessagesFlowType => {
|
||||
let value = &room_settings.text_to_speech.user_msgs_flow_type;
|
||||
setting_get::<TextToSpeechUserMessagesFlowType>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetUserMessagesFlowType(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_to_speech.user_msgs_flow_type = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<TextToSpeechUserMessagesFlowType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<TextToSpeechUserMessagesFlowType>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextToSpeechSettingRelatedControllerType::GetSpeedOverride => {
|
||||
let value = &room_settings.text_to_speech.speed_override;
|
||||
setting_get::<f32>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetSpeedOverride(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_to_speech.speed_override = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<f32>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<f32>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextToSpeechSettingRelatedControllerType::GetVoiceOverride => {
|
||||
let value = &room_settings.text_to_speech.voice_override;
|
||||
setting_get::<String>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextToSpeechSettingRelatedControllerType::SetVoiceOverride(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let value_setter = value.clone();
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_to_speech.voice_override = value_setter;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<String>(bot, message_context, &value, setter_callback).await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<String>(bot, message_context, &value, setter_callback)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/controller/cfg/global_config/generic_setting.rs
Normal file
38
src/controller/cfg/global_config/generic_setting.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use crate::entity::{roomconfig::RoomSettings, MessageContext};
|
||||
use crate::{strings, Bot};
|
||||
|
||||
pub async fn handle_set<T>(
|
||||
bot: &Bot,
|
||||
message_context: &MessageContext,
|
||||
value: &Option<T>,
|
||||
setter_callback: Box<dyn FnOnce(&mut RoomSettings) + Send>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
let mut global_config = message_context.global_config().clone();
|
||||
setter_callback(&mut global_config.fallback_room_settings);
|
||||
|
||||
bot.global_config_manager()
|
||||
.lock()
|
||||
.await
|
||||
.persist(&global_config)
|
||||
.await?;
|
||||
|
||||
let message = match value {
|
||||
Some(value) => strings::global_config::value_was_set_to(value),
|
||||
None => strings::global_config::value_was_unset(),
|
||||
};
|
||||
|
||||
bot.messaging()
|
||||
.send_success_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&message,
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
162
src/controller/cfg/global_config/handler.rs
Normal file
162
src/controller/cfg/global_config/handler.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use crate::{
|
||||
agent::{AgentPurpose, PublicIdentifier},
|
||||
entity::{globalconfig::GlobalConfigurationManager, MessageContext},
|
||||
strings, Bot,
|
||||
};
|
||||
|
||||
pub async fn handle_get(
|
||||
bot: &Bot,
|
||||
message_context: &MessageContext,
|
||||
purpose: AgentPurpose,
|
||||
) -> anyhow::Result<()> {
|
||||
let agent_id = message_context
|
||||
.global_config()
|
||||
.fallback_room_settings
|
||||
.handler
|
||||
.get_by_purpose(purpose);
|
||||
|
||||
let Some(agent_id) = agent_id else {
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::global_config::global_config_lacks_specific_agent_for_purpose(purpose),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let agent_identifier = match PublicIdentifier::from_str(agent_id.as_str()) {
|
||||
Some(agent_identifier) => agent_identifier,
|
||||
None => {
|
||||
bot.messaging()
|
||||
.send_error_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&strings::agent::invalid_id_generic(),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let agent_exists = bot
|
||||
.agent_manager()
|
||||
.available_room_agents_by_room_config_context(message_context.room_config_context())
|
||||
.iter()
|
||||
.any(|agent| *agent.identifier() == agent_identifier);
|
||||
|
||||
if agent_exists {
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::global_config::configured_to_use_agent_for_purpose(
|
||||
&agent_identifier,
|
||||
purpose,
|
||||
),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
} else {
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::global_config::configures_agent_for_purpose_but_does_not_exist(
|
||||
&agent_identifier,
|
||||
purpose,
|
||||
),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn handle_set(
|
||||
bot: &Bot,
|
||||
global_config_manager: &tokio::sync::Mutex<GlobalConfigurationManager>,
|
||||
message_context: &MessageContext,
|
||||
purpose: AgentPurpose,
|
||||
agent_identifier: &Option<PublicIdentifier>,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(agent_identifier) = agent_identifier {
|
||||
let is_allowed = match &agent_identifier {
|
||||
PublicIdentifier::Static(_) => true,
|
||||
PublicIdentifier::DynamicGlobal(_) => true,
|
||||
PublicIdentifier::DynamicRoomLocal(_) => false,
|
||||
};
|
||||
|
||||
if !is_allowed {
|
||||
bot.messaging()
|
||||
.send_error_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&strings::global_config::not_allowed_to_use_agent_in_global_config(
|
||||
agent_identifier,
|
||||
),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let agent_exists = bot
|
||||
.agent_manager()
|
||||
.available_room_agents_by_room_config_context(message_context.room_config_context())
|
||||
.iter()
|
||||
.any(|agent| agent.identifier() == agent_identifier);
|
||||
|
||||
if !agent_exists {
|
||||
bot.messaging()
|
||||
.send_error_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&strings::agent::agent_with_given_identifier_missing(agent_identifier),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let agent_id = agent_identifier
|
||||
.as_ref()
|
||||
.map(|agent_identifier| agent_identifier.as_string());
|
||||
|
||||
let mut global_config = global_config_manager.lock().await.get_or_create().await?;
|
||||
|
||||
global_config
|
||||
.fallback_room_settings
|
||||
.handler
|
||||
.set_by_purpose(purpose, agent_id);
|
||||
|
||||
global_config_manager
|
||||
.lock()
|
||||
.await
|
||||
.persist(&global_config)
|
||||
.await?;
|
||||
|
||||
let message = match agent_identifier {
|
||||
Some(agent_identifier) => {
|
||||
strings::global_config::reconfigured_to_use_agent_for_purpose(agent_identifier, purpose)
|
||||
}
|
||||
None => strings::global_config::reconfigured_to_not_specify_agent_for_purpose(purpose),
|
||||
};
|
||||
|
||||
bot.messaging()
|
||||
.send_success_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&message,
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
2
src/controller/cfg/global_config/mod.rs
Normal file
2
src/controller/cfg/global_config/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub(super) mod generic_setting;
|
||||
pub(super) mod handler;
|
||||
547
src/controller/cfg/help.rs
Normal file
547
src/controller/cfg/help.rs
Normal file
@@ -0,0 +1,547 @@
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use crate::{
|
||||
entity::{
|
||||
roomconfig::{
|
||||
SpeechToTextFlowType, TextGenerationAutoUsage, TextGenerationPrefixRequirementType,
|
||||
TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType,
|
||||
},
|
||||
MessageContext,
|
||||
},
|
||||
strings, Bot,
|
||||
};
|
||||
|
||||
pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyhow::Result<()> {
|
||||
let mut message = String::new();
|
||||
message.push_str(&build_section_intro());
|
||||
message.push_str("\n\n");
|
||||
message.push_str("\n---\n");
|
||||
message.push_str(&build_section_status(bot.command_prefix()));
|
||||
message.push_str("\n\n");
|
||||
message.push_str("\n---\n");
|
||||
message.push_str(&build_section_handlers(bot.command_prefix()));
|
||||
|
||||
message.push_str("\n\n");
|
||||
message.push_str("\n---\n");
|
||||
message.push_str(&build_section_text_generation(
|
||||
bot.command_prefix(),
|
||||
bot.user_id().localpart(),
|
||||
));
|
||||
|
||||
message.push_str("\n\n");
|
||||
message.push_str("\n---\n");
|
||||
message.push_str(&build_section_text_to_speech(bot.command_prefix()));
|
||||
|
||||
message.push_str("\n\n");
|
||||
message.push_str("\n---\n");
|
||||
message.push_str(&build_section_speech_to_text(bot.command_prefix()));
|
||||
|
||||
message.push_str("\n\n");
|
||||
message.push_str("\n---\n");
|
||||
message.push_str(&build_section_image_generation());
|
||||
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
message,
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_section_intro() -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(&format!("## {}", strings::help::cfg::heading()));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::intro_long());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn build_section_status(command_prefix: &str) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(&format!("### {}", strings::help::cfg::status_heading()));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::status_intro(command_prefix));
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn build_section_handlers(command_prefix: &str) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(&format!("### {}", strings::help::cfg::handlers_heading()));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::handlers_intro_common());
|
||||
message.push('\n');
|
||||
message.push_str(&strings::help::cfg::handlers_intro_purposes());
|
||||
message.push_str("\n\n");
|
||||
|
||||
message.push_str(strings::help::available_commands_intro());
|
||||
message.push('\n');
|
||||
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
strings::help::cfg::handlers_show(command_prefix)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
strings::help::cfg::handlers_set(command_prefix)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
strings::help::cfg::handlers_unset(command_prefix)
|
||||
));
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn build_section_text_generation(command_prefix: &str, bot_username: &str) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(&format!(
|
||||
"### {}",
|
||||
strings::help::cfg::text_generation_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_generation_common());
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Prefix requirement type
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_generation_prefix_requirement_type_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_generation_prefix_requirement_type_intro());
|
||||
message.push('\n');
|
||||
message.push_str(
|
||||
&strings::help::cfg::the_following_configuration_values_are_recognized(
|
||||
TextGenerationPrefixRequirementType::choices(),
|
||||
),
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
message
|
||||
.push_str(&strings::help::cfg::text_generation_prefix_requirement_type_outro(bot_username));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(
|
||||
command_prefix,
|
||||
"text-generation prefix-requirement-type"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-generation set-prefix-requirement-type VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-generation set-prefix-requirement-type"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Auto Usage
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_generation_auto_usage_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_generation_auto_usage_intro());
|
||||
message.push('\n');
|
||||
message.push_str(
|
||||
&strings::help::cfg::the_following_configuration_values_are_recognized(
|
||||
TextGenerationAutoUsage::choices(),
|
||||
),
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(command_prefix, "text-generation auto-usage")
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-generation set-auto-usage VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-generation set-auto-usage"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Context Management
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_generation_context_management_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_generation_context_management_intro());
|
||||
message.push('\n');
|
||||
message.push_str(
|
||||
&strings::help::cfg::the_following_configuration_values_are_recognized(vec![true, false]),
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(
|
||||
command_prefix,
|
||||
"text-generation context-management-enabled"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-generation set-context-management-enabled VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-generation set-context-management-enabled"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Prompt override
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_generation_prompt_override_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_generation_prompt_override_intro());
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(
|
||||
command_prefix,
|
||||
"text-generation prompt-override"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-generation set-prompt-override VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-generation set-prompt-override"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Speed override
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_generation_temperature_override_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_generation_temperature_override_intro());
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(
|
||||
command_prefix,
|
||||
"text-generation temperature-override"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-generation set-temperature-override VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-generation set-temperature-override"
|
||||
)
|
||||
));
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn build_section_speech_to_text(command_prefix: &str) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(&format!(
|
||||
"### {}",
|
||||
strings::help::cfg::speech_to_text_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::speech_to_text_common());
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Flow Type
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::speech_to_text_flow_type_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(strings::help::cfg::speech_to_text_flow_type_intro());
|
||||
message.push('\n');
|
||||
message.push_str(
|
||||
&strings::help::cfg::the_following_configuration_values_are_recognized(
|
||||
SpeechToTextFlowType::choices(),
|
||||
),
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(command_prefix, "speech-to-text flow-type")
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"speech-to-text set-flow-type VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(command_prefix, "speech-to-text set-flow-type")
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Language
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::speech_to_text_language_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(strings::help::cfg::speech_to_text_language_intro());
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(command_prefix, "speech-to-text language")
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"speech-to-text set-language VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(command_prefix, "speech-to-text set-language")
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn build_section_text_to_speech(command_prefix: &str) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(&format!(
|
||||
"### {}",
|
||||
strings::help::cfg::text_to_speech_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(strings::help::cfg::text_to_speech_common());
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Bot Messages Flow Type
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_to_speech_bot_msgs_flow_type_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_to_speech_bot_msgs_flow_type_intro());
|
||||
message.push('\n');
|
||||
message.push_str(
|
||||
&strings::help::cfg::the_following_configuration_values_are_recognized(
|
||||
TextToSpeechBotMessagesFlowType::choices(),
|
||||
),
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(
|
||||
command_prefix,
|
||||
"text-to-speech bot-msgs-flow-type"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-to-speech set-bot-msgs-flow-type VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-to-speech set-bot-msgs-flow-type"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// User Messages Flow Type
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_to_speech_user_msgs_flow_type_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_to_speech_user_msgs_flow_type_intro());
|
||||
message.push('\n');
|
||||
message.push_str(
|
||||
&strings::help::cfg::the_following_configuration_values_are_recognized(
|
||||
TextToSpeechUserMessagesFlowType::choices(),
|
||||
),
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(
|
||||
command_prefix,
|
||||
"text-to-speech user-msgs-flow-type"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-to-speech set-user-msgs-flow-type VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-to-speech set-user-msgs-flow-type"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Speed override
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_to_speech_speed_override_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_to_speech_speed_override_intro());
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(command_prefix, "text-to-speech speed-override")
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-to-speech set-speed-override VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-to-speech set-speed-override"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Voice override
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_to_speech_voice_override_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_to_speech_voice_override_intro());
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(command_prefix, "text-to-speech voice-override")
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-to-speech set-voice-override VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-to-speech set-voice-override"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn build_section_image_generation() -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(&format!(
|
||||
"### {}",
|
||||
strings::help::cfg::image_generation_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(strings::help::cfg::image_generation_common());
|
||||
|
||||
message
|
||||
}
|
||||
12
src/controller/cfg/mod.rs
Normal file
12
src/controller/cfg/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
mod common;
|
||||
mod controller_type;
|
||||
mod determination;
|
||||
mod dispatching;
|
||||
mod global_config;
|
||||
mod help;
|
||||
mod room_config;
|
||||
mod status;
|
||||
|
||||
pub use controller_type::ConfigControllerType;
|
||||
pub use determination::determine_controller;
|
||||
pub use dispatching::dispatch_controller;
|
||||
38
src/controller/cfg/room_config/generic_setting.rs
Normal file
38
src/controller/cfg/room_config/generic_setting.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use crate::entity::{roomconfig::RoomSettings, MessageContext};
|
||||
use crate::{strings, Bot};
|
||||
|
||||
pub async fn handle_set<T>(
|
||||
bot: &Bot,
|
||||
message_context: &MessageContext,
|
||||
value: &Option<T>,
|
||||
setter_callback: Box<dyn FnOnce(&mut RoomSettings) + Send>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
let mut room_config = message_context.room_config().clone();
|
||||
setter_callback(&mut room_config.settings);
|
||||
|
||||
bot.room_config_manager()
|
||||
.lock()
|
||||
.await
|
||||
.persist(message_context.room(), &room_config)
|
||||
.await?;
|
||||
|
||||
let message = match value {
|
||||
Some(value) => strings::room_config::value_was_set_to(value),
|
||||
None => strings::room_config::value_was_unset(),
|
||||
};
|
||||
|
||||
bot.messaging()
|
||||
.send_success_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&message,
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
141
src/controller/cfg/room_config/handler.rs
Normal file
141
src/controller/cfg/room_config/handler.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use crate::{
|
||||
agent::{AgentPurpose, PublicIdentifier},
|
||||
entity::MessageContext,
|
||||
strings, Bot,
|
||||
};
|
||||
|
||||
use crate::entity::roomconfig::RoomConfigurationManager;
|
||||
|
||||
pub async fn handle_get(
|
||||
bot: &Bot,
|
||||
message_context: &MessageContext,
|
||||
purpose: AgentPurpose,
|
||||
) -> anyhow::Result<()> {
|
||||
let agent_id = message_context
|
||||
.room_config()
|
||||
.settings
|
||||
.handler
|
||||
.get_by_purpose(purpose);
|
||||
|
||||
let Some(agent_id) = agent_id else {
|
||||
bot.messaging()
|
||||
.send_error_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&strings::room_config::room_not_configured_with_specific_agent_for_purpose(purpose),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let Some(agent_identifier) = PublicIdentifier::from_str(agent_id.as_str()) else {
|
||||
bot.messaging()
|
||||
.send_error_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&strings::agent::invalid_id_generic(),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let agent_exists = bot
|
||||
.agent_manager()
|
||||
.available_room_agents_by_room_config_context(message_context.room_config_context())
|
||||
.iter()
|
||||
.any(|agent| *agent.identifier() == agent_identifier);
|
||||
|
||||
if agent_exists {
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::room_config::configured_to_use_agent_for_purpose(
|
||||
&agent_identifier,
|
||||
purpose,
|
||||
),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
} else {
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
strings::room_config::configures_agent_for_purpose_but_does_not_exist(
|
||||
&agent_identifier,
|
||||
purpose,
|
||||
),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn handle_set(
|
||||
bot: &Bot,
|
||||
room_config_manager: &tokio::sync::Mutex<RoomConfigurationManager>,
|
||||
message_context: &MessageContext,
|
||||
purpose: AgentPurpose,
|
||||
agent_identifier: &Option<PublicIdentifier>,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(agent_identifier) = agent_identifier {
|
||||
let agent_exists = bot
|
||||
.agent_manager()
|
||||
.available_room_agents_by_room_config_context(message_context.room_config_context())
|
||||
.iter()
|
||||
.any(|agent| agent.identifier() == agent_identifier);
|
||||
|
||||
if !agent_exists {
|
||||
bot.messaging()
|
||||
.send_error_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&strings::agent::agent_with_given_identifier_missing(agent_identifier),
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_room_config = message_context.room_config().clone();
|
||||
|
||||
let agent_id = agent_identifier
|
||||
.as_ref()
|
||||
.map(|agent_identifier| agent_identifier.as_string());
|
||||
|
||||
new_room_config
|
||||
.settings
|
||||
.handler
|
||||
.set_by_purpose(purpose, agent_id);
|
||||
|
||||
room_config_manager
|
||||
.lock()
|
||||
.await
|
||||
.persist(message_context.room(), &new_room_config)
|
||||
.await?;
|
||||
|
||||
let message = match agent_identifier {
|
||||
Some(agent_identifier) => {
|
||||
strings::room_config::reconfigured_to_use_agent_for_purpose(agent_identifier, purpose)
|
||||
}
|
||||
None => strings::room_config::reconfigured_to_not_specify_agent_for_purpose(purpose),
|
||||
};
|
||||
|
||||
bot.messaging()
|
||||
.send_success_markdown_no_fail(
|
||||
message_context.room(),
|
||||
&message,
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
2
src/controller/cfg/room_config/mod.rs
Normal file
2
src/controller/cfg/room_config/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub(super) mod generic_setting;
|
||||
pub(super) mod handler;
|
||||
759
src/controller/cfg/status.rs
Normal file
759
src/controller/cfg/status.rs
Normal file
@@ -0,0 +1,759 @@
|
||||
use mxlink::MessageResponseType;
|
||||
|
||||
use crate::{
|
||||
agent::{
|
||||
utils::get_effective_agent_for_purpose, AgentInstance, AgentPurpose, ControllerTrait,
|
||||
Manager as AgentManager, PublicIdentifier,
|
||||
},
|
||||
entity::{
|
||||
roomconfig::{RoomConfig, RoomSettingsHandler},
|
||||
MessageContext, RoomConfigContext,
|
||||
},
|
||||
strings, Bot,
|
||||
};
|
||||
|
||||
pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyhow::Result<()> {
|
||||
let mut message = String::new();
|
||||
|
||||
let agent_manager = bot.agent_manager();
|
||||
|
||||
let agents = agent_manager
|
||||
.available_room_agents_by_room_config_context(message_context.room_config_context());
|
||||
|
||||
// Room handlers
|
||||
message.push_str(&generate_room_handlers_section(
|
||||
&message_context.room_config().settings.handler,
|
||||
&agents,
|
||||
bot.command_prefix(),
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Global handlers
|
||||
message.push_str(&generate_global_config_handlers_section(
|
||||
&message_context
|
||||
.global_config()
|
||||
.fallback_room_settings
|
||||
.handler,
|
||||
&agents,
|
||||
bot.command_prefix(),
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Agents
|
||||
message.push_str(&generate_room_agents_section(
|
||||
message_context.room_config(),
|
||||
&agents,
|
||||
bot.command_prefix(),
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Text Generation
|
||||
message.push_str(
|
||||
&generate_text_generation_section(agent_manager, message_context.room_config_context())
|
||||
.await,
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Text-to-Speech
|
||||
message.push_str(
|
||||
&generate_text_to_speech_section(agent_manager, message_context.room_config_context())
|
||||
.await,
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Speech-to-Text
|
||||
message.push_str(
|
||||
&generate_speech_to_text_section(agent_manager, message_context.room_config_context())
|
||||
.await,
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Image Generation
|
||||
message.push_str(
|
||||
&generate_image_generation_section(agent_manager, message_context.room_config_context())
|
||||
.await,
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
|
||||
bot.messaging()
|
||||
.send_text_markdown_no_fail(
|
||||
message_context.room(),
|
||||
message,
|
||||
MessageResponseType::Reply(message_context.thread_info().root_event_id.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_room_handlers_section(
|
||||
handler_config: &RoomSettingsHandler,
|
||||
agents: &[AgentInstance],
|
||||
command_prefix: &str,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(
|
||||
format!(
|
||||
"## {}\n",
|
||||
strings::cfg::status_room_config_handlers_heading()
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
message.push_str(strings::cfg::status_room_config_handlers_intro());
|
||||
message.push_str("\n\n");
|
||||
|
||||
for purpose in AgentPurpose::choices() {
|
||||
message.push_str(&generate_handler_line_for_purpose(
|
||||
purpose,
|
||||
handler_config,
|
||||
agents,
|
||||
false,
|
||||
));
|
||||
message.push('\n');
|
||||
}
|
||||
|
||||
message.push_str("\n\n");
|
||||
|
||||
message.push_str(strings::cfg::status_room_config_handlers_outro(command_prefix).as_str());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn generate_global_config_handlers_section(
|
||||
handler_config: &RoomSettingsHandler,
|
||||
agents: &[AgentInstance],
|
||||
command_prefix: &str,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(
|
||||
format!(
|
||||
"## {}\n",
|
||||
strings::cfg::status_global_config_handlers_heading()
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
message.push_str(strings::cfg::status_global_config_handlers_intro());
|
||||
message.push_str("\n\n");
|
||||
|
||||
for purpose in AgentPurpose::choices() {
|
||||
message.push_str(&generate_handler_line_for_purpose(
|
||||
purpose,
|
||||
handler_config,
|
||||
agents,
|
||||
true,
|
||||
));
|
||||
message.push('\n');
|
||||
}
|
||||
|
||||
message.push_str("\n\n");
|
||||
|
||||
message.push_str(strings::cfg::status_global_config_handlers_outro(command_prefix).as_str());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn generate_handler_line_for_purpose(
|
||||
purpose: &AgentPurpose,
|
||||
handler_config: &RoomSettingsHandler,
|
||||
agents: &[AgentInstance],
|
||||
is_for_global_config: bool,
|
||||
) -> String {
|
||||
let agent_id = handler_config.get_by_purpose(*purpose);
|
||||
|
||||
match agent_id {
|
||||
Some(agent_id) => {
|
||||
let agent = agents
|
||||
.iter()
|
||||
.find(|a| *a.identifier().as_string() == agent_id);
|
||||
|
||||
strings::cfg::status_handler_line_agent_found(purpose, &agent_id, agent)
|
||||
}
|
||||
None => match purpose {
|
||||
AgentPurpose::CatchAll => {
|
||||
if is_for_global_config {
|
||||
return strings::cfg::status_handler_line_catch_all_agent_not_set_globally();
|
||||
}
|
||||
|
||||
strings::cfg::status_handler_line_catch_all_agent_not_set_in_room_default_to_global(
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
if is_for_global_config {
|
||||
return strings::cfg::status_handler_line_non_catch_all_agent_not_set_globally(
|
||||
purpose,
|
||||
);
|
||||
}
|
||||
|
||||
strings::cfg::status_handler_line_non_catch_all_agent_not_set_in_room_default_to_global(
|
||||
purpose,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_room_agents_section(
|
||||
room_config: &RoomConfig,
|
||||
agents: &Vec<AgentInstance>,
|
||||
command_prefix: &str,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(format!("## {}\n", strings::cfg::status_room_agents_heading()).as_str());
|
||||
|
||||
if room_config.agents.is_empty() {
|
||||
message.push_str(strings::cfg::status_room_agents_empty());
|
||||
|
||||
message.push_str("\n\n");
|
||||
|
||||
message.push_str(&strings::help::learn_more_send_a_command(
|
||||
command_prefix,
|
||||
"agent",
|
||||
));
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
message.push_str(strings::cfg::status_room_agents_intro());
|
||||
message.push_str("\n\n");
|
||||
|
||||
for agent in agents {
|
||||
let PublicIdentifier::DynamicRoomLocal(_) = agent.identifier() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
message.push_str(&format!(
|
||||
"- `{}` ({})\n",
|
||||
agent.identifier(),
|
||||
strings::agent::create_support_badges_text(agent.controller()),
|
||||
));
|
||||
}
|
||||
|
||||
message.push_str("\n\n");
|
||||
|
||||
message.push_str(strings::cfg::status_room_agents_outro(command_prefix).as_str());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
async fn generate_text_generation_section(
|
||||
agent_manager: &AgentManager,
|
||||
room_config_context: &RoomConfigContext,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(format!("## {}\n", strings::cfg::status_text_generation_heading()).as_str());
|
||||
|
||||
let text_generation_agent_info = get_effective_agent_for_purpose(
|
||||
agent_manager,
|
||||
room_config_context,
|
||||
AgentPurpose::TextGeneration,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Effective agent
|
||||
|
||||
let text_generation_agent = match text_generation_agent_info {
|
||||
Ok(text_generation_agent_info) => {
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent(
|
||||
text_generation_agent_info.instance.identifier(),
|
||||
text_generation_agent_info.configuration_source,
|
||||
));
|
||||
|
||||
Some(text_generation_agent_info.instance)
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!(?err, "Failed to determine text-generation agent");
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent_error());
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Prefix requirement type
|
||||
|
||||
let effective_prefix_requirement_type =
|
||||
room_config_context.text_generation_prefix_requirement_type();
|
||||
let room_config_prefix_requirement_type = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_generation
|
||||
.prefix_requirement_type;
|
||||
let global_config_prefix_requirement_type = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_generation
|
||||
.prefix_requirement_type;
|
||||
|
||||
let prefix_requirement_type_set_where = if room_config_prefix_requirement_type.is_some() {
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_prefix_requirement_type.is_some() {
|
||||
strings::cfg::status_badge_set_in_global_config()
|
||||
} else {
|
||||
strings::cfg::status_badge_using_hardcoded_default()
|
||||
};
|
||||
|
||||
message.push_str(
|
||||
&strings::cfg::status_text_generation_entry_prefix_requirement_type(
|
||||
effective_prefix_requirement_type,
|
||||
prefix_requirement_type_set_where,
|
||||
),
|
||||
);
|
||||
|
||||
// Auto usage
|
||||
|
||||
let effective_auto_usage = room_config_context.auto_text_generation_usage();
|
||||
let room_config_auto_usage = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_generation
|
||||
.auto_usage;
|
||||
let global_config_auto_usage = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_generation
|
||||
.auto_usage;
|
||||
|
||||
let auto_usage_set_where = if room_config_auto_usage.is_some() {
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_auto_usage.is_some() {
|
||||
strings::cfg::status_badge_set_in_global_config()
|
||||
} else {
|
||||
strings::cfg::status_badge_using_hardcoded_default()
|
||||
};
|
||||
|
||||
message.push_str(&strings::cfg::status_text_generation_entry_auto_usage(
|
||||
effective_auto_usage,
|
||||
auto_usage_set_where,
|
||||
));
|
||||
|
||||
// Context Management
|
||||
|
||||
let effective_context_management =
|
||||
room_config_context.text_generation_context_management_enabled();
|
||||
let room_config_context_management = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_generation
|
||||
.context_management_enabled;
|
||||
let global_config_context_management = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_generation
|
||||
.context_management_enabled;
|
||||
|
||||
let context_management_set_where = if room_config_context_management.is_some() {
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_context_management.is_some() {
|
||||
strings::cfg::status_badge_set_in_global_config()
|
||||
} else {
|
||||
strings::cfg::status_badge_using_hardcoded_default()
|
||||
};
|
||||
|
||||
message.push_str(
|
||||
&strings::cfg::status_text_generation_entry_context_management(
|
||||
effective_context_management,
|
||||
context_management_set_where,
|
||||
),
|
||||
);
|
||||
|
||||
// Prompt override
|
||||
|
||||
let text_agent_prompt = if let Some(text_generation_agent) = &text_generation_agent {
|
||||
text_generation_agent.controller().text_generation_prompt()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let room_config_prompt_override = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_generation
|
||||
.prompt_override
|
||||
.clone();
|
||||
let global_config_prompt_override = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_generation
|
||||
.prompt_override
|
||||
.clone();
|
||||
|
||||
let (prompt, prompt_set_where) =
|
||||
if let Some(room_config_prompt_override) = room_config_prompt_override {
|
||||
(
|
||||
room_config_prompt_override,
|
||||
strings::cfg::status_badge_set_in_room_config(),
|
||||
)
|
||||
} else if let Some(global_config_prompt_override) = global_config_prompt_override {
|
||||
(
|
||||
global_config_prompt_override,
|
||||
strings::cfg::status_badge_set_in_global_config(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
text_agent_prompt.unwrap_or("".to_owned()),
|
||||
strings::cfg::status_badge_set_in_agent_config(),
|
||||
)
|
||||
};
|
||||
|
||||
message.push_str(&strings::cfg::status_text_generation_entry_prompt(
|
||||
&prompt,
|
||||
prompt_set_where,
|
||||
));
|
||||
|
||||
// Temperature
|
||||
|
||||
let text_agent_temperature = if let Some(text_generation_agent) = &text_generation_agent {
|
||||
text_generation_agent
|
||||
.controller()
|
||||
.text_generation_temperature()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let room_config_temperature_override = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_generation
|
||||
.temperature_override;
|
||||
let global_config_temperature_override = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_generation
|
||||
.temperature_override;
|
||||
|
||||
let (effective_temperature, set_where) = if let Some(room_config_temperature_override) =
|
||||
room_config_temperature_override
|
||||
{
|
||||
(
|
||||
Some(room_config_temperature_override),
|
||||
strings::cfg::status_badge_set_in_room_config(),
|
||||
)
|
||||
} else if let Some(global_config_temperature_override) = global_config_temperature_override {
|
||||
(
|
||||
Some(global_config_temperature_override),
|
||||
strings::cfg::status_badge_set_in_global_config(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
text_agent_temperature,
|
||||
strings::cfg::status_badge_set_in_agent_config(),
|
||||
)
|
||||
};
|
||||
|
||||
message.push_str(&strings::cfg::status_text_generation_entry_temperature(
|
||||
effective_temperature,
|
||||
set_where,
|
||||
));
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
async fn generate_speech_to_text_section(
|
||||
agent_manager: &AgentManager,
|
||||
room_config_context: &RoomConfigContext,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(format!("## {}\n", strings::cfg::status_speech_to_text_heading()).as_str());
|
||||
|
||||
let speech_to_text_agent_info = get_effective_agent_for_purpose(
|
||||
agent_manager,
|
||||
room_config_context,
|
||||
AgentPurpose::SpeechToText,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Effective agent
|
||||
|
||||
match speech_to_text_agent_info {
|
||||
Ok(speech_to_text_agent_info) => {
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent(
|
||||
speech_to_text_agent_info.instance.identifier(),
|
||||
speech_to_text_agent_info.configuration_source,
|
||||
));
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!(?err, "Failed to determine speech-to-text agent");
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent_error());
|
||||
}
|
||||
};
|
||||
|
||||
// Flow type
|
||||
|
||||
let effective_flow_type = room_config_context.speech_to_text_flow_type();
|
||||
let room_config_flow_type = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.speech_to_text
|
||||
.flow_type;
|
||||
let global_config_flow_type = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.speech_to_text
|
||||
.flow_type;
|
||||
|
||||
let flow_type_set_where = if room_config_flow_type.is_some() {
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_flow_type.is_some() {
|
||||
strings::cfg::status_badge_set_in_global_config()
|
||||
} else {
|
||||
strings::cfg::status_badge_using_hardcoded_default()
|
||||
};
|
||||
|
||||
message.push_str(&strings::cfg::status_speech_to_text_entry_flow_type(
|
||||
effective_flow_type,
|
||||
flow_type_set_where,
|
||||
));
|
||||
|
||||
// Language
|
||||
|
||||
let effective_language = room_config_context.speech_to_text_language();
|
||||
let room_config_language = &room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.speech_to_text
|
||||
.language;
|
||||
let global_config_language = &room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.speech_to_text
|
||||
.language;
|
||||
|
||||
let language_set_where = if room_config_language.is_some() {
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_language.is_some() {
|
||||
strings::cfg::status_badge_set_in_global_config()
|
||||
} else {
|
||||
strings::cfg::status_badge_using_hardcoded_default()
|
||||
};
|
||||
|
||||
message.push_str(&strings::cfg::status_speech_to_text_entry_language(
|
||||
effective_language,
|
||||
language_set_where,
|
||||
));
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
async fn generate_text_to_speech_section(
|
||||
agent_manager: &AgentManager,
|
||||
room_config_context: &RoomConfigContext,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(format!("## {}\n", strings::cfg::status_text_to_speech_heading()).as_str());
|
||||
|
||||
let text_to_speech_agent_info = get_effective_agent_for_purpose(
|
||||
agent_manager,
|
||||
room_config_context,
|
||||
AgentPurpose::TextToSpeech,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Effective agent
|
||||
|
||||
let text_to_speech_agent = match text_to_speech_agent_info {
|
||||
Ok(text_to_speech_agent_info) => {
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent(
|
||||
text_to_speech_agent_info.instance.identifier(),
|
||||
text_to_speech_agent_info.configuration_source,
|
||||
));
|
||||
Some(text_to_speech_agent_info.instance)
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!(?err, "Failed to determine text-to-speech agent");
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent_error());
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Bot messages flow type
|
||||
|
||||
let effective_bot_messages_tts_flow_type =
|
||||
room_config_context.text_to_speech_bot_messages_flow_type();
|
||||
let room_config_bot_messages_tts_flow_type = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_to_speech
|
||||
.bot_msgs_flow_type;
|
||||
let global_config_bot_messages_tts_flow_type = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_to_speech
|
||||
.bot_msgs_flow_type;
|
||||
|
||||
let bot_messages_tts_flow_type_set_where = if room_config_bot_messages_tts_flow_type.is_some() {
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_bot_messages_tts_flow_type.is_some() {
|
||||
strings::cfg::status_badge_set_in_global_config()
|
||||
} else {
|
||||
strings::cfg::status_badge_using_hardcoded_default()
|
||||
};
|
||||
|
||||
message.push_str(
|
||||
&strings::cfg::status_text_to_speech_entry_bot_msgs_flow_type(
|
||||
effective_bot_messages_tts_flow_type,
|
||||
bot_messages_tts_flow_type_set_where,
|
||||
),
|
||||
);
|
||||
|
||||
// User messages flow type
|
||||
|
||||
let effective_user_messages_tts_flow_type =
|
||||
room_config_context.text_to_speech_user_messages_flow_type();
|
||||
let room_config_user_messages_tts_flow_type = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_to_speech
|
||||
.user_msgs_flow_type;
|
||||
let global_config_user_messages_tts_flow_type = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_to_speech
|
||||
.user_msgs_flow_type;
|
||||
|
||||
let user_messages_tts_flow_type_set_where = if room_config_user_messages_tts_flow_type.is_some()
|
||||
{
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_user_messages_tts_flow_type.is_some() {
|
||||
strings::cfg::status_badge_set_in_global_config()
|
||||
} else {
|
||||
strings::cfg::status_badge_using_hardcoded_default()
|
||||
};
|
||||
|
||||
message.push_str(
|
||||
&strings::cfg::status_text_to_speech_entry_user_msgs_flow_type(
|
||||
effective_user_messages_tts_flow_type,
|
||||
user_messages_tts_flow_type_set_where,
|
||||
),
|
||||
);
|
||||
|
||||
// Speed
|
||||
|
||||
let agent_speed = if let Some(text_to_speech_agent) = &text_to_speech_agent {
|
||||
text_to_speech_agent.controller().text_to_speech_speed()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let room_config_speed_override = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_to_speech
|
||||
.speed_override;
|
||||
let global_config_speed_override = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_to_speech
|
||||
.speed_override;
|
||||
|
||||
let (effective_speed, set_where) =
|
||||
if let Some(room_config_speed_override) = room_config_speed_override {
|
||||
(
|
||||
Some(room_config_speed_override),
|
||||
strings::cfg::status_badge_set_in_room_config(),
|
||||
)
|
||||
} else if let Some(global_config_speed_override) = global_config_speed_override {
|
||||
(
|
||||
Some(global_config_speed_override),
|
||||
strings::cfg::status_badge_set_in_global_config(),
|
||||
)
|
||||
} else if agent_speed.is_some() {
|
||||
(
|
||||
agent_speed,
|
||||
strings::cfg::status_badge_set_in_agent_config(),
|
||||
)
|
||||
} else {
|
||||
(None, strings::cfg::status_badge_using_hardcoded_default())
|
||||
};
|
||||
|
||||
message.push_str(&strings::cfg::status_text_to_speech_entry_speed(
|
||||
effective_speed,
|
||||
set_where,
|
||||
));
|
||||
|
||||
// Voice
|
||||
|
||||
let agent_voice = if let Some(text_to_speech_agent) = &text_to_speech_agent {
|
||||
text_to_speech_agent.controller().text_to_speech_voice()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let room_config_voice_override = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_to_speech
|
||||
.voice_override
|
||||
.clone();
|
||||
let global_config_voice_override = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_to_speech
|
||||
.voice_override
|
||||
.clone();
|
||||
|
||||
let (effective_voice, set_where) =
|
||||
if let Some(room_config_voice_override) = room_config_voice_override {
|
||||
(
|
||||
Some(room_config_voice_override),
|
||||
strings::cfg::status_badge_set_in_room_config(),
|
||||
)
|
||||
} else if let Some(global_config_voice_override) = global_config_voice_override {
|
||||
(
|
||||
Some(global_config_voice_override),
|
||||
strings::cfg::status_badge_set_in_global_config(),
|
||||
)
|
||||
} else if agent_voice.is_some() {
|
||||
(
|
||||
agent_voice,
|
||||
strings::cfg::status_badge_set_in_agent_config(),
|
||||
)
|
||||
} else {
|
||||
(None, strings::cfg::status_badge_using_hardcoded_default())
|
||||
};
|
||||
|
||||
message.push_str(&strings::cfg::status_text_to_speech_entry_voice(
|
||||
effective_voice,
|
||||
set_where,
|
||||
));
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
async fn generate_image_generation_section(
|
||||
agent_manager: &AgentManager,
|
||||
room_config_context: &RoomConfigContext,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
message.push_str(format!("## {}\n", strings::cfg::status_image_generation_heading()).as_str());
|
||||
|
||||
let image_generation_agent_info = get_effective_agent_for_purpose(
|
||||
agent_manager,
|
||||
room_config_context,
|
||||
AgentPurpose::ImageGeneration,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Effective agent
|
||||
|
||||
let _image_generation_agent = match image_generation_agent_info {
|
||||
Ok(image_generation_agent_info) => {
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent(
|
||||
image_generation_agent_info.instance.identifier(),
|
||||
image_generation_agent_info.configuration_source,
|
||||
));
|
||||
Some(image_generation_agent_info.instance)
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!(?err, "Failed to determine image generation agent");
|
||||
message.push_str(&strings::cfg::status_entry_effective_agent_error());
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
message
|
||||
}
|
||||
Reference in New Issue
Block a user