Implement Manticore fully and re-theme

This commit is contained in:
2026-03-11 02:19:08 +00:00
parent da044be68c
commit cbedcd67f6
46 changed files with 3444 additions and 944 deletions

View File

@@ -1,5 +1,6 @@
import asyncio
import re
import time
from asgiref.sync import sync_to_async
from django.conf import settings
@@ -12,7 +13,8 @@ from core.clients.whatsapp import WhatsAppClient
from core.clients.xmpp import XMPPClient
from core.commands.base import CommandContext
from core.commands.engine import process_inbound_message
from core.events import event_ledger_status
from core.events import append_event, event_ledger_enabled, event_ledger_status
from core.events.behavior import ComposingTracker
from core.messaging import history
from core.models import PersonIdentifier
from core.observability.tracing import ensure_trace_id
@@ -32,7 +34,13 @@ class UnifiedRouter(object):
self.typing_auto_stop_seconds = int(
getattr(settings, "XMPP_TYPING_AUTO_STOP_SECONDS", 3)
)
self.composing_abandoned_window_seconds = int(
getattr(settings, "COMPOSING_ABANDONED_WINDOW_SECONDS", 300)
)
self._typing_stop_tasks = {}
self._composing_tracker = ComposingTracker(
window_ms=self.composing_abandoned_window_seconds * 1000
)
self.log = logs.get_logger("router")
self.log.info("Initialised Unified Router Interface.")
@@ -85,6 +93,55 @@ class UnifiedRouter(object):
self._typing_stop_tasks[key] = self.loop.create_task(_timer())
def _behavior_direction(self, protocol: str) -> str:
return "out" if str(protocol or "").strip().lower() == "xmpp" else "in"
def _event_ts_from_kwargs(self, kwargs: dict) -> int | None:
payload = dict(kwargs.get("payload") or {})
for candidate in (
kwargs.get("ts"),
payload.get("ts"),
payload.get("timestamp"),
payload.get("messageTimestamp"),
payload.get("message_ts"),
):
try:
parsed = int(candidate)
except Exception:
continue
if parsed > 0:
return parsed
return int(time.time() * 1000)
async def _append_identifier_event(
self,
*,
identifier_row,
event_type: str,
protocol: str,
direction: str,
ts: int | None = None,
payload: dict | None = None,
raw_payload: dict | None = None,
actor_identifier: str = "",
):
if not event_ledger_enabled():
return None
session = await history.get_chat_session(identifier_row.user, identifier_row)
await append_event(
user=identifier_row.user,
session=session,
ts=ts,
event_type=event_type,
direction=direction,
actor_identifier=str(actor_identifier or identifier_row.identifier or ""),
origin_transport=str(protocol or "").strip().lower(),
origin_chat_id=str(identifier_row.identifier or ""),
payload=dict(payload or {}),
raw_payload=dict(raw_payload or {}),
)
return session
def _start(self):
self.log.info("Starting unified router clients")
self.xmpp.start()
@@ -117,6 +174,9 @@ class UnifiedRouter(object):
message_text = str(kwargs.get("text") or "").strip()
if local_message is None:
return
self._composing_tracker.observe_message(
str(getattr(local_message, "session_id", "") or "")
)
identifiers = await self._resolve_identifier_objects(protocol, identifier)
if identifiers:
outgoing = str(
@@ -239,6 +299,10 @@ class UnifiedRouter(object):
timestamps = kwargs.get("message_timestamps") or []
read_ts = kwargs.get("read_ts")
payload = kwargs.get("payload") or {}
payload_type = str((payload or {}).get("type") or "").strip().lower()
receipt_event_type = (
"delivery_receipt" if payload_type == "delivered" else "read_receipt"
)
trace_id = (
ensure_trace_id(payload=payload)
if bool(getattr(settings, "TRACE_PROPAGATION_ENABLED", True))
@@ -257,6 +321,7 @@ class UnifiedRouter(object):
read_by_identifier=read_by or row.identifier,
payload=payload,
trace_id=trace_id,
receipt_event_type=receipt_event_type,
)
record_native_signal(
AvailabilitySignal(
@@ -264,12 +329,13 @@ class UnifiedRouter(object):
person=row.person,
person_identifier=row,
service=str(protocol or "").strip().lower(),
source_kind="read_receipt",
source_kind=receipt_event_type,
availability_state="available",
confidence=0.95,
ts=int(read_ts or 0),
payload={
"origin": "router.message_read",
"receipt_event_type": receipt_event_type,
"message_timestamps": [
int(v) for v in list(timestamps or []) if str(v).isdigit()
],
@@ -309,11 +375,41 @@ class UnifiedRouter(object):
payload=payload,
)
)
state_event = None
if state == "available":
state_event = "presence_available"
elif state == "unavailable":
state_event = "presence_unavailable"
if state_event:
try:
await self._append_identifier_event(
identifier_row=row,
event_type=state_event,
protocol=protocol,
direction="system",
ts=(ts or None),
payload={
"state": state,
"confidence": confidence,
**payload,
},
raw_payload=payload,
actor_identifier=str(row.identifier or ""),
)
except Exception as exc:
self.log.warning(
"Failed to append presence event for %s: %s",
row.identifier,
exc,
)
await self._refresh_workspace_metrics_for_identifiers(identifiers)
async def started_typing(self, protocol, *args, **kwargs):
self.log.info(f"Started typing ({protocol}) {args} {kwargs}")
identifier = kwargs.get("identifier")
payload = dict(kwargs.get("payload") or {})
event_ts = self._event_ts_from_kwargs(kwargs)
direction = self._behavior_direction(protocol)
identifiers = await self._resolve_identifier_objects(protocol, identifier)
for src in identifiers:
record_native_signal(
@@ -329,6 +425,30 @@ class UnifiedRouter(object):
payload={"origin": "router.started_typing"},
)
)
try:
session = await history.get_chat_session(src.user, src)
state = self._composing_tracker.observe_started(
str(session.id),
int(event_ts or 0),
)
await append_event(
user=src.user,
session=session,
ts=event_ts,
event_type="typing_started",
direction=direction,
actor_identifier=str(src.identifier or ""),
origin_transport=str(protocol or "").strip().lower(),
origin_chat_id=str(src.identifier or ""),
payload=dict(payload or {}, revision=int(state.revision or 1)),
raw_payload=dict(payload or {}),
)
except Exception as exc:
self.log.warning(
"Failed to append typing-start event for %s: %s",
src.identifier,
exc,
)
if protocol != "xmpp":
set_person_typing_state(
user_id=src.user_id,
@@ -362,6 +482,9 @@ class UnifiedRouter(object):
async def stopped_typing(self, protocol, *args, **kwargs):
self.log.info(f"Stopped typing ({protocol}) {args} {kwargs}")
identifier = kwargs.get("identifier")
payload = dict(kwargs.get("payload") or {})
event_ts = self._event_ts_from_kwargs(kwargs)
direction = self._behavior_direction(protocol)
identifiers = await self._resolve_identifier_objects(protocol, identifier)
for src in identifiers:
record_native_signal(
@@ -377,6 +500,52 @@ class UnifiedRouter(object):
payload={"origin": "router.stopped_typing"},
)
)
try:
session = await history.get_chat_session(src.user, src)
await append_event(
user=src.user,
session=session,
ts=event_ts,
event_type="typing_stopped",
direction=direction,
actor_identifier=str(src.identifier or ""),
origin_transport=str(protocol or "").strip().lower(),
origin_chat_id=str(src.identifier or ""),
payload=dict(payload or {}),
raw_payload=dict(payload or {}),
)
if session is not None:
abandoned = self._composing_tracker.observe_stopped(
str(session.id),
int(event_ts or 0),
)
if abandoned is not None:
await append_event(
user=src.user,
session=session,
ts=int(abandoned.get("stopped_ts") or event_ts or 0),
event_type="composing_abandoned",
direction=direction,
actor_identifier=str(src.identifier or ""),
origin_transport=str(protocol or "").strip().lower(),
origin_chat_id=str(src.identifier or ""),
payload={
**dict(payload or {}),
"abandoned": True,
"duration_ms": int(
abandoned.get("duration_ms") or 0
),
"revision": int(abandoned.get("revision") or 1),
"started_ts": int(abandoned.get("started_ts") or 0),
},
raw_payload=dict(payload or {}),
)
except Exception as exc:
self.log.warning(
"Failed to append typing-stop event for %s: %s",
src.identifier,
exc,
)
if protocol != "xmpp":
set_person_typing_state(
user_id=src.user_id,