feat: support authType on AI providers for IAM role authentication (#19016)
## Summary - Adds an `authType` field (`'api_key' | 'access_key' | 'iam_role'`) to AI provider config - Providers like Amazon Bedrock that authenticate via IAM role (instance profile) can now be registered without explicit API keys or access keys - Backend: `isProviderConfigured()` checks `apiKey || accessKeyId || authType` - Frontend admin panel: shows green "Configured" badge and "IAM role" description for providers with `authType: "iam_role"` - Provider detail page shows "IAM role (instance profile)" in the credentials row ## Companion PR - twentyhq/twenty-infra#528 — patches `authType: "iam_role"` into dev/staging Bedrock catalogs ## Changed files - **Backend**: new `AiProviderAuthType` type, `isProviderConfigured` util, updated registry + resolver - **Frontend**: new `AiProviderAuthType` type, updated provider list card + detail page ## Test plan - [ ] Deploy with a Bedrock catalog that includes `"authType": "iam_role"` — verify Bedrock shows "Configured" in admin AI panel - [ ] Verify OpenAI/Anthropic with `apiKey` still show "Configured" - [ ] Verify a provider with no credentials and no `authType` still shows "No credentials" Made with [Cursor](https://cursor.com)
This commit is contained in:
+7
-2
@@ -33,7 +33,9 @@ const getProviderDescription = (provider: AiProviderItem): string => {
|
||||
parts.push(provider.baseUrl);
|
||||
}
|
||||
|
||||
if (provider.apiKey) {
|
||||
if (provider.authType === 'role') {
|
||||
parts.push(t`IAM role`);
|
||||
} else if (provider.apiKey) {
|
||||
parts.push(t`API key configured`);
|
||||
} else if (provider.hasAccessKey) {
|
||||
parts.push(t`IAM credentials`);
|
||||
@@ -42,6 +44,9 @@ const getProviderDescription = (provider: AiProviderItem): string => {
|
||||
return parts.join(' · ');
|
||||
};
|
||||
|
||||
const isProviderConfigured = (provider: AiProviderItem): boolean =>
|
||||
!!(provider.authType || provider.apiKey || provider.hasAccessKey);
|
||||
|
||||
export const SettingsAdminAiProviderListCard = ({
|
||||
providers,
|
||||
showAddButton = true,
|
||||
@@ -70,7 +75,7 @@ export const SettingsAdminAiProviderListCard = ({
|
||||
getItemLabel={(provider) => provider.label ?? provider.id}
|
||||
getItemDescription={getProviderDescription}
|
||||
RowRightComponent={({ item: provider }) =>
|
||||
provider.apiKey || provider.hasAccessKey ? (
|
||||
isProviderConfigured(provider) ? (
|
||||
<Status color="green" text={t`Configured`} weight="medium" />
|
||||
) : (
|
||||
<Status color="orange" text={t`No credentials`} weight="medium" />
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export type AiProviderAuthType = 'key' | 'credentials' | 'role';
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type AiSdkPackage, type DataResidency } from 'twenty-shared/ai';
|
||||
|
||||
import { type AiProviderAuthType } from '@/settings/admin-panel/ai/types/AiProviderAuthType';
|
||||
import { type AiProviderSource } from '@/settings/admin-panel/ai/types/AiProviderSource';
|
||||
|
||||
// AiProviderItem = RawAiProviderConfig (from the backend's Record<string,
|
||||
@@ -11,6 +12,7 @@ export type AiProviderItem = {
|
||||
// Optional provider display/catalog name from config (not a model name; models use `models[].name` on the backend).
|
||||
name?: string;
|
||||
label?: string;
|
||||
authType?: AiProviderAuthType;
|
||||
source?: AiProviderSource;
|
||||
baseUrl?: string;
|
||||
region?: string;
|
||||
|
||||
Reference in New Issue
Block a user