feat: add capability source policy metadata

This commit is contained in:
lda
2026-06-13 18:07:27 +07:00 Verified
parent e667f5da11
commit 41c24fc0e5
3 changed files with 49 additions and 0 deletions
+6
View File
@@ -20,6 +20,8 @@ if TYPE_CHECKING:
SourceKind, SourceKind,
SourcePermissions, SourcePermissions,
SourcePermissionsSnapshot, SourcePermissionsSnapshot,
SourcePolicy,
SourcePolicySnapshot,
SourceStatus, SourceStatus,
SourceVisibility, SourceVisibility,
SourceVisibilitySnapshot, SourceVisibilitySnapshot,
@@ -37,6 +39,8 @@ _LAZY_EXPORTS = {
"SourceKind": ".sources", "SourceKind": ".sources",
"SourcePermissions": ".sources", "SourcePermissions": ".sources",
"SourcePermissionsSnapshot": ".sources", "SourcePermissionsSnapshot": ".sources",
"SourcePolicy": ".sources",
"SourcePolicySnapshot": ".sources",
"SourceStatus": ".sources", "SourceStatus": ".sources",
"SourceVisibility": ".sources", "SourceVisibility": ".sources",
"SourceVisibilitySnapshot": ".sources", "SourceVisibilitySnapshot": ".sources",
@@ -57,6 +61,8 @@ __all__ = [
"SourceKind", "SourceKind",
"SourcePermissions", "SourcePermissions",
"SourcePermissionsSnapshot", "SourcePermissionsSnapshot",
"SourcePolicy",
"SourcePolicySnapshot",
"SourceStatus", "SourceStatus",
"SourceVisibility", "SourceVisibility",
"SourceVisibilitySnapshot", "SourceVisibilitySnapshot",
+25
View File
@@ -30,6 +30,18 @@ class SourcePermissions:
mutates_auth: bool = False mutates_auth: bool = False
@dataclass(frozen=True, slots=True)
class SourcePolicy:
"""Runtime/deployment policy for one capability source.
Platform sources are process-provided built-ins such as `wf.std`. They are
not account-bound and should not require deployment source bindings.
"""
platform: bool = False
binding_required: bool = True
class SourceVisibilitySnapshot(BaseModel): class SourceVisibilitySnapshot(BaseModel):
"""Serializable visibility flags for one source inventory snapshot.""" """Serializable visibility flags for one source inventory snapshot."""
@@ -47,6 +59,13 @@ class SourcePermissionsSnapshot(BaseModel):
mutates_auth: bool = False mutates_auth: bool = False
class SourcePolicySnapshot(BaseModel):
"""Serializable source policy used by CLI/API inventory responses."""
platform: bool = False
binding_required: bool = True
class NodeSpecInventory(BaseModel): class NodeSpecInventory(BaseModel):
"""Serializable public contract for one executable node spec.""" """Serializable public contract for one executable node spec."""
@@ -108,6 +127,7 @@ class SourceStatus(BaseModel):
enabled: bool enabled: bool
visibility: SourceVisibilitySnapshot visibility: SourceVisibilitySnapshot
permissions: SourcePermissionsSnapshot permissions: SourcePermissionsSnapshot
policy: SourcePolicySnapshot
description: str | None = None description: str | None = None
tool_count: int tool_count: int
node_spec_count: int node_spec_count: int
@@ -142,6 +162,7 @@ class CapabilitySource:
enabled: bool = True enabled: bool = True
visibility: SourceVisibility = field(default_factory=SourceVisibility) visibility: SourceVisibility = field(default_factory=SourceVisibility)
permissions: SourcePermissions = field(default_factory=SourcePermissions) permissions: SourcePermissions = field(default_factory=SourcePermissions)
policy: SourcePolicy = field(default_factory=SourcePolicy)
description: str | None = None description: str | None = None
def as_status(self) -> SourceStatus: def as_status(self) -> SourceStatus:
@@ -161,6 +182,10 @@ class CapabilitySource:
mutates_config=self.permissions.mutates_config, mutates_config=self.permissions.mutates_config,
mutates_auth=self.permissions.mutates_auth, mutates_auth=self.permissions.mutates_auth,
), ),
policy=SourcePolicySnapshot(
platform=self.policy.platform,
binding_required=self.policy.binding_required,
),
description=self.description, description=self.description,
tool_count=len(self.capabilities.tools), tool_count=len(self.capabilities.tools),
node_spec_count=len(self.capabilities.node_specs), node_spec_count=len(self.capabilities.node_specs),
+18
View File
@@ -7,6 +7,7 @@ from wf_platform import (
DocumentationResource, DocumentationResource,
SourceInventory, SourceInventory,
SourcePermissions, SourcePermissions,
SourcePolicy,
SourceStatus, SourceStatus,
SourceVisibility, SourceVisibility,
build_documentation_source, build_documentation_source,
@@ -100,3 +101,20 @@ def test_documentation_source_owns_provider_neutral_resources() -> None:
assert source.capabilities.prompts["wf.docs.operator_guide"].text == ( assert source.capabilities.prompts["wf.docs.operator_guide"].text == (
"Read wf://docs/operator-manual first." "Read wf://docs/operator-manual first."
) )
def test_capability_source_exposes_policy_snapshot() -> None:
source = CapabilitySource(
id="wf.std",
kind="system",
policy=SourcePolicy(platform=True, binding_required=False),
)
status = source.as_status()
assert status.policy.platform is True
assert status.policy.binding_required is False
assert status.model_dump(mode="json")["policy"] == {
"platform": True,
"binding_required": False,
}