Skip to content

Commit e173db5

Browse files
committed
ai-constructs: add support for cross-region inference system profiles
1 parent 7d1415e commit e173db5

File tree

3 files changed

+194
-6
lines changed

3 files changed

+194
-6
lines changed

.changeset/blue-waves-travel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@aws-amplify/ai-constructs': minor
3+
---
4+
5+
add support for bedrock system cross-region inference profiles

packages/ai-constructs/src/conversation/conversation_handler_construct.test.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,4 +414,145 @@ void describe('Conversation Handler Function construct', () => {
414414
});
415415
});
416416
});
417+
418+
void describe('cross-region models', () => {
419+
void it('creates handler with access to eu cross-region models and inference profiles', () => {
420+
const app = new App();
421+
const stack = new Stack(app, 'TestStack', {
422+
env: { region: 'eu-west-1' },
423+
});
424+
new ConversationHandlerFunction(stack, 'conversationHandler', {
425+
models: [
426+
{
427+
modelId: 'eu.anthropic.claude-3-sonnet',
428+
},
429+
],
430+
});
431+
432+
const template = Template.fromStack(stack);
433+
template.hasResourceProperties('AWS::IAM::Policy', {
434+
PolicyDocument: {
435+
Statement: [
436+
{
437+
Action: [
438+
'bedrock:InvokeModel',
439+
'bedrock:InvokeModelWithResponseStream',
440+
],
441+
Effect: 'Allow',
442+
Resource: [
443+
{
444+
'Fn::Join': [
445+
'',
446+
[
447+
'arn:aws:bedrock:eu-west-1:',
448+
{
449+
Ref: 'AWS::AccountId',
450+
},
451+
':inference-profile/eu.anthropic.claude-3-sonnet',
452+
],
453+
],
454+
},
455+
'arn:aws:bedrock:eu-west-1::foundation-model/anthropic.claude-3-sonnet',
456+
'arn:aws:bedrock:eu-west-3::foundation-model/anthropic.claude-3-sonnet',
457+
'arn:aws:bedrock:eu-central-1::foundation-model/anthropic.claude-3-sonnet',
458+
],
459+
},
460+
],
461+
},
462+
});
463+
});
464+
465+
void it('creates handler with access to us cross-region models and inference profiles', () => {
466+
const app = new App();
467+
const stack = new Stack(app, 'TestStack', {
468+
env: { region: 'us-east-1' },
469+
});
470+
new ConversationHandlerFunction(stack, 'conversationHandler', {
471+
models: [
472+
{
473+
modelId: 'us.anthropic.claude-3-sonnet',
474+
},
475+
],
476+
});
477+
478+
const template = Template.fromStack(stack);
479+
template.hasResourceProperties('AWS::IAM::Policy', {
480+
PolicyDocument: {
481+
Statement: [
482+
{
483+
Action: [
484+
'bedrock:InvokeModel',
485+
'bedrock:InvokeModelWithResponseStream',
486+
],
487+
Effect: 'Allow',
488+
Resource: [
489+
{
490+
'Fn::Join': [
491+
'',
492+
[
493+
'arn:aws:bedrock:us-east-1:',
494+
{
495+
Ref: 'AWS::AccountId',
496+
},
497+
':inference-profile/us.anthropic.claude-3-sonnet',
498+
],
499+
],
500+
},
501+
'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet',
502+
'arn:aws:bedrock:us-east-2::foundation-model/anthropic.claude-3-sonnet',
503+
'arn:aws:bedrock:us-west-2::foundation-model/anthropic.claude-3-sonnet',
504+
],
505+
},
506+
],
507+
},
508+
});
509+
});
510+
511+
void it('creates handler with access to apac cross-region models and inference profiles', () => {
512+
const app = new App();
513+
const stack = new Stack(app, 'TestStack', {
514+
env: { region: 'ap-northeast-1' },
515+
});
516+
new ConversationHandlerFunction(stack, 'conversationHandler', {
517+
models: [
518+
{
519+
modelId: 'apac.anthropic.claude-3-sonnet',
520+
},
521+
],
522+
});
523+
524+
const template = Template.fromStack(stack);
525+
template.hasResourceProperties('AWS::IAM::Policy', {
526+
PolicyDocument: {
527+
Statement: [
528+
{
529+
Action: [
530+
'bedrock:InvokeModel',
531+
'bedrock:InvokeModelWithResponseStream',
532+
],
533+
Effect: 'Allow',
534+
Resource: [
535+
{
536+
'Fn::Join': [
537+
'',
538+
[
539+
'arn:aws:bedrock:ap-northeast-1:',
540+
{
541+
Ref: 'AWS::AccountId',
542+
},
543+
':inference-profile/apac.anthropic.claude-3-sonnet',
544+
],
545+
],
546+
},
547+
'arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-sonnet',
548+
'arn:aws:bedrock:ap-northeast-2::foundation-model/anthropic.claude-3-sonnet',
549+
'arn:aws:bedrock:ap-southeast-1::foundation-model/anthropic.claude-3-sonnet',
550+
'arn:aws:bedrock:ap-southeast-2::foundation-model/anthropic.claude-3-sonnet',
551+
],
552+
},
553+
],
554+
},
555+
});
556+
});
557+
});
417558
});

