Librarian: answer each query back to the bot that sent it
CI / compile (pull_request) Successful in 8s
CI / unit (pull_request) Successful in 26s
CI / integration (pull_request) Successful in 26s

So one librarian can serve several bots (test + deploy) instead of firing
every result/pong at a single static CONJURER_MAIN_BOT.

* The bot includes its own callback address (CONJURER_SELF_CALLBACK) in
  every /query and /ping.
* The librarian stores that callback with the query (persisted with the
  request, so a replay after restart still answers the right bot) and, for
  results, in the OUTBOX entry ({target, payload}) so the resender delivers
  to the origin bot even across a librarian restart.
* Pongs go back to the pinging bot too - otherwise a second bot's health
  check would be ponged to the first and always time out, so it could
  never enable its librarian cog.
* Empty callback falls back to MAIN_BOT_ADDRESS, and a legacy OUTBOX entry
  (raw payload, pre-callback) is still delivered to the default bot, so the
  upgrade is seamless.

Tests: per-origin result delivery + legacy-shape fallback (outbox),
busy/idle pong routed to the callback bot vs default (lifecycle). Suite:
58 unit + 52 integration green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 18:36:49 +02:00
parent ac16b77f56
commit 26b6ab636e
7 changed files with 153 additions and 64 deletions
+6 -2
View File
@@ -349,9 +349,13 @@ def scan_incoming(stop_event: Optional[threading.Event] = None):
def librarian_ping(address: str, endpoint: str, headers: Optional[dict] = None,
timeout: float = 3.0) -> bool:
timeout: float = 3.0, callback: str = "") -> bool:
"""Health-check the librarian by round-tripping a ping through the FULL path.
``callback`` is where THIS bot wants the pong sent back to, so a shared
librarian pongs each bot at its own address (else a second bot's ping would
be ponged to the first and its health check would always time out).
The ping is a pseudo-query that exercises exactly the same machinery a real
search does, on BOTH sides:
@@ -380,7 +384,7 @@ def librarian_ping(address: str, endpoint: str, headers: Optional[dict] = None,
try:
response = requests.post(
f"{address}{endpoint}",
json={"UUID": ping_uuid},
json={"UUID": ping_uuid, "callback": callback},
headers=headers or {},
timeout=timeout,
)