11import { useEffect , useMemo , useState , useSyncExternalStore } from "react" ;
22
33import { Button , Timeline , toast } from "@ace/ui" ;
4- import type { Listing } from "@ace/host/protocol" ;
4+ import { channelProject , type Listing } from "@ace/host/protocol" ;
55
66import { Checks } from "./checks" ;
77import { Composer } from "./composer" ;
@@ -11,7 +11,8 @@ import { EditMessage } from "./edit-message";
1111import { publish , useDetails } from "./details" ;
1212import { host } from "./host" ;
1313import { MessageQueue } from "./message-queue" ;
14- import { OfflineHost } from "./onboarding" ;
14+ import { OfflineHost , useRoster } from "./onboarding" ;
15+ import { present } from "./presence" ;
1516import { pendingQuestion , Question } from "./question" ;
1617import { sources , toEvents } from "./timeline" ;
1718import { useTranscript } from "./transcript" ;
@@ -158,6 +159,23 @@ export function Conversation(
158159 ) ,
159160 [ people ] ,
160161 ) ;
162+ const presence = useSyncExternalStore ( host . subscribe , ( ) => host . presence ) ;
163+ const roster = useRoster ( ) ;
164+ // Mentions name people by GitHub login. A name still holding @ is a Tailscale login with no
165+ // GitHub account, or an agent from another channel (`agent@<prefix>`), and can't be mentioned.
166+ const members = useMemo ( ( ) => {
167+ const self = people [ user ] || user ;
168+ const names = new Set ( [
169+ ...present ( presence [ channelProject ( channel ) ] , self , channel . id ) . map ( ( value ) => value . name ) ,
170+ ...transcript . items . flatMap ( ( item ) =>
171+ item . kind === "message" ? [ people [ item . author ] || item . author ] : [ ]
172+ ) ,
173+ ...( roster || [ ] ) . map ( ( member ) => member . github || member . login ) ,
174+ ] ) ;
175+ return [ ...names ]
176+ . filter ( ( name ) => name !== self && name !== "ace" && ! name . includes ( "@" ) )
177+ . map ( ( name ) => ( { name, avatar : avatars [ name ] } ) ) ;
178+ } , [ people , user , presence , channel , transcript . items , roster , avatars ] ) ;
161179 const results = useMemo (
162180 ( ) =>
163181 transcript . items . reduce (
@@ -304,6 +322,7 @@ export function Conversation(
304322 failure = { failure }
305323 onProviders = { onProviders }
306324 accessory = { chat ?. usage && < Usage value = { chat . usage } context = { chat . context } /> }
325+ members = { members }
307326 />
308327 </ div >
309328 </ div >
0 commit comments