3c7069bdcb
authz_mixin, browser_control_broker, delivery, delivery_ledger, display_config, drain_control, hosted_room_links/peer/policy_checkpoint, hosted_rooms, platform_registry, relay/__init__, relay/ws_transport, run.py and slash_commands.py (comments), session_context, session_state, streaming_tts_consumer, turn_lease and small modules. - HostedRoomPolicyCheckpoint._apply_event -> per-kind handler table - WebSocketRelayTransport._handle_frame -> frame-handler table - GatewayAuthorizationMixin: unified adapter setting/flag/extra readers - dead symbols removed (verified zero references): RoomLinkProbe/select_room_link, relay_bot_username, is_restart_loop_tripped, debug_rows, DeadTargetRegistry.all_dead, BrowserControlBroker.detach_owner/_prune_tickets, StreamingTTSConsumer.started/_enqueue_done/ _iter_stream_chunks/_next_stream_chunk, RecoverableHandleCache.status_for, _auth_env, _copy_default_catalog, _parse_timestamp_prefix, _present_* helpers, _send_result_error_kind, _truthy_env, SessionFieldView/TurnLeaseTokenView dunder shims, and their orphaned tests. - lost WHY/invariant text from the earlier compaction restored compactly (541 hunks audited)
125 lines
4.8 KiB
Python
125 lines
4.8 KiB
Python
"""Gateway response filtering helpers.
|
|
|
|
These decide whether a completed agent turn should be delivered to the chat,
|
|
not what should be persisted in conversation history.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import unicodedata
|
|
from typing import Any
|
|
|
|
# Exact whole-response markers meaning "the agent intentionally chose not to
|
|
# reply". Keep small and explicit; arbitrary empty output remains an
|
|
# error/empty-response path, not silence.
|
|
LIVE_GATEWAY_SILENT_MARKERS = frozenset({
|
|
"[SILENT]",
|
|
"SILENT",
|
|
"NO_REPLY",
|
|
"NO REPLY",
|
|
})
|
|
|
|
# Longer than any marker could plausibly be, even with stray punctuation.
|
|
_MARKER_LENGTH_CAP = 64
|
|
|
|
|
|
def _canonical_silence_candidate(text: str) -> str:
|
|
return " ".join(text.strip().upper().split())
|
|
|
|
|
|
def _is_edge_punctuation(ch: str) -> bool:
|
|
# Square brackets stay structural so malformed ``[SILENT`` cannot become ``SILENT``.
|
|
return ch not in "[]" and unicodedata.category(ch).startswith("P")
|
|
|
|
|
|
def _strip_edge_silence_punctuation(text: str) -> str:
|
|
"""Strip stray edge punctuation (``.NO_REPLY``, ``*NO_REPLY*``) without erasing marker structure."""
|
|
start, end = 0, len(text)
|
|
while start < end and _is_edge_punctuation(text[start]):
|
|
start += 1
|
|
while end > start and _is_edge_punctuation(text[end - 1]):
|
|
end -= 1
|
|
return text[start:end].strip()
|
|
|
|
|
|
def _canonical_silence_candidates(text: str) -> tuple[str, ...]:
|
|
exact = _canonical_silence_candidate(text)
|
|
stripped = _strip_edge_silence_punctuation(text.strip())
|
|
if stripped == text.strip():
|
|
return (exact,)
|
|
return (exact, _canonical_silence_candidate(stripped))
|
|
|
|
|
|
def _short_stripped(text: Any) -> str:
|
|
"""Stripped text if it is a non-empty string within the marker cap, else ''."""
|
|
if not isinstance(text, str):
|
|
return ""
|
|
stripped = text.strip()
|
|
return stripped if 0 < len(stripped) <= _MARKER_LENGTH_CAP else ""
|
|
|
|
|
|
def is_intentional_silence_response(response: Any) -> bool:
|
|
"""True only when ``response`` is exactly a silence marker.
|
|
|
|
Prose that merely mentions ``NO_REPLY`` must be delivered normally. A blank
|
|
response is not silence either — that is the empty-response failure path.
|
|
"""
|
|
stripped = _short_stripped(response)
|
|
return bool(stripped) and any(
|
|
c in LIVE_GATEWAY_SILENT_MARKERS for c in _canonical_silence_candidates(stripped)
|
|
)
|
|
|
|
|
|
def is_autonomous_silence_response(response: Any) -> bool:
|
|
"""Loose silence matcher for autonomous lanes (cron, webhook).
|
|
|
|
Autonomous lanes ask for ``[SILENT]`` when a tick produced nothing worth
|
|
attention, and models reliably bracket the marker with a short note. Unlike
|
|
:func:`is_intentional_silence_response` (interactive rule: EXACTLY a marker),
|
|
this suppresses when a marker is the whole response, sits on its own first or
|
|
last line, or the bracketed sentinel opens the response (``[SILENT] No
|
|
changes detected``). A token buried mid-sentence is still delivered.
|
|
Shares :data:`LIVE_GATEWAY_SILENT_MARKERS` so the two sets cannot drift.
|
|
"""
|
|
if not isinstance(response, str):
|
|
return False
|
|
stripped = response.strip()
|
|
if not stripped:
|
|
return False
|
|
|
|
def _is_token(line: str) -> bool:
|
|
return _canonical_silence_candidate(line) in LIVE_GATEWAY_SILENT_MARKERS
|
|
|
|
if _is_token(stripped):
|
|
return True
|
|
lines = [ln for ln in stripped.splitlines() if ln.strip()]
|
|
if lines and (_is_token(lines[0]) or _is_token(lines[-1])):
|
|
return True
|
|
# Bracketed form only, so a bare "Silent retry succeeded" is NOT swallowed.
|
|
return stripped.upper().startswith("[SILENT]")
|
|
|
|
|
|
def is_intentional_silence_agent_result(agent_result: dict | None, response: Any) -> bool:
|
|
"""Silence markers suppress delivery only for successful agent turns."""
|
|
if not isinstance(agent_result, dict) or agent_result.get("failed"):
|
|
return False
|
|
return is_intentional_silence_response(response)
|
|
|
|
|
|
def is_partial_silence_marker(text: Any) -> bool:
|
|
"""True while streamed ``text`` could still resolve to a silence marker.
|
|
|
|
The streaming path must decide, before the whole response is known, whether
|
|
to show its buffer. A buffer whose canonical form is a non-empty *prefix* of
|
|
a marker (``"NO"`` on the way to ``"NO_REPLY"``, or an exact marker not yet
|
|
terminated by stream-end) is held back so a raw marker is never shown and
|
|
then retracted. Anything that has diverged from every marker, or exceeds the
|
|
marker cap, returns False so normal streaming resumes. Shares the marker set
|
|
and canonicalization with :func:`is_intentional_silence_response`.
|
|
"""
|
|
stripped = _short_stripped(text)
|
|
return bool(stripped) and any(
|
|
c and any(marker.startswith(c) for marker in LIVE_GATEWAY_SILENT_MARKERS)
|
|
for c in _canonical_silence_candidates(stripped)
|
|
)
|