Python: add agent-framework-hosting-telegram channel#5643
Python: add agent-framework-hosting-telegram channel#5643eavanvalkenburg wants to merge 2 commits intomicrosoft:feature/python-hostingfrom
Conversation
There was a problem hiding this comment.
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_shutdowndoes not cancel or await in-flight_update_tasksbefore 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'srun()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_fixturesas iftestswere a unique package, but this repo runs allpackages/**/teststrees in one pytest session and already has another top-leveltestspackage inpackages/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 exposetests/__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. |
There was a problem hiding this comment.
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.
f8c881a to
7958ec5
Compare
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>
7958ec5 to
3aea8f0
Compare
Motivation and Context
Implements the Telegram channel described in SPEC-002 §7 (merged via #5549). Demonstrates a non-Microsoft channel built on the same
Channelprotocol — a useful reference for community channels.Description
Adds
agent-framework-hosting-telegram(python/packages/hosting-telegram/):TelegramChannel— mounts a webhook endpoint, decodes TelegramUpdatepayloads intoChannelRequest, supports text replies + simple multicast (response_targets).chat_id(the basis forlocal_telegramand the cross-channellocal_identity_linksample in PR-8).Stack
PR-6 of 9. Depends on #PR-2 (
feat/hosting-core).Contribution Checklist