import { Notification } from "../utils/types.ts"; import { doesUserFollowTarget } from "../utils/doesUserFollow.ts"; import { agentContext } from "../utils/agentContext.ts"; import { getCleanThread } from "../utils/getCleanThread.ts"; export const mentionPrompt = async (notification: Notification) => { const isUserFollower = await doesUserFollowTarget( notification.author.did, agentContext.agentBskyDID, ); const notifierHandle = `@${notification.author.handle}`; const isUserFollowerString = isUserFollower === true ? `${notifierHandle} FOLLOWS YOU` : isUserFollower === false ? `${notifierHandle} DOES NOT FOLLOW YOU` : ""; const doYouFollow = await doesUserFollowTarget( agentContext.agentBskyDID, notification.author.did, ); const doYouFollowString = doYouFollow === true ? `YOU FOLLOW ${notifierHandle}` : doYouFollow === false ? `YOU DO NOT FOLLOW ${notifierHandle}` : ""; const thread = notification.uri ? await getCleanThread(notification.uri) : [{ // @TODO: find a better way to handle this authorHandle: undefined, message: "ERROR: could not get thread", uri: undefined, authorDID: undefined, postedDateTime: undefined, bookmarks: undefined, replies: undefined, reposts: undefined, likes: undefined, quotes: undefined, }]; return ` # NOTIFICATION: You've been mentioned on Bluesky ## Context • **Mentioned by:** @${notification.author.handle} • **Sender DID:** ${notification.author.did} • **Mention Post URI:** ${notification.uri} • **Mention Post timestamp:** ${notification.record.createdAt} ${isUserFollowerString} ${doYouFollowString} ## Current Message from @${notification.author.handle} (message you are responding to) \`\`\` ${notification.record.text} \`\`\` ## Full Thread Context Below is the complete conversation thread leading up to this mention. Each post includes message text, timestamp, author information, and engagement metrics (likes, replies, reposts, quotes, bookmarks). Engagement signals can help you understand what has resonated with others in the thread. \`\`\`json ${JSON.stringify(thread, null, 2)} \`\`\` ## Your Task: Assess and Decide **Your default action is to NOT respond.** Most mentions do not warrant replies. ### Step 1: Understand the Situation Identify which scenario applies: • **Direct address:** Are you being spoken to directly with a question, request, or reply? • **Mid-thread mention:** Are you being pulled into an ongoing conversation? Is your input solicited or would it be intrusive? • **Indirect reference:** Are you mentioned but not expected to respond? (e.g., "I saw @agent posted about...") ### Step 2: Determine If Response Is Warranted Only consider responding when ALL of these are true: ✓ You're directly addressed OR your input is clearly solicited ✓ You have relevant expertise or value to add ✓ A response aligns with your defined purpose ✓ This is not spam, harassment, or off-topic **When in doubt, don't respond.** It's better to miss an optional interaction than to intrude where you're not needed. ## Available Actions ### ignore_notification — YOUR DEFAULT ACTION **This is your most common response.** Use this liberally. Use when: • You're mentioned indirectly or in passing • You have nothing meaningful to contribute • The conversation doesn't relate to your purpose • You're unsure whether to engage • The mention appears to be spam or harassment ### archival_memory_search — USE SELECTIVELY Do NOT automatically search memory for every mention. Only search for previous interactions with this user when: • The user explicitly references past conversations ("as we discussed...", "you mentioned before...") • You need to verify specific details from prior exchanges • Historical context would materially change your response If you have no reason to believe prior context exists or matters, skip the search. ### create_bluesky_post — USE JUDICIOUSLY Only after deciding a response is warranted. **Guidelines:** • Each call creates one post (maximum 200 characters) • **Default to a single post** — most responses should be one post • Only create threaded replies (multiple calls) when: • The response genuinely requires extended explanation that cannot fit in 200 characters • You're explicitly asked for a detailed or long response • The topic naturally benefits from a structured multi-part answer • Avoid unnecessary threads — be concise when possible **Error handling:** If an individual post fails, only recreate that specific post. Do not regenerate the entire thread. ## Archival (After Responding) If you chose to respond, archive the interaction when it meets ANY of these criteria: • Contains a specific argument, opinion, or question relevant to your domain • Is the user's second or subsequent message in this thread • References external sources (articles, studies, people, events) **Archival entry must include:** • User handle • Root post URI • Concise summary of the exchange • Conceptual tags for retrieval • Key context valuable for future interactions After archiving, update any other relevant memory blocks as needed. --- **Remember:** Having these tools available does NOT mean you must use them. Selective, intentional engagement is better than reflexive responses to every mention. `; };