Skip to content

Commit d8ad915

Browse files
authored
Merge pull request #1054 from Hypn0sis/feat/discord-smart-thread
feat(discord): smart auto-thread mode (true/false/smart)
2 parents c27bfeb + 0227ff1 commit d8ad915

5 files changed

Lines changed: 363 additions & 23 deletions

File tree

crates/openfang-api/src/channel_bridge.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ pub async fn start_channel_bridge_with_config(
11851185
dc_config.allowed_users.clone(),
11861186
dc_config.ignore_bots,
11871187
dc_config.intents,
1188+
dc_config.auto_thread.clone(),
11881189
));
11891190
adapters.push((adapter, dc_config.default_agent.clone()));
11901191
}

crates/openfang-channels/src/bridge.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -773,12 +773,20 @@ async fn dispatch_message(
773773
.as_ref()
774774
.map(|o| o.lifecycle_reactions)
775775
.unwrap_or(true);
776-
let thread_id = if threading_enabled {
777-
message.thread_id.as_deref()
776+
777+
// --- Auto-thread: decide intent now, but create AFTER all policy guards ---
778+
let auto_thread_name = if !threading_enabled && message.thread_id.is_none() {
779+
adapter.should_auto_thread(message).await
778780
} else {
779781
None
780782
};
781783

784+
// thread_id is resolved later, after all guards pass.
785+
// Always propagate an existing thread_id (message arrived inside a thread),
786+
// regardless of threading_enabled — that flag controls explicit threading config,
787+
// not auto-detected thread context.
788+
let mut effective_thread_id: Option<String> = message.thread_id.clone();
789+
782790
// --- DM/Group policy check ---
783791
if let Some(ref ov) = overrides {
784792
if message.is_group {
@@ -839,12 +847,42 @@ async fn dispatch_message(
839847
if let Err(msg) =
840848
rate_limiter.check(ct_str, sender_user_id(message), ov.rate_limit_per_user)
841849
{
842-
send_response(adapter, &message.sender, msg, thread_id, output_format).await;
850+
// Rate-limit rejection: don't create a thread, use existing thread if any
851+
send_response(
852+
adapter,
853+
&message.sender,
854+
msg,
855+
message.thread_id.as_deref(),
856+
output_format,
857+
)
858+
.await;
843859
return;
844860
}
845861
}
846862
}
847863

864+
// --- Create auto-thread NOW (after all policy guards have passed) ---
865+
if let Some(ref thread_name) = auto_thread_name {
866+
match adapter
867+
.create_thread(&message.sender, &message.platform_message_id, thread_name)
868+
.await
869+
{
870+
Ok(new_thread_id) => {
871+
info!(
872+
"Created auto-thread {} for message {}",
873+
thread_name, message.platform_message_id
874+
);
875+
effective_thread_id = Some(new_thread_id);
876+
}
877+
Err(e) => {
878+
warn!("Failed to create auto-thread: {}", e);
879+
}
880+
}
881+
}
882+
883+
// Resolve final thread_id reference used by all downstream send_response calls
884+
let thread_id = effective_thread_id.as_deref();
885+
848886
// Handle commands first (early return)
849887
if let ChannelContent::Command { ref name, ref args } = message.content {
850888
let result = handle_command(

0 commit comments

Comments
 (0)