packages/ai-constructs/src/conversation/conversation_handler_construct.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,7 @@ export class ConversationHandlerFunction
130130
);
131131

132132
if (this.props.models && this.props.models.length > 0) {
133-
const resources = this.props.models.map(
134-
(model) =>
135-
`arn:aws:bedrock:${
136-
model.region ?? Stack.of(this).region
137-
}::foundation-model/${model.modelId}`
138-
);
133+
const resources = this.generateIamPolicyResourceBlocks(this.props.models);
139134
conversationHandler.addToRolePolicy(
140135
new PolicyStatement({
141136
effect: Effect.ALLOW,
@@ -160,6 +155,53 @@ export class ConversationHandlerFunction
160155
this.storeOutput(this.props.outputStorageStrategy);
161156
}
162157

158+
private generateIamPolicyResourceBlocks = (
159+
models: { modelId: string; region?: string }[]
160+
): string[] => {
161+
const crossRegionInferenceProfileRegions: Record<string, string[]> = {
162+
'eu.': ['eu-west-1', 'eu-west-3', 'eu-central-1'],
163+
'us.': ['us-east-1', 'us-east-2', 'us-west-2'],
164+
'apac.': [
165+
'ap-northeast-1',
166+
'ap-northeast-2',
167+
'ap-southeast-1',
168+
'ap-southeast-2',
169+
],
170+
};
171+
const resourceBlocks = models.map((model) => {
172+
const region = model.region ?? Stack.of(this).region;
173+
const modelPrefix = Object.keys(crossRegionInferenceProfileRegions).find(
174+
(prefix) => model.modelId.startsWith(prefix)
175+
);
176+
177+
if (modelPrefix) {
178+
// For cross-region models, generate resource blocks for all supported regions
179+
const foundationModelResourceBlocks =
180+
crossRegionInferenceProfileRegions[modelPrefix].map(
181+
(region) =>
182+
`arn:aws:bedrock:${region}::foundation-model/${model.modelId.substring(
183+
modelPrefix.length
184+
)}`
185+
);
186+
187+
// For cross-region models, also generate inference profile resource blocks
188+
const inferenceProfileResourceBlock = `arn:aws:bedrock:${region}:${
189+
Stack.of(this).account
190+
}:inference-profile/${model.modelId}`;
191+
192+
return [
193+
inferenceProfileResourceBlock,
194+
...foundationModelResourceBlocks,
195+
];
196+
}
197+
198+
// For non-cross-region models, use the specified or stack region
199+
return [`arn:aws:bedrock:${region}::foundation-model/${model.modelId}`];
200+
});
201+
202+
return resourceBlocks.flat();
203+
};
204+
163205
/**
164206
* Append conversation handler to defined functions.
165207
*/

0 commit comments

Comments
 (0)