feat: add source registry mutations

This commit is contained in:
lda
2026-06-04 15:14:31 +07:00 Unverified
parent c0a885f050
commit 9ca81fedf2
15 changed files with 1689 additions and 80 deletions
+2
View File
@@ -26,6 +26,7 @@ from .service import WorkflowApi
from .source_admin import WorkflowSourceAdminApi
from .source_registry_admin import (
WorkflowSourceRegistryApi,
WorkflowSourceRegistryMutationProvider,
WorkflowSourceRegistryProvider,
)
from .surface import (
@@ -107,6 +108,7 @@ __all__ = [
"WorkflowSourceAdminApi",
"WorkflowSourceAdminSurface",
"WorkflowSourceRegistryApi",
"WorkflowSourceRegistryMutationProvider",
"WorkflowSourceRegistryProvider",
"WorkflowSourceRegistrySurface",
"WorkflowSpecProvider",
+95 -7
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
from collections.abc import Mapping, Sequence, Set
from dataclasses import asdict, is_dataclass
from typing import Any, Protocol
from typing import Any, Protocol, runtime_checkable
from wf_platform import page_items
@@ -15,8 +15,22 @@ class WorkflowSourceRegistryProvider(Protocol):
def config_source_ids(self) -> Set[str]: ...
@runtime_checkable
class WorkflowSourceRegistryMutationProvider(Protocol):
"""Write capabilities for source registry mutation operations."""
def add_registry_entry(self, entry: Mapping[str, Any]) -> Mapping[str, Any] | object: ...
def update_registry_entry(
self, source_id: str, patch: Mapping[str, Any]
) -> Mapping[str, Any] | object: ...
def set_registry_entry_enabled(
self, source_id: str, enabled: bool
) -> Mapping[str, Any] | object: ...
def remove_registry_entry(self, source_id: str) -> Mapping[str, Any] | object: ...
class WorkflowSourceRegistryApi:
"""Protocol-neutral read-only desired source registry operations.
"""Protocol-neutral desired source registry operations.
This surface is intentionally separate from WorkflowSourceAdminApi.
WorkflowSourceAdminApi exposes observed/hydrated runtime source inventory.
@@ -28,8 +42,13 @@ class WorkflowSourceRegistryApi:
self,
*,
provider: WorkflowSourceRegistryProvider,
mutation_provider: WorkflowSourceRegistryMutationProvider | None = None,
) -> None:
self._provider = provider
self._mutation_provider = mutation_provider
def _is_shadowed(self, source_id: str) -> bool:
return source_id in self._provider.config_source_ids()
async def list_registry_entries(
self,
@@ -37,10 +56,9 @@ class WorkflowSourceRegistryApi:
cursor: str | None = None,
limit: int = 50,
) -> dict[str, Any]:
shadowed_ids = set(self._provider.config_source_ids())
entries = sorted(
(
_entry_summary(_payload(item), shadowed_ids)
_entry_summary(_payload(item), self._provider.config_source_ids())
for item in self._provider.list_registry_entries()
),
key=lambda item: str(item.get("id", "")),
@@ -57,16 +75,86 @@ class WorkflowSourceRegistryApi:
*,
source_id: str,
) -> dict[str, Any]:
shadowed_ids = set(self._provider.config_source_ids())
for item in self._provider.list_registry_entries():
entry = _payload(item)
if entry.get("id") == source_id:
return {
"entry": entry,
"shadowed_by_config": source_id in shadowed_ids,
"shadowed_by_config": self._is_shadowed(source_id),
}
raise KeyError(f"unknown registry source {source_id!r}")
async def add_registry_entry(
self,
*,
entry: dict[str, Any],
) -> dict[str, Any]:
if self._mutation_provider is None:
raise TypeError("add_registry_entry requires a mutation provider")
raw = self._mutation_provider.add_registry_entry(entry)
result = _payload(raw)
return {
"entry": result,
"shadowed_by_config": self._is_shadowed(result["id"]),
}
async def update_registry_entry(
self,
*,
source_id: str,
patch: dict[str, Any],
) -> dict[str, Any]:
if self._mutation_provider is None:
raise TypeError("update_registry_entry requires a mutation provider")
raw = self._mutation_provider.update_registry_entry(source_id, patch)
result = _payload(raw)
return {
"entry": result,
"shadowed_by_config": self._is_shadowed(result["id"]),
}
async def enable_registry_entry(
self,
*,
source_id: str,
) -> dict[str, Any]:
if self._mutation_provider is None:
raise TypeError("enable_registry_entry requires a mutation provider")
raw = self._mutation_provider.set_registry_entry_enabled(source_id, True)
result = _payload(raw)
return {
"entry": result,
"shadowed_by_config": self._is_shadowed(result["id"]),
}
async def disable_registry_entry(
self,
*,
source_id: str,
) -> dict[str, Any]:
if self._mutation_provider is None:
raise TypeError("disable_registry_entry requires a mutation provider")
raw = self._mutation_provider.set_registry_entry_enabled(source_id, False)
result = _payload(raw)
return {
"entry": result,
"shadowed_by_config": self._is_shadowed(result["id"]),
}
async def remove_registry_entry(
self,
*,
source_id: str,
) -> dict[str, Any]:
if self._mutation_provider is None:
raise TypeError("remove_registry_entry requires a mutation provider")
raw = self._mutation_provider.remove_registry_entry(source_id)
result = _payload(raw)
return {
"removed": bool(result.get("removed")),
"source_id": str(result.get("source_id", source_id)),
}
def _payload(value: Mapping[str, Any] | object) -> dict[str, Any]:
"""Normalize provider objects without depending on MCP registry types."""
@@ -84,7 +172,7 @@ def _payload(value: Mapping[str, Any] | object) -> dict[str, Any]:
)
def _entry_summary(entry: dict[str, Any], shadowed_ids: set[str]) -> dict[str, Any]:
def _entry_summary(entry: dict[str, Any], shadowed_ids: Set[str]) -> dict[str, Any]:
transport = entry.get("transport")
transport_kind = transport.get("kind") if isinstance(transport, Mapping) else None
return {
+32 -1
View File
@@ -227,7 +227,7 @@ class WorkflowAdminSurface(Protocol):
class WorkflowSourceRegistrySurface(Protocol):
"""Read-only desired source registry methods exposed by platform frontends."""
"""Desired source registry methods exposed by platform frontends."""
async def list_registry_entries(
self,
@@ -242,6 +242,37 @@ class WorkflowSourceRegistrySurface(Protocol):
source_id: str,
) -> dict[str, Any]: ...
async def add_registry_entry(
self,
*,
entry: dict[str, Any],
) -> dict[str, Any]: ...
async def update_registry_entry(
self,
*,
source_id: str,
patch: dict[str, Any],
) -> dict[str, Any]: ...
async def enable_registry_entry(
self,
*,
source_id: str,
) -> dict[str, Any]: ...
async def disable_registry_entry(
self,
*,
source_id: str,
) -> dict[str, Any]: ...
async def remove_registry_entry(
self,
*,
source_id: str,
) -> dict[str, Any]: ...
__all__ = [
"WorkflowAdminSurface",