@@ -41,6 +41,10 @@ struct SlackAdapterState {
4141 /// Maps slash command string (e.g. `"/ask"`) → agent_id.
4242 /// Built once at start() from the config; read-only afterwards.
4343 commands : Arc < HashMap < String , String > > ,
44+ /// Cache of resolved user identities to avoid repeated `users.info` API calls.
45+ user_identity_cache : Arc < RwLock < HashMap < String , SlackUserIdentity > > > ,
46+ /// Cache of resolved channel names to avoid repeated `conversations.info` API calls.
47+ channel_name_cache : Arc < RwLock < HashMap < String , String > > > ,
4448}
4549
4650#[ derive( Debug , Clone ) ]
@@ -202,6 +206,8 @@ async fn handle_message_event(
202206 msg_event. sender . user . as_ref ( ) ,
203207 & client,
204208 & adapter_state. bot_token ,
209+ & adapter_state. user_identity_cache ,
210+ & adapter_state. channel_name_cache ,
205211 )
206212 . await ;
207213
@@ -282,6 +288,8 @@ async fn handle_app_mention_event(
282288 Some ( & slack_uid) ,
283289 & client,
284290 & adapter_state. bot_token ,
291+ & adapter_state. user_identity_cache ,
292+ & adapter_state. channel_name_cache ,
285293 )
286294 . await ;
287295
@@ -652,6 +660,8 @@ impl Messaging for SlackAdapter {
652660 bot_token : self . bot_token . clone ( ) ,
653661 bot_user_id,
654662 commands : self . commands . clone ( ) ,
663+ user_identity_cache : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
664+ channel_name_cache : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
655665 } ) ;
656666
657667 let callbacks = SlackSocketModeListenerCallbacks :: new ( )
@@ -1104,11 +1114,10 @@ impl Messaging for SlackAdapter {
11041114 let author = if is_bot {
11051115 "bot" . to_string ( )
11061116 } else if let Some ( uid) = user_id {
1107- let display_name = user_identity_by_id
1117+ user_identity_by_id
11081118 . get ( & uid)
11091119 . map ( |i| i. display_name . clone ( ) )
1110- . unwrap_or_else ( || uid. clone ( ) ) ;
1111- format ! ( "{display_name} (<@{uid}>)" )
1120+ . unwrap_or_else ( || uid. clone ( ) )
11121121 } else {
11131122 "unknown" . to_string ( )
11141123 } ;
@@ -1241,6 +1250,8 @@ async fn build_metadata_and_author(
12411250 slack_user_id : Option < & SlackUserId > ,
12421251 client : & Arc < SlackHyperClient > ,
12431252 bot_token : & str ,
1253+ user_identity_cache : & Arc < RwLock < HashMap < String , SlackUserIdentity > > > ,
1254+ channel_name_cache : & Arc < RwLock < HashMap < String , String > > > ,
12441255) -> ( HashMap < String , serde_json:: Value > , Option < String > ) {
12451256 let mut metadata = HashMap :: new ( ) ;
12461257
@@ -1276,26 +1287,96 @@ async fn build_metadata_and_author(
12761287 ) ;
12771288 }
12781289
1279- // Resolve display name and username
1290+ let token = SlackApiToken :: new ( SlackApiTokenValue ( bot_token. to_string ( ) ) ) ;
1291+ let session = client. open_session ( & token) ;
1292+
1293+ // Resolve channel name via cache or conversations.info API.
1294+ if let Some ( name) = channel_name_cache. read ( ) . await . get ( channel_id) . cloned ( ) {
1295+ metadata. insert (
1296+ "slack_channel_name" . into ( ) ,
1297+ serde_json:: Value :: String ( name) ,
1298+ ) ;
1299+ } else {
1300+ match session
1301+ . conversations_info (
1302+ & SlackApiConversationsInfoRequest :: new ( SlackChannelId ( channel_id. to_string ( ) ) ) ,
1303+ )
1304+ . await
1305+ {
1306+ Ok ( channel_info) => {
1307+ if let Some ( name) = channel_info. channel . name {
1308+ channel_name_cache
1309+ . write ( )
1310+ . await
1311+ . insert ( channel_id. to_string ( ) , name. clone ( ) ) ;
1312+ metadata. insert (
1313+ "slack_channel_name" . into ( ) ,
1314+ serde_json:: Value :: String ( name) ,
1315+ ) ;
1316+ }
1317+ }
1318+ // DM channels (D-prefixed) don't support conversations.info in all cases
1319+ Err ( error) if !channel_id. starts_with ( 'D' ) => {
1320+ tracing:: warn!(
1321+ %error,
1322+ channel_id = %channel_id,
1323+ "failed to resolve Slack channel name; verify channels:read scope"
1324+ ) ;
1325+ }
1326+ Err ( _) => { }
1327+ }
1328+ }
1329+
1330+ // Resolve user identity via cache or users.info API.
12801331 let mut formatted_author = user_id. map ( |u| u. to_string ( ) ) ;
12811332
12821333 if let Some ( uid) = slack_user_id {
1283- let token = SlackApiToken :: new ( SlackApiTokenValue ( bot_token. to_string ( ) ) ) ;
1284- let session = client. open_session ( & token) ;
1285- if let Ok ( user_info) = session
1334+ let cached = user_identity_cache. read ( ) . await . get ( & uid. 0 ) . cloned ( ) ;
1335+ let identity = if let Some ( identity) = cached {
1336+ Some ( identity)
1337+ } else if let Ok ( user_info) = session
12861338 . users_info ( & SlackApiUsersInfoRequest :: new ( uid. clone ( ) ) )
12871339 . await
12881340 {
12891341 let identity = resolve_slack_user_identity ( & user_info. user , & uid. 0 ) ;
1290- let display_with_mention = format ! ( "{} (<@{}>)" , identity. display_name, uid. 0 ) ;
1342+ user_identity_cache
1343+ . write ( )
1344+ . await
1345+ . insert ( uid. 0 . clone ( ) , identity. clone ( ) ) ;
1346+ Some ( identity)
1347+ } else {
1348+ None
1349+ } ;
1350+
1351+ if let Some ( identity) = identity {
12911352 metadata. insert (
12921353 "sender_display_name" . into ( ) ,
1293- serde_json:: Value :: String ( display_with_mention. clone ( ) ) ,
1354+ serde_json:: Value :: String ( identity. display_name . clone ( ) ) ,
1355+ ) ;
1356+ metadata. insert (
1357+ "slack_user_mention" . into ( ) ,
1358+ serde_json:: Value :: String ( format ! ( "<@{}>" , uid. 0 ) ) ,
12941359 ) ;
1295- if let Some ( name) = identity. username {
1296- metadata. insert ( "sender_username" . into ( ) , serde_json:: Value :: String ( name) ) ;
1360+ if let Some ( ref name) = identity. username {
1361+ metadata. insert (
1362+ "sender_username" . into ( ) ,
1363+ serde_json:: Value :: String ( name. clone ( ) ) ,
1364+ ) ;
12971365 }
1298- formatted_author = Some ( display_with_mention) ;
1366+ formatted_author = Some ( identity. display_name . clone ( ) ) ;
1367+ }
1368+ }
1369+
1370+ // For DMs without a resolved channel name, use the sender's display name.
1371+ if channel_id. starts_with ( 'D' ) && !metadata. contains_key ( "slack_channel_name" ) {
1372+ if let Some ( display_name) = metadata
1373+ . get ( "sender_display_name" )
1374+ . and_then ( |v| v. as_str ( ) )
1375+ {
1376+ metadata. insert (
1377+ "slack_channel_name" . into ( ) ,
1378+ serde_json:: Value :: String ( format ! ( "dm-{display_name}" ) ) ,
1379+ ) ;
12991380 }
13001381 }
13011382
0 commit comments