refactor(rust-bridge): simplify catalog compatibility checks

This commit is contained in:
Devin AI 2026-10-20 17:45:05 +00:00
parent ca21e2572f
commit c7e4ea6032
3 changed files with 16 additions and 17 deletions

View file

@ -43,9 +43,6 @@ class RouteContext:
target: Target | None = None
features: frozenset[Feature] = frozenset()
def axes(self) -> tuple[frozenset[object], ...]:
return (frozenset({self.provider}), frozenset({self.model}), frozenset({self.target}), self.features)
@dataclass(frozen=True, slots=True)
class RouteRule:
@ -56,13 +53,16 @@ class RouteRule:
targets: frozenset[Target] | None = None
features: frozenset[Feature] | None = None
def constraints(self) -> tuple[frozenset[object] | None, ...]:
return (self.providers, self.models, self.targets, self.features)
def unconstrained(self) -> bool:
return self.providers is None and self.models is None and self.targets is None and self.features is None
def matches(self, context: RouteContext) -> bool:
return context.route is self.route and all(
allowed is None or not allowed.isdisjoint(values)
for allowed, values in zip(self.constraints(), context.axes(), strict=True)
return (
context.route is self.route
and (self.providers is None or context.provider in self.providers)
and (self.models is None or context.model in self.models)
and (self.targets is None or context.target in self.targets)
and (self.features is None or not self.features.isdisjoint(context.features))
)
@ -92,7 +92,7 @@ def decision(context: RouteContext, rules: Rules | None = None) -> Decision:
return _decision(rollout(context, rules))
def may_leave_python(route: Route, rules: Rules) -> bool:
def rust_might_handle(route: Route, rules: Rules) -> bool:
own: Final = tuple(rule for rule in rules if rule.route is route)
last: Final = next((i for i, rule in enumerate(own) if all(c is None for c in rule.constraints())), len(own))
last: Final = next((i for i, rule in enumerate(own) if rule.unconstrained()), len(own))
return any(_decision(rule.rollout) is not Decision.PYTHON for rule in own[: last + 1])

View file

@ -58,7 +58,7 @@ class PublicDispatch(Generic[RequestT]):
python=python,
rules=selected_rules,
)
if not catalog.may_leave_python(self.route, selected_rules):
if not catalog.rust_might_handle(self.route, selected_rules):
return python(*args, **kwargs)
request: Final = self.request(args, kwargs)
if request is None:
@ -91,7 +91,7 @@ class PublicDispatch(Generic[RequestT]):
python=python,
rules=selected_rules,
)
if not catalog.may_leave_python(self.route, selected_rules):
if not catalog.rust_might_handle(self.route, selected_rules):
return await python(*args, **kwargs)
request: Final = self.request(args, kwargs)
if request is None:

View file

@ -113,20 +113,19 @@ def _without_bags(legacy: inspect.Signature, named: Mapping[str, object]) -> Map
return MappingProxyType({name: value for name, value in named.items() if legacy.parameters[name].kind not in _BAGS})
def _is_true(value: object) -> bool:
return value is True
@dataclass(frozen=True, slots=True)
class AsyncFlag:
"""The keyword that makes a sync entry hand off to its async entry, as in ``completion(..., acompletion=True)``.
``is_set`` is the route's own reading of the flag. ``@client`` hands off on ``is True``, the Messages handler on truthiness.
Completion uses ``AsyncFlag("acompletion", sync=signature(_PYTHON_COMPLETION))``.
Messages uses ``AsyncFlag("is_async", sync=signature(_PYTHON_MESSAGES), is_set=bool)``.
"""
name: str
sync: inspect.Signature
is_set: Callable[[object], bool] = _is_true
is_set: Callable[[object], bool] = lambda value: value is True
def requested(self, kwargs: Mapping[str, object]) -> bool:
return self.is_set(kwargs.get(self.name))