Agent V2 Variable System#
Agent V2 uses a dual-variable architecture that separates operator-side environment configuration (env) from end-user-facing input variables (app_variables). Both live inside the top-level AgentSoulConfig JSON snapshot.
Dual-Variable Architecture#
env β Operator Environment Configuration#
AgentSoulEnvConfig holds two lists:
| Field | Type | Purpose |
|---|---|---|
variables | list[AgentEnvVariableConfig] | Plaintext key-value pairs injected as shell env vars |
secret_refs | list[AgentSecretRefConfig] | Sensitive values: either an inline user-provided string or a reference to a backend-managed credential |
AgentEnvVariableConfig carries name, key, env_name, variable, type, value, default, and required. The various name/key aliases exist for backward compatibility.
AgentSecretRefConfig adds id, ref, credential_id, provider_credential_id, and provider to support backend-managed credential lookups. Secret values are never stored in the config snapshot; a reference ID is stored instead, and the actual value is resolved at runtime.
CLI tools can also carry their own scoped environment via AgentCliToolEnvConfig, which wraps the same variables / secret_refs lists per tool.
app_variables β User Input Variables#
AppVariableConfig defines typed, user-facing input slots presented to the end-user at chat time:
name: str # displayed label and variable reference key
type: str # textInput, paragraph, select, number, json, etc.
required: bool
default: Any
These become the user_input_form rendered before a conversation starts and are mapped to InputForm objects for the preview UI via getAgentSoulInputsForm.
Frontend Store & Conversion#
The frontend models both variable types as a unified EnvVariable record:
type EnvScope = 'secret' | 'plain'
type EnvVariable = { id: string; key: string; value: string; scope: EnvScope; masked?: boolean }
Jotai atoms in store-modules/env.ts expose agentComposerEnvVariablesAtom plus individual setter atoms (setEnvVariableKeyAtom, setEnvVariableScopeAtom, setEnvVariableValueAtom, addEnvVariableAtom, importEnvVariablesAtom, removeEnvVariableAtom).
The bidirectional conversion between the backend schema and this flat array lives in conversions.ts:
- Backend β Frontend:
toEnvVariableFormState()mapsenv.variablesβscope: 'plain'andenv.secret_refsβscope: 'secret', masked: true. - Frontend β Backend:
toEnvConfig()splits the array back onscopeto repopulatevariablesandsecret_refs.
Environment Variables Editor UI#
The AgentEnvEditor component renders a table-style editor in the Advanced Settings panel of the agent configure view. Key behaviors:
- Column layout: KEY | VALUE | DELETE
- Plain text only: Environment variables are stored and displayed as plain text. The scope selection (plain/secret) and secret masking features are behind a disabled feature flag (
ENABLE_AGENT_SECRET_ENV_VARIABLES = false) and are not visible in the UI. .envfile import: A hidden<input type="file">triggersparseEnvImport(), which parses standard dotenv syntax (quoted values,exportprefixes, inline#comments, escape sequences). Invalid lines are counted and toasted as an error; valid entries are appended withscope: 'plain'by default .- Key validation: Spaces are auto-replaced with underscores; keys must pass the
checkKeys()validator .
Runtime Flow: env β Shell Layer#
At run time, AgentSoulConfig.env is converted to DifyShellLayerConfig and sent to the dify-agent backend:
- Plain variables and inline secrets β
DifyShellEnvVarConfig(name + value, ephemeral, not persisted to workspace) - Backend-managed secret refs (no inline value) β
DifyShellSecretRefConfig(name + ref ID; actual value resolved by the backend)
The split prevents secret values from travelling as plaintext in run requests. CLI tool-scoped env and secret_refs undergo the same transformation independently .
Comparison: Legacy ConfigVar vs. Agent V2 Variables#
| Dimension | Legacy ConfigVar (chatbot / completion apps) | Agent V2 env + app_variables |
|---|---|---|
| Component | config-var/index.tsx | orchestrate/advanced/env.tsx |
| Schema | PromptVariable (key, name, type, required, options, config) | AgentEnvVariableConfig / AgentSecretRefConfig + AppVariableConfig |
| Scope separation | None β all variables are user-facing | env = operator config; app_variables = user inputs |
| Secret masking | Not supported | Backend supports masked: true + reveal toggle for scope: 'secret', but UI hidden behind disabled feature flag |
| Import | Not supported | .env file upload |
| Runtime target | Injected into prompt template | Injected as shell env vars into the dify-agent shell layer |
| Storage | Flat PromptVariable[] in app config | Inside AgentSoulConfig JSON snapshot (AgentConfigVersion.config_snapshot) |
The legacy ConfigVar component is still used by non-V2 chat and completion app configuration (see config/index.tsx). Agent V2 agents do not use it.
Key Source Files#
| File | Role |
|---|---|
api/models/agent_config_entities.py | Pydantic DTOs: AgentEnvVariableConfig, AgentSecretRefConfig, AgentCliToolEnvConfig, AgentSoulEnvConfig, AppVariableConfig |
web/features/agent-v2/agent-composer/form-state.ts | EnvScope and EnvVariable TypeScript types |
web/features/agent-v2/agent-composer/store-modules/env.ts | Jotai atoms for env variable state management |
web/features/agent-v2/agent-composer/conversions.ts | toEnvVariableFormState() / toEnvConfig() round-trip converters |
web/features/agent-v2/agent-detail/configure/components/orchestrate/advanced/env.tsx | AgentEnvEditor UI component |
web/features/agent-v2/agent-detail/configure/components/orchestrate/advanced/env-utils.ts | .env file parse logic (parseEnvImport) |
web/features/agent-v2/agent-detail/configure/components/preview/chat-config.ts | Maps app_variables β chat preview InputForm |
web/app/components/app/configuration/config-var/index.tsx | Legacy ConfigVar (non-V2 apps only) |