mirror of
https://github.com/langgenius/dify.git
synced 2026-01-14 06:07:33 +08:00
feat(api): expose workflow_run_id in human_input extra contents
This commit is contained in:
parent
c1215ad9ef
commit
b3069bf154
@ -1,74 +1,46 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping, Sequence
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, TypeAlias
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from core.workflow.nodes.human_input.entities import FormInput, UserAction
|
||||
from models.execution_extra_content import ExecutionContentType
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class HumanInputFormDefinition:
|
||||
class HumanInputFormDefinition(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
form_id: str
|
||||
node_id: str
|
||||
node_title: str
|
||||
form_content: str
|
||||
inputs: Sequence[FormInput] = field(default_factory=list)
|
||||
actions: Sequence[UserAction] = field(default_factory=list)
|
||||
inputs: Sequence[FormInput] = Field(default_factory=list)
|
||||
actions: Sequence[UserAction] = Field(default_factory=list)
|
||||
display_in_ui: bool = False
|
||||
form_token: str | None = None
|
||||
resolved_placeholder_values: Mapping[str, Any] = field(default_factory=dict)
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"form_id": self.form_id,
|
||||
"node_id": self.node_id,
|
||||
"node_title": self.node_title,
|
||||
"form_content": self.form_content,
|
||||
"inputs": [item.model_dump(mode="json") for item in self.inputs],
|
||||
"actions": [item.model_dump(mode="json") for item in self.actions],
|
||||
"display_in_ui": self.display_in_ui,
|
||||
"form_token": self.form_token,
|
||||
"resolved_placeholder_values": self.resolved_placeholder_values,
|
||||
}
|
||||
resolved_placeholder_values: Mapping[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class HumanInputFormSubmissionData:
|
||||
class HumanInputFormSubmissionData(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
node_id: str
|
||||
node_title: str
|
||||
rendered_content: str
|
||||
action_id: str
|
||||
action_text: str
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"node_id": self.node_id,
|
||||
"node_title": self.node_title,
|
||||
"rendered_content": self.rendered_content,
|
||||
"action_id": self.action_id,
|
||||
"action_text": self.action_text,
|
||||
}
|
||||
|
||||
class HumanInputContent(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class HumanInputContent:
|
||||
workflow_run_id: str
|
||||
submitted: bool
|
||||
form_definition: HumanInputFormDefinition | None = None
|
||||
form_submission_data: HumanInputFormSubmissionData | None = None
|
||||
type: ExecutionContentType = field(default=ExecutionContentType.HUMAN_INPUT, init=False)
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
payload: dict[str, Any] = {
|
||||
"type": self.type.value,
|
||||
"submitted": self.submitted,
|
||||
}
|
||||
if self.form_definition is not None:
|
||||
payload["form_definition"] = self.form_definition.to_dict()
|
||||
if self.form_submission_data is not None:
|
||||
payload["form_submission_data"] = self.form_submission_data.to_dict()
|
||||
return payload
|
||||
type: ExecutionContentType = Field(default=ExecutionContentType.HUMAN_INPUT)
|
||||
|
||||
|
||||
ExecutionExtraContentDomainModel: TypeAlias = HumanInputContent
|
||||
|
||||
@ -123,6 +123,7 @@ class SQLAlchemyExecutionExtraContentRepository(ExecutionExtraContentRepository)
|
||||
if not submitted:
|
||||
form_token = self._resolve_form_token(recipients_by_form_id.get(form.id, []))
|
||||
return HumanInputContentDomainModel(
|
||||
workflow_run_id=model.workflow_run_id,
|
||||
submitted=False,
|
||||
form_definition=HumanInputFormDefinition(
|
||||
form_id=form.id,
|
||||
@ -162,6 +163,7 @@ class SQLAlchemyExecutionExtraContentRepository(ExecutionExtraContentRepository)
|
||||
)
|
||||
|
||||
return HumanInputContentDomainModel(
|
||||
workflow_run_id=model.workflow_run_id,
|
||||
submitted=True,
|
||||
form_submission_data=HumanInputFormSubmissionData(
|
||||
node_id=form.node_id,
|
||||
|
||||
@ -44,7 +44,7 @@ def _attach_message_extra_contents(messages: Sequence[Message]) -> None:
|
||||
|
||||
for index, message in enumerate(messages):
|
||||
contents = extra_contents_lists[index] if index < len(extra_contents_lists) else []
|
||||
message.set_extra_contents([content.to_dict() for content in contents])
|
||||
message.set_extra_contents([content.model_dump(mode="json", exclude_none=True) for content in contents])
|
||||
|
||||
|
||||
class MessageService:
|
||||
|
||||
@ -25,6 +25,7 @@ def test_pagination_returns_extra_contents(db_session_with_containers):
|
||||
assert message.extra_contents == [
|
||||
{
|
||||
"type": "human_input",
|
||||
"workflow_run_id": fixture.message.workflow_run_id,
|
||||
"submitted": True,
|
||||
"form_submission_data": {
|
||||
"node_id": fixture.form.node_id,
|
||||
|
||||
@ -102,8 +102,9 @@ def test_get_by_message_ids_groups_contents_by_message() -> None:
|
||||
result = repository.get_by_message_ids(message_ids)
|
||||
|
||||
assert len(result) == 2
|
||||
assert [content.to_dict() for content in result[0]] == [
|
||||
assert [content.model_dump(mode="json", exclude_none=True) for content in result[0]] == [
|
||||
HumanInputContentDomain(
|
||||
workflow_run_id="workflow-run",
|
||||
submitted=True,
|
||||
form_submission_data=HumanInputFormSubmissionData(
|
||||
node_id="node-id",
|
||||
@ -112,7 +113,7 @@ def test_get_by_message_ids_groups_contents_by_message() -> None:
|
||||
action_id="approve",
|
||||
action_text="Approve",
|
||||
),
|
||||
).to_dict()
|
||||
).model_dump(mode="json", exclude_none=True)
|
||||
]
|
||||
assert result[1] == []
|
||||
|
||||
@ -165,6 +166,7 @@ def test_get_by_message_ids_returns_unsubmitted_form_definition() -> None:
|
||||
assert len(result[0]) == 1
|
||||
domain_content = result[0][0]
|
||||
assert domain_content.submitted is False
|
||||
assert domain_content.workflow_run_id == "workflow-run"
|
||||
assert domain_content.form_definition is not None
|
||||
form_definition = domain_content.form_definition
|
||||
assert form_definition.form_id == "form-1"
|
||||
|
||||
@ -24,6 +24,7 @@ def test_attach_message_extra_contents_assigns_serialized_payload(monkeypatch: p
|
||||
"get_by_message_ids": lambda _self, message_ids: [
|
||||
[
|
||||
HumanInputContent(
|
||||
workflow_run_id="workflow-run-1",
|
||||
submitted=True,
|
||||
form_submission_data=HumanInputFormSubmissionData(
|
||||
node_id="node-1",
|
||||
@ -46,6 +47,7 @@ def test_attach_message_extra_contents_assigns_serialized_payload(monkeypatch: p
|
||||
assert messages[0].extra_contents == [
|
||||
{
|
||||
"type": "human_input",
|
||||
"workflow_run_id": "workflow-run-1",
|
||||
"submitted": True,
|
||||
"form_submission_data": {
|
||||
"node_id": "node-1",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user