Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 0 additions & 149 deletions examples/thread_example.py

This file was deleted.

1 change: 0 additions & 1 deletion src/webexpythonsdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
WebhookEvent,
)
from .models.simple import simple_data_factory, SimpleDataModel
from .thread_utils import collect_thread_text_and_attachments
from .utils import WebexDateTime


Expand Down
180 changes: 0 additions & 180 deletions src/webexpythonsdk/api/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,183 +394,3 @@ def update(self, messageId=None, roomId=None, text=None, markdown=None):

# Add edit() as an alias to the update() method for backward compatibility
edit = update

def _is_direct_room(self, message):
"""Determine if a message is from a direct (1:1) room.

Args:
message: Message object with roomType property

Returns:
bool: True if the message is from a direct room, False otherwise
"""
if hasattr(message, "roomType"):
return message.roomType == "direct"
return False

def _is_group_room(self, message):
"""Determine if a message is from a group room (space).

Args:
message: Message object with roomType property

Returns:
bool: True if the message is from a group room, False otherwise
"""
if hasattr(message, "roomType"):
return message.roomType == "group"
return False

def get_thread_messages(self, message, max_scan=500):
"""Retrieve all messages in a thread, including the root message.

This method provides a robust way to collect thread messages that works
for both 1:1 conversations and spaces, handling the different permission
models and API limitations.

Args:
message: The message object to get the thread for
max_scan (int): Maximum number of messages to scan when searching for parent

Returns:
tuple: (thread_messages, root_message, error_message)
- thread_messages: List of all messages in the thread (oldest to newest)
- root_message: The root message of the thread (or None if not found)
- error_message: Error description if any issues occurred
"""
thread_messages = []
root_message = None
error_message = None

parent_id = getattr(message, "parentId", None)
room_id = getattr(message, "roomId", None)

if not parent_id or not room_id:
# Not a threaded message, return just this message
return [message], None, None

try:
# Strategy 1: Try to get the parent message directly
try:
root_message = self.get(parent_id)
thread_messages.append(root_message)
except Exception:
# Direct retrieval failed, try alternative strategies
if self._is_direct_room(message):
# For direct rooms, try list_direct with parentId
try:
direct_messages = list(
self.list_direct(
personId=getattr(message, "toPersonId", None),
personEmail=getattr(
message, "toPersonEmail", None
),
parentId=parent_id,
max=100,
)
)
if direct_messages:
root_message = direct_messages[0]
thread_messages.extend(direct_messages)
except Exception:
pass
else:
# For group rooms, try scanning recent messages
try:
scanned = 0
for msg in self.list(roomId=room_id, max=100):
scanned += 1
if getattr(msg, "id", None) == parent_id:
root_message = msg
thread_messages.append(msg)
break
if scanned >= max_scan:
break
except Exception:
pass

if not root_message:
error_message = f"Could not retrieve parent message {parent_id}. Bot may have joined after thread started or lacks permission."

# Strategy 2: Get all replies in the thread
try:
if self._is_direct_room(message):
# For direct rooms, use list_direct
replies = list(
self.list_direct(
personId=getattr(message, "toPersonId", None),
personEmail=getattr(
message, "toPersonEmail", None
),
parentId=parent_id,
max=100,
)
)
else:
# For group rooms, use list
replies = list(
self.list(roomId=room_id, parentId=parent_id, max=100)
)

# Add replies to thread messages, avoiding duplicates
existing_ids = {
getattr(m, "id", None) for m in thread_messages
}
for reply in replies:
reply_id = getattr(reply, "id", None)
if reply_id and reply_id not in existing_ids:
thread_messages.append(reply)
existing_ids.add(reply_id)

except Exception as e:
if not error_message:
error_message = (
f"Could not retrieve thread replies: {str(e)}"
)

# Strategy 3: Ensure the original message is included
original_id = getattr(message, "id", None)
if original_id and not any(
getattr(m, "id", None) == original_id for m in thread_messages
):
thread_messages.append(message)

# Sort messages by creation time (oldest to newest)
thread_messages.sort(key=lambda m: getattr(m, "created", ""))

except Exception as e:
error_message = f"Unexpected error retrieving thread: {str(e)}"

return thread_messages, root_message, error_message

def get_thread_context(self, message, max_scan=500):
"""Get thread context including root message and all replies.

This is a convenience method that returns a structured result with
thread information, making it easy to work with thread data.

Args:
message: The message object to get thread context for
max_scan (int): Maximum number of messages to scan when searching for parent

Returns:
dict: Dictionary containing:
- "thread_messages": List of all messages in thread (oldest to newest)
- "root_message": The root message of the thread
- "reply_count": Number of replies in the thread
- "is_thread": Boolean indicating if this is a threaded conversation
- "error": Error message if any issues occurred
- "room_type": Type of room (direct/group)
"""
thread_messages, root_message, error = self.get_thread_messages(
message, max_scan
)

return {
"thread_messages": thread_messages,
"root_message": root_message,
"reply_count": len(thread_messages) - 1 if root_message else 0,
"is_thread": getattr(message, "parentId", None) is not None,
"error": error,
"room_type": getattr(message, "roomType", "unknown"),
}
Loading