fix(bot-mode): qualify a relayed author from the local connection too
delivery_turn_author kept the bare bot:<profile> id when the sender's connection was the Desktop's own "local", so a DM relayed from that machine collided with the recipient's profile of the same name. A relayed DM always crosses gateways, so the connection id is now part of the id whenever the Desktop sends one, and only the direct message_agent path in tools/bot_mode_dm.py stays bare. The relay.ts and session_auto_continue.py comments added earlier are cut to one line each.
This commit is contained in:
@@ -402,8 +402,7 @@ async function drainRelayOutboxes() {
|
||||
{
|
||||
profile: String(envelope?.target_profile || ''),
|
||||
message: String(envelope?.message || ''),
|
||||
// The target gateway sets HERMES_TURN_AUTHOR on the delivery turn from these; the
|
||||
// sender's connection id qualifies a bot on another machine.
|
||||
// The target gateway builds the delivery turn's HERMES_TURN_AUTHOR from these three.
|
||||
from_profile: String(envelope?.from_profile || ''),
|
||||
from_handle: String(envelope?.from_handle || ''),
|
||||
from_connection: String(sender.id)
|
||||
|
||||
@@ -599,11 +599,12 @@ def test_delivery_turn_author_from_envelope_sender_fields():
|
||||
|
||||
|
||||
def test_delivery_turn_author_qualifies_a_remote_sender_by_its_connection():
|
||||
"""Two machines can both run ``ops``; the Desktop's connection id keeps them apart, and its own gateway
|
||||
(``local``) keeps the bare id."""
|
||||
"""A relayed DM always crosses gateways, so the sender's connection id is part of the author id, ``local``
|
||||
included; the recipient's own ``ops`` is the only bare ``bot:ops``."""
|
||||
remote = bot_relay.delivery_turn_author("ops", "ops-bot", "cloud-1")
|
||||
assert remote == {"id": "bot:cloud-1/ops", "name": "ops-bot", "is_bot": True}
|
||||
assert bot_relay.delivery_turn_author("ops", "ops-bot", "local") == {"id": "bot:ops", "name": "ops-bot", "is_bot": True}
|
||||
assert bot_relay.delivery_turn_author("ops", "ops-bot", "local") == {"id": "bot:local/ops", "name": "ops-bot", "is_bot": True}
|
||||
# An older Desktop that sends no connection id still yields an author.
|
||||
assert bot_relay.delivery_turn_author("ops", "ops-bot", "") == {"id": "bot:ops", "name": "ops-bot", "is_bot": True}
|
||||
|
||||
|
||||
|
||||
+5
-7
@@ -401,18 +401,16 @@ class DeliveryAuthor:
|
||||
|
||||
|
||||
def delivery_turn_author(from_profile: Any, from_handle: Any, from_connection: Any = None) -> Optional[dict]:
|
||||
"""The author of a relayed DM's recipient turn, built from the envelope's sender fields. A sender on another
|
||||
machine is qualified by the Desktop's id for its connection, so two machines' ``scout`` profiles stay distinct.
|
||||
None when the envelope names no sender, so an unattributed delivery stays unattributed."""
|
||||
"""The author of a relayed DM's recipient turn, built from the envelope's sender fields. A relayed DM always
|
||||
comes from another gateway, so the id carries the Desktop's id for the sender's connection (``local`` included)
|
||||
and only the recipient's own profiles are bare ``bot:<profile>``. None when the envelope names no sender."""
|
||||
from agent.turn_author import bot_author_id
|
||||
|
||||
profile = str(from_profile or "").strip()
|
||||
if not profile:
|
||||
return None
|
||||
connection = str(from_connection or "").strip()
|
||||
# The Desktop names its own gateway "local"; that sender keeps the bare id local deliveries always had.
|
||||
origin = connection if connection != "local" else ""
|
||||
return {"id": bot_author_id(profile, origin), "name": str(from_handle or "").strip() or profile, "is_bot": True}
|
||||
return {"id": bot_author_id(profile, str(from_connection or "")), "name": str(from_handle or "").strip() or profile,
|
||||
"is_bot": True}
|
||||
|
||||
|
||||
def delivery_env(author: Optional[dict]) -> dict[str, str]:
|
||||
|
||||
@@ -137,8 +137,7 @@ def _enqueue_prompt(session: dict, text: Any, transport: Any, image_paths: list[
|
||||
# See #84417.
|
||||
_drop_queued_duplicates_of_inflight_user(session)
|
||||
text_only = not image_paths and isinstance(text, str)
|
||||
# Never queue a text-only self-copy of the live prompt: draining it would restart it. Another sender's
|
||||
# identical text is their message, not a copy.
|
||||
# A text-only self-copy of the live prompt would restart it on drain; an authored copy is another sender's message.
|
||||
if text_only and not turn_author and text.strip() == _ac_inflight_original(session) != "":
|
||||
return
|
||||
queued = {"text": text, "transport": transport, **({"image_paths": image_paths} if image_paths else {}),
|
||||
|
||||
Reference in New Issue
Block a user