slack unfurl links

* Add unfurl_links config for Slack channel

Add unfurl_links: bool (default true) to SlackConfig to control
Slack's automatic URL preview expansion. When set to false, links
in agent messages are not unfurled, keeping output compact.

Applied to SlackAdapter's chat.postMessage payload via unfurl_links
and unfurl_media parameters, affecting both real-time and cron
delivery paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Rename test per review: clarify it tests explicit true, not default

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vincent Leraitre
2026-03-15 14:44:53 +03:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 52647b2996
commit dec081a326
3 changed files with 56 additions and 0 deletions
@@ -1150,6 +1150,7 @@ pub async fn start_channel_bridge_with_config(
sl_config.allowed_channels.clone(),
sl_config.auto_thread_reply,
sl_config.thread_ttl_hours,
sl_config.unfurl_links,
));
adapters.push((adapter, sl_config.default_agent.clone()));
}
+33
View File
@@ -39,6 +39,8 @@ pub struct SlackAdapter {
thread_ttl: Duration,
/// Whether auto-thread-reply is enabled.
auto_thread_reply: bool,
/// Whether to unfurl (expand previews for) links in posted messages.
unfurl_links: bool,
}
impl SlackAdapter {
@@ -48,6 +50,7 @@ impl SlackAdapter {
allowed_channels: Vec<String>,
auto_thread_reply: bool,
thread_ttl_hours: u64,
unfurl_links: bool,
) -> Self {
let (shutdown_tx, shutdown_rx) = watch::channel(false);
Self {
@@ -61,6 +64,7 @@ impl SlackAdapter {
active_threads: Arc::new(DashMap::new()),
thread_ttl: Duration::from_secs(thread_ttl_hours * 3600),
auto_thread_reply,
unfurl_links,
}
}
@@ -100,6 +104,8 @@ impl SlackAdapter {
let mut body = serde_json::json!({
"channel": channel_id,
"text": chunk,
"unfurl_links": self.unfurl_links,
"unfurl_media": self.unfurl_links,
});
if let Some(ts) = thread_ts {
body["thread_ts"] = serde_json::json!(ts);
@@ -691,8 +697,35 @@ mod tests {
vec!["C123".to_string()],
true,
24,
true,
);
assert_eq!(adapter.name(), "slack");
assert_eq!(adapter.channel_type(), ChannelType::Slack);
}
#[test]
fn test_slack_adapter_unfurl_links_enabled() {
let adapter = SlackAdapter::new(
"xapp-test".to_string(),
"xoxb-test".to_string(),
vec![],
true,
24,
true,
);
assert!(adapter.unfurl_links);
}
#[test]
fn test_slack_adapter_unfurl_links_disabled() {
let adapter = SlackAdapter::new(
"xapp-test".to_string(),
"xoxb-test".to_string(),
vec![],
true,
24,
false,
);
assert!(!adapter.unfurl_links);
}
}
+22
View File
@@ -1752,6 +1752,9 @@ pub struct SlackConfig {
/// Hours to track a thread after last interaction (default: 24).
#[serde(default = "default_thread_ttl")]
pub thread_ttl_hours: u64,
/// Whether to unfurl (expand previews for) links in messages (default: true).
#[serde(default = "default_true")]
pub unfurl_links: bool,
}
impl Default for SlackConfig {
@@ -1764,6 +1767,7 @@ impl Default for SlackConfig {
overrides: ChannelOverrides::default(),
auto_thread_reply: true,
thread_ttl_hours: 24,
unfurl_links: true,
}
}
}
@@ -3872,4 +3876,22 @@ mod tests {
"AZURE_OPENAI_KEY"
);
}
#[test]
fn test_slack_config_unfurl_links_defaults_true() {
let config: SlackConfig = toml::from_str("").unwrap();
assert!(config.unfurl_links);
}
#[test]
fn test_slack_config_unfurl_links_explicit_false() {
let config: SlackConfig = toml::from_str("unfurl_links = false").unwrap();
assert!(!config.unfurl_links);
}
#[test]
fn test_slack_config_unfurl_links_explicit_true() {
let config: SlackConfig = toml::from_str("unfurl_links = true").unwrap();
assert!(config.unfurl_links);
}
}