Skip to content

Feature/gateway code#3317

Merged
davincios merged 11 commits into
mainfrom
feature/gateway-code
Jun 30, 2026
Merged

Feature/gateway code#3317
davincios merged 11 commits into
mainfrom
feature/gateway-code

Conversation

@davincios

Copy link
Copy Markdown
Contributor

Fixes #

Describe the changes you have made in this PR -

Demo/Screenshot for feature changes and bug fixes -


Code Understanding and AI Usage

Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?

  • No, I wrote all the code myself
  • Yes, I used AI assistance (continue below)

If you used AI assistance:

  • I have reviewed every single line of the AI-generated code
  • I can explain the purpose and logic of each function/component I added
  • I have tested edge cases and understand how the code handles them
  • I have modified the AI output to follow this project's coding standards and conventions

Explain your implementation approach:


Checklist before requesting a review

  • I have added proper PR title and linked to the issue
  • I have performed a self-review of my code
  • I can explain the purpose of every function, class, and logic block I added
  • I understand why my changes work and have tested them thoroughly
  • I have considered potential edge cases and how my code handles them
  • If it is a core feature, I have added thorough tests
  • My code follows the project's style guidelines and conventions

Note: Please check Allow edits from maintainers if you would like us to assist in the PR.

davincios and others added 10 commits June 29, 2026 22:15
Split gateway into focused packages (config, storage, routers, core) so
turn execution, inbound routing, and background poll logic live under
gateway/core/, with function-oriented settings loading and updated imports.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

Greptile code review

This repo uses Greptile for automated review. Before merge, aim for Confidence Score: 5/5 with zero unresolved review threads — see CONTRIBUTING.md.

Run a review — add a PR comment with:

@greptile review

Give it ~5-10 minutes (sometimes longer) for results, then fix feedback and re-trigger until you reach Confidence Score: 5/5.

Optional: automate with the greploop skill.

Resolve conflicts by keeping the follow-up gateway work: dedicated-process
only startup, improved gateway logging, and no REPL co-located gateway.

Co-authored-by: Cursor <cursoragent@cursor.com>
@davincios davincios merged commit 1fdb2b6 into main Jun 30, 2026
5 of 6 checks passed
@davincios davincios deleted the feature/gateway-code branch June 30, 2026 01:05
@github-actions

Copy link
Copy Markdown
Contributor

🧠 @davincios opened a PR. Maintainers feared them. CI genuflected. It merged. 🚨


👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome.

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces the previous FastAPI/webhook gateway with a fully long-poll-only Telegram gateway. The monolithic gateway/runner.py, gateway/app.py, gateway/background.py, and gateway/turn_executor.py are deleted and replaced by a cleanly layered module tree under gateway/{agent,config,polling,session,storage}, each with co-located tests under gateway/tests/.

  • Architecture restructure: the gateway is split into distinct layers — polling transport (polling/), session management (session/), agent dispatch (agent/), and persistence (storage/) — with start_gateway.py as the new clean entry-point.
  • Agent integration: the old execute_shell_turn path is replaced by dispatch_message_to_headless_agent with purpose-built adapter classes implementing core.agent_harness.ports.
  • Security: inbound authorization and session resolution are now separate, explicit steps with audit logging and pairing support.

Confidence Score: 3/5

Safe to merge once the unbounded recursion in _resolve_provider_models is addressed; the remaining findings are low-risk quality improvements.

The provider alias resolution in gateway_agent_adapters.py recurses without any cycle guard. A circular alias configuration silently fails every gateway turn with a user-visible error until the config is fixed, and the failure is only recoverable by an operator. The rest of the rewrite is well-structured with clean layering, solid error handling, and co-located tests.

gateway/agent/gateway_agent_adapters.py needs the cycle-detection fix in _resolve_provider_models. gateway/config/get_gateway_settings.py has a dead branch worth cleaning up. gateway/polling/telegram_poller/poller.py should mask the token in logged URLs.

Security Review

  • Bot token exposure in logs (gateway/polling/telegram_poller/poller.py): the bot token is embedded directly in the getUpdates URL path. Some httpx transport exceptions include the request URL in their string representation; if a network error is logged, the token would appear in plain text.
  • No other secrets, credential leakage, injection, or auth-boundary issues were identified. The inbound authorization flow correctly requires explicit user-ID allowlisting and audits every message.

Important Files Changed

