Skip to content

feat: custom gateway adapter + Telegram PoC#546

Merged
thepagent merged 10 commits intomainfrom
feat/custom-gateway
Apr 24, 2026
Merged

feat: custom gateway adapter + Telegram PoC#546
thepagent merged 10 commits intomainfrom
feat/custom-gateway

Conversation

@chaodu-agent
Copy link
Copy Markdown
Collaborator

@chaodu-agent chaodu-agent commented Apr 24, 2026

Description

Implements the v2 custom gateway architecture from ADR: Custom Gateway. OAB connects outbound to a standalone gateway service via WebSocket — no inbound ports, no TLS on OAB.

Architecture

Telegram ──POST──▶ Gateway (:8080)
                      ▲ WebSocket (OAB initiates outbound)
                   OAB Pod (gateway.rs adapter)
                      ▼
                   AdapterRouter → SessionPool → kiro-cli

OAB Changes (generic, platform-agnostic)

  • src/gateway.rsGatewayAdapter implementing ChatAdapter over WebSocket
  • src/config.rs[gateway] config with url, platform, token fields (+12 lines)
  • src/main.rs — spawn gateway adapter alongside Slack/Discord (+22 lines)

Gateway Service (Telegram-specific, standalone)

  • gateway/ — axum HTTP + WebSocket server with own Dockerfile
  • Telegram webhook → normalize to openab.gateway.event.v1
  • OAB replies → Telegram sendMessage API
  • create_topic command → Telegram createForumTopic for forum thread isolation
  • secret_token validation on webhook, shared token auth on WebSocket

Config

[gateway]
url = "ws://gateway:8080/ws"
platform = "telegram"          # session key namespace (default: telegram)
token = "${GATEWAY_WS_TOKEN}"  # shared WS auth token (recommended)

Testing

  • E2E verified locally: Telegram DM → Gateway → OAB → kiro-cli → reply → Telegram
  • Supergroup forum topic creation tested (requires bot Manage Topics permission)
  • Cloudflare Tunnel used for HTTPS webhook endpoint

Follow-up (not in this PR)

  • CI/CD: add build-gateway.yml workflow to build and push ghcr.io/openabdev/openab-gateway image
  • Helm: gateway subchart or standalone chart
  • LINE adapter
  • Generic /webhook/custom endpoint
  • @mention gating using the mentions field in group chats

Implements the v2 custom gateway architecture from ADR docs/adr/custom-gateway.md:

OAB side (generic, platform-agnostic):
- src/gateway.rs: GatewayAdapter implementing ChatAdapter over WebSocket
- src/config.rs: [gateway] config section with url field
- src/main.rs: spawn gateway adapter alongside Slack/Discord

Gateway service (Telegram-specific, standalone binary):
- gateway/: axum HTTP + WebSocket server
- Telegram webhook → normalize to openab.gateway.event.v1
- OAB replies → Telegram sendMessage API
- create_topic command → Telegram createForumTopic for thread isolation

Tested end-to-end: Telegram → Gateway → OAB → kiro-cli → reply → Telegram
@chaodu-agent chaodu-agent requested a review from thepagent as a code owner April 24, 2026 11:07
@github-actions github-actions Bot added the closing-soon PR missing Discord Discussion URL — will auto-close in 3 days label Apr 24, 2026
@github-actions
Copy link
Copy Markdown

⚠️ This PR is missing a Discord Discussion URL in the body.

All PRs must reference a prior Discord discussion to ensure community alignment before implementation.

Please edit the PR description to include a link like:

Discord Discussion URL: https://discord.com/channels/...

This PR will be automatically closed in 3 days if the link is not added.

@github-actions github-actions Bot added the pending-screening PR awaiting automated screening label Apr 24, 2026
@shaun-agent
Copy link
Copy Markdown
Contributor

OpenAB PR Screening

This is auto-generated by the OpenAB project-screening flow for context collection and reviewer handoff.
Click 👍 if you find this useful. Human review will be done within 24 hours. We appreciate your support and contribution 🙏

Screening report ## Intent

This PR is trying to add a new integration boundary for OpenAB: instead of embedding platform-specific webhook handling inside the main OAB process, OAB can connect outbound to a standalone gateway service over WebSocket. The immediate operator-visible problem it solves is deployment friction for platforms like Telegram, where inbound HTTPS webhooks, TLS, and public exposure are awkward or undesirable inside the OAB pod. The user-visible goal is to let Telegram messages reach OpenAB sessions and receive replies, including forum-topic isolation for supergroups.

Feat

