feat(relay): block-formatting hints on relay text egress (rich/markdown blocks)

Field report (enterprise side-by-side, 2026-08-18, finding 2): identical
agent output renders native rich_text lists, Block Kit tables, and
highlighted code on native Slack, but literal '-' bullets and code-fence
tables on the relay lane. Native reads platforms.slack.extra.rich_blocks /
markdown_blocks and renders Block Kit locally; relay frames carried no
formatting signal, so the connector had no way to know the operator wants
block rendering.

Contract (additive, v1): the connector advertises supports_block_formatting
in its capability descriptor. When it does AND the operator enables
platforms.relay.extra.slack.rich_blocks / markdown_blocks (same per-platform
sub-block and same _coerce_flag semantics as the other relay Slack knobs),
the gateway stamps format_hints into outbound metadata on BOTH text egress
lanes — send and edit (a streamed reply's final edit carries the finished
markdown, so it must signal too or streams seal as plain text). The
connector renders blocks and keeps plain text as the fallback.

Old connector: never advertises -> no dead metadata ever sent. Old gateway:
never stamps -> connector renders plain text as today. Knobs default OFF,
matching native's opt-in posture.

8 new tests: descriptor default/from_json, hint stamping (capable+enabled),
capability-absent suppression, knobs-off suppression, YAML-quoted-false
coercion, partial knobs, edit-lane parity.
This commit is contained in:
Victor Kyriazakos
2026-08-19 13:47:18 +00:00
parent 85b89451f6
commit 31a4b8503d
3 changed files with 206 additions and 2 deletions
+47 -2
View File
@@ -1089,6 +1089,43 @@ class RelayAdapter(BasePlatformAdapter):
raw_response=result,
)
def _format_hints(self) -> Optional[Dict[str, bool]]:
"""Block-formatting hints for outbound text frames, or None.
Native Slack reads ``platforms.slack.extra.rich_blocks`` /
``markdown_blocks`` and renders Block Kit locally; on the relay lane
the CONNECTOR owns the Slack API call, so the gateway can only signal
intent. Hints are stamped ONLY when (a) the connector advertises
``supports_block_formatting`` in its descriptor — an old connector
never receives dead metadata — and (b) the operator enabled at least
one knob under the relay's per-platform sub-block
(``platforms.relay.extra.slack.rich_blocks`` / ``markdown_blocks``,
same seam and same _coerce_flag semantics as reply_in_thread).
Both knobs default OFF, matching native's opt-in posture.
"""
if not getattr(self.descriptor, "supports_block_formatting", False):
return None
try:
extra = self._relay_slack_extra()
except Exception: # noqa: BLE001 - config shape is operator-owned
return None
hints: Dict[str, bool] = {}
for knob in ("rich_blocks", "markdown_blocks"):
if self._coerce_flag(extra.get(knob), False):
hints[knob] = True
return hints or None
def _with_format_hints(
self, metadata: Optional[Dict[str, Any]]
) -> Optional[Dict[str, Any]]:
"""Return metadata with ``format_hints`` stamped when applicable."""
hints = self._format_hints()
if not hints:
return metadata
merged = dict(metadata or {})
merged.setdefault("format_hints", hints)
return merged
async def send(
self,
chat_id: str,
@@ -1121,7 +1158,9 @@ class RelayAdapter(BasePlatformAdapter):
"chat_id": chat_id,
"content": content,
"reply_to": effective_reply_to,
"metadata": self._with_scope(chat_id, send_metadata),
"metadata": self._with_scope(
chat_id, self._with_format_hints(send_metadata)
),
},
platform=self._platform_by_chat.get(str(chat_id)),
)
@@ -1359,7 +1398,13 @@ class RelayAdapter(BasePlatformAdapter):
"chat_id": chat_id,
"message_id": message_id,
"content": content,
"metadata": self._with_scope(chat_id, metadata),
# Same format_hints as send: a streamed reply's FINAL edit is
# the frame that carries the finished markdown, so the edit
# lane must signal block rendering too or streams would seal
# as plain text (boundary rule: every text egress lane).
"metadata": self._with_scope(
chat_id, self._with_format_hints(metadata)
),
},
platform=self._platform_by_chat.get(str(chat_id)),
)
+9
View File
@@ -72,6 +72,15 @@ class CapabilityDescriptor:
# that never sends this keeps today's thread behavior — additive within
# contract_version 1.
supports_inchannel_continuable: bool = False
# Whether the connector's platform sender can render block-level
# formatting from raw markdown (Slack: rich_text lists, Block Kit
# tables/markdown blocks). When True AND the operator enables the
# rich_blocks/markdown_blocks knobs, the gateway stamps ``format_hints``
# into outbound send/edit metadata; the connector renders blocks and
# keeps the plain text as fallback. Default False — old connectors never
# receive hints, old gateways never send them. Additive within
# contract_version 1.
supports_block_formatting: bool = False
# Op-level capability discovery (Phase 1 parity): the outbound op names the
# connector's sender for this platform actually implements (e.g.
# ["send", "edit", "typing", "follow_up", "get_chat_info"]). Empty tuple =
+150
View File
@@ -0,0 +1,150 @@
"""Relay lane parity: block formatting hints on outbound frames (Coatue F2).
Field report 2026-08-18, finding 2: identical agent output renders as native
rich_text lists / Block Kit tables / highlighted code on native Slack, but
literal `-` bullets and code-fence tables on the relay lane. Native reads
platforms.slack.extra.rich_blocks / markdown_blocks; relay frames carry no
formatting signal at all, and the connector has no way to know the operator
wants block rendering.
Contract (additive, v1): the connector advertises
``supports_block_formatting`` in its capability descriptor; when the operator
enables the knobs (relay shape: platforms.relay.extra.slack.rich_blocks /
markdown_blocks — same sub-block as the other relay Slack knobs), the gateway
stamps ``format_hints`` into outbound send metadata. Old connectors never
advertise, so no hint is ever sent (no dead metadata); old gateways never
stamp, so connectors keep rendering plain text.
"""
import json
from types import SimpleNamespace
import pytest
from gateway.config import PlatformConfig
from gateway.relay.adapter import RelayAdapter
from gateway.relay.descriptor import CapabilityDescriptor
def _descriptor(**overrides):
base = dict(
contract_version=1,
platform="slack",
label="Slack",
max_message_length=4000,
supports_draft_streaming=False,
supports_edit=True,
supports_threads=True,
markdown_dialect="mrkdwn",
len_unit="chars",
)
base.update(overrides)
return CapabilityDescriptor(**base)
class FakeTransport:
def __init__(self):
self.frames = []
async def send_outbound(self, frame, platform=None):
self.frames.append((frame, platform))
return {"success": True, "message_id": "1.2"}
def _adapter(extra=None, descriptor=None):
config = PlatformConfig(enabled=True, extra=extra or {})
a = RelayAdapter(config, descriptor or _descriptor(), transport=FakeTransport())
return a
class TestDescriptorBit:
def test_default_false(self):
assert _descriptor().supports_block_formatting is False
def test_from_json_reads_flag(self):
payload = dict(
contract_version=1, platform="slack", label="Slack",
max_message_length=4000, supports_draft_streaming=False,
supports_edit=True, supports_threads=True,
markdown_dialect="mrkdwn", len_unit="chars",
supports_block_formatting=True,
)
assert CapabilityDescriptor.from_json(
json.dumps(payload)
).supports_block_formatting is True
class TestFormatHintsStamping:
@pytest.mark.asyncio
async def test_hints_stamped_when_capable_and_enabled(self):
a = _adapter(
extra={"slack": {"rich_blocks": True, "markdown_blocks": True}},
descriptor=_descriptor(supports_block_formatting=True),
)
await a.send("D01", "# Report\n\n| a | b |\n|---|---|\n| 1 | 2 |")
frame, _ = a._transport.frames[-1]
hints = (frame.get("metadata") or {}).get("format_hints")
assert hints == {"rich_blocks": True, "markdown_blocks": True}
@pytest.mark.asyncio
async def test_no_hints_when_connector_lacks_capability(self):
"""Old connector: knob on, capability absent -> no dead metadata."""
a = _adapter(
extra={"slack": {"rich_blocks": True}},
descriptor=_descriptor(),
)
await a.send("D01", "text")
frame, _ = a._transport.frames[-1]
assert "format_hints" not in (frame.get("metadata") or {})
@pytest.mark.asyncio
async def test_no_hints_when_knobs_off(self):
"""Capable connector, operator never opted in -> no hint (native
parity: rich_blocks/markdown_blocks are opt-in on native too)."""
a = _adapter(
extra={},
descriptor=_descriptor(supports_block_formatting=True),
)
await a.send("D01", "text")
frame, _ = a._transport.frames[-1]
assert "format_hints" not in (frame.get("metadata") or {})
@pytest.mark.asyncio
async def test_quoted_false_knob_stays_off(self):
"""YAML-quoted 'false' must coerce off — same _coerce_flag semantics
as the other relay Slack knobs."""
a = _adapter(
extra={"slack": {"rich_blocks": "false", "markdown_blocks": "false"}},
descriptor=_descriptor(supports_block_formatting=True),
)
await a.send("D01", "text")
frame, _ = a._transport.frames[-1]
assert "format_hints" not in (frame.get("metadata") or {})
@pytest.mark.asyncio
async def test_partial_knobs_stamp_only_enabled(self):
a = _adapter(
extra={"slack": {"markdown_blocks": True}},
descriptor=_descriptor(supports_block_formatting=True),
)
await a.send("D01", "text")
frame, _ = a._transport.frames[-1]
hints = (frame.get("metadata") or {}).get("format_hints")
assert hints == {"markdown_blocks": True}
@pytest.mark.asyncio
async def test_edit_lane_carries_hints_too(self):
"""Boundary rule: every text egress lane crossing the frame contract
gets the hint — send AND edit (streaming final edits render blocks
on native)."""
a = _adapter(
extra={"slack": {"rich_blocks": True}},
descriptor=_descriptor(supports_block_formatting=True),
)
edit = getattr(a, "edit_message", None)
if edit is None:
pytest.skip("relay adapter has no edit lane")
await edit("D01", "1.2", "updated **content**")
frame, _ = a._transport.frames[-1]
hints = (frame.get("metadata") or {}).get("format_hints")
assert hints == {"rich_blocks": True}