mirror of
https://github.com/langgenius/dify.git
synced 2026-09-24 23:22:26 +08:00
fix(api): tighten agent v2 generated contracts (#36989)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -91,7 +91,7 @@ class AgentAppConfigManager(BaseAppConfigManager):
|
||||
"provider": model.model_provider,
|
||||
"name": model.model,
|
||||
"mode": "chat",
|
||||
"completion_params": dict(model.model_settings or {}),
|
||||
"completion_params": model.model_settings.model_dump(mode="json", exclude_none=True),
|
||||
}
|
||||
# The Agent Soul system prompt rides the EasyUI "simple" prompt slot; the
|
||||
# agent backend is the real prompt authority, this only feeds the chat
|
||||
|
||||
@@ -112,7 +112,7 @@ class AgentAppRuntimeRequestBuilder:
|
||||
model_provider=self._plugin_daemon_provider_name(agent_soul.model.model_provider),
|
||||
model=agent_soul.model.model,
|
||||
credentials=self._normalize_credentials(credentials),
|
||||
model_settings=agent_soul.model.model_settings,
|
||||
model_settings=agent_soul.model.model_settings.model_dump(mode="json", exclude_none=True),
|
||||
),
|
||||
execution_context=DifyExecutionContextLayerConfig(
|
||||
tenant_id=context.dify_context.tenant_id,
|
||||
|
||||
@@ -31,7 +31,7 @@ RESERVED_AGENT_BACKEND_FEATURES = frozenset(
|
||||
def build_runtime_feature_manifest(agent_soul: AgentSoulConfig) -> dict[str, Any]:
|
||||
"""Describe PRD capabilities that are persisted but not executed in phase 3."""
|
||||
warnings: list[dict[str, str]] = []
|
||||
soul_dump = agent_soul.model_dump(mode="json")
|
||||
soul_dump = agent_soul.model_dump(mode="json", exclude_none=True, exclude_defaults=True)
|
||||
for section in sorted(RESERVED_AGENT_BACKEND_FEATURES):
|
||||
value = _get_nested(soul_dump, section)
|
||||
has_value = bool(value)
|
||||
|
||||
@@ -25,6 +25,7 @@ from models.agent_config_entities import (
|
||||
DeclaredOutputConfig,
|
||||
DeclaredOutputType,
|
||||
WorkflowNodeJobConfig,
|
||||
WorkflowPreviousNodeOutputRef,
|
||||
)
|
||||
from models.agent_config_entities import (
|
||||
effective_declared_outputs as _effective_declared_outputs,
|
||||
@@ -139,7 +140,7 @@ class WorkflowAgentRuntimeRequestBuilder:
|
||||
model_provider=self._plugin_daemon_provider_name(agent_soul.model.model_provider),
|
||||
model=agent_soul.model.model,
|
||||
credentials=self._normalize_credentials(credentials),
|
||||
model_settings=agent_soul.model.model_settings,
|
||||
model_settings=agent_soul.model.model_settings.model_dump(mode="json", exclude_none=True),
|
||||
),
|
||||
# The execution-context layer is now the only public protocol
|
||||
# carrier for Dify tenant/user/run identifiers. ``user_id`` must
|
||||
@@ -253,7 +254,7 @@ class WorkflowAgentRuntimeRequestBuilder:
|
||||
def _resolve_previous_node_outputs(
|
||||
self,
|
||||
variable_pool: VariablePoolReader,
|
||||
refs: Sequence[Mapping[str, Any]],
|
||||
refs: Sequence[WorkflowPreviousNodeOutputRef],
|
||||
) -> list[dict[str, Any]]:
|
||||
resolved: list[dict[str, Any]] = []
|
||||
for ref in refs:
|
||||
@@ -279,7 +280,7 @@ class WorkflowAgentRuntimeRequestBuilder:
|
||||
return resolved
|
||||
|
||||
@staticmethod
|
||||
def _selector_from_ref(ref: Mapping[str, Any]) -> list[str] | None:
|
||||
def _selector_from_ref(ref: WorkflowPreviousNodeOutputRef) -> list[str] | None:
|
||||
for key in ("selector", "variable_selector", "value_selector"):
|
||||
value = ref.get(key)
|
||||
if isinstance(value, list) and all(isinstance(item, str) for item in value):
|
||||
|
||||
@@ -9,7 +9,13 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from graphon.enums import BuiltinNodeTypes
|
||||
from models.agent import Agent, AgentConfigSnapshot, AgentStatus, WorkflowAgentNodeBinding
|
||||
from models.agent_config_entities import AgentSoulConfig, WorkflowNodeJobConfig
|
||||
from models.agent_config_entities import (
|
||||
AgentFileRefConfig,
|
||||
AgentHumanContactConfig,
|
||||
AgentSoulConfig,
|
||||
WorkflowNodeJobConfig,
|
||||
WorkflowPreviousNodeOutputRef,
|
||||
)
|
||||
from models.model import UploadFile
|
||||
from models.workflow import Workflow
|
||||
|
||||
@@ -183,16 +189,15 @@ class WorkflowAgentNodeValidator:
|
||||
for human_ref in node_job.human_contacts:
|
||||
cls._validate_human_ref(binding=binding, human_ref=human_ref)
|
||||
|
||||
file_refs = node_job.metadata.get("file_refs")
|
||||
file_refs = node_job.metadata.file_refs
|
||||
if isinstance(file_refs, list):
|
||||
for file_ref in file_refs:
|
||||
if isinstance(file_ref, Mapping):
|
||||
cls._validate_file_ref(
|
||||
session=session,
|
||||
binding=binding,
|
||||
file_ref=file_ref,
|
||||
ref_context="metadata file ref",
|
||||
)
|
||||
cls._validate_file_ref(
|
||||
session=session,
|
||||
binding=binding,
|
||||
file_ref=file_ref,
|
||||
ref_context="metadata file ref",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def iter_agent_v2_nodes(graph_dict: Mapping[str, Any]) -> Iterator[tuple[str, Mapping[str, Any]]]:
|
||||
@@ -210,7 +215,7 @@ class WorkflowAgentNodeValidator:
|
||||
yield node_id, node_data
|
||||
|
||||
@staticmethod
|
||||
def selector_from_ref(ref: Mapping[str, Any]) -> list[str] | None:
|
||||
def selector_from_ref(ref: WorkflowPreviousNodeOutputRef) -> list[str] | None:
|
||||
for key in ("selector", "variable_selector", "value_selector"):
|
||||
value = ref.get(key)
|
||||
if isinstance(value, list) and all(isinstance(item, str) for item in value):
|
||||
@@ -237,7 +242,7 @@ class WorkflowAgentNodeValidator:
|
||||
binding: WorkflowAgentNodeBinding,
|
||||
node_job: WorkflowNodeJobConfig,
|
||||
) -> None:
|
||||
forbidden_paths = cls._find_locked_agent_soul_paths(node_job.metadata)
|
||||
forbidden_paths = cls._find_locked_agent_soul_paths(node_job.metadata.model_dump(mode="python"))
|
||||
if forbidden_paths:
|
||||
raise WorkflowAgentNodeValidationError(
|
||||
f"Workflow Agent node {binding.node_id} cannot override locked Agent Soul fields: "
|
||||
@@ -261,7 +266,7 @@ class WorkflowAgentNodeValidator:
|
||||
cls,
|
||||
*,
|
||||
binding: WorkflowAgentNodeBinding,
|
||||
human_ref: Mapping[str, Any],
|
||||
human_ref: AgentHumanContactConfig,
|
||||
) -> None:
|
||||
contact_id = human_ref.get("contact_id") or human_ref.get("human_id") or human_ref.get("id")
|
||||
if not isinstance(contact_id, str) or not contact_id:
|
||||
@@ -306,7 +311,7 @@ class WorkflowAgentNodeValidator:
|
||||
*,
|
||||
session: Session,
|
||||
binding: WorkflowAgentNodeBinding,
|
||||
file_ref: Mapping[str, Any],
|
||||
file_ref: AgentFileRefConfig,
|
||||
ref_context: str,
|
||||
) -> None:
|
||||
tenant_id = file_ref.get("tenant_id")
|
||||
|
||||
Reference in New Issue
Block a user