refactor(gateway): add adapter reply delivery policy - #40931
Conversation
|
e149f06 to
9dedf3c
Compare
9dedf3c to
9931c84
Compare
|
Rebased this PR onto the refreshed LINE media branch (#35785) and fixed the voice-reply regressions from the previous revision. Additional cleanup in this update:
Local verification: uv run --with pytest --with pytest-asyncio --with aiohttp python -m pytest \
tests/gateway/test_voice_command.py \
tests/gateway/test_reply_delivery_policy.py \
tests/gateway/test_media_download_retry.py \
tests/gateway/test_line_plugin.py \
-q -o 'addopts='
# 283 passed, 21 skipped |
b0121e3 to
498fa50
Compare
1b83acb to
14b775e
Compare
14b775e to
913cb33
Compare
|
@liuhao1024 thanks again for catching the |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for extracting a platform delivery seam; the stated LINE follow-up gives it a concrete consumer. Two changes are needed when salvaging onto current main.
Problems
gateway/run.py:12331usesself.adapters.get(event.source.platform). Current main commit8a9bc38cdocuments that this selects the default profile's adapter in multiplex mode; use_adapter_for_source(event.source)so secondary-profile delivery policy is evaluated by the correct adapter.gateway/run.py:12339calls the new adapter policy without a fallback on exception. The adjacent newobserve_inbound_messagepath deliberately catches callback failures (gateway/run.py:12314-12321); policy failures should likewise preserve the legacy reply path rather than disrupt final delivery.
Suggested changes
- Resolve via
_adapter_for_source(event.source)and add a multiplex-source regression. - Catch policy callback exceptions, fall back to the legacy policy, and test that behavior.
Automated hermes-sweeper review.
|
|
||
| ): | ||
| """Return the adapter's reply delivery policy for this turn.""" | ||
| adapter = self.adapters.get(event.source.platform) |
There was a problem hiding this comment.
Current main's multiplex fix 8a9bc38c establishes that self.adapters is the default-profile map. Resolve this through _adapter_for_source(event.source) so a secondary profile evaluates its own adapter's policy.
There was a problem hiding this comment.
Fixed in 1646488 — both lookups this PR introduced (_observe_inbound_message and _reply_delivery_policy) now resolve via self._adapter_for_source(event.source). Two multiplex regressions in tests/gateway/test_reply_delivery_policy.py prove a source stamped for a secondary profile consults that profile's adapter's policy, and the default-profile adapter is never called.
| return ReplyDeliveryPolicy() | ||
|
|
||
| if adapter and hasattr(adapter, "reply_delivery_policy"): | ||
| policy = adapter.reply_delivery_policy( |
There was a problem hiding this comment.
Please catch policy-callback exceptions and fall back to the legacy policy. The adjacent inbound-observer callback is already isolated; an adapter policy failure should not interrupt final-reply delivery.
There was a problem hiding this comment.
Fixed in e1a9252 — the reply_delivery_policy callback is now wrapped in try/except mirroring the inbound-observer isolation pattern: on exception it logs a warning (exc_info=True) and falls back to the legacy voice-mode gate, so a policy failure can never disrupt final-reply delivery. Covered by test_policy_callback_failure_falls_back_to_legacy_delivery (raising policy → legacy gate still honored in both the off and /voice all states).
913cb33 to
e1a9252
Compare
|
Thanks for the review — both points fixed; specifics in the inline replies (adapter resolution via |
55bceff to
f72e34a
Compare
Rebase note: upstream 73e193c ("fix(line): normalize inbound media types and cache routing") independently shipped a superset of this branch's adapter fix — typed cache helper dispatch, fileName threading, and a (path, media_type) return from _download_media. The adapter changes are therefore dropped in favor of upstream's version. What remains from the original commit: the mocked regression tests covering _download_media routing for all four LINE content types, cache/fetch failure fallbacks, and fileName threading from the message event — adapted to upstream's keyword-only ``filename=`` parameter and tuple return, and to media_types now carrying MIME types. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Map the contributor email used on the LINE media PR stack to the jethac GitHub handle, replacing the stale legacy-map entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rebase note (onto f75b577): upstream's voice.auto_tts sync (_should_auto_tts_for_chat, "voice accompanies text replies unless the chat explicitly set off", with unset voice_mode None distinct from "off") and the NousResearch#60671 streaming-TTS skip landed in these same paths since this branch's base. Adapted the graft to preserve both: the base adapter's default reply_delivery_policy and the runner's legacy fallback now include the auto_tts term, _reply_delivery_policy passes voice_mode through raw (None when unset) instead of defaulting to "off", and the runner call site keeps upstream's streaming-TTS guard while threading _voice_reply_sent/suppress-text through it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> [rebase note 2026-08-01: re-resolved against upstream e444d16 — adopted upstream's tightened voice.auto_tts precedence (fallback only when chat has no explicit voice mode, `voice_mode is None`, upstream changed from `!= "off"`) in both the base adapter's default reply_delivery_policy and the runner's legacy fallback]
self.adapters is the default profile's adapter map. Resolve the reply-delivery-policy and inbound-observe adapter through _adapter_for_source(event.source) so multiplex secondary profiles consult their own adapter's policy (aligns with 8a9bc38). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Catch exceptions from the adapter reply_delivery_policy callback and fall back to the legacy voice-mode gate so a buggy adapter policy can never disrupt final reply delivery. Mirrors the isolation pattern used by _observe_inbound_message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
f72e34a to
795998e
Compare
Summary
ReplyDeliveryPolicyhook for platform adapters.Why this matters
Stack
fix(line): correct media caching and message type mapping).feat(line): add opt-in smart reply modality).main; review it after test(line): regression coverage for typed media-cache routing #35785 and before feat(line): add opt-in smart reply modality #40933.Test Plan
python -m py_compile gateway/run.py gateway/platforms/base.py plugins/platforms/line/adapter.pypython -m pytest tests/gateway/test_reply_delivery_policy.py tests/gateway/test_line_plugin.py tests/gateway/test_telegram_audio_vs_voice.py -q -o 'addopts='git diff --check line-media-adapter-pr35785-rebased...refactor/gateway-reply-delivery-policy