Skip to content

fix(gateway): suppress exact silence tokens without mutating history#46080

Merged
teknium1 merged 1 commit into
mainfrom
fix/gateway-exact-silence-token
Jun 14, 2026
Merged

fix(gateway): suppress exact silence tokens without mutating history#46080
teknium1 merged 1 commit into
mainfrom
fix/gateway-exact-silence-token

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Gateway final-response delivery now treats exact whole-response silence tokens as an intentional no-op: the assistant turn stays in history, but no chat message is sent.

Changes

  • Add gateway.response_filters with the exact-token silence contract.
  • Recognize only whole-response markers: [SILENT], SILENT, NO_REPLY, NO REPLY after whitespace/case normalization.
  • Suppress outbound delivery after transcript persistence, so assistant silence turns remain in history and adjacent user turns are not merged.
  • Keep empty responses, failed turns, and prose mentioning silence tokens on the normal delivery/error paths.
  • Add release author mapping for @aldoeliacim.

Validation

Check Result
scripts/run_tests.sh tests/gateway/test_response_filters.py tests/gateway/test_gateway_silence_tokens.py 9 passed
scripts/run_tests.sh tests/gateway/test_response_filters.py tests/gateway/test_gateway_silence_tokens.py tests/gateway/test_stream_consumer.py tests/gateway/test_telegram_group_gating.py tests/gateway/test_42039_duplicate_user_message.py 150 passed
python3 -m py_compile gateway/response_filters.py gateway/run.py gateway/platforms/base.py tests/gateway/test_response_filters.py tests/gateway/test_gateway_silence_tokens.py && git diff --check passed

Narrowly salvages #37940 by @aldoeliacim with authorship preserved. This intentionally does not salvage #13252's broader silence_allowed retry-loop/adapter plumbing.

Closes #13248.

Infographic

Exact Silence Tokens

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: fix/gateway-exact-silence-token vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 10905 on HEAD, 10893 on base (🆕 +12)

🆕 New issues (12):

Rule Count
invalid-assignment 9
unresolved-attribute 2
unresolved-import 1
First entries
tests/gateway/test_gateway_silence_tokens.py:6: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/gateway/test_gateway_silence_tokens.py:51: [invalid-assignment] invalid-assignment: Object of type `(...) -> Literal[False]` is not assignable to attribute `_should_send_voice_reply` of type `def _should_send_voice_reply(self, event: MessageEvent, response: str, agent_messages: list[Unknown], already_sent: bool = False) -> bool`
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
run_agent.py:2891: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`
tests/gateway/test_gateway_silence_tokens.py:48: [invalid-assignment] invalid-assignment: Object of type `(_key, _gen) -> Literal[True]` is not assignable to attribute `_is_session_run_current` of type `def _is_session_run_current(self, session_key: str, generation: int) -> bool`
tests/gateway/test_gateway_silence_tokens.py:44: [invalid-assignment] invalid-assignment: Object of type `AsyncMock` is not assignable to attribute `_handle_active_session_busy_message` of type `def _handle_active_session_busy_message(self, event: MessageEvent, session_key: str) -> CoroutineType[Any, Any, bool]`
tests/gateway/test_gateway_silence_tokens.py:46: [invalid-assignment] invalid-assignment: Object of type `(_source) -> None` is not assignable to attribute `_recover_telegram_topic_thread_id` of type `def _recover_telegram_topic_thread_id(self, source: SessionSource) -> str | None`
tests/gateway/test_gateway_silence_tokens.py:49: [invalid-assignment] invalid-assignment: Object of type `(_event) -> None` is not assignable to attribute `_reply_anchor_for_event` of type `def _reply_anchor_for_event(event: MessageEvent) -> str | None`
tests/gateway/test_gateway_silence_tokens.py:47: [invalid-assignment] invalid-assignment: Object of type `(_key, _source) -> None` is not assignable to attribute `_cache_session_source` of type `def _cache_session_source(self, session_key: str, source) -> None`
tests/gateway/test_gateway_silence_tokens.py:43: [invalid-assignment] invalid-assignment: Object of type `(_context) -> None` is not assignable to attribute `_set_session_env` of type `def _set_session_env(self, context: SessionContext) -> list[Unknown]`
tests/gateway/test_gateway_silence_tokens.py:50: [invalid-assignment] invalid-assignment: Object of type `(_event) -> None` is not assignable to attribute `_get_guild_id` of type `def _get_guild_id(event: MessageEvent) -> int | None`
tests/gateway/test_gateway_silence_tokens.py:42: [invalid-assignment] invalid-assignment: Object of type `(_source) -> Literal[True]` is not assignable to attribute `_is_user_authorized` of type `def _is_user_authorized(self, source: SessionSource) -> bool`

✅ Fixed issues (1):

Rule Count
invalid-assignment 1
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`

Unchanged: 5724 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

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.

Empty-response retry loop on claude-opus-4-7 in Slack group threads (non-@mention discussion messages)

2 participants