feat: deliver Python workflow client

This commit is contained in:
lda
2026-08-31 02:49:07 +07:00 Verified
parent d53b96fd7c
commit 5315d4b66e
18 changed files with 717 additions and 19 deletions
+117
View File
@@ -0,0 +1,117 @@
from __future__ import annotations
from typing import Any, cast
from wf_client.capabilities import CapabilityResult, RemoteCapability
from wf_client.deployments import Deployment, DeploymentValidation
from wf_client.protocols import WorkflowClientPort
from wf_client.runs import Run, TracePage
from wf_client.workflows import (
ArtifactRef,
WorkflowDiagnostic,
WorkflowValidation,
)
from wf_core import ValidationReport
from wf_platform import CapabilityRef
class _Port:
"""A port that records accidental representation-time remote operations."""
def __init__(self) -> None:
self.calls: list[tuple[str, dict[str, Any]]] = []
def __getattr__(self, name: str) -> Any:
async def operation(**params: Any) -> object:
self.calls.append((name, params))
return {}
return operation
def _port() -> _Port:
return _Port()
def test_capability_html_repr_is_bounded_and_does_not_call_port() -> None:
port = _port()
remote = RemoteCapability(
_port=cast(WorkflowClientPort, port),
ref=CapabilityRef.parse("app.default.search"),
qualified_name="app.default.search",
description="Search things <carefully>",
input_schema={"type": "object", "properties": {"query": {"type": "string"}}},
output_schema={"type": "object", "properties": {"items": {"type": "array"}}},
outcomes=("ok",),
is_async=False,
)
rendered = remote._repr_html_()
assert "app.default.search" in rendered
assert "input schema" in rendered.lower()
assert "&lt;carefully&gt;" in rendered
assert port.calls == []
def test_rich_representations_bound_large_values_and_redact_secret_like_fields() -> (
None
):
port = _port()
result = CapabilityResult(
outcome="ok",
output={"token": "do-not-show", "items": ["x" * 400] * 20},
diagnostics=(),
)
run = Run(
_port=cast(WorkflowClientPort, port),
run_id="run-1",
deployment_id="deployment-1",
status="completed",
outcome="ok",
output=result.output,
interrupt=None,
diagnostics=(),
trace_count=1000,
)
rendered = repr(run)
html = run._repr_html_()
assert len(rendered) <= 1_201
assert len(html) <= 2_500
assert "do-not-show" not in rendered
assert "do-not-show" not in html
assert "1000 frames" in rendered
assert port.calls == []
def test_all_rich_objects_render_without_port_access() -> None:
port = cast(WorkflowClientPort, _port())
diagnostic = WorkflowDiagnostic("error", "bad", "state.x", "broken")
local = ValidationReport()
objects = [
ArtifactRef("artifact", 1),
diagnostic,
WorkflowValidation(local, "valid", (diagnostic,)),
CapabilityResult("ok", {"value": 1}, ()),
DeploymentValidation("deployment", "artifact", 1, "runnable", ()),
TracePage(0, 25, (), False, 0),
]
for value in objects:
assert repr(value)
assert value._repr_html_()
assert repr(
Deployment.from_payload(
port,
{
"id": "deployment",
"artifact_id": "artifact",
"artifact_version": 1,
"bindings": [],
"drift_policy": "block",
},
)
)
assert port.calls == []