feat: expose draft document replacement over rpc
This commit is contained in:
@@ -34,6 +34,7 @@ from .models import (
|
||||
PatchDraftParams,
|
||||
PatchDraftWorkspaceParams,
|
||||
ReadRunTraceParams,
|
||||
ReplaceDraftWorkspaceDocumentParams,
|
||||
RemoveDraftBindingParams,
|
||||
RemoveDraftRouteParams,
|
||||
RemoveDraftStepParams,
|
||||
@@ -90,6 +91,7 @@ __all__ = [
|
||||
"PatchDraftParams",
|
||||
"PatchDraftWorkspaceParams",
|
||||
"ReadRunTraceParams",
|
||||
"ReplaceDraftWorkspaceDocumentParams",
|
||||
"RemoveDraftBindingParams",
|
||||
"RemoveDraftRouteParams",
|
||||
"RemoveDraftStepParams",
|
||||
|
||||
@@ -99,6 +99,22 @@ class RpcDraftClientMixin:
|
||||
{"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(
|
||||
self: RpcCaller,
|
||||
*,
|
||||
|
||||
@@ -24,6 +24,7 @@ from ..models import (
|
||||
ListDraftWorkspacesParams,
|
||||
PatchDraftParams,
|
||||
PatchDraftWorkspaceParams,
|
||||
ReplaceDraftWorkspaceDocumentParams,
|
||||
RemoveDraftBindingParams,
|
||||
RemoveDraftRouteParams,
|
||||
RemoveDraftStepParams,
|
||||
@@ -147,6 +148,22 @@ def register_methods(
|
||||
except (ValueError, KeyError, LookupError, FileNotFoundError) as 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(
|
||||
name="workflow.draft_workspaces.set_name", errors=[WorkflowRpcError]
|
||||
)
|
||||
|
||||
@@ -153,6 +153,12 @@ class PatchDraftWorkspaceParams(RpcParamsModel):
|
||||
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):
|
||||
workspace_id: str = Field(min_length=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"
|
||||
|
||||
|
||||
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:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
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:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
app = create_rpc_app(server)
|
||||
|
||||
Reference in New Issue
Block a user