Files
lda-wf/src/wf_api/capability_requirements.py
T

70 lines
2.1 KiB
Python

from __future__ import annotations
from typing import Any
from wf_artifacts import (
RequiredCapability,
)
from wf_artifacts import (
create_workflow_artifact_from_plan as build_workflow_artifact_from_plan,
)
from wf_platform import CapabilityRef, NodeSpecInventory
from .artifact_plans import plan_nodes
from .operation_context import WorkflowOperationContext
def required_capability_payloads(
requirements: dict[str, RequiredCapability],
) -> dict[str, dict[str, Any]]:
"""Return deterministic JSON payloads for required capabilities."""
return {
name: capability.model_dump(mode="json")
for name, capability in sorted(requirements.items())
}
def observed_node_specs(
context: WorkflowOperationContext,
) -> dict[str, NodeSpecInventory]:
"""Project current executable specs into serializable observed contracts."""
observed: dict[str, NodeSpecInventory] = {}
for source in context.specs.capability_sources.values():
inventory = source.as_inventory()
observed.update(
{detail.name: detail for detail in inventory.capabilities.node_spec_details}
)
return observed
def required_capabilities_for_plan(
plan: dict[str, Any],
*,
source_bindings: dict[str, str] | None,
context: WorkflowOperationContext,
) -> dict[str, RequiredCapability]:
"""Infer a draft dependency summary without persisting an artifact."""
artifact = build_workflow_artifact_from_plan(
artifact_id="draft_preview",
version=1,
title="Draft Preview",
plan=plan,
outcomes=("completed",),
source_bindings=source_bindings,
observed_node_specs=observed_node_specs(context),
)
requirements = artifact.required_capability_map()
for node in plan_nodes(artifact):
raw_ref = node.get("node")
if not isinstance(raw_ref, str) or raw_ref in requirements:
continue
try:
parsed = CapabilityRef.parse(raw_ref)
except ValueError:
continue
requirements[raw_ref] = RequiredCapability(
ref=parsed,
kind="node_spec",
)
return requirements