mirror of
https://github.com/langgenius/dify.git
synced 2026-11-11 22:02:23 +08:00
844 lines
27 KiB
Python
844 lines
27 KiB
Python
"""Pydantic request and response schemas for the Console Dify Builder API."""
|
|
|
|
from datetime import datetime
|
|
from typing import Annotated, Any, Literal
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, RootModel, StrictBool, StrictInt, StringConstraints, model_validator
|
|
|
|
from core.dify_builder.contract import (
|
|
ActionKind,
|
|
AssistantTurnItem,
|
|
BuilderErrorCode,
|
|
Decision,
|
|
DecisionItem,
|
|
ExecutionActivityState,
|
|
ExecutionProgressStatus,
|
|
FormCard,
|
|
InteractionResponseItem,
|
|
NoticeItem,
|
|
Phase,
|
|
PlanCard,
|
|
PreflightContextCard,
|
|
RecoveryRef,
|
|
ResourceSelectCard,
|
|
RunContextCard,
|
|
RunStatus,
|
|
SessionModel,
|
|
TestResultCard,
|
|
UserItem,
|
|
)
|
|
from core.dify_builder.models import TaskSummary
|
|
from core.dify_builder.real_call_consent import ConsentState
|
|
from fields.base import ResponseModel
|
|
from fields.workflow_stream_fields import WorkflowStreamPayload
|
|
from runtime_contracts.builder.presentation import BuilderText
|
|
from services.dify_builder.native_testing.public_contracts import NativeTestInputBinding, NativeTestPublicReceipt
|
|
|
|
NonEmptyString = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
|
|
ClientTurnId = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=128)]
|
|
# Real-call consent identifiers are bound byte-exactly by the consent owner: no trimming or coercion.
|
|
RealCallId = Annotated[str, StringConstraints(min_length=1, max_length=128)]
|
|
ScopeDigest = Annotated[str, StringConstraints(pattern=r"^[a-f0-9]{64}$")]
|
|
IdempotencyKey = Annotated[str, StringConstraints(min_length=1, max_length=128)]
|
|
ReasonCode = Annotated[str, StringConstraints(pattern=r"^[a-z][a-z0-9_]{0,127}$")]
|
|
|
|
|
|
class DifyBuilderPayload(BaseModel):
|
|
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
|
|
|
|
class DifyBuilderAttachmentPayload(DifyBuilderPayload):
|
|
"""An opaque native upload reference; authority is reconstructed server-side."""
|
|
|
|
upload_file_id: UUID
|
|
|
|
|
|
class DifyBuilderMaterialPayload(DifyBuilderPayload):
|
|
attachments: list[DifyBuilderAttachmentPayload] = Field(default_factory=list, max_length=5)
|
|
|
|
|
|
class DifyBuilderGoalPayload(DifyBuilderMaterialPayload):
|
|
goal_text: Annotated[str, StringConstraints(strip_whitespace=True, max_length=20000)] = ""
|
|
|
|
@model_validator(mode="after")
|
|
def require_goal_or_material(self) -> "DifyBuilderGoalPayload":
|
|
if not self.goal_text and not self.attachments:
|
|
raise ValueError("goal_text or attachments are required")
|
|
return self
|
|
|
|
|
|
class DifyBuilderCreateBuildSessionPayload(DifyBuilderGoalPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["build"]
|
|
# 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(DifyBuilderGoalPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["edit"]
|
|
model_config_data: SessionModel | None = Field(default=None, alias="model_config")
|
|
|
|
|
|
class DifyBuilderCreateFixSessionPayload(DifyBuilderMaterialPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["fix"]
|
|
failed_run_id: NonEmptyString
|
|
session_id: NonEmptyString | None = None
|
|
client_action_id: ClientTurnId | None = None
|
|
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(DifyBuilderMaterialPayload):
|
|
app_id: NonEmptyString
|
|
scenario: Literal["fix"]
|
|
checklist_errors: Annotated[list[DifyBuilderChecklistErrorPayload], Field(min_length=1)]
|
|
failed_run_id: NonEmptyString | None = None
|
|
session_id: NonEmptyString | None = None
|
|
client_action_id: ClientTurnId | 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 DifyBuilderReceiptFieldSnapshot(DifyBuilderPayload):
|
|
key: NonEmptyString
|
|
label: str
|
|
display_value: str
|
|
|
|
|
|
class DifyBuilderReceiptSnapshot(DifyBuilderPayload):
|
|
"""Localized display only; submitted values remain in action.payload."""
|
|
|
|
interaction_kind: Literal["choice", "form", "resource"]
|
|
reply_language: Annotated[str, StringConstraints(min_length=1, max_length=35)]
|
|
# Display metadata must not impose limits absent from action.payload.
|
|
question: str
|
|
answer: str = ""
|
|
fields: list[DifyBuilderReceiptFieldSnapshot] = Field(default_factory=list)
|
|
|
|
|
|
class DifyBuilderTaskControlPayload(DifyBuilderPayload):
|
|
"""Control the current task with a durable client replay identity."""
|
|
|
|
base_version: StrictInt
|
|
client_action_id: ClientTurnId
|
|
base_app_revision: str = ""
|
|
|
|
|
|
class DifyBuilderConversationLifecyclePayload(DifyBuilderPayload):
|
|
"""Lifecycle control uses Session CAS, never a graph revision."""
|
|
|
|
base_version: StrictInt = Field(ge=1)
|
|
client_action_id: ClientTurnId
|
|
expected_task_id: str = Field(default="", max_length=255)
|
|
|
|
|
|
class DifyBuilderClearConversationPayload(DifyBuilderConversationLifecyclePayload):
|
|
confirmed: StrictBool
|
|
|
|
@model_validator(mode="after")
|
|
def require_confirmation(self) -> "DifyBuilderClearConversationPayload":
|
|
if self.confirmed is not True:
|
|
raise ValueError("Explicit clear confirmation is required")
|
|
return self
|
|
|
|
|
|
class DifyBuilderFixIntentPayload(DifyBuilderPayload):
|
|
base_version: StrictInt = Field(ge=1)
|
|
client_action_id: ClientTurnId
|
|
failed_run_id: NonEmptyString | None = None
|
|
checklist_errors: list[DifyBuilderChecklistErrorPayload] = Field(default_factory=list, max_length=100)
|
|
model_config_data: SessionModel | None = Field(default=None, alias="model_config")
|
|
|
|
@model_validator(mode="after")
|
|
def require_one_source(self) -> "DifyBuilderFixIntentPayload":
|
|
if bool(self.failed_run_id) == bool(self.checklist_errors):
|
|
raise ValueError("Exactly one failed run or checklist source is required")
|
|
return self
|
|
|
|
|
|
class DifyBuilderConversationLifecycleResponse(ResponseModel):
|
|
session_id: str
|
|
version: int
|
|
last_command_id: str
|
|
task_id: str
|
|
task_status: Literal["abandoned"]
|
|
conversation_cleared: bool
|
|
conversation_last_seq: int
|
|
settlement: Literal["settled", "pending", "unknown"]
|
|
|
|
|
|
class DifyBuilderSubmitActionPayload(DifyBuilderPayload):
|
|
action_id: NonEmptyString
|
|
client_action_id: ClientTurnId | None = None
|
|
receipt_snapshot: DifyBuilderReceiptSnapshot | None = None
|
|
payload: dict[str, Any] = Field(
|
|
default_factory=dict,
|
|
description=(
|
|
"Existing action payload. Native controls: confirm_test_operation/deny_test_operation take "
|
|
"request_id,pending_operation_id,pending_version,scope_digest; resume_test takes request_id,"
|
|
"expected_generation; cancel_test takes request_id. Copy payload from the current server action."
|
|
),
|
|
)
|
|
base_version: StrictInt
|
|
base_app_revision: NonEmptyString
|
|
|
|
|
|
class DifyBuilderSubmitMessagePayload(DifyBuilderMaterialPayload):
|
|
text: Annotated[str, StringConstraints(strip_whitespace=True, max_length=20000)] = ""
|
|
base_version: StrictInt
|
|
client_turn_id: ClientTurnId
|
|
|
|
@model_validator(mode="after")
|
|
def require_text_or_material(self) -> "DifyBuilderSubmitMessagePayload":
|
|
if not self.text and not self.attachments:
|
|
raise ValueError("text or attachments are required")
|
|
return self
|
|
|
|
|
|
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
|
|
|
|
|
|
# Real-call consent requests name what a person reviews or approves. They never
|
|
# carry Tool parameters, credentials, graph, execution context or guards: the
|
|
# consent owner reconstructs all of those server-side from authoritative rows.
|
|
|
|
|
|
class DifyBuilderPrepareRealCallPayload(DifyBuilderPayload):
|
|
node_id: RealCallId
|
|
test_input_id: RealCallId
|
|
credential_id: RealCallId
|
|
at_version: StrictInt = Field(ge=1)
|
|
base_app_revision: RealCallId
|
|
idempotency_key: IdempotencyKey
|
|
|
|
|
|
class DifyBuilderConfirmRealCallPayload(DifyBuilderPayload):
|
|
decision: Literal["confirm", "decline"]
|
|
scope_digest: ScopeDigest
|
|
at_version: StrictInt = Field(ge=1)
|
|
idempotency_key: IdempotencyKey
|
|
|
|
|
|
class DifyBuilderExecuteRealCallPayload(DifyBuilderPayload):
|
|
scope_digest: ScopeDigest
|
|
at_version: StrictInt = Field(ge=1)
|
|
idempotency_key: IdempotencyKey
|
|
|
|
|
|
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 DifyBuilderInteractionResponseConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["interaction_response"]
|
|
payload: InteractionResponseItem
|
|
|
|
|
|
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 DifyBuilderResourceSelectConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["resource_select"]
|
|
payload: ResourceSelectCard
|
|
|
|
|
|
class DifyBuilderTestResultConversationItemResponse(DifyBuilderConversationItemBase):
|
|
kind: Literal["test_result"]
|
|
payload: TestResultCard
|
|
|
|
|
|
DifyBuilderConversationItem = Annotated[
|
|
DifyBuilderUserConversationItemResponse
|
|
| DifyBuilderDecisionConversationItemResponse
|
|
| DifyBuilderInteractionResponseConversationItemResponse
|
|
| DifyBuilderNoticeConversationItemResponse
|
|
| DifyBuilderRunContextConversationItemResponse
|
|
| DifyBuilderPreflightContextConversationItemResponse
|
|
| DifyBuilderAssistantTurnConversationItemResponse
|
|
| DifyBuilderPlanConversationItemResponse
|
|
| DifyBuilderFormConversationItemResponse
|
|
| DifyBuilderResourceSelectConversationItemResponse
|
|
| DifyBuilderTestResultConversationItemResponse,
|
|
Field(discriminator="kind"),
|
|
]
|
|
|
|
# Complete assistant presentation arrives as a committed item. Native streamed
|
|
# assistant text is restricted to agent_message by the event validator.
|
|
DifyBuilderAppendedConversationItem = Annotated[
|
|
DifyBuilderUserConversationItemResponse
|
|
| DifyBuilderDecisionConversationItemResponse
|
|
| DifyBuilderInteractionResponseConversationItemResponse
|
|
| DifyBuilderNoticeConversationItemResponse
|
|
| DifyBuilderRunContextConversationItemResponse
|
|
| DifyBuilderPreflightContextConversationItemResponse
|
|
| DifyBuilderAssistantTurnConversationItemResponse
|
|
| DifyBuilderPlanConversationItemResponse
|
|
| DifyBuilderFormConversationItemResponse
|
|
| DifyBuilderResourceSelectConversationItemResponse
|
|
| DifyBuilderTestResultConversationItemResponse,
|
|
Field(discriminator="kind"),
|
|
]
|
|
|
|
|
|
class DifyBuilderActiveInteractionResponse(ResponseModel):
|
|
action_id: str
|
|
card_seq: int
|
|
valid_at_version: int
|
|
|
|
|
|
class DifyBuilderActionResponse(ResponseModel):
|
|
payload: dict[str, Any] = Field(default_factory=dict)
|
|
id: str
|
|
label: BuilderText
|
|
kind: ActionKind
|
|
|
|
|
|
class DifyBuilderAppRevisionResponse(ResponseModel):
|
|
current: str
|
|
conflicted: bool
|
|
|
|
|
|
class DifyBuilderAttachmentStateResponse(ResponseModel):
|
|
upload_file_id: UUID
|
|
name: str
|
|
extension: str
|
|
size: int
|
|
status: Literal["pending", "consumed", "truncated", "rejected"]
|
|
digest: str = ""
|
|
reason: str = ""
|
|
|
|
|
|
class DifyBuilderMaterialReceiptResponse(ResponseModel):
|
|
id: UUID
|
|
seq: int
|
|
app_id: str
|
|
session_id: str
|
|
task_id: str
|
|
generation: int
|
|
client_turn_id: str
|
|
status: Literal["pending", "consumed", "truncated", "rejected", "superseded"]
|
|
consumed_version: int | None
|
|
test_input_candidate: bool
|
|
attachments: list[DifyBuilderAttachmentStateResponse] = Field(max_length=5)
|
|
|
|
|
|
class DifyBuilderSessionStateResponse(ResponseModel):
|
|
attachments: list[DifyBuilderMaterialReceiptResponse] = Field(default_factory=list, max_length=100)
|
|
test_execution: NativeTestPublicReceipt | None = None
|
|
diagnostics: list[dict[str, Any]] = Field(default_factory=list, max_length=33)
|
|
session_id: str
|
|
reply_language: str = Field(
|
|
description="Detected user-input language (BCP-47); empty until a user language is detected."
|
|
)
|
|
version: int
|
|
canvas_read_only: bool
|
|
run_status: RunStatus
|
|
interrupted: bool
|
|
conversation_last_seq: int
|
|
phase: Phase
|
|
actions: list[DifyBuilderActionResponse] = Field(default_factory=list)
|
|
decision: Decision | None = None
|
|
active_interaction: DifyBuilderActiveInteractionResponse | None = None
|
|
recovery: RecoveryRef | None = None
|
|
model: SessionModel | None = None
|
|
app_revision: DifyBuilderAppRevisionResponse | None = None
|
|
task_id: str = ""
|
|
task_status: Literal["active", "paused", "completed", "abandoned"] = "active"
|
|
task_summaries: list[TaskSummary] = Field(default_factory=list, max_length=8)
|
|
conversation_cleared: bool = False
|
|
lifecycle_settlement: Literal["settled", "pending", "unknown"] | None = Field(
|
|
default=None,
|
|
description=(
|
|
"Known execution state of the current clear/abandon control, not physical cleanup proof. "
|
|
"Null means no applicable control; missing applicable evidence is unknown. "
|
|
"Clear retains its durable acknowledgment state without inferring later cleanup."
|
|
),
|
|
)
|
|
pending_fix_context: RunContextCard | PreflightContextCard | None = None
|
|
|
|
|
|
class DifyBuilderSessionViewResponse(DifyBuilderSessionStateResponse):
|
|
last_command_id: str = ""
|
|
|
|
|
|
class DifyBuilderFixIntentResponse(ResponseModel):
|
|
fix_intent_id: str
|
|
status: str
|
|
session: DifyBuilderSessionViewResponse
|
|
|
|
|
|
class DifyBuilderConversationPageResponse(ResponseModel):
|
|
data: list[DifyBuilderConversationItem]
|
|
has_more: bool
|
|
first_seq: int | None
|
|
last_seq: int | None
|
|
|
|
|
|
class DifyBuilderCommandFinishedEventData(DifyBuilderSessionStateResponse):
|
|
command_id: str
|
|
post_canvas_action_id: str | None = None
|
|
|
|
|
|
class DifyBuilderCommandStartedEventData(ResponseModel):
|
|
session_id: str
|
|
command_id: str
|
|
version: int
|
|
phase: Phase
|
|
run_status: RunStatus
|
|
|
|
|
|
class DifyBuilderCommandStartedEventResponse(ResponseModel):
|
|
event: Literal["command_started"]
|
|
data: DifyBuilderCommandStartedEventData
|
|
|
|
|
|
class DifyBuilderWorkflowEventData(ResponseModel):
|
|
session_id: str
|
|
operation_id: str
|
|
at_version: int
|
|
revision: int
|
|
payload: WorkflowStreamPayload
|
|
|
|
|
|
class DifyBuilderWorkflowEventResponse(ResponseModel):
|
|
event: Literal["workflow"]
|
|
data: DifyBuilderWorkflowEventData
|
|
|
|
|
|
class DifyBuilderCanvasEventBase(ResponseModel):
|
|
session_id: str
|
|
operation_id: str
|
|
at_version: int
|
|
revision: int
|
|
|
|
|
|
class DifyBuilderGraphChangedEventData(DifyBuilderCanvasEventBase):
|
|
event: Literal["graph_changed"]
|
|
cause: Literal["apply", "restore"]
|
|
|
|
|
|
class DifyBuilderEditTargetsChangedEventData(DifyBuilderCanvasEventBase):
|
|
event: Literal["edit_targets_changed"]
|
|
node_ids: list[str]
|
|
|
|
|
|
class DifyBuilderPublishedEventData(DifyBuilderCanvasEventBase):
|
|
event: Literal["publish_workflow"]
|
|
|
|
|
|
DifyBuilderCanvasEventData = Annotated[
|
|
DifyBuilderGraphChangedEventData | DifyBuilderEditTargetsChangedEventData | DifyBuilderPublishedEventData,
|
|
Field(discriminator="event"),
|
|
]
|
|
|
|
|
|
class DifyBuilderCanvasEventResponse(ResponseModel):
|
|
event: Literal["canvas"]
|
|
data: DifyBuilderCanvasEventData
|
|
|
|
|
|
class DifyBuilderExecutionActivityResponse(ResponseModel):
|
|
id: str
|
|
label: BuilderText
|
|
state: ExecutionActivityState
|
|
parent_id: str | None = None
|
|
|
|
|
|
class DifyBuilderExecutionProgressResponse(ResponseModel):
|
|
status: ExecutionProgressStatus
|
|
activities: list[DifyBuilderExecutionActivityResponse] = Field(default_factory=list)
|
|
|
|
|
|
class DifyBuilderAgentMessageEventData(ResponseModel):
|
|
session_id: str
|
|
command_id: str
|
|
operation_id: str
|
|
turn_id: str
|
|
delta: str
|
|
seq: int
|
|
at_version: int
|
|
revision: int
|
|
done: bool
|
|
text_bytes: int
|
|
execution: DifyBuilderExecutionProgressResponse | None = None
|
|
cards: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class DifyBuilderAgentMessageEventResponse(ResponseModel):
|
|
event: Literal["agent_message"]
|
|
data: DifyBuilderAgentMessageEventData
|
|
|
|
|
|
class DifyBuilderConversationItemAppendedEventData(ResponseModel):
|
|
session_id: str
|
|
command_id: str
|
|
item: DifyBuilderAppendedConversationItem
|
|
|
|
@model_validator(mode="after")
|
|
def complete_assistant_only(self):
|
|
if self.item.kind == "assistant_turn" and self.item.payload.reply_mode != "complete":
|
|
raise ValueError("streamed assistant turns use agent_message")
|
|
return self
|
|
|
|
|
|
class DifyBuilderConversationItemAppendedEventResponse(ResponseModel):
|
|
event: Literal["conversation_item_appended"]
|
|
data: DifyBuilderConversationItemAppendedEventData
|
|
|
|
|
|
class DifyBuilderReasoningEventData(ResponseModel):
|
|
session_id: str
|
|
operation_id: str
|
|
at_version: int
|
|
revision: int
|
|
delta: str
|
|
|
|
|
|
class DifyBuilderReasoningEventResponse(ResponseModel):
|
|
event: Literal["reasoning"]
|
|
data: DifyBuilderReasoningEventData
|
|
|
|
|
|
class DifyBuilderProgressEventData(ResponseModel):
|
|
session_id: str
|
|
operation_id: str
|
|
at_version: int
|
|
revision: int
|
|
status: ExecutionProgressStatus
|
|
activity: DifyBuilderExecutionActivityResponse | None
|
|
reply_language: str = ""
|
|
|
|
|
|
class DifyBuilderProgressEventResponse(ResponseModel):
|
|
event: Literal["progress"]
|
|
data: DifyBuilderProgressEventData
|
|
|
|
|
|
class DifyBuilderProgressSnapshotEventData(ResponseModel):
|
|
"""Complete observed activity state before subsequent live progress deltas."""
|
|
|
|
session_id: str
|
|
operation_id: str
|
|
at_version: int
|
|
revision: int
|
|
reply_language: str
|
|
execution: DifyBuilderExecutionProgressResponse
|
|
|
|
|
|
class DifyBuilderProgressSnapshotEventResponse(ResponseModel):
|
|
event: Literal["progress_snapshot"]
|
|
data: DifyBuilderProgressSnapshotEventData
|
|
|
|
|
|
class DifyBuilderCommandFinishedEventResponse(ResponseModel):
|
|
event: Literal["command_finished"]
|
|
data: DifyBuilderCommandFinishedEventData
|
|
|
|
|
|
class DifyBuilderErrorEventData(ResponseModel):
|
|
session_id: str | None = None
|
|
command_id: str | None = None
|
|
code: str | None = None
|
|
message: str
|
|
reason_code: ReasonCode | None = None
|
|
recoverable: bool | None = None
|
|
|
|
|
|
class DifyBuilderErrorEventResponse(ResponseModel):
|
|
event: Literal["error"]
|
|
data: DifyBuilderErrorEventData
|
|
|
|
|
|
class DifyBuilderNativeExecutionEventData(ResponseModel):
|
|
session_id: str
|
|
cursor: ScopeDigest
|
|
receipt: NativeTestPublicReceipt
|
|
|
|
|
|
class DifyBuilderNativeExecutionEventResponse(ResponseModel):
|
|
event: Literal["native_execution"]
|
|
data: DifyBuilderNativeExecutionEventData
|
|
|
|
|
|
class DifyBuilderStreamEventResponse(
|
|
RootModel[
|
|
Annotated[
|
|
DifyBuilderCommandStartedEventResponse
|
|
| DifyBuilderWorkflowEventResponse
|
|
| DifyBuilderCanvasEventResponse
|
|
| DifyBuilderAgentMessageEventResponse
|
|
| DifyBuilderConversationItemAppendedEventResponse
|
|
| DifyBuilderReasoningEventResponse
|
|
| DifyBuilderProgressEventResponse
|
|
| DifyBuilderProgressSnapshotEventResponse
|
|
| DifyBuilderCommandFinishedEventResponse
|
|
| DifyBuilderErrorEventResponse
|
|
| DifyBuilderNativeExecutionEventResponse,
|
|
Field(discriminator="event"),
|
|
]
|
|
]
|
|
):
|
|
"""One JSON object carried by an SSE ``data:`` frame."""
|
|
|
|
|
|
class DifyBuilderErrorResponse(ResponseModel):
|
|
reason_code: ReasonCode | None = None
|
|
code: BuilderErrorCode
|
|
message: str | None = None
|
|
recoverable: bool | None = None
|
|
|
|
|
|
class DifyBuilderRealCallDisclosureResponse(ResponseModel):
|
|
"""The approved public disclosure of one real Tool call; no credential revision or secret."""
|
|
|
|
action: Literal["get_message"]
|
|
credential_id: str
|
|
credential_alias: str
|
|
credential_type: str
|
|
identity_basis: Literal["workspace_credential"] = Field(
|
|
description="The alias names a workspace credential, not a verified remote account identity"
|
|
)
|
|
remote_account_status: Literal["unknown"]
|
|
message_id: str
|
|
request_method: Literal["GET"]
|
|
request_url: str
|
|
response_format: Literal["full"]
|
|
include_body: bool
|
|
include_attachments: bool
|
|
oauth_refresh: Literal["if_needed"] = Field(
|
|
description=(
|
|
"One OAuth token refresh request is made only if the stored access token must be refreshed "
|
|
"before the call; otherwise no refresh request is sent"
|
|
)
|
|
)
|
|
oauth_refresh_method: Literal["POST"]
|
|
oauth_refresh_url: Literal["https://oauth2.googleapis.com/token"]
|
|
native_attempt_limit: Literal[1]
|
|
refresh_limit: Literal[1]
|
|
automatic_replay: Literal[False]
|
|
quota_usage: Literal["possible"]
|
|
monetary_estimate: Literal["unknown"]
|
|
output_retention: Literal["native_run_retention"]
|
|
data_description: Literal["gmail_message_headers_snippet_and_selected_body_or_attachment_metadata"]
|
|
expires_at: datetime
|
|
prior_uncertain_consent_id: str | None = None
|
|
|
|
|
|
class DifyBuilderRealCallConsentResponse(ResponseModel):
|
|
"""Current or saved receipt of one real-call consent."""
|
|
|
|
# The discriminator is always emitted, so document it as required.
|
|
model_config = ConfigDict(json_schema_serialization_defaults_required=True)
|
|
|
|
result: Literal["receipt"] = "receipt"
|
|
consent_id: str
|
|
scope_digest: str
|
|
state: ConsentState = Field(
|
|
description=(
|
|
"Consent lifecycle state. 'unknown' is final: a claimed call whose real effect could not be "
|
|
"confirmed. It is bounded by the disclosed limits of one native attempt and at most one token "
|
|
"refresh, is never replayed automatically, and any further real call needs a new human-approved "
|
|
"consent"
|
|
)
|
|
)
|
|
at_version: int
|
|
disclosure: DifyBuilderRealCallDisclosureResponse
|
|
command_id: str | None
|
|
execution_request_id: str | None
|
|
native_run_id: str | None
|
|
native_node_execution_id: str | None
|
|
reason_code: ReasonCode | None = Field(description="Fixed server reason code; never provider text")
|
|
refresh_claimed: bool
|
|
business_claimed: bool
|
|
can_retry: bool = Field(
|
|
description="Whether a new consent may be prepared; always false once a launch is reserved or claimed"
|
|
)
|
|
|
|
|
|
DifyBuilderRealCallRefusalCode = Literal[
|
|
"needs_setup", "needs_permission", "unsupported_action", "unavailable_metadata", "conflict"
|
|
]
|
|
DifyBuilderRealCallRefusalReason = Literal[
|
|
# needs_setup
|
|
"needs_setup",
|
|
"credential_required",
|
|
"credential_binding_mismatch",
|
|
"credential_provider_mismatch",
|
|
"unsupported_test_input",
|
|
# needs_permission
|
|
"credential_reference_unavailable",
|
|
"credential_policy_refused",
|
|
# unsupported_action
|
|
"unsupported_action",
|
|
"unsupported_tool_node",
|
|
"unsupported_tool_parameters",
|
|
"unsupported_tool_configuration",
|
|
"unsafe_message_id",
|
|
"unsupported_session_state",
|
|
"unsupported_graph",
|
|
"unsupported_workflow",
|
|
"unsupported_node_retry",
|
|
"unsupported_default_output",
|
|
"unsupported_selector",
|
|
"unsupported_node_implementation",
|
|
"unsupported_node_configuration",
|
|
"invalid_node_configuration",
|
|
"unsupported_start_input",
|
|
"unsupported_input_value",
|
|
"unsupported_features",
|
|
"unsupported_variables",
|
|
"unsupported_external_tracing",
|
|
# unavailable_metadata
|
|
"installed_tool_unavailable",
|
|
"invalid_graph_metadata",
|
|
"session_state_unavailable",
|
|
"real_call_unavailable",
|
|
# conflict
|
|
"stale_session_version",
|
|
"stale_app_revision",
|
|
"stale_consent_version",
|
|
"stale_execution_revision",
|
|
"test_input_binding_mismatch",
|
|
"consent_scope_mismatch",
|
|
"consent_scope_changed",
|
|
"consent_invalidated",
|
|
"consent_expired",
|
|
"consent_not_prepared",
|
|
"consent_not_confirmed",
|
|
"consent_already_claimed",
|
|
"consent_decision_conflict",
|
|
"idempotency_conflict",
|
|
"execution_already_launched",
|
|
"command_lineage_changed",
|
|
"session_busy",
|
|
"session_conflict",
|
|
]
|
|
|
|
|
|
class DifyBuilderRealCallRefusalResponse(ResponseModel):
|
|
"""Sanitized refusal of a real-call consent operation; carries fixed codes only."""
|
|
|
|
model_config = ConfigDict(json_schema_serialization_defaults_required=True)
|
|
|
|
result: Literal["refusal"] = "refusal"
|
|
code: DifyBuilderRealCallRefusalCode
|
|
reason_code: DifyBuilderRealCallRefusalReason
|
|
|
|
|
|
class DifyBuilderRealCallPermissionRefusalResponse(ResponseModel):
|
|
"""Execution permission refused after ownership was established; nothing foreign is disclosed."""
|
|
|
|
model_config = ConfigDict(json_schema_serialization_defaults_required=True)
|
|
|
|
result: Literal["refusal"] = "refusal"
|
|
code: Literal["needs_permission"]
|
|
reason_code: Literal["execution_permission_denied"]
|
|
|
|
|
|
class DifyBuilderFeatureUnavailableResponse(ResponseModel):
|
|
"""Builder is not enabled for the workspace (the shared ``dify_builder_required`` gate)."""
|
|
|
|
code: Literal["feature_unavailable"]
|
|
|
|
|
|
class DifyBuilderConsoleForbiddenResponse(ResponseModel):
|
|
"""Console permission-guard denial as serialized by the shared console HTTP error handler."""
|
|
|
|
code: Literal["forbidden"]
|
|
message: str
|
|
status: Literal[403]
|
|
|
|
|
|
class DifyBuilderRealCallForbiddenResponse(
|
|
RootModel[
|
|
Annotated[
|
|
DifyBuilderRealCallPermissionRefusalResponse
|
|
| DifyBuilderFeatureUnavailableResponse
|
|
| DifyBuilderConsoleForbiddenResponse,
|
|
Field(discriminator="code"),
|
|
]
|
|
]
|
|
):
|
|
"""Every HTTP 403 body a real-call consent route can return."""
|
|
|
|
|
|
class DifyBuilderNativeTestResponse(ResponseModel):
|
|
"""Strict public native receipt; domain DTO also owns generated schemas."""
|
|
|
|
data: NativeTestPublicReceipt
|
|
|
|
|
|
class DifyBuilderNativeTestInputResponse(ResponseModel):
|
|
data: NativeTestInputBinding
|