Lightweight containerized prosody tooling + moved auth scripts + xmpp reconnect/auth stabilization

This commit is contained in:
2026-03-05 02:18:12 +00:00
parent 0718a06c19
commit 2140c5facf
69 changed files with 3767 additions and 144 deletions

View File

@@ -30,6 +30,7 @@ from core.assist.engine import process_inbound_assist
from core.commands.base import CommandContext
from core.commands.engine import process_inbound_message
from core.commands.policies import ensure_variant_policies_for_profile
from core.events.ledger import append_event_sync
from core.messaging import ai as ai_runner
from core.messaging import history
from core.messaging import media_bridge
@@ -53,6 +54,7 @@ from core.models import (
from core.presence import get_settings as get_availability_settings
from core.presence import spans_for_range
from core.realtime.typing_state import get_person_typing_state
from core.transports.capabilities import supports, unsupported_reason
from core.translation.engine import process_inbound_translation
from core.views.workspace import (
INSIGHT_METRICS,
@@ -516,7 +518,8 @@ def _serialize_message(msg: Message) -> dict:
emoji = str(item.get("emoji") or "").strip()
if not emoji:
continue
actor = str(item.get("actor") or "").strip()
# Keep actor/source normalization stable to avoid duplicate/hiding issues.
actor = str(item.get("actor") or "").strip().lower()
source = str(item.get("source_service") or "").strip().lower()
key = (emoji, actor, source)
if key in seen_reactions:
@@ -1811,6 +1814,7 @@ def _reaction_actor_key(user_id, service: str) -> str:
def _resolve_reaction_target(message: Message, service: str, channel_identifier: str) -> dict:
service_key = _default_service(service)
message_source_service = str(getattr(message, "source_service", "") or "").strip().lower()
source_message_id = str(getattr(message, "source_message_id", "") or "").strip()
sender_uuid = str(getattr(message, "sender_uuid", "") or "").strip()
source_chat_id = str(getattr(message, "source_chat_id", "") or "").strip()
@@ -1819,23 +1823,23 @@ def _resolve_reaction_target(message: Message, service: str, channel_identifier:
if service_key == "signal":
target_ts = 0
if source_message_id.isdigit():
if message_source_service == "signal" and source_message_id.isdigit():
target_ts = int(source_message_id)
bridge_ref = _latest_signal_bridge_ref(message)
if not target_ts:
bridge_ref = _latest_signal_bridge_ref(message)
upstream_id = str(bridge_ref.get("upstream_message_id") or "").strip()
if upstream_id.isdigit():
target_ts = int(upstream_id)
if not target_ts:
target_ts = int(bridge_ref.get("upstream_ts") or 0)
if not target_ts:
# Local web messages are only reactable once bridge refs exist.
if not target_ts and message_source_service == "signal":
target_ts = delivered_ts or local_ts
if target_ts <= 0:
return {"error": "signal_target_unresolvable"}
target_author = sender_uuid
if not target_author:
bridge_ref = _latest_signal_bridge_ref(message)
target_author = str(bridge_ref.get("upstream_author") or "").strip()
if (
str(getattr(message, "custom_author", "") or "").strip().upper()
@@ -1856,10 +1860,10 @@ def _resolve_reaction_target(message: Message, service: str, channel_identifier:
}
if service_key == "whatsapp":
target_message_id = source_message_id
target_message_id = source_message_id if message_source_service == "whatsapp" else ""
target_ts = delivered_ts or local_ts
bridge_ref = _latest_whatsapp_bridge_ref(message)
if not target_message_id:
bridge_ref = _latest_whatsapp_bridge_ref(message)
target_message_id = str(bridge_ref.get("upstream_message_id") or "").strip()
if not target_ts:
target_ts = int(bridge_ref.get("upstream_ts") or 0)
@@ -4357,7 +4361,7 @@ class ComposeEngageSend(LoginRequiredMixin, View):
identifier=base["person_identifier"],
)
ts_value = int(ts) if str(ts).isdigit() else int(time.time() * 1000)
Message.objects.create(
created = Message.objects.create(
user=request.user,
session=session,
sender_uuid="",
@@ -4366,6 +4370,23 @@ class ComposeEngageSend(LoginRequiredMixin, View):
delivered_ts=ts_value if str(ts).isdigit() else None,
custom_author="USER",
)
try:
append_event_sync(
user=request.user,
session=session,
ts=ts_value,
event_type="message_created",
direction="out",
actor_identifier="USER",
origin_transport="web",
origin_message_id=str(created.id),
origin_chat_id=str(base["identifier"] or ""),
payload={"message_id": str(created.id), "text": outbound},
raw_payload={},
trace_id="",
)
except Exception:
pass
return JsonResponse({"ok": True, "message": "Shared engage sent."})
@@ -4519,6 +4540,23 @@ class ComposeSend(LoginRequiredMixin, View):
),
message_meta={},
)
try:
append_event_sync(
user=request.user,
session=session,
ts=int(ts),
event_type="message_created",
direction="out",
actor_identifier="USER",
origin_transport="web",
origin_message_id=str(created_message.id),
origin_chat_id=str(base["identifier"] or ""),
payload={"message_id": str(created_message.id), "text": text},
raw_payload={},
trace_id="",
)
except Exception:
pass
command_id = transport.enqueue_runtime_command(
base["service"],
"send_message_raw",
@@ -4591,6 +4629,23 @@ class ComposeSend(LoginRequiredMixin, View):
reply_source_message_id=str(reply_to.id) if reply_to is not None else None,
message_meta={},
)
try:
append_event_sync(
user=request.user,
session=session,
ts=msg_ts,
event_type="message_created",
direction="out",
actor_identifier="USER",
origin_transport="web",
origin_message_id=str(created_message.id),
origin_chat_id=str(base["identifier"] or ""),
payload={"message_id": str(created_message.id), "text": text},
raw_payload={},
trace_id="",
)
except Exception:
pass
if created_message is not None:
async_to_sync(process_inbound_message)(
CommandContext(
@@ -4643,6 +4698,14 @@ class ComposeReact(LoginRequiredMixin, View):
service_key = _default_service(service)
if service_key not in {"signal", "whatsapp"}:
return JsonResponse({"ok": False, "error": "service_not_supported"})
if bool(getattr(settings, "CAPABILITY_ENFORCEMENT_ENABLED", True)) and not supports(service_key, "reactions"):
return JsonResponse(
{
"ok": False,
"error": "unsupported_action",
"reason": unsupported_reason(service_key, "reactions"),
}
)
if not identifier and person is None:
return JsonResponse({"ok": False, "error": "missing_scope"})