Filename Overview
gateway/agent/gateway_agent_adapters.py Provides adapter classes for the headless agent harness; contains _resolve_provider_models which recurses without cycle detection — a circular provider alias would overflow the stack.
gateway/config/get_gateway_settings.py Loads Telegram gateway settings from env + integration store with solid validation; contains a dead-code branch (if not settings.bot_token) unreachable after load_gateway_settings raises on missing token.
gateway/session/resolve_or_rotate_session.py Applies security decision side effects and resolves/rotates sessions; uses a magic-string sentinel "__ROTATE_SESSION__" as an inter-module protocol that is fragile if the string ever diverges.
gateway/agent/dispatch_gateway_msg_to_agent.py Orchestrates a full headless agent turn with solid exception handling, Sentry reporting, and graceful sink finalization.
gateway/agent/gateway_action_tools.py Defines gateway-local shell and investigation tools with clear deny/allow policy, timeout enforcement, and output truncation.
gateway/polling/telegram_poller/poller.py Long-poll transport with conflict backoff and throttled warning logs; bot token embedded in the URL path may appear in httpx exception strings under some network failure modes.
gateway/polling/telegram_polling_runtime.py Wires shared polling resources (client, db, executor) and provides clean initialize/shutdown lifecycle callbacks.
gateway/storage/session/resolver.py Session resolution backed by SQLite bindings with correct user_id keying and safe rotate logic.
gateway/session/enforce_inbound_telegram_message_security.py Inbound authorization with /pair, /new, /help commands and audit logging; env user IDs are applied in-memory without accidental persistence.
gateway/agent/gateway_output_sink.py Throttled streaming sink using edit_message_text with a lock protecting the Telegram API call; clean finalize/render_error paths.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant TB as Telegram Bot API
    participant TP as TelegramPoller
    participant BG as TelegramGatewayBackground
    participant H as handle_polled_inbound_msg
    participant Auth as enforce_security
    participant SR as SessionResolver
    participant D as dispatch_gateway_msg_to_agent
    participant Sink as GatewayOutputSink

    loop Long Poll
        TP->>TB: "getUpdates (timeout=30, offset)"
        TB-->>TP: Update events
    end
    TP-->>BG: list[TelegramInboundMessage]
    BG->>H: event (per update)
    H->>Auth: enforce_inbound_telegram_message_security
    Auth-->>H: InboundDecision
    H->>SR: resolve_or_rotate_session
    SR-->>H: ReplSession or None
    H->>Sink: init, send Working message
    Sink->>TB: sendMessage
    H->>D: dispatch_gateway_msg_to_agent
    D->>D: inject_gateway_chat_context
    loop Streaming
        D->>Sink: stream chunks
        Sink->>TB: editMessageText throttled
    end
    D->>Sink: finalize
    Sink->>TB: editMessageText final
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant TB as Telegram Bot API
    participant TP as TelegramPoller
    participant BG as TelegramGatewayBackground
    participant H as handle_polled_inbound_msg
    participant Auth as enforce_security
    participant SR as SessionResolver
    participant D as dispatch_gateway_msg_to_agent
    participant Sink as GatewayOutputSink

    loop Long Poll
        TP->>TB: "getUpdates (timeout=30, offset)"
        TB-->>TP: Update events
    end
    TP-->>BG: list[TelegramInboundMessage]
    BG->>H: event (per update)
    H->>Auth: enforce_inbound_telegram_message_security
    Auth-->>H: InboundDecision
    H->>SR: resolve_or_rotate_session
    SR-->>H: ReplSession or None
    H->>Sink: init, send Working message
    Sink->>TB: sendMessage
    H->>D: dispatch_gateway_msg_to_agent
    D->>D: inject_gateway_chat_context
    loop Streaming
        D->>Sink: stream chunks
        Sink->>TB: editMessageText throttled
    end
    D->>Sink: finalize
    Sink->>TB: editMessageText final
Loading

Comments Outside Diff (4)

  1. gateway/agent/gateway_agent_adapters.py, line 31-44 (link)

    P1 Unbounded recursion in provider alias resolution. If effective_llm_provider returns a provider that eventually aliases back to an earlier value (A→B→A), this recurses until Python's recursion limit is hit and raises a RecursionError. That exception propagates out of environment_block() and is only caught several frames up in dispatch_gateway_msg_to_agent, which silently fails every turn with a user-visible error until the configuration is fixed. Adding a visited set to detect cycles prevents the stack overflow and makes the failure observable at the right layer.

  2. gateway/config/get_gateway_settings.py, line 170-174 (link)

    P2 Unreachable dead-code branch. load_gateway_settings() calls choose_bot_token(), which raises GatewayConfigurationError when the token is empty. That exception is caught on line 155 and causes an early return None. A settings object with an empty bot_token can therefore never be returned, making the if not settings.bot_token guard permanently skipped. Remove or replace it with an assertion so the intent is clear.

  3. gateway/session/enforce_inbound_telegram_message_security.py, line 136-142 (link)

    P2 Magic-string sentinel couples two modules implicitly. "__ROTATE_SESSION__" is produced here and consumed in resolve_or_rotate_session.py as a raw string comparison. If either side is ever updated without the other (e.g. a typo, a refactor), the /new command silently falls through to the normal agent dispatch path instead of rotating the session. Consider extracting this as a module-level constant or replacing the string protocol with a dedicated field on InboundDecision such as rotate_session: bool = False.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  4. gateway/polling/telegram_poller/poller.py, line 44-52 (link)

    P2 security Bot token embedded in the URL path may appear in exception strings. httpx.ConnectError and similar transport exceptions sometimes include the request URL in their __str__ representation. Since url = _API.format(token=self._token, ...) embeds the token in the path, a network failure logged by _log_transient would expose it in plain text. Consider storing a separate redacted URL for logging and only using the real URL for the actual request.

Reviews (1): Last reviewed commit: "Merge main into feature/gateway-code aft..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant