diff --git a/api/controllers/console/app/agent_app_feature.py b/api/controllers/console/app/agent_app_feature.py index fbedddaf0d..104fc391d5 100644 --- a/api/controllers/console/app/agent_app_feature.py +++ b/api/controllers/console/app/agent_app_feature.py @@ -9,8 +9,6 @@ persists them onto the app's ``app_model_config`` without touching anything the Soul owns. """ -from typing import Any - from flask_restx import Resource from pydantic import BaseModel, Field @@ -25,13 +23,20 @@ from controllers.console.wraps import ( with_current_user, ) from events.app_event import app_model_config_was_updated +from libs.helper import dump_response from libs.login import login_required from models import Account +from models.agent_config_entities import ( + AgentFeatureToggleConfig, + AgentSensitiveWordAvoidanceFeatureConfig, + AgentSuggestedQuestionsAfterAnswerFeatureConfig, + AgentTextToSpeechFeatureConfig, +) from models.model import App, AppMode from services.agent_app_feature_service import AgentAppFeatureConfigService -class AgentAppFeaturesRequest(BaseModel): +class AgentAppFeaturesPayload(BaseModel): """Presentation features configurable on an Agent App. All fields are optional; an omitted field is reset to its disabled/empty @@ -42,18 +47,20 @@ class AgentAppFeaturesRequest(BaseModel): suggested_questions: list[str] | None = Field( default=None, description="Preset questions shown alongside the opener" ) - suggested_questions_after_answer: dict[str, Any] | None = Field( + suggested_questions_after_answer: AgentSuggestedQuestionsAfterAnswerFeatureConfig | None = Field( default=None, description="Follow-up suggestions config, e.g. {'enabled': true}" ) - speech_to_text: dict[str, Any] | None = Field(default=None, description="Speech-to-text config") - text_to_speech: dict[str, Any] | None = Field(default=None, description="Text-to-speech config") - retriever_resource: dict[str, Any] | None = Field( + speech_to_text: AgentFeatureToggleConfig | None = Field(default=None, description="Speech-to-text config") + text_to_speech: AgentTextToSpeechFeatureConfig | None = Field(default=None, description="Text-to-speech config") + retriever_resource: AgentFeatureToggleConfig | None = Field( default=None, description="Citations / attributions config, e.g. {'enabled': true}" ) - sensitive_word_avoidance: dict[str, Any] | None = Field(default=None, description="Content moderation config") + sensitive_word_avoidance: AgentSensitiveWordAvoidanceFeatureConfig | None = Field( + default=None, description="Content moderation config" + ) -register_schema_models(console_ns, AgentAppFeaturesRequest) +register_schema_models(console_ns, AgentAppFeaturesPayload) register_response_schema_models(console_ns, SimpleResultResponse) @@ -62,7 +69,7 @@ class AgentAppFeatureConfigResource(Resource): @console_ns.doc("update_agent_app_features") @console_ns.doc(description="Update an Agent App's presentation features (opener, follow-up, citations, ...)") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[AgentAppFeaturesRequest.__name__]) + @console_ns.expect(console_ns.models[AgentAppFeaturesPayload.__name__]) @console_ns.response(200, "Features updated successfully", console_ns.models[SimpleResultResponse.__name__]) @console_ns.response(400, "Invalid configuration") @console_ns.response(404, "App not found") @@ -73,7 +80,7 @@ class AgentAppFeatureConfigResource(Resource): @get_app_model(mode=[AppMode.AGENT]) @with_current_user def post(self, current_user: Account, app_model: App): - args = AgentAppFeaturesRequest.model_validate(console_ns.payload) + args = AgentAppFeaturesPayload.model_validate(console_ns.payload or {}) new_app_model_config = AgentAppFeatureConfigService.update_features( app_model=app_model, @@ -83,4 +90,4 @@ class AgentAppFeatureConfigResource(Resource): app_model_config_was_updated.send(app_model, app_model_config=new_app_model_config) - return {"result": "success"} + return dump_response(SimpleResultResponse, {"result": "success"}) diff --git a/api/core/app/apps/agent_app/app_config_manager.py b/api/core/app/apps/agent_app/app_config_manager.py index 5889c7c285..6721f8bcb1 100644 --- a/api/core/app/apps/agent_app/app_config_manager.py +++ b/api/core/app/apps/agent_app/app_config_manager.py @@ -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 diff --git a/api/core/app/apps/agent_app/runtime_request_builder.py b/api/core/app/apps/agent_app/runtime_request_builder.py index 1c4c59ae37..a62728c9cf 100644 --- a/api/core/app/apps/agent_app/runtime_request_builder.py +++ b/api/core/app/apps/agent_app/runtime_request_builder.py @@ -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, diff --git a/api/core/workflow/nodes/agent_v2/runtime_feature_manifest.py b/api/core/workflow/nodes/agent_v2/runtime_feature_manifest.py index b08dc36fb7..63d67b1532 100644 --- a/api/core/workflow/nodes/agent_v2/runtime_feature_manifest.py +++ b/api/core/workflow/nodes/agent_v2/runtime_feature_manifest.py @@ -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) diff --git a/api/core/workflow/nodes/agent_v2/runtime_request_builder.py b/api/core/workflow/nodes/agent_v2/runtime_request_builder.py index f093587b57..1715e9e938 100644 --- a/api/core/workflow/nodes/agent_v2/runtime_request_builder.py +++ b/api/core/workflow/nodes/agent_v2/runtime_request_builder.py @@ -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): diff --git a/api/core/workflow/nodes/agent_v2/validators.py b/api/core/workflow/nodes/agent_v2/validators.py index 768fcdadeb..964ed24c2e 100644 --- a/api/core/workflow/nodes/agent_v2/validators.py +++ b/api/core/workflow/nodes/agent_v2/validators.py @@ -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") diff --git a/api/fields/agent_fields.py b/api/fields/agent_fields.py index 9590032383..a25b5e67d3 100644 --- a/api/fields/agent_fields.py +++ b/api/fields/agent_fields.py @@ -1,4 +1,4 @@ -from typing import Any, Literal +from typing import Literal from pydantic import Field @@ -13,10 +13,15 @@ from models.agent import ( WorkflowAgentBindingType, ) from models.agent_config_entities import ( + AgentCliToolConfig, + AgentHumanContactConfig, + AgentKnowledgeDatasetConfig, + AgentSkillRefConfig, AgentSoulConfig, DeclaredOutputConfig, DeclaredOutputType, WorkflowNodeJobConfig, + WorkflowPreviousNodeOutputRef, ) from services.entities.agent_entities import ( ComposerCandidateCapabilities, @@ -167,18 +172,27 @@ class AgentComposerValidateResponse(ResponseModel): errors: list[str] = Field(default_factory=list) +class AgentComposerDifyToolCandidateResponse(ResponseModel): + id: str | None = None + name: str | None = None + description: str | None = None + provider: str | None = None + provider_id: str | None = None + plugin_id: str | None = None + + class AgentComposerNodeJobCandidatesResponse(ResponseModel): - previous_node_outputs: list[dict[str, Any]] = Field(default_factory=list) + previous_node_outputs: list[WorkflowPreviousNodeOutputRef] = Field(default_factory=list) declare_output_types: list[DeclaredOutputType] = Field(default_factory=list) - human_contacts: list[dict[str, Any]] = Field(default_factory=list) + human_contacts: list[AgentHumanContactConfig] = Field(default_factory=list) class AgentComposerSoulCandidatesResponse(ResponseModel): - skills_files: list[dict[str, Any]] = Field(default_factory=list) - dify_tools: list[dict[str, Any]] = Field(default_factory=list) - cli_tools: list[dict[str, Any]] = Field(default_factory=list) - knowledge_datasets: list[dict[str, Any]] = Field(default_factory=list) - human_contacts: list[dict[str, Any]] = Field(default_factory=list) + skills_files: list[AgentSkillRefConfig] = Field(default_factory=list) + dify_tools: list[AgentComposerDifyToolCandidateResponse] = Field(default_factory=list) + cli_tools: list[AgentCliToolConfig] = Field(default_factory=list) + knowledge_datasets: list[AgentKnowledgeDatasetConfig] = Field(default_factory=list) + human_contacts: list[AgentHumanContactConfig] = Field(default_factory=list) class AgentComposerCandidatesResponse(ResponseModel): diff --git a/api/models/agent_config_entities.py b/api/models/agent_config_entities.py index ec604115de..c5a16c46b0 100644 --- a/api/models/agent_config_entities.py +++ b/api/models/agent_config_entities.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re from enum import StrEnum from typing import Any, Final, Literal @@ -40,14 +42,182 @@ class OutputErrorStrategy(StrEnum): # JSON-schema-friendly name pattern. Stage 4 §3.1 / §10.1. _OUTPUT_NAME_PATTERN: Final[re.Pattern[str]] = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") +JsonPrimitive = str | int | float | bool | None +RuntimeParameterValue = JsonPrimitive | list[str] | list[int] | list[float] | list[bool] + + +class AgentFlexibleConfig(BaseModel): + model_config = ConfigDict(extra="allow") + + def get(self, key: str, default: Any = None) -> Any: + return self.model_dump(mode="python").get(key, default) + + def items(self): + return self.model_dump(mode="python").items() + + def __bool__(self) -> bool: + return bool(self.model_dump(mode="python", exclude_none=True, exclude_defaults=True)) + + +class AgentFileRefConfig(AgentFlexibleConfig): + id: str | None = Field(default=None, max_length=255) + name: str | None = Field(default=None, max_length=255) + type: str | None = Field(default=None, max_length=64) + transfer_method: str | None = Field(default=None, max_length=64) + url: str | None = None + + +class AgentSkillRefConfig(AgentFlexibleConfig): + id: str | None = Field(default=None, max_length=255) + name: str | None = Field(default=None, max_length=255) + description: str | None = None + file_id: str | None = Field(default=None, max_length=255) + path: str | None = None + + +class AgentCliToolConfig(AgentFlexibleConfig): + enabled: bool = True + name: str | None = Field(default=None, max_length=255) + description: str | None = None + command: str | None = None + + +class AgentKnowledgeDatasetConfig(AgentFlexibleConfig): + id: str | None = Field(default=None, max_length=255) + name: str | None = Field(default=None, max_length=255) + description: str | None = None + + +class AgentKnowledgeQueryConfig(AgentFlexibleConfig): + query: str | None = None + top_k: int | None = Field(default=None, ge=1) + score_threshold: float | None = Field(default=None, ge=0, le=1) + score_threshold_enabled: bool | None = None + + +class AgentHumanContactConfig(AgentFlexibleConfig): + id: str | None = Field(default=None, max_length=255) + contact_id: str | None = Field(default=None, max_length=255) + human_id: str | None = Field(default=None, max_length=255) + name: str | None = Field(default=None, max_length=255) + email: str | None = Field(default=None, max_length=255) + + +class AgentHumanToolConfig(AgentFlexibleConfig): + enabled: bool = True + name: str | None = Field(default=None, max_length=255) + description: str | None = None + + +class AgentEnvVariableConfig(AgentFlexibleConfig): + name: str | None = Field(default=None, max_length=255) + type: str | None = Field(default=None, max_length=64) + value: RuntimeParameterValue = None + required: bool = False + + +class AgentSecretRefConfig(AgentFlexibleConfig): + name: str | None = Field(default=None, max_length=255) + type: str | None = Field(default=None, max_length=64) + id: str | None = Field(default=None, max_length=255) + provider: str | None = Field(default=None, max_length=255) + + +class AgentSandboxProviderConfig(AgentFlexibleConfig): + image: str | None = None + working_dir: str | None = None + env: list[AgentEnvVariableConfig] = Field(default_factory=list) + + +class AgentMemoryArtifactConfig(AgentFlexibleConfig): + id: str | None = Field(default=None, max_length=255) + type: str | None = Field(default=None, max_length=64) + name: str | None = Field(default=None, max_length=255) + url: str | None = None + + +class AgentModelResponseFormatConfig(AgentFlexibleConfig): + type: str | None = Field(default=None, max_length=64) + + +class AgentSoulModelSettings(BaseModel): + model_config = ConfigDict(extra="allow") + + temperature: float | None = None + top_p: float | None = None + presence_penalty: float | None = None + frequency_penalty: float | None = None + max_tokens: int | None = None + stop: list[str] | None = None + response_format: AgentModelResponseFormatConfig | None = None + + +class AgentFeatureToggleConfig(AgentFlexibleConfig): + enabled: bool = False + + +class AgentTextToSpeechFeatureConfig(AgentFeatureToggleConfig): + language: str | None = None + voice: str | None = None + autoPlay: str | None = None + + +class AgentSuggestedQuestionsAfterAnswerFeatureConfig(AgentFeatureToggleConfig): + prompt: str | None = None + model: AgentSoulModelConfig | None = None + + +class AgentModerationIOConfig(AgentFlexibleConfig): + enabled: bool = False + preset_response: str | None = None + + +class AgentModerationProviderConfig(AgentFlexibleConfig): + keywords: str | None = None + api_based_extension_id: str | None = None + inputs_config: AgentModerationIOConfig | None = None + outputs_config: AgentModerationIOConfig | None = None + + +class AgentSensitiveWordAvoidanceFeatureConfig(AgentFeatureToggleConfig): + type: str | None = None + config: AgentModerationProviderConfig | None = None + + +class AgentSoulAppFeaturesConfig(AgentFlexibleConfig): + opening_statement: str | None = None + suggested_questions: list[str] | None = None + suggested_questions_after_answer: AgentSuggestedQuestionsAfterAnswerFeatureConfig | None = None + speech_to_text: AgentFeatureToggleConfig | None = None + text_to_speech: AgentTextToSpeechFeatureConfig | None = None + retriever_resource: AgentFeatureToggleConfig | None = None + sensitive_word_avoidance: AgentSensitiveWordAvoidanceFeatureConfig | None = None + + +class WorkflowPreviousNodeOutputRef(AgentFlexibleConfig): + selector: list[JsonPrimitive] | None = None + variable_selector: list[JsonPrimitive] | None = None + value_selector: list[JsonPrimitive] | None = None + node_id: str | None = Field(default=None, max_length=255) + output: str | None = Field(default=None, max_length=255) + name: str | None = Field(default=None, max_length=255) + variable: str | None = Field(default=None, max_length=255) + key: str | None = Field(default=None, max_length=255) + + +class WorkflowNodeJobMetadata(BaseModel): + model_config = ConfigDict(extra="allow") + + file_refs: list[AgentFileRefConfig] | None = None + class AgentSoulPromptConfig(BaseModel): system_prompt: str = "" class AgentSoulSkillsFilesConfig(BaseModel): - files: list[dict[str, Any]] = Field(default_factory=list) - skills: list[dict[str, Any]] = Field(default_factory=list) + files: list[AgentFileRefConfig] = Field(default_factory=list) + skills: list[AgentSkillRefConfig] = Field(default_factory=list) class AgentSoulDifyToolCredentialRef(BaseModel): @@ -97,7 +267,7 @@ class AgentSoulDifyToolConfig(BaseModel): # (see :meth:`_validate_provider_and_credentials`). name: str | None = Field(default=None, max_length=255) description: str | None = None - runtime_parameters: dict[str, Any] = Field(default_factory=dict) + runtime_parameters: dict[str, RuntimeParameterValue] = Field(default_factory=dict) @model_validator(mode="before") @classmethod @@ -118,7 +288,7 @@ class AgentSoulDifyToolConfig(BaseModel): return normalized @model_validator(mode="after") - def _validate_provider_and_credentials(self) -> "AgentSoulDifyToolConfig": + def _validate_provider_and_credentials(self) -> AgentSoulDifyToolConfig: if not self.provider_id and not (self.plugin_id and self.provider): raise ValueError("Dify tool requires provider_id or plugin_id + provider") if self.credential_type != "unauthorized" and (self.credential_ref is None or not self.credential_ref.id): @@ -134,34 +304,34 @@ class AgentSoulDifyToolConfig(BaseModel): class AgentSoulToolsConfig(BaseModel): dify_tools: list[AgentSoulDifyToolConfig] = Field(default_factory=list) - cli_tools: list[dict[str, Any]] = Field(default_factory=list) + cli_tools: list[AgentCliToolConfig] = Field(default_factory=list) class AgentSoulKnowledgeConfig(BaseModel): - datasets: list[dict[str, Any]] = Field(default_factory=list) + datasets: list[AgentKnowledgeDatasetConfig] = Field(default_factory=list) query_mode: AgentKnowledgeQueryMode | None = None - query_config: dict[str, Any] = Field(default_factory=dict) + query_config: AgentKnowledgeQueryConfig = Field(default_factory=AgentKnowledgeQueryConfig) class AgentSoulHumanConfig(BaseModel): - contacts: list[dict[str, Any]] = Field(default_factory=list) - tools: list[dict[str, Any]] = Field(default_factory=list) + contacts: list[AgentHumanContactConfig] = Field(default_factory=list) + tools: list[AgentHumanToolConfig] = Field(default_factory=list) class AgentSoulEnvConfig(BaseModel): - variables: list[dict[str, Any]] = Field(default_factory=list) - secret_refs: list[dict[str, Any]] = Field(default_factory=list) + variables: list[AgentEnvVariableConfig] = Field(default_factory=list) + secret_refs: list[AgentSecretRefConfig] = Field(default_factory=list) class AgentSoulSandboxConfig(BaseModel): provider: str | None = None - config: dict[str, Any] = Field(default_factory=dict) + config: AgentSandboxProviderConfig = Field(default_factory=AgentSandboxProviderConfig) class AgentSoulMemoryConfig(BaseModel): scope: str | None = None budget: str | None = None - artifacts: list[dict[str, Any]] = Field(default_factory=list) + artifacts: list[AgentMemoryArtifactConfig] = Field(default_factory=list) class AgentSoulModelCredentialRef(BaseModel): @@ -179,7 +349,7 @@ class AgentSoulModelConfig(BaseModel): model_provider: str = Field(min_length=1, max_length=255) model: str = Field(min_length=1, max_length=255) credential_ref: AgentSoulModelCredentialRef | None = None - model_settings: dict[str, Any] = Field(default_factory=dict) + model_settings: AgentSoulModelSettings = Field(default_factory=AgentSoulModelSettings) class AppVariableConfig(BaseModel): @@ -202,9 +372,9 @@ class AgentSoulConfig(BaseModel): sandbox: AgentSoulSandboxConfig = Field(default_factory=AgentSoulSandboxConfig) memory: AgentSoulMemoryConfig = Field(default_factory=AgentSoulMemoryConfig) model: AgentSoulModelConfig | None = None - app_features: dict[str, Any] = Field(default_factory=dict) + app_features: AgentSoulAppFeaturesConfig = Field(default_factory=AgentSoulAppFeaturesConfig) app_variables: list[AppVariableConfig] = Field(default_factory=list) - misc_legacy: dict[str, Any] = Field(default_factory=dict) + misc_legacy: AgentSoulAppFeaturesConfig = Field(default_factory=AgentSoulAppFeaturesConfig) class DeclaredOutputFileConfig(BaseModel): @@ -230,7 +400,7 @@ class DeclaredArrayItem(BaseModel): description: str | None = None @model_validator(mode="after") - def _reject_nested_array(self) -> "DeclaredArrayItem": + def _reject_nested_array(self) -> DeclaredArrayItem: if self.type == DeclaredOutputType.ARRAY: raise ValueError("nested arrays are not supported as array_item.type") return self @@ -246,13 +416,13 @@ class DeclaredOutputCheckConfig(BaseModel): enabled: bool = False prompt: str | None = None - benchmark_file_ref: dict[str, Any] | None = None + benchmark_file_ref: AgentFileRefConfig | None = None # Reserved for stage 4.1: pick a different model than Agent Soul's for the check. # Stage 4 leaves this Optional and unused by FileOutputCheckExecutor. - model_ref: dict[str, Any] | None = None + model_ref: AgentSoulModelConfig | None = None @model_validator(mode="after") - def _require_prompt_and_benchmark_when_enabled(self) -> "DeclaredOutputCheckConfig": + def _require_prompt_and_benchmark_when_enabled(self) -> DeclaredOutputCheckConfig: if self.enabled: if not self.prompt or not self.prompt.strip(): raise ValueError("prompt is required when output check is enabled") @@ -288,7 +458,7 @@ class DeclaredOutputFailureStrategy(BaseModel): default_value: Any = None @model_validator(mode="after") - def _require_default_value_when_default_strategy(self) -> "DeclaredOutputFailureStrategy": + def _require_default_value_when_default_strategy(self) -> DeclaredOutputFailureStrategy: if self.on_failure == OutputErrorStrategy.DEFAULT_VALUE and self.default_value is None: raise ValueError( "default_value must be provided when on_failure=default_value; None is reserved for 'not set'." @@ -326,7 +496,7 @@ class DeclaredOutputConfig(BaseModel): return value @model_validator(mode="after") - def _validate_shape(self) -> "DeclaredOutputConfig": + def _validate_shape(self) -> DeclaredOutputConfig: if not _OUTPUT_NAME_PATTERN.fullmatch(self.name): raise ValueError( f"output name {self.name!r} must match {_OUTPUT_NAME_PATTERN.pattern} (JSON-schema-friendly identifier)" @@ -427,7 +597,7 @@ class WorkflowNodeJobConfig(BaseModel): schema_version: int = 1 mode: WorkflowNodeJobMode = WorkflowNodeJobMode.TELL_AGENT_WHAT_TO_DO workflow_prompt: str = "" - previous_node_output_refs: list[dict[str, Any]] = Field(default_factory=list) + previous_node_output_refs: list[WorkflowPreviousNodeOutputRef] = Field(default_factory=list) declared_outputs: list[DeclaredOutputConfig] = Field(default_factory=list) - human_contacts: list[dict[str, Any]] = Field(default_factory=list) - metadata: dict[str, Any] = Field(default_factory=dict) + human_contacts: list[AgentHumanContactConfig] = Field(default_factory=list) + metadata: WorkflowNodeJobMetadata = Field(default_factory=WorkflowNodeJobMetadata) diff --git a/api/openapi/markdown/console-swagger.md b/api/openapi/markdown/console-swagger.md index 04235cd528..9f3dd16622 100644 --- a/api/openapi/markdown/console-swagger.md +++ b/api/openapi/markdown/console-swagger.md @@ -1072,7 +1072,7 @@ Update an Agent App's presentation features (opener, follow-up, citations, ...) | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| payload | body | | Yes | [AgentAppFeaturesRequest](#agentappfeaturesrequest) | +| payload | body | | Yes | [AgentAppFeaturesPayload](#agentappfeaturespayload) | | app_id | path | Application ID | Yes | string | ##### Responses @@ -10769,7 +10769,7 @@ Get banner list | save_options | [ [ComposerSaveStrategy](#composersavestrategy) ] | | Yes | | variant | string | | Yes | -#### AgentAppFeaturesRequest +#### AgentAppFeaturesPayload Presentation features configurable on an Agent App. @@ -10779,12 +10779,21 @@ default (the config form sends the full desired feature state on save). | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | opening_statement | string | Conversation opener shown before the first turn | No | -| retriever_resource | object | Citations / attributions config, e.g. {'enabled': true} | No | -| sensitive_word_avoidance | object | Content moderation config | No | -| speech_to_text | object | Speech-to-text config | No | +| retriever_resource | [AgentFeatureToggleConfig](#agentfeaturetoggleconfig) | Citations / attributions config, e.g. {'enabled': true} | No | +| sensitive_word_avoidance | [AgentSensitiveWordAvoidanceFeatureConfig](#agentsensitivewordavoidancefeatureconfig) | Content moderation config | No | +| speech_to_text | [AgentFeatureToggleConfig](#agentfeaturetoggleconfig) | Speech-to-text config | No | | suggested_questions | [ string ] | Preset questions shown alongside the opener | No | -| suggested_questions_after_answer | object | Follow-up suggestions config, e.g. {'enabled': true} | No | -| text_to_speech | object | Text-to-speech config | No | +| suggested_questions_after_answer | [AgentSuggestedQuestionsAfterAnswerFeatureConfig](#agentsuggestedquestionsafteranswerfeatureconfig) | Follow-up suggestions config, e.g. {'enabled': true} | No | +| text_to_speech | [AgentTextToSpeechFeatureConfig](#agenttexttospeechfeatureconfig) | Text-to-speech config | No | + +#### AgentCliToolConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| command | string | | No | +| description | string | | No | +| enabled | boolean | | No | +| name | string | | No | #### AgentComposerAgentResponse @@ -10817,6 +10826,17 @@ default (the config form sends the full desired feature state on save). | capabilities | [ComposerCandidateCapabilities](#composercandidatecapabilities) | | No | | variant | [ComposerVariant](#composervariant) | | Yes | +#### AgentComposerDifyToolCandidateResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| description | string | | No | +| id | string | | No | +| name | string | | No | +| plugin_id | string | | No | +| provider | string | | No | +| provider_id | string | | No | + #### AgentComposerImpactBindingResponse | Name | Type | Description | Required | @@ -10838,18 +10858,18 @@ default (the config form sends the full desired feature state on save). | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | declare_output_types | [ [DeclaredOutputType](#declaredoutputtype) ] | | No | -| human_contacts | [ object ] | | No | -| previous_node_outputs | [ object ] | | No | +| human_contacts | [ [AgentHumanContactConfig](#agenthumancontactconfig) ] | | No | +| previous_node_outputs | [ [WorkflowPreviousNodeOutputRef](#workflowpreviousnodeoutputref) ] | | No | #### AgentComposerSoulCandidatesResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| cli_tools | [ object ] | | No | -| dify_tools | [ object ] | | No | -| human_contacts | [ object ] | | No | -| knowledge_datasets | [ object ] | | No | -| skills_files | [ object ] | | No | +| cli_tools | [ [AgentCliToolConfig](#agentclitoolconfig) ] | | No | +| dify_tools | [ [AgentComposerDifyToolCandidateResponse](#agentcomposerdifytoolcandidateresponse) ] | | No | +| human_contacts | [ [AgentHumanContactConfig](#agenthumancontactconfig) ] | | No | +| knowledge_datasets | [ [AgentKnowledgeDatasetConfig](#agentknowledgedatasetconfig) ] | | No | +| skills_files | [ [AgentSkillRefConfig](#agentskillrefconfig) ] | | No | #### AgentComposerSoulLockResponse @@ -10920,6 +10940,49 @@ Audit operation recorded for Agent Soul version/revision changes. | version | integer | | Yes | | version_note | string | | No | +#### AgentEnvVariableConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| name | string | | No | +| required | boolean | | No | +| type | string | | No | +| value | string
integer
number
boolean
[ string ]
[ integer ]
[ number ]
[ boolean ] | | No | + +#### AgentFeatureToggleConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | + +#### AgentFileRefConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| id | string | | No | +| name | string | | No | +| transfer_method | string | | No | +| type | string | | No | +| url | string | | No | + +#### AgentHumanContactConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| contact_id | string | | No | +| email | string | | No | +| human_id | string | | No | +| id | string | | No | +| name | string | | No | + +#### AgentHumanToolConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| description | string | | No | +| enabled | boolean | | No | +| name | string | | No | + #### AgentIconType Supported icon storage formats for Agent roster entries. @@ -10993,6 +11056,23 @@ the current roster/workflow APIs scoped to Dify Agent. | ---- | ---- | ----------- | -------- | | AgentKind | string | Agent implementation family. This leaves room for future non-Dify agent implementations while keeping the current roster/workflow APIs scoped to Dify Agent. | | +#### AgentKnowledgeDatasetConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| description | string | | No | +| id | string | | No | +| name | string | | No | + +#### AgentKnowledgeQueryConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| query | string | | No | +| score_threshold | number | | No | +| score_threshold_enabled | boolean | | No | +| top_k | integer | | No | + #### AgentKnowledgeQueryMode | Name | Type | Description | Required | @@ -11006,6 +11086,37 @@ the current roster/workflow APIs scoped to Dify Agent. | conversation_id | string | Conversation UUID | Yes | | message_id | string | Message UUID | Yes | +#### AgentMemoryArtifactConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| id | string | | No | +| name | string | | No | +| type | string | | No | +| url | string | | No | + +#### AgentModelResponseFormatConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| type | string | | No | + +#### AgentModerationIOConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | +| preset_response | string | | No | + +#### AgentModerationProviderConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| api_based_extension_id | string | | No | +| inputs_config | [AgentModerationIOConfig](#agentmoderationioconfig) | | No | +| keywords | string | | No | +| outputs_config | [AgentModerationIOConfig](#agentmoderationioconfig) | | No | + #### AgentReferencingWorkflowResponse | Name | Type | Description | Required | @@ -11058,6 +11169,14 @@ the current roster/workflow APIs scoped to Dify Agent. | workflow_id | string | | No | | workflow_node_id | string | | No | +#### AgentSandboxProviderConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| env | [ [AgentEnvVariableConfig](#agentenvvariableconfig) ] | | No | +| image | string | | No | +| working_dir | string | | No | + #### AgentScope Visibility and lifecycle scope of an Agent record. @@ -11066,17 +11185,56 @@ Visibility and lifecycle scope of an Agent record. | ---- | ---- | ----------- | -------- | | AgentScope | string | Visibility and lifecycle scope of an Agent record. | | +#### AgentSecretRefConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| id | string | | No | +| name | string | | No | +| provider | string | | No | +| type | string | | No | + +#### AgentSensitiveWordAvoidanceFeatureConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| config | [AgentModerationProviderConfig](#agentmoderationproviderconfig) | | No | +| enabled | boolean | | No | +| type | string | | No | + +#### AgentSkillRefConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| description | string | | No | +| file_id | string | | No | +| id | string | | No | +| name | string | | No | +| path | string | | No | + +#### AgentSoulAppFeaturesConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| opening_statement | string | | No | +| retriever_resource | [AgentFeatureToggleConfig](#agentfeaturetoggleconfig) | | No | +| sensitive_word_avoidance | [AgentSensitiveWordAvoidanceFeatureConfig](#agentsensitivewordavoidancefeatureconfig) | | No | +| speech_to_text | [AgentFeatureToggleConfig](#agentfeaturetoggleconfig) | | No | +| suggested_questions | [ string ] | | No | +| suggested_questions_after_answer | [AgentSuggestedQuestionsAfterAnswerFeatureConfig](#agentsuggestedquestionsafteranswerfeatureconfig) | | No | +| text_to_speech | [AgentTextToSpeechFeatureConfig](#agenttexttospeechfeatureconfig) | | No | + #### AgentSoulConfig | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| app_features | object | | No | +| app_features | [AgentSoulAppFeaturesConfig](#agentsoulappfeaturesconfig) | | No | | app_variables | [ [AppVariableConfig](#appvariableconfig) ] | | No | | env | [AgentSoulEnvConfig](#agentsoulenvconfig) | | No | | human | [AgentSoulHumanConfig](#agentsoulhumanconfig) | | No | | knowledge | [AgentSoulKnowledgeConfig](#agentsoulknowledgeconfig) | | No | | memory | [AgentSoulMemoryConfig](#agentsoulmemoryconfig) | | No | -| misc_legacy | object | | No | +| misc_legacy | [AgentSoulAppFeaturesConfig](#agentsoulappfeaturesconfig) | | No | | model | [AgentSoulModelConfig](#agentsoulmodelconfig) | | No | | prompt | [AgentSoulPromptConfig](#agentsoulpromptconfig) | | No | | sandbox | [AgentSoulSandboxConfig](#agentsoulsandboxconfig) | | No | @@ -11125,29 +11283,29 @@ old Agent tool payloads can be read while new payloads stay explicit. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| secret_refs | [ object ] | | No | -| variables | [ object ] | | No | +| secret_refs | [ [AgentSecretRefConfig](#agentsecretrefconfig) ] | | No | +| variables | [ [AgentEnvVariableConfig](#agentenvvariableconfig) ] | | No | #### AgentSoulHumanConfig | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| contacts | [ object ] | | No | -| tools | [ object ] | | No | +| contacts | [ [AgentHumanContactConfig](#agenthumancontactconfig) ] | | No | +| tools | [ [AgentHumanToolConfig](#agenthumantoolconfig) ] | | No | #### AgentSoulKnowledgeConfig | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| datasets | [ object ] | | No | -| query_config | object | | No | +| datasets | [ [AgentKnowledgeDatasetConfig](#agentknowledgedatasetconfig) ] | | No | +| query_config | [AgentKnowledgeQueryConfig](#agentknowledgequeryconfig) | | No | | query_mode | [AgentKnowledgeQueryMode](#agentknowledgequerymode) | | No | #### AgentSoulMemoryConfig | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| artifacts | [ object ] | | No | +| artifacts | [ [AgentMemoryArtifactConfig](#agentmemoryartifactconfig) ] | | No | | budget | string | | No | | scope | string | | No | @@ -11160,7 +11318,7 @@ Stable model selection for Agent runtime without storing secret values. | credential_ref | [AgentSoulModelCredentialRef](#agentsoulmodelcredentialref) | | No | | model | string | | Yes | | model_provider | string | | Yes | -| model_settings | object | | No | +| model_settings | [AgentSoulModelSettings](#agentsoulmodelsettings) | | No | | plugin_id | string | | Yes | #### AgentSoulModelCredentialRef @@ -11173,6 +11331,18 @@ Reference to model credentials resolved only at runtime. | provider | string | | No | | type | string | | Yes | +#### AgentSoulModelSettings + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| frequency_penalty | number | | No | +| max_tokens | integer | | No | +| presence_penalty | number | | No | +| response_format | [AgentModelResponseFormatConfig](#agentmodelresponseformatconfig) | | No | +| stop | [ string ] | | No | +| temperature | number | | No | +| top_p | number | | No | + #### AgentSoulPromptConfig | Name | Type | Description | Required | @@ -11183,21 +11353,21 @@ Reference to model credentials resolved only at runtime. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| config | object | | No | +| config | [AgentSandboxProviderConfig](#agentsandboxproviderconfig) | | No | | provider | string | | No | #### AgentSoulSkillsFilesConfig | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| files | [ object ] | | No | -| skills | [ object ] | | No | +| files | [ [AgentFileRefConfig](#agentfilerefconfig) ] | | No | +| skills | [ [AgentSkillRefConfig](#agentskillrefconfig) ] | | No | #### AgentSoulToolsConfig | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| cli_tools | [ object ] | | No | +| cli_tools | [ [AgentCliToolConfig](#agentclitoolconfig) ] | | No | | dify_tools | [ [AgentSoulDifyToolConfig](#agentsouldifytoolconfig) ] | | No | #### AgentSource @@ -11216,6 +11386,23 @@ Soft lifecycle state for Agent records. | ---- | ---- | ----------- | -------- | | AgentStatus | string | Soft lifecycle state for Agent records. | | +#### AgentSuggestedQuestionsAfterAnswerFeatureConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | +| model | [AgentSoulModelConfig](#agentsoulmodelconfig) | | No | +| prompt | string | | No | + +#### AgentTextToSpeechFeatureConfig + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| autoPlay | string | | No | +| enabled | boolean | | No | +| language | string | | No | +| voice | string | | No | + #### AgentThought | Name | Type | Description | Required | @@ -12833,9 +13020,9 @@ Per PRD §OUTPUT 配置框, output check is **file-only** and optional. Stage 4 | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| benchmark_file_ref | object | | No | +| benchmark_file_ref | [AgentFileRefConfig](#agentfilerefconfig) | | No | | enabled | boolean | | No | -| model_ref | object | | No | +| model_ref | [AgentSoulModelConfig](#agentsoulmodelconfig) | | No | | prompt | string | | No | #### DeclaredOutputConfig @@ -16262,13 +16449,19 @@ How a workflow node is bound to an Agent. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | declared_outputs | [ [DeclaredOutputConfig](#declaredoutputconfig) ] | | No | -| human_contacts | [ object ] | | No | -| metadata | object | | No | +| human_contacts | [ [AgentHumanContactConfig](#agenthumancontactconfig) ] | | No | +| metadata | [WorkflowNodeJobMetadata](#workflownodejobmetadata) | | No | | mode | [WorkflowNodeJobMode](#workflownodejobmode) | | No | -| previous_node_output_refs | [ object ] | | No | +| previous_node_output_refs | [ [WorkflowPreviousNodeOutputRef](#workflowpreviousnodeoutputref) ] | | No | | schema_version | integer | | No | | workflow_prompt | string | | No | +#### WorkflowNodeJobMetadata + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| file_refs | [ [AgentFileRefConfig](#agentfilerefconfig) ] | | No | + #### WorkflowNodeJobMode | Name | Type | Description | Required | @@ -16328,6 +16521,19 @@ How a workflow node is bound to an Agent. | paused_at | string | | No | | paused_nodes | [ [PausedNodeResponse](#pausednoderesponse) ] | | Yes | +#### WorkflowPreviousNodeOutputRef + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| key | string | | No | +| name | string | | No | +| node_id | string | | No | +| output | string | | No | +| selector | [ ] | | No | +| value_selector | [ ] | | No | +| variable | string | | No | +| variable_selector | [ ] | | No | + #### WorkflowResponse | Name | Type | Description | Required | diff --git a/packages/contracts/generated/api/console/agents/orpc.gen.ts b/packages/contracts/generated/api/console/agents/orpc.gen.ts index 067dd6fc93..25c1ee7cc7 100644 --- a/packages/contracts/generated/api/console/agents/orpc.gen.ts +++ b/packages/contracts/generated/api/console/agents/orpc.gen.ts @@ -38,16 +38,8 @@ export const inviteOptions = { get, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getAgentsByAgentIdVersionsByVersionId', @@ -129,16 +121,8 @@ export const get5 = oc .input(z.object({ query: zGetAgentsQuery.optional() })) .output(zGetAgentsResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAgents', diff --git a/packages/contracts/generated/api/console/agents/types.gen.ts b/packages/contracts/generated/api/console/agents/types.gen.ts index 3ab55fe03a..f1451ab165 100644 --- a/packages/contracts/generated/api/console/agents/types.gen.ts +++ b/packages/contracts/generated/api/console/agents/types.gen.ts @@ -79,17 +79,13 @@ export type AgentConfigSnapshotDetailResponse = { } export type AgentSoulConfig = { - app_features?: { - [key: string]: unknown - } + app_features?: AgentSoulAppFeaturesConfig app_variables?: Array env?: AgentSoulEnvConfig human?: AgentSoulHumanConfig knowledge?: AgentSoulKnowledgeConfig memory?: AgentSoulMemoryConfig - misc_legacy?: { - [key: string]: unknown - } + misc_legacy?: AgentSoulAppFeaturesConfig model?: AgentSoulModelConfig prompt?: AgentSoulPromptConfig sandbox?: AgentSoulSandboxConfig @@ -157,6 +153,17 @@ export type AgentConfigRevisionResponse = { version_note?: string | null } +export type AgentSoulAppFeaturesConfig = { + opening_statement?: string | null + retriever_resource?: AgentFeatureToggleConfig + sensitive_word_avoidance?: AgentSensitiveWordAvoidanceFeatureConfig + speech_to_text?: AgentFeatureToggleConfig + suggested_questions?: Array | null + suggested_questions_after_answer?: AgentSuggestedQuestionsAfterAnswerFeatureConfig + text_to_speech?: AgentTextToSpeechFeatureConfig + [key: string]: unknown +} + export type AppVariableConfig = { default?: unknown name: string @@ -165,37 +172,23 @@ export type AppVariableConfig = { } export type AgentSoulEnvConfig = { - secret_refs?: Array<{ - [key: string]: unknown - }> - variables?: Array<{ - [key: string]: unknown - }> + secret_refs?: Array + variables?: Array } export type AgentSoulHumanConfig = { - contacts?: Array<{ - [key: string]: unknown - }> - tools?: Array<{ - [key: string]: unknown - }> + contacts?: Array + tools?: Array } export type AgentSoulKnowledgeConfig = { - datasets?: Array<{ - [key: string]: unknown - }> - query_config?: { - [key: string]: unknown - } + datasets?: Array + query_config?: AgentKnowledgeQueryConfig query_mode?: AgentKnowledgeQueryMode } export type AgentSoulMemoryConfig = { - artifacts?: Array<{ - [key: string]: unknown - }> + artifacts?: Array budget?: string | null scope?: string | null } @@ -204,9 +197,7 @@ export type AgentSoulModelConfig = { credential_ref?: AgentSoulModelCredentialRef model: string model_provider: string - model_settings?: { - [key: string]: unknown - } + model_settings?: AgentSoulModelSettings plugin_id: string } @@ -215,25 +206,17 @@ export type AgentSoulPromptConfig = { } export type AgentSoulSandboxConfig = { - config?: { - [key: string]: unknown - } + config?: AgentSandboxProviderConfig provider?: string | null } export type AgentSoulSkillsFilesConfig = { - files?: Array<{ - [key: string]: unknown - }> - skills?: Array<{ - [key: string]: unknown - }> + files?: Array + skills?: Array } export type AgentSoulToolsConfig = { - cli_tools?: Array<{ - [key: string]: unknown - }> + cli_tools?: Array dify_tools?: Array } @@ -244,14 +227,140 @@ export type AgentConfigRevisionOperation | 'save_new_version' | 'save_to_roster' +export type AgentFeatureToggleConfig = { + enabled?: boolean + [key: string]: unknown +} + +export type AgentSensitiveWordAvoidanceFeatureConfig = { + config?: AgentModerationProviderConfig + enabled?: boolean + type?: string | null + [key: string]: unknown +} + +export type AgentSuggestedQuestionsAfterAnswerFeatureConfig = { + enabled?: boolean + model?: AgentSoulModelConfig + prompt?: string | null + [key: string]: unknown +} + +export type AgentTextToSpeechFeatureConfig = { + autoPlay?: string | null + enabled?: boolean + language?: string | null + voice?: string | null + [key: string]: unknown +} + +export type AgentSecretRefConfig = { + id?: string | null + name?: string | null + provider?: string | null + type?: string | null + [key: string]: unknown +} + +export type AgentEnvVariableConfig = { + name?: string | null + required?: boolean + type?: string | null + value?: unknown + [key: string]: unknown +} + +export type AgentHumanContactConfig = { + contact_id?: string | null + email?: string | null + human_id?: string | null + id?: string | null + name?: string | null + [key: string]: unknown +} + +export type AgentHumanToolConfig = { + description?: string | null + enabled?: boolean + name?: string | null + [key: string]: unknown +} + +export type AgentKnowledgeDatasetConfig = { + description?: string | null + id?: string | null + name?: string | null + [key: string]: unknown +} + +export type AgentKnowledgeQueryConfig = { + query?: string | null + score_threshold?: number | null + score_threshold_enabled?: boolean | null + top_k?: number | null + [key: string]: unknown +} + export type AgentKnowledgeQueryMode = 'generated_query' | 'user_query' +export type AgentMemoryArtifactConfig = { + id?: string | null + name?: string | null + type?: string | null + url?: string | null + [key: string]: unknown +} + export type AgentSoulModelCredentialRef = { id?: string | null provider?: string | null type: string } +export type AgentSoulModelSettings = { + frequency_penalty?: number | null + max_tokens?: number | null + presence_penalty?: number | null + response_format?: AgentModelResponseFormatConfig + stop?: Array | null + temperature?: number | null + top_p?: number | null + [key: string]: unknown +} + +export type AgentSandboxProviderConfig = { + env?: Array + image?: string | null + working_dir?: string | null + [key: string]: unknown +} + +export type AgentFileRefConfig = { + id?: string | null + name?: string | null + transfer_method?: string | null + type?: string | null + url?: string | null + [key: string]: unknown +} + +export type AgentSkillRefConfig = { + description?: string | null + file_id?: string | null + id?: string | null + name?: string | null + path?: string | null + [key: string]: unknown +} + +export type AgentCliToolConfig = { + command?: string | null + description?: string | null + enabled?: boolean + name?: string | null + [key: string]: unknown +} + export type AgentSoulDifyToolConfig = { credential_ref?: AgentSoulDifyToolCredentialRef credential_type?: 'api-key' | 'oauth2' | 'unauthorized' @@ -268,12 +377,31 @@ export type AgentSoulDifyToolConfig = { tool_name: string } +export type AgentModerationProviderConfig = { + api_based_extension_id?: string | null + inputs_config?: AgentModerationIoConfig + keywords?: string | null + outputs_config?: AgentModerationIoConfig + [key: string]: unknown +} + +export type AgentModelResponseFormatConfig = { + type?: string | null + [key: string]: unknown +} + export type AgentSoulDifyToolCredentialRef = { id?: string | null provider?: string | null type?: 'provider' | 'tool' } +export type AgentModerationIoConfig = { + enabled?: boolean + preset_response?: string | null + [key: string]: unknown +} + export type GetAgentsData = { body?: never path?: never diff --git a/packages/contracts/generated/api/console/agents/zod.gen.ts b/packages/contracts/generated/api/console/agents/zod.gen.ts index 58e7f1c894..e36018567d 100644 --- a/packages/contracts/generated/api/console/agents/zod.gen.ts +++ b/packages/contracts/generated/api/console/agents/zod.gen.ts @@ -160,31 +160,6 @@ export const zAppVariableConfig = z.object({ type: z.string().min(1).max(64), }) -/** - * AgentSoulEnvConfig - */ -export const zAgentSoulEnvConfig = z.object({ - secret_refs: z.array(z.record(z.string(), z.unknown())).optional(), - variables: z.array(z.record(z.string(), z.unknown())).optional(), -}) - -/** - * AgentSoulHumanConfig - */ -export const zAgentSoulHumanConfig = z.object({ - contacts: z.array(z.record(z.string(), z.unknown())).optional(), - tools: z.array(z.record(z.string(), z.unknown())).optional(), -}) - -/** - * AgentSoulMemoryConfig - */ -export const zAgentSoulMemoryConfig = z.object({ - artifacts: z.array(z.record(z.string(), z.unknown())).optional(), - budget: z.string().nullish(), - scope: z.string().nullish(), -}) - /** * AgentSoulPromptConfig */ @@ -192,22 +167,6 @@ export const zAgentSoulPromptConfig = z.object({ system_prompt: z.string().optional().default(''), }) -/** - * AgentSoulSandboxConfig - */ -export const zAgentSoulSandboxConfig = z.object({ - config: z.record(z.string(), z.unknown()).optional(), - provider: z.string().nullish(), -}) - -/** - * AgentSoulSkillsFilesConfig - */ -export const zAgentSoulSkillsFilesConfig = z.object({ - files: z.array(z.record(z.string(), z.unknown())).optional(), - skills: z.array(z.record(z.string(), z.unknown())).optional(), -}) - /** * AgentConfigRevisionOperation * @@ -236,6 +195,98 @@ export const zAgentConfigRevisionResponse = z.object({ version_note: z.string().nullish(), }) +/** + * AgentFeatureToggleConfig + */ +export const zAgentFeatureToggleConfig = z.object({ + enabled: z.boolean().optional().default(false), +}) + +/** + * AgentTextToSpeechFeatureConfig + */ +export const zAgentTextToSpeechFeatureConfig = z.object({ + autoPlay: z.string().nullish(), + enabled: z.boolean().optional().default(false), + language: z.string().nullish(), + voice: z.string().nullish(), +}) + +/** + * AgentSecretRefConfig + */ +export const zAgentSecretRefConfig = z.object({ + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + provider: z.string().max(255).nullish(), + type: z.string().max(64).nullish(), +}) + +/** + * AgentEnvVariableConfig + */ +export const zAgentEnvVariableConfig = z.object({ + name: z.string().max(255).nullish(), + required: z.boolean().optional().default(false), + type: z.string().max(64).nullish(), + value: z.unknown().optional(), +}) + +/** + * AgentSoulEnvConfig + */ +export const zAgentSoulEnvConfig = z.object({ + secret_refs: z.array(zAgentSecretRefConfig).optional(), + variables: z.array(zAgentEnvVariableConfig).optional(), +}) + +/** + * AgentHumanContactConfig + */ +export const zAgentHumanContactConfig = z.object({ + contact_id: z.string().max(255).nullish(), + email: z.string().max(255).nullish(), + human_id: z.string().max(255).nullish(), + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), +}) + +/** + * AgentHumanToolConfig + */ +export const zAgentHumanToolConfig = z.object({ + description: z.string().nullish(), + enabled: z.boolean().optional().default(true), + name: z.string().max(255).nullish(), +}) + +/** + * AgentSoulHumanConfig + */ +export const zAgentSoulHumanConfig = z.object({ + contacts: z.array(zAgentHumanContactConfig).optional(), + tools: z.array(zAgentHumanToolConfig).optional(), +}) + +/** + * AgentKnowledgeDatasetConfig + */ +export const zAgentKnowledgeDatasetConfig = z.object({ + description: z.string().nullish(), + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), +}) + +/** + * AgentKnowledgeQueryConfig + */ +export const zAgentKnowledgeQueryConfig = z.object({ + query: z.string().nullish(), + score_threshold: z.number().gte(0).lte(1).nullish(), + score_threshold_enabled: z.boolean().nullish(), + top_k: z.int().gte(1).nullish(), +}) + /** * AgentKnowledgeQueryMode */ @@ -245,11 +296,30 @@ export const zAgentKnowledgeQueryMode = z.enum(['generated_query', 'user_query'] * AgentSoulKnowledgeConfig */ export const zAgentSoulKnowledgeConfig = z.object({ - datasets: z.array(z.record(z.string(), z.unknown())).optional(), - query_config: z.record(z.string(), z.unknown()).optional(), + datasets: z.array(zAgentKnowledgeDatasetConfig).optional(), + query_config: zAgentKnowledgeQueryConfig.optional(), query_mode: zAgentKnowledgeQueryMode.optional(), }) +/** + * AgentMemoryArtifactConfig + */ +export const zAgentMemoryArtifactConfig = z.object({ + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + type: z.string().max(64).nullish(), + url: z.string().nullish(), +}) + +/** + * AgentSoulMemoryConfig + */ +export const zAgentSoulMemoryConfig = z.object({ + artifacts: z.array(zAgentMemoryArtifactConfig).optional(), + budget: z.string().nullish(), + scope: z.string().nullish(), +}) + /** * AgentSoulModelCredentialRef * @@ -261,6 +331,83 @@ export const zAgentSoulModelCredentialRef = z.object({ type: z.string().min(1).max(64), }) +/** + * AgentSandboxProviderConfig + */ +export const zAgentSandboxProviderConfig = z.object({ + env: z.array(zAgentEnvVariableConfig).optional(), + image: z.string().nullish(), + working_dir: z.string().nullish(), +}) + +/** + * AgentSoulSandboxConfig + */ +export const zAgentSoulSandboxConfig = z.object({ + config: zAgentSandboxProviderConfig.optional(), + provider: z.string().nullish(), +}) + +/** + * AgentFileRefConfig + */ +export const zAgentFileRefConfig = z.object({ + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + transfer_method: z.string().max(64).nullish(), + type: z.string().max(64).nullish(), + url: z.string().nullish(), +}) + +/** + * AgentSkillRefConfig + */ +export const zAgentSkillRefConfig = z.object({ + description: z.string().nullish(), + file_id: z.string().max(255).nullish(), + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + path: z.string().nullish(), +}) + +/** + * AgentSoulSkillsFilesConfig + */ +export const zAgentSoulSkillsFilesConfig = z.object({ + files: z.array(zAgentFileRefConfig).optional(), + skills: z.array(zAgentSkillRefConfig).optional(), +}) + +/** + * AgentCliToolConfig + */ +export const zAgentCliToolConfig = z.object({ + command: z.string().nullish(), + description: z.string().nullish(), + enabled: z.boolean().optional().default(true), + name: z.string().max(255).nullish(), +}) + +/** + * AgentModelResponseFormatConfig + */ +export const zAgentModelResponseFormatConfig = z.object({ + type: z.string().max(64).nullish(), +}) + +/** + * AgentSoulModelSettings + */ +export const zAgentSoulModelSettings = z.object({ + frequency_penalty: z.number().nullish(), + max_tokens: z.int().nullish(), + presence_penalty: z.number().nullish(), + response_format: zAgentModelResponseFormatConfig.optional(), + stop: z.array(z.string()).nullish(), + temperature: z.number().nullish(), + top_p: z.number().nullish(), +}) + /** * AgentSoulModelConfig * @@ -270,10 +417,19 @@ export const zAgentSoulModelConfig = z.object({ credential_ref: zAgentSoulModelCredentialRef.optional(), model: z.string().min(1).max(255), model_provider: z.string().min(1).max(255), - model_settings: z.record(z.string(), z.unknown()).optional(), + model_settings: zAgentSoulModelSettings.optional(), plugin_id: z.string().min(1).max(255), }) +/** + * AgentSuggestedQuestionsAfterAnswerFeatureConfig + */ +export const zAgentSuggestedQuestionsAfterAnswerFeatureConfig = z.object({ + enabled: z.boolean().optional().default(false), + model: zAgentSoulModelConfig.optional(), + prompt: z.string().nullish(), +}) + /** * AgentSoulDifyToolCredentialRef * @@ -317,21 +473,61 @@ export const zAgentSoulDifyToolConfig = z.object({ * AgentSoulToolsConfig */ export const zAgentSoulToolsConfig = z.object({ - cli_tools: z.array(z.record(z.string(), z.unknown())).optional(), + cli_tools: z.array(zAgentCliToolConfig).optional(), dify_tools: z.array(zAgentSoulDifyToolConfig).optional(), }) +/** + * AgentModerationIOConfig + */ +export const zAgentModerationIoConfig = z.object({ + enabled: z.boolean().optional().default(false), + preset_response: z.string().nullish(), +}) + +/** + * AgentModerationProviderConfig + */ +export const zAgentModerationProviderConfig = z.object({ + api_based_extension_id: z.string().nullish(), + inputs_config: zAgentModerationIoConfig.optional(), + keywords: z.string().nullish(), + outputs_config: zAgentModerationIoConfig.optional(), +}) + +/** + * AgentSensitiveWordAvoidanceFeatureConfig + */ +export const zAgentSensitiveWordAvoidanceFeatureConfig = z.object({ + config: zAgentModerationProviderConfig.optional(), + enabled: z.boolean().optional().default(false), + type: z.string().nullish(), +}) + +/** + * AgentSoulAppFeaturesConfig + */ +export const zAgentSoulAppFeaturesConfig = z.object({ + opening_statement: z.string().nullish(), + retriever_resource: zAgentFeatureToggleConfig.optional(), + sensitive_word_avoidance: zAgentSensitiveWordAvoidanceFeatureConfig.optional(), + speech_to_text: zAgentFeatureToggleConfig.optional(), + suggested_questions: z.array(z.string()).nullish(), + suggested_questions_after_answer: zAgentSuggestedQuestionsAfterAnswerFeatureConfig.optional(), + text_to_speech: zAgentTextToSpeechFeatureConfig.optional(), +}) + /** * AgentSoulConfig */ export const zAgentSoulConfig = z.object({ - app_features: z.record(z.string(), z.unknown()).optional(), + app_features: zAgentSoulAppFeaturesConfig.optional(), app_variables: z.array(zAppVariableConfig).optional(), env: zAgentSoulEnvConfig.optional(), human: zAgentSoulHumanConfig.optional(), knowledge: zAgentSoulKnowledgeConfig.optional(), memory: zAgentSoulMemoryConfig.optional(), - misc_legacy: z.record(z.string(), z.unknown()).optional(), + misc_legacy: zAgentSoulAppFeaturesConfig.optional(), model: zAgentSoulModelConfig.optional(), prompt: zAgentSoulPromptConfig.optional(), sandbox: zAgentSoulSandboxConfig.optional(), diff --git a/packages/contracts/generated/api/console/apps/orpc.gen.ts b/packages/contracts/generated/api/console/apps/orpc.gen.ts index 7047f35a61..6fca124513 100644 --- a/packages/contracts/generated/api/console/apps/orpc.gen.ts +++ b/packages/contracts/generated/api/console/apps/orpc.gen.ts @@ -771,16 +771,8 @@ export const advancedChat = { workflows: workflows2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get4 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getAppsByAppIdAgentComposerCandidates', @@ -794,16 +786,8 @@ export const candidates = { get: get4, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post9 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdAgentComposerValidate', @@ -822,16 +806,8 @@ export const validate = { post: post9, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get5 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getAppsByAppIdAgentComposer', @@ -841,16 +817,8 @@ export const get5 = oc .input(z.object({ params: zGetAppsByAppIdAgentComposerPath })) .output(zGetAppsByAppIdAgentComposerResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const put = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PUT', operationId: 'putAppsByAppIdAgentComposer', @@ -871,16 +839,10 @@ export const agentComposer = { /** * Update an Agent App's presentation features (opener, follow-up, citations, ...) - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post10 = oc .route({ - deprecated: true, - description: - 'Update an Agent App\'s presentation features (opener, follow-up, citations, ...)\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Update an Agent App\'s presentation features (opener, follow-up, citations, ...)', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdAgentFeatures', @@ -3530,16 +3492,8 @@ export const loop2 = { nodes: nodes6, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get56 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCandidates', @@ -3555,16 +3509,8 @@ export const candidates2 = { get: get56, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post48 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpact', @@ -3583,16 +3529,8 @@ export const impact = { post: post48, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post49 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRoster', @@ -3611,16 +3549,8 @@ export const saveToRoster = { post: post49, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post50 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidate', @@ -3639,16 +3569,8 @@ export const validate2 = { post: post50, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get57 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposer', @@ -3658,16 +3580,8 @@ export const get57 = oc .input(z.object({ params: zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerPath })) .output(zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const put5 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PUT', operationId: 'putAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposer', diff --git a/packages/contracts/generated/api/console/apps/types.gen.ts b/packages/contracts/generated/api/console/apps/types.gen.ts index 7430914dd7..989d71a662 100644 --- a/packages/contracts/generated/api/console/apps/types.gen.ts +++ b/packages/contracts/generated/api/console/apps/types.gen.ts @@ -201,24 +201,14 @@ export type AgentComposerValidateResponse = { result: string } -export type AgentAppFeaturesRequest = { +export type AgentAppFeaturesPayload = { opening_statement?: string | null - retriever_resource?: { - [key: string]: unknown - } | null - sensitive_word_avoidance?: { - [key: string]: unknown - } | null - speech_to_text?: { - [key: string]: unknown - } | null + retriever_resource?: AgentFeatureToggleConfig + sensitive_word_avoidance?: AgentSensitiveWordAvoidanceFeatureConfig + speech_to_text?: AgentFeatureToggleConfig suggested_questions?: Array | null - suggested_questions_after_answer?: { - [key: string]: unknown - } | null - text_to_speech?: { - [key: string]: unknown - } | null + suggested_questions_after_answer?: AgentSuggestedQuestionsAfterAnswerFeatureConfig + text_to_speech?: AgentTextToSpeechFeatureConfig } export type SimpleResultResponse = { @@ -1048,17 +1038,13 @@ export type AgentComposerAgentResponse = { } export type AgentSoulConfig = { - app_features?: { - [key: string]: unknown - } + app_features?: AgentSoulAppFeaturesConfig app_variables?: Array env?: AgentSoulEnvConfig human?: AgentSoulHumanConfig knowledge?: AgentSoulKnowledgeConfig memory?: AgentSoulMemoryConfig - misc_legacy?: { - [key: string]: unknown - } + misc_legacy?: AgentSoulAppFeaturesConfig model?: AgentSoulModelConfig prompt?: AgentSoulPromptConfig sandbox?: AgentSoulSandboxConfig @@ -1082,16 +1068,10 @@ export type ComposerBindingPayload = { export type WorkflowNodeJobConfig = { declared_outputs?: Array - human_contacts?: Array<{ - [key: string]: unknown - }> - metadata?: { - [key: string]: unknown - } + human_contacts?: Array + metadata?: WorkflowNodeJobMetadata mode?: WorkflowNodeJobMode - previous_node_output_refs?: Array<{ - [key: string]: unknown - }> + previous_node_output_refs?: Array schema_version?: number workflow_prompt?: string } @@ -1105,36 +1085,49 @@ export type ComposerVariant = 'agent_app' | 'workflow' export type AgentComposerNodeJobCandidatesResponse = { declare_output_types?: Array - human_contacts?: Array<{ - [key: string]: unknown - }> - previous_node_outputs?: Array<{ - [key: string]: unknown - }> + human_contacts?: Array + previous_node_outputs?: Array } export type AgentComposerSoulCandidatesResponse = { - cli_tools?: Array<{ - [key: string]: unknown - }> - dify_tools?: Array<{ - [key: string]: unknown - }> - human_contacts?: Array<{ - [key: string]: unknown - }> - knowledge_datasets?: Array<{ - [key: string]: unknown - }> - skills_files?: Array<{ - [key: string]: unknown - }> + cli_tools?: Array + dify_tools?: Array + human_contacts?: Array + knowledge_datasets?: Array + skills_files?: Array } export type ComposerCandidateCapabilities = { human_roster_available?: boolean } +export type AgentFeatureToggleConfig = { + enabled?: boolean + [key: string]: unknown +} + +export type AgentSensitiveWordAvoidanceFeatureConfig = { + config?: AgentModerationProviderConfig + enabled?: boolean + type?: string | null + [key: string]: unknown +} + +export type AgentSuggestedQuestionsAfterAnswerFeatureConfig = { + enabled?: boolean + model?: AgentSoulModelConfig + prompt?: string | null + [key: string]: unknown +} + +export type AgentTextToSpeechFeatureConfig = { + autoPlay?: string | null + enabled?: boolean + language?: string | null + voice?: string | null + [key: string]: unknown +} + export type AgentReferencingWorkflowResponse = { app_id: string app_mode: string @@ -1516,6 +1509,17 @@ export type AgentScope = 'roster' | 'workflow_only' export type AgentStatus = 'active' | 'archived' +export type AgentSoulAppFeaturesConfig = { + opening_statement?: string | null + retriever_resource?: AgentFeatureToggleConfig + sensitive_word_avoidance?: AgentSensitiveWordAvoidanceFeatureConfig + speech_to_text?: AgentFeatureToggleConfig + suggested_questions?: Array | null + suggested_questions_after_answer?: AgentSuggestedQuestionsAfterAnswerFeatureConfig + text_to_speech?: AgentTextToSpeechFeatureConfig + [key: string]: unknown +} + export type AppVariableConfig = { default?: unknown name: string @@ -1524,37 +1528,23 @@ export type AppVariableConfig = { } export type AgentSoulEnvConfig = { - secret_refs?: Array<{ - [key: string]: unknown - }> - variables?: Array<{ - [key: string]: unknown - }> + secret_refs?: Array + variables?: Array } export type AgentSoulHumanConfig = { - contacts?: Array<{ - [key: string]: unknown - }> - tools?: Array<{ - [key: string]: unknown - }> + contacts?: Array + tools?: Array } export type AgentSoulKnowledgeConfig = { - datasets?: Array<{ - [key: string]: unknown - }> - query_config?: { - [key: string]: unknown - } + datasets?: Array + query_config?: AgentKnowledgeQueryConfig query_mode?: AgentKnowledgeQueryMode } export type AgentSoulMemoryConfig = { - artifacts?: Array<{ - [key: string]: unknown - }> + artifacts?: Array budget?: string | null scope?: string | null } @@ -1563,9 +1553,7 @@ export type AgentSoulModelConfig = { credential_ref?: AgentSoulModelCredentialRef model: string model_provider: string - model_settings?: { - [key: string]: unknown - } + model_settings?: AgentSoulModelSettings plugin_id: string } @@ -1574,32 +1562,91 @@ export type AgentSoulPromptConfig = { } export type AgentSoulSandboxConfig = { - config?: { - [key: string]: unknown - } + config?: AgentSandboxProviderConfig provider?: string | null } export type AgentSoulSkillsFilesConfig = { - files?: Array<{ - [key: string]: unknown - }> - skills?: Array<{ - [key: string]: unknown - }> + files?: Array + skills?: Array } export type AgentSoulToolsConfig = { - cli_tools?: Array<{ - [key: string]: unknown - }> + cli_tools?: Array dify_tools?: Array } +export type AgentHumanContactConfig = { + contact_id?: string | null + email?: string | null + human_id?: string | null + id?: string | null + name?: string | null + [key: string]: unknown +} + +export type WorkflowNodeJobMetadata = { + file_refs?: Array | null + [key: string]: unknown +} + export type WorkflowNodeJobMode = 'let_agent_figure_it_out' | 'tell_agent_what_to_do' +export type WorkflowPreviousNodeOutputRef = { + key?: string | null + name?: string | null + node_id?: string | null + output?: string | null + selector?: Array | null + value_selector?: Array | null + variable?: string | null + variable_selector?: Array | null + [key: string]: unknown +} + export type DeclaredOutputType = 'array' | 'boolean' | 'file' | 'number' | 'object' | 'string' +export type AgentCliToolConfig = { + command?: string | null + description?: string | null + enabled?: boolean + name?: string | null + [key: string]: unknown +} + +export type AgentComposerDifyToolCandidateResponse = { + description?: string | null + id?: string | null + name?: string | null + plugin_id?: string | null + provider?: string | null + provider_id?: string | null +} + +export type AgentKnowledgeDatasetConfig = { + description?: string | null + id?: string | null + name?: string | null + [key: string]: unknown +} + +export type AgentSkillRefConfig = { + description?: string | null + file_id?: string | null + id?: string | null + name?: string | null + path?: string | null + [key: string]: unknown +} + +export type AgentModerationProviderConfig = { + api_based_extension_id?: string | null + inputs_config?: AgentModerationIoConfig + keywords?: string | null + outputs_config?: AgentModerationIoConfig + [key: string]: unknown +} + export type SimpleModelConfig = { model_dict?: JsonValue pre_prompt?: string | null @@ -1676,13 +1723,9 @@ export type DeclaredArrayItem = { } export type DeclaredOutputCheckConfig = { - benchmark_file_ref?: { - [key: string]: unknown - } | null + benchmark_file_ref?: AgentFileRefConfig enabled?: boolean - model_ref?: { - [key: string]: unknown - } | null + model_ref?: AgentSoulModelConfig prompt?: string | null } @@ -1697,14 +1740,80 @@ export type DeclaredOutputFileConfig = { mime_types?: Array } +export type AgentSecretRefConfig = { + id?: string | null + name?: string | null + provider?: string | null + type?: string | null + [key: string]: unknown +} + +export type AgentEnvVariableConfig = { + name?: string | null + required?: boolean + type?: string | null + value?: unknown + [key: string]: unknown +} + +export type AgentHumanToolConfig = { + description?: string | null + enabled?: boolean + name?: string | null + [key: string]: unknown +} + +export type AgentKnowledgeQueryConfig = { + query?: string | null + score_threshold?: number | null + score_threshold_enabled?: boolean | null + top_k?: number | null + [key: string]: unknown +} + export type AgentKnowledgeQueryMode = 'generated_query' | 'user_query' +export type AgentMemoryArtifactConfig = { + id?: string | null + name?: string | null + type?: string | null + url?: string | null + [key: string]: unknown +} + export type AgentSoulModelCredentialRef = { id?: string | null provider?: string | null type: string } +export type AgentSoulModelSettings = { + frequency_penalty?: number | null + max_tokens?: number | null + presence_penalty?: number | null + response_format?: AgentModelResponseFormatConfig + stop?: Array | null + temperature?: number | null + top_p?: number | null + [key: string]: unknown +} + +export type AgentSandboxProviderConfig = { + env?: Array + image?: string | null + working_dir?: string | null + [key: string]: unknown +} + +export type AgentFileRefConfig = { + id?: string | null + name?: string | null + transfer_method?: string | null + type?: string | null + url?: string | null + [key: string]: unknown +} + export type AgentSoulDifyToolConfig = { credential_ref?: AgentSoulDifyToolCredentialRef credential_type?: 'api-key' | 'oauth2' | 'unauthorized' @@ -1721,6 +1830,12 @@ export type AgentSoulDifyToolConfig = { tool_name: string } +export type AgentModerationIoConfig = { + enabled?: boolean + preset_response?: string | null + [key: string]: unknown +} + export type UserActionConfig = { button_style?: ButtonStyle id: string @@ -1737,6 +1852,11 @@ export type DeclaredOutputRetryConfig = { retry_interval_ms?: number } +export type AgentModelResponseFormatConfig = { + type?: string | null + [key: string]: unknown +} + export type AgentSoulDifyToolCredentialRef = { id?: string | null provider?: string | null @@ -2278,7 +2398,7 @@ export type PostAppsByAppIdAgentComposerValidateResponse = PostAppsByAppIdAgentComposerValidateResponses[keyof PostAppsByAppIdAgentComposerValidateResponses] export type PostAppsByAppIdAgentFeaturesData = { - body: AgentAppFeaturesRequest + body: AgentAppFeaturesPayload path: { app_id: string } diff --git a/packages/contracts/generated/api/console/apps/zod.gen.ts b/packages/contracts/generated/api/console/apps/zod.gen.ts index 52d3c59c8a..2f79ac0900 100644 --- a/packages/contracts/generated/api/console/apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/apps/zod.gen.ts @@ -85,24 +85,6 @@ export const zAgentComposerValidateResponse = z.object({ result: z.string(), }) -/** - * AgentAppFeaturesRequest - * - * Presentation features configurable on an Agent App. - * - * All fields are optional; an omitted field is reset to its disabled/empty - * default (the config form sends the full desired feature state on save). - */ -export const zAgentAppFeaturesRequest = z.object({ - opening_statement: z.string().nullish(), - retriever_resource: z.record(z.string(), z.unknown()).nullish(), - sensitive_word_avoidance: z.record(z.string(), z.unknown()).nullish(), - speech_to_text: z.record(z.string(), z.unknown()).nullish(), - suggested_questions: z.array(z.string()).nullish(), - suggested_questions_after_answer: z.record(z.string(), z.unknown()).nullish(), - text_to_speech: z.record(z.string(), z.unknown()).nullish(), -}) - /** * SimpleResultResponse */ @@ -801,17 +783,6 @@ export const zComposerSoulLockPayload = z.object({ */ export const zComposerVariant = z.enum(['agent_app', 'workflow']) -/** - * AgentComposerSoulCandidatesResponse - */ -export const zAgentComposerSoulCandidatesResponse = z.object({ - cli_tools: z.array(z.record(z.string(), z.unknown())).optional(), - dify_tools: z.array(z.record(z.string(), z.unknown())).optional(), - human_contacts: z.array(z.record(z.string(), z.unknown())).optional(), - knowledge_datasets: z.array(z.record(z.string(), z.unknown())).optional(), - skills_files: z.array(z.record(z.string(), z.unknown())).optional(), -}) - /** * ComposerCandidateCapabilities */ @@ -819,6 +790,23 @@ export const zComposerCandidateCapabilities = z.object({ human_roster_available: z.boolean().optional().default(false), }) +/** + * AgentFeatureToggleConfig + */ +export const zAgentFeatureToggleConfig = z.object({ + enabled: z.boolean().optional().default(false), +}) + +/** + * AgentTextToSpeechFeatureConfig + */ +export const zAgentTextToSpeechFeatureConfig = z.object({ + autoPlay: z.string().nullish(), + enabled: z.boolean().optional().default(false), + language: z.string().nullish(), + voice: z.string().nullish(), +}) + /** * AgentReferencingWorkflowResponse */ @@ -1614,31 +1602,6 @@ export const zAppVariableConfig = z.object({ type: z.string().min(1).max(64), }) -/** - * AgentSoulEnvConfig - */ -export const zAgentSoulEnvConfig = z.object({ - secret_refs: z.array(z.record(z.string(), z.unknown())).optional(), - variables: z.array(z.record(z.string(), z.unknown())).optional(), -}) - -/** - * AgentSoulHumanConfig - */ -export const zAgentSoulHumanConfig = z.object({ - contacts: z.array(z.record(z.string(), z.unknown())).optional(), - tools: z.array(z.record(z.string(), z.unknown())).optional(), -}) - -/** - * AgentSoulMemoryConfig - */ -export const zAgentSoulMemoryConfig = z.object({ - artifacts: z.array(z.record(z.string(), z.unknown())).optional(), - budget: z.string().nullish(), - scope: z.string().nullish(), -}) - /** * AgentSoulPromptConfig */ @@ -1647,19 +1610,14 @@ export const zAgentSoulPromptConfig = z.object({ }) /** - * AgentSoulSandboxConfig + * AgentHumanContactConfig */ -export const zAgentSoulSandboxConfig = z.object({ - config: z.record(z.string(), z.unknown()).optional(), - provider: z.string().nullish(), -}) - -/** - * AgentSoulSkillsFilesConfig - */ -export const zAgentSoulSkillsFilesConfig = z.object({ - files: z.array(z.record(z.string(), z.unknown())).optional(), - skills: z.array(z.record(z.string(), z.unknown())).optional(), +export const zAgentHumanContactConfig = z.object({ + contact_id: z.string().max(255).nullish(), + email: z.string().max(255).nullish(), + human_id: z.string().max(255).nullish(), + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), }) /** @@ -1667,6 +1625,20 @@ export const zAgentSoulSkillsFilesConfig = z.object({ */ export const zWorkflowNodeJobMode = z.enum(['let_agent_figure_it_out', 'tell_agent_what_to_do']) +/** + * WorkflowPreviousNodeOutputRef + */ +export const zWorkflowPreviousNodeOutputRef = z.object({ + key: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + node_id: z.string().max(255).nullish(), + output: z.string().max(255).nullish(), + selector: z.array(z.unknown()).nullish(), + value_selector: z.array(z.unknown()).nullish(), + variable: z.string().max(255).nullish(), + variable_selector: z.array(z.unknown()).nullish(), +}) + /** * DeclaredOutputType */ @@ -1684,8 +1656,61 @@ export const zDeclaredOutputType = z.enum([ */ export const zAgentComposerNodeJobCandidatesResponse = z.object({ declare_output_types: z.array(zDeclaredOutputType).optional(), - human_contacts: z.array(z.record(z.string(), z.unknown())).optional(), - previous_node_outputs: z.array(z.record(z.string(), z.unknown())).optional(), + human_contacts: z.array(zAgentHumanContactConfig).optional(), + previous_node_outputs: z.array(zWorkflowPreviousNodeOutputRef).optional(), +}) + +/** + * AgentCliToolConfig + */ +export const zAgentCliToolConfig = z.object({ + command: z.string().nullish(), + description: z.string().nullish(), + enabled: z.boolean().optional().default(true), + name: z.string().max(255).nullish(), +}) + +/** + * AgentComposerDifyToolCandidateResponse + */ +export const zAgentComposerDifyToolCandidateResponse = z.object({ + description: z.string().nullish(), + id: z.string().nullish(), + name: z.string().nullish(), + plugin_id: z.string().nullish(), + provider: z.string().nullish(), + provider_id: z.string().nullish(), +}) + +/** + * AgentKnowledgeDatasetConfig + */ +export const zAgentKnowledgeDatasetConfig = z.object({ + description: z.string().nullish(), + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), +}) + +/** + * AgentSkillRefConfig + */ +export const zAgentSkillRefConfig = z.object({ + description: z.string().nullish(), + file_id: z.string().max(255).nullish(), + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + path: z.string().nullish(), +}) + +/** + * AgentComposerSoulCandidatesResponse + */ +export const zAgentComposerSoulCandidatesResponse = z.object({ + cli_tools: z.array(zAgentCliToolConfig).optional(), + dify_tools: z.array(zAgentComposerDifyToolCandidateResponse).optional(), + human_contacts: z.array(zAgentHumanContactConfig).optional(), + knowledge_datasets: z.array(zAgentKnowledgeDatasetConfig).optional(), + skills_files: z.array(zAgentSkillRefConfig).optional(), }) /** @@ -1918,20 +1943,6 @@ export const zDeclaredArrayItem = z.object({ type: zDeclaredOutputType, }) -/** - * DeclaredOutputCheckConfig - * - * File-output content check via a model-based comparison against a benchmark file. - * - * Per PRD §OUTPUT 配置框, output check is **file-only** and optional. Stage 4 §4.3. - */ -export const zDeclaredOutputCheckConfig = z.object({ - benchmark_file_ref: z.record(z.string(), z.unknown()).nullish(), - enabled: z.boolean().optional().default(false), - model_ref: z.record(z.string(), z.unknown()).nullish(), - prompt: z.string().nullish(), -}) - /** * DeclaredOutputFileConfig * @@ -1942,6 +1953,61 @@ export const zDeclaredOutputFileConfig = z.object({ mime_types: z.array(z.string()).optional(), }) +/** + * AgentSecretRefConfig + */ +export const zAgentSecretRefConfig = z.object({ + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + provider: z.string().max(255).nullish(), + type: z.string().max(64).nullish(), +}) + +/** + * AgentEnvVariableConfig + */ +export const zAgentEnvVariableConfig = z.object({ + name: z.string().max(255).nullish(), + required: z.boolean().optional().default(false), + type: z.string().max(64).nullish(), + value: z.unknown().optional(), +}) + +/** + * AgentSoulEnvConfig + */ +export const zAgentSoulEnvConfig = z.object({ + secret_refs: z.array(zAgentSecretRefConfig).optional(), + variables: z.array(zAgentEnvVariableConfig).optional(), +}) + +/** + * AgentHumanToolConfig + */ +export const zAgentHumanToolConfig = z.object({ + description: z.string().nullish(), + enabled: z.boolean().optional().default(true), + name: z.string().max(255).nullish(), +}) + +/** + * AgentSoulHumanConfig + */ +export const zAgentSoulHumanConfig = z.object({ + contacts: z.array(zAgentHumanContactConfig).optional(), + tools: z.array(zAgentHumanToolConfig).optional(), +}) + +/** + * AgentKnowledgeQueryConfig + */ +export const zAgentKnowledgeQueryConfig = z.object({ + query: z.string().nullish(), + score_threshold: z.number().gte(0).lte(1).nullish(), + score_threshold_enabled: z.boolean().nullish(), + top_k: z.int().gte(1).nullish(), +}) + /** * AgentKnowledgeQueryMode */ @@ -1951,11 +2017,30 @@ export const zAgentKnowledgeQueryMode = z.enum(['generated_query', 'user_query'] * AgentSoulKnowledgeConfig */ export const zAgentSoulKnowledgeConfig = z.object({ - datasets: z.array(z.record(z.string(), z.unknown())).optional(), - query_config: z.record(z.string(), z.unknown()).optional(), + datasets: z.array(zAgentKnowledgeDatasetConfig).optional(), + query_config: zAgentKnowledgeQueryConfig.optional(), query_mode: zAgentKnowledgeQueryMode.optional(), }) +/** + * AgentMemoryArtifactConfig + */ +export const zAgentMemoryArtifactConfig = z.object({ + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + type: z.string().max(64).nullish(), + url: z.string().nullish(), +}) + +/** + * AgentSoulMemoryConfig + */ +export const zAgentSoulMemoryConfig = z.object({ + artifacts: z.array(zAgentMemoryArtifactConfig).optional(), + budget: z.string().nullish(), + scope: z.string().nullish(), +}) + /** * AgentSoulModelCredentialRef * @@ -1968,16 +2053,73 @@ export const zAgentSoulModelCredentialRef = z.object({ }) /** - * AgentSoulModelConfig - * - * Stable model selection for Agent runtime without storing secret values. + * AgentSandboxProviderConfig */ -export const zAgentSoulModelConfig = z.object({ - credential_ref: zAgentSoulModelCredentialRef.optional(), - model: z.string().min(1).max(255), - model_provider: z.string().min(1).max(255), - model_settings: z.record(z.string(), z.unknown()).optional(), - plugin_id: z.string().min(1).max(255), +export const zAgentSandboxProviderConfig = z.object({ + env: z.array(zAgentEnvVariableConfig).optional(), + image: z.string().nullish(), + working_dir: z.string().nullish(), +}) + +/** + * AgentSoulSandboxConfig + */ +export const zAgentSoulSandboxConfig = z.object({ + config: zAgentSandboxProviderConfig.optional(), + provider: z.string().nullish(), +}) + +/** + * AgentFileRefConfig + */ +export const zAgentFileRefConfig = z.object({ + id: z.string().max(255).nullish(), + name: z.string().max(255).nullish(), + transfer_method: z.string().max(64).nullish(), + type: z.string().max(64).nullish(), + url: z.string().nullish(), +}) + +/** + * AgentSoulSkillsFilesConfig + */ +export const zAgentSoulSkillsFilesConfig = z.object({ + files: z.array(zAgentFileRefConfig).optional(), + skills: z.array(zAgentSkillRefConfig).optional(), +}) + +/** + * WorkflowNodeJobMetadata + */ +export const zWorkflowNodeJobMetadata = z.object({ + file_refs: z.array(zAgentFileRefConfig).nullish(), +}) + +/** + * AgentModerationIOConfig + */ +export const zAgentModerationIoConfig = z.object({ + enabled: z.boolean().optional().default(false), + preset_response: z.string().nullish(), +}) + +/** + * AgentModerationProviderConfig + */ +export const zAgentModerationProviderConfig = z.object({ + api_based_extension_id: z.string().nullish(), + inputs_config: zAgentModerationIoConfig.optional(), + keywords: z.string().nullish(), + outputs_config: zAgentModerationIoConfig.optional(), +}) + +/** + * AgentSensitiveWordAvoidanceFeatureConfig + */ +export const zAgentSensitiveWordAvoidanceFeatureConfig = z.object({ + config: zAgentModerationProviderConfig.optional(), + enabled: z.boolean().optional().default(false), + type: z.string().nullish(), }) export const zFormInputConfig = z.unknown() @@ -2018,6 +2160,93 @@ export const zDeclaredOutputFailureStrategy = z.object({ retry: zDeclaredOutputRetryConfig.optional(), }) +/** + * AgentModelResponseFormatConfig + */ +export const zAgentModelResponseFormatConfig = z.object({ + type: z.string().max(64).nullish(), +}) + +/** + * AgentSoulModelSettings + */ +export const zAgentSoulModelSettings = z.object({ + frequency_penalty: z.number().nullish(), + max_tokens: z.int().nullish(), + presence_penalty: z.number().nullish(), + response_format: zAgentModelResponseFormatConfig.optional(), + stop: z.array(z.string()).nullish(), + temperature: z.number().nullish(), + top_p: z.number().nullish(), +}) + +/** + * AgentSoulModelConfig + * + * Stable model selection for Agent runtime without storing secret values. + */ +export const zAgentSoulModelConfig = z.object({ + credential_ref: zAgentSoulModelCredentialRef.optional(), + model: z.string().min(1).max(255), + model_provider: z.string().min(1).max(255), + model_settings: zAgentSoulModelSettings.optional(), + plugin_id: z.string().min(1).max(255), +}) + +/** + * AgentSuggestedQuestionsAfterAnswerFeatureConfig + */ +export const zAgentSuggestedQuestionsAfterAnswerFeatureConfig = z.object({ + enabled: z.boolean().optional().default(false), + model: zAgentSoulModelConfig.optional(), + prompt: z.string().nullish(), +}) + +/** + * AgentAppFeaturesPayload + * + * Presentation features configurable on an Agent App. + * + * All fields are optional; an omitted field is reset to its disabled/empty + * default (the config form sends the full desired feature state on save). + */ +export const zAgentAppFeaturesPayload = z.object({ + opening_statement: z.string().nullish(), + retriever_resource: zAgentFeatureToggleConfig.optional(), + sensitive_word_avoidance: zAgentSensitiveWordAvoidanceFeatureConfig.optional(), + speech_to_text: zAgentFeatureToggleConfig.optional(), + suggested_questions: z.array(z.string()).nullish(), + suggested_questions_after_answer: zAgentSuggestedQuestionsAfterAnswerFeatureConfig.optional(), + text_to_speech: zAgentTextToSpeechFeatureConfig.optional(), +}) + +/** + * AgentSoulAppFeaturesConfig + */ +export const zAgentSoulAppFeaturesConfig = z.object({ + opening_statement: z.string().nullish(), + retriever_resource: zAgentFeatureToggleConfig.optional(), + sensitive_word_avoidance: zAgentSensitiveWordAvoidanceFeatureConfig.optional(), + speech_to_text: zAgentFeatureToggleConfig.optional(), + suggested_questions: z.array(z.string()).nullish(), + suggested_questions_after_answer: zAgentSuggestedQuestionsAfterAnswerFeatureConfig.optional(), + text_to_speech: zAgentTextToSpeechFeatureConfig.optional(), +}) + +/** + * DeclaredOutputCheckConfig + * + * File-output content check via a model-based comparison against a benchmark file. + * + * Per PRD §OUTPUT 配置框, output check is **file-only** and optional. Stage 4 §4.3. + */ +export const zDeclaredOutputCheckConfig = z.object({ + benchmark_file_ref: zAgentFileRefConfig.optional(), + enabled: z.boolean().optional().default(false), + model_ref: zAgentSoulModelConfig.optional(), + prompt: z.string().nullish(), +}) + /** * DeclaredOutputConfig * @@ -2044,10 +2273,10 @@ export const zDeclaredOutputConfig = z.object({ */ export const zWorkflowNodeJobConfig = z.object({ declared_outputs: z.array(zDeclaredOutputConfig).optional(), - human_contacts: z.array(z.record(z.string(), z.unknown())).optional(), - metadata: z.record(z.string(), z.unknown()).optional(), + human_contacts: z.array(zAgentHumanContactConfig).optional(), + metadata: zWorkflowNodeJobMetadata.optional(), mode: zWorkflowNodeJobMode.optional(), - previous_node_output_refs: z.array(z.record(z.string(), z.unknown())).optional(), + previous_node_output_refs: z.array(zWorkflowPreviousNodeOutputRef).optional(), schema_version: z.int().optional().default(1), workflow_prompt: z.string().optional().default(''), }) @@ -2095,7 +2324,7 @@ export const zAgentSoulDifyToolConfig = z.object({ * AgentSoulToolsConfig */ export const zAgentSoulToolsConfig = z.object({ - cli_tools: z.array(z.record(z.string(), z.unknown())).optional(), + cli_tools: z.array(zAgentCliToolConfig).optional(), dify_tools: z.array(zAgentSoulDifyToolConfig).optional(), }) @@ -2103,13 +2332,13 @@ export const zAgentSoulToolsConfig = z.object({ * AgentSoulConfig */ export const zAgentSoulConfig = z.object({ - app_features: z.record(z.string(), z.unknown()).optional(), + app_features: zAgentSoulAppFeaturesConfig.optional(), app_variables: z.array(zAppVariableConfig).optional(), env: zAgentSoulEnvConfig.optional(), human: zAgentSoulHumanConfig.optional(), knowledge: zAgentSoulKnowledgeConfig.optional(), memory: zAgentSoulMemoryConfig.optional(), - misc_legacy: z.record(z.string(), z.unknown()).optional(), + misc_legacy: zAgentSoulAppFeaturesConfig.optional(), model: zAgentSoulModelConfig.optional(), prompt: zAgentSoulPromptConfig.optional(), sandbox: zAgentSoulSandboxConfig.optional(), @@ -2653,7 +2882,7 @@ export const zPostAppsByAppIdAgentComposerValidatePath = z.object({ */ export const zPostAppsByAppIdAgentComposerValidateResponse = zAgentComposerValidateResponse -export const zPostAppsByAppIdAgentFeaturesBody = zAgentAppFeaturesRequest +export const zPostAppsByAppIdAgentFeaturesBody = zAgentAppFeaturesPayload export const zPostAppsByAppIdAgentFeaturesPath = z.object({ app_id: z.string(),