human handoffs
This commit is contained in:
parent
79188e0f59
commit
36a55930f9
35 changed files with 4039 additions and 139 deletions
137
backend/app/services/thread_service.py
Normal file
137
backend/app/services/thread_service.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
from datetime import datetime, timezone
|
||||
|
||||
from bson import ObjectId
|
||||
|
||||
from app.services.message_ids import build_references_header, normalize_message_id
|
||||
from app.services.subject_normalize import normalize_subject
|
||||
from app.services.thread_resolver import ThreadResolution
|
||||
|
||||
|
||||
def message_event_at(message: dict) -> datetime:
|
||||
return (
|
||||
message.get("received_at")
|
||||
or message.get("sent_at")
|
||||
or message.get("created_at")
|
||||
or datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
|
||||
async def create_thread(
|
||||
database,
|
||||
*,
|
||||
account_id: str,
|
||||
subject: str,
|
||||
message_id: ObjectId,
|
||||
event_at: datetime,
|
||||
thread_type: str = "EXTERNAL",
|
||||
) -> ObjectId:
|
||||
now = datetime.now(timezone.utc)
|
||||
document = {
|
||||
"account_id": account_id,
|
||||
"thread_type": thread_type,
|
||||
"normalized_subject": normalize_subject(subject),
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
"last_message_at": event_at,
|
||||
"latest_message_id": message_id,
|
||||
"message_count": 1,
|
||||
}
|
||||
result = await database.email_threads.insert_one(document)
|
||||
return result.inserted_id
|
||||
|
||||
|
||||
async def message_already_in_thread(
|
||||
database,
|
||||
*,
|
||||
account_id: str,
|
||||
thread_id: ObjectId,
|
||||
message_id: ObjectId,
|
||||
) -> bool:
|
||||
existing = await database.mailbox_entries.find_one(
|
||||
{
|
||||
"account_id": account_id,
|
||||
"thread_id": thread_id,
|
||||
"message_id": message_id,
|
||||
},
|
||||
{"_id": 1},
|
||||
)
|
||||
return existing is not None
|
||||
|
||||
|
||||
async def attach_message_to_thread(
|
||||
database,
|
||||
*,
|
||||
account_id: str,
|
||||
thread_id: ObjectId,
|
||||
message_id: ObjectId,
|
||||
subject: str,
|
||||
event_at: datetime,
|
||||
) -> None:
|
||||
if await message_already_in_thread(
|
||||
database,
|
||||
account_id=account_id,
|
||||
thread_id=thread_id,
|
||||
message_id=message_id,
|
||||
):
|
||||
return
|
||||
now = datetime.now(timezone.utc)
|
||||
await database.email_threads.update_one(
|
||||
{"_id": thread_id, "account_id": account_id},
|
||||
{
|
||||
"$set": {
|
||||
"updated_at": now,
|
||||
"last_message_at": event_at,
|
||||
"latest_message_id": message_id,
|
||||
"normalized_subject": normalize_subject(subject),
|
||||
},
|
||||
"$inc": {"message_count": 1},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def ensure_thread_for_message(
|
||||
database,
|
||||
*,
|
||||
account_id: str,
|
||||
message: dict,
|
||||
resolution: ThreadResolution,
|
||||
) -> ObjectId:
|
||||
message_id = message["_id"]
|
||||
event_at = message_event_at(message)
|
||||
subject = message.get("subject", "")
|
||||
|
||||
if resolution.thread_id is not None:
|
||||
await attach_message_to_thread(
|
||||
database,
|
||||
account_id=account_id,
|
||||
thread_id=resolution.thread_id,
|
||||
message_id=message_id,
|
||||
subject=subject,
|
||||
event_at=event_at,
|
||||
)
|
||||
return resolution.thread_id
|
||||
|
||||
return await create_thread(
|
||||
database,
|
||||
account_id=account_id,
|
||||
subject=subject,
|
||||
message_id=message_id,
|
||||
event_at=event_at,
|
||||
)
|
||||
|
||||
|
||||
def threading_fields_from_parent(parent: dict) -> dict:
|
||||
parent_internet_id = normalize_message_id(parent.get("message_id"))
|
||||
parent_references = parent.get("references") or []
|
||||
if isinstance(parent_references, str):
|
||||
parent_references = [parent_references]
|
||||
references = []
|
||||
if parent_references:
|
||||
references = list(parent_references)
|
||||
if parent_internet_id:
|
||||
references = build_references_header(references, parent_internet_id).split()
|
||||
return {
|
||||
"in_reply_to": parent_internet_id,
|
||||
"references": references,
|
||||
"parent_message_id": parent["_id"],
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue