lift workflow stuff out of the big Tool register

This commit is contained in:
lda
2026-05-12 19:22:32 +07:00 Verified
parent 6b696ff56a
commit 8235794c58
4 changed files with 449 additions and 212 deletions
+159
View File
@@ -0,0 +1,159 @@
from __future__ import annotations
import asyncio
from typing import Any
from wf_artifacts import (
FileWorkflowArtifactStore,
RequiredCapability,
WorkflowArtifact,
WorkflowDeployment,
)
from wf_mcp.broker import WfMcpService
from wf_mcp.models import ConnectionConfig
from wf_mcp.storage import FileStore
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
from .test_support import echo_tool, local_temp_root
def test_workflow_surface_lists_artifact_catalog_entries() -> None:
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "surface_artifacts")
artifact_store.save_artifact(_artifact())
handlers = _handlers(artifact_store)
payload = asyncio.run(handlers.list_artifacts())
nodes = payload["nodes"]
assert len(nodes) == 1
assert nodes[0]["name"] == "workflow.summarize_docs.v1"
assert nodes[0]["required_sources"] == ["context7"]
assert "plan" not in nodes[0]
def test_workflow_surface_validates_deployment_dependencies() -> None:
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "surface_validate")
artifact_store.save_artifact(_artifact())
artifact_store.save_deployment(
WorkflowDeployment(
id="summarize_docs.personal",
artifact_id="summarize_docs",
artifact_version=1,
bindings={"context7": "context7.personal"},
)
)
handlers = _handlers(artifact_store)
payload = asyncio.run(
handlers.validate_deployment(deployment_id="summarize_docs.personal")
)
assert payload["status"] == "unrunnable"
assert payload["diagnostics"][0]["code"] == "source_missing"
def test_workflow_surface_runs_non_interrupting_deployment() -> None:
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "surface_run")
artifact_store.save_artifact(_echo_artifact())
artifact_store.save_deployment(
WorkflowDeployment(
id="echo.personal",
artifact_id="echo",
artifact_version=1,
bindings={"demo": "demo.personal"},
)
)
service = WfMcpService(
store=FileStore(local_temp_root() / "surface_run_mcp"),
artifact_store=artifact_store,
)
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_specs("demo.personal", echo_tool)
handlers = WorkflowSurfaceHandlers(service)
payload = asyncio.run(
handlers.run_deployment(
deployment_id="echo.personal",
workflow_input={"text": "hello"},
)
)
assert payload["status"] == "completed"
assert payload["output"]["echoed"] == "hello"
assert payload["diagnostics"] == []
def _handlers(artifact_store: FileWorkflowArtifactStore) -> WorkflowSurfaceHandlers:
service = WfMcpService(
store=FileStore(local_temp_root() / "surface_mcp"),
artifact_store=artifact_store,
)
return WorkflowSurfaceHandlers(service)
def _artifact() -> WorkflowArtifact:
return WorkflowArtifact(
id="summarize_docs",
version=1,
title="Summarize Docs",
description="Summarize retrieved documentation.",
input_schema={"type": "object", "properties": {}},
output_schema={"type": "object", "properties": {}},
outcomes=("done",),
plan={"name": "summarize_docs", "nodes": [], "edges": []},
required_capabilities={
"context7.query-docs": RequiredCapability(
logical_source="context7",
capability_name="query-docs",
kind="tool",
input_schema_hash="sha256:input",
output_schema_hash="sha256:output",
)
},
)
def _echo_artifact() -> WorkflowArtifact:
plan: dict[str, Any] = {
"name": "echo",
"input_schema": {
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
"state_schema": {"fields": {"echoed": {"type": "string"}}},
"output_schema": {
"type": "object",
"properties": {"echoed": {"type": "string"}},
"required": ["echoed"],
},
"start": "echo",
"nodes": [
{
"id": "echo",
"type": "node",
"node": "demo.personal.echo_tool",
"in_map": {"input.text": "text"},
"out_map": {"echoed": "state.echoed"},
}
],
"edges": [{"from": "echo", "outcome": "ok", "to": "__end__"}],
}
return WorkflowArtifact(
id="echo",
version=1,
title="Echo",
input_schema=plan["input_schema"],
output_schema=plan["output_schema"],
outcomes=("completed",),
plan=plan,
required_capabilities={
"demo.echo_tool": RequiredCapability(
logical_source="demo",
capability_name="echo_tool",
kind="node_spec",
)
},
)