fix(ai-models): use AWS provider chain for Bedrock IRSA auth (#19470)

## Summary
- `buildBedrockProvider` ignored `authType: "role"` and only honored
static `accessKeyId`/`secretAccessKey` pairs, so deployments relying on
IRSA (e.g. EKS pods with `AWS_WEB_IDENTITY_TOKEN_FILE` + `AWS_ROLE_ARN`)
had no way to authenticate — `@ai-sdk/amazon-bedrock` does not walk the
AWS default credential chain on its own.
- When `authType === 'role'`, wire `fromNodeProviderChain()` from
`@aws-sdk/credential-providers` (already a server dependency, used by
the S3 and logic-function drivers) into `createAmazonBedrock` so IRSA
and other ambient AWS credentials resolve correctly.
- The static-credentials path is unchanged for `authType !== 'role'`.

## Test plan
- [ ] Deploy a server pod with IRSA + an `ai-models-config` entry using
`"authType": "role"` and verify Bedrock calls succeed (no `Could not
load credentials from any providers` error).
- [ ] Verify static-credentials providers (`accessKeyId` +
`secretAccessKey`) still work as before.
- [ ] `npx nx lint:diff-with-main twenty-server` passes.
- [ ] `npx nx typecheck twenty-server` passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Félix Malfait
2026-04-08 22:54:35 +02:00
committed by GitHub
parent 6073bb6706
commit ffb6029c2d
@@ -10,6 +10,7 @@ import { createMistral } from '@ai-sdk/mistral';
import { createOpenAI, type OpenAIProvider } from '@ai-sdk/openai';
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { createXai } from '@ai-sdk/xai';
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { type LanguageModel } from 'ai';
import { type AiSdkPackage } from 'twenty-shared/ai';
@@ -131,9 +132,27 @@ export class SdkProviderFactoryService {
private buildBedrockProvider(
config: AiProviderConfig,
): AiSdkProviderInstance {
const region = config.region ?? 'us-east-1';
const useRoleCredentials = config.authType === 'role';
const awsCredentialProvider = useRoleCredentials
? fromNodeProviderChain({ clientConfig: { region } })
: undefined;
const provider = createAmazonBedrock({
region: config.region ?? 'us-east-1',
...(config.accessKeyId &&
region,
...(awsCredentialProvider && {
credentialProvider: async () => {
const credentials = await awsCredentialProvider();
return {
accessKeyId: credentials.accessKeyId,
secretAccessKey: credentials.secretAccessKey,
sessionToken: credentials.sessionToken,
};
},
}),
...(!useRoleCredentials &&
config.accessKeyId &&
config.secretAccessKey && {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,