refactor: extract NextActions into reusable workflow-surface models
Move wrapper-draft next_actions from handler-local dict helpers into typed models in workflow_surface/next_actions.py. Adds NextActionTool enum, NextActionPatchExample, and NextActions.from_wrapper_hints() constructor. Replaces private _wrapper_draft_next_actions and _wrapper_draft_patch_examples helpers. Adds can_continue as additive advisory field. Keeps backward-compatible aliases in models.py.
This commit is contained in:
@@ -116,6 +116,11 @@ def test_server_exposes_upstream_admin_and_workflow_tools() -> None:
|
||||
next_actions_schema = from_capability_output["properties"]["next_actions"]
|
||||
assert "recommended_next_tool" in next_actions_schema["properties"]
|
||||
assert "patch_examples" in next_actions_schema["properties"]
|
||||
assert "can_continue" in next_actions_schema["properties"]
|
||||
assert (
|
||||
"Advisory"
|
||||
in next_actions_schema["properties"]["can_continue"]["description"]
|
||||
)
|
||||
assert (
|
||||
"Advisory"
|
||||
in next_actions_schema["properties"]["can_save_now"]["description"]
|
||||
|
||||
@@ -541,6 +541,7 @@ def test_workflow_surface_creates_draft_workspace_from_capability_hints() -> Non
|
||||
assert result["wrapper_hints"]["input_map"] == {"input.text": "text"}
|
||||
assert result["wrapper_hints"]["output_map"] == {"echoed": "state.echoed"}
|
||||
next_actions = result["next_actions"]
|
||||
assert next_actions["can_continue"] is True
|
||||
assert next_actions["can_save_now"] is True
|
||||
assert (
|
||||
next_actions["recommended_next_tool"] == "wf.workflow.validate_draft_workspace"
|
||||
@@ -705,6 +706,7 @@ def test_workflow_surface_low_confidence_draft_returns_patch_guidance() -> None:
|
||||
)
|
||||
|
||||
next_actions = result["next_actions"]
|
||||
assert next_actions["can_continue"] is True
|
||||
assert next_actions["can_save_now"] is False
|
||||
assert next_actions["recommended_next_tool"] == "wf.workflow.patch_draft_workspace"
|
||||
assert "missing wrapper decisions" in next_actions["reason"]
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from wf_mcp.workflow_surface.next_actions import NextActionTool, NextActions
|
||||
|
||||
|
||||
def test_next_actions_from_high_confidence_wrapper_hints_can_validate() -> None:
|
||||
actions = NextActions.from_wrapper_hints(
|
||||
workspace_id="echo_workspace",
|
||||
revision=3,
|
||||
hints={
|
||||
"confidence": "high",
|
||||
"missing_decisions": [],
|
||||
"notes": [],
|
||||
},
|
||||
)
|
||||
|
||||
dumped = actions.model_dump(mode="json")
|
||||
assert dumped["can_continue"] is True
|
||||
assert dumped["can_save_now"] is True
|
||||
assert dumped["recommended_next_tool"] == (
|
||||
NextActionTool.VALIDATE_DRAFT_WORKSPACE.value
|
||||
)
|
||||
assert "high confidence" in dumped["reason"]
|
||||
assert dumped["patch_examples"] == []
|
||||
assert dumped["warnings"] == []
|
||||
|
||||
|
||||
def test_next_actions_from_low_confidence_wrapper_hints_can_patch() -> None:
|
||||
actions = NextActions.from_wrapper_hints(
|
||||
workspace_id="echo_workspace",
|
||||
revision=4,
|
||||
hints={
|
||||
"confidence": "low",
|
||||
"missing_decisions": [
|
||||
{
|
||||
"kind": "review_nested_output",
|
||||
"message": "Review nested output fields before mapping.",
|
||||
},
|
||||
{
|
||||
"kind": "confirm_boolean_outcomes",
|
||||
"message": "Boolean fields may be data, not outcomes.",
|
||||
},
|
||||
],
|
||||
"notes": ["Raw MCP tool output is not workflow-shaped."],
|
||||
},
|
||||
)
|
||||
|
||||
dumped = actions.model_dump(mode="json")
|
||||
assert dumped["can_continue"] is True
|
||||
assert dumped["can_save_now"] is False
|
||||
assert dumped["recommended_next_tool"] == NextActionTool.PATCH_DRAFT_WORKSPACE.value
|
||||
assert "missing wrapper decisions" in dumped["reason"]
|
||||
assert dumped["warnings"][0] == "Raw MCP tool output is not workflow-shaped."
|
||||
assert dumped["patch_examples"][0]["tool"] == (
|
||||
NextActionTool.PATCH_DRAFT_WORKSPACE.value
|
||||
)
|
||||
assert dumped["patch_examples"][0]["request"]["workspace_id"] == "echo_workspace"
|
||||
assert dumped["patch_examples"][0]["request"]["revision"] == 4
|
||||
assert dumped["patch_examples"][0]["request"]["patch"][0]["path"] == (
|
||||
"/draft/steps/call/output"
|
||||
)
|
||||
assert dumped["patch_examples"][1]["request"]["patch"] == []
|
||||
Reference in New Issue
Block a user