feat: Workflow-Level Credential Override for Model Providers
[!IMPORTANT]
- Make sure you have read our contribution guidelines
- Ensure there is an associated issue and you have been assigned to it
- Use the correct syntax to link this PR:
Fixes #<issue number>.
Summary
fix issue #28815 enable llm node can have a api key config instead of using global api key config
Screenshots
before
after
test result
using default api key
using select api key
knowledge node
parameter extractor node
Checklist
- [ ] This change requires a documentation update, included: Dify Document
- [x] I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
- [x] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
- [x] I've updated the documentation accordingly.
- [x] I ran
dev/reformat(backend) andcd web && npx lint-staged(frontend) to appease the lint gods
[!WARNING] You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!
Thanks for working on this feature! I opened the original issue #28815 and have been exploring implementations as well.
Feedback on the Implementation
What I Like
- Unit tests: Great test coverage for the credential override logic
- Flexible data structure: Supporting both
credential_idandcredential_nameis useful - Graceful fallback: The error handling that falls back to default credentials is robust
- Inline token support: Treating unknown IDs as raw tokens is clever for quick testing
UI Improvement Suggestion
The current text input approach requires users to manually type or paste credential IDs:
<input
type='text'
placeholder={t(`${i18nPrefix}.credentialIdPlaceholder`)}
value={inputs.model?.credential_override?.credential_id || ''}
...
/>
This has some UX challenges:
- Users must know what credentials are available
- No validation until runtime (typos won't be caught)
- Credential IDs are UUIDs which are hard to remember/type
Suggested improvement: A dropdown selector that fetches available credentials from the provider:
// Fetch available credentials from the model provider
const { data: modelProviders } = useModelProviders()
const availableCredentials = modelProviders
?.find(p => p.provider === model?.provider)
?.custom_configuration?.available_credentials || []
// Render as dropdown
<select value={credentialId} onChange={handleChange}>
<option value="">Default (workspace credential)</option>
{availableCredentials.map(cred => (
<option key={cred.credential_id} value={cred.credential_id}>
{cred.credential_name}
</option>
))}
</select>
This approach:
- Shows users what credentials are actually available
- Validates selection before runtime
- Better matches Dify's existing UI patterns (model selector, etc.)
- Could still support manual input as a fallback for power users
Minor Suggestions
-
i18n: The hardcoded strings like
t('CredentialOverride')andt('override the credential')might need proper translation keys in the workflow translation files -
Styling: The input uses inline Tailwind classes that don't match Dify's component library patterns. Consider using existing components like the
Selectorfromnodes/_base/components/selector.tsx
Overall, great work on the backend logic and tests! The dropdown UI would make this feature much more user-friendly.
Thanks for working on this feature! I opened the original issue #28815 and have been exploring implementations as well.
Feedback on the Implementation
What I Like
- Unit tests: Great test coverage for the credential override logic
- Flexible data structure: Supporting both
credential_idandcredential_nameis useful- Graceful fallback: The error handling that falls back to default credentials is robust
- Inline token support: Treating unknown IDs as raw tokens is clever for quick testing
UI Improvement Suggestion
The current text input approach requires users to manually type or paste credential IDs:
<input type='text' placeholder={t(`${i18nPrefix}.credentialIdPlaceholder`)} value={inputs.model?.credential_override?.credential_id || ''} ... />This has some UX challenges:
- Users must know what credentials are available
- No validation until runtime (typos won't be caught)
- Credential IDs are UUIDs which are hard to remember/type
Suggested improvement: A dropdown selector that fetches available credentials from the provider:
// Fetch available credentials from the model provider const { data: modelProviders } = useModelProviders() const availableCredentials = modelProviders ?.find(p => p.provider === model?.provider) ?.custom_configuration?.available_credentials || [] // Render as dropdown <select value={credentialId} onChange={handleChange}> <option value="">Default (workspace credential)</option> {availableCredentials.map(cred => ( <option key={cred.credential_id} value={cred.credential_id}> {cred.credential_name} </option> ))} </select>This approach:
- Shows users what credentials are actually available
- Validates selection before runtime
- Better matches Dify's existing UI patterns (model selector, etc.)
- Could still support manual input as a fallback for power users
Minor Suggestions
- i18n: The hardcoded strings like
t('CredentialOverride')andt('override the credential')might need proper translation keys in the workflow translation files- Styling: The input uses inline Tailwind classes that don't match Dify's component library patterns. Consider using existing components like the
Selectorfromnodes/_base/components/selector.tsxOverall, great work on the backend logic and tests! The dropdown UI would make this feature much more user-friendly.
done, change to select option
Can you add an option to either select a pre-configured key or use a text box to enter a custom key? This key could be passed as a parameter, so that the new WebHook trigger can also accept a key, making it easier for callers to use their own models.