Skip to content

Commit 1bae8fa

Browse files
feat(discord): smart auto-thread mode (true/false/smart)
1 parent d94508e commit 1bae8fa

6 files changed

Lines changed: 390 additions & 28 deletions

File tree

crates/openfang-api/src/channel_bridge.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,7 @@ pub async fn start_channel_bridge_with_config(
11661166
dc_config.allowed_users.clone(),
11671167
dc_config.ignore_bots,
11681168
dc_config.intents,
1169+
dc_config.auto_thread.clone(),
11691170
));
11701171
adapters.push((adapter, dc_config.default_agent.clone()));
11711172
}
@@ -1470,8 +1471,13 @@ pub async fn start_channel_bridge_with_config(
14701471
// Revolt
14711472
if let Some(ref rv_config) = config.revolt {
14721473
if let Some(token) = read_token(&rv_config.bot_token_env, "Revolt") {
1473-
let adapter = Arc::new(RevoltAdapter::new(token));
1474-
adapters.push((adapter, rv_config.default_agent.clone()));
1474+
let adapter = RevoltAdapter::with_urls_and_channels(
1475+
token,
1476+
rv_config.api_url.clone(),
1477+
rv_config.ws_url.clone(),
1478+
rv_config.allowed_channels.clone(),
1479+
);
1480+
adapters.push((Arc::new(adapter), rv_config.default_agent.clone()));
14751481
}
14761482
}
14771483

crates/openfang-channels/src/bridge.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ fn default_output_format_for_channel(channel_type: &str) -> OutputFormat {
524524
"telegram" => OutputFormat::TelegramHtml,
525525
"slack" => OutputFormat::SlackMrkdwn,
526526
"wecom" => OutputFormat::PlainText,
527+
"signal" => OutputFormat::PlainText,
527528
_ => OutputFormat::Markdown,
528529
}
529530
}
@@ -642,12 +643,20 @@ async fn dispatch_message(
642643
.as_ref()
643644
.map(|o| o.lifecycle_reactions)
644645
.unwrap_or(true);
645-
let thread_id = if threading_enabled {
646-
message.thread_id.as_deref()
646+
647+
// --- Auto-thread: decide intent now, but create AFTER all policy guards ---
648+
let auto_thread_name = if !threading_enabled && message.thread_id.is_none() {
649+
adapter.should_auto_thread(message).await
647650
} else {
648651
None
649652
};
650653

654+
// thread_id is resolved later, after all guards pass.
655+
// Always propagate an existing thread_id (message arrived inside a thread),
656+
// regardless of threading_enabled — that flag controls explicit threading config,
657+
// not auto-detected thread context.
658+
let mut effective_thread_id: Option<String> = message.thread_id.clone();
659+
651660
// --- DM/Group policy check ---
652661
if let Some(ref ov) = overrides {
653662
if message.is_group {
@@ -708,12 +717,42 @@ async fn dispatch_message(
708717
if let Err(msg) =
709718
rate_limiter.check(ct_str, sender_user_id(message), ov.rate_limit_per_user)
710719
{
711-
send_response(adapter, &message.sender, msg, thread_id, output_format).await;
720+
// Rate-limit rejection: don't create a thread, use existing thread if any
721+
send_response(
722+
adapter,
723+
&message.sender,
724+
msg,
725+
message.thread_id.as_deref(),
726+
output_format,
727+
)
728+
.await;
712729
return;
713730
}
714731
}
715732
}
716733

734+
// --- Create auto-thread NOW (after all policy guards have passed) ---
735+
if let Some(ref thread_name) = auto_thread_name {
736+
match adapter
737+
.create_thread(&message.sender, &message.platform_message_id, thread_name)
738+
.await
739+
{
740+
Ok(new_thread_id) => {
741+
info!(
742+
"Created auto-thread {} for message {}",
743+
thread_name, message.platform_message_id
744+
);
745+
effective_thread_id = Some(new_thread_id);
746+
}
747+
Err(e) => {
748+
warn!("Failed to create auto-thread: {}", e);
749+
}
750+
}
751+
}
752+
753+
// Resolve final thread_id reference used by all downstream send_response calls
754+
let thread_id = effective_thread_id.as_deref();
755+
717756
// Handle commands first (early return)
718757
if let ChannelContent::Command { ref name, ref args } = message.content {
719758
let result = handle_command(name, args, handle, router, &message.sender).await;
@@ -1946,6 +1985,10 @@ mod tests {
19461985
default_output_format_for_channel("discord"),
19471986
OutputFormat::Markdown
19481987
);
1988+
assert_eq!(
1989+
default_output_format_for_channel("signal"),
1990+
OutputFormat::PlainText
1991+
)
19491992
}
19501993

19511994
#[tokio::test]

0 commit comments

Comments
 (0)