mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
Run workflow streaming inside the Builder worker to avoid queue deadlocks. Forward native events to shared editor callbacks and wait for graph refresh before retesting repairs. Keep command cleanup stable, preserve batched canvas events, and allow failed or unfinished historical runs to refresh again.
373 lines
11 KiB
Python
373 lines
11 KiB
Python
"""Pydantic request and response schemas for the Console Dify Builder API."""
|
|
|
|
from typing import Annotated, Any, Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, RootModel, StrictInt, StringConstraints, model_validator
|
|
|
|
from core.dify_builder.contract import (
|
|
Action,
|
|
AgentMessageEventData,
|
|
AppRevision,
|
|
AssistantTurnItem,
|
|
BuilderErrorCode,
|
|
BuildLearningCard,
|
|
CanvasEventData,
|
|
ChallengeCard,
|
|
ChangeSetCard,
|
|
CheckpointCard,
|
|
CheckpointRef,
|
|
Decision,
|
|
DecisionItem,
|
|
ErrorCard,
|
|
ErrorEventData,
|
|
FormCard,
|
|
NoticeItem,
|
|
Phase,
|
|
PlanCard,
|
|
PreflightContextCard,
|
|
ProgressEventData,
|
|
PublishCard,
|
|
ReasoningEventData,
|
|
RecoveryRef,
|
|
ResourceSelectCard,
|
|
RunContextCard,
|
|
RunStatus,
|
|
SessionModel,
|
|
SummaryCard,
|
|
TestResultCard,
|
|
UserItem,
|
|
)
|
|
from core.dify_builder.models import EntryMode
|
|
from fields.base import ResponseModel
|
|
from fields.workflow_stream_fields import WorkflowStreamPayload
|
|
|
|
NonEmptyString = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
|
|
ClientTurnId = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=128)]
|
|
|
|
|
|
class DifyBuilderPayload(BaseModel):
|
|
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
|
|
|
|
class DifyBuilderCreateBuildSessionPayload(DifyBuilderPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["build"]
|
|
goal_text: NonEmptyString
|
|
# True when the app was created from this same prompt and still carries the
|
|
# name cut from it, so Builder may rewrite it once it understands the goal.
|
|
# False is create-from-blank: the user named the app, Builder inherits it.
|
|
derive_app_name: bool = False
|
|
model_config_data: SessionModel | None = Field(default=None, alias="model_config")
|
|
|
|
|
|
class DifyBuilderCreateEditSessionPayload(DifyBuilderPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["edit"]
|
|
goal_text: NonEmptyString
|
|
model_config_data: SessionModel | None = Field(default=None, alias="model_config")
|
|
|
|
|
|
class DifyBuilderCreateFixSessionPayload(DifyBuilderPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["fix"]
|
|
failed_run_id: NonEmptyString
|
|
model_config_data: SessionModel | None = Field(default=None, alias="model_config")
|
|
|
|
|
|
class DifyBuilderChecklistErrorPayload(DifyBuilderPayload):
|
|
node_id: str
|
|
node_type: str
|
|
title: str
|
|
messages: list[str]
|
|
unconnected: bool
|
|
plugin_missing: bool
|
|
|
|
|
|
class DifyBuilderCreateChecklistFixSessionPayload(DifyBuilderPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["fix"]
|
|
checklist_errors: Annotated[list[DifyBuilderChecklistErrorPayload], Field(min_length=1)]
|
|
failed_run_id: NonEmptyString | None = None
|
|
model_config_data: SessionModel | None = Field(default=None, alias="model_config")
|
|
|
|
|
|
class DifyBuilderCreateSessionPayload(
|
|
RootModel[
|
|
DifyBuilderCreateBuildSessionPayload
|
|
| DifyBuilderCreateEditSessionPayload
|
|
| DifyBuilderCreateFixSessionPayload
|
|
| DifyBuilderCreateChecklistFixSessionPayload
|
|
]
|
|
):
|
|
"""Create a Build, Edit, failed-run Fix, or checklist Fix session."""
|
|
|
|
|
|
class DifyBuilderSubmitActionPayload(DifyBuilderPayload):
|
|
action_id: NonEmptyString
|
|
payload: dict[str, Any] = Field(default_factory=dict)
|
|
base_version: StrictInt
|
|
base_app_revision: NonEmptyString
|
|
|
|
|
|
class DifyBuilderSubmitMessagePayload(DifyBuilderPayload):
|
|
text: NonEmptyString
|
|
base_version: StrictInt
|
|
client_turn_id: ClientTurnId
|
|
|
|
|
|
class DifyBuilderConversationListQuery(DifyBuilderPayload):
|
|
before_seq: int | None = Field(default=None, ge=0, description="Load groups before this sequence")
|
|
after_seq: int | None = Field(default=None, ge=-1, description="Load groups after this sequence")
|
|
limit: int = Field(default=20, ge=1, le=100, description="Number of conversation groups to return")
|
|
|
|
@model_validator(mode="after")
|
|
def validate_cursor(self) -> "DifyBuilderConversationListQuery":
|
|
if self.before_seq is not None and self.after_seq is not None:
|
|
raise ValueError("before_seq and after_seq are mutually exclusive")
|
|
return self
|
|
|
|
|
|
class DifyBuilderConversationItemBase(ResponseModel):
|
|
seq: int
|
|
at_version: int
|
|
|
|
|
|
class DifyBuilderUserConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["user"]
|
|
payload: UserItem
|
|
|
|
|
|
class DifyBuilderDecisionConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["decision"]
|
|
payload: DecisionItem
|
|
|
|
|
|
class DifyBuilderNoticeConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["notice"]
|
|
payload: NoticeItem
|
|
|
|
|
|
class DifyBuilderRunContextConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["run_context"]
|
|
payload: RunContextCard
|
|
|
|
|
|
class DifyBuilderPreflightContextConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["preflight_context"]
|
|
payload: PreflightContextCard
|
|
|
|
|
|
class DifyBuilderAssistantTurnConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["assistant_turn"]
|
|
payload: AssistantTurnItem
|
|
|
|
|
|
class DifyBuilderPlanConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["plan"]
|
|
payload: PlanCard
|
|
|
|
|
|
class DifyBuilderFormConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["form"]
|
|
payload: FormCard
|
|
|
|
|
|
class DifyBuilderChallengeConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["challenge"]
|
|
payload: ChallengeCard
|
|
|
|
|
|
class DifyBuilderResourceSelectConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["resource_select"]
|
|
payload: ResourceSelectCard
|
|
|
|
|
|
class DifyBuilderCheckpointConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["checkpoint"]
|
|
payload: CheckpointCard
|
|
|
|
|
|
class DifyBuilderChangeSetConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["change_set"]
|
|
payload: ChangeSetCard
|
|
|
|
|
|
class DifyBuilderTestResultConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["test_result"]
|
|
payload: TestResultCard
|
|
|
|
|
|
class DifyBuilderErrorConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["error"]
|
|
payload: ErrorCard
|
|
|
|
|
|
class DifyBuilderSummaryConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["summary"]
|
|
payload: SummaryCard
|
|
|
|
|
|
class DifyBuilderPublishConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["publish"]
|
|
payload: PublishCard
|
|
|
|
|
|
class DifyBuilderBuildLearningConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["build_learning"]
|
|
payload: BuildLearningCard
|
|
|
|
|
|
DifyBuilderConversationItem = Annotated[
|
|
DifyBuilderUserConversationItemResponse
|
|
| DifyBuilderDecisionConversationItemResponse
|
|
| DifyBuilderNoticeConversationItemResponse
|
|
| DifyBuilderRunContextConversationItemResponse
|
|
| DifyBuilderPreflightContextConversationItemResponse
|
|
| DifyBuilderAssistantTurnConversationItemResponse
|
|
| DifyBuilderPlanConversationItemResponse
|
|
| DifyBuilderFormConversationItemResponse
|
|
| DifyBuilderChallengeConversationItemResponse
|
|
| DifyBuilderResourceSelectConversationItemResponse
|
|
| DifyBuilderCheckpointConversationItemResponse
|
|
| DifyBuilderChangeSetConversationItemResponse
|
|
| DifyBuilderTestResultConversationItemResponse
|
|
| DifyBuilderErrorConversationItemResponse
|
|
| DifyBuilderSummaryConversationItemResponse
|
|
| DifyBuilderPublishConversationItemResponse
|
|
| DifyBuilderBuildLearningConversationItemResponse,
|
|
Field(discriminator="kind"),
|
|
]
|
|
|
|
|
|
class DifyBuilderActiveInteractionResponse(ResponseModel):
|
|
action_id: str
|
|
card: DifyBuilderConversationItem
|
|
valid_at_version: int
|
|
|
|
|
|
class DifyBuilderSessionViewResponse(ResponseModel):
|
|
session_id: str
|
|
app_id: str
|
|
version: int
|
|
state: str
|
|
canvas_read_only: bool
|
|
run_status: RunStatus
|
|
interrupted: bool
|
|
conversation_last_seq: int
|
|
entry_mode: EntryMode = EntryMode.FIX
|
|
phase: Phase = Phase.UNDERSTAND
|
|
actions: list[Action] = Field(default_factory=list)
|
|
decision: Decision | None = None
|
|
active_interaction: DifyBuilderActiveInteractionResponse | None = None
|
|
checkpoint: CheckpointRef | None = None
|
|
recovery: RecoveryRef | None = None
|
|
model: SessionModel | None = None
|
|
app_revision: AppRevision | None = None
|
|
|
|
|
|
class DifyBuilderConversationPageResponse(ResponseModel):
|
|
data: list[DifyBuilderConversationItem]
|
|
has_more: bool
|
|
first_seq: int | None
|
|
last_seq: int | None
|
|
|
|
|
|
class DifyBuilderCommitEventData(ResponseModel):
|
|
session_id: str
|
|
operation_id: str
|
|
stage_id: str
|
|
at_version: int
|
|
version: int
|
|
state: str
|
|
settled: bool
|
|
items: list[DifyBuilderConversationItem]
|
|
kind: Literal["commit"] = "commit"
|
|
|
|
|
|
class DifyBuilderStateEventData(DifyBuilderSessionViewResponse):
|
|
kind: Literal["state"] = "state"
|
|
|
|
|
|
class DifyBuilderCommandStartedEventData(DifyBuilderSessionViewResponse):
|
|
kind: Literal["command_started"] = "command_started"
|
|
|
|
|
|
class DifyBuilderCommandStartedEventResponse(ResponseModel):
|
|
event: Literal["command_started"]
|
|
data: DifyBuilderCommandStartedEventData
|
|
|
|
|
|
class DifyBuilderWorkflowEventData(ResponseModel):
|
|
session_id: str
|
|
operation_id: str
|
|
stage_id: str
|
|
at_version: int
|
|
revision: int
|
|
payload: WorkflowStreamPayload
|
|
kind: Literal["workflow"] = "workflow"
|
|
|
|
|
|
class DifyBuilderWorkflowEventResponse(ResponseModel):
|
|
event: Literal["workflow"]
|
|
data: DifyBuilderWorkflowEventData
|
|
|
|
|
|
class DifyBuilderCanvasEventResponse(ResponseModel):
|
|
event: Literal["canvas"]
|
|
data: CanvasEventData
|
|
|
|
|
|
class DifyBuilderAgentMessageEventResponse(ResponseModel):
|
|
event: Literal["agent_message"]
|
|
data: AgentMessageEventData
|
|
|
|
|
|
class DifyBuilderReasoningEventResponse(ResponseModel):
|
|
event: Literal["reasoning"]
|
|
data: ReasoningEventData
|
|
|
|
|
|
class DifyBuilderProgressEventResponse(ResponseModel):
|
|
event: Literal["progress"]
|
|
data: ProgressEventData
|
|
|
|
|
|
class DifyBuilderCommitEventResponse(ResponseModel):
|
|
event: Literal["commit"]
|
|
data: DifyBuilderCommitEventData
|
|
|
|
|
|
class DifyBuilderStateEventResponse(ResponseModel):
|
|
event: Literal["state"]
|
|
data: DifyBuilderStateEventData
|
|
|
|
|
|
class DifyBuilderErrorEventResponse(ResponseModel):
|
|
event: Literal["error"]
|
|
data: ErrorEventData
|
|
|
|
|
|
class DifyBuilderStreamEventResponse(
|
|
RootModel[
|
|
Annotated[
|
|
DifyBuilderCommandStartedEventResponse
|
|
| DifyBuilderWorkflowEventResponse
|
|
| DifyBuilderCanvasEventResponse
|
|
| DifyBuilderAgentMessageEventResponse
|
|
| DifyBuilderReasoningEventResponse
|
|
| DifyBuilderProgressEventResponse
|
|
| DifyBuilderCommitEventResponse
|
|
| DifyBuilderStateEventResponse
|
|
| DifyBuilderErrorEventResponse,
|
|
Field(discriminator="event"),
|
|
]
|
|
]
|
|
):
|
|
"""One JSON object carried by an SSE ``data:`` frame."""
|
|
|
|
|
|
class DifyBuilderErrorResponse(ResponseModel):
|
|
code: BuilderErrorCode
|
|
message: str | None = None
|
|
recoverable: bool | None = None
|