feat(relay): derive descriptor from PlatformEntry

CapabilityDescriptor.from_platform_entry() projects an existing PlatformEntry
(label, max_message_length, emoji, platform_hint, pii_safe, name) into a
descriptor, proving the descriptor is a projection of existing config rather
than a parallel concept. Runtime-only capabilities (len_unit, draft/edit/
thread/markdown) are caller-supplied. max_message_length==0 ('no limit') maps
to the stream_consumer 4096 default.

Phase 0 complete. Task 0.3 of the gateway-relay plan.
This commit is contained in:
Ben 2026-06-08 15:08:41 +10:00 committed by Teknium
parent 53d9b98305
commit 3db49381d6
2 changed files with 105 additions and 0 deletions

View file

@ -75,3 +75,44 @@ class CapabilityDescriptor:
known = {f for f in cls.__dataclass_fields__} # type: ignore[attr-defined]
filtered = {k: v for k, v in raw.items() if k in known}
return cls(**filtered)
@classmethod
def from_platform_entry(
cls,
entry,
*,
len_unit: str = "chars",
supports_draft_streaming: bool = False,
supports_edit: bool = True,
supports_threads: bool = False,
markdown_dialect: str = "plain",
) -> "CapabilityDescriptor":
"""Project a ``gateway.platform_registry.PlatformEntry`` into a descriptor.
Demonstrates the descriptor is a *subset/projection* of what
``PlatformEntry`` already encodes, not a parallel concept: ``label``,
``max_message_length``, ``emoji``, ``platform_hint``, ``pii_safe`` and
the platform name come straight off the entry. The runtime capability
bits that ``PlatformEntry`` does NOT encode (length unit, draft/edit/
thread/markdown behavior) are supplied by the caller in production
the connector fills these from the live adapter's capability methods.
``max_message_length`` of 0 on a ``PlatformEntry`` means "no limit";
we map that to the stream_consumer default of 4096 so the descriptor
always carries a concrete chunking bound.
"""
max_len = getattr(entry, "max_message_length", 0) or 4096
return cls(
contract_version=CONTRACT_VERSION,
platform=entry.name,
label=entry.label,
max_message_length=max_len,
supports_draft_streaming=supports_draft_streaming,
supports_edit=supports_edit,
supports_threads=supports_threads,
markdown_dialect=markdown_dialect,
len_unit=len_unit,
emoji=getattr(entry, "emoji", "\U0001f50c"),
platform_hint=getattr(entry, "platform_hint", ""),
pii_safe=getattr(entry, "pii_safe", False),
)

View file

@ -0,0 +1,64 @@
"""Descriptor <- PlatformEntry projection (relay Phase 0, Task 0.3).
Proves the CapabilityDescriptor is a projection of the existing PlatformEntry,
not a parallel concept: the entry's label/limit/emoji/hint/pii fields carry
straight through.
"""
from gateway.platform_registry import PlatformEntry
from gateway.relay.descriptor import CONTRACT_VERSION, CapabilityDescriptor
def _entry(**overrides) -> PlatformEntry:
base = dict(
name="telegram",
label="Telegram",
adapter_factory=lambda cfg: None,
check_fn=lambda: True,
max_message_length=4096,
pii_safe=False,
emoji="\u2708\ufe0f",
platform_hint="You are on Telegram.",
)
base.update(overrides)
return PlatformEntry(**base)
def test_projection_carries_platform_entry_fields():
d = CapabilityDescriptor.from_platform_entry(_entry(), len_unit="utf16")
assert d.contract_version == CONTRACT_VERSION
assert d.platform == "telegram"
assert d.label == "Telegram"
assert d.max_message_length == 4096
assert d.emoji == "\u2708\ufe0f"
assert d.platform_hint == "You are on Telegram."
assert d.pii_safe is False
assert d.len_unit == "utf16"
def test_zero_max_length_maps_to_4096_default():
"""PlatformEntry.max_message_length == 0 means 'no limit'; the descriptor
carries a concrete bound matching the stream_consumer default."""
d = CapabilityDescriptor.from_platform_entry(_entry(max_message_length=0))
assert d.max_message_length == 4096
def test_runtime_capabilities_supplied_by_caller():
"""PlatformEntry doesn't encode draft/edit/thread/markdown behavior — those
come from the caller (the connector, reading the live adapter)."""
d = CapabilityDescriptor.from_platform_entry(
_entry(),
supports_draft_streaming=True,
supports_edit=False,
supports_threads=True,
markdown_dialect="discord",
)
assert d.supports_draft_streaming is True
assert d.supports_edit is False
assert d.supports_threads is True
assert d.markdown_dialect == "discord"
def test_projection_roundtrips_through_json():
d = CapabilityDescriptor.from_platform_entry(_entry(), len_unit="utf16")
assert CapabilityDescriptor.from_json(d.to_json()) == d