feat: type draft workspace results
This commit is contained in:
@@ -71,12 +71,13 @@
|
|||||||
- A 2026-07-30 spike confirmed that `fastapi-jsonrpc` already exports a
|
- A 2026-07-30 spike confirmed that `fastapi-jsonrpc` already exports a
|
||||||
complete OpenRPC document for all 70 registered methods. Request payloads
|
complete OpenRPC document for all 70 registered methods. Request payloads
|
||||||
retain useful Pydantic schemas, so OpenRPC is a viable transport input.
|
retain useful Pydantic schemas, so OpenRPC is a viable transport input.
|
||||||
- Typed-result slices now give `workflow.health` and all artifact, deployment,
|
- Typed-result slices now give `workflow.health`, all artifact, deployment,
|
||||||
and run operations named transport-neutral result schemas: 16 of 70
|
and run operations, and 26 uniform persisted draft-workspace operations
|
||||||
methods. The remaining 54 success results still collapse to generic objects
|
named transport-neutral result schemas: 42 of 70 methods. The remaining 28
|
||||||
because their Python API and JSON-RPC handlers return `dict[str, Any]`.
|
success results still collapse to generic objects, including exceptional
|
||||||
Continue introducing operation result DTOs before adopting generated
|
draft compile/save shapes and capability/source/admin operations. Continue
|
||||||
TypeScript contracts.
|
introducing operation result DTOs before adopting generated TypeScript
|
||||||
|
contracts.
|
||||||
- The stock `@open-rpc/generator` TypeScript client is not suitable here. It
|
- The stock `@open-rpc/generator` TypeScript client is not suitable here. It
|
||||||
exhausted a 4 GB Node heap on the full contract and emitted invalid dotted
|
exhausted a 4 GB Node heap on the full contract and emitted invalid dotted
|
||||||
class members plus `any` results for a minimal `workflow.health` contract.
|
class members plus `any` results for a minimal `workflow.health` contract.
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ from .drafts import (
|
|||||||
_draft_input_maps,
|
_draft_input_maps,
|
||||||
_draft_output_map,
|
_draft_output_map,
|
||||||
)
|
)
|
||||||
|
from .models import DraftWorkspaceResult, JsonProjector
|
||||||
from .operation_context import WorkflowOperationContext
|
from .operation_context import WorkflowOperationContext
|
||||||
from .schema_projection import (
|
from .schema_projection import (
|
||||||
project_output_property_to_state_schema,
|
project_output_property_to_state_schema,
|
||||||
@@ -67,6 +68,8 @@ from .schema_projection import (
|
|||||||
validate_json_value_at_schema_path,
|
validate_json_value_at_schema_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_PROJECT_DRAFT_WORKSPACE = JsonProjector(DraftWorkspaceResult)
|
||||||
|
|
||||||
|
|
||||||
def _graph_parts(path: str) -> tuple[str, tuple[str, ...]]:
|
def _graph_parts(path: str) -> tuple[str, tuple[str, ...]]:
|
||||||
parsed = GraphSourcePath.parse(path)
|
parsed = GraphSourcePath.parse(path)
|
||||||
@@ -322,7 +325,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
) -> WorkflowDraftWorkspace | dict[str, Any]:
|
) -> WorkflowDraftWorkspace | DraftWorkspaceResult:
|
||||||
"""Load a workspace and enforce optimistic locking before semantic preflight."""
|
"""Load a workspace and enforce optimistic locking before semantic preflight."""
|
||||||
return self.drafts._workspace_if_revision_matches(
|
return self.drafts._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -367,7 +370,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
step: DraftStep,
|
step: DraftStep,
|
||||||
incoming: RouteSource | None = None,
|
incoming: RouteSource | None = None,
|
||||||
routes: dict[str, str] | None = None,
|
routes: dict[str, str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Add one typed draft step and optional route edits in one revision."""
|
"""Add one typed draft step and optional route edits in one revision."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -471,7 +474,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
output_map: dict[str, str] | None = None,
|
output_map: dict[str, str] | None = None,
|
||||||
error_message_source: str | GraphSourcePath | None = None,
|
error_message_source: str | GraphSourcePath | None = None,
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Bootstrap the smallest patchable draft around one workflow capability."""
|
"""Bootstrap the smallest patchable draft around one workflow capability."""
|
||||||
draft_input, draft_with = _draft_input_maps(
|
draft_input, draft_with = _draft_input_maps(
|
||||||
input=input,
|
input=input,
|
||||||
@@ -530,7 +533,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Replace one capability step's canonical input bindings atomically."""
|
"""Replace one capability step's canonical input bindings atomically."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -556,7 +559,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
and workspace.draft.get("input_schema", {}) == projected.input_schema
|
and workspace.draft.get("input_schema", {}) == projected.input_schema
|
||||||
and workspace.draft.get("state_schema", {}) == projected.state_schema
|
and workspace.draft.get("state_schema", {}) == projected.state_schema
|
||||||
):
|
):
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
|
|
||||||
patch = _step_input_bindings_patch(
|
patch = _step_input_bindings_patch(
|
||||||
workspace=workspace,
|
workspace=workspace,
|
||||||
@@ -651,7 +654,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
update: CapabilityStepUpdate,
|
update: CapabilityStepUpdate,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Return a workspace summary or conflict after one atomic step patch."""
|
"""Return a workspace summary or conflict after one atomic step patch."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -718,7 +721,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
and workspace.draft.get("input_schema", {}) == input_schema
|
and workspace.draft.get("input_schema", {}) == input_schema
|
||||||
and workspace.draft.get("state_schema", {}) == state_schema
|
and workspace.draft.get("state_schema", {}) == state_schema
|
||||||
):
|
):
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
|
|
||||||
next_draft = deepcopy(workspace.draft)
|
next_draft = deepcopy(workspace.draft)
|
||||||
next_steps = next_draft.get("steps")
|
next_steps = next_draft.get("steps")
|
||||||
@@ -739,7 +742,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Replace canonical workflow output bindings atomically."""
|
"""Replace canonical workflow output bindings atomically."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -839,7 +842,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
|
|
||||||
payload = [binding.model_dump(mode="json") for binding in bindings]
|
payload = [binding.model_dump(mode="json") for binding in bindings]
|
||||||
if workspace.draft.get("output", []) == payload and projected == output_schema:
|
if workspace.draft.get("output", []) == payload and projected == output_schema:
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
|
|
||||||
patch: list[dict[str, Any]] = []
|
patch: list[dict[str, Any]] = []
|
||||||
if projected != output_schema:
|
if projected != output_schema:
|
||||||
@@ -864,7 +867,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[OutputBinding],
|
bindings: Sequence[OutputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Replace one capability step's canonical output bindings atomically."""
|
"""Replace one capability step's canonical output bindings atomically."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -924,7 +927,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
step.get("output", []) == payload
|
step.get("output", []) == payload
|
||||||
and workspace.draft.get("state_schema", {}) == projected_state
|
and workspace.draft.get("state_schema", {}) == projected_state
|
||||||
):
|
):
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
|
|
||||||
return await self.drafts.patch_draft_workspace(
|
return await self.drafts.patch_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -945,7 +948,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
source_path: str,
|
source_path: str,
|
||||||
target_path: str,
|
target_path: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Bind a graph path to or from one capability-local path."""
|
"""Bind a graph path to or from one capability-local path."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -1141,7 +1144,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
desc: str | None = None,
|
desc: str | None = None,
|
||||||
retry: int | None = None,
|
retry: int | None = None,
|
||||||
timeout_seconds: int | None = None,
|
timeout_seconds: int | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Add one capability step plus explicit route/map/schema wiring.
|
"""Add one capability step plus explicit route/map/schema wiring.
|
||||||
|
|
||||||
This is a composed authoring helper for agents. It edits the draft in
|
This is a composed authoring helper for agents. It edits the draft in
|
||||||
@@ -1321,7 +1324,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
routes: dict[str, str],
|
routes: dict[str, str],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Atomically set routes for one step, preserving unspecified outcomes."""
|
"""Atomically set routes for one step, preserving unspecified outcomes."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -1338,7 +1341,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
raise ValueError(f"routes for step {step_id!r} must be an object")
|
raise ValueError(f"routes for step {step_id!r} must be an object")
|
||||||
merged = {**existing, **routes}
|
merged = {**existing, **routes}
|
||||||
if merged == existing:
|
if merged == existing:
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
return await self.drafts.patch_draft_workspace(
|
return await self.drafts.patch_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -1358,7 +1361,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
branches: Sequence[RouteSource],
|
branches: Sequence[RouteSource],
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Update the target for multiple (step, outcome) pairs atomically."""
|
"""Update the target for multiple (step, outcome) pairs atomically."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -1368,7 +1371,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
return checked
|
return checked
|
||||||
workspace = checked
|
workspace = checked
|
||||||
if not branches:
|
if not branches:
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
draft_routes = workspace.draft.get("routes", {})
|
draft_routes = workspace.draft.get("routes", {})
|
||||||
if not isinstance(draft_routes, dict):
|
if not isinstance(draft_routes, dict):
|
||||||
raise ValueError("draft routes must be an object")
|
raise ValueError("draft routes must be an object")
|
||||||
@@ -1397,7 +1400,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
if not patch:
|
if not patch:
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
return await self.drafts.patch_draft_workspace(
|
return await self.drafts.patch_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -1411,7 +1414,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Remove one route; missing routes are revision-checked no-ops."""
|
"""Remove one route; missing routes are revision-checked no-ops."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -1427,7 +1430,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
if not isinstance(step_routes, dict):
|
if not isinstance(step_routes, dict):
|
||||||
raise ValueError(f"routes for step {step_id!r} must be an object")
|
raise ValueError(f"routes for step {step_id!r} must be an object")
|
||||||
if outcome not in step_routes:
|
if outcome not in step_routes:
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
return await self.drafts.patch_draft_workspace(
|
return await self.drafts.patch_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -1448,7 +1451,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Remove a step and its own route map; inbound routes are left explicit."""
|
"""Remove a step and its own route map; inbound routes are left explicit."""
|
||||||
checked = self._workspace_if_revision_matches(
|
checked = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -1461,7 +1464,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
if not isinstance(steps, dict):
|
if not isinstance(steps, dict):
|
||||||
raise ValueError("draft steps must be an object")
|
raise ValueError("draft steps must be an object")
|
||||||
if step_id not in steps:
|
if step_id not in steps:
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
patch = [
|
patch = [
|
||||||
{
|
{
|
||||||
"op": "remove",
|
"op": "remove",
|
||||||
@@ -1490,7 +1493,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
inputs: Sequence[str] = (),
|
inputs: Sequence[str] = (),
|
||||||
outputs: Sequence[str] = (),
|
outputs: Sequence[str] = (),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Remove selected local input/output bindings from one draft step."""
|
"""Remove selected local input/output bindings from one draft step."""
|
||||||
if not inputs and not outputs:
|
if not inputs and not outputs:
|
||||||
raise ValueError("pass at least one input or output binding to remove")
|
raise ValueError("pass at least one input or output binding to remove")
|
||||||
@@ -1525,7 +1528,7 @@ class WorkflowDraftAuthoringApi:
|
|||||||
item for item in current_outputs if item.get("source") not in output_sources
|
item for item in current_outputs if item.get("source") not in output_sources
|
||||||
]
|
]
|
||||||
if next_inputs == current_inputs and next_outputs == current_outputs:
|
if next_inputs == current_inputs and next_outputs == current_outputs:
|
||||||
return summarize_draft_workspace(workspace)
|
return _PROJECT_DRAFT_WORKSPACE(summarize_draft_workspace(workspace))
|
||||||
patch: list[dict[str, Any]] = []
|
patch: list[dict[str, Any]] = []
|
||||||
if next_inputs != current_inputs:
|
if next_inputs != current_inputs:
|
||||||
patch.append(
|
patch.append(
|
||||||
|
|||||||
+101
-69
@@ -52,9 +52,19 @@ from .draft_payloads import (
|
|||||||
from .draft_payloads import (
|
from .draft_payloads import (
|
||||||
output_bindings_payload as _draft_output_bindings_payload,
|
output_bindings_payload as _draft_output_bindings_payload,
|
||||||
)
|
)
|
||||||
|
from .models import (
|
||||||
|
DeleteDraftWorkspaceResult,
|
||||||
|
DraftWorkspaceResult,
|
||||||
|
JsonProjector,
|
||||||
|
ListDraftWorkspacesResult,
|
||||||
|
)
|
||||||
from .operation_context import WorkflowOperationContext
|
from .operation_context import WorkflowOperationContext
|
||||||
from .schema_projection import project_property_to_schema_path, schema_path_exists
|
from .schema_projection import project_property_to_schema_path, schema_path_exists
|
||||||
|
|
||||||
|
_PROJECT_DRAFT_WORKSPACE = JsonProjector(DraftWorkspaceResult)
|
||||||
|
_PROJECT_DRAFT_WORKSPACE_LIST = JsonProjector(ListDraftWorkspacesResult)
|
||||||
|
_PROJECT_DRAFT_WORKSPACE_DELETE = JsonProjector(DeleteDraftWorkspaceResult)
|
||||||
|
|
||||||
|
|
||||||
def _empty_object_schema() -> dict[str, Any]:
|
def _empty_object_schema() -> dict[str, Any]:
|
||||||
"""Return one fresh unconstrained object schema for an empty draft."""
|
"""Return one fresh unconstrained object schema for an empty draft."""
|
||||||
@@ -108,25 +118,27 @@ class WorkflowDraftApi:
|
|||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
) -> WorkflowDraftWorkspace | dict[str, Any]:
|
) -> WorkflowDraftWorkspace | DraftWorkspaceResult:
|
||||||
"""Load a workspace or return its canonical revision-conflict payload."""
|
"""Load a workspace or return its canonical revision-conflict payload."""
|
||||||
workspace = self._draft_store().get_workspace(workspace_id)
|
workspace = self._draft_store().get_workspace(workspace_id)
|
||||||
if workspace.revision == revision:
|
if workspace.revision == revision:
|
||||||
return workspace
|
return workspace
|
||||||
return {
|
return _PROJECT_DRAFT_WORKSPACE(
|
||||||
**summarize_draft_workspace(workspace),
|
{
|
||||||
"status": "conflict",
|
**summarize_draft_workspace(workspace),
|
||||||
"diagnostics": [
|
"status": "conflict",
|
||||||
{
|
"diagnostics": [
|
||||||
"code": "revision_conflict",
|
{
|
||||||
"path": "revision",
|
"code": "revision_conflict",
|
||||||
"message": (
|
"path": "revision",
|
||||||
f"workspace {workspace.id!r} is at revision "
|
"message": (
|
||||||
f"{workspace.revision}, not {revision}"
|
f"workspace {workspace.id!r} is at revision "
|
||||||
),
|
f"{workspace.revision}, not {revision}"
|
||||||
}
|
),
|
||||||
],
|
}
|
||||||
}
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def _outcomes_for_capability(self, qualified_name: str) -> tuple[str, ...] | None:
|
def _outcomes_for_capability(self, qualified_name: str) -> tuple[str, ...] | None:
|
||||||
try:
|
try:
|
||||||
@@ -189,15 +201,17 @@ class WorkflowDraftApi:
|
|||||||
node_defs_for_draft=self._node_defs_for_draft,
|
node_defs_for_draft=self._node_defs_for_draft,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def list_draft_workspaces(self) -> dict[str, Any]:
|
async def list_draft_workspaces(self) -> ListDraftWorkspacesResult:
|
||||||
"""Return compact summaries for stored draft workspaces."""
|
"""Return compact summaries for stored draft workspaces."""
|
||||||
store = self._draft_store()
|
store = self._draft_store()
|
||||||
return {
|
return _PROJECT_DRAFT_WORKSPACE_LIST(
|
||||||
"workspaces": [
|
{
|
||||||
get_draft_workspace_record(store, workspace_id=workspace.id)
|
"workspaces": [
|
||||||
for workspace in store.list_workspaces()
|
get_draft_workspace_record(store, workspace_id=workspace.id)
|
||||||
]
|
for workspace in store.list_workspaces()
|
||||||
}
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
async def create_draft_workspace(
|
async def create_draft_workspace(
|
||||||
self,
|
self,
|
||||||
@@ -205,12 +219,14 @@ class WorkflowDraftApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
draft: dict[str, Any],
|
draft: dict[str, Any],
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return create_draft_workspace_record(
|
return _PROJECT_DRAFT_WORKSPACE(
|
||||||
self._draft_store(),
|
create_draft_workspace_record(
|
||||||
workspace_id=workspace_id,
|
self._draft_store(),
|
||||||
draft=draft,
|
workspace_id=workspace_id,
|
||||||
title=title,
|
draft=draft,
|
||||||
|
title=title,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def create_empty_draft_workspace(
|
async def create_empty_draft_workspace(
|
||||||
@@ -223,7 +239,7 @@ class WorkflowDraftApi:
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] = ("ok",),
|
outcomes: Sequence[str] = ("ok",),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Create an intentionally invalid, capability-free draft workspace.
|
"""Create an intentionally invalid, capability-free draft workspace.
|
||||||
|
|
||||||
The empty entry point is persisted so callers can assemble the graph in
|
The empty entry point is persisted so callers can assemble the graph in
|
||||||
@@ -272,22 +288,30 @@ class WorkflowDraftApi:
|
|||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
include_draft: bool = False,
|
include_draft: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return get_draft_workspace_record(
|
return _PROJECT_DRAFT_WORKSPACE(
|
||||||
self._draft_store(),
|
get_draft_workspace_record(
|
||||||
workspace_id=workspace_id,
|
self._draft_store(),
|
||||||
include_draft=include_draft,
|
workspace_id=workspace_id,
|
||||||
|
include_draft=include_draft,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def delete_draft_workspace(self, *, workspace_id: str) -> dict[str, Any]:
|
async def delete_draft_workspace(
|
||||||
|
self, *, workspace_id: str
|
||||||
|
) -> DeleteDraftWorkspaceResult:
|
||||||
deleted = self._draft_store().delete_workspace(workspace_id)
|
deleted = self._draft_store().delete_workspace(workspace_id)
|
||||||
return {
|
return _PROJECT_DRAFT_WORKSPACE_DELETE(
|
||||||
"workspace_id": workspace_id,
|
{
|
||||||
"deleted": deleted,
|
"workspace_id": workspace_id,
|
||||||
"status": "deleted" if deleted else "not_found",
|
"deleted": deleted,
|
||||||
}
|
"status": "deleted" if deleted else "not_found",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
async def validate_draft_workspace(self, *, workspace_id: str) -> dict[str, Any]:
|
async def validate_draft_workspace(
|
||||||
|
self, *, workspace_id: str
|
||||||
|
) -> DraftWorkspaceResult:
|
||||||
"""Refresh stored validation status without changing draft revision."""
|
"""Refresh stored validation status without changing draft revision."""
|
||||||
store = self._draft_store()
|
store = self._draft_store()
|
||||||
workspace = store.get_workspace(workspace_id)
|
workspace = store.get_workspace(workspace_id)
|
||||||
@@ -303,7 +327,9 @@ class WorkflowDraftApi:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
store.save_workspace(refreshed)
|
store.save_workspace(refreshed)
|
||||||
return get_draft_workspace_record(store, workspace_id=workspace_id)
|
return _PROJECT_DRAFT_WORKSPACE(
|
||||||
|
get_draft_workspace_record(store, workspace_id=workspace_id)
|
||||||
|
)
|
||||||
|
|
||||||
async def compile_draft_workspace(self, *, workspace_id: str) -> dict[str, Any]:
|
async def compile_draft_workspace(self, *, workspace_id: str) -> dict[str, Any]:
|
||||||
"""Compile a stored draft workspace without mutating it."""
|
"""Compile a stored draft workspace without mutating it."""
|
||||||
@@ -319,14 +345,16 @@ class WorkflowDraftApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
patch: list[dict[str, Any]],
|
patch: list[dict[str, Any]],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
store = self._draft_store()
|
store = self._draft_store()
|
||||||
return patch_draft_workspace_record(
|
return _PROJECT_DRAFT_WORKSPACE(
|
||||||
store,
|
patch_draft_workspace_record(
|
||||||
workspace_id=workspace_id,
|
store,
|
||||||
revision=revision,
|
workspace_id=workspace_id,
|
||||||
patch=patch,
|
revision=revision,
|
||||||
node_defs_for_draft=self._node_defs_for_draft,
|
patch=patch,
|
||||||
|
node_defs_for_draft=self._node_defs_for_draft,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def replace_validated_draft_document(
|
async def replace_validated_draft_document(
|
||||||
@@ -335,13 +363,15 @@ class WorkflowDraftApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
draft: dict[str, Any],
|
draft: dict[str, Any],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Persist a focused, structurally validated edit without provider lookup."""
|
"""Persist a focused, structurally validated edit without provider lookup."""
|
||||||
return replace_validated_draft_document(
|
return _PROJECT_DRAFT_WORKSPACE(
|
||||||
self._draft_store(),
|
replace_validated_draft_document(
|
||||||
workspace_id=workspace_id,
|
self._draft_store(),
|
||||||
revision=revision,
|
workspace_id=workspace_id,
|
||||||
draft=draft,
|
revision=revision,
|
||||||
|
draft=draft,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def replace_draft_workspace_document(
|
async def replace_draft_workspace_document(
|
||||||
@@ -350,14 +380,16 @@ class WorkflowDraftApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
draft: dict[str, Any],
|
draft: dict[str, Any],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Replace and semantically revalidate one complete workspace draft."""
|
"""Replace and semantically revalidate one complete workspace draft."""
|
||||||
return replace_draft_workspace_document_record(
|
return _PROJECT_DRAFT_WORKSPACE(
|
||||||
self._draft_store(),
|
replace_draft_workspace_document_record(
|
||||||
workspace_id=workspace_id,
|
self._draft_store(),
|
||||||
revision=revision,
|
workspace_id=workspace_id,
|
||||||
draft=draft,
|
revision=revision,
|
||||||
node_defs_for_draft=self._node_defs_for_draft,
|
draft=draft,
|
||||||
|
node_defs_for_draft=self._node_defs_for_draft,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def set_draft_name(
|
async def set_draft_name(
|
||||||
@@ -366,7 +398,7 @@ class WorkflowDraftApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
name: str,
|
name: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.patch_draft_workspace(
|
return await self.patch_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -379,7 +411,7 @@ class WorkflowDraftApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Select an entry point, including a forward-referenced step id."""
|
"""Select an entry point, including a forward-referenced step id."""
|
||||||
if not isinstance(step_id, str) or not step_id.strip():
|
if not isinstance(step_id, str) or not step_id.strip():
|
||||||
raise ValueError("draft start step id must not be blank")
|
raise ValueError("draft start step id must not be blank")
|
||||||
@@ -398,7 +430,7 @@ class WorkflowDraftApi:
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] | None = None,
|
outcomes: Sequence[str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Replace supplied top-level contract fields in one draft revision.
|
"""Replace supplied top-level contract fields in one draft revision.
|
||||||
|
|
||||||
Complete schema replacement is intentional: deep merging JSON Schema
|
Complete schema replacement is intentional: deep merging JSON Schema
|
||||||
@@ -445,7 +477,7 @@ class WorkflowDraftApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.patch_draft_workspace(
|
return await self.patch_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -469,7 +501,7 @@ class WorkflowDraftApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
input_map: dict[str, str],
|
input_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
input_values: dict[str, Any] = {}
|
input_values: dict[str, Any] = {}
|
||||||
if merge:
|
if merge:
|
||||||
workspace = self._workspace_if_revision_matches(
|
workspace = self._workspace_if_revision_matches(
|
||||||
@@ -504,7 +536,7 @@ class WorkflowDraftApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
if merge:
|
if merge:
|
||||||
workspace = self._workspace_if_revision_matches(
|
workspace = self._workspace_if_revision_matches(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -539,7 +571,7 @@ class WorkflowDraftApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
output_bindings: list[dict[str, Any]]
|
output_bindings: list[dict[str, Any]]
|
||||||
workspace: WorkflowDraftWorkspace | None = None
|
workspace: WorkflowDraftWorkspace | None = None
|
||||||
if merge:
|
if merge:
|
||||||
|
|||||||
@@ -34,6 +34,13 @@ from .deployments import (
|
|||||||
ValidateDeploymentResult,
|
ValidateDeploymentResult,
|
||||||
WorkflowDeploymentPayload,
|
WorkflowDeploymentPayload,
|
||||||
)
|
)
|
||||||
|
from .drafts import (
|
||||||
|
DeleteDraftWorkspaceResult,
|
||||||
|
DraftDiagnosticPayload,
|
||||||
|
DraftWorkspaceResult,
|
||||||
|
DraftWorkspaceSummary,
|
||||||
|
ListDraftWorkspacesResult,
|
||||||
|
)
|
||||||
from .runs import (
|
from .runs import (
|
||||||
InterruptPayload,
|
InterruptPayload,
|
||||||
InterruptRoutePayload,
|
InterruptRoutePayload,
|
||||||
@@ -55,8 +62,12 @@ __all__ = [
|
|||||||
"CapabilityRefPayload",
|
"CapabilityRefPayload",
|
||||||
"DeleteArtifactResult",
|
"DeleteArtifactResult",
|
||||||
"DeleteDeploymentResult",
|
"DeleteDeploymentResult",
|
||||||
|
"DeleteDraftWorkspaceResult",
|
||||||
"DependencyDiagnosticPayload",
|
"DependencyDiagnosticPayload",
|
||||||
"DeploymentSummary",
|
"DeploymentSummary",
|
||||||
|
"DraftDiagnosticPayload",
|
||||||
|
"DraftWorkspaceResult",
|
||||||
|
"DraftWorkspaceSummary",
|
||||||
"HealthResult",
|
"HealthResult",
|
||||||
"GuidedResultPayload",
|
"GuidedResultPayload",
|
||||||
"InterruptPayload",
|
"InterruptPayload",
|
||||||
@@ -65,6 +76,7 @@ __all__ = [
|
|||||||
"JsonProjector",
|
"JsonProjector",
|
||||||
"JsonSchema",
|
"JsonSchema",
|
||||||
"ListDeploymentsResult",
|
"ListDeploymentsResult",
|
||||||
|
"ListDraftWorkspacesResult",
|
||||||
"ListArtifactsResult",
|
"ListArtifactsResult",
|
||||||
"ListRunsResult",
|
"ListRunsResult",
|
||||||
"NextActionPatchExamplePayload",
|
"NextActionPatchExamplePayload",
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
"""Canonical result models for persisted draft-workspace operations."""
|
||||||
|
|
||||||
|
from typing import Any, Literal, NotRequired, TypedDict
|
||||||
|
|
||||||
|
from .common import JsonObject
|
||||||
|
|
||||||
|
|
||||||
|
class DraftDiagnosticPayload(TypedDict):
|
||||||
|
"""One validation or revision diagnostic attached to a draft workspace."""
|
||||||
|
|
||||||
|
code: str
|
||||||
|
path: str
|
||||||
|
message: str
|
||||||
|
step_id: NotRequired[str | None]
|
||||||
|
repair_hint: NotRequired[str | None]
|
||||||
|
details: NotRequired[JsonObject]
|
||||||
|
|
||||||
|
|
||||||
|
class DraftWorkspaceSummary(TypedDict):
|
||||||
|
"""Compact graph facts included with every persisted workspace result."""
|
||||||
|
|
||||||
|
# Invalid workspaces preserve malformed authoring values for later repair.
|
||||||
|
name: Any
|
||||||
|
start: Any
|
||||||
|
step_count: int
|
||||||
|
route_count: int
|
||||||
|
steps: list[str]
|
||||||
|
|
||||||
|
|
||||||
|
class DraftWorkspaceResult(TypedDict):
|
||||||
|
"""Canonical persisted workspace envelope returned after reads and edits."""
|
||||||
|
|
||||||
|
workspace_id: str
|
||||||
|
revision: int
|
||||||
|
title: str | None
|
||||||
|
status: Literal["valid", "invalid", "conflict"]
|
||||||
|
diagnostics: list[DraftDiagnosticPayload]
|
||||||
|
summary: DraftWorkspaceSummary
|
||||||
|
draft: NotRequired[JsonObject]
|
||||||
|
|
||||||
|
|
||||||
|
class ListDraftWorkspacesResult(TypedDict):
|
||||||
|
"""All persisted draft-workspace summaries."""
|
||||||
|
|
||||||
|
workspaces: list[DraftWorkspaceResult]
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteDraftWorkspaceResult(TypedDict):
|
||||||
|
"""Outcome of deleting one persisted draft workspace."""
|
||||||
|
|
||||||
|
workspace_id: str
|
||||||
|
deleted: bool
|
||||||
|
status: Literal["deleted", "not_found"]
|
||||||
+31
-28
@@ -16,8 +16,11 @@ from .drafts import WorkflowDraftApi
|
|||||||
from .models import (
|
from .models import (
|
||||||
DeleteArtifactResult,
|
DeleteArtifactResult,
|
||||||
DeleteDeploymentResult,
|
DeleteDeploymentResult,
|
||||||
|
DeleteDraftWorkspaceResult,
|
||||||
|
DraftWorkspaceResult,
|
||||||
ListArtifactsResult,
|
ListArtifactsResult,
|
||||||
ListDeploymentsResult,
|
ListDeploymentsResult,
|
||||||
|
ListDraftWorkspacesResult,
|
||||||
ListRunsResult,
|
ListRunsResult,
|
||||||
RawWorkflowPlan,
|
RawWorkflowPlan,
|
||||||
RunResult,
|
RunResult,
|
||||||
@@ -263,7 +266,7 @@ class WorkflowApi:
|
|||||||
|
|
||||||
# -- draft workspaces --
|
# -- draft workspaces --
|
||||||
|
|
||||||
async def list_draft_workspaces(self) -> dict[str, Any]:
|
async def list_draft_workspaces(self) -> ListDraftWorkspacesResult:
|
||||||
return await self.drafts.list_draft_workspaces()
|
return await self.drafts.list_draft_workspaces()
|
||||||
|
|
||||||
async def create_draft_workspace(
|
async def create_draft_workspace(
|
||||||
@@ -272,7 +275,7 @@ class WorkflowApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
draft: dict[str, Any],
|
draft: dict[str, Any],
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.create_draft_workspace(
|
return await self.drafts.create_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
draft=draft,
|
draft=draft,
|
||||||
@@ -289,7 +292,7 @@ class WorkflowApi:
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] = ("ok",),
|
outcomes: Sequence[str] = ("ok",),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.create_empty_draft_workspace(
|
return await self.drafts.create_empty_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
name=name,
|
name=name,
|
||||||
@@ -305,7 +308,7 @@ class WorkflowApi:
|
|||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
include_draft: bool = False,
|
include_draft: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.get_draft_workspace(
|
return await self.drafts.get_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
include_draft=include_draft,
|
include_draft=include_draft,
|
||||||
@@ -315,14 +318,14 @@ class WorkflowApi:
|
|||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DeleteDraftWorkspaceResult:
|
||||||
return await self.drafts.delete_draft_workspace(workspace_id=workspace_id)
|
return await self.drafts.delete_draft_workspace(workspace_id=workspace_id)
|
||||||
|
|
||||||
async def validate_draft_workspace(
|
async def validate_draft_workspace(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.validate_draft_workspace(workspace_id=workspace_id)
|
return await self.drafts.validate_draft_workspace(workspace_id=workspace_id)
|
||||||
|
|
||||||
async def compile_draft_workspace(
|
async def compile_draft_workspace(
|
||||||
@@ -338,7 +341,7 @@ class WorkflowApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
patch: list[dict[str, Any]],
|
patch: list[dict[str, Any]],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.patch_draft_workspace(
|
return await self.drafts.patch_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -351,7 +354,7 @@ class WorkflowApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
draft: dict[str, Any],
|
draft: dict[str, Any],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Replace and semantically revalidate one complete workspace draft."""
|
"""Replace and semantically revalidate one complete workspace draft."""
|
||||||
return await self.drafts.replace_draft_workspace_document(
|
return await self.drafts.replace_draft_workspace_document(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -365,7 +368,7 @@ class WorkflowApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
name: str,
|
name: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.set_draft_name(
|
return await self.drafts.set_draft_name(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -378,7 +381,7 @@ class WorkflowApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.set_draft_start(
|
return await self.drafts.set_draft_start(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -394,7 +397,7 @@ class WorkflowApi:
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] | None = None,
|
outcomes: Sequence[str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.set_draft_contract(
|
return await self.drafts.set_draft_contract(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -412,7 +415,7 @@ class WorkflowApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.set_draft_route(
|
return await self.drafts.set_draft_route(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -429,7 +432,7 @@ class WorkflowApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
input_map: dict[str, str],
|
input_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.set_step_input_map(
|
return await self.drafts.set_step_input_map(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -445,7 +448,7 @@ class WorkflowApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.set_step_input_bindings(
|
return await self.draft_authoring.set_step_input_bindings(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -460,7 +463,7 @@ class WorkflowApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[OutputBinding],
|
bindings: Sequence[OutputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.set_step_output_bindings(
|
return await self.draft_authoring.set_step_output_bindings(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -475,7 +478,7 @@ class WorkflowApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
update: CapabilityStepUpdate,
|
update: CapabilityStepUpdate,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Return the updated workspace summary or a revision-conflict payload."""
|
"""Return the updated workspace summary or a revision-conflict payload."""
|
||||||
return await self.draft_authoring.update_capability_step(
|
return await self.draft_authoring.update_capability_step(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
@@ -492,7 +495,7 @@ class WorkflowApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.set_step_output_map(
|
return await self.drafts.set_step_output_map(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -508,7 +511,7 @@ class WorkflowApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.drafts.set_workflow_output_map(
|
return await self.drafts.set_workflow_output_map(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -522,7 +525,7 @@ class WorkflowApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.set_workflow_output_bindings(
|
return await self.draft_authoring.set_workflow_output_bindings(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -537,7 +540,7 @@ class WorkflowApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
source_path: str,
|
source_path: str,
|
||||||
target_path: str,
|
target_path: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.bind_draft(
|
return await self.draft_authoring.bind_draft(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -562,7 +565,7 @@ class WorkflowApi:
|
|||||||
desc: str | None = None,
|
desc: str | None = None,
|
||||||
retry: int | None = None,
|
retry: int | None = None,
|
||||||
timeout_seconds: int | None = None,
|
timeout_seconds: int | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.add_step_from_capability(
|
return await self.draft_authoring.add_step_from_capability(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -588,7 +591,7 @@ class WorkflowApi:
|
|||||||
step: DraftStep,
|
step: DraftStep,
|
||||||
incoming: RouteSource | None = None,
|
incoming: RouteSource | None = None,
|
||||||
routes: dict[str, str] | None = None,
|
routes: dict[str, str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.add_step(
|
return await self.draft_authoring.add_step(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -605,7 +608,7 @@ class WorkflowApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
routes: dict[str, str],
|
routes: dict[str, str],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.branch_draft(
|
return await self.draft_authoring.branch_draft(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -620,7 +623,7 @@ class WorkflowApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
branches: list[dict[str, str]],
|
branches: list[dict[str, str]],
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
refs = [
|
refs = [
|
||||||
RouteSource(step_id=b["step_id"], outcome=b["outcome"]) for b in branches
|
RouteSource(step_id=b["step_id"], outcome=b["outcome"]) for b in branches
|
||||||
]
|
]
|
||||||
@@ -646,7 +649,7 @@ class WorkflowApi:
|
|||||||
output_map: dict[str, str] | None = None,
|
output_map: dict[str, str] | None = None,
|
||||||
error_message_source: Any | None = None,
|
error_message_source: Any | None = None,
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.create_minimal_draft_workspace(
|
return await self.draft_authoring.create_minimal_draft_workspace(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
name=name,
|
name=name,
|
||||||
@@ -669,7 +672,7 @@ class WorkflowApi:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.remove_draft_route(
|
return await self.draft_authoring.remove_draft_route(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -683,7 +686,7 @@ class WorkflowApi:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.remove_draft_step(
|
return await self.draft_authoring.remove_draft_step(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
@@ -698,7 +701,7 @@ class WorkflowApi:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
inputs: Sequence[str] = (),
|
inputs: Sequence[str] = (),
|
||||||
outputs: Sequence[str] = (),
|
outputs: Sequence[str] = (),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self.draft_authoring.remove_draft_binding(
|
return await self.draft_authoring.remove_draft_binding(
|
||||||
workspace_id=workspace_id,
|
workspace_id=workspace_id,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
|
|||||||
+29
-26
@@ -12,8 +12,11 @@ from .draft_updates import CapabilityStepUpdate
|
|||||||
from .models import (
|
from .models import (
|
||||||
DeleteArtifactResult,
|
DeleteArtifactResult,
|
||||||
DeleteDeploymentResult,
|
DeleteDeploymentResult,
|
||||||
|
DeleteDraftWorkspaceResult,
|
||||||
|
DraftWorkspaceResult,
|
||||||
ListArtifactsResult,
|
ListArtifactsResult,
|
||||||
ListDeploymentsResult,
|
ListDeploymentsResult,
|
||||||
|
ListDraftWorkspacesResult,
|
||||||
ListRunsResult,
|
ListRunsResult,
|
||||||
RunResult,
|
RunResult,
|
||||||
RunTraceResult,
|
RunTraceResult,
|
||||||
@@ -60,14 +63,14 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
not every same-process authoring helper on ``WorkflowApi``.
|
not every same-process authoring helper on ``WorkflowApi``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def list_draft_workspaces(self) -> dict[str, Any]: ...
|
async def list_draft_workspaces(self) -> ListDraftWorkspacesResult: ...
|
||||||
|
|
||||||
async def get_draft_workspace(
|
async def get_draft_workspace(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
include_draft: bool = False,
|
include_draft: bool = False,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def create_draft_workspace_from_capability(
|
async def create_draft_workspace_from_capability(
|
||||||
self,
|
self,
|
||||||
@@ -96,7 +99,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] = ("ok",),
|
outcomes: Sequence[str] = ("ok",),
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def patch_draft_workspace(
|
async def patch_draft_workspace(
|
||||||
self,
|
self,
|
||||||
@@ -104,7 +107,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
patch: list[dict[str, Any]],
|
patch: list[dict[str, Any]],
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def replace_draft_workspace_document(
|
async def replace_draft_workspace_document(
|
||||||
self,
|
self,
|
||||||
@@ -112,7 +115,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
draft: dict[str, Any],
|
draft: dict[str, Any],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Replace and semantically revalidate one complete workspace draft."""
|
"""Replace and semantically revalidate one complete workspace draft."""
|
||||||
...
|
...
|
||||||
|
|
||||||
@@ -122,7 +125,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
name: str,
|
name: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_draft_start(
|
async def set_draft_start(
|
||||||
self,
|
self,
|
||||||
@@ -130,7 +133,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_draft_contract(
|
async def set_draft_contract(
|
||||||
self,
|
self,
|
||||||
@@ -141,7 +144,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] | None = None,
|
outcomes: Sequence[str] | None = None,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_draft_route(
|
async def set_draft_route(
|
||||||
self,
|
self,
|
||||||
@@ -151,7 +154,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_step_input_map(
|
async def set_step_input_map(
|
||||||
self,
|
self,
|
||||||
@@ -161,7 +164,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
input_map: dict[str, str],
|
input_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_step_input_bindings(
|
async def set_step_input_bindings(
|
||||||
self,
|
self,
|
||||||
@@ -170,7 +173,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_step_output_bindings(
|
async def set_step_output_bindings(
|
||||||
self,
|
self,
|
||||||
@@ -179,7 +182,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[OutputBinding],
|
bindings: Sequence[OutputBinding],
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def update_capability_step(
|
async def update_capability_step(
|
||||||
self,
|
self,
|
||||||
@@ -188,7 +191,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
update: CapabilityStepUpdate,
|
update: CapabilityStepUpdate,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_step_output_map(
|
async def set_step_output_map(
|
||||||
self,
|
self,
|
||||||
@@ -198,7 +201,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_workflow_output_map(
|
async def set_workflow_output_map(
|
||||||
self,
|
self,
|
||||||
@@ -207,7 +210,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
revision: int,
|
revision: int,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def set_workflow_output_bindings(
|
async def set_workflow_output_bindings(
|
||||||
self,
|
self,
|
||||||
@@ -215,7 +218,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def bind_draft(
|
async def bind_draft(
|
||||||
self,
|
self,
|
||||||
@@ -225,7 +228,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
source_path: str,
|
source_path: str,
|
||||||
target_path: str,
|
target_path: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def add_step_from_capability(
|
async def add_step_from_capability(
|
||||||
self,
|
self,
|
||||||
@@ -243,7 +246,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
desc: str | None = None,
|
desc: str | None = None,
|
||||||
retry: int | None = None,
|
retry: int | None = None,
|
||||||
timeout_seconds: int | None = None,
|
timeout_seconds: int | None = None,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def add_step(
|
async def add_step(
|
||||||
self,
|
self,
|
||||||
@@ -254,7 +257,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
step: DraftStep,
|
step: DraftStep,
|
||||||
incoming: RouteSource | None = None,
|
incoming: RouteSource | None = None,
|
||||||
routes: dict[str, str] | None = None,
|
routes: dict[str, str] | None = None,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def branch_draft(
|
async def branch_draft(
|
||||||
self,
|
self,
|
||||||
@@ -263,7 +266,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
routes: dict[str, str],
|
routes: dict[str, str],
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def handle_draft(
|
async def handle_draft(
|
||||||
self,
|
self,
|
||||||
@@ -272,7 +275,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
revision: int,
|
revision: int,
|
||||||
branches: list[dict[str, str]],
|
branches: list[dict[str, str]],
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def remove_draft_route(
|
async def remove_draft_route(
|
||||||
self,
|
self,
|
||||||
@@ -281,7 +284,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def remove_draft_step(
|
async def remove_draft_step(
|
||||||
self,
|
self,
|
||||||
@@ -289,7 +292,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def remove_draft_binding(
|
async def remove_draft_binding(
|
||||||
self,
|
self,
|
||||||
@@ -299,13 +302,13 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
inputs: Sequence[str] = (),
|
inputs: Sequence[str] = (),
|
||||||
outputs: Sequence[str] = (),
|
outputs: Sequence[str] = (),
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def validate_draft_workspace(
|
async def validate_draft_workspace(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def compile_draft_workspace(
|
async def compile_draft_workspace(
|
||||||
self,
|
self,
|
||||||
@@ -317,7 +320,7 @@ class WorkflowDraftSurface(Protocol):
|
|||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
) -> dict[str, Any]: ...
|
) -> DeleteDraftWorkspaceResult: ...
|
||||||
|
|
||||||
async def create_artifact_from_workspace(
|
async def create_artifact_from_workspace(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal, cast
|
||||||
|
|
||||||
from wf_api import CapabilityStepUpdate
|
from wf_api import CapabilityStepUpdate
|
||||||
|
from wf_api.models import (
|
||||||
|
DeleteDraftWorkspaceResult,
|
||||||
|
DraftWorkspaceResult,
|
||||||
|
ListDraftWorkspacesResult,
|
||||||
|
)
|
||||||
from wf_api.surface import RouteSource
|
from wf_api.surface import RouteSource
|
||||||
from wf_artifacts.drafts.models import DraftStep
|
from wf_artifacts.drafts.models import DraftStep
|
||||||
from wf_core.models.steps import InputBinding, OutputBinding
|
from wf_core.models.steps import InputBinding, OutputBinding
|
||||||
@@ -11,20 +16,33 @@ from wf_core.models.steps import InputBinding, OutputBinding
|
|||||||
from .base import RpcCaller
|
from .base import RpcCaller
|
||||||
|
|
||||||
|
|
||||||
|
async def _call_draft_workspace(
|
||||||
|
caller: RpcCaller,
|
||||||
|
method: str,
|
||||||
|
params: dict[str, Any],
|
||||||
|
) -> DraftWorkspaceResult:
|
||||||
|
"""Call one server-validated draft method with its canonical client type."""
|
||||||
|
return cast(DraftWorkspaceResult, await caller._call(method, params))
|
||||||
|
|
||||||
|
|
||||||
class RpcDraftClientMixin:
|
class RpcDraftClientMixin:
|
||||||
"""JSON-RPC implementation of workflow draft workspace surface methods."""
|
"""JSON-RPC implementation of workflow draft workspace surface methods."""
|
||||||
|
|
||||||
async def list_draft_workspaces(self: RpcCaller) -> dict[str, Any]:
|
async def list_draft_workspaces(self: RpcCaller) -> ListDraftWorkspacesResult:
|
||||||
return await self._call("workflow.draft_workspaces.list", {})
|
return cast(
|
||||||
|
ListDraftWorkspacesResult,
|
||||||
|
await self._call("workflow.draft_workspaces.list", {}),
|
||||||
|
)
|
||||||
|
|
||||||
async def get_draft_workspace(
|
async def get_draft_workspace(
|
||||||
self: RpcCaller,
|
self: RpcCaller,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
include_draft: bool = False,
|
include_draft: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
"""Return the remote workspace summary or revision-conflict payload."""
|
"""Return the remote workspace summary or revision-conflict payload."""
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.get",
|
"workflow.draft_workspaces.get",
|
||||||
{"workspace_id": workspace_id, "include_draft": include_draft},
|
{"workspace_id": workspace_id, "include_draft": include_draft},
|
||||||
)
|
)
|
||||||
@@ -73,8 +91,9 @@ class RpcDraftClientMixin:
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] = ("ok",),
|
outcomes: Sequence[str] = ("ok",),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.create_empty",
|
"workflow.draft_workspaces.create_empty",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -93,8 +112,9 @@ class RpcDraftClientMixin:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
patch: list[dict[str, Any]],
|
patch: list[dict[str, Any]],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.patch",
|
"workflow.draft_workspaces.patch",
|
||||||
{"workspace_id": workspace_id, "revision": revision, "patch": patch},
|
{"workspace_id": workspace_id, "revision": revision, "patch": patch},
|
||||||
)
|
)
|
||||||
@@ -105,8 +125,9 @@ class RpcDraftClientMixin:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
draft: dict[str, Any],
|
draft: dict[str, Any],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.replace_document",
|
"workflow.draft_workspaces.replace_document",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -121,8 +142,9 @@ class RpcDraftClientMixin:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
name: str,
|
name: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_name",
|
"workflow.draft_workspaces.set_name",
|
||||||
{"workspace_id": workspace_id, "revision": revision, "name": name},
|
{"workspace_id": workspace_id, "revision": revision, "name": name},
|
||||||
)
|
)
|
||||||
@@ -133,8 +155,9 @@ class RpcDraftClientMixin:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_start",
|
"workflow.draft_workspaces.set_start",
|
||||||
{"workspace_id": workspace_id, "revision": revision, "step_id": step_id},
|
{"workspace_id": workspace_id, "revision": revision, "step_id": step_id},
|
||||||
)
|
)
|
||||||
@@ -148,8 +171,9 @@ class RpcDraftClientMixin:
|
|||||||
state_schema: dict[str, Any] | None = None,
|
state_schema: dict[str, Any] | None = None,
|
||||||
output_schema: dict[str, Any] | None = None,
|
output_schema: dict[str, Any] | None = None,
|
||||||
outcomes: Sequence[str] | None = None,
|
outcomes: Sequence[str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_contract",
|
"workflow.draft_workspaces.set_contract",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -169,8 +193,9 @@ class RpcDraftClientMixin:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_route",
|
"workflow.draft_workspaces.set_route",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -189,8 +214,9 @@ class RpcDraftClientMixin:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
input_map: dict[str, str],
|
input_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_step_input_map",
|
"workflow.draft_workspaces.set_step_input_map",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -208,8 +234,9 @@ class RpcDraftClientMixin:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_step_input_bindings",
|
"workflow.draft_workspaces.set_step_input_bindings",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -226,8 +253,9 @@ class RpcDraftClientMixin:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
bindings: Sequence[OutputBinding],
|
bindings: Sequence[OutputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_step_output_bindings",
|
"workflow.draft_workspaces.set_step_output_bindings",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -244,8 +272,9 @@ class RpcDraftClientMixin:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
update: CapabilityStepUpdate,
|
update: CapabilityStepUpdate,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.update_capability_step",
|
"workflow.draft_workspaces.update_capability_step",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -263,8 +292,9 @@ class RpcDraftClientMixin:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_step_output_map",
|
"workflow.draft_workspaces.set_step_output_map",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -282,8 +312,9 @@ class RpcDraftClientMixin:
|
|||||||
revision: int,
|
revision: int,
|
||||||
output_map: dict[str, str],
|
output_map: dict[str, str],
|
||||||
merge: bool = False,
|
merge: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_workflow_output_map",
|
"workflow.draft_workspaces.set_workflow_output_map",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -299,8 +330,9 @@ class RpcDraftClientMixin:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
bindings: Sequence[InputBinding],
|
bindings: Sequence[InputBinding],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.set_workflow_output_bindings",
|
"workflow.draft_workspaces.set_workflow_output_bindings",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -317,8 +349,9 @@ class RpcDraftClientMixin:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
source_path: str,
|
source_path: str,
|
||||||
target_path: str,
|
target_path: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.bind",
|
"workflow.draft_workspaces.bind",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -345,7 +378,7 @@ class RpcDraftClientMixin:
|
|||||||
desc: str | None = None,
|
desc: str | None = None,
|
||||||
retry: int | None = None,
|
retry: int | None = None,
|
||||||
timeout_seconds: int | None = None,
|
timeout_seconds: int | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
if input_map is not None and input_bindings is not None:
|
if input_map is not None and input_bindings is not None:
|
||||||
raise ValueError("input_map and input_bindings are mutually exclusive")
|
raise ValueError("input_map and input_bindings are mutually exclusive")
|
||||||
params: dict[str, object] = {
|
params: dict[str, object] = {
|
||||||
@@ -370,7 +403,8 @@ class RpcDraftClientMixin:
|
|||||||
params["retry"] = retry
|
params["retry"] = retry
|
||||||
if timeout_seconds is not None:
|
if timeout_seconds is not None:
|
||||||
params["timeout_seconds"] = timeout_seconds
|
params["timeout_seconds"] = timeout_seconds
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.add_step_from_capability",
|
"workflow.draft_workspaces.add_step_from_capability",
|
||||||
params,
|
params,
|
||||||
)
|
)
|
||||||
@@ -384,8 +418,9 @@ class RpcDraftClientMixin:
|
|||||||
step: DraftStep,
|
step: DraftStep,
|
||||||
incoming: RouteSource | None = None,
|
incoming: RouteSource | None = None,
|
||||||
routes: dict[str, str] | None = None,
|
routes: dict[str, str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.add_step",
|
"workflow.draft_workspaces.add_step",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -408,8 +443,9 @@ class RpcDraftClientMixin:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
routes: dict[str, str],
|
routes: dict[str, str],
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.branch",
|
"workflow.draft_workspaces.branch",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -426,8 +462,9 @@ class RpcDraftClientMixin:
|
|||||||
revision: int,
|
revision: int,
|
||||||
branches: list[dict[str, str]],
|
branches: list[dict[str, str]],
|
||||||
target: str,
|
target: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.handle",
|
"workflow.draft_workspaces.handle",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -444,8 +481,9 @@ class RpcDraftClientMixin:
|
|||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
outcome: str,
|
outcome: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.remove_route",
|
"workflow.draft_workspaces.remove_route",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -461,8 +499,9 @@ class RpcDraftClientMixin:
|
|||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
revision: int,
|
revision: int,
|
||||||
step_id: str,
|
step_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.remove_step",
|
"workflow.draft_workspaces.remove_step",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -479,8 +518,9 @@ class RpcDraftClientMixin:
|
|||||||
step_id: str,
|
step_id: str,
|
||||||
inputs: Sequence[str] = (),
|
inputs: Sequence[str] = (),
|
||||||
outputs: Sequence[str] = (),
|
outputs: Sequence[str] = (),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.remove_binding",
|
"workflow.draft_workspaces.remove_binding",
|
||||||
{
|
{
|
||||||
"workspace_id": workspace_id,
|
"workspace_id": workspace_id,
|
||||||
@@ -495,8 +535,9 @@ class RpcDraftClientMixin:
|
|||||||
self: RpcCaller,
|
self: RpcCaller,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
return await self._call(
|
return await _call_draft_workspace(
|
||||||
|
self,
|
||||||
"workflow.draft_workspaces.validate",
|
"workflow.draft_workspaces.validate",
|
||||||
{"workspace_id": workspace_id},
|
{"workspace_id": workspace_id},
|
||||||
)
|
)
|
||||||
@@ -515,10 +556,13 @@ class RpcDraftClientMixin:
|
|||||||
self: RpcCaller,
|
self: RpcCaller,
|
||||||
*,
|
*,
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
) -> dict[str, Any]:
|
) -> DeleteDraftWorkspaceResult:
|
||||||
return await self._call(
|
return cast(
|
||||||
"workflow.draft_workspaces.delete",
|
DeleteDraftWorkspaceResult,
|
||||||
{"workspace_id": workspace_id},
|
await self._call(
|
||||||
|
"workflow.draft_workspaces.delete",
|
||||||
|
{"workspace_id": workspace_id},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def create_artifact_from_workspace(
|
async def create_artifact_from_workspace(
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
from __future__ import annotations
|
"""Draft JSON-RPC method registration.
|
||||||
|
|
||||||
|
Return annotations stay eagerly evaluated because fastapi-jsonrpc captures them
|
||||||
|
while registering nested handlers for response validation and OpenRPC output.
|
||||||
|
"""
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import fastapi_jsonrpc as jsonrpc
|
import fastapi_jsonrpc as jsonrpc
|
||||||
|
|
||||||
|
from wf_api.models import (
|
||||||
|
DeleteDraftWorkspaceResult,
|
||||||
|
DraftWorkspaceResult,
|
||||||
|
ListDraftWorkspacesResult,
|
||||||
|
)
|
||||||
from wf_api.surface import RouteSource
|
from wf_api.surface import RouteSource
|
||||||
from wf_server import WorkflowServer
|
from wf_server import WorkflowServer
|
||||||
|
|
||||||
@@ -83,7 +92,7 @@ def register_methods(
|
|||||||
@entrypoint.method(name="workflow.draft_workspaces.list", errors=[WorkflowRpcError])
|
@entrypoint.method(name="workflow.draft_workspaces.list", errors=[WorkflowRpcError])
|
||||||
async def workflow_draft_workspaces_list(
|
async def workflow_draft_workspaces_list(
|
||||||
params: ListDraftWorkspacesParams = RpcParams(),
|
params: ListDraftWorkspacesParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> ListDraftWorkspacesResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.list_draft_workspaces()
|
return await server.api.list_draft_workspaces()
|
||||||
except (ValueError, KeyError, LookupError, FileNotFoundError) as exc:
|
except (ValueError, KeyError, LookupError, FileNotFoundError) as exc:
|
||||||
@@ -92,7 +101,7 @@ def register_methods(
|
|||||||
@entrypoint.method(name="workflow.draft_workspaces.get", errors=[WorkflowRpcError])
|
@entrypoint.method(name="workflow.draft_workspaces.get", errors=[WorkflowRpcError])
|
||||||
async def workflow_draft_workspaces_get(
|
async def workflow_draft_workspaces_get(
|
||||||
params: GetDraftWorkspaceParams = RpcParams(),
|
params: GetDraftWorkspaceParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.get_draft_workspace(
|
return await server.api.get_draft_workspace(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -119,7 +128,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_create_empty(
|
async def workflow_draft_workspaces_create_empty(
|
||||||
params: CreateEmptyDraftWorkspaceParams = RpcParams(),
|
params: CreateEmptyDraftWorkspaceParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.create_empty_draft_workspace(
|
return await server.api.create_empty_draft_workspace(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -138,7 +147,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_patch(
|
async def workflow_draft_workspaces_patch(
|
||||||
params: PatchDraftWorkspaceParams = RpcParams(),
|
params: PatchDraftWorkspaceParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.patch_draft_workspace(
|
return await server.api.patch_draft_workspace(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -154,7 +163,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_replace_document(
|
async def workflow_draft_workspaces_replace_document(
|
||||||
params: ReplaceDraftWorkspaceDocumentParams = RpcParams(),
|
params: ReplaceDraftWorkspaceDocumentParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.replace_draft_workspace_document(
|
return await server.api.replace_draft_workspace_document(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -169,7 +178,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_name(
|
async def workflow_draft_workspaces_set_name(
|
||||||
params: SetDraftNameParams = RpcParams(),
|
params: SetDraftNameParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_draft_name(
|
return await server.api.set_draft_name(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -184,7 +193,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_start(
|
async def workflow_draft_workspaces_set_start(
|
||||||
params: SetDraftStartParams = RpcParams(),
|
params: SetDraftStartParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_draft_start(
|
return await server.api.set_draft_start(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -199,7 +208,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_contract(
|
async def workflow_draft_workspaces_set_contract(
|
||||||
params: SetDraftContractParams = RpcParams(),
|
params: SetDraftContractParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_draft_contract(
|
return await server.api.set_draft_contract(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -217,7 +226,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_route(
|
async def workflow_draft_workspaces_set_route(
|
||||||
params: SetDraftRouteParams = RpcParams(),
|
params: SetDraftRouteParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_draft_route(
|
return await server.api.set_draft_route(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -235,7 +244,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_step_input_map(
|
async def workflow_draft_workspaces_set_step_input_map(
|
||||||
params: SetStepInputMapParams = RpcParams(),
|
params: SetStepInputMapParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_step_input_map(
|
return await server.api.set_step_input_map(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -253,7 +262,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_step_input_bindings(
|
async def workflow_draft_workspaces_set_step_input_bindings(
|
||||||
params: SetStepInputBindingsParams = RpcParams(),
|
params: SetStepInputBindingsParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_step_input_bindings(
|
return await server.api.set_step_input_bindings(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -270,7 +279,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_update_capability_step(
|
async def workflow_draft_workspaces_update_capability_step(
|
||||||
params: UpdateCapabilityStepParams = RpcParams(),
|
params: UpdateCapabilityStepParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.update_capability_step(
|
return await server.api.update_capability_step(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -287,7 +296,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_step_output_bindings(
|
async def workflow_draft_workspaces_set_step_output_bindings(
|
||||||
params: SetStepOutputBindingsParams = RpcParams(),
|
params: SetStepOutputBindingsParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_step_output_bindings(
|
return await server.api.set_step_output_bindings(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -304,7 +313,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_step_output_map(
|
async def workflow_draft_workspaces_set_step_output_map(
|
||||||
params: SetStepOutputMapParams = RpcParams(),
|
params: SetStepOutputMapParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_step_output_map(
|
return await server.api.set_step_output_map(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -322,7 +331,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_workflow_output_map(
|
async def workflow_draft_workspaces_set_workflow_output_map(
|
||||||
params: SetWorkflowOutputMapParams = RpcParams(),
|
params: SetWorkflowOutputMapParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_workflow_output_map(
|
return await server.api.set_workflow_output_map(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -339,7 +348,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_set_workflow_output_bindings(
|
async def workflow_draft_workspaces_set_workflow_output_bindings(
|
||||||
params: SetWorkflowOutputBindingsParams = RpcParams(),
|
params: SetWorkflowOutputBindingsParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.set_workflow_output_bindings(
|
return await server.api.set_workflow_output_bindings(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -355,7 +364,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_bind(
|
async def workflow_draft_workspaces_bind(
|
||||||
params: BindDraftParams = RpcParams(),
|
params: BindDraftParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.bind_draft(
|
return await server.api.bind_draft(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -373,7 +382,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_add_step_from_capability(
|
async def workflow_draft_workspaces_add_step_from_capability(
|
||||||
params: AddStepFromCapabilityParams = RpcParams(),
|
params: AddStepFromCapabilityParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.add_step_from_capability(
|
return await server.api.add_step_from_capability(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -399,7 +408,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_add_step(
|
async def workflow_draft_workspaces_add_step(
|
||||||
params: AddDraftStepParams = RpcParams(),
|
params: AddDraftStepParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
incoming = (
|
incoming = (
|
||||||
None
|
None
|
||||||
@@ -425,7 +434,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_branch(
|
async def workflow_draft_workspaces_branch(
|
||||||
params: BranchDraftParams = RpcParams(),
|
params: BranchDraftParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.branch_draft(
|
return await server.api.branch_draft(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -441,7 +450,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_handle(
|
async def workflow_draft_workspaces_handle(
|
||||||
params: HandleDraftParams = RpcParams(),
|
params: HandleDraftParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.handle_draft(
|
return await server.api.handle_draft(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -460,7 +469,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_validate(
|
async def workflow_draft_workspaces_validate(
|
||||||
params: ValidateDraftWorkspaceParams = RpcParams(),
|
params: ValidateDraftWorkspaceParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.validate_draft_workspace(
|
return await server.api.validate_draft_workspace(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -486,7 +495,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_delete(
|
async def workflow_draft_workspaces_delete(
|
||||||
params: DeleteDraftWorkspaceParams = RpcParams(),
|
params: DeleteDraftWorkspaceParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DeleteDraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.delete_draft_workspace(
|
return await server.api.delete_draft_workspace(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -499,7 +508,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_remove_route(
|
async def workflow_draft_workspaces_remove_route(
|
||||||
params: RemoveDraftRouteParams = RpcParams(),
|
params: RemoveDraftRouteParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.remove_draft_route(
|
return await server.api.remove_draft_route(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -515,7 +524,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_remove_step(
|
async def workflow_draft_workspaces_remove_step(
|
||||||
params: RemoveDraftStepParams = RpcParams(),
|
params: RemoveDraftStepParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.remove_draft_step(
|
return await server.api.remove_draft_step(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
@@ -530,7 +539,7 @@ def register_methods(
|
|||||||
)
|
)
|
||||||
async def workflow_draft_workspaces_remove_binding(
|
async def workflow_draft_workspaces_remove_binding(
|
||||||
params: RemoveDraftBindingParams = RpcParams(),
|
params: RemoveDraftBindingParams = RpcParams(),
|
||||||
) -> dict[str, Any]:
|
) -> DraftWorkspaceResult:
|
||||||
try:
|
try:
|
||||||
return await server.api.remove_draft_binding(
|
return await server.api.remove_draft_binding(
|
||||||
workspace_id=params.workspace_id,
|
workspace_id=params.workspace_id,
|
||||||
|
|||||||
@@ -760,6 +760,28 @@ async def test_create_draft_workspace_creates_workspace(tmp_path: Path) -> None:
|
|||||||
assert fetched["draft"]["steps"]["echo"]["use"] == "demo.personal.echo_tool"
|
assert fetched["draft"]["steps"]["echo"]["use"] == "demo.personal.echo_tool"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_invalid_summary_values_remain_inspectable_and_listable(
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "invalid_summary_values")
|
||||||
|
api, _service, _authoring = _draft_api(artifact_store)
|
||||||
|
draft = _echo_draft()
|
||||||
|
draft["name"] = 123
|
||||||
|
draft["start"] = ["echo"]
|
||||||
|
|
||||||
|
created = await api.create_draft_workspace(
|
||||||
|
workspace_id="repairable",
|
||||||
|
draft=draft,
|
||||||
|
)
|
||||||
|
listed = await api.list_draft_workspaces()
|
||||||
|
|
||||||
|
assert created["status"] == "invalid"
|
||||||
|
assert created["summary"]["name"] == 123
|
||||||
|
assert created["summary"]["start"] == ["echo"]
|
||||||
|
assert listed["workspaces"][0]["workspace_id"] == "repairable"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_create_empty_draft_workspace_persists_invalid_skeleton(
|
async def test_create_empty_draft_workspace_persists_invalid_skeleton(
|
||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
|
|||||||
@@ -99,6 +99,109 @@ def test_openrpc_exposes_typed_artifact_results(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"method_name",
|
||||||
|
[
|
||||||
|
"workflow.draft_workspaces.get",
|
||||||
|
"workflow.draft_workspaces.create_empty",
|
||||||
|
"workflow.draft_workspaces.patch",
|
||||||
|
"workflow.draft_workspaces.replace_document",
|
||||||
|
"workflow.draft_workspaces.set_name",
|
||||||
|
"workflow.draft_workspaces.set_start",
|
||||||
|
"workflow.draft_workspaces.set_contract",
|
||||||
|
"workflow.draft_workspaces.set_route",
|
||||||
|
"workflow.draft_workspaces.set_step_input_map",
|
||||||
|
"workflow.draft_workspaces.set_step_input_bindings",
|
||||||
|
"workflow.draft_workspaces.update_capability_step",
|
||||||
|
"workflow.draft_workspaces.set_step_output_bindings",
|
||||||
|
"workflow.draft_workspaces.set_step_output_map",
|
||||||
|
"workflow.draft_workspaces.set_workflow_output_map",
|
||||||
|
"workflow.draft_workspaces.set_workflow_output_bindings",
|
||||||
|
"workflow.draft_workspaces.bind",
|
||||||
|
"workflow.draft_workspaces.add_step_from_capability",
|
||||||
|
"workflow.draft_workspaces.add_step",
|
||||||
|
"workflow.draft_workspaces.branch",
|
||||||
|
"workflow.draft_workspaces.handle",
|
||||||
|
"workflow.draft_workspaces.validate",
|
||||||
|
"workflow.draft_workspaces.remove_route",
|
||||||
|
"workflow.draft_workspaces.remove_step",
|
||||||
|
"workflow.draft_workspaces.remove_binding",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_openrpc_exposes_typed_draft_workspace_results(
|
||||||
|
openrpc_document: dict[str, Any],
|
||||||
|
method_name: str,
|
||||||
|
) -> None:
|
||||||
|
_assert_result_component(
|
||||||
|
openrpc_document,
|
||||||
|
method_name=method_name,
|
||||||
|
component_name="DraftWorkspaceResult",
|
||||||
|
properties={
|
||||||
|
"workspace_id",
|
||||||
|
"revision",
|
||||||
|
"title",
|
||||||
|
"status",
|
||||||
|
"diagnostics",
|
||||||
|
"summary",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_openrpc_exposes_typed_draft_workspace_list_result(
|
||||||
|
openrpc_document: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
_assert_result_component(
|
||||||
|
openrpc_document,
|
||||||
|
method_name="workflow.draft_workspaces.list",
|
||||||
|
component_name="ListDraftWorkspacesResult",
|
||||||
|
properties={"workspaces"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_openrpc_exposes_typed_delete_draft_workspace_result(
|
||||||
|
openrpc_document: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
_assert_result_component(
|
||||||
|
openrpc_document,
|
||||||
|
method_name="workflow.draft_workspaces.delete",
|
||||||
|
component_name="DeleteDraftWorkspaceResult",
|
||||||
|
properties={"workspace_id", "deleted", "status"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_openrpc_pins_nested_draft_workspace_contract(
|
||||||
|
openrpc_document: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
schemas = openrpc_document["components"]["schemas"]
|
||||||
|
workspace = schemas["DraftWorkspaceResult"]
|
||||||
|
diagnostic = schemas["DraftDiagnosticPayload"]
|
||||||
|
listed = schemas["ListDraftWorkspacesResult"]
|
||||||
|
deleted = schemas["DeleteDraftWorkspaceResult"]
|
||||||
|
|
||||||
|
assert workspace["required"] == [
|
||||||
|
"workspace_id",
|
||||||
|
"revision",
|
||||||
|
"title",
|
||||||
|
"status",
|
||||||
|
"diagnostics",
|
||||||
|
"summary",
|
||||||
|
]
|
||||||
|
assert "draft" not in workspace["required"]
|
||||||
|
assert workspace["properties"]["status"]["enum"] == [
|
||||||
|
"valid",
|
||||||
|
"invalid",
|
||||||
|
"conflict",
|
||||||
|
]
|
||||||
|
assert workspace["properties"]["diagnostics"]["items"] == {
|
||||||
|
"$ref": "#/components/schemas/DraftDiagnosticPayload"
|
||||||
|
}
|
||||||
|
assert diagnostic["required"] == ["code", "path", "message"]
|
||||||
|
assert listed["properties"]["workspaces"]["items"] == {
|
||||||
|
"$ref": "#/components/schemas/DraftWorkspaceResult"
|
||||||
|
}
|
||||||
|
assert deleted["properties"]["status"]["enum"] == ["deleted", "not_found"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("method_name", "component_name", "properties"),
|
("method_name", "component_name", "properties"),
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user