fix(bot-mode): carry the relay sender into a live Bot Chat turn

When the target Bot Chat is already open on this gateway, the relay handler delivers through
`prompt.submit` with `queued: true`, and that branch dropped the envelope's sender. The model
still saw the text prefix, but the turn reached the agent unattributed, the exact case the
subprocess branch fixes.

The relay handler now stamps the author on the submit as a `DeliveryAuthor`, an in-process object
a JSON client cannot build, so `prompt.submit` accepts it the way it accepts a hosted-room callback
and refuses a dict with error 4124. The busy queue keeps an authored envelope in its own slot, the
drain hands the author to the turn runner, and the runner passes it to an agent that declares the
keyword. A plain prompt after an authored dm carries no author.

Local deliveries to a desktop-owned Bot Chat take the live-owner mailbox instead. The admission
intent and the mailbox record now carry the author, a retry under the same id with a different
author is refused, and the owner gateway hands the author to the turn it runs. Isolated compute
turns still run unattributed, because the compute-host frame has no author field.
This commit is contained in:
Erosika
2026-09-08 10:55:46 -04:00
committed by Teknium
parent 366f9446c9
commit 6881e4d3fc
12 changed files with 231 additions and 68 deletions
+8 -4
View File
@@ -90,10 +90,16 @@ def _(rid, params: dict, _root=_relay_root, _run=_run_delivery) -> dict:
if isinstance(record, dict) and (record.get("profile_home") or None) == want_home
and _session_live_title(
record, _session_lookup_key(record, fallback=live_sid)) == BOT_CHAT_TITLE), "")
# The Desktop forwards the envelope's sender. The author labels memory only and grants nothing.
from tools.bot_relay import DeliveryAuthor, delivery_env, delivery_turn_author
author = delivery_turn_author(params.get("from_profile"), params.get("from_handle"))
if live_sid:
# queued=True: a teammate's DM runs as the NEXT turn and never interrupts or steers a
# turn in flight (the default busy mode does); arrivals queue in order.
submitted = _methods["prompt.submit"](rid, {"session_id": live_sid, "text": message, "queued": True})
submit_params: dict = {"session_id": live_sid, "text": message, "queued": True}
if author:
submit_params["_turn_author"] = DeliveryAuthor(author)
submitted = _methods["prompt.submit"](rid, submit_params)
if "error" in submitted:
return submitted
reply = f"Delivered into @{resolved}'s open Bot Chat; the reply will appear there."
@@ -102,9 +108,7 @@ def _(rid, params: dict, _root=_relay_root, _run=_run_delivery) -> dict:
def _detail(p) -> str:
return (p.stderr or p.stdout or "").strip()[-500:]
# The Desktop forwards the envelope's sender. The author labels memory only and grants nothing.
from tools.bot_relay import delivery_env, delivery_turn_author
turn_env = delivery_env(delivery_turn_author(params.get("from_profile"), params.get("from_handle")))
turn_env = delivery_env(author)
fd, tmp = tempfile.mkstemp(prefix="hermes-relay-dm-", suffix=".txt", text=True)
try: