#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ReactionSentiment {
Positive,
Negative,
Neutral,
}
const POSITIVE: &[&str] = &["👍", "👌", "💪", "🫡", "🆗", "🔥", "💯"];
const NEGATIVE: &[&str] = &["⛔️", "⛔", "🚫", "🛑", "👎"];
pub(crate) fn classify_reaction(emoji: &str) -> ReactionSentiment {
let trimmed = emoji.trim();
if POSITIVE.contains(&trimmed) {
ReactionSentiment::Positive
} else if NEGATIVE.contains(&trimmed) {
ReactionSentiment::Negative
} else {
ReactionSentiment::Neutral
}
}
pub(crate) fn build_reaction_prompt(
first_name: &str,
emoji: &str,
preview: &str,
is_group: bool,
) -> String {
let steer = match classify_reaction(emoji) {
ReactionSentiment::Negative => format!(
"This reads as {first_name} flagging that something is off. This is the one case \
that warrants a short reply: address {first_name} by first name, pause rather than \
press on, and ask what they'd like changed."
),
ReactionSentiment::Positive | ReactionSentiment::Neutral => {
let group_note = if is_group {
" This is a group, so a text reply is noise for everyone else: react-only unless \
a text response is genuinely necessary."
} else {
""
};
format!(
"This is a lightweight acknowledgement from {first_name}, not a request. Default \
to reacting back with a single emoji and NO text.{group_note} Only write text if \
you have something genuinely new and useful to add, which a reaction almost never \
calls for."
)
}
};
format!(
"[Reaction notification] {first_name} reacted with {emoji} to your message:\n\
\"{preview}\"\n\n\
{steer}\n\n\
To acknowledge silently, reply with ONLY <<react:EMOJI>> (e.g. <<react:🙏>> or \
<<react:{emoji}>>) and no other text. That is the expected response for a routine \
reaction."
)
}
pub(crate) fn build_midturn_reaction_message(first_name: &str, emoji: &str) -> String {
match classify_reaction(emoji) {
ReactionSentiment::Positive => format!(
"[Live feedback from {first_name}: reacted {emoji}] They approve of the current \
direction, you're on the right path. Keep going with the current plan, no need to \
stop or re-confirm. Acknowledge {first_name} by first name when you next reply."
),
ReactionSentiment::Negative => format!(
"[Live feedback from {first_name}: reacted {emoji}] They want you to PAUSE. Stop at \
the next safe point, summarize what you've done so far, and ask {first_name} (by \
first name) what they'd like changed before continuing."
),
ReactionSentiment::Neutral => format!(
"[Live feedback from {first_name}: reacted {emoji}] Take it into account and \
acknowledge {first_name} by first name when you next reply."
),
}
}