From 97130bd7ffaacc3761322c62afe19059803d2bc8 Mon Sep 17 00:00:00 2001 From: Mitchell Valine Date: Mon, 11 Dec 2023 06:57:59 -0800 Subject: [PATCH 1/4] chore: CONTRIBUTING.md clarifications (#28314) Clarify some preferred strategies for our design process for contributors. Highlight readme driven development as the preferred route for new L2s in existing services and third party package publishing for anything else. Additionally remove the strict requirement of an RFC for any L2 contribution. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- CONTRIBUTING.md | 23 ++++++++++++--------- docs/NEW_CONSTRUCTS_GUIDE.md | 39 ++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c202b8ee980e..564695c76a0ec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,10 @@ This document describes how to set up a development environment and submit your let us know if it's not up-to-date (even better, submit a PR with your corrections ;-)). - [Where To Contribute](#where-to-contribute) + - [Demonstrating Value](#demonstrating-value) + - [Publishing Your Own Package](#publishing-your-own-package) + - [Trust and Third Party Packages](#trust-and-third-party-packages) + - [Third Party Package Administration](#third-party-package-administration) - [Getting Started](#getting-started) - [Local setup](#setup) - [Dev Container](#dev-container) @@ -99,7 +103,7 @@ Here are some things we look at when evaluating a contribution: 1. Signal - Is there a github issue, or possibly multiple related ones, that the contribution addresses. Do the issues have a lot of engagement, such as comments, +1 reactions, etc that indicate that many users are affected by it? 1. Size - Is the contribution limited to a relatively self-contained surface area? Is it broken up into the smallest possible unit of functionality that makes sense? 1. Priority - Does the contribution address an issue in, or add a new feature of, a service that has a high priority for coverage? These are generally core services most commonly used on AWS such as IAM, EC2, Lambda, and ECS. -1. Quality - Does the contribution take into account all of the guidance provided in our documentation regarding design patterns, test coverage, and best practices as it relates to code within the aws-cdk repository? Does it also make an effort to follow patterns commonly used within the aws-cdk repository and not deviate unecessarily from these conventions? +1. Quality - Does the contribution take into account all of the guidance provided in our documentation regarding [design patterns](./docs/DESIGN_GUIDELINES.md), test coverage, and best practices as it relates to code within the aws-cdk repository? Does it also make an effort to follow patterns commonly used within the aws-cdk repository and not deviate unecessarily from these conventions? 1. Breaking Changes - Does the contribution introduce any risk for breaking existing users applications? Specifically, does it require any code changes or can it trigger any resource replacement in cloudformation that would result in downtime? ### Demonstrating Value @@ -362,16 +366,15 @@ much more likely to give a PR for those issues prompt attention. ### Step 2: Design -In some cases, it is useful to seek feedback by iterating on a design document. This is useful -when you plan a big change or feature, or you want advice on what would be the best path forward. +In some cases, it is useful to seek feedback by iterating on a design document. This is useful when you plan a big change or feature, or you want advice on what would be the best path forward. -In many cases, the GitHub issue is sufficient for such discussions, and can be -sufficient to get clarity on what you plan to do. If the changes are -significant or intrusive to the existing CDK experience, and especially for a -brand new L2 construct implementation, please write an RFC in our [RFC -repository](https://github.com/aws/aws-cdk-rfcs) before jumping into the code -base. L2 construct implementation pull requests will not be reviewed without -linking an approved RFC. +In many cases, the comments section of the relevant Github issue is sufficent for such discussion, and can be a good place to socialize and get feedback on what you plan to do. If the changes are significant in scope, require a longer form medium to communicate, or you just want to ensure that the core team agrees with your planned implementation before you submit it for review to avoid wasted work, there are a few different strategies you can pursue. + +1. README driven development - This is the core team's preferred method for reviewing new APIs. Submit a draft PR with updates to the README for the package that you intend to change that clearly describes how the functionality will be used. For new L2s, include usage examples that cover common use cases and showcase the features of the API you're designing. The most important thing to consider for any feature is the public API and this will help to give a clear picture of what changes users can expect. +1. Write an [RFC](aws/aws-cdk-rfcs) - This is a process for discussing new functionality that is large in scope, may incur breaking changes, or may otherwise warrant discussion from multiple stakeholders on the core team or within the community. Spefically, it is a good place to discuss new features in the core CDK framework or the CLI that are unable to be decoupled from the core cdk codebase. +1. Publish a package - A separate package is the best place to demonstrate the value of new functionality that you believe should be included within the CDK core libraries. It not only illustrates a complete solution with it's entire API surface area available to review, it also proves that your design works! When publishing a package with the goal for eventual inclusion within aws-cdk-lib, make sure to follow our [design guidelines](./docs/DESIGN_GUIDELINES.md) wherever relevant. + +Performing any of the above processes helps us to ensure that expectations are clearly set before a contribution is made. We want to ensure that everyone is able to contribute to the CDK ecosystem effectively. If you make a contribution that is ultimately not merged by into aws-cdk-lib, but you believe it should be, we encourage you to keep pursuing it. The scope of the core framework is intentionally limited to ensure that we can effectively maintain it's surface area and ensure code quality and reliablity over the long term. However, new patterns may emerge in the ecosystem that clearly provide better solutions than those currently in aws-cdk-lib. If your solutions gains popularity within the community, and you want us to re-evaluate it's inclusion, reach out to us on cdk.dev or create a github issue with a feature request and references to your package. See [demonstrating value](#demonstrating-value) for more information. ### Step 3: Work your Magic diff --git a/docs/NEW_CONSTRUCTS_GUIDE.md b/docs/NEW_CONSTRUCTS_GUIDE.md index 307a748bf7f0d..63e3d217188de 100644 --- a/docs/NEW_CONSTRUCTS_GUIDE.md +++ b/docs/NEW_CONSTRUCTS_GUIDE.md @@ -11,8 +11,9 @@ If you wish to create new L2 (or potentially L3) constructs, this guide can help Users of the aws-cdk can use constructs from a number of packages within their application. `aws-cdk-lib` and/or any of the other constructs vended from npm, maven, pypi, nuget, or GitHub (for go) that are publicly available are indexed and searchable on [Construct Hub](constructs.dev). Anyone can create and publish new constructs that will be indexed on Construct Hub using repositories and packages that they own. However, if you believe your constructs should be part of the core aws construct library, here are some guidelines that they must adhere to. 1. They meet the definition of [L2 constructs](https://github.com/aws/aws-cdk/blob/e4fdb0217edd7ecccdd4cbc20de958e3ba1a2349/docs/DESIGN_GUIDELINES.md?plain=1#L139-L147) -2. They follow the relevant [design guidelines](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) -3. They can follow the aws-cdk's versioning and release strategy, ie: if they are to be vended in aws-cdk-lib they must be stable or instead be vended in an `-alpha` package. +1. They follow the relevant [design guidelines](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) +1. They can follow the aws-cdk's versioning and release strategy, ie: if they are to be vended in aws-cdk-lib they must be stable or instead be vended in an `-alpha` package. +1. They provide constructs for a service that intersect with core aws usage patterns. For example, IAM, Lambda, EC2, DynamoDB, RDS, etc. 100% L2 coverage of every AWS service is not a goal of aws-cdk-lib. If your constructs do not meet these guidelines, see the [publishing your own package](#publishing-your-own-package) section of this guide, otherwise, you may choose to [publish your own package](#publishing-your-own-package) or [open a PR to aws-cdk-lib](#open-a-pr-to-aws-cdk-lib). @@ -22,22 +23,21 @@ Whether you want to pursue inclusion of your new constructs in aws-cdk-lib or no To get started creating your own construct package, we recommend using [`projen`](https://github.com/projen/projen). Additionally you can follow [this guide](https://dev.to/aws-builders/a-beginner-s-guide-to-create-aws-cdk-construct-library-with-projen-5eh4) which will help you setup your repository, packages and tooling step by step. -Once your constructs have been published for some time and you feel that the apis are stable and bugs have been identified, you can continue to distribute it as a separate package and/or attempt to add them to `aws-cdk-lib` via a PR +Once your constructs have been published for some time and you feel that the apis are stable and bugs have been identified, you can continue to distribute it as a separate package and/or attempt to add them to `aws-cdk-lib` via a PR. ## Open a PR to `aws-cdk-lib` You can [create a PR](https://github.com/aws/aws-cdk/compare) in the `aws/aws-cdk` repository with your constructs at any time if you believe they are ready for inclusion. Here are some cases where opening a PR directly without publishing your own package first is ideal. 1. It is a small addition to a service that has had stable L2 constructs for some time -2. The service usage is well known and the API is unlikely to change. -3. The defaults provided by the L2 are well known best practice +1. The service usage is well known and the API is unlikely to change. +1. The defaults provided by the L2 are well known best practice -If any of the above are true and your constructs adhere to [the relevant guidelines](#do-my-constructs-belong-in-aws-cdk-lib), we encourage you to follow the [contributing guide](../CONTRIBUTING.md) and create a new pull request. Since the bandwidth of the aws-cdk team is limited, reviews and iteration may take some time. Additionally pull requests for new constructs are more likely to be accepted if they have any of the following: +If all of the above are true and your constructs adhere to [the relevant guidelines](#do-my-constructs-belong-in-aws-cdk-lib), we encourage you to follow the [contributing guide](../CONTRIBUTING.md) and create a new pull request. Specifically, see the section on within the [Design](../CONTRIBUTING.md#step-2-design) section. Since the bandwidth of the aws-cdk team is limited, reviews and iteration may take some time. Additionally pull requests for new constructs are more likely to be accepted if they have any of the following: -1. An [RFC](https://github.com/aws/aws-cdk-rfcs) with detailed design that has been reviewed by a member of AWS -2. An existing package with users who have used and tested the Constructs and provided feedback -3. Strong documentation -4. Good unit and integration test coverage +1. An existing package with users who have used and tested the Constructs and provided feedback +1. Strong documentation +1. Good unit and integration test coverage ## New Construct Development lifecycle @@ -47,16 +47,15 @@ Whether publishing your own package or making a PR against aws-cdk-lib immediate ### Self Publishing 1. Publish: design, write, and publish your new constructs -2. Iterate: respond to issues from users, fix bugs, optimize usage patterns and gain consensus -3. Stabilize: settle on the api - +1. Iterate: respond to issues from users, fix bugs, optimize usage patterns and gain consensus +1. Stabilize: settle on the api *Optionally* -4. Upstream: open a PR to aws-cdk-lib to include if still relevant +1. Upstream: open a PR to aws-cdk-lib to include if still relevant ### Alpha CDK Package -1. Design: create an [rfc](http://github.com/aws/aws-cdk-rfcs), socialize, and gain consensus -2. Implement: write the construct as designed and create a new pull requests -3. Iterate: respond to feedback from pull request reviewers on the aws-cdk team -4. Publish: publish your new constructs as an alpha module -5. Iterate: respond to issues from users, fix bugs and optimize usage patterns -6. Stabilize: settle on the api and create a new PR migrating all constructs stability to "stable" +1. Design: create a draft PR with the new README detailing the API, socialize, and gain consensus +1. Implement: write the construct as designed and create a new pull requests +1. Iterate: respond to feedback from pull request reviewers on the aws-cdk team +1. Publish: publish your new constructs as an alpha module +1. Iterate: respond to issues from users, fix bugs and optimize usage patterns +1. Stabilize: settle on the api and create a new PR migrating all constructs stability to "stable" From 2af78638aa113fb2b68f32e8b393c1ab3fd6716a Mon Sep 17 00:00:00 2001 From: Masashi Tomooka Date: Tue, 12 Dec 2023 00:24:29 +0900 Subject: [PATCH 2/4] docs(apigateway): set integrationHttpMethod for vpc link integration (#28299) As written in #6404, a VPC link integration fails to deploy unless we set `integrationHttpMethod` prop explicitly. In this PR we fix the sample code accordingly. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk-lib/aws-apigateway/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/aws-cdk-lib/aws-apigateway/README.md b/packages/aws-cdk-lib/aws-apigateway/README.md index fc3af88c46443..2a6be5ad2b12a 100644 --- a/packages/aws-cdk-lib/aws-apigateway/README.md +++ b/packages/aws-cdk-lib/aws-apigateway/README.md @@ -1453,6 +1453,7 @@ const link = new apigateway.VpcLink(this, 'link', { const integration = new apigateway.Integration({ type: apigateway.IntegrationType.HTTP_PROXY, + integrationHttpMethod: 'ANY', options: { connectionType: apigateway.ConnectionType.VPC_LINK, vpcLink: link, From 15c7bb2908cff1ab8bebacacc09f26bbab6ec391 Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:31:49 -0800 Subject: [PATCH 3/4] feat: update AWS Service Spec (#28328) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update AWS Service Spec packages to latest versions **@aws-cdk/aws-service-spec changes:** ``` ├[~] service aws-autoscaling │ └ resources │ ├[~] resource AWS::AutoScaling::AutoScalingGroup │ │ └ types │ │ └[~] type InstanceRequirements │ │ └ properties │ │ ├ MemoryMiB: - MemoryMiBRequest │ │ │ + MemoryMiBRequest (required) │ │ └ VCpuCount: - VCpuCountRequest │ │ + VCpuCountRequest (required) │ └[~] resource AWS::AutoScaling::ScalingPolicy │ └ types │ └[~] type MetricStat │ └ - documentation: `MetricStat` is a property of the [AWS::AutoScaling::ScalingPolicy MetricDataQuery](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html) property type. │ This structure defines the CloudWatch metric to return, along with the statistic, period, and unit. │ For more information about the CloudWatch terminology below, see [Amazon CloudWatch concepts](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html) in the *Amazon CloudWatch User Guide* . │ + documentation: `MetricStat` is a property of the [AWS::AutoScaling::ScalingPolicy MetricDataQuery](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html) property type. │ This structure defines the CloudWatch metric to return, along with the statistic and unit. │ For more information about the CloudWatch terminology below, see [Amazon CloudWatch concepts](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html) in the *Amazon CloudWatch User Guide* . ├[~] service aws-billingconductor │ └ resources │ └[~] resource AWS::BillingConductor::CustomLineItem │ └ properties │ └[+] AccountId: string (immutable) ├[~] service aws-cleanrooms │ └ resources │ ├[~] resource AWS::CleanRooms::Collaboration │ │ ├ properties │ │ │ └ CreatorPaymentConfiguration: (documentation changed) │ │ └ types │ │ ├[~] type MemberSpecification │ │ │ └ properties │ │ │ └ PaymentConfiguration: (documentation changed) │ │ ├[~] type PaymentConfiguration │ │ │ ├ - documentation: undefined │ │ │ │ + documentation: An object representing the collaboration member's payment responsibilities set by the collaboration creator. │ │ │ └ properties │ │ │ └ QueryCompute: (documentation changed) │ │ └[~] type QueryComputePaymentConfig │ │ ├ - documentation: undefined │ │ │ + documentation: An object representing the collaboration member's payment responsibilities set by the collaboration creator for query compute costs. │ │ └ properties │ │ └ IsResponsible: (documentation changed) │ └[~] resource AWS::CleanRooms::Membership │ ├ properties │ │ └ PaymentConfiguration: (documentation changed) │ └ types │ ├[~] type MembershipPaymentConfiguration │ │ ├ - documentation: undefined │ │ │ + documentation: An object representing the payment responsibilities accepted by the collaboration member. │ │ └ properties │ │ └ QueryCompute: (documentation changed) │ └[~] type MembershipQueryComputePaymentConfig │ ├ - documentation: undefined │ │ + documentation: An object representing the payment responsibilities accepted by the collaboration member for query compute costs. │ └ properties │ └ IsResponsible: (documentation changed) ├[~] service aws-cloudformation │ └ resources │ └[~] resource AWS::CloudFormation::StackSet │ └ types │ └[~] type OperationPreferences │ └ properties │ └ RegionOrder: (documentation changed) ├[~] service aws-cloudtrail │ └ resources │ └[~] resource AWS::CloudTrail::EventDataStore │ └ properties │ ├[+] FederationEnabled: boolean │ └[+] FederationRoleArn: string ├[~] service aws-codedeploy │ └ resources │ └[~] resource AWS::CodeDeploy::DeploymentConfig │ ├ - documentation: The `AWS::CodeDeploy::DeploymentConfig` resource creates a set of deployment rules, deployment success conditions, and deployment failure conditions that AWS CodeDeploy uses during a deployment. The deployment configuration specifies, through the use of a `MinimumHealthyHosts` value, the number or percentage of instances that must remain available at any time during a deployment. │ │ + documentation: The `AWS::CodeDeploy::DeploymentConfig` resource creates a set of deployment rules, deployment success conditions, and deployment failure conditions that AWS CodeDeploy uses during a deployment. The deployment configuration specifies the number or percentage of instances that must remain available at any time during a deployment. │ ├ properties │ │ └[+] ZonalConfig: ZonalConfig (immutable) │ └ types │ ├[+] type MinimumHealthyHostsPerZone │ │ ├ name: MinimumHealthyHostsPerZone │ │ └ properties │ │ ├Value: integer (required) │ │ └Type: string (required) │ └[+] type ZonalConfig │ ├ name: ZonalConfig │ └ properties │ ├FirstZoneMonitorDurationInSeconds: integer │ ├MonitorDurationInSeconds: integer │ └MinimumHealthyHostsPerZone: MinimumHealthyHostsPerZone ├[~] service aws-connect │ └ resources │ └[~] resource AWS::Connect::Instance │ ├ - tagInformation: undefined │ │ + tagInformation: {"tagPropertyName":"Tags","variant":"standard"} │ └ properties │ └[+] Tags: Array ├[~] service aws-dlm │ └ resources │ └[~] resource AWS::DLM::LifecyclePolicy │ ├ properties │ │ └ DefaultPolicy: (documentation changed) │ └ types │ └[~] type PolicyDetails │ └ properties │ └ PolicyType: (documentation changed) ├[~] service aws-dms │ └ resources │ ├[+] resource AWS::DMS::DataProvider │ │ ├ name: DataProvider │ │ │ cloudFormationType: AWS::DMS::DataProvider │ │ │ documentation: Resource schema for AWS::DMS::DataProvider │ │ │ tagInformation: {"tagPropertyName":"Tags","variant":"standard"} │ │ ├ properties │ │ │ ├DataProviderName: string │ │ │ ├DataProviderIdentifier: string │ │ │ ├Description: string │ │ │ ├Engine: string (required) │ │ │ ├ExactSettings: boolean (default=false) │ │ │ ├Settings: Settings │ │ │ └Tags: Array │ │ ├ attributes │ │ │ ├DataProviderArn: string │ │ │ └DataProviderCreationTime: string │ │ └ types │ │ ├type Settings │ │ │├ documentation: PostgreSqlSettings property identifier. │ │ ││ name: Settings │ │ │└ properties │ │ │ └PostgreSqlSettings: PostgreSqlSettings │ │ └type PostgreSqlSettings │ │ ├ name: PostgreSqlSettings │ │ └ properties │ │ ├ServerName: string │ │ ├Port: integer │ │ ├DatabaseName: string │ │ ├SslMode: string │ │ └CertificateArn: string │ ├[+] resource AWS::DMS::InstanceProfile │ │ ├ name: InstanceProfile │ │ │ cloudFormationType: AWS::DMS::InstanceProfile │ │ │ documentation: Resource schema for AWS::DMS::InstanceProfile. │ │ │ tagInformation: {"tagPropertyName":"Tags","variant":"standard"} │ │ ├ properties │ │ │ ├InstanceProfileIdentifier: string │ │ │ ├AvailabilityZone: string │ │ │ ├Description: string │ │ │ ├KmsKeyArn: string │ │ │ ├PubliclyAccessible: boolean (default=false) │ │ │ ├NetworkType: string │ │ │ ├InstanceProfileName: string │ │ │ ├SubnetGroupIdentifier: string │ │ │ ├VpcSecurityGroups: Array │ │ │ └Tags: Array │ │ └ attributes │ │ ├InstanceProfileArn: string │ │ └InstanceProfileCreationTime: string │ └[+] resource AWS::DMS::MigrationProject │ ├ name: MigrationProject │ │ cloudFormationType: AWS::DMS::MigrationProject │ │ documentation: Resource schema for AWS::DMS::MigrationProject │ │ tagInformation: {"tagPropertyName":"Tags","variant":"standard"} │ ├ properties │ │ ├MigrationProjectName: string │ │ ├MigrationProjectIdentifier: string │ │ ├MigrationProjectCreationTime: string (deprecated=WARN) │ │ ├InstanceProfileIdentifier: string │ │ ├InstanceProfileName: string │ │ ├InstanceProfileArn: string │ │ ├TransformationRules: string │ │ ├Description: string │ │ ├SchemaConversionApplicationAttributes: SchemaConversionApplicationAttributes │ │ ├SourceDataProviderDescriptors: Array │ │ ├TargetDataProviderDescriptors: Array │ │ └Tags: Array │ ├ attributes │ │ └MigrationProjectArn: string │ └ types │ ├type SchemaConversionApplicationAttributes │ │├ documentation: The property describes schema conversion application attributes for the migration project. │ ││ name: SchemaConversionApplicationAttributes │ │└ properties │ │ ├S3BucketPath: string │ │ └S3BucketRoleArn: string │ └type DataProviderDescriptor │ ├ documentation: It is an object that describes Source and Target DataProviders and credentials for connecting to databases that are used in MigrationProject │ │ name: DataProviderDescriptor │ └ properties │ ├DataProviderIdentifier: string │ ├DataProviderName: string │ ├DataProviderArn: string │ ├SecretsManagerSecretId: string │ └SecretsManagerAccessRoleArn: string ├[~] service aws-ec2 │ └ resources │ ├[~] resource AWS::EC2::EC2Fleet │ │ └ types │ │ └[~] type InstanceRequirementsRequest │ │ └ properties │ │ ├ AcceleratorManufacturers: (documentation changed) │ │ └ AcceleratorNames: (documentation changed) │ ├[~] resource AWS::EC2::LaunchTemplate │ │ └ types │ │ ├[~] type ConnectionTrackingSpecification │ │ │ ├ - documentation: Allows customer to specify Connection Tracking options │ │ │ │ + documentation: A security group connection tracking specification that enables you to set the idle timeout for connection tracking on an Elastic network interface. For more information, see [Connection tracking timeouts](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-connection-tracking.html#connection-tracking-timeouts) in the *Amazon Elastic Compute Cloud User Guide* . │ │ │ └ properties │ │ │ ├ TcpEstablishedTimeout: (documentation changed) │ │ │ ├ UdpStreamTimeout: (documentation changed) │ │ │ └ UdpTimeout: (documentation changed) │ │ ├[~] type InstanceRequirements │ │ │ └ properties │ │ │ ├ AcceleratorManufacturers: (documentation changed) │ │ │ └ AcceleratorNames: (documentation changed) │ │ └[~] type NetworkInterface │ │ └ properties │ │ ├ ConnectionTrackingSpecification: (documentation changed) │ │ └ EnaSrdSpecification: (documentation changed) │ ├[~] resource AWS::EC2::SpotFleet │ │ └ types │ │ └[~] type InstanceRequirementsRequest │ │ └ properties │ │ ├ AcceleratorManufacturers: (documentation changed) │ │ └ AcceleratorNames: (documentation changed) │ ├[~] resource AWS::EC2::Subnet │ │ └ properties │ │ ├ Ipv4NetmaskLength: (documentation changed) │ │ └ Ipv6NetmaskLength: (documentation changed) │ ├[~] resource AWS::EC2::TransitGateway │ │ └ attributes │ │ └ TransitGatewayArn: (documentation changed) │ └[~] resource AWS::EC2::VerifiedAccessTrustProvider │ └ types │ └[~] type DeviceOptions │ └ properties │ └[+] PublicSigningKeyUrl: string ├[~] service aws-ecs │ └ resources │ └[~] resource AWS::ECS::CapacityProvider │ └ types │ └[~] type AutoScalingGroupProvider │ └ properties │ └[+] ManagedDraining: string ├[~] service aws-efs │ └ resources │ └[~] resource AWS::EFS::AccessPoint │ └ types │ └[~] type RootDirectory │ └ - documentation: Specifies the directory on the Amazon EFS file system that the access point provides access to. The access point exposes the specified file system path as the root directory of your file system to applications using the access point. NFS clients using the access point can only access data in the access point's `RootDirectory` and it's subdirectories. │ + documentation: Specifies the directory on the Amazon EFS file system that the access point provides access to. The access point exposes the specified file system path as the root directory of your file system to applications using the access point. NFS clients using the access point can only access data in the access point's `RootDirectory` and its subdirectories. ├[~] service aws-emr │ └ resources │ └[~] resource AWS::EMR::Studio │ └ properties │ ├[+] EncryptionKeyArn: string (immutable) │ ├[+] IdcInstanceArn: string (immutable) │ ├[+] IdcUserAssignment: string (immutable) │ └[+] TrustedIdentityPropagationEnabled: boolean (immutable) ├[~] service aws-eventschemas │ └ resources │ ├[~] resource AWS::EventSchemas::Discoverer │ │ └ attributes │ │ └ State: (documentation changed) │ └[~] resource AWS::EventSchemas::Registry ├[~] service aws-fis │ └ resources │ ├[~] resource AWS::FIS::ExperimentTemplate │ │ ├ - documentation: Specifies an experiment template. │ │ │ An experiment template includes the following components: │ │ │ - *Targets* : A target can be a specific resource in your AWS environment, or one or more resources that match criteria that you specify, for example, resources that have specific tags. │ │ │ - *Actions* : The actions to carry out on the target. You can specify multiple actions, the duration of each action, and when to start each action during an experiment. │ │ │ - *Stop conditions* : If a stop condition is triggered while an experiment is running, the experiment is automatically stopped. You can define a stop condition as a CloudWatch alarm. │ │ │ For more information, see [Experiment templates](https://docs.aws.amazon.com/fis/latest/userguide/experiment-templates.html) in the *AWS Fault Injection Simulator User Guide* . │ │ │ + documentation: Describes an experiment template. │ │ ├ properties │ │ │ └[+] ExperimentOptions: ExperimentTemplateExperimentOptions │ │ ├ attributes │ │ │ └ Id: (documentation changed) │ │ └ types │ │ ├[~] type ExperimentTemplateAction │ │ │ └ - documentation: Specifies an action for an experiment template. │ │ │ For more information, see [Actions](https://docs.aws.amazon.com/fis/latest/userguide/actions.html) in the *AWS Fault Injection Simulator User Guide* . │ │ │ + documentation: Describes an action for an experiment template. │ │ ├[+] type ExperimentTemplateExperimentOptions │ │ │ ├ documentation: Describes the experiment options for an experiment template. │ │ │ │ name: ExperimentTemplateExperimentOptions │ │ │ └ properties │ │ │ ├AccountTargeting: string │ │ │ └EmptyTargetResolutionMode: string │ │ ├[~] type ExperimentTemplateLogConfiguration │ │ │ ├ - documentation: Specifies the configuration for experiment logging. │ │ │ │ For more information, see [Experiment logging](https://docs.aws.amazon.com/fis/latest/userguide/monitoring-logging.html) in the *AWS Fault Injection Simulator User Guide* . │ │ │ │ + documentation: Describes the configuration for experiment logging. │ │ │ └ properties │ │ │ ├ CloudWatchLogsConfiguration: (documentation changed) │ │ │ └ S3Configuration: (documentation changed) │ │ ├[~] type ExperimentTemplateStopCondition │ │ │ └ - documentation: Specifies a stop condition for an experiment template. │ │ │ For more information, see [Stop conditions](https://docs.aws.amazon.com/fis/latest/userguide/stop-conditions.html) in the *AWS Fault Injection Simulator User Guide* . │ │ │ + documentation: Describes a stop condition for an experiment template. │ │ ├[~] type ExperimentTemplateTarget │ │ │ ├ - documentation: Specifies a target for an experiment. You must specify at least one Amazon Resource Name (ARN) or at least one resource tag. You cannot specify both ARNs and tags. │ │ │ │ For more information, see [Targets](https://docs.aws.amazon.com/fis/latest/userguide/targets.html) in the *AWS Fault Injection Simulator User Guide* . │ │ │ │ + documentation: Describes a target for an experiment template. │ │ │ └ properties │ │ │ └ Parameters: (documentation changed) │ │ └[~] type ExperimentTemplateTargetFilter │ │ └ - documentation: Specifies a filter used for the target resource input in an experiment template. │ │ For more information, see [Resource filters](https://docs.aws.amazon.com/fis/latest/userguide/targets.html#target-filters) in the *AWS Fault Injection Simulator User Guide* . │ │ + documentation: Describes a filter used for the target resources in an experiment template. │ └[+] resource AWS::FIS::TargetAccountConfiguration │ ├ name: TargetAccountConfiguration │ │ cloudFormationType: AWS::FIS::TargetAccountConfiguration │ │ documentation: Creates a target account configuration for the experiment template. A target account configuration is required when `accountTargeting` of `experimentOptions` is set to `multi-account` . For more information, see [experiment options](https://docs.aws.amazon.com/fis/latest/userguide/experiment-options.html) in the *AWS Fault Injection Simulator User Guide* . │ └ properties │ ├ExperimentTemplateId: string (required, immutable) │ ├AccountId: string (required, immutable) │ ├RoleArn: string (required) │ └Description: string ├[~] service aws-internetmonitor │ └ resources │ └[~] resource AWS::InternetMonitor::Monitor │ └ types │ ├[~] type InternetMeasurementsLogDelivery │ │ └ properties │ │ └ S3Config: (documentation changed) │ └[~] type S3Config │ ├ - documentation: The configuration for publishing Amazon CloudWatch Internet Monitor internet measurements to Amazon S3. The configuration includes the bucket name and (optionally) bucket prefix for the S3 bucket to store the measurements, and the delivery status. The delivery status is `ENABLED` if you choose to deliver internet measurements to S3 logs, and `DISABLED` otherwise. │ │ The measurements are also published to Amazon CloudWatch Logs. │ │ + documentation: The configuration for publishing Amazon CloudWatch Internet Monitor internet measurements to Amazon S3. The configuration includes the bucket name and (optionally) prefix for the S3 bucket to store the measurements, and the delivery status. The delivery status is `ENABLED` or `DISABLED` , depending on whether you choose to deliver internet measurements to S3 logs. │ └ properties │ ├ BucketName: (documentation changed) │ ├ BucketPrefix: (documentation changed) │ └ LogDeliveryStatus: (documentation changed) ├[~] service aws-lambda │ └ resources │ └[~] resource AWS::Lambda::Function │ └ properties │ └[-] Policy: json ├[~] service aws-lightsail │ └ resources │ └[~] resource AWS::Lightsail::Database │ └ properties │ └ BackupRetention: (documentation changed) ├[~] service aws-opensearchservice │ └ resources │ └[~] resource AWS::OpenSearchService::Domain │ ├ properties │ │ └[+] IPAddressType: string │ └ attributes │ └[+] DomainEndpointV2: string ├[~] service aws-osis │ └ resources │ └[~] resource AWS::OSIS::Pipeline │ ├ properties │ │ ├[+] BufferOptions: BufferOptions │ │ └[+] EncryptionAtRestOptions: EncryptionAtRestOptions │ └ types │ ├[+] type BufferOptions │ │ ├ documentation: Key-value pairs to configure buffering. │ │ │ name: BufferOptions │ │ └ properties │ │ └PersistentBufferEnabled: boolean (required) │ ├[~] type CloudWatchLogDestination │ │ └ properties │ │ └ LogGroup: - string │ │ + string (required) │ ├[+] type EncryptionAtRestOptions │ │ ├ documentation: Key-value pairs to configure encryption at rest. │ │ │ name: EncryptionAtRestOptions │ │ └ properties │ │ └KmsKeyArn: string (required) │ └[~] type VpcOptions │ └ properties │ └ SubnetIds: - Array │ + Array (required) ├[~] service aws-rds │ └ resources │ ├[~] resource AWS::RDS::DBInstance │ │ └ properties │ │ ├ AllocatedStorage: (documentation changed) │ │ ├ DBName: (documentation changed) │ │ ├ Domain: (documentation changed) │ │ ├ EnableCloudwatchLogsExports: (documentation changed) │ │ ├ Engine: (documentation changed) │ │ ├ EngineVersion: (documentation changed) │ │ ├ Iops: (documentation changed) │ │ ├ LicenseModel: (documentation changed) │ │ ├ MasterUsername: (documentation changed) │ │ ├ MasterUserPassword: (documentation changed) │ │ └ Port: (documentation changed) │ ├[~] resource AWS::RDS::DBParameterGroup │ │ └ properties │ │ └ Parameters: (documentation changed) │ └[~] resource AWS::RDS::DBProxy │ └ properties │ └ EngineFamily: (documentation changed) ├[~] service aws-resiliencehub │ └ resources │ └[~] resource AWS::ResilienceHub::App │ └ types │ └[~] type ResourceMapping │ └ properties │ ├ EksSourceName: (documentation changed) │ ├ LogicalStackName: (documentation changed) │ ├ MappingType: (documentation changed) │ ├ ResourceName: (documentation changed) │ └ TerraformSourceName: (documentation changed) ├[~] service aws-rolesanywhere │ └ resources │ ├[~] resource AWS::RolesAnywhere::Profile │ │ ├ - documentation: Creates a *profile* , a list of the roles that Roles Anywhere service is trusted to assume. You use profiles to intersect permissions with IAM managed policies. │ │ │ *Required permissions:* `rolesanywhere:CreateProfile` . │ │ │ + documentation: Creates a Profile. │ │ └ properties │ │ ├ DurationSeconds: (documentation changed) │ │ ├ Enabled: (documentation changed) │ │ ├ ManagedPolicyArns: (documentation changed) │ │ ├ Name: (documentation changed) │ │ ├ RequireInstanceProperties: (documentation changed) │ │ ├ RoleArns: (documentation changed) │ │ ├ SessionPolicy: (documentation changed) │ │ └ Tags: (documentation changed) │ └[~] resource AWS::RolesAnywhere::TrustAnchor │ ├ - documentation: Creates a trust anchor to establish trust between IAM Roles Anywhere and your certificate authority (CA). You can define a trust anchor as a reference to an AWS Private Certificate Authority ( AWS Private CA ) or by uploading a CA certificate. Your AWS workloads can authenticate with the trust anchor using certificates issued by the CA in exchange for temporary AWS credentials. │ │ *Required permissions:* `rolesanywhere:CreateTrustAnchor` . │ │ + documentation: Creates a TrustAnchor. │ └ types │ ├[~] type Source │ │ ├ - documentation: The trust anchor type and its related certificate data. │ │ │ + documentation: Object representing the TrustAnchor type and its related certificate data. │ │ └ properties │ │ ├ SourceData: (documentation changed) │ │ └ SourceType: (documentation changed) │ └[~] type SourceData │ └ - documentation: The data field of the trust anchor depending on its type. │ + documentation: A union object representing the data field of the TrustAnchor depending on its type ├[~] service aws-s3 │ └ resources │ └[~] resource AWS::S3::Bucket │ └ types │ └[~] type InventoryConfiguration │ └ properties │ ├ OptionalFields: (documentation changed) │ └ ScheduleFrequency: (documentation changed) ├[~] service aws-s3express │ └ resources │ └[~] resource AWS::S3Express::DirectoryBucket │ └ properties │ └ BucketName: (documentation changed) ├[~] service aws-sagemaker │ └ resources │ ├[~] resource AWS::SageMaker::FeatureGroup │ │ └ types │ │ └[~] type OnlineStoreConfig │ │ └ properties │ │ └[+] StorageType: string │ └[~] resource AWS::SageMaker::Model │ └ types │ ├[~] type ContainerDefinition │ │ └ properties │ │ └ ModelDataSource: (documentation changed) │ ├[~] type ModelDataSource │ │ ├ - documentation: undefined │ │ │ + documentation: Specifies the location of ML model data to deploy. If specified, you must specify one and only one of the available data sources. │ │ └ properties │ │ └ S3DataSource: (documentation changed) │ └[~] type S3DataSource │ ├ - documentation: undefined │ │ + documentation: Describes the S3 data source. │ │ Your input bucket must be in the same AWS region as your training job. │ └ properties │ ├ S3DataType: (documentation changed) │ └ S3Uri: (documentation changed) ├[~] service aws-sns │ └ resources │ └[~] resource AWS::SNS::Topic │ ├ properties │ │ └[+] DeliveryStatusLogging: Array │ └ types │ └[+] type LoggingConfig │ ├ name: LoggingConfig │ └ properties │ ├Protocol: string (required) │ ├SuccessFeedbackRoleArn: string │ ├SuccessFeedbackSampleRate: string │ └FailureFeedbackRoleArn: string └[~] service aws-workspacesthinclient └ resources └[~] resource AWS::WorkSpacesThinClient::Environment ├ - documentation: Resource type definition for AWS::WorkSpacesThinClient::Environment. │ + documentation: Describes an environment. ├ properties │ ├ DesktopArn: (documentation changed) │ ├ DesktopEndpoint: (documentation changed) │ ├ MaintenanceWindow: (documentation changed) │ └ Tags: (documentation changed) ├ attributes │ ├ ActivationCode: (documentation changed) │ ├ Arn: (documentation changed) │ ├ CreatedAt: (documentation changed) │ ├ DesktopType: (documentation changed) │ ├ RegisteredDevicesCount: (documentation changed) │ └ UpdatedAt: (documentation changed) └ types └[~] type MaintenanceWindow ├ - documentation: undefined │ + documentation: Describes the maintenance window for a thin client device. └ properties ├ ApplyTimeOf: (documentation changed) ├ DaysOfTheWeek: (documentation changed) ├ EndTimeHour: (documentation changed) ├ EndTimeMinute: (documentation changed) ├ StartTimeHour: (documentation changed) ├ StartTimeMinute: (documentation changed) └ Type: (documentation changed) ``` --- .../@aws-cdk/cloudformation-diff/package.json | 4 +-- packages/@aws-cdk/integ-runner/package.json | 2 +- .../aws-lambda/lib/function-hash.ts | 1 - packages/aws-cdk-lib/package.json | 2 +- tools/@aws-cdk/spec2cdk/package.json | 6 ++-- yarn.lock | 28 +++++++++---------- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index c97b0e3b77928..f518ea5e7a149 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -23,8 +23,8 @@ }, "license": "Apache-2.0", "dependencies": { - "@aws-cdk/aws-service-spec": "^0.0.34", - "@aws-cdk/service-spec-types": "^0.0.34", + "@aws-cdk/aws-service-spec": "^0.0.35", + "@aws-cdk/service-spec-types": "^0.0.35", "chalk": "^4", "diff": "^5.1.0", "fast-deep-equal": "^3.1.3", diff --git a/packages/@aws-cdk/integ-runner/package.json b/packages/@aws-cdk/integ-runner/package.json index 9d68652f35ff0..5e04182868c24 100644 --- a/packages/@aws-cdk/integ-runner/package.json +++ b/packages/@aws-cdk/integ-runner/package.json @@ -74,7 +74,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/aws-service-spec": "^0.0.34", + "@aws-cdk/aws-service-spec": "^0.0.35", "cdk-assets": "0.0.0", "@aws-cdk/cdk-cli-wrapper": "0.0.0", "aws-cdk": "0.0.0", diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function-hash.ts b/packages/aws-cdk-lib/aws-lambda/lib/function-hash.ts index 2e5d100116bc8..660d1c5f188b1 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function-hash.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function-hash.ts @@ -73,7 +73,6 @@ export const VERSION_LOCKED: { [key: string]: boolean } = { // not locked to the version CodeSigningConfigArn: false, - Policy: true, ReservedConcurrentExecutions: false, Tags: false, }; diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 3d7069027e068..8163c74978145 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -133,7 +133,7 @@ "yaml": "1.10.2" }, "devDependencies": { - "@aws-cdk/aws-service-spec": "^0.0.34", + "@aws-cdk/aws-service-spec": "^0.0.35", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/custom-resource-handlers": "0.0.0", "@aws-cdk/pkglint": "0.0.0", diff --git a/tools/@aws-cdk/spec2cdk/package.json b/tools/@aws-cdk/spec2cdk/package.json index e445807d3c301..a27c05f84c917 100644 --- a/tools/@aws-cdk/spec2cdk/package.json +++ b/tools/@aws-cdk/spec2cdk/package.json @@ -32,9 +32,9 @@ }, "license": "Apache-2.0", "dependencies": { - "@aws-cdk/aws-service-spec": "^0.0.34", - "@aws-cdk/service-spec-importers": "^0.0.10", - "@aws-cdk/service-spec-types": "^0.0.34", + "@aws-cdk/aws-service-spec": "^0.0.35", + "@aws-cdk/service-spec-importers": "^0.0.11", + "@aws-cdk/service-spec-types": "^0.0.35", "@cdklabs/tskb": "^0.0.3", "@cdklabs/typewriter": "^0.0.3", "camelcase": "^6", diff --git a/yarn.lock b/yarn.lock index 618912028d629..521b94f18df9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -56,12 +56,12 @@ resolved "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.0.1.tgz#6dc9b7cdb22ff622a7176141197962360c33e9ac" integrity sha512-DDt4SLdLOwWCjGtltH4VCST7hpOI5DzieuhGZsBpZ+AgJdSI2GCjklCXm0GCTwJG/SolkL5dtQXyUKgg9luBDg== -"@aws-cdk/aws-service-spec@^0.0.34": - version "0.0.34" - resolved "https://registry.npmjs.org/@aws-cdk/aws-service-spec/-/aws-service-spec-0.0.34.tgz#0c04646e76c995bfb520f380ed84411521c1562b" - integrity sha512-4M7SEhG05BmqXROKrXYyUFJR0dbE66feqo+lnyq/xNSfoJR6PMSRWpsOWvty8iy1Ih8N4tjKAW0Zbzw+Y8gG4A== +"@aws-cdk/aws-service-spec@^0.0.35": + version "0.0.35" + resolved "https://registry.npmjs.org/@aws-cdk/aws-service-spec/-/aws-service-spec-0.0.35.tgz#d6a225a5a306a595c6d51a920141337dd39a0407" + integrity sha512-75rNt8JBVMIv7iE/OfaYli5uVNXhzO/S5ExfXa8IgcXXykyMiYvTgBm7xPN85/pcqWvPIXP0C7ttsmF0JZYEng== dependencies: - "@aws-cdk/service-spec-types" "^0.0.34" + "@aws-cdk/service-spec-types" "^0.0.35" "@cdklabs/tskb" "^0.0.3" "@aws-cdk/lambda-layer-kubectl-v24@^2.0.242": @@ -69,12 +69,12 @@ resolved "https://registry.npmjs.org/@aws-cdk/lambda-layer-kubectl-v24/-/lambda-layer-kubectl-v24-2.0.242.tgz#4273a5ad7714f933a7eba155eb9280823086db71" integrity sha512-7/wIOo685tmrEe4hh6zqDELhBZh5OQGf3Hd2FU2Vnwy2ZubW8qTmEw5gqJCsCrGKeYDoa1BcVhDRZ/nzjkaqyA== -"@aws-cdk/service-spec-importers@^0.0.10": - version "0.0.10" - resolved "https://registry.npmjs.org/@aws-cdk/service-spec-importers/-/service-spec-importers-0.0.10.tgz#47dd42fccb1252eb4edfb9ca1f525fe0b28a0053" - integrity sha512-hQk7iEeD8B2fCz3XlmYUA3vysVojMazcoOZNa2J7cNkHbL0RZb3O8jxA9IswT6eQJX2ws89XXYu9Z9f7nRGu8w== +"@aws-cdk/service-spec-importers@^0.0.11": + version "0.0.11" + resolved "https://registry.npmjs.org/@aws-cdk/service-spec-importers/-/service-spec-importers-0.0.11.tgz#f7e60063337934313036d573a96d1e67ed9922d9" + integrity sha512-EjEpNx7rZNVuUwpJcttwAfQOKhCUojbDOZvu5k/0AcMKs6E/y/zGRdyt5xXxW04979ciLKcdWwgcGf4CcX9CSg== dependencies: - "@aws-cdk/service-spec-types" "^0.0.34" + "@aws-cdk/service-spec-types" "^0.0.35" "@cdklabs/tskb" "^0.0.3" ajv "^6" canonicalize "^2.0.0" @@ -85,10 +85,10 @@ glob "^8" sort-json "^2.0.1" -"@aws-cdk/service-spec-types@^0.0.34": - version "0.0.34" - resolved "https://registry.npmjs.org/@aws-cdk/service-spec-types/-/service-spec-types-0.0.34.tgz#79203599ad1fdf3534fead56cf946c4c3809ce26" - integrity sha512-ydG/wOXlbpDLTe5mmKDW2AKZP5/gwMCJPH7YEyR4N51Zs1+4rhYhODWk8ME/KXHs+TUpjWz4q0yE80BJQdhOvw== +"@aws-cdk/service-spec-types@^0.0.35": + version "0.0.35" + resolved "https://registry.npmjs.org/@aws-cdk/service-spec-types/-/service-spec-types-0.0.35.tgz#0d599074f6f09e741eea8621aa06de29fe4a1653" + integrity sha512-+XqMpPxyH2Hot/ifSF0eWmHUEYBIpUGvjEs4yxCdOrVAxOTYyJv6Ch/MZokOBmNF3Y03gxmaS0lPBhf8isT9EA== dependencies: "@cdklabs/tskb" "^0.0.3" From f3dafa49ec900fc044384441a9163d7ed6a63dda Mon Sep 17 00:00:00 2001 From: Clare Liguori Date: Mon, 11 Dec 2023 12:18:21 -0800 Subject: [PATCH 4/4] feat(stepfunctions-tasks): support for the Step Functions optimized integration for Bedrock InvokeModel API (#28276) Step Functions recently released an optimized integration for Bedrock InvokeModel API, and these changes add support for adding the Bedrock InvokeModel task to Step Functions state machines. Closes https://github.com/aws/aws-cdk/issues/28268. *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- ...efaultTestDeployAssert9C0D2DFC.assets.json | 19 + ...aultTestDeployAssert9C0D2DFC.template.json | 36 ++ ...sks-bedrock-invoke-model-integ.assets.json | 19 + ...s-bedrock-invoke-model-integ.template.json | 140 +++++++ .../integ.invoke-model.js.snapshot/cdk.out | 1 + .../integ.invoke-model.js.snapshot/integ.json | 12 + .../manifest.json | 125 ++++++ .../integ.invoke-model.js.snapshot/tree.json | 275 +++++++++++++ .../test/bedrock/integ.invoke-model.ts | 66 ++++ packages/aws-cdk-lib/aws-bedrock/.jsiirc.json | 13 + packages/aws-cdk-lib/aws-bedrock/README.md | 32 ++ packages/aws-cdk-lib/aws-bedrock/index.ts | 1 + .../aws-bedrock/lib/foundation-model.ts | 119 ++++++ packages/aws-cdk-lib/aws-bedrock/lib/index.ts | 3 + .../aws-cdk-lib/aws-bedrock/lib/model-base.ts | 13 + .../aws-bedrock/lib/provisioned-model.ts | 30 ++ .../aws-bedrock/test/model.test.ts | 41 ++ .../aws-stepfunctions-tasks/README.md | 38 ++ .../lib/bedrock/invoke-model.ts | 217 +++++++++++ .../aws-stepfunctions-tasks/lib/index.ts | 1 + .../test/bedrock/invoke-model.test.ts | 363 ++++++++++++++++++ packages/aws-cdk-lib/index.ts | 1 + packages/aws-cdk-lib/package.json | 1 + 23 files changed, 1566 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.ts create mode 100644 packages/aws-cdk-lib/aws-bedrock/.jsiirc.json create mode 100644 packages/aws-cdk-lib/aws-bedrock/README.md create mode 100644 packages/aws-cdk-lib/aws-bedrock/index.ts create mode 100644 packages/aws-cdk-lib/aws-bedrock/lib/foundation-model.ts create mode 100644 packages/aws-cdk-lib/aws-bedrock/lib/index.ts create mode 100644 packages/aws-cdk-lib/aws-bedrock/lib/model-base.ts create mode 100644 packages/aws-cdk-lib/aws-bedrock/lib/provisioned-model.ts create mode 100644 packages/aws-cdk-lib/aws-bedrock/test/model.test.ts create mode 100644 packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/bedrock/invoke-model.ts create mode 100644 packages/aws-cdk-lib/aws-stepfunctions-tasks/test/bedrock/invoke-model.test.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.assets.json new file mode 100644 index 0000000000000..ec22c34fcf613 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.assets.json @@ -0,0 +1,19 @@ +{ + "version": "35.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "InvokeModelDefaultTestDeployAssert9C0D2DFC.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/InvokeModelDefaultTestDeployAssert9C0D2DFC.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets.json new file mode 100644 index 0000000000000..2d7004e16caf5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets.json @@ -0,0 +1,19 @@ +{ + "version": "35.0.0", + "files": { + "19db222d8d51351d1127c4b099aa6545a4c1ddd9425a2e0f78c328f39ff74edf": { + "source": { + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "19db222d8d51351d1127c4b099aa6545a4c1ddd9425a2e0f78c328f39ff74edf.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.template.json new file mode 100644 index 0000000000000..ce41a5e96cc20 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/aws-stepfunctions-tasks-bedrock-invoke-model-integ.template.json @@ -0,0 +1,140 @@ +{ + "Resources": { + "StateMachineRoleB840431D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "states.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StateMachineRoleDefaultPolicyDF1E6607": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "bedrock:InvokeModel", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/amazon.titan-text-express-v1" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StateMachineRoleDefaultPolicyDF1E6607", + "Roles": [ + { + "Ref": "StateMachineRoleB840431D" + } + ] + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Prompt1\",\"States\":{\"Prompt1\":{\"Next\":\"Prompt2\",\"Type\":\"Task\",\"ResultPath\":\"$\",\"ResultSelector\":{\"names.$\":\"$.Body.results[0].outputText\"},\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::bedrock:invokeModel\",\"Parameters\":{\"ModelId\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/amazon.titan-text-express-v1\",\"Body\":{\"inputText\":\"Generate a list of five first names.\",\"textGenerationConfig\":{\"maxTokenCount\":100,\"temperature\":1}}}},\"Prompt2\":{\"End\":true,\"Type\":\"Task\",\"ResultPath\":\"$\",\"ResultSelector\":{\"names.$\":\"$.Body.results[0].outputText\"},\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::bedrock:invokeModel\",\"Parameters\":{\"ModelId\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/amazon.titan-text-express-v1\",\"Body\":{\"inputText.$\":\"States.Format('Alphabetize this list of first names:\\n{}', $.names)\",\"textGenerationConfig\":{\"maxTokenCount\":100,\"temperature\":1}}}}},\"TimeoutSeconds\":30}" + ] + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + } + }, + "DependsOn": [ + "StateMachineRoleDefaultPolicyDF1E6607", + "StateMachineRoleB840431D" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/cdk.out new file mode 100644 index 0000000000000..c5cb2e5de6344 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"35.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/integ.json new file mode 100644 index 0000000000000..5eb622d1d7b82 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "35.0.0", + "testCases": { + "InvokeModel/DefaultTest": { + "stacks": [ + "aws-stepfunctions-tasks-bedrock-invoke-model-integ" + ], + "assertionStack": "InvokeModel/DefaultTest/DeployAssert", + "assertionStackName": "InvokeModelDefaultTestDeployAssert9C0D2DFC" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/manifest.json new file mode 100644 index 0000000000000..60de1b8de8ab7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/manifest.json @@ -0,0 +1,125 @@ +{ + "version": "35.0.0", + "artifacts": { + "aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-stepfunctions-tasks-bedrock-invoke-model-integ": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-stepfunctions-tasks-bedrock-invoke-model-integ.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/19db222d8d51351d1127c4b099aa6545a4c1ddd9425a2e0f78c328f39ff74edf.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-stepfunctions-tasks-bedrock-invoke-model-integ.assets" + ], + "metadata": { + "/aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "StateMachineRoleB840431D" + } + ], + "/aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "StateMachineRoleDefaultPolicyDF1E6607" + } + ], + "/aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "StateMachine2E01A3A5" + } + ], + "/aws-stepfunctions-tasks-bedrock-invoke-model-integ/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-stepfunctions-tasks-bedrock-invoke-model-integ/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-stepfunctions-tasks-bedrock-invoke-model-integ" + }, + "InvokeModelDefaultTestDeployAssert9C0D2DFC.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "InvokeModelDefaultTestDeployAssert9C0D2DFC.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "InvokeModelDefaultTestDeployAssert9C0D2DFC": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "InvokeModelDefaultTestDeployAssert9C0D2DFC.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "InvokeModelDefaultTestDeployAssert9C0D2DFC.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "InvokeModelDefaultTestDeployAssert9C0D2DFC.assets" + ], + "metadata": { + "/InvokeModel/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/InvokeModel/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "InvokeModel/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/tree.json new file mode 100644 index 0000000000000..b3a2882dbd6fb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.js.snapshot/tree.json @@ -0,0 +1,275 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-stepfunctions-tasks-bedrock-invoke-model-integ": { + "id": "aws-stepfunctions-tasks-bedrock-invoke-model-integ", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ", + "children": { + "Prompt1": { + "id": "Prompt1", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/Prompt1", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_stepfunctions_tasks.BedrockInvokeModel", + "version": "0.0.0" + } + }, + "Prompt2": { + "id": "Prompt2", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/Prompt2", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_stepfunctions_tasks.BedrockInvokeModel", + "version": "0.0.0" + } + }, + "StateMachine": { + "id": "StateMachine", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine", + "children": { + "Role": { + "id": "Role", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "states.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "bedrock:InvokeModel", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/amazon.titan-text-express-v1" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "StateMachineRoleDefaultPolicyDF1E6607", + "roles": [ + { + "Ref": "StateMachineRoleB840431D" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/StateMachine/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::StepFunctions::StateMachine", + "aws:cdk:cloudformation:props": { + "definitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Prompt1\",\"States\":{\"Prompt1\":{\"Next\":\"Prompt2\",\"Type\":\"Task\",\"ResultPath\":\"$\",\"ResultSelector\":{\"names.$\":\"$.Body.results[0].outputText\"},\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::bedrock:invokeModel\",\"Parameters\":{\"ModelId\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/amazon.titan-text-express-v1\",\"Body\":{\"inputText\":\"Generate a list of five first names.\",\"textGenerationConfig\":{\"maxTokenCount\":100,\"temperature\":1}}}},\"Prompt2\":{\"End\":true,\"Type\":\"Task\",\"ResultPath\":\"$\",\"ResultSelector\":{\"names.$\":\"$.Body.results[0].outputText\"},\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::bedrock:invokeModel\",\"Parameters\":{\"ModelId\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/amazon.titan-text-express-v1\",\"Body\":{\"inputText.$\":\"States.Format('Alphabetize this list of first names:\\n{}', $.names)\",\"textGenerationConfig\":{\"maxTokenCount\":100,\"temperature\":1}}}}},\"TimeoutSeconds\":30}" + ] + ] + }, + "roleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_stepfunctions.CfnStateMachine", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_stepfunctions.StateMachine", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-stepfunctions-tasks-bedrock-invoke-model-integ/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "InvokeModel": { + "id": "InvokeModel", + "path": "InvokeModel", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "InvokeModel/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "InvokeModel/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "InvokeModel/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "InvokeModel/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "InvokeModel/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.ts new file mode 100644 index 0000000000000..95860f09e624e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/bedrock/integ.invoke-model.ts @@ -0,0 +1,66 @@ +import * as bedrock from 'aws-cdk-lib/aws-bedrock'; +import * as sfn from 'aws-cdk-lib/aws-stepfunctions'; +import * as cdk from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { BedrockInvokeModel } from 'aws-cdk-lib/aws-stepfunctions-tasks'; + +/* + * Stack verification steps: + * * aws stepfunctions start-execution --state-machine-arn : should return execution arn + * * aws stepfunctions describe-execution --execution-arn : should return status as SUCCEEDED + * This integ test does not actually verify a Step Functions execution, as not all AWS accounts have Bedrock model access. + */ +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-bedrock-invoke-model-integ'); + +const model = bedrock.FoundationModel.fromFoundationModelId(stack, 'Model', bedrock.FoundationModelIdentifier.AMAZON_TITAN_TEXT_G1_EXPRESS_V1); + +const prompt1 = new BedrockInvokeModel(stack, 'Prompt1', { + model, + body: sfn.TaskInput.fromObject( + { + inputText: 'Generate a list of five first names.', + textGenerationConfig: { + maxTokenCount: 100, + temperature: 1, + }, + }, + ), + resultSelector: { + names: sfn.JsonPath.stringAt('$.Body.results[0].outputText'), + }, + resultPath: '$', +}); + +const prompt2 = new BedrockInvokeModel(stack, 'Prompt2', { + model, + body: sfn.TaskInput.fromObject( + { + inputText: sfn.JsonPath.format( + 'Alphabetize this list of first names:\n{}', + sfn.JsonPath.stringAt('$.names'), + ), + textGenerationConfig: { + maxTokenCount: 100, + temperature: 1, + }, + }, + ), + resultSelector: { + names: sfn.JsonPath.stringAt('$.Body.results[0].outputText'), + }, + resultPath: '$', +}); + +const chain = sfn.Chain.start(prompt1).next(prompt2); + +new sfn.StateMachine(stack, 'StateMachine', { + definitionBody: sfn.DefinitionBody.fromChainable(chain), + timeout: cdk.Duration.seconds(30), +}); + +new IntegTest(app, 'InvokeModel', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/aws-cdk-lib/aws-bedrock/.jsiirc.json b/packages/aws-cdk-lib/aws-bedrock/.jsiirc.json new file mode 100644 index 0000000000000..5d9d8fdd12efe --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/.jsiirc.json @@ -0,0 +1,13 @@ +{ + "targets": { + "java": { + "package": "software.amazon.awscdk.services.bedrock" + }, + "dotnet": { + "namespace": "Amazon.CDK.AWS.Bedrock" + }, + "python": { + "module": "aws_cdk.aws_bedrock" + } + } +} diff --git a/packages/aws-cdk-lib/aws-bedrock/README.md b/packages/aws-cdk-lib/aws-bedrock/README.md new file mode 100644 index 0000000000000..cc353def5f1eb --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/README.md @@ -0,0 +1,32 @@ +# Amazon Bedrock Construct Library + +Amazon Bedrock is a fully managed service that offers a choice of foundation models (FMs) +along with a broad set of capabilities for building generative AI applications. + +CloudFormation does not currently support any Bedrock resource types. +This construct library is a collection of constructs that can look up existing Bedrock models +for use with other services' CDK constructs, such as AWS Step Functions. + +To look up a Bedrock base foundation model: + +```ts +import * as bedrock from 'aws-cdk-lib/aws-bedrock'; + +bedrock.FoundationModel.fromFoundationModelId( + this, + 'Model', + bedrock.FoundationModelIdentifier.ANTHROPIC_CLAUDE_V2, +); +``` + +To look up a Bedrock provisioned throughput model: + +```ts +import * as bedrock from 'aws-cdk-lib/aws-bedrock'; + +bedrock.ProvisionedModel.fromProvisionedModelArn( + this, + 'Model', + 'arn:aws:bedrock:us-east-2:123456789012:provisioned-model/abc-123', +); +``` diff --git a/packages/aws-cdk-lib/aws-bedrock/index.ts b/packages/aws-cdk-lib/aws-bedrock/index.ts new file mode 100644 index 0000000000000..f41a696fd204d --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/index.ts @@ -0,0 +1 @@ +export * from './lib'; diff --git a/packages/aws-cdk-lib/aws-bedrock/lib/foundation-model.ts b/packages/aws-cdk-lib/aws-bedrock/lib/foundation-model.ts new file mode 100644 index 0000000000000..b4e0a31d9c7fc --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/lib/foundation-model.ts @@ -0,0 +1,119 @@ +import { Construct } from 'constructs'; +import { IModel } from './model-base'; +import { ArnFormat, Stack } from '../../core'; + +/** + * The model identifiers for the Bedrock base foundation models. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html + */ +export class FoundationModelIdentifier { + /** Base model "ai21.j2-mid-v1". */ + public static readonly AI21_LABS_JURASSIC_2_MID_V1 = new FoundationModelIdentifier('ai21.j2-mid-v1'); + + /** Base model "ai21.j2-ultra-v1". */ + public static readonly AI21_LABS_JURASSIC_2_ULTRA_V1 = new FoundationModelIdentifier('ai21.j2-ultra-v1'); + + /** Base model "amazon.titan-embed-text-v1". */ + public static readonly AMAZON_TITAN_EMBEDDINGS_G1_TEXT_V1 = new FoundationModelIdentifier('amazon.titan-embed-text-v1'); + + /** Base model "amazon.titan-text-express-v1". */ + public static readonly AMAZON_TITAN_TEXT_G1_EXPRESS_V1 = new FoundationModelIdentifier('amazon.titan-text-express-v1'); + + /** Base model "amazon.titan-embed-image-v1". */ + public static readonly AMAZON_TITAN_MULTIMODAL_EMBEDDINGS_G1_V1 = new FoundationModelIdentifier('amazon.titan-embed-image-v1'); + + /** Base model "amazon.titan-image-generator-v1". */ + public static readonly AMAZON_TITAN_IMAGE_GENERATOR_G1_V1 = new FoundationModelIdentifier('amazon.titan-image-generator-v1'); + + /** Base model "anthropic.claude-v1". */ + public static readonly ANTHROPIC_CLAUDE_V1 = new FoundationModelIdentifier('anthropic.claude-v1'); + + /** Base model "anthropic.claude-v2". */ + public static readonly ANTHROPIC_CLAUDE_V2 = new FoundationModelIdentifier('anthropic.claude-v2'); + + /** Base model "anthropic.claude-v2:1". */ + public static readonly ANTHROPIC_CLAUDE_V2_1 = new FoundationModelIdentifier('anthropic.claude-v2:1'); + + /** Base model "anthropic.claude-instant-v1". */ + public static readonly ANTHROPIC_CLAUDE_INSTANT_V1 = new FoundationModelIdentifier('anthropic.claude-instant-v1'); + + /** Base model "cohere.command-text-v14". */ + public static readonly COHERE_COMMAND_V14 = new FoundationModelIdentifier('cohere.command-text-v14'); + + /** Base model "cohere.command-light-text-v14". */ + public static readonly COHERE_COMMAND_LIGHT_V14 = new FoundationModelIdentifier('cohere.command-light-text-v14'); + + /** Base model "cohere.embed-english-v3". */ + public static readonly COHERE_EMBED_ENGLISH_V3 = new FoundationModelIdentifier('cohere.embed-english-v3'); + + /** Base model "cohere.embed-multilingual-v3". */ + public static readonly COHERE_EMBED_MULTILINGUAL_V3 = new FoundationModelIdentifier('cohere.embed-multilingual-v3'); + + /** Base model "meta.llama2-13b-chat-v1". */ + public static readonly META_LLAMA_2_CHAT_13B_V1 = new FoundationModelIdentifier('meta.llama2-13b-chat-v1'); + + /** Base model "meta.llama2-70b-chat-v1". */ + public static readonly META_LLAMA_2_CHAT_70B_V1 = new FoundationModelIdentifier('meta.llama2-70b-chat-v1'); + + /** + * Constructor for foundation model identifier + * @param modelId the model identifier + */ + public constructor(public readonly modelId: string) { } +} + +/** + * Construction properties of `FoundationModel`. + * Module-private, as the constructor of `FoundationModel` is private. + */ +interface FoundationModelProps { + readonly modelId: string; + readonly modelArn: string; +} + +/** + * A Bedrock base foundation model. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html + */ +export class FoundationModel implements IModel { + /** + * Construct a Bedrock base foundation model given the model identifier. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html + * + * @param scope The parent construct + * @param _id The name of the model construct + * @param foundationModelId The model identifier such as 'amazon.titan-text-express-v1' + * @returns A Bedrock base foundation model. + */ + public static fromFoundationModelId(scope: Construct, _id: string, foundationModelId: FoundationModelIdentifier): FoundationModel { + return new FoundationModel({ + modelId: foundationModelId.modelId, + modelArn: Stack.of(scope).formatArn({ + service: 'bedrock', + account: '', + resource: 'foundation-model', + resourceName: foundationModelId.modelId, + arnFormat: ArnFormat.SLASH_RESOURCE_NAME, + }), + }); + } + + /** + * The foundation model ID. + * @example 'amazon.titan-text-express-v1' + */ + public readonly modelId: string; + + /** + * The foundation model ARN. + */ + public readonly modelArn: string; + + private constructor(props: FoundationModelProps) { + this.modelId = props.modelId; + this.modelArn = props.modelArn; + } +} diff --git a/packages/aws-cdk-lib/aws-bedrock/lib/index.ts b/packages/aws-cdk-lib/aws-bedrock/lib/index.ts new file mode 100644 index 0000000000000..4249e058d34c5 --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/lib/index.ts @@ -0,0 +1,3 @@ +export * from './foundation-model'; +export * from './model-base'; +export * from './provisioned-model'; diff --git a/packages/aws-cdk-lib/aws-bedrock/lib/model-base.ts b/packages/aws-cdk-lib/aws-bedrock/lib/model-base.ts new file mode 100644 index 0000000000000..97ef32bb7f08e --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/lib/model-base.ts @@ -0,0 +1,13 @@ +/** + * Represents a Bedrock model. + * The model could be a foundation model, a custom model, or a provisioned model. + */ +export interface IModel { + /** + * The ARN of the model + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/api-methods-run.html + * @see https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonbedrock.html#amazonbedrock-actions-as-permissions + */ + readonly modelArn: string; +} diff --git a/packages/aws-cdk-lib/aws-bedrock/lib/provisioned-model.ts b/packages/aws-cdk-lib/aws-bedrock/lib/provisioned-model.ts new file mode 100644 index 0000000000000..4c1a72e2a0252 --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/lib/provisioned-model.ts @@ -0,0 +1,30 @@ +import { Construct } from 'constructs'; +import { IModel } from './model-base'; + +/** + * A Bedrock provisioned model + * + * Note: CloudFormation does not currently support creating Bedrock Provisioned Throughput + * resources outside of a custom resource. You can import provisioned models created by + * provisioning throughput in Bedrock outside the CDK or via a custom resource with + * {@link ProvisionedModel#fromProvisionedModelArn}. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/prov-throughput.html + */ +export class ProvisionedModel implements IModel { + /** + * Import an provisioned model given an ARN + */ + public static fromProvisionedModelArn(_scope: Construct, _id: string, provisionedModelArn: string): IModel { + return new ProvisionedModel(provisionedModelArn); + } + + /** + * The ARN of the provisioned model. + */ + public readonly modelArn: string; + + private constructor(provisionedModelArn: string) { + this.modelArn = provisionedModelArn; + } +} diff --git a/packages/aws-cdk-lib/aws-bedrock/test/model.test.ts b/packages/aws-cdk-lib/aws-bedrock/test/model.test.ts new file mode 100644 index 0000000000000..f5887cd4203cb --- /dev/null +++ b/packages/aws-cdk-lib/aws-bedrock/test/model.test.ts @@ -0,0 +1,41 @@ +import * as cdk from '../../core'; +import * as bedrock from '../lib'; + +/* eslint-disable quote-props */ + +describe('ProvisionedModel', () => { + test('fromProvisionedModelArn', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const model = bedrock.ProvisionedModel.fromProvisionedModelArn(stack, 'Model', 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + + // THEN + expect(model.modelArn).toEqual('arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + }); +}); + +describe('FoundationModel', () => { + test('fromFoundationModelId', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const model = bedrock.FoundationModel.fromFoundationModelId(stack, 'Model', bedrock.FoundationModelIdentifier.ANTHROPIC_CLAUDE_V2); + + // THEN + expect(stack.resolve(model.modelArn)).toEqual({ 'Fn::Join': ['', ['arn:', { 'Ref': 'AWS::Partition' }, ':bedrock:', { 'Ref': 'AWS::Region' }, '::foundation-model/anthropic.claude-v2']] }); + }); + + test('fromFoundationModelId with newer model ID', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const model = bedrock.FoundationModel.fromFoundationModelId(stack, 'Model', new bedrock.FoundationModelIdentifier('new-base-model')); + + // THEN + expect(stack.resolve(model.modelArn)).toEqual({ 'Fn::Join': ['', ['arn:', { 'Ref': 'AWS::Partition' }, ':bedrock:', { 'Ref': 'AWS::Region' }, '::foundation-model/new-base-model']] }); + }); +}); diff --git a/packages/aws-cdk-lib/aws-stepfunctions-tasks/README.md b/packages/aws-cdk-lib/aws-stepfunctions-tasks/README.md index bf726ce12a802..8f32286484f39 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions-tasks/README.md +++ b/packages/aws-cdk-lib/aws-stepfunctions-tasks/README.md @@ -31,6 +31,8 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw - [StopQueryExecution](#stopqueryexecution) - [Batch](#batch) - [SubmitJob](#submitjob) + - [Bedrock](#bedrock) + - [InvokeModel](#invokemodel) - [CodeBuild](#codebuild) - [StartBuild](#startbuild) - [DynamoDB](#dynamodb) @@ -311,6 +313,42 @@ const task = new tasks.BatchSubmitJob(this, 'Submit Job', { }); ``` +## Bedrock + +Step Functions supports [Bedrock](https://docs.aws.amazon.com/step-functions/latest/dg/connect-bedrock.html) through the service integration pattern. + +### InvokeModel + +The [InvokeModel](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModel.html) API +invokes the specified Bedrock model to run inference using the input provided. +The format of the input body and the response body depend on the model selected. + +```ts +import * as bedrock from 'aws-cdk-lib/aws-bedrock'; + +const model = bedrock.FoundationModel.fromFoundationModelId( + this, + 'Model', + bedrock.FoundationModelIdentifier.AMAZON_TITAN_TEXT_G1_EXPRESS_V1, +); + +const task = new tasks.BedrockInvokeModel(this, 'Prompt Model', { + model, + body: sfn.TaskInput.fromObject( + { + inputText: 'Generate a list of five first names.', + textGenerationConfig: { + maxTokenCount: 100, + temperature: 1, + }, + }, + ), + resultSelector: { + names: sfn.JsonPath.stringAt('$.Body.results[0].outputText'), + }, +}); +``` + ## CodeBuild Step Functions supports [CodeBuild](https://docs.aws.amazon.com/step-functions/latest/dg/connect-codebuild.html) through the service integration pattern. diff --git a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/bedrock/invoke-model.ts b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/bedrock/invoke-model.ts new file mode 100644 index 0000000000000..f123ca00ac271 --- /dev/null +++ b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/bedrock/invoke-model.ts @@ -0,0 +1,217 @@ +import { Construct } from 'constructs'; +import * as bedrock from '../../../aws-bedrock'; +import * as iam from '../../../aws-iam'; +import * as s3 from '../../../aws-s3'; +import * as sfn from '../../../aws-stepfunctions'; +import { Stack } from '../../../core'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * Location to retrieve the input data, prior to calling Bedrock InvokeModel. + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-bedrock.html + */ +export interface BedrockInvokeModelInputProps { + + /** + * S3 object to retrieve the input data from. + * + * If the S3 location is not set, then the Body must be set. + * + * @default Input data is retrieved from the `body` field + */ + readonly s3Location?: s3.Location; +} + +/** + * Location where the Bedrock InvokeModel API response is written. + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-bedrock.html + */ +export interface BedrockInvokeModelOutputProps { + + /** + * S3 object where the Bedrock InvokeModel API response is written. + * + * If you specify this field, the API response body is replaced with + * a reference to the Amazon S3 location of the original output. + * + * @default Response body is returned in the task result + */ + readonly s3Location?: s3.Location; +} + +/** + * Properties for invoking a Bedrock Model + */ +export interface BedrockInvokeModelProps extends sfn.TaskStateBaseProps { + + /** + * The Bedrock model that the task will invoke. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/api-methods-run.html + */ + readonly model: bedrock.IModel; + + /** + * The input data for the Bedrock model invocation. + * + * The inference parameters contained in the body depend on the Bedrock model being used. + * + * The body must be in the format specified in the `contentType` field. + * For example, if the content type is `application/json`, the body must be + * JSON formatted. + * + * The body must be up to 256 KB in size. For input data that exceeds 256 KB, + * use `input` instead to retrieve the input data from S3. + * + * You must specify either the `body` or the `input` field, but not both. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters.html + * + * @default Input data is retrieved from the location specified in the `input` field + */ + readonly body?: sfn.TaskInput; + + /** + * The desired MIME type of the inference body in the response. + * + * @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModel.html + * @default 'application/json' + */ + readonly accept?: string; + + /** + * The MIME type of the input data in the request. + * + * @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModel.html + * @default 'application/json' + */ + readonly contentType?: string; + + /** + * The source location to retrieve the input data from. + * + * @default Input data is retrieved from the `body` field + */ + readonly input?: BedrockInvokeModelInputProps; + + /** + * The destination location where the API response is written. + * + * If you specify this field, the API response body is replaced with a reference to the + * output location. + * + * @default The API response body is returned in the result. + */ + readonly output?: BedrockInvokeModelOutputProps; +} + +/** + * A Step Functions Task to invoke a model in Bedrock. + * + */ +export class BedrockInvokeModel extends sfn.TaskStateBase { + + private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ + sfn.IntegrationPattern.REQUEST_RESPONSE, + ]; + + protected readonly taskMetrics: sfn.TaskMetricsConfig | undefined; + protected readonly taskPolicies: iam.PolicyStatement[] | undefined; + + private readonly integrationPattern: sfn.IntegrationPattern; + + constructor(scope: Construct, id: string, private readonly props: BedrockInvokeModelProps) { + super(scope, id, props); + this.integrationPattern = props.integrationPattern ?? sfn.IntegrationPattern.REQUEST_RESPONSE; + + validatePatternSupported(this.integrationPattern, BedrockInvokeModel.SUPPORTED_INTEGRATION_PATTERNS); + + const isBodySpecified = props.body !== undefined; + const isInputSpecified = props.input !== undefined && props.input.s3Location !== undefined; + + if (isBodySpecified && isInputSpecified) { + throw new Error('Either `body` or `input` must be specified, but not both.'); + } + if (!isBodySpecified && !isInputSpecified) { + throw new Error('Either `body` or `input` must be specified.'); + } + if (props.input?.s3Location?.objectVersion !== undefined) { + throw new Error('Input S3 object version is not supported.'); + } + if (props.output?.s3Location?.objectVersion !== undefined) { + throw new Error('Output S3 object version is not supported.'); + } + + this.taskPolicies = this.renderPolicyStatements(); + } + + private renderPolicyStatements(): iam.PolicyStatement[] { + const policyStatements = [ + new iam.PolicyStatement({ + actions: ['bedrock:InvokeModel'], + resources: [this.props.model.modelArn], + }), + ]; + + if (this.props.input !== undefined && this.props.input.s3Location !== undefined) { + policyStatements.push( + new iam.PolicyStatement({ + actions: ['s3:GetObject'], + resources: [ + Stack.of(this).formatArn({ + region: '', + account: '', + service: 's3', + resource: this.props.input?.s3Location?.bucketName, + resourceName: this.props.input?.s3Location?.objectKey, + }), + ], + }), + ); + } + + if (this.props.output !== undefined && this.props.output.s3Location !== undefined) { + policyStatements.push( + new iam.PolicyStatement({ + actions: ['s3:PutObject'], + resources: [ + Stack.of(this).formatArn({ + region: '', + account: '', + service: 's3', + resource: this.props.output?.s3Location?.bucketName, + resourceName: this.props.output?.s3Location?.objectKey, + }), + ], + }), + ); + } + + return policyStatements; + } + + /** + * Provides the Bedrock InvokeModel service integration task configuration + * + * @internal + */ + protected _renderTask(): any { + return { + Resource: integrationResourceArn('bedrock', 'invokeModel'), + Parameters: sfn.FieldUtils.renderObject({ + ModelId: this.props.model.modelArn, + Accept: this.props.accept, + ContentType: this.props.contentType, + Body: this.props.body?.value, + Input: this.props.input?.s3Location ? { + S3Uri: `s3://${this.props.input.s3Location.bucketName}/${this.props.input.s3Location.objectKey}`, + } : undefined, + Output: this.props.output?.s3Location ? { + S3Uri: `s3://${this.props.output.s3Location.bucketName}/${this.props.output.s3Location.objectKey}`, + } : undefined, + }), + }; + } +} diff --git a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/index.ts b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/index.ts index 04fd1846f1d08..575464d22dcf0 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/index.ts +++ b/packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/index.ts @@ -51,3 +51,4 @@ export * from './eks/call'; export * from './apigateway'; export * from './eventbridge/put-events'; export * from './aws-sdk/call-aws-service'; +export * from './bedrock/invoke-model'; diff --git a/packages/aws-cdk-lib/aws-stepfunctions-tasks/test/bedrock/invoke-model.test.ts b/packages/aws-cdk-lib/aws-stepfunctions-tasks/test/bedrock/invoke-model.test.ts new file mode 100644 index 0000000000000..32c636cf679cf --- /dev/null +++ b/packages/aws-cdk-lib/aws-stepfunctions-tasks/test/bedrock/invoke-model.test.ts @@ -0,0 +1,363 @@ +import { Template, Match } from '../../../assertions'; +import * as bedrock from '../../../aws-bedrock'; +import * as sfn from '../../../aws-stepfunctions'; +import * as cdk from '../../../core'; +import { BedrockInvokeModel } from '../../lib/bedrock/invoke-model'; + +describe('Invoke Model', () => { + + test('default settings', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack1', { env: { account: '12345678', region: 'us-turbo-1' } }); + + // WHEN + const task = new BedrockInvokeModel(stack, 'Invoke', { + model: bedrock.FoundationModel.fromFoundationModelId(stack, 'Model', bedrock.FoundationModelIdentifier.ANTHROPIC_CLAUDE_INSTANT_V1), + body: sfn.TaskInput.fromObject( + { + prompt: 'Hello world', + }, + ), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::bedrock:invokeModel', + ], + ], + }, + End: true, + Parameters: { + ModelId: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':bedrock:us-turbo-1::foundation-model/anthropic.claude-instant-v1', + ], + ], + }, + Body: { + prompt: 'Hello world', + }, + }, + }); + }); + + test('InvokeModel permissions are created in generated policy', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack1', { env: { account: '12345678', region: 'us-turbo-1' } }); + + // WHEN + const task = new BedrockInvokeModel(stack, 'Invoke', { + model: bedrock.FoundationModel.fromFoundationModelId(stack, 'Model', bedrock.FoundationModelIdentifier.ANTHROPIC_CLAUDE_INSTANT_V1), + body: sfn.TaskInput.fromObject( + { + prompt: 'Hello world', + }, + ), + }); + + new sfn.StateMachine(stack, 'StateMachine', { + definitionBody: sfn.DefinitionBody.fromChainable(task), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: Match.objectLike({ + Statement: Match.arrayWith([ + { + Action: 'bedrock:InvokeModel', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':bedrock:us-turbo-1::foundation-model/anthropic.claude-instant-v1', + ], + ], + }, + }, + ]), + }), + }); + }); + + test('MIME type configurations', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack1', { env: { account: '12345678', region: 'us-turbo-1' } }); + + // WHEN + const task = new BedrockInvokeModel(stack, 'Invoke', { + model: bedrock.FoundationModel.fromFoundationModelId(stack, 'Model', bedrock.FoundationModelIdentifier.ANTHROPIC_CLAUDE_INSTANT_V1), + body: sfn.TaskInput.fromObject( + { + prompt: 'Hello world', + }, + ), + accept: 'image/png', + contentType: 'text/plain', + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::bedrock:invokeModel', + ], + ], + }, + End: true, + Parameters: { + ModelId: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':bedrock:us-turbo-1::foundation-model/anthropic.claude-instant-v1', + ], + ], + }, + Body: { + prompt: 'Hello world', + }, + Accept: 'image/png', + ContentType: 'text/plain', + }, + }); + }); + + test('input and output configurations', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack1', { env: { account: '12345678', region: 'us-turbo-1' } }); + const model = bedrock.ProvisionedModel.fromProvisionedModelArn(stack, 'Imported', 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + + // WHEN + const task = new BedrockInvokeModel(stack, 'Invoke', { + model, + input: { + s3Location: { + bucketName: 'input-bucket', + objectKey: 'input-key', + }, + }, + output: { + s3Location: { + bucketName: 'output-bucket', + objectKey: 'output-key', + }, + }, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::bedrock:invokeModel', + ], + ], + }, + End: true, + Parameters: { + ModelId: 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123', + Input: { + S3Uri: 's3://input-bucket/input-key', + }, + Output: { + S3Uri: 's3://output-bucket/output-key', + }, + }, + }); + }); + + test('S3 permissions are created in generated policy when input and output locations are specified', () => { + // GIVEN + const stack = new cdk.Stack(); + const model = bedrock.ProvisionedModel.fromProvisionedModelArn(stack, 'Imported', 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + + // WHEN + const task = new BedrockInvokeModel(stack, 'Invoke', { + model, + input: { + s3Location: { + bucketName: 'input-bucket', + objectKey: 'input-key', + }, + }, + output: { + s3Location: { + bucketName: 'output-bucket', + objectKey: 'output-key', + }, + }, + }); + + new sfn.StateMachine(stack, 'StateMachine', { + definitionBody: sfn.DefinitionBody.fromChainable(task), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: Match.objectLike({ + Statement: Match.arrayWith([ + { + Action: 'bedrock:InvokeModel', + Effect: 'Allow', + Resource: 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123', + }, + { + Action: 's3:GetObject', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::input-bucket/input-key', + ], + ], + }, + }, + { + Action: 's3:PutObject', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::output-bucket/output-key', + ], + ], + }, + }, + ]), + }), + }); + }); + + test('fails on neither input nor body set', () => { + // GIVEN + const stack = new cdk.Stack(); + const model = bedrock.ProvisionedModel.fromProvisionedModelArn(stack, 'Imported', 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + + expect(() => { + // WHEN + new BedrockInvokeModel(stack, 'Invoke', { + model, + }); + // THEN + }).toThrow(/Either `body` or `input` must be specified./); + }); + + test('fails on both input and body set', () => { + // GIVEN + const stack = new cdk.Stack(); + const model = bedrock.ProvisionedModel.fromProvisionedModelArn(stack, 'Imported', 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + + expect(() => { + // WHEN + new BedrockInvokeModel(stack, 'Invoke', { + model, + body: sfn.TaskInput.fromObject( + { + prompt: 'Hello world', + }, + ), + input: { + s3Location: { + bucketName: 'hello', + objectKey: 'world', + }, + }, + }); + // THEN + }).toThrow(/Either `body` or `input` must be specified, but not both./); + }); + + test('fails on S3 object version in input', () => { + // GIVEN + const stack = new cdk.Stack(); + const model = bedrock.ProvisionedModel.fromProvisionedModelArn(stack, 'Imported', 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + + expect(() => { + // WHEN + new BedrockInvokeModel(stack, 'Invoke', { + model, + input: { + s3Location: { + bucketName: 'hello', + objectKey: 'world', + objectVersion: '123', + }, + }, + }); + // THEN + }).toThrow(/Input S3 object version is not supported./); + }); + + test('fails on S3 object version in output', () => { + // GIVEN + const stack = new cdk.Stack(); + const model = bedrock.ProvisionedModel.fromProvisionedModelArn(stack, 'Imported', 'arn:aws:bedrock:us-turbo-2:123456789012:provisioned-model/abc-123'); + + expect(() => { + // WHEN + new BedrockInvokeModel(stack, 'Invoke', { + model, + body: sfn.TaskInput.fromObject( + { + prompt: 'Hello world', + }, + ), + output: { + s3Location: { + bucketName: 'hello', + objectKey: 'world', + objectVersion: '123', + }, + }, + }); + // THEN + }).toThrow(/Output S3 object version is not supported./); + }); +}); diff --git a/packages/aws-cdk-lib/index.ts b/packages/aws-cdk-lib/index.ts index 2a77270f03d99..739ab80ae4644 100644 --- a/packages/aws-cdk-lib/index.ts +++ b/packages/aws-cdk-lib/index.ts @@ -30,6 +30,7 @@ export * as aws_autoscalingplans from './aws-autoscalingplans'; export * as aws_backup from './aws-backup'; export * as aws_backupgateway from './aws-backupgateway'; export * as aws_batch from './aws-batch'; +export * as aws_bedrock from './aws-bedrock'; export * as aws_billingconductor from './aws-billingconductor'; export * as aws_budgets from './aws-budgets'; export * as aws_cassandra from './aws-cassandra'; diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 8163c74978145..d2b2ad6c7acae 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -241,6 +241,7 @@ "./aws-backup": "./aws-backup/index.js", "./aws-backupgateway": "./aws-backupgateway/index.js", "./aws-batch": "./aws-batch/index.js", + "./aws-bedrock": "./aws-bedrock/index.js", "./aws-billingconductor": "./aws-billingconductor/index.js", "./aws-budgets": "./aws-budgets/index.js", "./aws-cassandra": "./aws-cassandra/index.js",