mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-27 21:50:36 +00:00
* fix(channels): follow Buzz threads mapped in the connection repository With channel_connections enabled, ChannelManager stores a bound author's thread mapping only in the connection repository, but Buzz's thread-follow gate read only the JSON ChannelStore. engaged_thread was therefore always False for authors bound with /connect, and every unmentioned reply in a thread the bot was already answering was silently dropped. Buzz now resolves the connection identity before the mention gate and looks the thread up through lookup_thread_id, a helper extracted from ChannelManager._lookup_thread_id that both sides now share, so the gate and the manager can no longer disagree about which store owns a mapping. * fix(channels): drop the manager's own JSON-store read in the skill whitelist _resolve_available_skill_names fell back to reading the JSON ChannelStore when the caller's lookup_thread_id found nothing. For a bound message that lookup is repo-only, so a legacy unbound mapping for the same chat decided which custom agent's skill whitelist applied. The parameter is now required and the caller passes "" when nothing is mapped. Also pin the Buzz thread-follow fix against the real SQL connection repository (bound through a real /connect) instead of a fake. * docs(changelog): reference #6232 for the Buzz thread-follow fix * fix(channels): log Buzz drops of unmentioned replies with no engaged thread The thread-follow gate was the one drop in _handle_chat_event without a log line. Log it at DEBUG with the thread root and whether the author was bound, matching the allowlist drop, so a report that the bot stopped following replies can be told apart from a lost bind or missing mapping. --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
"""Helpers for attaching persisted channel connection ownership to inbound messages."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from app.channels.message_bus import InboundMessage
|
|
|
|
|
|
async def attach_connection_identity(
|
|
inbound: InboundMessage,
|
|
*,
|
|
repo: Any,
|
|
provider: str,
|
|
workspace_id: str | None,
|
|
fallback_without_workspace: bool = False,
|
|
) -> InboundMessage:
|
|
"""Attach connection metadata to an inbound message when a persisted binding exists."""
|
|
if repo is None:
|
|
return inbound
|
|
|
|
workspace_candidates: list[str | None] = []
|
|
if workspace_id:
|
|
workspace_candidates.append(workspace_id)
|
|
if fallback_without_workspace:
|
|
workspace_candidates.append(None)
|
|
if not workspace_candidates:
|
|
return inbound
|
|
|
|
for candidate in workspace_candidates:
|
|
connection = await repo.find_connection_by_external_identity(
|
|
provider=provider,
|
|
external_account_id=inbound.user_id,
|
|
workspace_id=candidate,
|
|
)
|
|
if connection is None:
|
|
continue
|
|
|
|
inbound.connection_id = connection["id"]
|
|
inbound.owner_user_id = connection["owner_user_id"]
|
|
inbound.workspace_id = connection.get("workspace_id")
|
|
return inbound
|
|
|
|
return inbound
|
|
|
|
|
|
async def lookup_thread_id(msg: InboundMessage, *, repo: Any, store: Any) -> str | None:
|
|
"""Return the DeerFlow thread mapped to *msg*'s conversation/topic, if any.
|
|
|
|
A message carrying a resolved connection is mapped in the connection repository
|
|
and nowhere else (``ChannelManager._store_thread_id`` writes only there); every
|
|
other message is mapped in the JSON ``ChannelStore``. Adapters that gate on "is
|
|
this thread already ours?" must use this rather than reading the store directly,
|
|
or bound users' threads look unengaged.
|
|
"""
|
|
if msg.connection_id and repo is not None:
|
|
return await repo.get_thread_id(msg.connection_id, msg.chat_id, msg.topic_id)
|
|
if store is None:
|
|
return None
|
|
return store.get_thread_id(msg.channel_name, msg.chat_id, topic_id=msg.topic_id)
|