Add sender context mode for text generation (#104)
Add a per-room/global `sender_context_mode` setting that optionally
prefixes conversation messages with sender metadata before sending them
to the model provider.
This helps models distinguish between participants in multi-user rooms.
Three modes are supported:
- `disabled` (default, no change)
- `matrix_user_id` (prefixes with `[sender=@user:server]`)
- `matrix_user_id_and_timestamp` (adds `send_at`; Example: `[sender=@user:server sent_at=<ISO 8601>]`)
Sender context is applied to user and assistant text messages only,
skipping system prompts and non-text content.
Mixed-sender merged turns (something we intentionally do for Anthropic)
have their `sender_id` cleared to avoid misattribution.
This commit is contained in:
@@ -3,7 +3,8 @@ use crate::{
|
||||
entity::roomconfig::{
|
||||
SpeechToTextFlowType, SpeechToTextMessageTypeForNonThreadedOnlyTranscribedMessages,
|
||||
TextGenerationAutoUsage, TextGenerationPrefixRequirementType,
|
||||
TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType,
|
||||
TextGenerationSenderContextMode, TextToSpeechBotMessagesFlowType,
|
||||
TextToSpeechUserMessagesFlowType,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -48,6 +49,9 @@ pub enum ConfigTextGenerationSettingRelatedControllerType {
|
||||
|
||||
GetTemperatureOverride,
|
||||
SetTemperatureOverride(Option<f32>),
|
||||
|
||||
GetSenderContextMode,
|
||||
SetSenderContextMode(Option<TextGenerationSenderContextMode>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
||||
@@ -163,6 +163,26 @@ fn determine_controller() {
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room text-generation/sender-context-mode getter",
|
||||
input: "room text-generation sender-context-mode",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Room,
|
||||
controller_type::ConfigSettingRelatedControllerType::TextGeneration(
|
||||
controller_type::ConfigTextGenerationSettingRelatedControllerType::GetSenderContextMode,
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "global text-generation/sender-context-mode getter",
|
||||
input: "global text-generation sender-context-mode",
|
||||
expected: super::ControllerType::Config(controller_type::ConfigControllerType::SettingsRelated(
|
||||
controller_type::SettingsStorageSource::Global,
|
||||
controller_type::ConfigSettingRelatedControllerType::TextGeneration(
|
||||
controller_type::ConfigTextGenerationSettingRelatedControllerType::GetSenderContextMode,
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "per-room text-to-speech/speed-override getter",
|
||||
input: "room text-to-speech speed-override",
|
||||
|
||||
@@ -3,7 +3,10 @@ mod tests;
|
||||
|
||||
use crate::{
|
||||
controller::ControllerType,
|
||||
entity::roomconfig::{TextGenerationAutoUsage, TextGenerationPrefixRequirementType},
|
||||
entity::roomconfig::{
|
||||
TextGenerationAutoUsage, TextGenerationPrefixRequirementType,
|
||||
TextGenerationSenderContextMode,
|
||||
},
|
||||
strings,
|
||||
};
|
||||
|
||||
@@ -197,5 +200,43 @@ pub(super) fn determine(
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(remaining_text) = text.strip_prefix("sender-context-mode") {
|
||||
let remaining_text = remaining_text.trim();
|
||||
|
||||
if !remaining_text.is_empty() {
|
||||
return Err(ControllerType::Error(
|
||||
strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"sender-context-mode",
|
||||
remaining_text,
|
||||
)
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
return Ok(ConfigTextGenerationSettingRelatedControllerType::GetSenderContextMode);
|
||||
}
|
||||
|
||||
if let Some(value_string) = text.strip_prefix("set-sender-context-mode") {
|
||||
let value_string = value_string.trim().to_owned();
|
||||
let value_choice = if value_string.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let value_choice =
|
||||
TextGenerationSenderContextMode::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::SetSenderContextMode(value_choice),
|
||||
);
|
||||
}
|
||||
|
||||
Err(ControllerType::Unknown)
|
||||
}
|
||||
|
||||
@@ -90,6 +90,74 @@ fn determine_controller_context_management() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_controller_sender_context() {
|
||||
use super::ConfigTextGenerationSettingRelatedControllerType;
|
||||
use super::ControllerType;
|
||||
use crate::entity::roomconfig::TextGenerationSenderContextMode;
|
||||
|
||||
struct TestCase {
|
||||
name: &'static str,
|
||||
input: &'static str,
|
||||
expected: Result<ConfigTextGenerationSettingRelatedControllerType, ControllerType>,
|
||||
}
|
||||
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
name: "sender-context-mode getter ok",
|
||||
input: "sender-context-mode",
|
||||
expected: Ok(ConfigTextGenerationSettingRelatedControllerType::GetSenderContextMode),
|
||||
},
|
||||
TestCase {
|
||||
name: "sender-context-mode getter extra args",
|
||||
input: "sender-context-mode some values here",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_getter_used_with_extra_text(
|
||||
"sender-context-mode",
|
||||
"some values here",
|
||||
),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "sender-context-mode setter matrix_user_id",
|
||||
input: "set-sender-context-mode matrix_user_id",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetSenderContextMode(Some(
|
||||
TextGenerationSenderContextMode::MatrixUserId,
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "sender-context-mode setter uppercase",
|
||||
input: "set-sender-context-mode MATRIX_USER_ID_AND_TIMESTAMP",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetSenderContextMode(Some(
|
||||
TextGenerationSenderContextMode::MatrixUserIdAndTimestamp,
|
||||
)),
|
||||
),
|
||||
},
|
||||
TestCase {
|
||||
name: "sender-context-mode setter invalid",
|
||||
input: "set-sender-context-mode non-Enum-Value",
|
||||
expected: Err(ControllerType::Error(
|
||||
crate::strings::cfg::configuration_value_unrecognized("non-Enum-Value"),
|
||||
)),
|
||||
},
|
||||
TestCase {
|
||||
name: "sender-context-mode unsetter",
|
||||
input: "set-sender-context-mode",
|
||||
expected: Ok(
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetSenderContextMode(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;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::entity::roomconfig::{
|
||||
RoomSettings, TextGenerationAutoUsage, TextGenerationPrefixRequirementType,
|
||||
TextGenerationSenderContextMode,
|
||||
};
|
||||
use crate::{Bot, entity::MessageContext};
|
||||
|
||||
@@ -151,5 +152,38 @@ pub(super) async fn dispatch(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigTextGenerationSettingRelatedControllerType::GetSenderContextMode => {
|
||||
let value = &room_settings.text_generation.sender_context_mode;
|
||||
setting_get::<TextGenerationSenderContextMode>(bot, message_context, value).await
|
||||
}
|
||||
ConfigTextGenerationSettingRelatedControllerType::SetSenderContextMode(value) => {
|
||||
let value = value.to_owned();
|
||||
|
||||
let setter_callback = Box::new(move |room_settings: &mut RoomSettings| {
|
||||
room_settings.text_generation.sender_context_mode = value;
|
||||
});
|
||||
|
||||
match config_type {
|
||||
SettingsStorageSource::Room => {
|
||||
room_setting_set::<TextGenerationSenderContextMode>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SettingsStorageSource::Global => {
|
||||
global_setting_set::<TextGenerationSenderContextMode>(
|
||||
bot,
|
||||
message_context,
|
||||
&value,
|
||||
setter_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ use crate::{
|
||||
roomconfig::{
|
||||
SpeechToTextFlowType, SpeechToTextMessageTypeForNonThreadedOnlyTranscribedMessages,
|
||||
TextGenerationAutoUsage, TextGenerationPrefixRequirementType,
|
||||
TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType,
|
||||
TextGenerationSenderContextMode, TextToSpeechBotMessagesFlowType,
|
||||
TextToSpeechUserMessagesFlowType,
|
||||
},
|
||||
},
|
||||
strings,
|
||||
@@ -233,6 +234,46 @@ fn build_section_text_generation(command_prefix: &str, bot_username: &str) -> St
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Sender Context
|
||||
|
||||
message.push_str(&format!(
|
||||
"#### {}",
|
||||
strings::help::cfg::text_generation_sender_context_heading()
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&strings::help::cfg::text_generation_sender_context_intro());
|
||||
message.push('\n');
|
||||
message.push_str(
|
||||
&strings::help::cfg::the_following_configuration_values_are_recognized(
|
||||
TextGenerationSenderContextMode::choices(),
|
||||
),
|
||||
);
|
||||
message.push_str("\n\n");
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_show(
|
||||
command_prefix,
|
||||
"text-generation sender-context-mode"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_set(
|
||||
command_prefix,
|
||||
"text-generation set-sender-context-mode VALUE"
|
||||
)
|
||||
));
|
||||
message.push('\n');
|
||||
message.push_str(&format!(
|
||||
"- {}",
|
||||
&strings::help::cfg::current_setting_unset(
|
||||
command_prefix,
|
||||
"text-generation set-sender-context-mode"
|
||||
)
|
||||
));
|
||||
message.push_str("\n\n");
|
||||
|
||||
// Prompt override
|
||||
|
||||
message.push_str(&format!(
|
||||
|
||||
@@ -359,6 +359,33 @@ async fn generate_text_generation_section(
|
||||
),
|
||||
);
|
||||
|
||||
// Sender Context
|
||||
|
||||
let effective_sender_context = room_config_context.text_generation_sender_context_mode();
|
||||
let room_config_sender_context = room_config_context
|
||||
.room_config
|
||||
.settings
|
||||
.text_generation
|
||||
.sender_context_mode;
|
||||
let global_config_sender_context = room_config_context
|
||||
.global_config
|
||||
.fallback_room_settings
|
||||
.text_generation
|
||||
.sender_context_mode;
|
||||
|
||||
let sender_context_set_where = if room_config_sender_context.is_some() {
|
||||
strings::cfg::status_badge_set_in_room_config()
|
||||
} else if global_config_sender_context.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_sender_context(
|
||||
effective_sender_context,
|
||||
sender_context_set_where,
|
||||
));
|
||||
|
||||
// Prompt override
|
||||
|
||||
let text_agent_prompt = if let Some(text_generation_agent) = &text_generation_agent {
|
||||
|
||||
@@ -15,7 +15,8 @@ use crate::conversation::matrix::MatrixMessageProcessingParams;
|
||||
use crate::entity::MessagePayload;
|
||||
use crate::entity::roomconfig::{
|
||||
SpeechToTextFlowType, SpeechToTextMessageTypeForNonThreadedOnlyTranscribedMessages,
|
||||
TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType,
|
||||
TextGenerationSenderContextMode, TextToSpeechBotMessagesFlowType,
|
||||
TextToSpeechUserMessagesFlowType,
|
||||
};
|
||||
use crate::strings;
|
||||
use crate::utils::text_to_speech::create_transcribed_message_text;
|
||||
@@ -23,6 +24,7 @@ use crate::{
|
||||
Bot,
|
||||
conversation::{
|
||||
create_llm_conversation_for_matrix_reply_chain, create_llm_conversation_for_matrix_thread,
|
||||
llm::{Author, Conversation, MessageContent},
|
||||
matrix::create_list_of_bot_user_prefixes_to_strip,
|
||||
},
|
||||
entity::MessageContext,
|
||||
@@ -486,6 +488,13 @@ async fn handle_stage_text_generation(
|
||||
}
|
||||
};
|
||||
|
||||
let conversation = inject_sender_context(
|
||||
conversation,
|
||||
message_context
|
||||
.room_config_context()
|
||||
.text_generation_sender_context_mode(),
|
||||
);
|
||||
|
||||
tracing::debug!(
|
||||
agent_id = agent.identifier().as_string(),
|
||||
provider = format!("{}", agent.definition().provider.clone()),
|
||||
@@ -761,3 +770,238 @@ async fn generate_and_send_tts_for_message(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
fn inject_sender_context(
|
||||
conversation: Conversation,
|
||||
sender_context_mode: TextGenerationSenderContextMode,
|
||||
) -> Conversation {
|
||||
if sender_context_mode == TextGenerationSenderContextMode::Disabled {
|
||||
return conversation;
|
||||
}
|
||||
|
||||
let include_timestamp =
|
||||
sender_context_mode == TextGenerationSenderContextMode::MatrixUserIdAndTimestamp;
|
||||
|
||||
let messages = conversation
|
||||
.messages
|
||||
.into_iter()
|
||||
.map(|mut message| {
|
||||
if message.author == Author::Prompt {
|
||||
return message;
|
||||
}
|
||||
|
||||
let Some(sender_id) = &message.sender_id else {
|
||||
return message;
|
||||
};
|
||||
|
||||
if let MessageContent::Text(ref mut text) = message.content {
|
||||
*text = if include_timestamp {
|
||||
let timestamp = message.timestamp.format("%Y-%m-%dT%H:%M:%SZ");
|
||||
format!("[sender={} sent_at={}] {}", sender_id, timestamp, text)
|
||||
} else {
|
||||
format!("[sender={}] {}", sender_id, text)
|
||||
};
|
||||
}
|
||||
|
||||
message
|
||||
})
|
||||
.collect();
|
||||
|
||||
Conversation { messages }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sender_context_tests {
|
||||
use super::inject_sender_context;
|
||||
use crate::conversation::llm::{Author, Conversation, ImageDetails, Message, MessageContent};
|
||||
use crate::entity::roomconfig::TextGenerationSenderContextMode;
|
||||
use chrono::{TimeZone, Utc};
|
||||
use mxlink::matrix_sdk::ruma::events::room::message::ImageMessageEventContent;
|
||||
use mxlink::matrix_sdk::ruma::{OwnedMxcUri, OwnedUserId};
|
||||
use mxlink::mime;
|
||||
|
||||
#[test]
|
||||
fn test_inject_sender_context_prefixes_text_messages() {
|
||||
let timestamp = Utc.with_ymd_and_hms(2026, 3, 23, 14, 30, 0).unwrap();
|
||||
let user_id = OwnedUserId::try_from("@alice:example.com").unwrap();
|
||||
|
||||
let conversation = Conversation {
|
||||
messages: vec![Message {
|
||||
author: Author::User,
|
||||
sender_id: Some(user_id),
|
||||
timestamp,
|
||||
content: MessageContent::Text("Hello bot".to_string()),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = inject_sender_context(
|
||||
conversation,
|
||||
TextGenerationSenderContextMode::MatrixUserIdAndTimestamp,
|
||||
);
|
||||
|
||||
assert_eq!(result.messages.len(), 1);
|
||||
assert_eq!(
|
||||
result.messages[0].content,
|
||||
MessageContent::Text(
|
||||
"[sender=@alice:example.com sent_at=2026-03-23T14:30:00Z] Hello bot".to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inject_sender_context_can_prefix_without_timestamp() {
|
||||
let timestamp = Utc.with_ymd_and_hms(2026, 3, 23, 14, 30, 0).unwrap();
|
||||
let user_id = OwnedUserId::try_from("@alice:example.com").unwrap();
|
||||
|
||||
let conversation = Conversation {
|
||||
messages: vec![Message {
|
||||
author: Author::User,
|
||||
sender_id: Some(user_id),
|
||||
timestamp,
|
||||
content: MessageContent::Text("Hello bot".to_string()),
|
||||
}],
|
||||
};
|
||||
|
||||
let result =
|
||||
inject_sender_context(conversation, TextGenerationSenderContextMode::MatrixUserId);
|
||||
|
||||
assert_eq!(result.messages.len(), 1);
|
||||
assert_eq!(
|
||||
result.messages[0].content,
|
||||
MessageContent::Text("[sender=@alice:example.com] Hello bot".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inject_sender_context_prefixes_assistant_messages() {
|
||||
let timestamp = Utc.with_ymd_and_hms(2026, 3, 23, 14, 30, 0).unwrap();
|
||||
let user_id = OwnedUserId::try_from("@baibot:example.com").unwrap();
|
||||
|
||||
let conversation = Conversation {
|
||||
messages: vec![Message {
|
||||
author: Author::Assistant,
|
||||
sender_id: Some(user_id),
|
||||
timestamp,
|
||||
content: MessageContent::Text("Hello human".to_string()),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = inject_sender_context(
|
||||
conversation,
|
||||
TextGenerationSenderContextMode::MatrixUserIdAndTimestamp,
|
||||
);
|
||||
|
||||
assert_eq!(result.messages.len(), 1);
|
||||
assert_eq!(
|
||||
result.messages[0].content,
|
||||
MessageContent::Text(
|
||||
"[sender=@baibot:example.com sent_at=2026-03-23T14:30:00Z] Hello human".to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inject_sender_context_skips_prompt_messages() {
|
||||
let timestamp = Utc.with_ymd_and_hms(2026, 3, 23, 14, 30, 0).unwrap();
|
||||
|
||||
let conversation = Conversation {
|
||||
messages: vec![Message {
|
||||
author: Author::Prompt,
|
||||
sender_id: None,
|
||||
timestamp,
|
||||
content: MessageContent::Text("You are a bot".to_string()),
|
||||
}],
|
||||
};
|
||||
|
||||
let result =
|
||||
inject_sender_context(conversation, TextGenerationSenderContextMode::MatrixUserId);
|
||||
|
||||
assert_eq!(
|
||||
result.messages[0].content,
|
||||
MessageContent::Text("You are a bot".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inject_sender_context_skips_messages_without_sender_id() {
|
||||
let timestamp = Utc.with_ymd_and_hms(2026, 3, 23, 14, 30, 0).unwrap();
|
||||
|
||||
let conversation = Conversation {
|
||||
messages: vec![Message {
|
||||
author: Author::User,
|
||||
sender_id: None,
|
||||
timestamp,
|
||||
content: MessageContent::Text("Transcribed text".to_string()),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = inject_sender_context(
|
||||
conversation,
|
||||
TextGenerationSenderContextMode::MatrixUserIdAndTimestamp,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
result.messages[0].content,
|
||||
MessageContent::Text("Transcribed text".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inject_sender_context_leaves_non_text_content_unchanged() {
|
||||
let timestamp = Utc.with_ymd_and_hms(2026, 3, 23, 14, 30, 0).unwrap();
|
||||
let user_id = OwnedUserId::try_from("@alice:example.com").unwrap();
|
||||
let image_event_content = ImageMessageEventContent::plain(
|
||||
"image.png".to_string(),
|
||||
OwnedMxcUri::from("mxc://example.com/1234567890"),
|
||||
);
|
||||
|
||||
let conversation = Conversation {
|
||||
messages: vec![Message {
|
||||
author: Author::User,
|
||||
sender_id: Some(user_id),
|
||||
timestamp,
|
||||
content: MessageContent::Image(ImageDetails::new(
|
||||
image_event_content.clone(),
|
||||
mime::IMAGE_PNG,
|
||||
vec![],
|
||||
)),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = inject_sender_context(
|
||||
conversation,
|
||||
TextGenerationSenderContextMode::MatrixUserIdAndTimestamp,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
result.messages[0].content,
|
||||
MessageContent::Image(ImageDetails::new(
|
||||
image_event_content,
|
||||
mime::IMAGE_PNG,
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inject_sender_context_none_leaves_text_unchanged() {
|
||||
let timestamp = Utc.with_ymd_and_hms(2026, 3, 23, 14, 30, 0).unwrap();
|
||||
let user_id = OwnedUserId::try_from("@alice:example.com").unwrap();
|
||||
|
||||
let conversation = Conversation {
|
||||
messages: vec![Message {
|
||||
author: Author::User,
|
||||
sender_id: Some(user_id),
|
||||
timestamp,
|
||||
content: MessageContent::Text("Hello bot".to_string()),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = inject_sender_context(conversation, TextGenerationSenderContextMode::Disabled);
|
||||
|
||||
assert_eq!(
|
||||
result.messages[0].content,
|
||||
MessageContent::Text("Hello bot".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ mod tests {
|
||||
original_prompt: "Generate a picture of a dog",
|
||||
messages: vec![Message {
|
||||
author: Author::User,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text("Must be blue".to_owned()),
|
||||
timestamp,
|
||||
}],
|
||||
@@ -75,16 +76,19 @@ mod tests {
|
||||
messages: vec![
|
||||
Message {
|
||||
author: Author::User,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text("Must be blue".to_owned()),
|
||||
timestamp,
|
||||
},
|
||||
Message {
|
||||
author: Author::Assistant,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text("Whatever".to_owned()),
|
||||
timestamp,
|
||||
},
|
||||
Message {
|
||||
author: Author::User,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text(
|
||||
"Must be 3-legged.\nMust be flying.".to_owned(),
|
||||
),
|
||||
@@ -99,21 +103,25 @@ mod tests {
|
||||
messages: vec![
|
||||
Message {
|
||||
author: Author::User,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text("Must be blue".to_owned()),
|
||||
timestamp,
|
||||
},
|
||||
Message {
|
||||
author: Author::Assistant,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text("Whatever".to_owned()),
|
||||
timestamp,
|
||||
},
|
||||
Message {
|
||||
author: Author::User,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text("Again".to_owned()),
|
||||
timestamp,
|
||||
},
|
||||
Message {
|
||||
author: Author::User,
|
||||
sender_id: None,
|
||||
content: MessageContent::Text("again".to_owned()),
|
||||
timestamp,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user