This is primarily a feature, with some architectural refactoring. In plain terms: OpenAB gains a generic GatewayAdapter that speaks a normalized event protocol over WebSocket, and the PR ships a Telegram proof of concept gateway service that accepts Telegram webhooks, translates them into OpenAB events, and relays replies back through Telegram APIs.

Who It Serves

The primary beneficiary is deployers and agent runtime operators who want to run OpenAB behind outbound-only connectivity, or add new chat platforms without baking each platform directly into the main binary. Secondary beneficiaries are Telegram end users, because they gain a working OpenAB integration path, and maintainers, because the platform-specific code can move to a separate service boundary.

Rewritten Prompt

Implement the custom gateway architecture behind a clear, minimal contract. Add a platform-agnostic GatewayAdapter to OpenAB that connects outbound to a configured WebSocket endpoint, consumes normalized inbound chat events, and sends normalized outbound reply actions. Ship the Telegram integration as a separate gateway service that converts Telegram webhook traffic into the shared event schema and maps OpenAB replies back to Telegram APIs. Keep the OpenAB-side integration generic, validate reconnect/error behavior, document deployment topology and config, and add focused tests or fixtures for protocol correctness and failure handling.

Merge Pitch

This item is worth advancing because it opens a cleaner expansion path for non-Slack, non-Discord channels while reducing deployment requirements on the core OAB service. The risk profile is medium: the architectural direction is strong, but reviewers will likely worry about durability, delivery guarantees, reconnection behavior, and whether the Telegram PoC is too tightly coupled to a supposedly generic gateway model.

Best-Practice Comparison

Against OpenClaw, the relevant principles are explicit delivery routing, isolated executions, durable job persistence, and retry/run visibility. This PR clearly moves toward explicit delivery routing by introducing a gateway boundary and normalized event flow. It appears weaker on durable persistence, retry/backoff policy, and operational run logs; the summary describes successful E2E behavior, but not durable queueing or replay semantics if OAB or the gateway disconnects mid-run.

Against Hermes Agent, the most relevant principles are gateway-owned scheduling only in the broader sense of gateway-owned ingress, atomic persisted state, overlap protection, fresh session boundaries, and self-contained task payloads. Scheduling itself is not central here, so that comparison is only partially relevant. What does fit is the idea that the gateway should own ingress concerns cleanly, persist state safely if needed, and send self-contained normalized payloads into OAB. The PR aligns with the boundary separation principle, but the provided summary does not show file locking, atomic persistence, or other safeguards because this appears to be a live chat transport rather than a scheduled-run daemon.

Implementation Options

  1. Conservative option: merge only the generic OpenAB-side GatewayAdapter and config plumbing, but hold the Telegram gateway out of tree or behind a draft/example status until protocol, reliability expectations, and ownership boundaries are tightened.

  2. Balanced option: merge the OpenAB adapter plus the Telegram gateway PoC together, but explicitly mark the gateway protocol as v1 experimental, add reconnect/error-handling tests, and document current non-goals such as no durable persistence or at-least-once guarantees.

  3. Ambitious option: expand the gateway architecture before merge into a fuller integration subsystem with a versioned protocol spec, delivery acknowledgements, retry/backoff, persisted pending events, structured run logs, and a cleaner abstraction for multiple external gateway implementations beyond Telegram.

Comparison Table

Option Speed to ship Complexity Reliability Maintainability User impact Fit for OpenAB right now
Conservative: core adapter only Fast Low Medium High Medium Strong if reviewers want architecture first
Balanced: adapter + Telegram PoC with guardrails Medium Medium Medium Medium-High High Best overall fit
Ambitious: full protocol hardening first Slow High High High if finished well High Likely too heavy for immediate merge

Recommendation

Recommend the balanced option.

It preserves the main value of the PR: proving the custom gateway direction with a real Telegram path, not just an abstract interface. At the same time, it keeps the merge discussion disciplined by framing the gateway protocol as intentionally minimal and experimental, with explicit documentation around current delivery semantics, reconnect behavior, and operational limits. That gives Masami or Pahud a concrete artifact to review without pretending the reliability story is already complete.

The likely follow-up split is straightforward: first merge the generic gateway boundary plus Telegram PoC with documented constraints; then iterate in separate PRs on protocol hardening, delivery acknowledgements, persistence, and broader multi-platform gateway support.

