what now
This commit is contained in:
@@ -198,6 +198,9 @@ The code now has the first capability-source layer in place.
|
|||||||
Python callables. Inventory exposes `NodeSpecInventory` contracts instead:
|
Python callables. Inventory exposes `NodeSpecInventory` contracts instead:
|
||||||
names, descriptions, outcomes, schemas, and execution flags, but never the
|
names, descriptions, outcomes, schemas, and execution flags, but never the
|
||||||
wrapped function object itself.
|
wrapped function object itself.
|
||||||
|
- Reducer inventory follows the same rule: executable reducer definitions stay
|
||||||
|
private, while `ReducerInventory` exposes only reducer names, descriptions,
|
||||||
|
and config schemas.
|
||||||
- `WfMcpService.capability_sources` is the canonical in-memory registry.
|
- `WfMcpService.capability_sources` is the canonical in-memory registry.
|
||||||
- Planner node lookup reads `CapabilitySource.capabilities.node_specs`
|
- Planner node lookup reads `CapabilitySource.capabilities.node_specs`
|
||||||
directly; the old `SpecSource` compatibility layer has been removed.
|
directly; the old `SpecSource` compatibility layer has been removed.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from .sources import (
|
|||||||
CapabilityBuckets,
|
CapabilityBuckets,
|
||||||
CapabilitySource,
|
CapabilitySource,
|
||||||
NodeSpecInventory,
|
NodeSpecInventory,
|
||||||
|
ReducerInventory,
|
||||||
SourceCapabilityInventory,
|
SourceCapabilityInventory,
|
||||||
SourceInventory,
|
SourceInventory,
|
||||||
SourceKind,
|
SourceKind,
|
||||||
@@ -19,6 +20,7 @@ __all__ = [
|
|||||||
"CapabilitySource",
|
"CapabilitySource",
|
||||||
"CapabilityRef",
|
"CapabilityRef",
|
||||||
"NodeSpecInventory",
|
"NodeSpecInventory",
|
||||||
|
"ReducerInventory",
|
||||||
"SourceCapabilityInventory",
|
"SourceCapabilityInventory",
|
||||||
"SourceInventory",
|
"SourceInventory",
|
||||||
"SourceKind",
|
"SourceKind",
|
||||||
|
|||||||
@@ -55,6 +55,14 @@ class NodeSpecInventory(BaseModel):
|
|||||||
accepts_context: bool
|
accepts_context: bool
|
||||||
|
|
||||||
|
|
||||||
|
class ReducerInventory(BaseModel):
|
||||||
|
"""Serializable public contract for one pure reducer."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
description: str | None = None
|
||||||
|
config_schema: JsonObject
|
||||||
|
|
||||||
|
|
||||||
class SourceCapabilityInventory(BaseModel):
|
class SourceCapabilityInventory(BaseModel):
|
||||||
"""Serializable names owned by one source, grouped by capability kind."""
|
"""Serializable names owned by one source, grouped by capability kind."""
|
||||||
|
|
||||||
@@ -62,6 +70,7 @@ class SourceCapabilityInventory(BaseModel):
|
|||||||
node_specs: tuple[str, ...] = ()
|
node_specs: tuple[str, ...] = ()
|
||||||
node_spec_details: tuple[NodeSpecInventory, ...] = ()
|
node_spec_details: tuple[NodeSpecInventory, ...] = ()
|
||||||
reducers: tuple[str, ...] = ()
|
reducers: tuple[str, ...] = ()
|
||||||
|
reducer_details: tuple[ReducerInventory, ...] = ()
|
||||||
prompts: tuple[str, ...] = ()
|
prompts: tuple[str, ...] = ()
|
||||||
resources: tuple[str, ...] = ()
|
resources: tuple[str, ...] = ()
|
||||||
|
|
||||||
@@ -148,6 +157,17 @@ class CapabilitySource:
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
reducers=tuple(sorted(self.capabilities.reducers)),
|
reducers=tuple(sorted(self.capabilities.reducers)),
|
||||||
|
reducer_details=tuple(
|
||||||
|
ReducerInventory(
|
||||||
|
name=reducer.name,
|
||||||
|
description=reducer.description,
|
||||||
|
config_schema=reducer.config_schema,
|
||||||
|
)
|
||||||
|
for reducer in sorted(
|
||||||
|
self.capabilities.reducers.values(),
|
||||||
|
key=lambda reducer: reducer.name,
|
||||||
|
)
|
||||||
|
),
|
||||||
prompts=tuple(sorted(self.capabilities.prompts)),
|
prompts=tuple(sorted(self.capabilities.prompts)),
|
||||||
resources=tuple(sorted(self.capabilities.resources)),
|
resources=tuple(sorted(self.capabilities.resources)),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,7 +3,13 @@ from __future__ import annotations
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from wf_authoring import node
|
from wf_authoring import node
|
||||||
from wf_platform import CapabilityBuckets, CapabilitySource, NodeSpecInventory
|
from wf_core import ReducerSpec
|
||||||
|
from wf_platform import (
|
||||||
|
CapabilityBuckets,
|
||||||
|
CapabilitySource,
|
||||||
|
NodeSpecInventory,
|
||||||
|
ReducerInventory,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EchoInput(BaseModel):
|
class EchoInput(BaseModel):
|
||||||
@@ -37,3 +43,26 @@ def test_source_inventory_exposes_serializable_node_spec_details() -> None:
|
|||||||
assert detail.outcomes == ("ok",)
|
assert detail.outcomes == ("ok",)
|
||||||
assert detail.input_schema["properties"]["text"]["description"] == "Text to echo."
|
assert detail.input_schema["properties"]["text"]["description"] == "Text to echo."
|
||||||
assert "fn" not in dumped["capabilities"]["node_spec_details"][0]
|
assert "fn" not in dumped["capabilities"]["node_spec_details"][0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_source_inventory_exposes_serializable_reducer_details() -> None:
|
||||||
|
source = CapabilitySource(
|
||||||
|
id="wf.std",
|
||||||
|
kind="system",
|
||||||
|
capabilities=CapabilityBuckets(
|
||||||
|
reducers={
|
||||||
|
"wf.std.max": ReducerSpec(
|
||||||
|
name="wf.std.max",
|
||||||
|
description="Keep the greater value.",
|
||||||
|
config_schema={"type": "object", "properties": {}},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
detail = source.as_inventory().capabilities.reducer_details[0]
|
||||||
|
|
||||||
|
assert isinstance(detail, ReducerInventory)
|
||||||
|
assert detail.name == "wf.std.max"
|
||||||
|
assert detail.description == "Keep the greater value."
|
||||||
|
assert detail.config_schema == {"type": "object", "properties": {}}
|
||||||
|
|||||||
Reference in New Issue
Block a user