feat: add out-of-process relay transport abstraction for gateway#2490
Conversation
#2485) Add core RelayTransport and CapabilityDescriptor protocols so a thin connector process can own the platform socket and relay normalised events to a headless gateway, enabling NAT-friendly hosting, one gateway fronting many connectors, and lossless scale-to-zero. Wire a transport= seam on Bot plus a generic RelayAdapter in the wrapper. Co-authored-by: MervinPraison <MervinPraison@users.noreply.github.com>
|
@coderabbitai review |
|
/review |
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
✅ Action performedReview finished.
|
|
Warning Review limit reached
Next review available in: 32 seconds Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above from Qodo, Coderabbit, and Gemini first — incorporate their findings. Review areas:
|
Greptile SummaryThis PR adds an out-of-process relay path for gateway-backed bots. The main changes are:
Confidence Score: 4/5This is close, but these issues should be fixed before merging.
src/praisonai/praisonai/bots/bot.py; src/praisonai/praisonai/bots/_relay_adapter.py
|
| Filename | Overview |
|---|---|
| src/praisonai/praisonai/bots/bot.py | Adds relay adapter construction and dormant forwarding, but the relay branch still skips normal session wiring. |
| src/praisonai/praisonai/bots/_relay_adapter.py | Adds relay lifecycle, inbound routing, and outbound relay sends, but the send result shape still differs from existing adapters. |
| src/praisonai-agents/praisonaiagents/gateway/protocols.py | Adds relay capability descriptors and a relay transport protocol. |
| src/praisonai-agents/praisonaiagents/gateway/init.py | Exports the new relay protocol symbols from the gateway package. |
Reviews (2): Last reviewed commit: "fix(bots): route relay inbound to agent ..." | Re-trigger Greptile
| reply_to=reply_to, | ||
| metadata={"thread_id": thread_id} if thread_id else {}, | ||
| ) | ||
| return await self._transport.send_outbound(target, message) |
There was a problem hiding this comment.
Bot.send_message() now returns the raw DeliveryResult from RelayTransport.send_outbound on the relay path, while the existing platform adapters return BotMessage objects for the same adapter method. Code that reads the normal send result fields can fail only when transport= is supplied.
|
@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding. Phase 1: Review per AGENTS.md
Phase 2: FIX Valid Issues Phase 3: Final Verdict |
|
Claude finished @MervinPraison's task —— View job Claude — Final Architecture Review (PR #2490)
Architecture validation (per AGENTS.md)
Valid reviewer issues found & FIXEDGreptile's P1 was real and blocking: Implemented:
Skipped (with reasoning)
Verdict — ✅ Approve (blocking issues resolved)Files modified: Tests: core relay (7) ✅ · new relay adapter (4) ✅ · related bots suite (118) ✅ — no regressions. |
Address blocking reviewer feedback (Greptile P1/P2) on the relay seam: - RelayAdapter now builds a real BotSessionManager and routes relayed inbound GatewayMessages through session.chat() to the configured agent, relaying the reply back down the transport. Previously inbound only fired manual on_message handlers, so a headless gateway never replied and bypassed the BotOS-spliced admission gate / identity / delivery wiring (which duck-types on adapter._session). - Bot.go_dormant() forwarder so scale-to-zero controllers can ask the out-of-process connector to keep buffering while the gateway sleeps. - Add wrapper unit tests for inbound->agent routing, manual-handler coexistence, session/admission splice point, and dormant forwarding. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
|
@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding. Phase 1: Review per AGENTS.md
Phase 2: FIX Valid Issues Phase 3: Final Verdict |
|
Claude finished @MervinPraison's task —— View job Claude — Final Architecture Review (PR #2490)
State checkThe prior reviewer run (commit Architecture validation (per AGENTS.md)
Reviewer issues — status
Tests (run locally on this branch)
Verdict — ✅ ApproveAll blocking reviewer issues (Greptile P1×2, P2 dormant) are resolved and committed; the one skipped P2 is a non-blocking design choice. Architecture conforms to AGENTS.md (protocol-driven, backward-compatible, no Agent bloat, no hot-path regression, real SDK value). No new commits needed this run. |
| return RelayAdapter( | ||
| transport=self._transport, | ||
| platform=self._platform, | ||
| agent=agent, | ||
| config=self._config, | ||
| ) |
There was a problem hiding this comment.
This relay branch returns the adapter before the normal session wiring below can attach the configured identity resolver, delivery router, and admission gate. RelayAdapter.start() creates a _session, but that session keeps those fields unset because the splice code is only reached on the non-relay path. When a relay-backed bot is created with an admission gate, connector-delivered inbound traffic can still enter session.chat() without the gate or identity normalization that an in-process adapter receives. Please route the relay adapter through the same post-construction session wiring before inbound dispatch starts.
| reply_to=reply_to, | ||
| metadata={"thread_id": thread_id} if thread_id else {}, | ||
| ) | ||
| return await self._transport.send_outbound(target, message) |
There was a problem hiding this comment.
This returns the raw DeliveryResult from send_outbound(), while the existing adapter contract returns a BotMessage from send_message(). Bot.send_message() forwards the adapter result unchanged, so relay-backed callers that read normal fields such as message_id, channel, or message_type can fail at runtime only when transport= is used. Please translate the relay transport response into the same BotMessage shape returned by the other adapters.
Fixes #2485
Summary
Adds a protocol-first relay seam so a thin connector process can own the platform socket (Telegram/Discord/WhatsApp/…) and relay normalised events to a headless gateway over an authenticated transport. This unblocks NAT-friendly hosting, one gateway fronting many remotely-hosted connectors, and lossless scale-to-zero (the connector keeps buffering while the gateway is dormant).
Changes
Core (
praisonaiagents/gateway) — protocols only, no heavy imports:CapabilityDescriptor(frozen dataclass): a capability profile a connector attests at handshake time (max_message_length,length_unitchars/utf16,supports_edit,supports_draft_streaming,markdown_dialect) withas_dict/from_dict.RelayTransport(@runtime_checkableProtocol):connect() -> CapabilityDescriptor,set_inbound_handler,send_outbound,go_dormant,disconnect.praisonaiagents.gateway.Wrapper (
praisonai/bots) — concrete, optional touch:transport=parameter onBot; when supplied,_build_adapter()short-circuits to a genericRelayAdapterinstead of building an in-process platform adapter.RelayAdapterdrives anyRelayTransport: connects + negotiates capabilities, dispatches relayed inboundGatewayMessages to handlers, relays outbound sends, and forwardsgo_dormant()for lossless scale-to-zero. Presents the same adapter contract (start/stop/is_running/send_message).Backward-compatible (new optional param/protocols only); no new dependencies.
Usage
Testing
tests/unit/test_gateway_relay_transport.py— 7 passing (descriptor defaults/frozen/roundtrip, structural conformance, handshake+send).Generated with Claude Code