1. Telegram secret_token validation (ADR Compliance #4):
   - TELEGRAM_SECRET_TOKEN env var → checks X-Telegram-Bot-Api-Secret-Token header
   - Returns 401 on mismatch, warns at startup if not configured

2. WebSocket reconnect with exponential backoff:
   - 1s → 2s → 4s → ... → 30s cap
   - Connection failures and WS disconnects both trigger reconnect
   - Shutdown signal checked at every wait point

3. Mentions field (ADR schema requirement):
   - Added mentions: Vec<String> to GatewayEvent
   - Gateway parses Telegram entities type=mention → @username list
   - OAB deserializes with serde(default) for backward compat
@chaodu-agent
Copy link
Copy Markdown
Collaborator Author

三法師 Consolidated Triage Review — PR #546

CHANGES_REQUESTED 🔴 — Architecture direction is correct and aligns with the merged ADR: Custom Gateway. The latest commit (1a0a907) addressed webhook signature validation, WebSocket reconnect, and the mentions field. Three blockers remain.

Reviewers: 超渡法師 (Claude) · 擺渡法師 (Codex) · 覺渡法師 (Gemini)


🔴 Must-Fix Before Merge

1. CI Clippy Failure (擺渡)
cargo clippy -- -D warnings fails. Message::Text(json.into()) useless conversions in src/gateway.rs (lines ~144, ~179). This is a required check — PR cannot merge while red.

2. platform() Returns Fixed "gateway" → Session Namespace Collision (擺渡 + 覺渡)
GatewayAdapter::platform() returns "gateway" instead of the actual platform (e.g. "telegram"). Session keys are constructed from adapter.platform() + channel/thread ID. Once a second platform connects through the gateway, cross-platform session collisions are inevitable. Suggestion: propagate the platform field from the inbound event, or accept it as a config parameter.

3. WebSocket Endpoint Has No Authentication (覺渡, 擺渡 confirmed)
GatewayConfig only has url. The gateway /ws endpoint accepts any connection with no auth. Anyone who discovers the gateway address can receive the full message stream or impersonate OAB. The ADR itself states: "the internal WebSocket connection must use mTLS or equivalent authentication." Suggestion: at minimum, add a shared access_token validated via header on WS upgrade.


🟡 Important Design Gaps (non-blocking, should track)

# Issue Found by
1 SenderContext schema is "sender.v1" — should be "openab.sender.v1" per existing convention 覺渡
2 OAB-side GatewayEvent struct omits timestamp field present in gateway-side schema 覺渡
3 gateway/ crate not covered by CI workflows (trigger paths, cargo check/clippy/test) 擺渡
4 Multi-client broadcast semantics — all connected OAB instances receive all inbound events, causing duplicate processing 超渡 + 覺渡, scoped by 擺渡
5 gateway/ not included in root Dockerfile build 覺渡, de-escalated by 擺渡

🟢 Cleanup (non-blocking)

# Issue Found by
1 reply_handlers: Vec<Sender> only pushed, never cleaned on disconnect (memory leak) 超渡 + 覺渡
2 tempfile added to [dependencies] in root Cargo.toml — should be [dev-dependencies] 超渡 + 覺渡
3 gateway/Cargo.lock adds 2289 lines 超渡
4 Unbounded tokio::spawn per message — no concurrency limit or rate control 覺渡
5 Inner loop indentation inconsistency in src/gateway.rs (rustfmt) 超渡

🟢 Positive Observations

  • OAB-side changes are minimal and clean: config.rs +7 lines, main.rs +22 lines — zero impact on existing Discord/Slack paths
  • ChatAdapter trait implementation is complete
  • Telegram forum topic support (create_topic command) is a nice touch for conversation isolation
  • Gateway README is well-written with architecture diagrams, quick start, and platform setup instructions
  • Shutdown handling with watch channel is correct
  • Reconnect with exponential backoff (post-fix) is solid

Note: This PR is missing a Discord Discussion URL and is tagged closing-soon. Please add the discussion link to prevent auto-close.

This review follows the PR Review Practice baseline-check SOP and traffic light triage format.

1. Fix clippy -D warnings: dead_code annotations, remove useless .into()
2. platform() now returns configurable name (default: telegram) instead
   of hardcoded 'gateway' — prevents session key collision across platforms
3. Add shared token WS auth: OAB sends token as query param, gateway
   validates before upgrading WebSocket. Config: gateway.token / GATEWAY_WS_TOKEN
4. Both sides warn at startup if auth tokens are not configured
Must-fix:
- SenderContext schema: 'sender.v1' → 'openab.sender.v1' (matches discord/slack)
- Graceful shutdown: replace tokio::spawn with JoinSet, drain in-flight
  tasks on shutdown and before reconnect

Design/cleanup:
- Add timestamp field to OAB-side GatewayEvent (ADR alignment)
- Remove unused reply_handlers vec (dead code, potential leak)
@thepagent thepagent merged commit 0ef93dd into main Apr 24, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

closing-soon PR missing Discord Discussion URL — will auto-close in 3 days feature pending-screening PR awaiting automated screening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants