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

@@ -7,6 +7,12 @@ from django.urls import reverse
from django.views import View
from core.clients import transport
from core.events.manticore import (
count_behavioral_events,
get_recent_event_rows,
get_trace_event_rows,
get_trace_ids,
)
from core.events.projection import shadow_compare_session
from core.memory.search_backend import backend_status, get_memory_search_backend
from core.models import (
@@ -56,12 +62,20 @@ class SystemSettings(SuperUserRequiredMixin, View):
template_name = "pages/system-settings.html"
def _counts(self, user):
behavioral_event_rows = 0
try:
behavioral_event_rows = int(count_behavioral_events(user_id=int(user.id)) or 0)
except Exception:
behavioral_event_rows = 0
return {
"chat_sessions": ChatSession.objects.filter(user=user).count(),
"messages": Message.objects.filter(user=user).count(),
"queued_messages": QueuedMessage.objects.filter(user=user).count(),
"message_events": MessageEvent.objects.filter(user=user).count(),
"conversation_events": ConversationEvent.objects.filter(user=user).count(),
"conversation_event_shadow_rows": ConversationEvent.objects.filter(
user=user
).count(),
"behavioral_event_rows": behavioral_event_rows,
"adapter_health_events": AdapterHealthEvent.objects.filter(
user=user
).count(),
@@ -203,6 +217,21 @@ class SystemSettings(SuperUserRequiredMixin, View):
trace_options.append(value)
if len(trace_options) >= 120:
break
if len(trace_options) < 120:
try:
for trace_id in get_trace_ids(
user_id=int(user.id),
limit=max(1, 120 - len(trace_options)),
):
value = str(trace_id or "").strip()
if not value or value in seen_trace_ids:
continue
seen_trace_ids.add(value)
trace_options.append(value)
if len(trace_options) >= 120:
break
except Exception:
pass
service_candidates = {"signal", "whatsapp", "xmpp", "instagram", "web"}
service_candidates.update(
@@ -212,6 +241,18 @@ class SystemSettings(SuperUserRequiredMixin, View):
.values_list("origin_transport", flat=True)
.distinct()[:50]
)
try:
service_candidates.update(
str(item.get("origin_transport") or "").strip().lower()
for item in get_recent_event_rows(
minutes=60 * 24 * 30,
user_id=str(user.id),
limit=500,
)
if str(item.get("origin_transport") or "").strip()
)
except Exception:
pass
service_options = sorted(value for value in service_candidates if value)
event_type_candidates = {
@@ -229,6 +270,18 @@ class SystemSettings(SuperUserRequiredMixin, View):
.values_list("event_type", flat=True)
.distinct()[:80]
)
try:
event_type_candidates.update(
str(item.get("event_type") or "").strip().lower()
for item in get_recent_event_rows(
minutes=60 * 24 * 30,
user_id=str(user.id),
limit=500,
)
if str(item.get("event_type") or "").strip()
)
except Exception:
pass
event_type_options = sorted(value for value in event_type_candidates if value)
return {
@@ -306,10 +359,26 @@ class TraceDiagnosticsAPI(SuperUserRequiredMixin, View):
.select_related("session")
.order_by("ts", "created_at")[:500]
)
data_source = "django"
if not rows:
try:
rows = get_trace_event_rows(
user_id=int(request.user.id),
trace_id=trace_id,
limit=500,
)
except Exception:
rows = []
if rows:
data_source = "manticore"
related_session_ids = []
seen_sessions = set()
for row in rows:
session_id = str(row.session_id or "").strip()
session_id = (
str(row.session_id or "").strip()
if not isinstance(row, dict)
else str(row.get("session_id") or "").strip()
)
if not session_id or session_id in seen_sessions:
continue
seen_sessions.add(session_id)
@@ -319,6 +388,7 @@ class TraceDiagnosticsAPI(SuperUserRequiredMixin, View):
{
"ok": True,
"trace_id": trace_id,
"data_source": data_source,
"count": len(rows),
"related_session_ids": related_session_ids,
"projection_shadow_urls": [
@@ -327,19 +397,56 @@ class TraceDiagnosticsAPI(SuperUserRequiredMixin, View):
],
"events": [
{
"id": str(row.id),
"ts": int(row.ts or 0),
"event_type": str(row.event_type or ""),
"direction": str(row.direction or ""),
"session_id": str(row.session_id or ""),
"id": (
str(row.id)
if not isinstance(row, dict)
else str(row.get("id") or "")
),
"ts": (
int(row.ts or 0)
if not isinstance(row, dict)
else int(row.get("ts") or 0)
),
"event_type": (
str(row.event_type or "")
if not isinstance(row, dict)
else str(row.get("event_type") or "")
),
"direction": (
str(row.direction or "")
if not isinstance(row, dict)
else str(row.get("direction") or "")
),
"session_id": (
str(row.session_id or "")
if not isinstance(row, dict)
else str(row.get("session_id") or "")
),
"projection_shadow_url": (
f"{reverse('system_projection_shadow')}?session_id={str(row.session_id or '').strip()}"
if str(row.session_id or "").strip()
f"{reverse('system_projection_shadow')}?session_id="
f"{(str(row.session_id or '').strip() if not isinstance(row, dict) else str(row.get('session_id') or '').strip())}"
if (
str(row.session_id or "").strip()
if not isinstance(row, dict)
else str(row.get("session_id") or "").strip()
)
else ""
),
"origin_transport": str(row.origin_transport or ""),
"origin_message_id": str(row.origin_message_id or ""),
"payload": dict(row.payload or {}),
"origin_transport": (
str(row.origin_transport or "")
if not isinstance(row, dict)
else str(row.get("origin_transport") or "")
),
"origin_message_id": (
str(row.origin_message_id or "")
if not isinstance(row, dict)
else str(row.get("origin_message_id") or "")
),
"payload": (
dict(row.payload or {})
if not isinstance(row, dict)
else dict(row.get("payload") or {})
),
}
for row in rows
],
@@ -377,18 +484,7 @@ class EventProjectionShadowAPI(SuperUserRequiredMixin, View):
class EventLedgerSmokeAPI(SuperUserRequiredMixin, View):
def get(self, request):
minutes = max(1, int(request.GET.get("minutes") or 120))
service = str(request.GET.get("service") or "").strip().lower()
user_id = str(request.GET.get("user_id") or "").strip() or str(request.user.id)
limit = max(1, min(500, int(request.GET.get("limit") or 200)))
require_types_raw = str(request.GET.get("require_types") or "").strip()
required_types = [
item.strip().lower()
for item in require_types_raw.split(",")
if item.strip()
]
def _recent_rows(self, *, minutes: int, service: str, user_id: str, limit: int):
cutoff_ts = int(time.time() * 1000) - (minutes * 60 * 1000)
queryset = ConversationEvent.objects.filter(ts__gte=cutoff_ts).order_by("-ts")
if service:
@@ -408,6 +504,37 @@ class EventLedgerSmokeAPI(SuperUserRequiredMixin, View):
"trace_id",
)[:limit]
)
if rows:
return rows, "django"
try:
manticore_rows = get_recent_event_rows(
minutes=minutes,
service=service,
user_id=user_id,
limit=limit,
)
except Exception:
manticore_rows = []
return manticore_rows, "manticore" if manticore_rows else "django"
def get(self, request):
minutes = max(1, int(request.GET.get("minutes") or 120))
service = str(request.GET.get("service") or "").strip().lower()
user_id = str(request.GET.get("user_id") or "").strip() or str(request.user.id)
limit = max(1, min(500, int(request.GET.get("limit") or 200)))
require_types_raw = str(request.GET.get("require_types") or "").strip()
required_types = [
item.strip().lower()
for item in require_types_raw.split(",")
if item.strip()
]
rows, data_source = self._recent_rows(
minutes=minutes,
service=service,
user_id=user_id,
limit=limit,
)
event_type_counts = {}
for row in rows:
key = str(row.get("event_type") or "")
@@ -423,6 +550,7 @@ class EventLedgerSmokeAPI(SuperUserRequiredMixin, View):
"minutes": minutes,
"service": service,
"user_id": user_id,
"data_source": data_source,
"count": len(rows),
"event_type_counts": event_type_counts,
"required_types": required_types,