代码提交

This commit is contained in:
董宏凯 committed 2026-08-30 01:25:20 +08:00
1 parent 4ac7bc21cd
commit 17cf849361
110 files changed
+17007 -518

No files matched your search

@@ -0,0 +1,77 @@
"""``human_input`` node: suspends the run and validates the resumed payload."""
from __future__ import annotations
from typing import Any
from deerflow.workflows.errors import WorkflowError
from deerflow.workflows.expressions import render_template
from deerflow.workflows.runtime.context import RunContext, WorkflowPaused
from deerflow.workflows.schemas import NodeResult, WorkflowNode
DEFAULT_ACTIONS = ("submit",)
def _form_schema(node: WorkflowNode) -> dict[str, Any]:
schema = node.config.get("formSchema") or node.config.get("form_schema") or {}
return schema if isinstance(schema, dict) else {}
def _actions(node: WorkflowNode) -> list[str]:
raw = node.config.get("actions")
actions = [str(a) for a in raw] if isinstance(raw, list) and raw else list(DEFAULT_ACTIONS)
return actions
class HumanInputNodeExecutor:
"""First pass raises :class:`WorkflowPaused`; the resume pass consumes the
payload the API stored on the context and validates it against the form."""
async def execute(self, node: WorkflowNode, ctx: RunContext) -> NodeResult:
payload = ctx.resume_payload
if not payload or str(payload.get("nodeId") or "") != node.id:
raise WorkflowPaused(
node.id,
{
"nodeId": node.id,
"name": node.name,
"prompt": render_template(str(node.config.get("prompt") or ""), ctx.state()),
"formSchema": _form_schema(node),
"actions": _actions(node),
},
)
action = str(payload.get("action") or "submit")
allowed = _actions(node)
if action not in allowed:
raise WorkflowError(
"WORKFLOW_HUMAN_INPUT_INVALID",
f"不支持的操作:{action}",
node_id=node.id,
details={"allowed": allowed},
)
values = payload.get("values")
values = values if isinstance(values, dict) else {}
schema = _form_schema(node)
required = schema.get("required")
if isinstance(required, list) and action != "cancel":
missing = [str(key) for key in required if values.get(str(key)) in (None, "")]
if missing:
raise WorkflowError(
"WORKFLOW_HUMAN_INPUT_INVALID",
f"缺少必填项:{'、'.join(missing)}",
node_id=node.id,
details={"missing": missing},
)
if action == "cancel":
raise WorkflowError(
"WORKFLOW_CANCELLED",
"用户在人工节点选择终止运行",
node_id=node.id,
)
# One-shot: a later human node in the same run must pause again.
ctx.resume_payload = None
return NodeResult(data={"action": action, "values": values})
__all__ = ["HumanInputNodeExecutor"]