feat: deliver Python workflow client
This commit is contained in:
@@ -5,25 +5,27 @@ from .service import WorkflowApi
|
||||
from .stores import WorkflowStores
|
||||
|
||||
|
||||
def require_workflow_stores(context: WorkflowOperationContext) -> WorkflowStores:
|
||||
def require_workflow_stores(
|
||||
context: WorkflowOperationContext,
|
||||
*,
|
||||
drafts: bool = True,
|
||||
) -> WorkflowStores:
|
||||
"""Return required stores or fail before constructing durable frontends.
|
||||
|
||||
`WorkflowOperationContext` keeps stores optional for compatibility tests and
|
||||
lightweight MCP surfaces. Durable API surfaces need all stores up front so a
|
||||
run cannot start without somewhere to persist artifacts, drafts, and stopped
|
||||
execution state.
|
||||
lightweight MCP surfaces. Durable API surfaces need artifact/run stores up
|
||||
front; a draft store is only required when draft APIs are enabled.
|
||||
"""
|
||||
missing = []
|
||||
if context.artifact_store is None:
|
||||
missing.append("artifact_store")
|
||||
if context.draft_workspace_store is None:
|
||||
if drafts and context.draft_workspace_store is None:
|
||||
missing.append("draft_workspace_store")
|
||||
if context.run_store is None:
|
||||
missing.append("run_store")
|
||||
if missing:
|
||||
raise ValueError("durable workflow API requires stores: " + ", ".join(missing))
|
||||
assert context.artifact_store is not None
|
||||
assert context.draft_workspace_store is not None
|
||||
assert context.run_store is not None
|
||||
return WorkflowStores(
|
||||
artifact_store=context.artifact_store,
|
||||
@@ -32,10 +34,14 @@ def require_workflow_stores(context: WorkflowOperationContext) -> WorkflowStores
|
||||
)
|
||||
|
||||
|
||||
def durable_workflow_api(context: WorkflowOperationContext) -> WorkflowApi:
|
||||
"""Construct a WorkflowApi only after durable store dependencies exist."""
|
||||
require_workflow_stores(context)
|
||||
return WorkflowApi(context)
|
||||
def durable_workflow_api(
|
||||
context: WorkflowOperationContext,
|
||||
*,
|
||||
drafts: bool = True,
|
||||
) -> WorkflowApi:
|
||||
"""Construct a durable API, optionally omitting the draft product surface."""
|
||||
require_workflow_stores(context, drafts=drafts)
|
||||
return WorkflowApi(context, drafts=drafts)
|
||||
|
||||
|
||||
__all__ = ["durable_workflow_api", "require_workflow_stores"]
|
||||
|
||||
+32
-4
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping, Sequence
|
||||
from typing import Any, Literal, overload
|
||||
from typing import Any, Literal, cast, overload
|
||||
|
||||
from wf_artifacts import ArtifactKind, compile_workflow_draft
|
||||
from wf_artifacts.drafts.models import DraftStep
|
||||
@@ -56,6 +56,19 @@ from .operation_context import WorkflowOperationContext
|
||||
from .runs import TraceRangeLike, WorkflowRunApi
|
||||
|
||||
|
||||
class _DisabledDraftSurface:
|
||||
"""Placeholder that fails clearly if disabled draft methods are called.
|
||||
|
||||
Keeping this tiny seam avoids constructing draft services while preserving
|
||||
the existing method layout on ``WorkflowApi`` for explicit draft callers.
|
||||
"""
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
raise RuntimeError(
|
||||
"workflow draft APIs are disabled; compose WorkflowApi with drafts=True"
|
||||
)
|
||||
|
||||
|
||||
def _authoring_schema(
|
||||
value: object,
|
||||
*,
|
||||
@@ -100,11 +113,26 @@ class WorkflowApi:
|
||||
callers share one operation surface without importing wf_mcp.
|
||||
"""
|
||||
|
||||
def __init__(self, context: WorkflowOperationContext) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
context: WorkflowOperationContext,
|
||||
*,
|
||||
drafts: bool = True,
|
||||
) -> None:
|
||||
self.context = context
|
||||
self.capabilities = WorkflowCapabilityApi(context)
|
||||
self.drafts = WorkflowDraftApi(context)
|
||||
self.draft_authoring = WorkflowDraftAuthoringApi(context, self.drafts)
|
||||
# ``drafts`` keeps server composition explicit: callers that omit draft
|
||||
# storage must pass False, while the default preserves legacy direct
|
||||
# WorkflowApi callers that use the draft service for validation only.
|
||||
self.drafts_enabled = drafts
|
||||
if self.drafts_enabled:
|
||||
self.drafts = WorkflowDraftApi(context)
|
||||
self.draft_authoring = WorkflowDraftAuthoringApi(context, self.drafts)
|
||||
else:
|
||||
self.drafts = cast(WorkflowDraftApi, _DisabledDraftSurface())
|
||||
self.draft_authoring = cast(
|
||||
WorkflowDraftAuthoringApi, _DisabledDraftSurface()
|
||||
)
|
||||
self.artifacts = WorkflowArtifactApi(context)
|
||||
self.deployments = WorkflowDeploymentApi(context)
|
||||
self.runs = WorkflowRunApi(context)
|
||||
|
||||
@@ -18,7 +18,7 @@ class WorkflowStores:
|
||||
"""Protocol-neutral persistence dependencies for workflow APIs."""
|
||||
|
||||
artifact_store: WorkflowArtifactStore
|
||||
draft_workspace_store: DraftWorkspaceStore
|
||||
draft_workspace_store: DraftWorkspaceStore | None
|
||||
run_store: RunStore
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user