new wf_server: local static workflow server; docs

This commit is contained in:
lda
2026-06-03 06:29:56 +07:00 Verified
parent e1d71d7d37
commit f13f099949
10 changed files with 808 additions and 155 deletions
+4
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
from .listing import matches_query, paged_list_payload
from .artifacts import WorkflowArtifactApi
from .local_sources import builtin_sources, get_qualified_spec, qualify_spec
from .models import RawWorkflowPlan, TraceRange
from .capabilities import WorkflowCapabilityApi
from .constants import (
@@ -43,8 +44,11 @@ from .durable_context import durable_workflow_api, require_workflow_stores
__all__ = [
"DEFAULT_CALL_STEP_ID",
"builtin_sources",
"get_qualified_spec",
"matches_query",
"paged_list_payload",
"qualify_spec",
"DEFAULT_ERROR_OUTCOME",
"DEFAULT_ERROR_STEP_ID",
"DEFAULT_OK_OUTCOME",
+186
View File
@@ -0,0 +1,186 @@
from __future__ import annotations
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any
from wf_authoring import NodeSpec, coalesce, concat, constant, default_if_none
from wf_authoring import extract_field, filter_items, filter_items_present, first_item
from wf_authoring import first_item_maybe, first_item_or_none, is_empty, last_item
from wf_authoring import last_item_or_none, length, node, pick_key, pick_path
from wf_authoring import project_fields, rename_fields, runtime_error, truthy
from wf_authoring import extract_text_content
from wf_core.runtime.ops.merges import DEFAULT_REDUCER_DEFINITIONS
from wf_platform import (
CapabilityBuckets,
CapabilitySource,
SourcePermissions,
SourceVisibility,
)
if TYPE_CHECKING:
from wf_core import ReducerSpec
BUILTIN_SOURCE_ID = "wf.std"
"""Internal source id for workflow standard-library node specs."""
BUILTIN_CONNECTION_ID = BUILTIN_SOURCE_ID
"""Compatibility alias for older MCP broker code."""
MCP_SOURCE_ID = "wf.mcp"
"""Reserved source id for future workflow-safe MCP utility node specs."""
RECIPE_SOURCE_ID = "wf.recipes"
"""Internal source id for first-party composed workflow recipes."""
AUTHORING_STD_SPECS: tuple[NodeSpec[Any, Any], ...] = (
coalesce,
default_if_none,
constant,
pick_key,
pick_path,
project_fields,
rename_fields,
truthy,
runtime_error,
first_item,
first_item_or_none,
first_item_maybe,
last_item,
last_item_or_none,
length,
is_empty,
filter_items,
filter_items_present,
extract_field,
concat,
)
"""Existing authoring ops exposed through the workflow stdlib."""
RECIPE_SPECS: tuple[NodeSpec[Any, Any], ...] = (extract_text_content,)
"""Composed first-party recipes exposed as workflow-facing capabilities."""
def qualify_node_name(source_id: str, local_name: str) -> str:
"""Return one source-qualified node name without assuming MCP connections."""
if not source_id:
raise ValueError("source_id must not be empty")
if not local_name:
raise ValueError("local node name must not be empty")
return f"{source_id}.{local_name}"
def qualify_spec(source_id: str, spec: NodeSpec[Any, Any]) -> NodeSpec[Any, Any]:
"""Return a copy of a spec with its node name scoped to a source."""
return NodeSpec(
name=qualify_node_name(source_id, spec.name),
input_model=spec.input_model,
output_model=spec.output_model,
outcomes=spec.outcomes,
fn=spec.fn,
description=spec.description,
is_async=spec.is_async,
accepts_context=spec.accepts_context,
input_schema_contract=spec.input_schema_contract,
output_schema_contract=spec.output_schema_contract,
)
def get_qualified_spec(
sources: Mapping[str, CapabilitySource],
qualified_name: str,
) -> NodeSpec[Any, Any]:
"""Resolve a namespaced node spec from enabled planner-visible sources."""
for source in sources.values():
if not source.enabled or not source.visibility.planner:
continue
spec = source.capabilities.node_specs.get(qualified_name)
if spec is not None:
return spec
raise KeyError(f"unknown qualified node {qualified_name!r}")
def _qualified_specs(
source_id: str,
specs: tuple[NodeSpec[Any, Any], ...],
) -> dict[str, NodeSpec[Any, Any]]:
"""Return specs with authoring names rewritten under one source id."""
local_specs = [
node(spec, name=spec.name.removeprefix("authoring.")) for spec in specs
]
qualified_specs = [qualify_spec(source_id, spec) for spec in local_specs]
return {spec.name: spec for spec in qualified_specs}
def builtin_specs() -> dict[str, NodeSpec[Any, Any]]:
"""Return primitive built-in NodeSpecs available to raw workflow plans."""
return _qualified_specs(BUILTIN_SOURCE_ID, AUTHORING_STD_SPECS)
def recipe_specs() -> dict[str, NodeSpec[Any, Any]]:
"""Return composed first-party recipe specs."""
return _qualified_specs(RECIPE_SOURCE_ID, RECIPE_SPECS)
def builtin_reducers() -> dict[str, ReducerSpec]:
"""Return built-in reducers owned by the workflow standard library."""
return {
definition.spec.name: definition.spec
for definition in DEFAULT_REDUCER_DEFINITIONS.values()
}
def builtin_reducer_definitions():
"""Return executable built-in reducers for trusted runtime dependency wiring."""
return dict(DEFAULT_REDUCER_DEFINITIONS)
def builtin_sources() -> dict[str, CapabilitySource]:
"""Return all local workflow-facing capability sources."""
return {
BUILTIN_SOURCE_ID: CapabilitySource(
id=BUILTIN_SOURCE_ID,
kind="system",
capabilities=CapabilityBuckets(
node_specs=builtin_specs(),
reducers=builtin_reducers(),
reducer_definitions=builtin_reducer_definitions(),
),
visibility=SourceVisibility(
planner=True,
mcp_client=True,
admin_dashboard=True,
),
permissions=SourcePermissions(safe_for_workflow=True),
description="Workflow standard-library nodes.",
),
RECIPE_SOURCE_ID: CapabilitySource(
id=RECIPE_SOURCE_ID,
kind="system",
capabilities=CapabilityBuckets(node_specs=recipe_specs()),
visibility=SourceVisibility(
planner=True,
mcp_client=True,
admin_dashboard=True,
),
permissions=SourcePermissions(safe_for_workflow=True),
description="First-party workflow recipes composed from standard nodes.",
),
}
__all__ = [
"AUTHORING_STD_SPECS",
"BUILTIN_CONNECTION_ID",
"BUILTIN_SOURCE_ID",
"MCP_SOURCE_ID",
"RECIPE_SOURCE_ID",
"RECIPE_SPECS",
"builtin_reducer_definitions",
"builtin_reducers",
"builtin_sources",
"builtin_specs",
"get_qualified_spec",
"qualify_node_name",
"qualify_spec",
"recipe_specs",
]