Coverage for src / lexigram / contracts / ai / relay / protocols.py: 0%
36 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""Relay conversion service protocols.
3Gateway and LLM packages consume these protocols from the container and
4never import concrete relay implementation modules. The concrete engine
5in ``lexigram-ai-relay`` implements them.
6"""
8from __future__ import annotations
10from typing import Any, Protocol, TypeAlias, runtime_checkable
12from lexigram.contracts.ai.exceptions import RelayError
13from lexigram.contracts.ai.relay.context import RelayConversionContext
14from lexigram.contracts.ai.relay.types import (
15 ConversionQuality,
16 RelayConvertResult,
17 RelayFormat,
18 RelayRequestPayload,
19 RelayResponsePayload,
20)
21from lexigram.contracts.core.result import Result
23__all__ = [
24 "RelayConverterProtocol",
25 "RelayMapperProtocol",
26 "RelayRegistryProtocol",
27 "RelayStreamOptions",
28 "RelayStreamSessionProtocol",
29]
32RelayStreamOptions: TypeAlias = dict[str, Any]
33"""Stream options (include_usage, per-target knobs) for a stream session."""
36@runtime_checkable
37class RelayConverterProtocol(Protocol):
38 """Explicit source/target protocol conversion and stream ownership.
40 The engine is synchronous, side-effect free, and performs no HTTP,
41 channel selection, billing, or model selection. Callers supply the
42 already-selected upstream model and any host callbacks via context.
43 """
45 def convert_request(
46 self,
47 payload: RelayRequestPayload,
48 source: RelayFormat,
49 target: RelayFormat,
50 *,
51 context: RelayConversionContext | None = None,
52 registry: RelayRegistryProtocol | None = None,
53 ) -> Result[RelayConvertResult[RelayRequestPayload], RelayError]:
54 """Convert a request payload from *source* to *target*."""
55 ...
57 def convert_response(
58 self,
59 payload: RelayResponsePayload,
60 source: RelayFormat,
61 target: RelayFormat,
62 *,
63 context: RelayConversionContext | None = None,
64 registry: RelayRegistryProtocol | None = None,
65 ) -> Result[RelayConvertResult[RelayResponsePayload], RelayError]:
66 """Convert a non-stream response payload from *source* to *target*."""
67 ...
69 def new_stream_session(
70 self,
71 source: RelayFormat,
72 target: RelayFormat,
73 *,
74 options: RelayStreamOptions | None = None,
75 context: RelayConversionContext | None = None,
76 registry: RelayRegistryProtocol | None = None,
77 ) -> Result[RelayStreamSessionProtocol, RelayError]:
78 """Create a stateful stream session for one upstream stream."""
79 ...
81 def convert_stream_chunk(
82 self,
83 session: RelayStreamSessionProtocol,
84 event: Any,
85 ) -> tuple[Any, ...]:
86 """Convert one source stream event through *session*.
88 Args:
89 session: A session previously returned by ``new_stream_session``.
90 event: One source wire event.
92 Returns:
93 Zero, one, or many target wire events.
95 Raises:
96 RelayError: Wrong source format, already finalized, or
97 malformed event.
98 """
99 ...
101 def finalize(
102 self,
103 session: RelayStreamSessionProtocol,
104 ) -> tuple[Any, ...]:
105 """Close the stream deterministically and return terminal events.
107 Args:
108 session: A session previously returned by ``new_stream_session``.
110 Returns:
111 Target terminal events; empty when already finalized.
112 """
113 ...
116@runtime_checkable
117class RelayStreamSessionProtocol(Protocol):
118 """One mutable upstream stream, owned by the caller.
120 The session accepts exactly one source-format event at a time,
121 emits zero, one, or many target events, and finalizes idempotently.
122 """
124 def accept(self, event: Any) -> tuple[Any, ...]:
125 """Accept one source wire event and return emitted target events.
127 Args:
128 event: One source wire event (DTO or raw dict per mapper).
130 Returns:
131 Zero, one, or many target wire events.
133 Raises:
134 RelayError: Wrong source format, already finalized, or
135 malformed event.
136 """
137 ...
139 def finalize(self) -> tuple[Any, ...]:
140 """Close the stream deterministically and return terminal events.
142 Repeated calls return an empty tuple without mutation.
143 """
144 ...
146 def snapshot(self) -> Any:
147 """Return a read-only snapshot of the session state."""
148 ...
151@runtime_checkable
152class RelayMapperProtocol(Protocol):
153 """One wire format's bidirectional mapping to the canonical IR.
155 A mapper may reject a feature with a ``RelayLoss`` plus a warning,
156 but must raise ``RelayError`` for malformed or impossible payloads.
157 """
159 def request_to_ir(self, payload: Any) -> Any:
160 """Convert a source request DTO into canonical ``RelayRequest``."""
161 ...
163 def ir_to_request(self, request: Any) -> Any:
164 """Convert a canonical ``RelayRequest`` into the target request DTO."""
165 ...
167 def response_to_ir(self, payload: Any) -> Any:
168 """Convert a source response DTO into canonical ``RelayResponse``."""
169 ...
171 def ir_to_response(self, response: Any) -> Any:
172 """Convert a canonical ``RelayResponse`` into the target response DTO."""
173 ...
175 def stream_to_delta(self, event: Any) -> tuple[Any, ...]:
176 """Convert one source stream event into canonical ``StreamDelta``s."""
177 ...
179 def delta_to_stream(self, delta: Any) -> tuple[Any, ...]:
180 """Convert one canonical ``StreamDelta`` into target stream events."""
181 ...
184@runtime_checkable
185class RelayRegistryProtocol(Protocol):
186 """Route lookup and caller-owned mapper registration."""
188 def mapper(
189 self,
190 source: RelayFormat,
191 target: RelayFormat,
192 ) -> RelayMapperProtocol | None:
193 """Return the mapper for a directed pair, or ``None``.
195 Args:
196 source: Source wire format.
197 target: Target wire format.
199 Returns:
200 The registered mapper, or ``None`` when the route is unknown.
201 """
202 ...
204 def converter_routes(self) -> tuple[tuple[RelayFormat, RelayFormat], ...]:
205 """Return every supported directed route pair.
207 Returns:
208 Sorted route pairs; same-format no-op pairs are excluded.
209 """
210 ...
212 def mapper_ids(self) -> tuple[str, ...]:
213 """Return the registered mapper wire-format identifiers.
215 Returns:
216 Sorted mapper ids, one per registered mapper.
217 """
218 ...
220 def converter_version(self) -> str:
221 """Return the converter engine version string.
223 Returns:
224 A version string suitable for diagnostics display.
225 """
226 ...
228 def route_quality(
229 self,
230 source: RelayFormat,
231 target: RelayFormat,
232 ) -> ConversionQuality:
233 """Return the semantic-closeness quality for a directed pair.
235 Same-format pairs are always ``GOOD``; unknown routes fall back
236 to ``DISCOURAGED`` rather than raising.
238 Args:
239 source: Source wire format.
240 target: Target wire format.
242 Returns:
243 The stable quality value for the pair.
244 """
245 ...