feat: add search_room_history tool for deep conversation search
Allows the bot to paginate back up to 500 messages in a room to find specific content, beyond the default 10-message context window. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
70
bot.py
70
bot.py
@@ -311,7 +311,28 @@ WEB_SEARCH_TOOLS = [{
|
|||||||
},
|
},
|
||||||
}]
|
}]
|
||||||
|
|
||||||
ALL_TOOLS = IMAGE_GEN_TOOLS + WEB_SEARCH_TOOLS + ATLASSIAN_TOOLS
|
ROOM_TOOLS = [{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "search_room_history",
|
||||||
|
"description": (
|
||||||
|
"Search the current chat room's message history for specific content. "
|
||||||
|
"Use when the user asks about something said earlier in the conversation that is beyond "
|
||||||
|
"the recent messages visible to you, e.g. 'what did I say about X last week', "
|
||||||
|
"'find the message where I mentioned Y', 'what was the first thing I asked today'."
|
||||||
|
),
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"query": {"type": "string", "description": "Search term or phrase to look for in room messages"},
|
||||||
|
"limit": {"type": "integer", "description": "Max messages to scan (default 200, max 500)", "default": 200},
|
||||||
|
},
|
||||||
|
"required": ["query"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
|
||||||
|
ALL_TOOLS = IMAGE_GEN_TOOLS + WEB_SEARCH_TOOLS + ATLASSIAN_TOOLS + ROOM_TOOLS
|
||||||
|
|
||||||
ATLASSIAN_NOT_CONNECTED_MSG = (
|
ATLASSIAN_NOT_CONNECTED_MSG = (
|
||||||
"Your Atlassian account is not connected. "
|
"Your Atlassian account is not connected. "
|
||||||
@@ -2047,6 +2068,12 @@ class Bot:
|
|||||||
return f"Could not reach {url}. The domain may be misspelled — ask the user to clarify."
|
return f"Could not reach {url}. The domain may be misspelled — ask the user to clarify."
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
# Room history search — no auth needed
|
||||||
|
if tool_name == "search_room_history":
|
||||||
|
return await self._search_room_history(
|
||||||
|
room_id, args.get("query", ""), args.get("limit", 200)
|
||||||
|
)
|
||||||
|
|
||||||
# Atlassian tools — need per-user token
|
# Atlassian tools — need per-user token
|
||||||
token = await self.atlassian.get_token(sender) if sender else None
|
token = await self.atlassian.get_token(sender) if sender else None
|
||||||
if not token:
|
if not token:
|
||||||
@@ -2080,6 +2107,47 @@ class Bot:
|
|||||||
else:
|
else:
|
||||||
return f"Unknown tool: {tool_name}"
|
return f"Unknown tool: {tool_name}"
|
||||||
|
|
||||||
|
async def _search_room_history(self, room_id: str, query: str, limit: int = 200) -> str:
|
||||||
|
"""Search room message history for messages matching a query string."""
|
||||||
|
limit = min(limit, 500)
|
||||||
|
query_lower = query.lower()
|
||||||
|
try:
|
||||||
|
# Paginate through room history
|
||||||
|
matches = []
|
||||||
|
token = self.client.next_batch or ""
|
||||||
|
fetched = 0
|
||||||
|
while fetched < limit:
|
||||||
|
batch_size = min(100, limit - fetched)
|
||||||
|
resp = await self.client.room_messages(
|
||||||
|
room_id, start=token, limit=batch_size
|
||||||
|
)
|
||||||
|
if not hasattr(resp, "chunk") or not resp.chunk:
|
||||||
|
break
|
||||||
|
for evt in resp.chunk:
|
||||||
|
if not hasattr(evt, "body"):
|
||||||
|
continue
|
||||||
|
if query_lower in evt.body.lower():
|
||||||
|
ts = evt.server_timestamp / 1000
|
||||||
|
date_str = time.strftime("%Y-%m-%d %H:%M", time.gmtime(ts))
|
||||||
|
sender_name = evt.sender.split(":")[0].lstrip("@")
|
||||||
|
matches.append(f"[{date_str}] {sender_name}: {evt.body[:500]}")
|
||||||
|
fetched += len(resp.chunk)
|
||||||
|
token = resp.end
|
||||||
|
if not token:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not matches:
|
||||||
|
return f"No messages found matching '{query}' in the last {fetched} messages."
|
||||||
|
# Return newest first (matches are in reverse chronological from pagination)
|
||||||
|
result = f"Found {len(matches)} message(s) matching '{query}' (scanned {fetched} messages):\n\n"
|
||||||
|
result += "\n\n---\n\n".join(matches[:20]) # cap at 20 results
|
||||||
|
if len(matches) > 20:
|
||||||
|
result += f"\n\n... and {len(matches) - 20} more matches."
|
||||||
|
return result
|
||||||
|
except Exception:
|
||||||
|
logger.warning("Room history search failed", exc_info=True)
|
||||||
|
return "Failed to search room history."
|
||||||
|
|
||||||
# -- Escalation patterns for model routing --
|
# -- Escalation patterns for model routing --
|
||||||
_ESCALATION_KEYWORDS = re.compile(
|
_ESCALATION_KEYWORDS = re.compile(
|
||||||
r"\b(debug|architecture|algorithm|regex|sql|refactor|optimize|migration"
|
r"\b(debug|architecture|algorithm|regex|sql|refactor|optimize|migration"
|
||||||
|
|||||||
Reference in New Issue
Block a user