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
+9
View File
@@ -22,6 +22,15 @@ The durable product path is now `wf-rpc-server` plus neutral `wf_config` /
`wf_server` composition. The old `wf-mcp` script remains a legacy/special-purpose
MCP entrypoint and compatibility surface.
Completed: the async `wf_client` Python slice is verified against the real
JSON-RPC ASGI application. It covers capability discovery, local graph
authoring, remote validation, immutable artifact save, deployment selection,
and durable run execution. Rich client objects have bounded, secret-safe
`repr()` and `_repr_html_()` views that never perform remote I/O. Draft
workspaces remain a separate server/admin surface and are not part of the
client; server registration is explicit so the artifact -> deployment -> run
path does not require draft storage.
## Active Initiative: Workflow Console And Defense Demo
The next product-facing push is a local-first web console and defense demo that
+40
View File
@@ -25,6 +25,7 @@ For verified Python 3.14 dependency constraints and their removal criteria, see
| `wf_api` | Workflow application surface over core/artifacts/platform: capabilities, drafts, artifacts, deployments, runs, and source/admin surfaces. | `wf_cli`, `wf_server`, JSON-RPC clients, future transports. |
| `wf_server` | Durable server composition boundary around `WorkflowApi` plus optional admin/source-registry surfaces. Owns the `wf-rpc-server` startup CLI/policy. | Transport packages and server startup code. |
| `wf_transport_rpc_http` | JSON-RPC-over-HTTP app/client and compatibility CLI shim. | Remote `wf` clients and local server smoke tests. |
| `wf_client` | Async-native Python client for capability discovery, local authoring, immutable artifacts, deployments, and durable runs. | Python applications and notebooks using a workflow server. |
| `wf_sources_mcp` | MCP-as-upstream-source implementation: ids, registry DTOs, auth/catalog stores, discovery, SDK client/facade, runtime pool, wrappers. | `wf_server`, broker glue, MCP source tests. |
| `wf_mcp` | MCP frontend/compatibility package: legacy `wf-mcp` entrypoints, broker glue, proxy/admin tools, and shims while extraction continues. | Compatibility callers and MCP transport work. |
| `wf_cli` | Command-line frontend over local or remote workflow APIs. | Humans, scripts, agent skills. |
@@ -87,6 +88,8 @@ permanent graph node or expose it as a final workflow-output source.
- `wf_server.WorkflowServer`: durable workflow server composition object.
- `wf_transport_rpc_http.RpcWorkflowApiClient`: JSON-RPC client implementing
the workflow/admin surfaces over HTTP.
- `wf_client.App`: transport-independent async Python facade over capabilities,
authored workflows, saved artifacts, deployments, and durable runs.
- `wf_transport_rpc_http.create_rpc_app`: JSON-RPC HTTP adapter over an existing
`WorkflowServer`.
- `wf_sources_mcp.McpRuntimePool`: persistent MCP source runtime for stateful
@@ -121,6 +124,43 @@ permanent graph node or expose it as a final workflow-output source.
`--keep-temp` to preserve the generated config/store on failure.
- `examples/browser_click_workflow/` is a serial browser-click workflow
example with bounded before/after snapshots and full lifecycle tests.
### Python client walkthrough
The Python client is intended for an application that already has a running
workflow server. This is the complete shape of a real client call; the schema
arguments may be JSON Schema dictionaries or the application's schema model
values:
```python
from wf_client import App
app = App.from_http_jsonrpc("http://localhost:8765/rpc")
capability = await app.capability("wf.std.constant")
graph = app.new_workflow(
"example",
input_schema=InputModel,
state_schema=StateModel,
output_schema=OutputModel,
)
step = graph.use(capability)
graph.set_entry_point(step)
validation = await graph.validate()
validation.raise_for_errors()
artifact = await graph.save(version=1)
run = await artifact.run({})
```
The graph is a local, mutable builder. `validate()` checks its structure locally
and then asks the server to validate the serialized plan. `save()` persists an
immutable artifact version; it does not deploy or execute the graph.
`artifact.run()` selects or creates a deployment, validates its source bindings,
and starts a durable run. The returned run is a loaded snapshot; call
`refresh()`, `resume()`, or bounded `trace(start=..., limit=...)` when more
server state is needed.
Draft workspaces are intentionally not part of `wf_client`. They are a separate
server/admin surface and must be explicitly enabled when composing a server.
- `examples/agent_challenges/` contains reusable opencode challenge harnesses
for evaluating whether agents can use the public workflow CLI/server path.
+27
View File
@@ -51,6 +51,7 @@ OpenAPI, or a built-in source. It should see `CapabilitySource` and executable
| `wf_sources_python` | Trusted Python module registry loading and projection to `CapabilitySource`. | Authoring primitives, registry mutation/apply, sandboxing. |
| `wf_server` | `WorkflowServer` composition from config/store/source providers. | JSON-RPC method definitions, MCP protocol frontend. |
| `wf_transport_rpc_http` | JSON-RPC HTTP app/client around an existing `WorkflowServer`. | Server startup policy, source-provider composition. |
| `wf_client` | Async Python facade over a narrow client port: capability discovery, local authoring, artifact/deployment snapshots, and durable runs. | Draft workspace authoring, server composition, transport registration. |
| `wf_mcp` | Legacy/special-purpose MCP frontend, broker glue, proxy, compatibility shims. | New durable product behavior unless explicitly retiring old callers. |
## Data Flow
@@ -65,6 +66,17 @@ wf_config.server.sources[]
-> transport or CLI
```
Python applications consume the same server through `wf_client.App`; the
client's local builder and immutable snapshots sit above the transport:
```text
wf_client.App
-> WorkflowClientPort
-> RpcWorkflowApiClient
-> JSON-RPC HTTP
-> WorkflowServer / WorkflowApi
```
The first shared provider seam is intentionally static:
```python
@@ -212,3 +224,18 @@ Then add:
Do not add source-family branches inside `wf_api` run execution. Source-specific
logic belongs in the provider package or server composition layer.
## Python client boundary
`wf_client` is a consumer-facing layer, not another server API.
`App.from_http_jsonrpc()` creates a lazy HTTP transport; the first
capability/artifact/deployment/run operation performs I/O. `EditableWorkflow`
keeps graph construction local and uses the port only for remote validation and
artifact persistence. The server remains responsible for durable artifact,
deployment, and run stores and for resolving concrete source bindings.
The client intentionally omits draft workspace operations. Drafts are a
server-side authoring/admin surface, and a server composition must opt in to
registering their JSON-RPC methods. This keeps a normal Python application
focused on the stable artifact -> deployment -> run lifecycle while retaining
the underlying draft implementation for explicit server users.
+35
View File
@@ -20,6 +20,7 @@ frontends can share.
| `wf_sources_mcp` | MCP-as-upstream-source implementation: source ids, source registry DTOs, auth/catalog stores, discovery, SDK client/facade, persistent runtime pool, and tool-wrapper helpers. |
| `wf_mcp` | MCP frontend/compatibility package: old `wf-mcp` server entry points, broker glue around MCP-hosted services, proxy/admin tools, and compatibility shims while callers migrate. |
| `wf_transport_rpc_http` | JSON-RPC-over-HTTP transport adapter and remote client over `WorkflowApiSurface`, not a reimplementation of workflow business logic. |
| `wf_client` | Async Python consumer facade over a narrow capability/artifact/deployment/run port. It reconstructs immutable snapshots and keeps representations bounded and inert. |
| future `wf_http` / WebSocket / MCP server transports | Additional transports over `WorkflowApiSurface`, not new workflow application APIs. |
| `wf_cli` | CLI frontend over `WorkflowApiSurface`; it may run locally against process-local stores or target a remote JSON-RPC backend. |
@@ -107,6 +108,40 @@ Important rules:
Do not add a catch-all `service` field to the context. If a domain API needs a
new dependency, add a narrow protocol or explicit field.
## Python client lifecycle
The Python client makes the intended application flow explicit:
```python
app = App.from_http_jsonrpc("http://localhost:8765/rpc")
capability = await app.capability("wf.std.constant")
graph = app.new_workflow(
"example",
input_schema=InputModel,
state_schema=StateModel,
output_schema=OutputModel,
)
step = graph.use(capability)
graph.set_entry_point(step)
validation = await graph.validate()
validation.raise_for_errors()
artifact = await graph.save(version=1)
run = await artifact.run({})
```
The graph is an in-process builder. Validation is local structural checking
plus a server plan check. Saving creates an immutable, versioned artifact; it
does not execute anything. A deployment is the server's runnable configuration
for one exact artifact version, including logical-to-concrete source bindings
and drift policy. A run is a durable execution record for that deployment;
inspection and bounded trace reads return snapshots, while resume is an
explicit operation for interrupted runs.
`wf_client` does not expose draft workspaces. Draft API classes remain useful
to server/admin and console callers, but normal server composition keeps draft
JSON-RPC registration opt-in so artifact, deployment, and run durability do not
depend on a draft store.
## WorkflowApiSurface And Domain Services
`WorkflowApiSurface` is the public application contract shared by local and