Skip to content

Python: add agent-framework-hosting-telegram channel#5643

Open
eavanvalkenburg wants to merge 2 commits intomicrosoft:feature/python-hostingfrom
eavanvalkenburg:feat/hosting-channel-telegram
Open

Python: add agent-framework-hosting-telegram channel#5643
eavanvalkenburg wants to merge 2 commits intomicrosoft:feature/python-hostingfrom
eavanvalkenburg:feat/hosting-channel-telegram

Conversation

@eavanvalkenburg
Copy link
Copy Markdown
Member

Motivation and Context

Implements the Telegram channel described in SPEC-002 §7 (merged via #5549). Demonstrates a non-Microsoft channel built on the same Channel protocol — a useful reference for community channels.

Description

Adds agent-framework-hosting-telegram (python/packages/hosting-telegram/):

  • TelegramChannel — mounts a webhook endpoint, decodes Telegram Update payloads into ChannelRequest, supports text replies + simple multicast (response_targets).
  • Identity derivation from Telegram chat_id (the basis for local_telegram and the cross-channel local_identity_link sample in PR-8).
  • Tests covering channel wiring + webhook handling.

Stack

PR-6 of 9. Depends on #PR-2 (feat/hosting-core).

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? No — new package.

@moonbox3 moonbox3 added documentation Improvements or additions to documentation python labels May 5, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 4 | Confidence: 83%

✓ Correctness

No actionable issues found in this dimension.

✓ Security Reliability

The Telegram channel and hosting package introduce a non-constant-time comparison for the webhook secret token (line 326 of _channel.py), which could theoretically enable timing-based attacks against the authentication mechanism. Additionally, the shutdown sequence in _on_shutdown does not cancel or await in-flight _update_tasks before closing the shared HTTP client, creating a race condition that can produce errors during graceful shutdown.

✓ Test Coverage

The Telegram channel tests cover parsing helpers, webhook dispatch, push, and command handling, but have significant gaps around the streaming path (_stream_to_chat) which is the constructor's default behavior (stream=True), callback query handling, and image delivery in _reply_with_result. The streaming code is ~150 lines of complex async coordination (edit workers, typing workers, rate limiting, error recovery) with zero test coverage. Additionally, the webhook dispatch test assertion only checks that the agent was invoked, not what input it received or what response was sent to the user. The test suite is comprehensive and well-structured, covering host wiring, invocation, session management, workflow targeting, checkpointing, and delivery routing with meaningful assertions throughout. Two notable coverage gaps exist: (1) no test exercises the streaming path (run_stream) with an agent target (only workflow targets are tested for streaming), and (2) no test verifies error-propagation behavior when the underlying target's run() raises an exception. Both gaps are acknowledged in the code (pragma: no cover comment at line 68) and are reasonable additions to consider.

✗ Design Approach

Those are approach issues rather than implementation nits, so I would request changes. One design issue stands out: the new hosting tests rely on tests._workflow_fixtures as if tests were a unique package, but this repo runs all packages/**/tests trees in one pytest session and already has another top-level tests package in packages/core. That makes the new approach import-order dependent rather than package-local, so these tests are fragile and can resolve to the wrong package or fail once multiple packages expose tests/__init__.py.


Automated review by eavanvalkenburg's agents

offset = update_id + 1
# Each update is processed in its own task so a slow agent
# call doesn't stall the next poll. Order within a chat is
# still preserved by Telegram-side queueing.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating one task per update does not preserve ordering within a chat once two updates arrive close together; Telegram only preserves delivery order up to getUpdates, and this fan-out removes that guarantee. The result is out-of-order replies and overlapping sessionful runs for the same chat. Use per-chat serialization (queue/lock keyed by chat_id or isolation key) instead of assuming Telegram-side queueing is enough.

@eavanvalkenburg eavanvalkenburg force-pushed the feat/hosting-channel-telegram branch from f8c881a to 7958ec5 Compare May 5, 2026 09:00
eavanvalkenburg and others added 2 commits May 5, 2026 11:08
New ``agent-framework-hosting`` package implementing ADR 0026 / SPEC-002:
the channel-neutral host that lets a single ``Agent`` (or ``Workflow``)
fan out across multiple wire protocols ("channels") behind one Starlette
ASGI app.

Surface (re-exported from ``agent_framework_hosting``):

- ``AgentFrameworkHost`` — wraps a hostable target, mounts channels onto
  an ASGI app, owns per-isolation-key ``AgentSession`` reuse, threads
  request context (``response_id`` / ``previous_response_id``) into
  context providers via an ``ExitStack`` of ``bind_request_context``
  calls, and exposes an opt-in Hypercorn ``serve()`` helper (extra
  ``[serve]``).
- ``Channel`` protocol + ``ChannelContribution`` — the surface a channel
  package implements (routes, lifespans, identity hooks, …).
- ``ChannelRequest`` / ``ChannelSession`` / ``ChannelIdentity`` /
  ``ChannelPush`` / ``ChannelCommand[Context]`` / ``ChannelRunHook`` /
  ``ChannelStreamTransformHook`` / ``DeliveryReport`` /
  ``HostedRunResult`` / ``ResponseTarget`` / ``ResponseTargetKind`` /
  ``apply_run_hook`` — channel-side dataclasses + helpers.
- ``IsolationKeys`` + ``ISOLATION_HEADER_USER`` / ``..._CHAT`` +
  ``get/set/reset_current_isolation_keys`` — the host's ASGI middleware
  reads the ``x-agent-{user,chat}-isolation-key`` headers off each
  inbound request and exposes them to the agent stack via a
  ``ContextVar`` so storage-side providers (e.g.
  ``FoundryHostedAgentHistoryProvider``) can apply per-tenant
  partitioning without channels having to forward anything.

Includes 45 unit tests covering the host, channel contributions,
isolation contextvar, and shared types. Registers the package in
``python/pyproject.toml`` ``[tool.uv.sources]`` and adds the matching
pyright ``executionEnvironments`` entry for tests.

Hypercorn is an optional dependency (``[serve]`` extra); the soft import
in ``serve()`` is annotated for pyright since it isn't on the default
install.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New ``agent-framework-hosting-telegram`` package implementing the
Telegram Bot API channel for the Hosting framework. Mounts a webhook
endpoint (``POST /telegram/webhook``) and an in-process polling loop
onto an ``AgentFrameworkHost`` and translates Telegram ``Update``
payloads to/from the channel-neutral ``ChannelRequest`` /
``HostedRunResult`` plumbing.

Surface (re-exported from ``agent_framework_hosting_telegram``):

- ``TelegramChannel`` -- concrete ``Channel`` implementation. Owns the
  webhook route + an optional ``getUpdates`` long-polling lifespan,
  parses Telegram ``Update``s into ``ChannelRequest`` (text, photo,
  document, voice, callback_query, …), runs the optional
  ``ChannelRunHook``, calls back into the ``ChannelContext`` to invoke
  the agent target, and posts the response back via
  ``sendMessage`` / ``sendChatAction`` / ``answerCallbackQuery`` on the
  Telegram Bot API. Honours ``DeliveryReport.include_originating`` so
  cross-channel pushes can target the originating Telegram chat
  without double-acking.
- Native fields the channel doesn't lift onto ``ChannelRequest`` (e.g.
  ``chat.type``, ``message.message_id``, ``callback_query.data``) are
  attached to ``ChannelRequest.attributes`` so a ``ChannelRunHook``
  can pick them up via the standard ``protocol_request=`` kwarg.
- 13 unit tests covering route wiring, ``Update`` parsing across the
  common content shapes, hook composition, and originating vs
  non-originating delivery branches.

Registers the package in ``python/pyproject.toml``
``[tool.uv.sources]`` and adds the matching pyright
``executionEnvironments`` entry. Stacks on PR-2 (Hosting core);
independent of PR-3 / PR-4.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eavanvalkenburg eavanvalkenburg force-pushed the feat/hosting-channel-telegram branch from 7958ec5 to 3aea8f0 Compare May 5, 2026 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants