feat: expose draft document replacement over rpc
This commit is contained in:
@@ -34,6 +34,7 @@ from .models import (
|
|||||||
PatchDraftParams,
|
PatchDraftParams,
|
||||||
PatchDraftWorkspaceParams,
|
PatchDraftWorkspaceParams,
|
||||||
ReadRunTraceParams,
|
ReadRunTraceParams,
|
||||||
|
ReplaceDraftWorkspaceDocumentParams,
|
||||||
RemoveDraftBindingParams,
|
RemoveDraftBindingParams,
|
||||||
RemoveDraftRouteParams,
|
RemoveDraftRouteParams,
|
||||||
RemoveDraftStepParams,
|
RemoveDraftStepParams,
|
||||||
@@ -90,6 +91,7 @@ __all__ = [
|
|||||||
"PatchDraftParams",
|
"PatchDraftParams",
|
||||||
"PatchDraftWorkspaceParams",
|
"PatchDraftWorkspaceParams",
|
||||||
"ReadRunTraceParams",
|
"ReadRunTraceParams",
|
||||||
|
"ReplaceDraftWorkspaceDocumentParams",
|
||||||
"RemoveDraftBindingParams",
|
"RemoveDraftBindingParams",
|
||||||
"RemoveDraftRouteParams",
|
"RemoveDraftRouteParams",
|
||||||
"RemoveDraftStepParams",
|
"RemoveDraftStepParams",
|
||||||
|
|||||||
@@ -99,6 +99,22 @@ class RpcDraftClientMixin:
|
|||||||
{"workspace_id": workspace_id, "revision": revision, "patch": patch},
|
{"workspace_id": workspace_id, "revision": revision, "patch": patch},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def replace_draft_workspace_document(
|
||||||
|
self: RpcCaller,
|
||||||
|
*,
|
||||||
|
workspace_id: str,
|
||||||
|
revision: int,
|
||||||
|
draft: dict[str, Any],
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
return await self._call(
|
||||||
|
"workflow.draft_workspaces.replace_document",
|
||||||
|
{
|
||||||
|
"workspace_id": workspace_id,
|
||||||
|
"revision": revision,
|
||||||
|
"draft": draft,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
async def set_draft_name(
|
async def set_draft_name(
|
||||||
self: RpcCaller,
|
self: RpcCaller,
|
||||||
*,
|
*,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from ..models import (
|
|||||||
ListDraftWorkspacesParams,
|
ListDraftWorkspacesParams,
|
||||||
PatchDraftParams,
|
PatchDraftParams,
|
||||||
PatchDraftWorkspaceParams,
|
PatchDraftWorkspaceParams,
|
||||||
|
ReplaceDraftWorkspaceDocumentParams,
|
||||||
RemoveDraftBindingParams,
|
RemoveDraftBindingParams,
|
||||||
RemoveDraftRouteParams,
|
RemoveDraftRouteParams,
|
||||||
RemoveDraftStepParams,
|
RemoveDraftStepParams,
|
||||||
@@ -147,6 +148,22 @@ def register_methods(
|
|||||||
except (ValueError, KeyError, LookupError, FileNotFoundError) as exc:
|
except (ValueError, KeyError, LookupError, FileNotFoundError) as exc:
|
||||||
raise_workflow_rpc_error(exc)
|
raise_workflow_rpc_error(exc)
|
||||||
|
|
||||||
|
@entrypoint.method(
|
||||||
|
name="workflow.draft_workspaces.replace_document",
|
||||||
|
errors=[WorkflowRpcError],
|
||||||
|
)
|
||||||
|
async def workflow_draft_workspaces_replace_document(
|
||||||
|
params: ReplaceDraftWorkspaceDocumentParams = RpcParams(),
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
try:
|
||||||
|
return await server.api.replace_draft_workspace_document(
|
||||||
|
workspace_id=params.workspace_id,
|
||||||
|
revision=params.revision,
|
||||||
|
draft=params.draft,
|
||||||
|
)
|
||||||
|
except (ValueError, KeyError, LookupError, FileNotFoundError) as exc:
|
||||||
|
raise_workflow_rpc_error(exc)
|
||||||
|
|
||||||
@entrypoint.method(
|
@entrypoint.method(
|
||||||
name="workflow.draft_workspaces.set_name", errors=[WorkflowRpcError]
|
name="workflow.draft_workspaces.set_name", errors=[WorkflowRpcError]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -153,6 +153,12 @@ class PatchDraftWorkspaceParams(RpcParamsModel):
|
|||||||
patch: list[dict[str, Any]]
|
patch: list[dict[str, Any]]
|
||||||
|
|
||||||
|
|
||||||
|
class ReplaceDraftWorkspaceDocumentParams(RpcParamsModel):
|
||||||
|
workspace_id: str = Field(min_length=1)
|
||||||
|
revision: int = Field(ge=1)
|
||||||
|
draft: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
class SetDraftNameParams(RpcParamsModel):
|
class SetDraftNameParams(RpcParamsModel):
|
||||||
workspace_id: str = Field(min_length=1)
|
workspace_id: str = Field(min_length=1)
|
||||||
revision: int = Field(ge=1)
|
revision: int = Field(ge=1)
|
||||||
|
|||||||
@@ -413,6 +413,60 @@ async def test_rpc_draft_workspace_methods(tmp_path) -> None:
|
|||||||
assert artifact["result"]["artifact_id"] == "remote_artifact"
|
assert artifact["result"]["artifact_id"] == "remote_artifact"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_replace_document_replaces_complete_draft_workspace(
|
||||||
|
tmp_path,
|
||||||
|
) -> None:
|
||||||
|
server = build_local_static_workflow_server(tmp_path / "store")
|
||||||
|
app = create_rpc_app(server)
|
||||||
|
transport = httpx.ASGITransport(app=app)
|
||||||
|
async with httpx.AsyncClient(transport=transport, base_url="http://test") as client:
|
||||||
|
await _rpc(
|
||||||
|
client,
|
||||||
|
"workflow.draft_workspaces.create_empty",
|
||||||
|
{"workspace_id": "report", "name": "initial"},
|
||||||
|
)
|
||||||
|
initial = await _rpc(
|
||||||
|
client,
|
||||||
|
"workflow.draft_workspaces.get",
|
||||||
|
{"workspace_id": "report", "include_draft": True},
|
||||||
|
)
|
||||||
|
replacement = {**initial["result"]["draft"], "name": "replacement"}
|
||||||
|
|
||||||
|
replaced = await _rpc(
|
||||||
|
client,
|
||||||
|
"workflow.draft_workspaces.replace_document",
|
||||||
|
{
|
||||||
|
"workspace_id": "report",
|
||||||
|
"revision": 1,
|
||||||
|
"draft": replacement,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
inspected = await _rpc(
|
||||||
|
client,
|
||||||
|
"workflow.draft_workspaces.get",
|
||||||
|
{"workspace_id": "report", "include_draft": True},
|
||||||
|
)
|
||||||
|
malformed = await _rpc(
|
||||||
|
client,
|
||||||
|
"workflow.draft_workspaces.replace_document",
|
||||||
|
{
|
||||||
|
"workspace_id": "report",
|
||||||
|
"revision": 2,
|
||||||
|
"draft": [],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
after_malformed = await _rpc(
|
||||||
|
client,
|
||||||
|
"workflow.draft_workspaces.get",
|
||||||
|
{"workspace_id": "report", "include_draft": True},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert replaced["result"]["revision"] == 2
|
||||||
|
assert inspected["result"]["draft"] == replacement
|
||||||
|
assert malformed["error"]["code"] == -32602
|
||||||
|
assert after_malformed["result"] == inspected["result"]
|
||||||
|
|
||||||
|
|
||||||
async def test_rpc_draft_workspace_lifecycle_methods(tmp_path) -> None:
|
async def test_rpc_draft_workspace_lifecycle_methods(tmp_path) -> None:
|
||||||
server = build_local_static_workflow_server(tmp_path / "store")
|
server = build_local_static_workflow_server(tmp_path / "store")
|
||||||
app = create_rpc_app(server)
|
app = create_rpc_app(server)
|
||||||
|
|||||||
@@ -399,6 +399,44 @@ async def test_rpc_client_sends_exact_draft_lifecycle_payloads() -> None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_client_sends_exact_replace_document_payload() -> None:
|
||||||
|
calls: list[dict[str, Any]] = []
|
||||||
|
|
||||||
|
class Client(RpcDraftClientMixin):
|
||||||
|
async def _call(self, method: str, params: dict[str, object]):
|
||||||
|
calls.append({"method": method, "params": params})
|
||||||
|
return {"revision": 5}
|
||||||
|
|
||||||
|
client = Client()
|
||||||
|
draft = {
|
||||||
|
"name": "report",
|
||||||
|
"input_schema": {"type": "object", "properties": {}},
|
||||||
|
"state_schema": {"type": "object", "properties": {}},
|
||||||
|
"output_schema": {"type": "object", "properties": {}},
|
||||||
|
"start": "finish",
|
||||||
|
"steps": {"finish": {"end": {}}},
|
||||||
|
"routes": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
result = await client.replace_draft_workspace_document(
|
||||||
|
workspace_id="report",
|
||||||
|
revision=4,
|
||||||
|
draft=draft,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["revision"] == 5
|
||||||
|
assert calls == [
|
||||||
|
{
|
||||||
|
"method": "workflow.draft_workspaces.replace_document",
|
||||||
|
"params": {
|
||||||
|
"workspace_id": "report",
|
||||||
|
"revision": 4,
|
||||||
|
"draft": draft,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def test_rpc_client_builds_capability_free_draft_lifecycle(tmp_path) -> None:
|
async def test_rpc_client_builds_capability_free_draft_lifecycle(tmp_path) -> None:
|
||||||
server = build_local_static_workflow_server(tmp_path / "store")
|
server = build_local_static_workflow_server(tmp_path / "store")
|
||||||
app = create_rpc_app(server)
|
app = create_rpc_app(server)
|
||||||
|
|||||||
Reference in New Issue
Block a user