Function bodies 23 total
handle_app_home_opened function · python · L8-L60 (53 LOC)handlers/home_handler.py
def handle_app_home_opened(client, event: dict, logger) -> None:
"""Publish the App Home view when a user opens the bot's Home tab."""
user_id = event["user"]
view = {
"type": "home",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Kahm-pew-terr",
"emoji": True,
},
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": (
"*Your AI research assistant.*\n"
"Ask me anything and I'll search the web for a source-cited answer."
),
},
},
{"type": "divider"},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": (
register_home_handler function · python · L63-L65 (3 LOC)handlers/home_handler.py
def register_home_handler(app) -> None:
"""Register the app_home_opened event handler with the Bolt app."""
app.event("app_home_opened")(handle_app_home_opened)handle_mention function · python · L6-L29 (24 LOC)handlers/mention_handler.py
def handle_mention(event, client) -> None:
"""Handle @mentions in channels — strip the mention tag, fetch context, then answer."""
raw_text = event.get("text", "")
user_text = MENTION_RE.sub("", raw_text).strip()
if not user_text:
return
bot_user_id = get_bot_user_id(client)
channel = event["channel"]
if event.get("thread_ts"):
messages = fetch_thread_history(client, channel, event["thread_ts"], event["ts"], bot_user_id)
else:
messages = fetch_channel_history(client, channel, bot_user_id)
_handle_question(
client,
channel=channel,
thread_ts=event["ts"],
user_id=event.get("user", ""),
user_text=user_text,
messages=messages,
)register_mention_handler function · python · L32-L34 (3 LOC)handlers/mention_handler.py
def register_mention_handler(app) -> None:
"""Register the @mention handler on the given Bolt app."""
app.event("app_mention")(handle_mention)ack_message function · python · L6-L19 (14 LOC)handlers/message_handler.py
def ack_message(ack, event):
"""Acknowledge message events for DM (im) and group DM (mpim) channels.
For mpim, also requires that the message @mentions the bot.
"""
if event.get("bot_id"):
return
if event.get("subtype"):
return
channel_type = event.get("channel_type")
if channel_type == "im":
ack()
elif channel_type == "mpim" and MENTION_RE.search(event.get("text", "")):
ack()handle_dm function · python · L22-L46 (25 LOC)handlers/message_handler.py
def handle_dm(client, event: dict) -> None:
"""Lazy listener: process a DM, call Perplexity, reply with cited answer."""
if event.get("bot_id"):
return
if event.get("subtype"):
return
if event.get("channel_type") != "im":
return
bot_user_id = get_bot_user_id(client)
channel = event["channel"]
if event.get("thread_ts"):
messages = fetch_thread_history(client, channel, event["thread_ts"], event["ts"], bot_user_id)
else:
messages = fetch_channel_history(client, channel, bot_user_id)
_handle_question(
client,
channel=channel,
thread_ts=event["ts"],
user_id=event.get("user", ""),
user_text=event.get("text", ""),
messages=messages,
)handle_mpim function · python · L49-L79 (31 LOC)handlers/message_handler.py
def handle_mpim(client, event: dict) -> None:
"""Lazy listener: handle @mentions in group DMs (mpim), strip mention, answer."""
if event.get("bot_id"):
return
if event.get("subtype"):
return
if event.get("channel_type") != "mpim":
return
raw_text = event.get("text", "")
if not MENTION_RE.search(raw_text):
return
user_text = MENTION_RE.sub("", raw_text).strip()
bot_user_id = get_bot_user_id(client)
channel = event["channel"]
if event.get("thread_ts"):
messages = fetch_thread_history(client, channel, event["thread_ts"], event["ts"], bot_user_id)
else:
messages = fetch_channel_history(client, channel, bot_user_id)
_handle_question(
client,
channel=channel,
thread_ts=event["ts"],
user_id=event.get("user", ""),
user_text=user_text,
messages=messages,
)Repobility · open methodology · https://repobility.com/research/
register_message_handlers function · python · L82-L88 (7 LOC)handlers/message_handler.py
def register_message_handlers(app) -> None:
"""Register DM and group DM handlers on the given Bolt app.
Both handle_dm and handle_mpim are registered as lazy listeners on the 'message'
event. Each function guards on channel_type so only one fires per event.
"""
app.event("message")(ack=ack_message, lazy=[handle_dm, handle_mpim])get_bot_user_id function · python · L17-L22 (6 LOC)handlers/shared.py
def get_bot_user_id(client) -> str:
"""Return the bot's Slack user ID, fetching and caching it on first call."""
global _bot_user_id
if _bot_user_id is None:
_bot_user_id = client.auth_test()["user_id"]
return _bot_user_idupdate_slow_message function · python · L42-L48 (7 LOC)handlers/shared.py
def update_slow_message(client, channel: str, loading_ts: str) -> None:
"""Called by the 60-second timer if Perplexity is still running."""
client.chat_update(
channel=channel,
ts=loading_ts,
text="Taking longer than expected, still working on it...",
)_handle_question function · python · L51-L125 (75 LOC)handlers/shared.py
def _handle_question(
client,
channel: str,
thread_ts: str | None,
user_id: str,
user_text: str,
messages: list[dict] | None = None,
) -> None:
"""Shared logic: post loading indicator, call Perplexity, update with cited answer.
When thread_ts is None (e.g. slash command / App Home), the loading message is posted
as a top-level message. The loading message ts is then used as the thread anchor for
all subsequent overflow chunk replies.
Args:
client: Slack WebClient.
channel: Channel ID to post into.
thread_ts: Thread timestamp to reply in, or None for top-level.
user_id: Slack user ID of the asker.
user_text: The question text (may contain <@UID> tags).
messages: Optional prior conversation history for Perplexity context.
"""
# Resolve any <@UID> tags in the question text to display names.
user_text = resolve_uids(user_text, client)
# Build loading message kwargs — omit thread_tack_ask function · python · L12-L18 (7 LOC)handlers/slash_handler.py
def ack_ask(ack) -> None:
"""Acknowledge the /ask command unconditionally.
Per Bolt's ack/lazy pattern the ack function must respond within 3 seconds.
Empty-text handling is deferred to the lazy run_ask function.
"""
ack()run_ask function · python · L21-L58 (38 LOC)handlers/slash_handler.py
def run_ask(body: dict, respond) -> None:
"""Lazy handler: validate text and call Perplexity via respond().
Uses respond() instead of chat.postMessage so the slash command works in
any channel — even ones the bot hasn't joined. respond() posts via the
response_url which doesn't require channel membership.
"""
text = (body.get("text") or "").strip()
if not text:
respond(
text="Usage: /ask <your question>",
response_type="ephemeral",
)
return
user_id = body["user_id"]
respond(text="Searching...", response_type="in_channel")
try:
result = query_perplexity(text)
formatted = format_answer(result["answer"], result["citations"])
if user_id not in greeted_users:
greeted_users.add(user_id)
full_text = GREETING + formatted
else:
full_text = formatted
chunks = split_message(full_text)
respond(text=chunks[0], response_typregister_slash_handler function · python · L61-L63 (3 LOC)handlers/slash_handler.py
def register_slash_handler(app) -> None:
"""Register /ask command with the Bolt app using ack/lazy pattern."""
app.command("/ask")(ack=ack_ask, lazy=[run_ask])resolve_uids function · python · L19-L46 (28 LOC)services/context.py
def resolve_uids(text: str, client) -> str:
"""Replace all <@UID> tags in text with display names from Slack API.
Lookups are cached in memory so the same UID is only fetched once.
If a lookup fails for any reason, the raw tag is left unchanged.
Args:
text: The message text, potentially containing <@UID> tags.
client: A Slack WebClient instance.
Returns:
The text with UID tags replaced by display names where available.
"""
uids = re.findall(r"<@([A-Z0-9]+)>", text)
for uid in uids:
if uid not in _uid_cache:
try:
result = client.users_info(user=uid)
display_name = result["user"]["profile"]["display_name"]
real_name = result["user"]["real_name"]
# Fall back to real_name if display_name is empty
_uid_cache[uid] = display_name if display_name else real_name
except Exception:
# Leave raw tag — do not cache Repobility — same analyzer, your code, free for public repos · /scan/
_truncate function · python · L53-L57 (5 LOC)services/context.py
def _truncate(text: str) -> str:
"""Truncate text to MSG_TRUNCATE_LENGTH characters, appending '...' if cut."""
if len(text) > MSG_TRUNCATE_LENGTH:
return text[:MSG_TRUNCATE_LENGTH] + "..."
return text_build_message function · python · L60-L72 (13 LOC)services/context.py
def _build_message(text: str, bot_user_id: str, sender_id: str) -> dict:
"""Build a structured message dict compatible with Perplexity InputMessage.
Args:
text: The message content (already truncated if needed).
bot_user_id: The Slack user ID of this bot.
sender_id: The Slack user ID of the message sender.
Returns:
A dict with type, role, and content keys.
"""
role = "assistant" if sender_id == bot_user_id else "user"
return {"type": "message", "role": role, "content": _truncate(text)}fetch_thread_history function · python · L79-L119 (41 LOC)services/context.py
def fetch_thread_history(
client,
channel: str,
thread_ts: str,
current_ts: str,
bot_user_id: str,
) -> list[dict]:
"""Fetch prior messages from a thread, excluding the current trigger message.
Args:
client: A Slack WebClient instance.
channel: The channel ID containing the thread.
thread_ts: The thread's root timestamp.
current_ts: The timestamp of the message that triggered this handler
(excluded from results).
bot_user_id: The Slack user ID of this bot, used for role assignment.
Returns:
A list of structured {type, role, content} dicts in thread order,
up to HISTORY_DEPTH messages. Returns [] on API failure.
"""
try:
response = client.conversations_replies(
channel=channel,
ts=thread_ts,
limit=HISTORY_DEPTH + 1, # +1 to account for the current message
)
messages = [
msg for msg in response["messfetch_channel_history function · python · L122-L153 (32 LOC)services/context.py
def fetch_channel_history(
client,
channel: str,
bot_user_id: str,
) -> list[dict]:
"""Fetch recent messages from a channel in chronological order.
Args:
client: A Slack WebClient instance.
channel: The channel ID to fetch history from.
bot_user_id: The Slack user ID of this bot, used for role assignment.
Returns:
A list of structured {type, role, content} dicts, oldest-first,
up to HISTORY_DEPTH messages. Returns [] on API failure.
"""
try:
response = client.conversations_history(
channel=channel,
limit=HISTORY_DEPTH,
)
# API returns newest-first — reverse to chronological order
messages = list(reversed(response["messages"]))
result = []
for msg in messages:
text = resolve_uids(msg.get("text", ""), client)
sender_id = msg.get("user", "")
result.append(_build_message(text, bot_user_id, sender_id))
query_perplexity function · python · L11-L47 (37 LOC)services/perplexity.py
def query_perplexity(question: str, messages: list[dict] | None = None) -> dict:
"""Query Perplexity using the pro-search preset and extract citations.
Args:
question: The question to ask Perplexity.
messages: Optional list of prior conversation messages as structured
{type, role, content} dicts. When provided (and non-empty),
messages are sent as a list with the question appended as the
final user message. When None or empty, question is sent as a
plain string (backward-compatible behavior).
Returns:
A dict with:
- "answer": str — the response text
- "citations": list[dict] — up to 5 sources, each with "title" and "url"
Raises:
Any Perplexity SDK exceptions propagate to the caller unchanged.
"""
if messages:
input_items = list(messages) + [
{"type": "message", "role": "user", "content": question}
]
markdown_to_slack function · python · L5-L64 (60 LOC)utils/formatting.py
def markdown_to_slack(text: str) -> str:
"""Convert common Markdown patterns to Slack mrkdwn format.
Handles: bold, italic, headings, inline code, code blocks,
links, horizontal rules, and list markers.
"""
# Preserve code blocks (``` ... ```) — don't transform inside them
code_blocks: list[str] = []
def _stash_code_block(match):
code_blocks.append(match.group(0))
return f"\x00CODEBLOCK{len(code_blocks) - 1}\x00"
text = re.sub(r"```[\s\S]*?```", _stash_code_block, text)
# Preserve inline code (` ... `)
inline_codes: list[str] = []
def _stash_inline_code(match):
inline_codes.append(match.group(0))
return f"\x00INLINE{len(inline_codes) - 1}\x00"
text = re.sub(r"`[^`]+`", _stash_inline_code, text)
# Headings → bold text (Slack has no heading support)
text = re.sub(r"^#{1,6}\s+(.+)$", r"*\1*", text, flags=re.MULTILINE)
# Bold+italic ***text*** or ___text___ → Slack bold *text*
text = re.format_answer function · python · L67-L84 (18 LOC)utils/formatting.py
def format_answer(answer: str, citations: list[dict]) -> str:
"""Format a Perplexity answer with Slack mrkdwn citation footnotes.
Converts Markdown to Slack mrkdwn and appends clickable source links.
"""
slack_answer = markdown_to_slack(answer)
# Safety net: cap at 5 even if caller passes more
limited_citations = citations[:5]
if not limited_citations:
return f"{slack_answer}\n\n_No web sources found for this query_"
lines = [f"{slack_answer}\n───"]
for i, citation in enumerate(limited_citations, start=1):
lines.append(f"[{i}] <{citation['url']}|{citation['title']}>")
return "\n".join(lines)split_message function · python · L87-L105 (19 LOC)utils/formatting.py
def split_message(text: str, limit: int = 3800) -> list[str]:
"""Split a long message into chunks that fit within Slack's character limit.
Args:
text: The message text to split.
limit: Maximum characters per chunk (default 3800, well under Slack's 4000).
Returns:
List of string chunks. Always contains at least one element.
"""
if len(text) <= limit:
return [text]
chunks = []
while text:
chunks.append(text[:limit])
text = text[limit:]
return chunks