responsiveness fix

This commit is contained in:
debu-2 2026-10-06 21:03:37 +05:30
parent 4ad05bf137
commit f7a4753217
9 changed files with 396 additions and 13 deletions

View file

@ -58,6 +58,7 @@ from app.services.reply_extractor import (
)
from app.services.thread_service import (
attach_message_to_thread,
create_thread,
message_event_at,
threading_fields_from_parent,
)
@ -102,8 +103,8 @@ def build_handoff_subject(
del rule_name
subject = " · ".join(
[
_safe_subject_part(sender_name, "unknown sender"),
"handoff",
_safe_subject_part(sender_name, "unknown sender"),
_safe_subject_part(external_sender, "unknown sender"),
_safe_subject_part(external_subject, "(No subject)"),
]
@ -111,6 +112,48 @@ def build_handoff_subject(
return subject[:998].rstrip()
_EMAIL_PATTERN = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
_SUBJECT_PREFIX = re.compile(r"^(?:re|fw|fwd)\s*:\s*", re.IGNORECASE)
_HANDOFF_OPENER = re.compile(
r"^handoff(?:\s*·\s*|\s*\|\s*|\s+-\s+)",
re.IGNORECASE,
)
_HANDOFF_SEPARATOR = re.compile(r"\s*·\s*|\s*\|\s*|\s+-\s+")
def parse_human_initiated_subject(subject: str | None) -> dict | None:
"""Read `handoff · Name · email · subject` from a human-started email.
The word handoff must come first. The three parts after it are the
customer name, the customer email, and the subject the customer should
see. Separate them with ·, |, or a spaced hyphen.
"""
cleaned = re.sub(r"[\r\n]+", " ", subject or "").strip()
while True:
without_prefix = _SUBJECT_PREFIX.sub("", cleaned, count=1).strip()
if without_prefix == cleaned:
break
cleaned = without_prefix
opener = _HANDOFF_OPENER.match(cleaned)
if opener is None:
return None
parts = _HANDOFF_SEPARATOR.split(cleaned[opener.end() :], maxsplit=2)
if len(parts) < 3:
return None
customer_name = parts[0].strip()
customer_email = parts[1].strip().lower()
customer_subject = parts[2].strip()
if not customer_name or not customer_subject:
return None
if _EMAIL_PATTERN.fullmatch(customer_email) is None:
return None
return {
"customer_name": customer_name,
"customer_email": customer_email,
"subject": customer_subject,
}
def redact_human_address(
value: str | None,
*,
@ -304,6 +347,223 @@ async def resolve_handoff_from_inbound(
return None
async def start_human_initiated_handoff(
database,
*,
account_id: str,
agent_email: str,
parsed: dict,
body_text: str,
body_html: str | None,
raw_mime: dict,
delivery_key: str,
) -> bool:
"""Send the first customer email when a Human Owner writes to Gentic.
Subject shape: handoff · Customer name · customer@email · Subject
The customer receives a normal new email. Later replies from that
customer are mirrored back on the same handoff thread.
"""
initiated = parse_human_initiated_subject(parsed.get("subject"))
if initiated is None:
return False
sender = parsed.get("sender") or {}
human_email = (sender.get("address") or "").strip().lower()
if not human_email:
return False
rules = (
await database.human_handoff_rules.find(
{
"account_id": account_id,
"owner_email": human_email,
"active": True,
}
)
.sort([("priority", 1), ("created_at", 1), ("_id", 1)])
.to_list(length=1)
)
if not rules:
return False
rule = rules[0]
delivery_marker = f"handoff-init:{account_id}:{delivery_key}"
if await database.messages.find_one({"handoff_delivery_key": delivery_marker}):
return True
extracted = extract_new_reply_content(body_text=body_text, body_html=body_html)
rich = None
try:
raw = await get_raw_mime_storage().get(raw_mime)
rich = extract_new_reply_mime_content(raw)
except Exception:
logger.exception(
"handoff_initiate_rich_extract_failed delivery=%s",
delivery_key,
)
new_text = (
rich.body_text if rich and rich.body_text else extracted["new_reply_content"]
).strip()
new_html = rich.body_html if rich and rich.body_html else None
new_text = (
redact_human_address(
new_text,
human_email=human_email,
agent_email=agent_email,
)
or ""
).strip()
new_html = redact_human_address(
new_html,
human_email=human_email,
agent_email=agent_email,
)
if not new_text or not validate_external_reply_body(new_text):
logger.info(
"handoff_initiate_not_sent account_id=%s reason=empty_or_private_body",
account_id,
)
return False
_, domain, sender_name = await _account_and_domain(account_id, agent_email)
customer_name = initiated["customer_name"]
customer_email = initiated["customer_email"]
customer_subject = initiated["subject"]
internet_message_id = await deliver_email(
sender=agent_email,
sender_name=sender_name,
recipients=[customer_email],
cc=[],
bcc=[],
subject=customer_subject,
body_text=new_text,
body_html=new_html,
domain=domain,
reply_to=agent_email,
envelope_sender=agent_email,
inline_parts=getattr(rich, "inline_parts", None),
file_attachments=getattr(rich, "file_attachments", None),
)
now = _now()
normalized_id = canonical_message_id(internet_message_id)
external = {
"direction": "outbound",
"message_scope": MESSAGE_SCOPE_EXTERNAL,
"message_origin": MESSAGE_ORIGIN_HUMAN_OWNER,
"generated_by": GENERATED_BY_HANDOFF_BRIDGE,
"account_id": account_id,
"sender": {"name": sender_name, "address": agent_email.lower()},
"to": [{"name": customer_name, "address": customer_email}],
"cc": [],
"bcc": [],
"subject": customer_subject,
"snippet": _snippet(new_text),
"new_reply_content": new_text,
"body_text": new_text,
"body_html": new_html,
"attachments": [],
"created_at": now,
"sent_at": now,
"status": "accepted",
"thread_relation": "new_thread",
"thread_resolution_method": "human_handoff_initiate",
**message_id_fields(normalized_id),
}
inserted = await database.messages.insert_one(external)
external["_id"] = inserted.inserted_id
thread_id = await create_thread(
database,
account_id=account_id,
subject=customer_subject,
message_id=external["_id"],
event_at=now,
)
await database.mailbox_entries.insert_one(
{
"account_id": account_id,
"message_id": external["_id"],
"thread_id": thread_id,
"mailbox": "sent",
"message_scope": MESSAGE_SCOPE_EXTERNAL,
"direction": "outbound",
"sender": external["sender"],
"recipients": external["to"],
"subject": customer_subject,
"snippet": external["snippet"],
"attachments": [],
"status": "accepted",
"is_read": True,
"is_starred": False,
"event_at": now,
"created_at": now,
"trashed_at": None,
"deletion_state": None,
}
)
handoff = await _create_handoff_mapping(
database,
account_id=account_id,
agent_email=agent_email,
external_message={
"_id": external["_id"],
"sender": {"name": customer_name, "address": customer_email},
"subject": customer_subject,
"message_id": normalized_id,
},
external_thread_id=thread_id,
rule=rule,
)
human_message = await store_handoff_message(
database,
account_id=account_id,
thread_id=handoff["handoff_thread_id"],
direction="inbound",
sender={"name": sender.get("name") or "", "address": human_email},
recipients=[{"name": sender_name, "address": agent_email.lower()}],
subject=handoff["private_subject"],
body_text=body_text,
body_html=body_html,
internet_message_id=parsed.get("message_id"),
in_reply_to=parsed.get("in_reply_to"),
references=parsed.get("references") or [],
handoff_id=handoff["_id"],
event_at=parsed.get("sent_at") or now,
raw_mime=raw_mime,
handoff_delivery_key=delivery_marker,
new_reply_content=new_text,
new_reply_html=new_html,
quoted_content=extracted.get("quoted_content", ""),
message_origin=MESSAGE_ORIGIN_HUMAN_OWNER,
generated_by=GENERATED_BY_HUMAN,
relay_status=RELAY_STATUS_SENT,
)
await database.messages.update_one(
{"_id": human_message["_id"]},
{"$set": {"generated_external_message_id": external["_id"]}},
)
await database.messages.update_one(
{"_id": external["_id"]},
{"$set": {"generated_from_handoff_message_id": human_message["_id"]}},
)
await database.human_handoffs.update_one(
{"_id": handoff["_id"]},
{
"$set": {
"status": HANDOFF_STATUS_HUMAN_REPLIED,
"current_owner": OWNER_AGENT,
"last_human_message_at": now,
"updated_at": now,
}
},
)
logger.info(
"handoff_initiated account_id=%s handoff_id=%s customer=%s",
account_id,
handoff["_id"],
customer_email,
)
return True
async def _record_link(
database,
*,

View file

@ -19,6 +19,7 @@ from app.services.human_handoff_service import (
maybe_trigger_handoff,
process_human_reply,
resolve_handoff_from_inbound,
start_human_initiated_handoff,
)
from app.services.message_ids import canonical_message_id, message_id_fields
from app.services.mime_parser import parse_mime
@ -154,6 +155,23 @@ class InboundHandler:
references=parsed.get("references", []),
)
if handoff is None:
started = await start_human_initiated_handoff(
mongo_db,
account_id=account_id,
agent_email=recipient,
parsed=parsed,
body_text=body_text,
body_html=body_html,
raw_mime=raw_mime,
delivery_key=delivery_key,
)
if started:
logger.info(
"handoff_initiated_from_human account_id=%s message_id=%s",
account_id,
internet_message_id,
)
continue
external_recipients.append(recipient)
continue
await process_human_reply(

View file

@ -17,6 +17,9 @@ TEXT_QUOTE_MARKERS = [
PRIVATE_LEAK_MARKERS = [
"human handoff",
" · handoff · ",
"handoff · ",
"handoff - ",
"handoff | ",
"a conversation needs your attention",
"why this was handed off",
"why you're receiving this",