diff --git a/package.json b/package.json index 08f2f000c0642..e72167a9dcadd 100644 --- a/package.json +++ b/package.json @@ -180,4 +180,4 @@ "dependencies": { "string-width": "^4.2.3" } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/.eslintrc.js b/packages/@aws-cdk/aws-bedrock-alpha/.eslintrc.js new file mode 100644 index 0000000000000..73d2505a85a7f --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/.eslintrc.js @@ -0,0 +1,4 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +baseConfig.rules['import/order'] = 'off'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-bedrock-alpha/.gitignore b/packages/@aws-cdk/aws-bedrock-alpha/.gitignore new file mode 100644 index 0000000000000..820021a6ac1ea --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/.gitignore @@ -0,0 +1,24 @@ +*.js +!jest.config.js +*.d.ts +node_modules +dist +.LAST_PACKAGE +*.tsbuildinfo +.LAST_BUILD +*.snk +junit.xml +.nyc_output +coverage +nyc.config.js +!.eslintrc.js + +!**/*.snapshot/**/asset.*/*.js +!**/*.snapshot/**/asset.*/*.d.ts + +!**/*.snapshot/**/asset.*/** + +*.jsii +.jsii.tabl.json.gz +.jsiirc.json +tsconfig.json diff --git a/packages/@aws-cdk/aws-bedrock-alpha/.npmignore b/packages/@aws-cdk/aws-bedrock-alpha/.npmignore new file mode 100644 index 0000000000000..7782bcab1dc19 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/.npmignore @@ -0,0 +1,18 @@ +dist +.LAST_PACKAGE +*.tsbuildinfo +test/ +tsconfig.json +.eslintrc.js +coverage +.nyc_output +*.tgz +*.ts +!*.d.ts +!*.js +!*.lit.ts +!.jsii +.LAST_BUILD +*.snk +junit.xml +**/cdk.out diff --git a/packages/@aws-cdk/aws-bedrock-alpha/LICENSE b/packages/@aws-cdk/aws-bedrock-alpha/LICENSE new file mode 100644 index 0000000000000..5ccf0c6780bab --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-bedrock-alpha/NOTICE b/packages/@aws-cdk/aws-bedrock-alpha/NOTICE new file mode 100644 index 0000000000000..cd0946c1cf193 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-bedrock-alpha/README.md b/packages/@aws-cdk/aws-bedrock-alpha/README.md new file mode 100644 index 0000000000000..e1e24a303976f --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/README.md @@ -0,0 +1,608 @@ +# Amazon Bedrock Construct Library + + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + +--- + + + +| **Language** | **Package** | +| :--------------------------------------------------------------------------------------------- | --------------------------------------- | +| ![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) TypeScript | `@aws-cdk/aws-bedrock-alpha` | + +[Amazon Bedrock](https://aws.amazon.com/bedrock/) is a fully managed service that offers a choice of high-performing foundation models (FMs) from leading AI companies and Amazon through a single API, along with a broad set of capabilities you need to build generative AI applications with security, privacy, and responsible AI. + +This construct library facilitates the deployment of Bedrock Agents, enabling you to create sophisticated AI applications that can interact with your systems and data sources. + +## Table of contents + +- [Agents](#agents) + - [Create an Agent](#create-an-agent) + - [Action groups](#action-groups) + - [Prepare the Agent](#prepare-the-agent) + - [Prompt Override Configuration](#prompt-override-configuration) + - [Memory Configuration](#memory-configuration) + - [Agent Collaboration](#agent-collaboration) + - [Custom Orchestration](#custom-orchestration) + - [Agent Alias](#agent-alias) + +## Agents + +Amazon Bedrock Agents allow generative AI applications to automate complex, multistep tasks by seamlessly integrating with your company's systems, APIs, and data sources. It uses the reasoning of foundation models (FMs), APIs, and data to break down user requests, gather relevant information, and efficiently complete tasks. + +### Create an Agent + +Building an agent is straightforward and fast. +The following example creates an Agent with a simple instruction and default prompts: + +```ts fixture=default +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', +}); +``` + +### Agent Properties + +The Bedrock Agent class supports the following properties. + +| Name | Type | Required | Description | +|---|---|---|---| +| name | string | No | The name of the agent. Defaults to a name generated by CDK | +| instruction | string | Yes | The instruction used by the agent that determines how it will perform its task. Must have a minimum of 40 characters | +| foundationModel | IBedrockInvokable | Yes | The foundation model used for orchestration by the agent | +| existingRole | iam.IRole | No | The existing IAM Role for the agent to use. Must have a trust policy allowing Bedrock service to assume the role. Defaults to a new created role | +| shouldPrepareAgent | boolean | No | Specifies whether to automatically update the `DRAFT` version of the agent after making changes. Defaults to false | +| idleSessionTTL | Duration | No | How long sessions should be kept open for the agent. Session expires if no conversation occurs during this time. Defaults to 1 hour | +| kmsKey | kms.IKey | No | The KMS key of the agent if custom encryption is configured. Defaults to AWS managed key | +| description | string | No | A description of the agent. Defaults to no description | +| actionGroups | AgentActionGroup[] | No | The Action Groups associated with the agent | +| promptOverrideConfiguration | PromptOverrideConfiguration | No | Overrides some prompt templates in different parts of an agent sequence configuration | +| userInputEnabled | boolean | No | Select whether the agent can prompt additional information from the user when it lacks enough information. Defaults to false | +| codeInterpreterEnabled | boolean | No | Select whether the agent can generate, run, and troubleshoot code when trying to complete a task. Defaults to false | +| forceDelete | boolean | No | Whether to delete the resource even if it's in use. Defaults to true | +| agentCollaboration | AgentCollaboration | No | Configuration for agent collaboration settings, including type and collaborators. This property allows you to define how the agent collaborates with other agents and what collaborators it can work with. Defaults to no agent collaboration configuration | +| customOrchestrationExecutor | CustomOrchestrationExecutor | No | The Lambda function to use for custom orchestration. If provided, orchestrationType is set to CUSTOM_ORCHESTRATION. If not provided, orchestrationType defaults to DEFAULT. Defaults to default orchestration | + +### Action Groups + +An action group defines functions your agent can call. The functions are Lambda functions. The action group uses an OpenAPI schema to tell the agent what your functions do and how to call them. + +#### Action Group Properties + +The AgentActionGroup class supports the following properties. + +| Name | Type | Required | Description | +|---|---|---|---| +| name | string | No | The name of the action group. Defaults to a name generated in the format 'action_group_quick_start_UUID' | +| description | string | No | A description of the action group | +| apiSchema | ApiSchema | No | The OpenAPI schema that defines the functions in the action group | +| executor | ActionGroupExecutor | No | The Lambda function that executes the actions in the group | +| enabled | boolean | No | Whether the action group is enabled. Defaults to true | +| forceDelete | boolean | No | Whether to delete the resource even if it's in use. Defaults to false | +| functionSchema | FunctionSchema | No | Defines functions that each define parameters that the agent needs to invoke from the user | +| parentActionGroupSignature | ParentActionGroupSignature | No | The AWS Defined signature for enabling certain capabilities in your agent | + +There are three ways to provide an API schema for your action group: + +From a local asset file (requires binding to scope): + +```ts fixture=default +const actionGroupFunction = new lambda.Function(this, 'ActionGroupFunction', { + runtime: lambda.Runtime.PYTHON_3_12, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/action-group')), +}); + +// When using ApiSchema.fromLocalAsset, you must bind the schema to a scope +const schema = bedrock.ApiSchema.fromLocalAsset(path.join(__dirname, 'action-group.yaml')); +schema.bind(this); + +const actionGroup = new bedrock.AgentActionGroup({ + name: 'query-library', + description: 'Use these functions to get information about the books in the library.', + executor: bedrock.ActionGroupExecutor.fromLambda(actionGroupFunction), + enabled: true, + apiSchema: schema, +}); + +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', +}); + +agent.addActionGroup(actionGroup); +``` + +From an inline OpenAPI schema: + +```ts fixture=default +const inlineSchema = bedrock.ApiSchema.fromInline(` +openapi: 3.0.3 +info: + title: Library API + version: 1.0.0 +paths: + /search: + get: + summary: Search for books + operationId: searchBooks + parameters: + - name: query + in: query + required: true + schema: + type: string +`); + +const actionGroupFunction = new lambda.Function(this, 'ActionGroupFunction', { + runtime: lambda.Runtime.PYTHON_3_12, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/action-group')), +}); + +const actionGroup = new bedrock.AgentActionGroup({ + name: 'query-library', + description: 'Use these functions to get information about the books in the library.', + executor: bedrock.ActionGroupExecutor.fromLambda(actionGroupFunction), + enabled: true, + apiSchema: inlineSchema, +}); + +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', +}); + +agent.addActionGroup(actionGroup); +``` + +From an existing S3 file: + +```ts fixture=default +const bucket = s3.Bucket.fromBucketName(this, 'ExistingBucket', 'my-schema-bucket'); +const s3Schema = bedrock.ApiSchema.fromS3File(bucket, 'schemas/action-group.yaml'); + +const actionGroupFunction = new lambda.Function(this, 'ActionGroupFunction', { + runtime: lambda.Runtime.PYTHON_3_12, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/action-group')), +}); + +const actionGroup = new bedrock.AgentActionGroup({ + name: 'query-library', + description: 'Use these functions to get information about the books in the library.', + executor: bedrock.ActionGroupExecutor.fromLambda(actionGroupFunction), + enabled: true, + apiSchema: s3Schema, +}); + +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', +}); + +agent.addActionGroup(actionGroup); +``` + +### Using FunctionSchema with Action Groups + +As an alternative to using OpenAPI schemas, you can define functions directly using the `FunctionSchema` class. This approach provides a more structured way to define the functions that your agent can call. + +```ts fixture=default +const actionGroupFunction = new lambda.Function(this, 'ActionGroupFunction', { + runtime: lambda.Runtime.PYTHON_3_12, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/action-group')), +}); + +// Define a function schema with parameters +const functionSchema = new bedrock.FunctionSchema({ + functions: [ + { + name: 'searchBooks', + description: 'Search for books in the library catalog', + parameters: { + 'query': { + type: bedrock.ParameterType.STRING, + required: true, + description: 'The search query string', + }, + 'maxResults': { + type: bedrock.ParameterType.INTEGER, + required: false, + description: 'Maximum number of results to return', + }, + 'includeOutOfPrint': { + type: bedrock.ParameterType.BOOLEAN, + required: false, + description: 'Whether to include out-of-print books', + } + }, + requireConfirmation: bedrock.RequireConfirmation.DISABLED, + }, + { + name: 'getBookDetails', + description: 'Get detailed information about a specific book', + parameters: { + 'bookId': { + type: bedrock.ParameterType.STRING, + required: true, + description: 'The unique identifier of the book', + } + }, + requireConfirmation: bedrock.RequireConfirmation.ENABLED, + } + ] +}); + +// Create an action group using the function schema +const actionGroup = new bedrock.AgentActionGroup({ + name: 'library-functions', + description: 'Functions for interacting with the library catalog', + executor: bedrock.ActionGroupExecutor.fromLambda(actionGroupFunction), + functionSchema: functionSchema, + enabled: true, +}); + +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', + actionGroups: [actionGroup], +}); +``` + +The `FunctionSchema` approach offers several advantages: + +- Type-safe definition of functions and parameters +- Built-in validation of parameter names, descriptions, and other properties +- Clear structure that maps directly to the AWS Bedrock API +- Support for parameter types including string, number, integer, boolean, array, and object +- Option to require user confirmation before executing specific functions + +If you chose to load your schema file from S3, the construct will provide the necessary permissions to your agent's execution role to access the schema file from the specific bucket. Similar to performing the operation through the console, the agent execution role will get a permission like: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AmazonBedrockAgentS3PolicyProd", + "Effect": "Allow", + "Action": [ + "s3:GetObject" + ], + "Resource": [ + "arn:aws:s3:::/" + ], + "Condition": { + "StringEquals": { + "aws:ResourceAccount": "ACCOUNT_NUMBER" + } + } + } + ] +} +``` + +```ts fixture=default +// create a bucket containing the input schema +const schemaBucket = new s3.Bucket(this, 'SchemaBucket', { + enforceSSL: true, + versioned: true, + publicReadAccess: false, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + encryption: s3.BucketEncryption.S3_MANAGED, + removalPolicy: RemovalPolicy.DESTROY, + autoDeleteObjects: true, +}); + +// deploy the local schema file to S3 +const deployement = new aws_s3_deployment.BucketDeployment(this, 'DeployWebsite', { + sources: [aws_s3_deployment.Source.asset(path.join(__dirname, '../inputschema'))], + destinationBucket: schemaBucket, + destinationKeyPrefix: 'inputschema', +}); + +// create the agent +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', + userInputEnabled: true, + shouldPrepareAgent:true +}); + +// create a lambda function +const actionGroupFunction = new lambda.Function(this, 'ActionGroupFunction', { + runtime: lambda.Runtime.PYTHON_3_12, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/action-group')), +}); + +// create an action group and read the schema file from S3 +const actionGroup = new bedrock.AgentActionGroup({ + name: 'query-library', + description: 'Use these functions to get information about the books in the library.', + executor: bedrock.ActionGroupExecutor.fromLambda(actionGroupFunction), + enabled: true, + apiSchema: bedrock.ApiSchema.fromS3File(schemaBucket, 'inputschema/action-group.yaml'), +}); + +// add the action group to the agent +agent.addActionGroup(actionGroup); + +// add dependency for the agent on the s3 deployment +agent.node.addDependency(deployement); +``` + +### Prepare the Agent + +The `Agent` constructs take an optional parameter `shouldPrepareAgent` to indicate that the Agent should be prepared after any updates to an agent or action group. This may increase the time to create and update those resources. By default, this value is false. + +#### Prepare Agent Properties + +| Name | Type | Required | Description | +|---|---|---|---| +| shouldPrepareAgent | boolean | No | Whether to automatically update the DRAFT version of the agent after making changes. Defaults to false | + +Creating an agent alias will not prepare the agent, so if you create an alias using the `AgentAlias` resource then you should set `shouldPrepareAgent` to **_true_**. + +### Prompt Override Configuration + +Bedrock Agents allows you to customize the prompts and LLM configuration for different steps in the agent sequence. The implementation provides type-safe configurations for each step type, ensuring correct usage at compile time. + +#### Prompt Override Configuration Properties + +| Name | Type | Required | Description | +|---|---|---|---| +| steps | PromptStepConfiguration[] | Yes | Array of step configurations for different parts of the agent sequence | +| parser | lambda.IFunction | No | Lambda function for custom parsing of agent responses | + +#### Prompt Step Configuration Properties + +Each step in the `steps` array supports the following properties: + +| Name | Type | Required | Description | +|---|---|---|---| +| stepType | AgentStepType | Yes | The type of step being configured (PRE_PROCESSING, ORCHESTRATION, POST_PROCESSING, ROUTING_CLASSIFIER, MEMORY_SUMMARIZATION, KNOWLEDGE_BASE_RESPONSE_GENERATION) | +| stepEnabled | boolean | No | Whether this step is enabled. Defaults to true | +| customPromptTemplate | string | No | Custom prompt template to use for this step | +| inferenceConfig | InferenceConfiguration | No | Configuration for model inference parameters | +| foundationModel | BedrockFoundationModel | No | Alternative foundation model to use for this step (only valid for ROUTING_CLASSIFIER step) | +| useCustomParser | boolean | No | Whether to use a custom parser for this step. Requires parser to be provided in PromptOverrideConfiguration | + +#### Inference Configuration Properties + +When providing `inferenceConfig`, the following properties are supported: + +| Name | Type | Required | Description | +|---|---|---|---| +| temperature | number | No | Controls randomness in the model's output (0.0-1.0) | +| topP | number | No | Controls diversity via nucleus sampling (0.0-1.0) | +| topK | number | No | Controls diversity by limiting the cumulative probability | +| maximumLength | number | No | Maximum length of generated text | +| stopSequences | string[] | No | Sequences where the model should stop generating | + +The following steps can be configured: + +- PRE_PROCESSING: Prepares the user input for orchestration +- ORCHESTRATION: Main step that determines the agent's actions +- POST_PROCESSING: Refines the agent's response +- ROUTING_CLASSIFIER: Classifies and routes requests to appropriate collaborators +- MEMORY_SUMMARIZATION: Summarizes conversation history for memory retention +- KNOWLEDGE_BASE_RESPONSE_GENERATION: Generates responses using knowledge base content + +Example with pre-processing configuration: + +```ts fixture=default +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, + instruction: 'You are a helpful assistant.', + promptOverrideConfiguration: bedrock.PromptOverrideConfiguration.fromSteps([ + { + stepType: bedrock.AgentStepType.PRE_PROCESSING, + stepEnabled: true, + customPromptTemplate: 'Your custom prompt template here', + inferenceConfig: { + temperature: 0.0, + topP: 1, + topK: 250, + maximumLength: 1, + stopSequences: ["\n\nHuman:"], + }, + } + ]) +}); +``` + +Example with routing classifier and foundation model: + +```ts fixture=default +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, + instruction: 'You are a helpful assistant.', + promptOverrideConfiguration: bedrock.PromptOverrideConfiguration.fromSteps([ + { + stepType: bedrock.AgentStepType.ROUTING_CLASSIFIER, + stepEnabled: true, + customPromptTemplate: 'Your routing template here', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_V2 + } as bedrock.PromptRoutingClassifierConfigCustomParser + ]) +}); +``` + +Using a custom Lambda parser: + +```ts fixture=default +const parserFunction = new lambda.Function(this, 'ParserFunction', { + runtime: lambda.Runtime.PYTHON_3_10, + handler: 'index.handler', + code: lambda.Code.fromAsset('lambda'), +}); + +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, + instruction: 'You are a helpful assistant.', + promptOverrideConfiguration: bedrock.PromptOverrideConfiguration.withCustomParser({ + parser: parserFunction, + preProcessingStep: { + stepType: bedrock.AgentStepType.PRE_PROCESSING, + useCustomParser: true + } + }) +}); +``` + +Foundation models can only be specified for the ROUTING_CLASSIFIER step. + +### Memory Configuration + +Agents can maintain context across multiple sessions and recall past interactions using memory. This feature is useful for creating a more coherent conversational experience. + +#### Memory Configuration Properties + +| Name | Type | Required | Description | +|---|---|---|---| +| maxRecentSessions | number | No | Maximum number of recent session summaries to retain | +| memoryDuration | Duration | No | How long to retain session summaries | + +Example: + +```ts fixture=default +const agent = new bedrock.Agent(this, 'MyAgent', { + agentName: 'MyAgent', + instruction: 'Your instruction here', + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, + memory: Memory.sessionSummary({ + maxRecentSessions: 10, // Keep the last 10 session summaries + memoryDuration: Duration.days(20), // Retain summaries for 20 days + }), +}); +``` + +### Agent Collaboration + +Agent Collaboration enables multiple Bedrock Agents to work together on complex tasks. This feature allows agents to specialize in different areas and collaborate to provide more comprehensive responses to user queries. + +#### Agent Collaboration Properties + +| Name | Type | Required | Description | +|---|---|---|---| +| type | AgentCollaboratorType | Yes | Type of collaboration (SUPERVISOR or PEER) | +| collaborators | AgentCollaborator[] | Yes | List of agent collaborators | + +#### Agent Collaborator Properties + +| Name | Type | Required | Description | +|---|---|---|---| +| agentAlias | AgentAlias | Yes | The agent alias to collaborate with | +| collaborationInstruction | string | Yes | Instructions for how to collaborate with this agent | +| collaboratorName | string | Yes | Name of the collaborator | +| relayConversationHistory | boolean | No | Whether to relay conversation history to the collaborator. Defaults to false | + +Example: + +```ts fixture=default +// Create a specialized agent +const customerSupportAgent = new bedrock.Agent(this, 'CustomerSupportAgent', { + instruction: 'You specialize in answering customer support questions.', + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, +}); + +// Create an agent alias +const customerSupportAlias = new bedrock.AgentAlias(this, 'CustomerSupportAlias', { + agent: customerSupportAgent, + agentAliasName: 'production', +}); + +// Create a main agent that collaborates with the specialized agent +const mainAgent = new bedrock.Agent(this, 'MainAgent', { + instruction: 'You route specialized questions to other agents.', + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, + agentCollaboration: { + type: bedrock.AgentCollaboratorType.SUPERVISOR, + collaborators: [ + new bedrock.AgentCollaborator({ + agentAlias: customerSupportAlias, + collaborationInstruction: 'Route customer support questions to this agent.', + collaboratorName: 'CustomerSupport', + relayConversationHistory: true + }), + ], + }, +}); +``` + +### Custom Orchestration + +Custom Orchestration allows you to override the default agent orchestration flow with your own Lambda function. This enables more control over how the agent processes user inputs and invokes action groups. + +When you provide a customOrchestrationExecutor, the agent's orchestrationType is automatically set to CUSTOM_ORCHESTRATION. If no customOrchestrationExecutor is provided, the orchestrationType defaults to DEFAULT, using Amazon Bedrock's built-in orchestration. + +#### Custom Orchestration Properties + +| Name | Type | Required | Description | +|---|---|---|---| +| function | lambda.IFunction | Yes | The Lambda function that implements the custom orchestration logic | + +Example: + +```ts fixture=default +const orchestrationFunction = new lambda.Function(this, 'OrchestrationFunction', { + runtime: lambda.Runtime.PYTHON_3_10, + handler: 'index.handler', + code: lambda.Code.fromAsset('lambda/orchestration'), +}); + +const agent = new bedrock.Agent(this, 'CustomOrchestrationAgent', { + instruction: 'You are a helpful assistant with custom orchestration logic.', + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, + customOrchestrationExecutor: bedrock.CustomOrchestrationExecutor.fromLambda(orchestrationFunction), +}); +``` + +### Agent Alias + +After you have sufficiently iterated on your working draft and are satisfied with the behavior of your agent, you can set it up for deployment and integration into your application by creating aliases. + +To deploy your agent, you need to create an alias. During alias creation, Amazon Bedrock automatically creates a version of your agent. The alias points to this newly created version. You can point the alias to a previously created version if necessary. You then configure your application to make API calls to that alias. + +By default, the Agent resource creates a test alias named 'AgentTestAlias' that points to the 'DRAFT' version. This test alias is accessible via the `testAlias` property of the agent. You can also create additional aliases for different environments using the AgentAlias construct. + +#### Agent Alias Properties + +| Name | Type | Required | Description | +|---|---|---|---| +| agent | Agent | Yes | The agent to create an alias for | +| agentAliasName | string | No | The name of the agent alias. Defaults to a name generated by CDK | +| description | string | No | A description of the agent alias. Defaults to no description | +| routingConfiguration | AgentAliasRoutingConfiguration | No | Configuration for routing traffic between agent versions | +| agentVersion | string | No | The version of the agent to use. If not specified, a new version is created | + +When redeploying an agent with changes, you must ensure the agent version is updated to avoid deployment failures with "agent already exists" errors. The recommended way to handle this is to include the `lastUpdated` property in the agent's description, which automatically updates whenever the agent is modified. This ensures a new version is created on each deployment. + +Example: + +```ts fixture=default +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', +}); + +const agentAlias = new bedrock.AgentAlias(this, 'myAlias', { + agentAliasName: 'production', + agent: agent, + description: `Production version of my agent. Created at ${agent.lastUpdated}` // ensure the version update +}); +``` diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/action-group.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/action-group.ts new file mode 100644 index 0000000000000..cca8461019b26 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/action-group.ts @@ -0,0 +1,218 @@ +import { CfnAgent } from 'aws-cdk-lib/aws-bedrock'; +import * as crypto from 'crypto'; +import { ActionGroupExecutor } from './api-executor'; +import { ApiSchema } from './api-schema'; +import { ValidationError } from './validation-helpers'; +import { FunctionSchema } from './function-schema'; + +/****************************************************************************** + * Signatures + *****************************************************************************/ +/** + * AWS Defined signatures for enabling certain capabilities in your agent. + */ +export class ParentActionGroupSignature { + /** + * Signature that allows your agent to request the user for additional information when trying to complete a task. + */ + public static readonly USER_INPUT = new ParentActionGroupSignature('AMAZON.UserInput'); + /** + * Signature that allows your agent to generate, run, and troubleshoot code when trying to complete a task. + */ + public static readonly CODE_INTERPRETER = new ParentActionGroupSignature('AMAZON.CodeInterpreter'); + /** + * Constructor should be used as a temporary solution when a new signature is supported but its implementation in CDK hasn't been added yet. + */ + constructor( + /** + * The AWS-defined signature value for this action group capability. + */ + public readonly value: string, + ) {} + + /** + * Returns the string representation of the signature value. + * Used when configuring the action group in CloudFormation. + */ + public toString() { + return this.value; + } +} +/****************************************************************************** + * PROPS - Action Group Class + *****************************************************************************/ +export interface AgentActionGroupProps { + /** + * The name of the action group. + * @default - A unique name is generated in the format 'action_group_quick_start_UUID' + */ + readonly name?: string; + + /** + * A description of the action group. + * + * @default undefined - No description is provided + */ + readonly description?: string; + + /** + * The API Schema defining the functions available to the agent. + * + * @default undefined - No API Schema is provided + */ + readonly apiSchema?: ApiSchema; + + /** + * The action group executor that implements the API functions. + * + * @default undefined - No executor is provided + */ + readonly executor?: ActionGroupExecutor; + + /** + * Specifies whether the action group is available for the agent to invoke or + * not when sending an InvokeAgent request. + * + * @default true - The action group is enabled + */ + readonly enabled?: boolean; + + /** + * Specifies whether to delete the resource even if it's in use. + * + * @default false - The resource will not be deleted if it's in use + */ + readonly forceDelete?: boolean; + + /** + * Defines functions that each define parameters that the agent needs to invoke from the user. + * NO L2 yet as this doesn't make much sense IMHO. + * + * @default undefined - No function schema is provided + */ + readonly functionSchema?: FunctionSchema; + + /** + * The AWS Defined signature for enabling certain capabilities in your agent. + * When this property is specified, you must leave the description, apiSchema, + * and actionGroupExecutor fields blank for this action group. + * + * @default undefined - No parent action group signature is provided + */ + readonly parentActionGroupSignature?: ParentActionGroupSignature; +} + +/****************************************************************************** + * DEF - Action Group Class + *****************************************************************************/ + +export class AgentActionGroup { + // ------------------------------------------------------ + // Static Constructors + // ------------------------------------------------------ + /** + * Defines an action group that allows your agent to request the user for + * additional information when trying to complete a task. + * @param enabled Specifies whether the action group is available for the agent + */ + public static userInput(enabled: boolean): AgentActionGroup { + return new AgentActionGroup({ + name: 'UserInputAction', + enabled: enabled, + parentActionGroupSignature: ParentActionGroupSignature.USER_INPUT, + }); + } + + /** + * Defines an action group that allows your agent to request the user for + * additional information when trying to complete a task. + * @param enabled Specifies whether the action group is available for the agent + */ + public static codeInterpreter(enabled: boolean): AgentActionGroup { + return new AgentActionGroup({ + name: 'CodeInterpreterAction', + enabled: enabled, + parentActionGroupSignature: ParentActionGroupSignature.CODE_INTERPRETER, + }); + } + + // ------------------------------------------------------ + // Attributes + // ------------------------------------------------------ + /** + * The name of the action group. + */ + public readonly name: string; + /** + * A description of the action group. + */ + public readonly description?: string; + /** + * Whether this action group is available for the agent to invoke or not. + */ + public readonly enabled: boolean; + /** + * The api schema for this action group (if defined). + */ + public readonly apiSchema?: ApiSchema; + /** + * The action group executor for this action group (if defined). + */ + public readonly executor?: ActionGroupExecutor; + /** + * Whether to delete the resource even if it's in use. + */ + public readonly forceDelete?: boolean; + /** + * The function schema for this action group (if defined). + */ + public readonly functionSchema?: FunctionSchema; + /** + * The AWS Defined signature (if defined). + */ + public readonly parentActionGroupSignature?: ParentActionGroupSignature; + + public constructor(props: AgentActionGroupProps) { + // Validate Props + this.validateProps(props); + + // ------------------------------------------------------ + // Set attributes or defaults + // ------------------------------------------------------ + this.name = props.name ?? `action_group_quick_start_${crypto.randomUUID()}`; + this.description = props.description; + this.apiSchema = props.apiSchema; + this.executor = props.executor; + this.enabled = props.enabled ?? true; + this.forceDelete = props.forceDelete ?? false; + this.functionSchema = props.functionSchema; + this.parentActionGroupSignature = props.parentActionGroupSignature; + } + + private validateProps(props: AgentActionGroupProps) { + if (props.parentActionGroupSignature && (props.description || props.apiSchema || props.executor)) { + throw new ValidationError( + 'When parentActionGroupSignature is specified, you must leave the description, ' + + 'apiSchema, and actionGroupExecutor fields blank for this action group', + ); + } + } + + /** + * Format as CFN properties + * + * @internal This is an internal core function and should not be called directly. + */ + public _render(): CfnAgent.AgentActionGroupProperty { + return { + actionGroupExecutor: this.executor?._render(), + actionGroupName: this.name, + actionGroupState: this.enabled ? 'ENABLED' : 'DISABLED', + apiSchema: this.apiSchema?._render(), + description: this.description, + functionSchema: this.functionSchema?._render(), + parentActionGroupSignature: this.parentActionGroupSignature?.toString(), + skipResourceInUseCheckOnDelete: this.forceDelete, + }; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-alias.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-alias.ts new file mode 100644 index 0000000000000..a562f9223d3e6 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-alias.ts @@ -0,0 +1,260 @@ +import { ArnFormat, aws_bedrock as bedrock, IResource, Resource, Stack } from 'aws-cdk-lib'; +import * as events from 'aws-cdk-lib/aws-events'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import { Construct } from 'constructs'; +import { IAgent } from './agent'; + +/****************************************************************************** + * COMMON + *****************************************************************************/ +/** + * Represents an Agent Alias, either created with CDK or imported. + */ +export interface IAgentAlias extends IResource { + /** + * The unique identifier of the agent alias. + * @attributes + */ + readonly aliasId: string; + /** + * The ARN of the agent alias. + * @attributes + */ + readonly aliasArn: string; + /** + * The underlying agent for this alias. + */ + readonly agent: IAgent; + + /** + * Grant the given principal identity permissions to perform actions on this agent alias. + */ + grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant; + + /** + * Grant the given identity permissions to invoke the agent alias. + */ + grantInvoke(grantee: iam.IGrantable): iam.Grant; + + /** + * Grant the given identity permissions to get the agent alias. + */ + grantGet(grantee: iam.IGrantable): iam.Grant; + + /** + * Define an EventBridge rule that triggers when something happens to this agent alias + * + * Requires that there exists at least one CloudTrail Trail in your account + * that captures the event. This method will not create the Trail. + * + * @param id The id of the rule + * @param options Options for adding the rule + */ + onCloudTrailEvent(id: string, options?: events.OnEventOptions): events.Rule; +} + +/****************************************************************************** + * ABSTRACT BASE CLASS + *****************************************************************************/ +/** + * Abstract base class for an Agent. + * Contains methods and attributes valid for Agents either created with CDK or imported. + */ +export abstract class AgentAliasBase extends Resource implements IAgentAlias { + public abstract readonly aliasId: string; + public abstract readonly aliasArn: string; + public abstract readonly agent: IAgent; + + /** + * Grant the given principal identity permissions to perform actions on this agent alias. + * Note: This grant will only work when the grantee is in the same AWS account + * where the agent alias is defined. Cross-account grant is not supported. + */ + public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { + return iam.Grant.addToPrincipal({ + grantee, + actions, + resourceArns: [this.aliasArn], + scope: this, + }); + } + + /** + * Grant the given identity permissions to invoke the agent alias. + * Note: This grant will only work when the grantee is in the same AWS account + * where the agent alias is defined. Cross-account invocation is not supported. + */ + public grantInvoke(grantee: iam.IGrantable): iam.Grant { + return this.grant(grantee, 'bedrock:InvokeAgent'); + } + + /** + * Grant the given identity permissions to get the agent alias. + * Note: This grant will only work when the grantee is in the same AWS account + * where the agent alias is defined. Cross-account agent read is not supported. + */ + public grantGet(grantee: iam.IGrantable): iam.Grant { + return this.grant(grantee, 'bedrock:GetAgentAlias'); + } + + /** + * Define an EventBridge rule that triggers when something happens to this agent alias + * + * Requires that there exists at least one CloudTrail Trail in your account + * that captures the event. This method will not create the Trail. + * + * @param id The id of the rule + * @param options Options for adding the rule + */ + public onCloudTrailEvent(id: string, options: events.OnEventOptions = {}): events.Rule { + const rule = new events.Rule(this, id, options); + rule.addTarget(options.target); + rule.addEventPattern({ + source: ['aws.bedrock'], + detailType: ['AWS API Call via CloudTrail'], + detail: { + requestParameters: { + agentAliasId: [this.aliasId], + }, + }, + }); + return rule; + } +} + +/****************************************************************************** + * PROPS FOR NEW CONSTRUCT + *****************************************************************************/ +/** + * Properties for creating a CDK-Managed Agent Alias. + */ +export interface AgentAliasProps { + /** + * The name for the agent alias. + * This will be used as the physical name of the agent alias. + * + * @default - "latest" + */ + readonly agentAliasName?: string; + /** + * The version of the agent to associate with the agent alias. + * + * @default - Creates a new version of the agent. + */ + readonly agentVersion?: string; + /** + * The agent associated to this alias. + */ + readonly agent: IAgent; + /** + * Description for the agent alias. + * @default undefined - No description is provided + */ + readonly description?: string; +} + +/****************************************************************************** + * ATTRS FOR IMPORTED CONSTRUCT + *****************************************************************************/ +/** + * Attributes needed to create an import + */ +export interface AgentAliasAttributes { + /** + * The Id of the agent alias. + */ + readonly aliasId: string; + /** + * The name of the agent alias. + * @default undefined - No alias name is provided + */ + readonly aliasName?: string; + /** + * The underlying agent for this alias. + */ + readonly agent: IAgent; + /** + * The agent version for this alias. + */ + readonly agentVersion: string; +} + +/****************************************************************************** + * NEW CONSTRUCT DEFINITION + *****************************************************************************/ +/** + * Class to create an Agent Alias with CDK. + * @cloudformationResource AWS::Bedrock::AgentAlias + */ +export class AgentAlias extends AgentAliasBase { + // ------------------------------------------------------ + // Imports + // ------------------------------------------------------ + /** + * Brings an Agent Alias from an existing one created outside of CDK. + */ + public static fromAttributes( + scope: Construct, + id: string, + attrs: AgentAliasAttributes, + ): IAgentAlias { + class Import extends AgentAliasBase { + public readonly agent = attrs.agent; + public readonly aliasId = attrs.aliasId; + public readonly aliasName = attrs.aliasName; + public readonly aliasArn = Stack.of(scope).formatArn({ + resource: 'agent-alias', + service: 'bedrock', + resourceName: `${attrs.agent.agentId}/${attrs.aliasId}`, + arnFormat: ArnFormat.SLASH_RESOURCE_NAME, + }); + } + return new Import(scope, id); + } + + // ---------------------------------------- + // Inherited Attributes + // ---------------------------------------- + public readonly agent: IAgent; + public readonly aliasId: string; + public readonly aliasArn: string; + /** + * The name of the agent alias. + * This is either provided by the user or generated from a hash. + */ + public readonly aliasName: string; + + // ------------------------------------------------------ + // CONSTRUCTOR + // ------------------------------------------------------ + constructor(scope: Construct, id: string, props: AgentAliasProps) { + super(scope, id); + + // ------------------------------------------------------ + // Set properties or defaults + // ------------------------------------------------------ + // see https://github.com/awslabs/generative-ai-cdk-constructs/issues/947 - The default name without any version update may result in this error. + // see https://github.com/awslabs/generative-ai-cdk-constructs/pull/1116 - If no agent version is provided then update the agent description for a new version. + this.aliasName = props.agentAliasName ?? 'latest'; + this.agent = props.agent; + + // ------------------------------------------------------ + // L1 Instantiation + // ------------------------------------------------------ + const alias = new bedrock.CfnAgentAlias(this, 'Resource', { + agentAliasName: this.aliasName, + agentId: this.agent.agentId, + description: props.description, + routingConfiguration: props.agentVersion + ? [ + { + agentVersion: props.agentVersion, + }, + ] + : undefined, + }); + + this.aliasId = alias.attrAgentAliasId; + this.aliasArn = alias.attrAgentAliasArn; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-collaboration.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-collaboration.ts new file mode 100644 index 0000000000000..7600c90d6697e --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-collaboration.ts @@ -0,0 +1,36 @@ +import { AgentCollaborator, AgentCollaboratorType } from './agent-collaborator'; + +/** + * Configuration for agent collaboration settings. + */ +export interface AgentCollaborationConfig { + /** + * The collaboration type for the agent. + */ + readonly type: AgentCollaboratorType; + + /** + * Collaborators that this agent will work with. + */ + readonly collaborators: AgentCollaborator[]; +} + +/** + * Class to manage agent collaboration configuration. + */ +export class AgentCollaboration { + /** + * The collaboration type for the agent. + */ + public readonly type: AgentCollaboratorType; + + /** + * Collaborators that this agent will work with. + */ + public readonly collaborators: AgentCollaborator[]; + + constructor(config: AgentCollaborationConfig) { + this.type = config.type; + this.collaborators = config.collaborators; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-collaborator.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-collaborator.ts new file mode 100644 index 0000000000000..184da0d5e3bc2 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent-collaborator.ts @@ -0,0 +1,143 @@ +import { CfnAgent } from 'aws-cdk-lib/aws-bedrock'; +import { IGrantable, Grant } from 'aws-cdk-lib/aws-iam'; +import { IAgentAlias } from './agent-alias'; +import { ValidationError } from './validation-helpers'; + +/** + * Enum for collaborator's relay conversation history types. + */ +export enum AgentCollaboratorType { + /** + * Supervisor agent. + */ + SUPERVISOR = 'SUPERVISOR', + + /** + * Disabling collaboration. + */ + DISABLED = 'DISABLED', + + /** + * Supervisor router. + */ + SUPERVISOR_ROUTER = 'SUPERVISOR_ROUTER', +} + +/** + * Enum for collaborator's relay conversation history types. + * @internal + */ +enum RelayConversationHistoryType { + /** + * Sending to the collaborator. + */ + TO_COLLABORATOR = 'TO_COLLABORATOR', + + /** + * Disabling relay of conversation history to the collaborator. + */ + DISABLED = 'DISABLED', +} + +/****************************************************************************** + * PROPS - Agent Collaborator Class + *****************************************************************************/ +export interface AgentCollaboratorProps { + /** + * Descriptor for the collaborating agent. + * This cannot be the TSTALIASID (`agent.testAlias`). + */ + readonly agentAlias: IAgentAlias; + + /** + * Instructions on how this agent should collaborate with the main agent. + */ + readonly collaborationInstruction: string; + + /** + * A friendly name for the collaborator. + */ + readonly collaboratorName: string; + + /** + * Whether to relay conversation history to this collaborator. + * + * @default - undefined (uses service default) + */ + readonly relayConversationHistory?: boolean; +} + +/****************************************************************************** + * Agent Collaborator Class + *****************************************************************************/ + +export class AgentCollaborator { + /** + * The agent alias that this collaborator represents. + * This is the agent that will be called upon for collaboration. + */ + public readonly agentAlias: IAgentAlias; + + /** + * Instructions on how this agent should collaborate with the main agent. + */ + public readonly collaborationInstruction: string; + + /** + * A friendly name for the collaborator. + */ + public readonly collaboratorName: string; + + /** + * Whether to relay conversation history to this collaborator. + * + * @default - undefined (uses service default) + */ + public readonly relayConversationHistory?: boolean; + + public constructor(props: AgentCollaboratorProps) { + // Validate Props + this.validateProps(props); + + // ------------------------------------------------------ + // Set attributes or defaults + // ------------------------------------------------------ + this.agentAlias = props.agentAlias; + this.collaborationInstruction = props.collaborationInstruction; + this.collaboratorName = props.collaboratorName; + this.relayConversationHistory = props.relayConversationHistory; + } + + private validateProps(props: AgentCollaboratorProps) { + if (props.agentAlias.aliasId === 'TSTALIASID') { + throw new ValidationError('Agent cannot collaborate with TSTALIASID alias of another agent'); + } + } + + /** + * Format as CFN properties + * + * @internal This is an internal core function and should not be called directly. + */ + public _render(): CfnAgent.AgentCollaboratorProperty { + return { + agentDescriptor: { + aliasArn: this.agentAlias.aliasArn, + }, + collaborationInstruction: this.collaborationInstruction, + collaboratorName: this.collaboratorName, + relayConversationHistory: this.relayConversationHistory ? RelayConversationHistoryType.TO_COLLABORATOR : RelayConversationHistoryType.DISABLED, + }; + } + + /** + * Grants the given identity permissions to collaborate with the agent + * @param grantee The principal to grant permissions to + * @returns The Grant object + */ + public grant(grantee: IGrantable): Grant { + const grant1 = this.agentAlias.grantInvoke(grantee); + const combinedGrant = grant1.combine(this.agentAlias.grantGet(grantee)); + return combinedGrant; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent.ts new file mode 100644 index 0000000000000..948a8068a38d6 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/agent.ts @@ -0,0 +1,798 @@ +import * as crypto from 'crypto'; +import { Arn, ArnFormat, Duration, IResource, Lazy, Names, Resource, Stack, Token, ValidationError } from 'aws-cdk-lib/core'; +import * as bedrock from 'aws-cdk-lib/aws-bedrock'; +import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch'; +import * as events from 'aws-cdk-lib/aws-events'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as kms from 'aws-cdk-lib/aws-kms'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { Construct, IConstruct } from 'constructs'; +// Internal Libs +import { AgentActionGroup } from './action-group'; +import { AgentAlias, IAgentAlias } from './agent-alias'; +import { AgentCollaborator } from './agent-collaborator'; +import { AgentCollaboration } from './agent-collaboration'; +import { PromptOverrideConfiguration } from './prompt-override'; +import { AssetApiSchema, S3ApiSchema } from './api-schema'; +import * as validation from './validation-helpers'; +import { IBedrockInvokable } from '.././models'; +import { Memory } from './memory'; +import { CustomOrchestrationExecutor, OrchestrationType } from './orchestration-executor'; + +/****************************************************************************** + * CONSTANTS + *****************************************************************************/ +/** + * The minimum number of characters required for an agent instruction. + * @internal + */ +const MIN_INSTRUCTION_LENGTH = 40; + +/** + * The maximum length for the node address in permission policy names. + * @internal + */ +const MAX_POLICY_NAME_NODE_LENGTH = 16; + +/****************************************************************************** + * COMMON + *****************************************************************************/ +/** + * Represents an Agent, either created with CDK or imported. + */ +export interface IAgent extends IResource, iam.IGrantable { + /** + * The ARN of the agent. + * @attribute + */ + readonly agentArn: string; + /** + * The ID of the Agent. + * @attribute + */ + readonly agentId: string; + /** + * The IAM role associated to the agent. + */ + readonly role: iam.IRole; + /** + * Optional KMS encryption key associated with this agent + */ + readonly kmsKey?: kms.IKey; + /** + * When this agent was last updated. + * @attribute + */ + readonly lastUpdated?: string; + + /** + * Grant invoke permissions on this agent to an IAM principal. + * Note: This grant will only work when the grantee is in the same AWS account + * where the agent is defined. Cross-account invocation is not supported. + */ + grantInvoke(grantee: iam.IGrantable): iam.Grant; + + /** + * Defines a CloudWatch event rule triggered by agent events. + */ + onEvent(id: string, options?: events.OnEventOptions): events.Rule; + + /** + * Return the CloudWatch metric for agent count. + */ + metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric; +} +/****************************************************************************** + * ABSTRACT BASE CLASS + *****************************************************************************/ +/** + * Abstract base class for an Agent. + * Contains methods and attributes valid for Agents either created with CDK or imported. + */ +export abstract class AgentBase extends Resource implements IAgent { + public abstract readonly agentArn: string; + public abstract readonly agentId: string; + public abstract readonly role: iam.IRole; + public abstract readonly kmsKey?: kms.IKey; + public abstract readonly lastUpdated?: string; + /** + * The version of the agent. + * @attribute + */ + public abstract readonly agentVersion: string; + public abstract readonly grantPrincipal: iam.IPrincipal; + + /** + * Grant invoke permissions on this agent to an IAM principal. + * + * @param grantee - The IAM principal to grant invoke permissions to + * @default - Default grant configuration: + * - actions: ['bedrock:InvokeAgent'] + * - resourceArns: [this.agentArn] + * @returns An IAM Grant object representing the granted permissions + */ + public grantInvoke(grantee: iam.IGrantable): iam.Grant { + return iam.Grant.addToPrincipal({ + grantee, + actions: ['bedrock:InvokeAgent'], + resourceArns: [this.agentArn], + }); + } + + /** + * Creates an EventBridge rule for agent events. + * + * @param id - Unique identifier for the rule + * @param options - Configuration options for the event rule + * @default - Default event pattern: + * - source: ['aws.bedrock'] + * - detail: { 'agent-id': [this.agentId] } + * @returns An EventBridge Rule configured for agent events + */ + public onEvent(id: string, options: events.OnEventOptions = {}): events.Rule { + // Create rule with minimal props and event pattern + const rule = new events.Rule(this, id, { + description: options.description, + eventPattern: { + source: ['aws.bedrock'], + detail: { + 'agent-id': [this.agentId], + }, + }, + }); + + // Add target if provided + if (options.target) { + rule.addTarget(options.target); + } + return rule; + } + + /** + * Creates a CloudWatch metric for tracking agent invocations. + * + * @param props - Configuration options for the metric + * @default - Default metric configuration: + * - namespace: 'AWS/Bedrock' + * - metricName: 'Invocations' + * - dimensionsMap: { AgentId: this.agentId } + * @returns A CloudWatch Metric configured for agent invocation counts + */ + public metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return new cloudwatch.Metric({ + namespace: 'AWS/Bedrock', + metricName: 'Invocations', + dimensionsMap: { + AgentId: this.agentId, + }, + ...props, + }).attachTo(this); + } +} + +/****************************************************************************** + * PROPS FOR NEW CONSTRUCT + *****************************************************************************/ +/** + * Properties for creating a CDK managed Bedrock Agent. + * TODO: Knowledge bases configuration will be added in a future update + * TODO: Guardrails configuration will be added in a future update + * TODO: Inference profile configuration will be added in a future update + * + */ +export interface AgentProps { + + /** + * The name of the agent. + * This will be used as the physical name of the agent. + * + * @default - A name is generated by CDK. + * Supported pattern : ^([0-9a-zA-Z][_-]?){1,100}$ + */ + readonly agentName?: string; + /** + * The instruction used by the agent. This determines how the agent will perform his task. + * This instruction must have a minimum of 40 characters. + */ + readonly instruction: string; + /** + * The foundation model used for orchestration by the agent. + */ + readonly foundationModel: IBedrockInvokable; + /** + * An existing IAM Role to associate with this agent. + * Use this property when you want to reuse an existing IAM role rather than create a new one. + * The role must have a trust policy that allows the Bedrock service to assume it. + * @default - A new role is created for you. + */ + readonly existingRole?: iam.IRole; + /** + * Specifies whether to automatically update the `DRAFT` version of the agent after + * making changes to the agent. The `DRAFT` version can be continually iterated + * upon during internal development. + * + * @default - false + */ + readonly shouldPrepareAgent?: boolean; + /** + * How long sessions should be kept open for the agent. If no conversation occurs + * during this time, the session expires and Amazon Bedrock deletes any data + * provided before the timeout. + * + * @default - 10 minutes + */ + readonly idleSessionTTL?: Duration; + /** + * The KMS key of the agent if custom encryption is configured. + * + * @default - An AWS managed key is used. + */ + readonly kmsKey?: kms.IKey; + /** + * A description of the agent. + * + * @default - No description is provided. + */ + readonly description?: string; + /** + * The Action Groups associated with the agent. + * @default - Only default action groups (UserInput and CodeInterpreter) are added + */ + readonly actionGroups?: AgentActionGroup[]; + + /** + * Overrides some prompt templates in different parts of an agent sequence configuration. + * + * @default - No overrides are provided. + */ + readonly promptOverrideConfiguration?: PromptOverrideConfiguration; + /** + * Select whether the agent can prompt additional information from the user when it does not have + * enough information to respond to an utterance + * + * @default - false + */ + readonly userInputEnabled?: boolean; + /** + * Select whether the agent can generate, run, and troubleshoot code when trying to complete a task + * + * @default - false + */ + readonly codeInterpreterEnabled?: boolean; + /** + * Whether to delete the resource even if it's in use. + * + * @default - false + */ + readonly forceDelete?: boolean; + /** + * The type and configuration of the memory to maintain context across multiple sessions and recall past interactions. + * This can be useful for maintaining continuity in multi-turn conversations and recalling user preferences + * or past interactions. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/agents-memory.html + * @default - No memory will be used. Agents will retain context from the current session only. + */ + readonly memory?: Memory; + /** + * Configuration for agent collaboration settings, including AgentCollaboratorType and AgentCollaborators. + * This property allows you to define how the agent collaborates with other agents + * and what collaborators it can work with. + * + * @default - No agent collaboration configuration. + */ + readonly agentCollaboration?: AgentCollaboration; + /** + * The Lambda function to use for custom orchestration. + * If provided, custom orchestration will be used. + * If not provided, default orchestration will be used. + * + * @default - Default orchestration + */ + readonly customOrchestrationExecutor?: CustomOrchestrationExecutor; +} +/****************************************************************************** + * ATTRS FOR IMPORTED CONSTRUCT + *****************************************************************************/ +/** + * Attributes for specifying an imported Bedrock Agent. + */ +export interface AgentAttributes { + /** + * The ARN of the agent. + * @attribute + */ + readonly agentArn: string; + /** + * The ARN of the IAM role associated to the agent. + * @attribute + */ + readonly roleArn: string; + /** + * Optional KMS encryption key associated with this agent + * @default undefined - An AWS managed key is used + */ + readonly kmsKeyArn?: string; + /** + * When this agent was last updated. + * @default undefined - No last updated timestamp is provided + */ + readonly lastUpdated?: string; + /** + * The agent version. If no explicit versions have been created, + * leave this empty to use the DRAFT version. Otherwise, use the + * version number (e.g. 1). + * @default 'DRAFT' + */ + readonly agentVersion?: string; +} +/****************************************************************************** + * NEW CONSTRUCT DEFINITION + *****************************************************************************/ +/** + * Class to create (or import) an Agent with CDK. + * @cloudformationResource AWS::Bedrock::Agent + */ +export class Agent extends AgentBase implements IAgent { + /** + * Static Method for importing an existing Bedrock Agent. + */ + /** + * Creates an Agent reference from an existing agent's attributes. + * + * @param scope - The construct scope + * @param id - Identifier of the construct + * @param attrs - Attributes of the existing agent + * @default - For attrs.agentVersion: 'DRAFT' if no explicit version is provided + * @returns An IAgent reference to the existing agent + */ + public static fromAgentAttributes(scope: Construct, id: string, attrs: AgentAttributes): IAgent { + class Import extends AgentBase { + public readonly agentArn = attrs.agentArn; + public readonly agentId = Arn.split(attrs.agentArn, ArnFormat.SLASH_RESOURCE_NAME).resourceName!; + public readonly role = iam.Role.fromRoleArn(scope, `${id}Role`, attrs.roleArn); + public readonly kmsKey = attrs.kmsKeyArn ? kms.Key.fromKeyArn(scope, `${id}Key`, attrs.kmsKeyArn) : undefined; + public readonly lastUpdated = attrs.lastUpdated; + public readonly agentVersion = attrs.agentVersion ?? 'DRAFT'; + public readonly grantPrincipal = this.role; + } + + // Return new Agent + return new Import(scope, id); + } + // ------------------------------------------------------ + // Base attributes + // ------------------------------------------------------ + /** + * The unique identifier for the agent + * @attribute + */ + public readonly agentId: string; + /** + * The ARN of the agent. + * @attribute + */ + public readonly agentArn: string; + /** + * The version of the agent. + * @attribute + */ + public readonly agentVersion: string; + /** + * The IAM role associated to the agent. + */ + public readonly role: iam.IRole; + /** + * Optional KMS encryption key associated with this agent + */ + public readonly kmsKey?: kms.IKey; + /** + * When this agent was last updated. + */ + public readonly lastUpdated?: string; + /** + * The principal to grant permissions to + */ + public readonly grantPrincipal: iam.IPrincipal; + /** + * Default alias of the agent + */ + public readonly testAlias: IAgentAlias; + /** + * action groups associated with the ageny + */ + public readonly actionGroups: AgentActionGroup[] = []; + // ------------------------------------------------------ + // CDK-only attributes + // ------------------------------------------------------ + /** + * The name of the agent. + */ + public readonly name: string; + + // ------------------------------------------------------ + // Internal Only + // ------------------------------------------------------ + private readonly ROLE_NAME_SUFFIX = '-bedrockagent'; + private readonly MAXLENGTH_FOR_ROLE_NAME = 64; + private readonly idleSessionTTL: Duration; + private readonly foundationModel: IBedrockInvokable; + private readonly userInputEnabled: boolean; + private readonly codeInterpreterEnabled: boolean; + private readonly agentCollaboration?: AgentCollaboration; + private readonly customOrchestrationExecutor?: CustomOrchestrationExecutor; + private readonly promptOverrideConfiguration?: PromptOverrideConfiguration; + private readonly __resource: bedrock.CfnAgent; + + // ------------------------------------------------------ + // CONSTRUCTOR + // ------------------------------------------------------ + constructor(scope: Construct, id: string, props: AgentProps) { + super(scope, id); + + // ------------------------------------------------------ + // Validate props + // ------------------------------------------------------ + if (props.instruction !== undefined && + !Token.isUnresolved(props.instruction) && + props.instruction.length < MIN_INSTRUCTION_LENGTH) { + throw new ValidationError(`instruction must be at least ${MIN_INSTRUCTION_LENGTH} characters`, this); + } + + // Validate idleSessionTTL + if (props.idleSessionTTL !== undefined && + !Token.isUnresolved(props.idleSessionTTL) && + (props.idleSessionTTL.toMinutes() < 1 || props.idleSessionTTL.toMinutes() > 60)) { + throw new ValidationError('idleSessionTTL must be between 1 and 60 minutes', this); + } + + // ------------------------------------------------------ + // Set properties and defaults + // ------------------------------------------------------ + this.name = + props.agentName ?? this.generatePhysicalName() + this.ROLE_NAME_SUFFIX; + this.idleSessionTTL = props.idleSessionTTL ?? Duration.minutes(10); + this.userInputEnabled = props.userInputEnabled ?? false; + this.codeInterpreterEnabled = props.codeInterpreterEnabled ?? false; + this.foundationModel = props.foundationModel; + // Optional + this.promptOverrideConfiguration = props.promptOverrideConfiguration; + this.kmsKey = props.kmsKey; + this.customOrchestrationExecutor = props.customOrchestrationExecutor; + + // ------------------------------------------------------ + // Role + // ------------------------------------------------------ + // If existing role is provided, use it. + if (props.existingRole) { + this.role = props.existingRole; + this.grantPrincipal = this.role; + // Otherwise, create a new one + } else { + this.role = new iam.Role(this, 'Role', { + // generate a role name + roleName: this.generatePhysicalName() + this.ROLE_NAME_SUFFIX, + // ensure the role has a trust policy that allows the Bedrock service to assume the role + assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com').withConditions({ + StringEquals: { + 'aws:SourceAccount': { Ref: 'AWS::AccountId' }, + }, + ArnLike: { + 'aws:SourceArn': Stack.of(this).formatArn({ + service: 'bedrock', + resource: 'agent', + resourceName: '*', + arnFormat: ArnFormat.SLASH_RESOURCE_NAME, + }), + }, + }), + }); + this.grantPrincipal = this.role; + } + // ------------------------------------------------------ + // Set Lazy Props initial values + // ------------------------------------------------------ + // Add Default Action Groups + this.addActionGroup(AgentActionGroup.userInput(this.userInputEnabled)); + this.addActionGroup(AgentActionGroup.codeInterpreter(this.codeInterpreterEnabled)); + + // Add specified elems through methods to handle permissions + // this needs to happen after role creation / assignment + props.actionGroups?.forEach(ag => { + this.addActionGroup(ag); + }); + + // Set agent collaboration configuration + this.agentCollaboration = props.agentCollaboration; + if (props.agentCollaboration) { + props.agentCollaboration.collaborators.forEach(ac => { + this.addAgentCollaborator(ac); + }); + } + + // Grant permissions for custom orchestration if provided + if (this.customOrchestrationExecutor?.lambdaFunction) { + this.customOrchestrationExecutor.lambdaFunction.grantInvoke(this.role); + this.customOrchestrationExecutor.lambdaFunction.addPermission(`OrchestrationLambdaInvocationPolicy-${this.node.addr.slice(0, MAX_POLICY_NAME_NODE_LENGTH)}`, { + principal: new iam.ServicePrincipal('bedrock.amazonaws.com'), + sourceArn: Lazy.string({ produce: () => this.agentArn }), + sourceAccount: { Ref: 'AWS::AccountId' } as any, + }); + } + + // ------------------------------------------------------ + // CFN Props - With Lazy support + // ------------------------------------------------------ + const cfnProps: bedrock.CfnAgentProps = { + actionGroups: Lazy.any({ produce: () => this.renderActionGroups() }, { omitEmptyArray: true }), + agentName: this.name, + agentResourceRoleArn: this.role.roleArn, + autoPrepare: props.shouldPrepareAgent ?? false, + customerEncryptionKeyArn: props.kmsKey?.keyArn, + description: props.description, + foundationModel: this.foundationModel.invokableArn, + idleSessionTtlInSeconds: this.idleSessionTTL.toSeconds(), + instruction: props.instruction, + memoryConfiguration: props.memory?._render(), + promptOverrideConfiguration: this.promptOverrideConfiguration?._render(), + skipResourceInUseCheckOnDelete: props.forceDelete ?? false, + agentCollaboration: props.agentCollaboration?.type, + agentCollaborators: Lazy.any({ produce: () => this.renderAgentCollaborators() }, { omitEmptyArray: true }), + customOrchestration: this.renderCustomOrchestration(), + orchestrationType: this.customOrchestrationExecutor ? OrchestrationType.CUSTOM_ORCHESTRATION : OrchestrationType.DEFAULT, + }; + + // ------------------------------------------------------ + // L1 Instantiation + // ------------------------------------------------------ + this.__resource = new bedrock.CfnAgent(this, 'Resource', cfnProps); + + this.agentId = this.__resource.attrAgentId; + this.agentArn = this.__resource.attrAgentArn; + this.agentVersion = this.__resource.attrAgentVersion; + this.lastUpdated = this.__resource.attrUpdatedAt; + + // Add explicit dependency between the agent resource and the agent's role default policy + // See https://github.com/awslabs/generative-ai-cdk-constructs/issues/899 + if (!props.existingRole) { + // add the appropriate permissions to use the FM + const grant = this.foundationModel.grantInvoke(this.role); + grant.applyBefore(this.__resource); + } + + this.testAlias = AgentAlias.fromAttributes(this, 'DefaultAlias', { + aliasId: 'TSTALIASID', + aliasName: 'AgentTestAlias', + agentVersion: 'DRAFT', + agent: this, + }); + } + + // ------------------------------------------------------ + // HELPER METHODS - addX() + // ------------------------------------------------------ + + /** + * Adds an action group to the agent and configures necessary permissions. + * + * @param actionGroup - The action group to add + * @default - Default permissions: + * - Lambda function invoke permissions if executor is present + * - S3 GetObject permissions if apiSchema.s3File is present + */ + public addActionGroup(actionGroup: AgentActionGroup) { + validation.throwIfInvalid(this.validateActionGroup, actionGroup); + this.actionGroups.push(actionGroup); + // Handle permissions to invoke the lambda function + actionGroup.executor?.lambdaFunction?.grantInvoke(this.role); + actionGroup.executor?.lambdaFunction?.addPermission(`LambdaInvocationPolicy-${this.node.addr.slice(0, MAX_POLICY_NAME_NODE_LENGTH)}`, { + principal: new iam.ServicePrincipal('bedrock.amazonaws.com'), + sourceArn: this.agentArn, + sourceAccount: { Ref: 'AWS::AccountId' } as any, + }); + // Handle permissions to access the schema file from S3 + if (actionGroup.apiSchema instanceof AssetApiSchema) { + const rendered = actionGroup.apiSchema._render(); + if (!('s3' in rendered) || !rendered.s3) { + throw new ValidationError('S3 configuration is missing in AssetApiSchema', this); + } + const s3Config = rendered.s3; + if (!('s3BucketName' in s3Config) || !('s3ObjectKey' in s3Config)) { + throw new ValidationError('S3 bucket name and object key are required in AssetApiSchema', this); + } + const bucketName = s3Config.s3BucketName; + const objectKey = s3Config.s3ObjectKey; + if (!bucketName || bucketName.trim() === '') { + throw new ValidationError('S3 bucket name cannot be empty in AssetApiSchema', this); + } + if (!objectKey || objectKey.trim() === '') { + throw new ValidationError('S3 object key cannot be empty in AssetApiSchema', this); + } + const bucket = s3.Bucket.fromBucketName(this, `${actionGroup.name}SchemaBucket`, bucketName); + bucket.grantRead(this.role, objectKey); + } else if (actionGroup.apiSchema instanceof S3ApiSchema) { + const s3File = actionGroup.apiSchema.s3File; + if (!s3File) { + throw new ValidationError('S3 file configuration is missing in S3ApiSchema', this); + } + if (!s3File.bucketName || s3File.bucketName.trim() === '') { + throw new ValidationError('S3 bucket name cannot be empty in S3ApiSchema', this); + } + if (!s3File.objectKey || s3File.objectKey.trim() === '') { + throw new ValidationError('S3 object key cannot be empty in S3ApiSchema', this); + } + const bucket = s3.Bucket.fromBucketName(this, `${actionGroup.name}SchemaBucket`, s3File.bucketName); + bucket.grantRead(this.role, s3File.objectKey); + } + } + + /** + * Adds a collaborator to the agent and grants necessary permissions. + * @param agentCollaborator - The collaborator to add + * @internal This method is used internally by the constructor and should not be called directly. + */ + private addAgentCollaborator(agentCollaborator: AgentCollaborator) { + agentCollaborator.grant(this.role); + } + + /** + * Configuration for agent collaboration. + * + * @default - No collaboration configuration. + */ + public addActionGroups(...actionGroups: AgentActionGroup[]) { + actionGroups.forEach(ag => this.addActionGroup(ag)); + } + + // ------------------------------------------------------ + // Lazy Renderers + // ------------------------------------------------------ + + /** + * Render the action groups + * + * @returns Array of AgentActionGroupProperty objects in CloudFormation format + * @default - Empty array if no action groups are defined + * @internal This is an internal core function and should not be called directly. + */ + private renderActionGroups(): bedrock.CfnAgent.AgentActionGroupProperty[] { + const actionGroupsCfn: bedrock.CfnAgent.AgentActionGroupProperty[] = []; + // Build the associations in the CFN format + this.actionGroups.forEach(ag => { + actionGroupsCfn.push(ag._render()); + }); + return actionGroupsCfn; + } + + /** + * Render the agent collaborators. + * + * @returns Array of AgentCollaboratorProperty objects in CloudFormation format, or undefined if no collaborators + * @default - undefined if no collaborators are defined or array is empty + * @internal This is an internal core function and should not be called directly. + */ + private renderAgentCollaborators(): bedrock.CfnAgent.AgentCollaboratorProperty[] | undefined { + if (!this.agentCollaboration) { + return undefined; + } + + return this.agentCollaboration.collaborators.map(ac => ac._render()); + } + + /** + * Render the custom orchestration. + * + * @returns CustomOrchestrationProperty object in CloudFormation format, or undefined if no custom orchestration + * @default - undefined if no custom orchestration is defined + * @internal This is an internal core function and should not be called directly. + */ + private renderCustomOrchestration(): bedrock.CfnAgent.CustomOrchestrationProperty | undefined { + if (!this.customOrchestrationExecutor) { + return undefined; + } + + return { + executor: { + lambda: this.customOrchestrationExecutor.lambdaFunction.functionArn, + }, + }; + } + + // ------------------------------------------------------ + // Validators + // ------------------------------------------------------ + /** + * Check if the action group is valid + * + * @param actionGroup - The action group to validate + * @returns Array of validation error messages, empty if valid + */ + private validateActionGroup = (actionGroup: AgentActionGroup) => { + let errors: string[] = []; + // Find if there is a conflicting action group name + if (this.actionGroups?.find(ag => ag.name === actionGroup.name)) { + errors.push('Action group already exists'); + } + return errors; + }; + + /** + * Generates a unique, deterministic name for AWS resources that includes a hash component. + * This method ensures consistent naming while avoiding conflicts and adhering to AWS naming constraints. + * @param scope - The construct scope used for generating unique names + * @param prefix - The prefix to prepend to the generated name + * @param options - Configuration options for name generation + * @param options.maxLength - Maximum length of the generated name + * @default - maxLength: 256 + * @param options.lower - Convert the generated name to lowercase + * @default - lower: false + * @param options.separator - Character(s) to use between name components + * @default - separator: '' + * @param options.allowedSpecialCharacters - String of allowed special characters + * @default - undefined + * @param options.destroyCreate - Object to include in hash generation for destroy/create operations + * @default - undefined + * @returns A string containing the generated name with format: prefix + hash + separator + uniqueName + * @throws ValidationError if the generated name would exceed maxLength or if prefix is too long + * @internal + */ + private generatePhysicalNameHash( + scope: IConstruct, + prefix: string, + options?: { + maxLength?: number; + lower?: boolean; + separator?: string; + allowedSpecialCharacters?: string; + destroyCreate?: any; + }, + ): string { + const objectToHash = (obj: any): string => { + if (obj === undefined) { return ''; } + const jsonString = JSON.stringify(obj); + const hash = crypto.createHash('sha256'); + return hash.update(jsonString).digest('hex').slice(0, 7); + }; + + const { + maxLength = 256, + lower = false, + separator = '', + allowedSpecialCharacters = undefined, + destroyCreate = undefined, + } = options ?? {}; + + const hash = objectToHash(destroyCreate); + if (maxLength < (prefix + hash + separator).length) { + throw new ValidationError('The prefix is longer than the maximum length.', this); + } + + const uniqueName = Names.uniqueResourceName( + scope, + { maxLength: maxLength - (prefix + hash + separator).length, separator, allowedSpecialCharacters }, + ); + const name = `${prefix}${hash}${separator}${uniqueName}`; + if (name.length > maxLength) { + throw new ValidationError(`The generated name is longer than the maximum length of ${maxLength}`, this); + } + return lower ? name.toLowerCase() : name; + } + + /** + * Generates a physical name for the agent. + * @returns A unique name for the agent with appropriate length constraints + * @default - Generated name format: 'agent-{hash}-{uniqueName}' with: + * - maxLength: MAXLENGTH_FOR_ROLE_NAME - '-bedrockagent'.length + * - lower: true + * - separator: '-' + * @protected + */ + protected generatePhysicalName(): string { + const maxLength = this.MAXLENGTH_FOR_ROLE_NAME - this.ROLE_NAME_SUFFIX.length; + return this.generatePhysicalNameHash(this, 'agent', { + maxLength, + lower: true, + separator: '-', + }); + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/api-executor.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/api-executor.ts new file mode 100644 index 0000000000000..fca764685c072 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/api-executor.ts @@ -0,0 +1,74 @@ +import * as bedrock from 'aws-cdk-lib/aws-bedrock'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; +import { ValidationError } from './validation-helpers'; + +/** + * The type of custom control for the action group executor. + */ +export enum CustomControl { + /** + * Returns the action group invocation results directly in the InvokeAgent response. + */ + RETURN_CONTROL = 'RETURN_CONTROL', +} + +/****************************************************************************** + * Action Group Executor + *****************************************************************************/ +/** + * Defines how fulfillment of the action group is handled after the necessary + * information has been elicited from the user. + * Valid executors are: + * - Lambda function + * - Return Control + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/action-handle.html + */ +export class ActionGroupExecutor { + /** + * Returns the action group invocation results directly in the InvokeAgent response. + * The information and parameters can be sent to your own systems to yield results. + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/agents-returncontrol.html + */ + public static readonly RETURN_CONTROL = new ActionGroupExecutor(undefined, CustomControl.RETURN_CONTROL); + + /** + * Defines an action group with a Lambda function containing the business logic. + * @param lambdaFunction - Lambda function to be called by the action group. + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html + */ + public static fromLambda(lambdaFunction: IFunction): ActionGroupExecutor { + return new ActionGroupExecutor(lambdaFunction, undefined); + } + + /** + * The Lambda function that will be called by the action group. + * Contains the business logic for handling the action group's invocation. + */ + public readonly lambdaFunction?: IFunction; + + /** + * The custom control type for the action group executor. + * Currently only supports 'RETURN_CONTROL' which returns results directly in the InvokeAgent response. + */ + public readonly customControl?: CustomControl; + + private constructor(lambdaFunction?: IFunction, customControl?: CustomControl) { + if (lambdaFunction && customControl) { + throw new ValidationError('ActionGroupExecutor cannot have both lambdaFunction and customControl defined - they are mutually exclusive.'); + } + this.lambdaFunction = lambdaFunction; + this.customControl = customControl; + } + + /** + * Format as CFN properties + * + * @internal This is an internal core function and should not be called directly. + */ + public _render(): bedrock.CfnAgent.ActionGroupExecutorProperty { + return { + customControl: this.customControl, + lambda: this.lambdaFunction?.functionArn, + }; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/api-schema.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/api-schema.ts new file mode 100644 index 0000000000000..b64d139327142 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/api-schema.ts @@ -0,0 +1,168 @@ +import { Construct } from 'constructs'; +import * as s3_assets from 'aws-cdk-lib/aws-s3-assets'; +import { CfnAgent } from 'aws-cdk-lib/aws-bedrock'; +import { IBucket, Location } from 'aws-cdk-lib/aws-s3'; +import { ActionGroupSchema } from './schema-base'; + +/** + * Error thrown when an ApiSchema is not properly initialized. + */ +class ApiSchemaError extends Error { + constructor(message: string, public readonly cause?: string) { + super(message); + this.name = 'ApiSchemaError'; + } +} + +/****************************************************************************** + * API SCHEMA CLASS + *****************************************************************************/ +/** + * Represents the concept of an API Schema for a Bedrock Agent Action Group. + */ +export abstract class ApiSchema extends ActionGroupSchema { + /** + * Creates an API Schema from a local file. + * @param path - the path to the local file containing the OpenAPI schema for the action group + */ + public static fromLocalAsset(path: string): AssetApiSchema { + return new AssetApiSchema(path); + } + + /** + * Creates an API Schema from an inline string. + * @param schema - the JSON or YAML payload defining the OpenAPI schema for the action group + */ + public static fromInline(schema: string): InlineApiSchema { + return new InlineApiSchema(schema); + } + + /** + * Creates an API Schema from an S3 File + * @param bucket - the bucket containing the local file containing the OpenAPI schema for the action group + * @param objectKey - object key in the bucket + */ + public static fromS3File(bucket: IBucket, objectKey: string): S3ApiSchema { + return new S3ApiSchema({ + bucketName: bucket.bucketName, + objectKey: objectKey, + }); + } + + /** + * The S3 location of the API schema file, if using an S3-based schema. + * Contains the bucket name and object key information. + */ + public readonly s3File?: Location; + + /** + * The inline OpenAPI schema definition as a string, if using an inline schema. + * Can be in JSON or YAML format. + */ + public readonly inlineSchema?: string; + + protected constructor(s3File?: Location, inlineSchema?: string) { + super(); + this.s3File = s3File; + this.inlineSchema = inlineSchema; + } + + /** + * Format as CFN properties + * + * @internal This is an internal core function and should not be called directly. + */ + public abstract _render(): CfnAgent.APISchemaProperty; +} + +/** + * API Schema from a local asset. + * + * The asset is uploaded to an S3 staging bucket, then moved to its final location + * by CloudFormation during deployment. + */ +export class AssetApiSchema extends ApiSchema { + private asset?: s3_assets.Asset; + + constructor(private readonly path: string, private readonly options: s3_assets.AssetOptions = {}) { + super(); + } + + /** + * Binds this API schema to a construct scope. + * This method initializes the S3 asset if it hasn't been initialized yet. + * Must be called before rendering the schema as CFN properties. + * + * @param scope - The construct scope to bind to + */ + public bind(scope: Construct): void { + // If the same AssetApiSchema is used multiple times, retain only the first instantiation + if (!this.asset) { + this.asset = new s3_assets.Asset(scope, 'Schema', { + path: this.path, + ...this.options, + }); + // Note: Permissions will be granted by the Agent construct when adding the action group + } + } + + /** + * Format as CFN properties + * @internal This is an internal core function and should not be called directly. + */ + public _render(): CfnAgent.APISchemaProperty { + if (!this.asset) { + throw new ApiSchemaError('ApiSchema must be bound to a scope before rendering. Call bind() first.', 'Asset not initialized'); + } + + return { + s3: { + s3BucketName: this.asset.s3BucketName, + s3ObjectKey: this.asset.s3ObjectKey, + }, + }; + } +} + +// ------------------------------------------------------ +/** + * Class to define an API Schema from an inline string. + * The schema can be provided directly as a string in either JSON or YAML format. + */ +export class InlineApiSchema extends ApiSchema { + constructor(private readonly schema: string) { + super(undefined, schema); + } + + /** + * @internal This is an internal core function and should not be called directly. + */ + public _render(): CfnAgent.APISchemaProperty { + return { + payload: this.schema, + }; + } +} + +// ------------------------------------------------------ +// S3 File +// ------------------------------------------------------ +/** + * Class to define an API Schema from an S3 object. + */ +export class S3ApiSchema extends ApiSchema { + constructor(private readonly location: Location) { + super(location, undefined); + } + /** + * @internal This is an internal core function and should not be called directly. + */ + public _render(): CfnAgent.APISchemaProperty { + return { + s3: { + s3BucketName: this.location.bucketName, + s3ObjectKey: this.location.objectKey, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/function-schema.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/function-schema.ts new file mode 100644 index 0000000000000..5f5fbab75c8d9 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/function-schema.ts @@ -0,0 +1,289 @@ +import { CfnAgent } from 'aws-cdk-lib/aws-bedrock'; +import * as validation from './validation-helpers'; +import { ActionGroupSchema } from './schema-base'; + +/** + * Enum for parameter types in function schemas + */ +export enum ParameterType { + /** + * String parameter type + */ + STRING = 'string', + + /** + * Number parameter type + */ + NUMBER = 'number', + + /** + * Integer parameter type + */ + INTEGER = 'integer', + + /** + * Boolean parameter type + */ + BOOLEAN = 'boolean', + + /** + * Array parameter type + */ + ARRAY = 'array', + + /** + * Object parameter type + */ + OBJECT = 'object', +} + +/** + * Enum for require confirmation state in function schemas + */ +export enum RequireConfirmation { + /** + * Confirmation is enabled + */ + ENABLED = 'ENABLED', + + /** + * Confirmation is disabled + */ + DISABLED = 'DISABLED', +} + +/** + * Properties for a function parameter + */ +export interface FunctionParameterProps { + /** + * The type of the parameter + */ + readonly type: ParameterType; + + /** + * Whether the parameter is required + * @default true + */ + readonly required?: boolean; + + /** + * Description of the parameter + * @default undefined no description will be present + */ + readonly description?: string; +} + +/** + * Properties for a function in a function schema + */ +export interface FunctionProps { + /** + * The name of the function + */ + readonly name: string; + + /** + * Description of the function + */ + readonly description: string; + + /** + * Parameters for the function as a record of parameter name to parameter properties + * @default {} + */ + readonly parameters?: Record; + + /** + * Whether to require confirmation before executing the function + * @default RequireConfirmation.DISABLED + */ + readonly requireConfirmation?: RequireConfirmation; +} + +/** + * Properties for a function schema + */ +export interface FunctionSchemaProps { + /** + * Functions defined in the schema + */ + readonly functions: FunctionProps[]; +} + +/** + * Represents a function parameter in a function schema + */ +export class FunctionParameter { + /** + * The type of the parameter + */ + public readonly type: ParameterType; + + /** + * Whether the parameter is required + */ + public readonly required: boolean; + + /** + * Description of the parameter + * @default undefined no description will be present + */ + public readonly description?: string; + + constructor(props: FunctionParameterProps) { + // Validate description if provided + if (props.description) { + const descErrors = validation.validateStringFieldLength({ + fieldName: 'parameter description', + value: props.description, + minLength: 1, + maxLength: 500, + }); + + if (descErrors.length > 0) { + throw new validation.ValidationError(descErrors.join('\n')); + } + } + + this.type = props.type; + this.required = props.required ?? true; + this.description = props.description; + } + + /** + * Render the parameter as a CloudFormation property + * @internal + */ + public _render(): any { + return { + type: this.type, + required: this.required, + description: this.description, + }; + } +} + +/** + * Represents a function in a function schema + */ +export class Function { + /** + * The name of the function + */ + public readonly name: string; + + /** + * Description of the function + */ + public readonly description: string; + + /** + * Parameters for the function + */ + public readonly parameters: Record; + + /** + * Whether to require confirmation before executing the function + */ + public readonly requireConfirmation: RequireConfirmation; + + constructor(props: FunctionProps) { + // Validate function name + const nameErrors = validation.validateStringFieldLength({ + fieldName: 'function name', + value: props.name, + minLength: 1, + maxLength: 100, + }); + + if (nameErrors.length > 0) { + throw new validation.ValidationError(nameErrors.join('\n')); + } + + // Validate function description + const descErrors = validation.validateStringFieldLength({ + fieldName: 'function description', + value: props.description, + minLength: 1, + maxLength: 500, + }); + + if (descErrors.length > 0) { + throw new validation.ValidationError(descErrors.join('\n')); + } + + this.name = props.name; + this.description = props.description; + + // Convert parameters object to a record of FunctionParameter instances + this.parameters = {}; + if (props.parameters) { + Object.entries(props.parameters).forEach(([name, paramProps]) => { + // Validate parameter name + const paramNameErrors = validation.validateStringFieldLength({ + fieldName: 'parameter name', + value: name, + minLength: 1, + maxLength: 100, + }); + + if (paramNameErrors.length > 0) { + throw new validation.ValidationError(paramNameErrors.join('\n')); + } + + this.parameters[name] = new FunctionParameter(paramProps); + }); + } + + this.requireConfirmation = props.requireConfirmation ?? RequireConfirmation.DISABLED; + } + + /** + * Render the function as a CloudFormation property + * @internal + */ + public _render(): any { + const parametersObj: Record = {}; + + Object.entries(this.parameters).forEach(([name, param]) => { + parametersObj[name] = param._render(); + }); + return { + name: this.name, + description: this.description, + parameters: parametersObj, + requireConfirmation: this.requireConfirmation, + }; + } +} + +/** + * Represents a function schema for a Bedrock Agent Action Group + */ +export class FunctionSchema extends ActionGroupSchema { + /** + * The functions defined in the schema + */ + public readonly functions: Function[]; + + constructor(props: FunctionSchemaProps) { + super(); + + if (!props.functions || props.functions.length === 0) { + throw new validation.ValidationError('At least one function must be defined in the function schema'); + } + + this.functions = props.functions.map(f => new Function(f)); + } + + /** + * Render the function schema as a CloudFormation property + * @internal + */ + public _render(): CfnAgent.FunctionSchemaProperty { + return { + functions: this.functions.map(f => f._render()), + }; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/memory.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/memory.ts new file mode 100644 index 0000000000000..e25822a1226a5 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/memory.ts @@ -0,0 +1,107 @@ +import { Duration } from 'aws-cdk-lib/core'; +import { CfnAgent } from 'aws-cdk-lib/aws-bedrock'; +import * as validation from './validation-helpers'; + +/** + * Memory options for agent conversational context retention. + * Memory enables agents to maintain context across multiple sessions and recall past interactions. + * By default, agents retain context from the current session only. + */ +enum MemoryType { + /** + * Your agent uses memory summarization to enhance accuracy using + * advanced prompt templates in Amazon Bedrock to call the foundation model with guidelines + * to summarize all your sessions. You can optionally modify the default prompt template + * or provide your own custom parser to parse model output. + * + * Since the summarization process takes place in an asynchronous flow after a session ends, + * logs for any failures in summarization due to overridden template or parser will be + * published to your AWS accounts. For more information on enabling the logging, see + * Enable memory summarization log delivery. + */ + SESSION_SUMMARY = 'SESSION_SUMMARY', +} + +/** + * Properties for SessionSummaryConfiguration. + */ +export interface SessionSummaryMemoryProps { + /** + * Duration for which session summaries are retained (between 1 and 365 days) + * @default Duration.days(30) + */ + readonly memoryDuration?: Duration; + + /** + * Maximum number of recent session summaries to include (min 1) + * @default 20 + */ + readonly maxRecentSessions?: number; +} + +/** + * Memory class for managing Bedrock Agent memory configurations. Enables conversational context retention + * across multiple sessions through session identifiers. Memory context is stored with unique + * memory IDs per user, allowing access to conversation history and summaries. Supports viewing + * stored sessions and clearing memory. + * + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/agents-memory.html + */ +export class Memory { + /** + * Returns session summary memory with default configuration. + * @default memoryDuration=Duration.days(30), maxRecentSessions=20 + */ + public static readonly SESSION_SUMMARY = new Memory({ memoryDuration: Duration.days(30), maxRecentSessions: 20 }); + + /** + * Creates a session summary memory with custom configuration. + * @param props Optional memory configuration properties + * @returns Memory instance + */ + public static sessionSummary(props: SessionSummaryMemoryProps): Memory { + return new Memory(props); + } + + private readonly memoryDuration?: Duration; + private readonly maxRecentSessions?: number; + + constructor(props: SessionSummaryMemoryProps) { + // Validate props + validation.throwIfInvalid((config: SessionSummaryMemoryProps) => { + let errors: string[] = []; + + // Validate memory duration is between 1 and 365 days + if (config.memoryDuration !== undefined) { + const days = config.memoryDuration.toDays(); + if (days < 1 || days > 365) { + errors.push('memoryDuration must be between 1 and 365 days'); + } + } + if (config.maxRecentSessions !== undefined) { + if (config.maxRecentSessions < 1) { + errors.push('maxRecentSessions must be greater than 0'); + } + } + + return errors; + }, props); + + this.memoryDuration = props.memoryDuration; + this.maxRecentSessions = props.maxRecentSessions; + } + + /** + * Render the memory configuration to a CloudFormation property. + * @internal + */ + public _render(): CfnAgent.MemoryConfigurationProperty { + return { + enabledMemoryTypes: [MemoryType.SESSION_SUMMARY], + storageDays: this.memoryDuration?.toDays() ?? 30, + sessionSummaryConfiguration: { + maxRecentSessions: this.maxRecentSessions ?? 20, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/orchestration-executor.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/orchestration-executor.ts new file mode 100644 index 0000000000000..6342fe37f39be --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/orchestration-executor.ts @@ -0,0 +1,60 @@ +import * as bedrock from 'aws-cdk-lib/aws-bedrock'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; + +/** + * Enum for orchestration types available for agents. + */ +export enum OrchestrationType { + /** + * Default orchestration by the agent. + */ + DEFAULT = 'DEFAULT', + + /** + * Custom orchestration using Lambda. + */ + CUSTOM_ORCHESTRATION = 'CUSTOM_ORCHESTRATION', +} + +/****************************************************************************** + * Custom Orchestration Executor + *****************************************************************************/ +/** + * Contains details about the Lambda function containing the orchestration logic carried + * out upon invoking the custom orchestration. + */ +export class CustomOrchestrationExecutor { + /** + * Defines an orchestration executor with a Lambda function containing the business logic. + * @param lambdaFunction - Lambda function to be called by the orchestration. + */ + public static fromLambda(lambdaFunction: IFunction): CustomOrchestrationExecutor { + return new CustomOrchestrationExecutor(lambdaFunction); + } + + /** + * The type of orchestration this executor performs. + */ + public readonly type: OrchestrationType = OrchestrationType.CUSTOM_ORCHESTRATION; + + /** + * The Lambda function that contains the custom orchestration logic. + * This function is called when the agent needs to make decisions about action execution. + */ + public readonly lambdaFunction: IFunction; + + private constructor(lambdaFunction: IFunction) { + this.lambdaFunction = lambdaFunction; + } + + /** + * Format as CFN properties + * + * @internal This is an internal core function and should not be called directly. + */ + public _render(): bedrock.CfnAgent.OrchestrationExecutorProperty { + return { + lambda: this.lambdaFunction?.functionArn, + }; + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/prompt-override.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/prompt-override.ts new file mode 100644 index 0000000000000..54637a46075d3 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/prompt-override.ts @@ -0,0 +1,473 @@ +import { CfnAgent } from 'aws-cdk-lib/aws-bedrock'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; +import * as validation from './validation-helpers'; +import { IBedrockInvokable } from '../models'; + +/** + * The step in the agent sequence that this prompt configuration applies to. + */ +export enum AgentStepType { + /** + * Pre-processing step that prepares the user input for orchestration. + */ + PRE_PROCESSING = 'PRE_PROCESSING', + + /** + * Main orchestration step that determines the agent's actions. + */ + ORCHESTRATION = 'ORCHESTRATION', + + /** + * Post-processing step that refines the agent's response. + */ + POST_PROCESSING = 'POST_PROCESSING', + + /** + * Step that classifies and routes requests to appropriate collaborators. + */ + ROUTING_CLASSIFIER = 'ROUTING_CLASSIFIER', + + /** + * Step that summarizes conversation history for memory retention. + */ + MEMORY_SUMMARIZATION = 'MEMORY_SUMMARIZATION', + + /** + * Step that generates responses using knowledge base content. + */ + KNOWLEDGE_BASE_RESPONSE_GENERATION = 'KNOWLEDGE_BASE_RESPONSE_GENERATION', +} + +/** + * LLM inference configuration + */ +export interface InferenceConfiguration { + /** + * The likelihood of the model selecting higher-probability options while + * generating a response. A lower value makes the model more likely to choose + * higher-probability options, while a higher value makes the model more + * likely to choose lower-probability options. + * + * Floating point + * + * min 0 + * max 1 + */ + readonly temperature: number; + /** + * While generating a response, the model determines the probability of the + * following token at each point of generation. The value that you set for + * Top P determines the number of most-likely candidates from which the model + * chooses the next token in the sequence. For example, if you set topP to + * 80, the model only selects the next token from the top 80% of the + * probability distribution of next tokens. + * + * Floating point + * + * min 0 + * max 1 + */ + readonly topP: number; + /** + * While generating a response, the model determines the probability of the + * following token at each point of generation. The value that you set for + * topK is the number of most-likely candidates from which the model chooses + * the next token in the sequence. For example, if you set topK to 50, the + * model selects the next token from among the top 50 most likely choices. + * + * Integer + * + * min 0 + * max 500 + */ + readonly topK: number; + /** + * A list of stop sequences. A stop sequence is a sequence of characters that + * causes the model to stop generating the response. + * + * length 0-4 + */ + readonly stopSequences: string[]; + /** + * The maximum number of tokens to generate in the response. + * + * Integer + * + * min 0 + * max 4096 + */ + readonly maximumLength: number; +} + +/** + * Base configuration interface for all prompt step types + */ +export interface PromptStepConfigBase { + /** + * The type of step this configuration applies to. + */ + readonly stepType: AgentStepType; + + /** + * Whether to enable or skip this step in the agent sequence. + * @default - The default state for each step type is as follows. + * + * PRE_PROCESSING – ENABLED + * ORCHESTRATION – ENABLED + * KNOWLEDGE_BASE_RESPONSE_GENERATION – ENABLED + * POST_PROCESSING – DISABLED + */ + readonly stepEnabled?: boolean; + + /** + * The custom prompt template to be used. + * + * @default - The default prompt template will be used. + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-placeholders.html + */ + readonly customPromptTemplate?: string; + + /** + * The inference configuration parameters to use. + * @default undefined - Default inference configuration will be used + */ + readonly inferenceConfig?: InferenceConfiguration; + + /** + * Whether to use the custom Lambda parser defined for the sequence. + * + * @default - false + */ + readonly useCustomParser?: boolean; +} + +/** + * Configuration for the pre-processing step + */ +export interface PromptPreProcessingConfigCustomParser extends PromptStepConfigBase {} + +/** + * Configuration for the orchestration step + */ +export interface PromptOrchestrationConfigCustomParser extends PromptStepConfigBase {} + +/** + * Configuration for the post-processing step + */ +export interface PromptPostProcessingConfigCustomParser extends PromptStepConfigBase {} + +/** + * Configuration for the routing classifier step + */ +export interface PromptRoutingClassifierConfigCustomParser extends PromptStepConfigBase { + /** + * The foundation model to use for the routing classifier step. + * This is required for the routing classifier step. + */ + readonly foundationModel: IBedrockInvokable; +} + +/** + * Configuration for the memory summarization step + */ +export interface PromptMemorySummarizationConfigCustomParser extends PromptStepConfigBase {} + +/** + * Configuration for the knowledge base response generation step + */ +export interface PromptKnowledgeBaseResponseGenerationConfigCustomParser extends PromptStepConfigBase {} + +/** + * Properties for configuring a custom Lambda parser for prompt overrides. + */ +export interface CustomParserProps { + /** + * Lambda function to use as custom parser. + * @default undefined - No custom parser is used + */ + readonly parser?: IFunction; + + /** + * Configuration for the pre-processing step. + * @default undefined - No pre-processing configuration + */ + readonly preProcessingStep?: PromptPreProcessingConfigCustomParser; + + /** + * Configuration for the orchestration step. + * @default undefined - No orchestration configuration + */ + readonly orchestrationStep?: PromptOrchestrationConfigCustomParser; + + /** + * Configuration for the post-processing step. + * @default undefined - No post-processing configuration + */ + readonly postProcessingStep?: PromptPostProcessingConfigCustomParser; + + /** + * Configuration for the routing classifier step. + * @default undefined - No routing classifier configuration + */ + readonly routingClassifierStep?: PromptRoutingClassifierConfigCustomParser; + + /** + * Configuration for the memory summarization step. + * @default undefined - No memory summarization configuration + */ + readonly memorySummarizationStep?: PromptMemorySummarizationConfigCustomParser; + + /** + * Configuration for the knowledge base response generation step. + * @default undefined - No knowledge base response generation configuration + */ + readonly knowledgeBaseResponseGenerationStep?: PromptKnowledgeBaseResponseGenerationConfigCustomParser; +} + +/** + * Configuration for overriding prompt templates and behaviors in different parts + * of an agent's sequence. This allows customizing how the agent processes inputs, + * makes decisions, and generates responses. + */ +export class PromptOverrideConfiguration { + /** + * Creates a PromptOverrideConfiguration from individual step configurations. + * Use this method when you want to override prompts without using a custom parser. + * @param steps The step configurations to use + * @returns A new PromptOverrideConfiguration instance + */ + public static fromSteps(steps: PromptStepConfigBase[]): PromptOverrideConfiguration { + if (!steps || steps.length === 0) { + throw new validation.ValidationError('Steps array cannot be empty'); + } + + // Convert steps array to props format + const stepMap = steps.reduce((acc, step) => { + switch (step.stepType) { + case AgentStepType.PRE_PROCESSING: + return { ...acc, preProcessingStep: step }; + case AgentStepType.ORCHESTRATION: + return { ...acc, orchestrationStep: step }; + case AgentStepType.POST_PROCESSING: + return { ...acc, postProcessingStep: step }; + case AgentStepType.ROUTING_CLASSIFIER: + return { ...acc, routingClassifierStep: step as PromptRoutingClassifierConfigCustomParser }; + case AgentStepType.MEMORY_SUMMARIZATION: + return { ...acc, memorySummarizationStep: step }; + case AgentStepType.KNOWLEDGE_BASE_RESPONSE_GENERATION: + return { ...acc, knowledgeBaseResponseGenerationStep: step }; + default: + return acc; + } + }, {} as CustomParserProps); + + return new PromptOverrideConfiguration(stepMap); + } + + /** + * Creates a PromptOverrideConfiguration with a custom Lambda parser function. + * @param props Configuration including: + * - `parser`: Lambda function to use as custom parser + * - Individual step configurations. At least one of the steps must make use of the custom parser. + */ + public static withCustomParser(props: CustomParserProps): PromptOverrideConfiguration { + return new PromptOverrideConfiguration(props); + } + + /** + * The custom Lambda parser function to use. + * The Lambda parser processes and interprets the raw foundation model output. + * It receives an input event with: + * - messageVersion: Version of message format (1.0) + * - agent: Info about the agent (name, id, alias, version) + * - invokeModelRawResponse: Raw model output to parse + * - promptType: Type of prompt being parsed + * - overrideType: Type of override (OUTPUT_PARSER) + * + * The Lambda must return a response that the agent uses for next actions. + * @see https://docs.aws.amazon.com/bedrock/latest/userguide/lambda-parser.html + */ + readonly parser?: IFunction; + + /** + * Configuration for the pre-processing step. + */ + readonly preProcessingStep?: PromptPreProcessingConfigCustomParser; + + /** + * Configuration for the orchestration step. + */ + readonly orchestrationStep?: PromptOrchestrationConfigCustomParser; + + /** + * Configuration for the post-processing step. + */ + readonly postProcessingStep?: PromptPostProcessingConfigCustomParser; + + /** + * Configuration for the routing classifier step. + */ + readonly routingClassifierStep?: PromptRoutingClassifierConfigCustomParser; + + /** + * Configuration for the memory summarization step. + */ + readonly memorySummarizationStep?: PromptMemorySummarizationConfigCustomParser; + + /** + * Configuration for the knowledge base response generation step. + */ + readonly knowledgeBaseResponseGenerationStep?: PromptKnowledgeBaseResponseGenerationConfigCustomParser; + + /** + * Create a new PromptOverrideConfiguration. + * + * @internal - This is marked as private so end users leverage it only through static methods + */ + private constructor(props: CustomParserProps) { + // Validate props + validation.throwIfInvalid(this.validateSteps, props); + if (props.parser) { + validation.throwIfInvalid(this.validateCustomParser, props); + } + this.parser = props.parser; + this.preProcessingStep = props.preProcessingStep; + this.orchestrationStep = props.orchestrationStep; + this.postProcessingStep = props.postProcessingStep; + this.routingClassifierStep = props.routingClassifierStep; + this.memorySummarizationStep = props.memorySummarizationStep; + this.knowledgeBaseResponseGenerationStep = props.knowledgeBaseResponseGenerationStep; + } + + /** + * Format as CfnAgent.PromptOverrideConfigurationProperty + * + * @internal This is an internal core function and should not be called directly. + */ + public _render(): CfnAgent.PromptOverrideConfigurationProperty { + const configurations: CfnAgent.PromptConfigurationProperty[] = []; + + // Helper function to add configuration if step exists + const addConfiguration = (step: PromptStepConfigBase | undefined, type: AgentStepType) => { + if (step) { + configurations.push({ + promptType: type, + promptState: step.stepEnabled === undefined ? undefined : step.stepEnabled ? 'ENABLED' : 'DISABLED', + parserMode: step.useCustomParser === undefined ? undefined : step.useCustomParser ? 'OVERRIDDEN' : 'DEFAULT', + promptCreationMode: step.customPromptTemplate === undefined ? undefined : step.customPromptTemplate ? 'OVERRIDDEN' : 'DEFAULT', + basePromptTemplate: step.customPromptTemplate, + inferenceConfiguration: step.inferenceConfig, + // Include foundation model if it's a routing classifier step + foundationModel: type === AgentStepType.ROUTING_CLASSIFIER + ? (step as PromptRoutingClassifierConfigCustomParser).foundationModel?.invokableArn + : undefined, + }); + } + }; + + // Add configurations for each step type if defined + addConfiguration(this.preProcessingStep, AgentStepType.PRE_PROCESSING); + addConfiguration(this.orchestrationStep, AgentStepType.ORCHESTRATION); + addConfiguration(this.postProcessingStep, AgentStepType.POST_PROCESSING); + addConfiguration(this.routingClassifierStep, AgentStepType.ROUTING_CLASSIFIER); + addConfiguration(this.memorySummarizationStep, AgentStepType.MEMORY_SUMMARIZATION); + addConfiguration(this.knowledgeBaseResponseGenerationStep, AgentStepType.KNOWLEDGE_BASE_RESPONSE_GENERATION); + + return { + overrideLambda: this.parser?.functionArn, + promptConfigurations: configurations, + }; + } + + private validateInferenceConfig = (config?: InferenceConfiguration): string[] => { + const errors: string[] = []; + if (config) { + if (config.temperature < 0 || config.temperature > 1) { + errors.push('Temperature must be between 0 and 1'); + } + if (config.topP < 0 || config.topP > 1) { + errors.push('TopP must be between 0 and 1'); + } + if (config.topK < 0 || config.topK > 500) { + errors.push('TopK must be between 0 and 500'); + } + if (config.stopSequences.length > 4) { + errors.push('Maximum 4 stop sequences allowed'); + } + if (config.maximumLength < 0 || config.maximumLength > 4096) { + errors.push('MaximumLength must be between 0 and 4096'); + } + } + return errors; + }; + + private validateSteps = (props: CustomParserProps): string[] => { + const errors: string[] = []; + + // Check if any steps are defined + const hasSteps = [ + props.preProcessingStep, + props.orchestrationStep, + props.postProcessingStep, + props.routingClassifierStep, + props.memorySummarizationStep, + props.knowledgeBaseResponseGenerationStep, + ].some(step => step !== undefined); + + if (!hasSteps) { + errors.push('Steps array cannot be empty'); + } + + // Helper function to validate a step's inference config + const validateStep = (step: PromptStepConfigBase | undefined, stepName: string) => { + if (step) { + // Check for foundation model in non-ROUTING_CLASSIFIER steps + if ('foundationModel' in step && step.stepType !== AgentStepType.ROUTING_CLASSIFIER) { + errors.push('Foundation model can only be specified for ROUTING_CLASSIFIER step type'); + } + + const inferenceErrors = this.validateInferenceConfig(step.inferenceConfig); + if (inferenceErrors.length > 0) { + errors.push(`${stepName} step: ${inferenceErrors.join(', ')}`); + } + } + }; + + // Validate each step's inference config + validateStep(props.preProcessingStep, 'Pre-processing'); + validateStep(props.orchestrationStep, 'Orchestration'); + validateStep(props.postProcessingStep, 'Post-processing'); + validateStep(props.routingClassifierStep, 'Routing classifier'); + validateStep(props.memorySummarizationStep, 'Memory summarization'); + validateStep(props.knowledgeBaseResponseGenerationStep, 'Knowledge base response generation'); + + // Validate routing classifier's foundation model if provided + if (props.routingClassifierStep?.foundationModel) { + if (!props.routingClassifierStep.foundationModel.invokableArn) { + errors.push('Foundation model must be a valid IBedrockInvokable with an invokableArn'); + } + } + + return errors; + }; + + private validateCustomParser = (props: CustomParserProps): string[] => { + const errors: string[] = []; + + // Check if at least one step uses custom parser + const hasCustomParser = [ + props.preProcessingStep?.useCustomParser, + props.orchestrationStep?.useCustomParser, + props.postProcessingStep?.useCustomParser, + props.routingClassifierStep?.useCustomParser, + props.memorySummarizationStep?.useCustomParser, + props.knowledgeBaseResponseGenerationStep?.useCustomParser, + ].some(useCustomParser => useCustomParser === true); + + if (!hasCustomParser) { + errors.push('At least one step must use custom parser'); + } + + return errors; + }; +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/schema-base.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/schema-base.ts new file mode 100644 index 0000000000000..df1a7382a7a4b --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/schema-base.ts @@ -0,0 +1,13 @@ +/** + * Base abstract class for all schema types used in Bedrock Agent Action Groups. + * This provides a common interface for both API schemas and function schemas. + * @internal + */ +export abstract class ActionGroupSchema { + /** + * Format as CFN properties + * + * @internal This is an internal core function and should not be called directly. + */ + public abstract _render(): any; +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/utils.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/utils.ts new file mode 100644 index 0000000000000..06216ed9a2eaa --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/utils.ts @@ -0,0 +1,200 @@ +import { createHash } from 'crypto'; +import * as cdk from 'aws-cdk-lib'; +import { IConstruct } from 'constructs'; +import { ValidationError } from 'aws-cdk-lib'; + +/** + * The CFN NAG suppress rule interface + * @interface CfnNagSuppressRule + */ +export interface CfnNagSuppressRule { + readonly id: string; + readonly reason: string; +} + +/** + * The version of this package + */ +// eslint-disable-next-line @typescript-eslint/no-require-imports +export const version = require('../../../package.json').version; +/** + * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. + * + * @summary Creates a physical resource name in the style of the CDK (string+hash) - this value incorporates Stack ID, + * so it will remain static in multiple updates of a single stack, but will be different in a separate stack instance + * @param {IConstruct} scope - the CDK scope of the resource + * @param {string} prefix - the prefix for the name + * @param {string[]} parts - the various string components of the name (eg - stackName, solutions construct ID, L2 construct ID) + * @param {number} maxLength - the longest string that can be returned + * @returns {string} - a string with concatenated parts (truncated if necessary) + a hash of the full concatenated parts + * + * @deprecated This function is deprecated and will be removed in a future major version. + * Please use the new function generatePhysicalNameV2 instead. + */ +export function generatePhysicalName( + scope: IConstruct, + prefix: string, + parts: string[], + maxLength: number, +): string { + // The result will consist of: + // -The prefix - unaltered + // -The parts concatenated, but reduced in size to meet the maxLength limit for the overall name + // -A hyphen delimiter + // -The GUID portion of the stack arn + + const stackIdGuidLength = 36; + const prefixLength = prefix.length; + const maxPartsLength = maxLength - prefixLength - 1 - stackIdGuidLength; // 1 is the hyphen + + // Extract the Stack ID Guid + const uniqueStackIdPart = cdk.Fn.select(2, cdk.Fn.split('/', `${cdk.Aws.STACK_ID}`)); + + let allParts: string = ''; + + parts.forEach((part) => { + allParts += part; + }); + + if (allParts.length > maxPartsLength) { + const subStringLength = maxPartsLength / 2; + allParts = allParts.substring(0, subStringLength) + allParts.substring(allParts.length - subStringLength); + } + + if (prefix.length + allParts.length + stackIdGuidLength + 1 /* hyphen */ > maxLength) { + throw new ValidationError(`The generated name is longer than the maximum length of ${maxLength}`, scope); + } + + return prefix.toLowerCase() + allParts + '-' + uniqueStackIdPart; +} + +export interface GeneratePhysicalNameV2Options extends cdk.UniqueResourceNameOptions { + /** + * Whether to convert the name to lower case. + * + * @default false + */ + lower?: boolean; + + /** + * This object is hashed for uniqueness and can force a destroy instead of a replace. + * @default: undefined + */ + destroyCreate?: any; +} +/** + * @internal This is an internal core function and should not be called directly by Solutions Constructs clients. + * + * @summary Creates a physical resource name in the style of the CDK (string+hash) - this value incorporates + * the Stack Name and node ID, so it will remain static in multiple updates of a single stack, but will be + * different in a separate stack instance. + * + * This new version allows for names shorter than 36 characters with control over casing. + * + * The minimum length is the length of the prefix and separator plus 10. + */ +export function generatePhysicalNameV2( + /** + * The CDK scope of the resource. + */ + scope: IConstruct, + /** + * The prefix for the name. + */ + prefix: string, + /** + * Options for generating the name. + */ + options?: GeneratePhysicalNameV2Options, +): string { + function objectToHash(obj: any): string { + // Nothing to hash if undefined + if (obj === undefined) { return ''; } + + // Convert the object to a JSON string + const jsonString = JSON.stringify(obj); + + // Create a SHA-256 hash + const hash = createHash('sha256'); + + // Update the hash with the JSON string and get the digest in hexadecimal format + // Shorten it (modeled after seven characters like git commit hash shortening) + return hash.update(jsonString).digest('hex').slice(0, 7); + } + const { + maxLength = 256, + lower = false, + separator = '', + allowedSpecialCharacters = undefined, + destroyCreate = undefined, + } = options ?? {}; + const hash = objectToHash(destroyCreate); + if (maxLength < (prefix + hash + separator).length) { + throw new ValidationError(`The prefix length (${prefix.length}) plus hash length (${hash.length}) and separator length (${separator.length}) exceeds the maximum allowed length of ${maxLength}`, scope); + } + const uniqueName = cdk.Names.uniqueResourceName( + scope, + { maxLength: maxLength - (prefix + hash + separator).length, separator, allowedSpecialCharacters }, + ); + const name = `${prefix}${hash}${separator}${uniqueName}`; + if (name.length > maxLength) { + throw new ValidationError(`The generated name is longer than the maximum length of ${maxLength}`, scope); + } + return lower ? name.toLowerCase() : name; +} + +export const maximumLambdaMemorySizeContextItem = 'maximumLambdaMemorySize'; +export const recommendedMaximumLambdaMemorySize = 7076; +export function lambdaMemorySizeLimiter(construct: IConstruct, requestedMemorySizeInMegabytes: number) { + const maximumLambdaMemorySize = construct.node.tryGetContext(maximumLambdaMemorySizeContextItem) === undefined ? + recommendedMaximumLambdaMemorySize : + parseInt(construct.node.tryGetContext(maximumLambdaMemorySizeContextItem)); + if (maximumLambdaMemorySize < recommendedMaximumLambdaMemorySize) { + cdk.Annotations.of(construct).addWarning( + `Maximum Lambda memorySize, ${maximumLambdaMemorySize}, is less than the recommended ${recommendedMaximumLambdaMemorySize}.`, + ); + } + if (requestedMemorySizeInMegabytes > maximumLambdaMemorySize) { + cdk.Annotations.of(construct).addWarning( + `Reducing Lambda memorySize, ${requestedMemorySizeInMegabytes} to ${maximumLambdaMemorySize} for ${construct.constructor.name}`, + ); + return maximumLambdaMemorySize; + } else { + return requestedMemorySizeInMegabytes; + } +} + +/** + * Adds CFN NAG suppress rules to the CDK resource. + * @param resource The CDK resource + * @param rules The CFN NAG suppress rules + */ +export function addCfnSuppressRules(resource: cdk.Resource | cdk.CfnResource, rules: CfnNagSuppressRule[]) { + if (resource instanceof cdk.Resource) { + resource = resource.node.defaultChild as cdk.CfnResource; + } + + if (resource.cfnOptions.metadata?.cfn_nag?.rules_to_suppress) { + resource.cfnOptions.metadata?.cfn_nag.rules_to_suppress.push(...rules); + } else { + resource.addMetadata('cfn_nag', { + rules_to_suppress: rules, + }); + } +} + +function isObject(val: object) { + return val !== null && typeof val === 'object' && !Array.isArray(val); +} + +export function isPlainObject(o: object) { + if (!isObject(o)) return false; + + if (Object.getPrototypeOf(o) === null) return true; + + let proto = o; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + return Object.getPrototypeOf(o) === proto; +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/validation-helpers.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/validation-helpers.ts new file mode 100644 index 0000000000000..34a7bcd40b5f3 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/agents/validation-helpers.ts @@ -0,0 +1,98 @@ +import { Token } from 'aws-cdk-lib'; + +/** + * Error thrown when validation fails + */ +export class ValidationError extends Error { + constructor(message: string) { + super(message); + this.name = 'ValidationError'; + } +} +interface IntervalValidation { + fieldName: string; + minLength: number; + maxLength: number; +} + +interface StringLengthValidation extends IntervalValidation { + value: string; +} + +/** + * Validates the length of a string field against minimum and maximum constraints. + * @param value - The string value to validate + * @param fieldName - Name of the field being validated (for error messages) + * @param minLength - Minimum allowed length (defaults to 0) + * @param maxLength - Maximum allowed length + * @returns true if validation passes + * @throws Error if validation fails with current length information + */ +export function validateStringFieldLength(params: StringLengthValidation): string[] { + const currentLength = params.value.length; + const errors: string[] = []; + + // Evaluate only if it is not an unresolved Token + if (!Token.isUnresolved(params.fieldName)) { + if (params.value.length > params.maxLength) { + errors.push( + `The field ${params.fieldName} is ${currentLength} characters long but must be less than or equal to ${params.maxLength} characters`, + ); + } + + if (params.value.length < params.minLength) { + errors.push( + `The field ${params.fieldName} is ${currentLength} characters long but must be at least ${params.minLength} characters`, + ); + } + } + + return errors; +} + +/** + * Validates a string field against a regex pattern. + * @param value - The string value to validate + * @param fieldName - Name of the field being validated (for error messages) + * @param pattern - Regular expression pattern to test against + * @param customMessage - Optional custom error message + * @returns true if validation passes + * @throws Error if validation fails with detailed message + */ +export function validateFieldPattern( + value: string, + fieldName: string, + pattern: RegExp, + customMessage?: string, +): string[] { + const errors: string[] = []; + // Evaluate only if it is not an unresolved Token + if (!Token.isUnresolved(value)) { + // Verify type + if (typeof value !== 'string') { + errors.push(`Expected string for ${fieldName}, got ${typeof value}`); + } + // Validate specified regex + if (!(pattern instanceof RegExp)) { + errors.push('Pattern must be a valid regular expression'); + } + + // Pattern validation + if (!pattern.test(value)) { + const defaultMessage = `The field ${fieldName} with value "${value}" does not match the required pattern ${pattern}`; + errors.push(customMessage || defaultMessage); + } + } + + return errors; +} + +export type ValidationFn = (param: T) => string[]; + +export function throwIfInvalid(validationFn: ValidationFn, param: T): T { + const errors = validationFn(param); + if (errors.length > 0) { + throw new ValidationError(errors.join('\n')); + } + return param; +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/index.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/index.ts new file mode 100644 index 0000000000000..7cd458e3713d9 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/index.ts @@ -0,0 +1,15 @@ +// =================================== +// Agents +// =================================== +export * from './agents/action-group'; +export * from './agents/agent'; +export * from './agents/agent-alias'; +export * from './agents/api-executor'; +export * from './agents/api-schema'; +export * from './agents/prompt-override'; +export * from './agents/memory'; +export * from './agents/agent-collaborator'; +export * from './agents/agent-collaboration'; +export * from './agents/orchestration-executor'; +export * from './models'; +export * from './agents/function-schema'; diff --git a/packages/@aws-cdk/aws-bedrock-alpha/bedrock/models.ts b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/models.ts new file mode 100644 index 0000000000000..a9969e16f7686 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/bedrock/models.ts @@ -0,0 +1,961 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +import { Arn, ArnFormat, Aws } from 'aws-cdk-lib'; +import { IModel, FoundationModel, FoundationModelIdentifier } from 'aws-cdk-lib/aws-bedrock'; +import { Grant, IGrantable } from 'aws-cdk-lib/aws-iam'; + +/** + * The data type for the vectors when using a model to convert text into vector embeddings. + * The model must support the specified data type for vector embeddings. Floating-point (float32) + * is the default data type, and is supported by most models for vector embeddings. See Supported + * embeddings models for information on the available models and their vector data types. + */ +export enum VectorType { + /** + * `FLOATING_POINT` convert the data to floating-point (float32) vector embeddings (more precise, but more costly). + */ + FLOATING_POINT = 'FLOAT32', + /** + * `BINARY` convert the data to binary vector embeddings (less precise, but less costly). + */ + BINARY = 'BINARY', +} + +/** + * Represents an Amazon Bedrock abstraction on which you can + * run the `Invoke` API. This can be a Foundational Model, + * a Custom Model, or an Inference Profile. + */ +export interface IBedrockInvokable { + /** + * The ARN of the Bedrock invokable abstraction. + */ + readonly invokableArn: string; + + /** + * Gives the appropriate policies to invoke and use the invokable abstraction. + */ + grantInvoke(grantee: IGrantable): Grant; +} + +/** + * Properties for configuring a Bedrock Foundation Model. + * These properties define the model's capabilities and supported features. + */ +export interface BedrockFoundationModelProps { + /** + * Bedrock Agents can use this model. + * When true, the model can be used with Bedrock Agents for automated task execution. + * + * @default - false + */ + readonly supportsAgents?: boolean; + + /** + * Currently, some of the offered models are optimized with prompts/parsers fine-tuned for integrating with the agents architecture. + * When true, the model has been specifically optimized for agent interactions. + * + * @default - false + */ + readonly optimizedForAgents?: boolean; + + /** + * https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html + * A version is marked Legacy when there is a more recent version which provides superior performance. + * Amazon Bedrock sets an EOL date for Legacy versions. + * + * @default - false + */ + readonly legacy?: boolean; + + /** + * Bedrock Knowledge Base can use this model. + * When true, the model can be used for knowledge base operations. + * + * @default - false + */ + readonly supportsKnowledgeBase?: boolean; + + /** + * Can be used with a Cross-Region Inference Profile. + * When true, the model supports inference across different AWS regions. + * + * @default - false + */ + readonly supportsCrossRegion?: boolean; + + /** + * Embedding models have different vector dimensions. + * Only applicable for embedding models. Defines the dimensionality of the vector embeddings. + * + * @default - undefined + */ + readonly vectorDimensions?: number; + + /** + * Embeddings models have different supported vector types. + * Defines whether the model supports floating-point or binary vectors. + * + * @default - undefined + */ + readonly supportedVectorType?: VectorType[]; +} + +/** + * Bedrock models. + * + * If you need to use a model name that doesn't exist as a static member, you + * can instantiate a `BedrockFoundationModel` object, e.g: `new BedrockFoundationModel('my-model')`. + */ +export class BedrockFoundationModel implements IBedrockInvokable { + /**************************************************************************** + * AI21 + ***************************************************************************/ + + /** + * AI21's Jamba 1.5 Large model optimized for text generation tasks. + * Suitable for complex language understanding and generation tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Optimized for natural language processing + * - Best for: Content generation, summarization, and complex text analysis + */ + public static readonly AI21_JAMBA_1_5_LARGE_V1 = new BedrockFoundationModel( + 'ai21.jamba-1-5-large-v1:0', + { + supportsAgents: true, + }, + ); + + /** + * AI21's Jamba 1.5 Mini model, a lighter version optimized for faster processing. + * Balances performance with efficiency for general text tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Faster response times compared to larger models + * - Best for: Quick text processing, basic content generation + */ + public static readonly AI21_JAMBA_1_5_MINI_V1 = new BedrockFoundationModel( + 'ai21.jamba-1-5-mini-v1:0', + { + supportsAgents: true, + }, + ); + + /** + * AI21's Jamba Instruct model, specifically designed for instruction-following tasks. + * Optimized for understanding and executing specific instructions. + * + * Features: + * - Supports Bedrock Agents integration + * - Enhanced instruction understanding + * - Best for: Task-specific instructions, command processing + */ + public static readonly AI21_JAMBA_INSTRUCT_V1 = new BedrockFoundationModel( + 'ai21.jamba-instruct-v1:0', + { + supportsAgents: true, + }, + ); + /**************************************************************************** + * AMAZON + ***************************************************************************/ + + /** + * Amazon's Titan Text Express model, optimized for fast text generation. + * Provides quick responses while maintaining good quality output. + * + * Features: + * - Supports Bedrock Agents integration + * - Fast response times + * - Best for: Real-time applications, chatbots, quick content generation + */ + public static readonly AMAZON_TITAN_TEXT_EXPRESS_V1 = new BedrockFoundationModel( + 'amazon.titan-text-express-v1', + { + supportsAgents: true, + }, + ); + + /** + * Amazon's Titan Text Premier model, designed for high-quality text generation. + * Offers enhanced capabilities for complex language tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Advanced language understanding + * - Best for: Complex content generation, detailed analysis + */ + public static readonly AMAZON_TITAN_PREMIER_V1_0 = new BedrockFoundationModel( + 'amazon.titan-text-premier-v1:0', + { + supportsAgents: true, + }, + ); + + /** + * Amazon's Nova Micro model, a lightweight model optimized for efficiency. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: Quick processing tasks, basic language understanding + */ + public static readonly AMAZON_NOVA_MICRO_V1 = new BedrockFoundationModel( + 'amazon.nova-micro-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + optimizedForAgents: true, + }, + ); + + /** + * Amazon's Nova Lite model, balancing performance with efficiency. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: General-purpose language tasks, moderate complexity + */ + public static readonly AMAZON_NOVA_LITE_V1 = new BedrockFoundationModel('amazon.nova-lite-v1:0', { + supportsAgents: true, + supportsCrossRegion: true, + optimizedForAgents: true, + }); + + /** + * Amazon's Nova Pro model, offering advanced capabilities for complex tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: Complex language tasks, professional applications + */ + public static readonly AMAZON_NOVA_PRO_V1 = new BedrockFoundationModel('amazon.nova-pro-v1:0', { + supportsAgents: true, + supportsCrossRegion: true, + optimizedForAgents: true, + }); + + /** + * Amazon's Nova Premier model, the most advanced in the Nova series. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: High-end applications, complex analysis, premium performance + */ + public static readonly AMAZON_NOVA_PREMIER_V1 = new BedrockFoundationModel('amazon.nova-premier-v1:0', { + supportsAgents: true, + supportsCrossRegion: true, + optimizedForAgents: true, + }); + + /** + * Amazon's Titan Embed Text V1 model for text embeddings. + * + * Features: + * - Supports Knowledge Base integration + * - 1536-dimensional vectors + * - Floating-point vector type + * - Best for: Text embeddings, semantic search, document similarity + */ + public static readonly TITAN_EMBED_TEXT_V1 = new BedrockFoundationModel( + 'amazon.titan-embed-text-v1', + { + supportsKnowledgeBase: true, + vectorDimensions: 1536, + supportedVectorType: [VectorType.FLOATING_POINT], + }, + ); + + /** + * Amazon's Titan Embed Text V2 model with 1024-dimensional vectors. + * + * Features: + * - Supports Knowledge Base integration + * - 1024-dimensional vectors + * - Supports both floating-point and binary vectors + * - Best for: High-dimensional embeddings, advanced semantic search + */ + public static readonly TITAN_EMBED_TEXT_V2_1024 = new BedrockFoundationModel( + 'amazon.titan-embed-text-v2:0', + { + supportsKnowledgeBase: true, + vectorDimensions: 1024, + supportedVectorType: [VectorType.FLOATING_POINT, VectorType.BINARY], + }, + ); + + /** + * Amazon's Titan Embed Text V2 model with 512-dimensional vectors. + * + * Features: + * - Supports Knowledge Base integration + * - 512-dimensional vectors + * - Supports both floating-point and binary vectors + * - Best for: Balanced performance and dimensionality + */ + public static readonly TITAN_EMBED_TEXT_V2_512 = new BedrockFoundationModel( + 'amazon.titan-embed-text-v2:0', + { + supportsKnowledgeBase: true, + vectorDimensions: 512, + supportedVectorType: [VectorType.FLOATING_POINT, VectorType.BINARY], + }, + ); + + /** + * Amazon's Titan Embed Text V2 model with 256-dimensional vectors. + * + * Features: + * - Supports Knowledge Base integration + * - 256-dimensional vectors + * - Supports both floating-point and binary vectors + * - Best for: Efficient embeddings with lower dimensionality + */ + public static readonly TITAN_EMBED_TEXT_V2_256 = new BedrockFoundationModel( + 'amazon.titan-embed-text-v2:0', + { + supportsKnowledgeBase: true, + vectorDimensions: 256, + supportedVectorType: [VectorType.FLOATING_POINT, VectorType.BINARY], + }, + ); + /**************************************************************************** + * ANTHROPIC + ***************************************************************************/ + + /** + * Anthropic's Claude 3.7 Sonnet model, latest in the Claude 3 series. + * Advanced language model with enhanced capabilities. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Complex reasoning, analysis, and content generation + */ + public static readonly ANTHROPIC_CLAUDE_3_7_SONNET_V1_0 = new BedrockFoundationModel( + 'anthropic.claude-3-7-sonnet-20250219-v1:0', + + { supportsAgents: true, supportsCrossRegion: true, optimizedForAgents: false }, + ); + + /** + * Anthropic's Claude 3.5 Sonnet V2 model, optimized for agent interactions. + * Enhanced version with improved performance and capabilities. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: Agent-based applications, complex dialogue + */ + public static readonly ANTHROPIC_CLAUDE_3_5_SONNET_V2_0 = new BedrockFoundationModel( + 'anthropic.claude-3-5-sonnet-20241022-v2:0', + { supportsAgents: true, supportsCrossRegion: true, optimizedForAgents: true }, + ); + + /** + * Anthropic's Claude 3.5 Sonnet V1 model, balanced performance model. + * Offers good balance between performance and efficiency. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: General language tasks, balanced performance + */ + public static readonly ANTHROPIC_CLAUDE_3_5_SONNET_V1_0 = new BedrockFoundationModel( + 'anthropic.claude-3-5-sonnet-20240620-v1:0', + { supportsAgents: true, supportsCrossRegion: true, optimizedForAgents: true }, + ); + + /** + * Anthropic's Claude 3.5 Haiku model, optimized for quick responses. + * Lightweight model focused on speed and efficiency. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: Fast responses, lightweight processing + */ + public static readonly ANTHROPIC_CLAUDE_3_5_HAIKU_V1_0 = new BedrockFoundationModel( + 'anthropic.claude-3-5-haiku-20241022-v1:0', + { supportsAgents: true, supportsCrossRegion: true, optimizedForAgents: true }, + ); + + /** + * Anthropic's Claude Opus model, designed for advanced tasks. + * High-performance model with extensive capabilities. + * + * Features: + * - Supports Bedrock Agents integration + * - Optimized for agents + * - Best for: Complex reasoning, research, and analysis + */ + public static readonly ANTHROPIC_CLAUDE_OPUS_V1_0 = new BedrockFoundationModel( + 'anthropic.claude-3-opus-20240229-v1:0', + { supportsAgents: true, optimizedForAgents: true }, + ); + + /** + * Anthropic's Claude Sonnet model, legacy version. + * Balanced model for general-purpose tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Legacy model with EOL date + * - Best for: General language tasks, standard applications + */ + public static readonly ANTHROPIC_CLAUDE_SONNET_V1_0 = new BedrockFoundationModel( + 'anthropic.claude-3-sonnet-20240229-v1:0', + { supportsAgents: true, supportsCrossRegion: true, legacy: true, optimizedForAgents: true }, + ); + + /** + * Anthropic's Claude Haiku model, optimized for efficiency. + * Fast and efficient model for lightweight tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Optimized for agents + * - Best for: Quick responses, simple tasks + */ + public static readonly ANTHROPIC_CLAUDE_HAIKU_V1_0 = new BedrockFoundationModel( + 'anthropic.claude-3-haiku-20240307-v1:0', + { supportsAgents: true, supportsCrossRegion: true, optimizedForAgents: true }, + ); + + /** + * Anthropic's Claude V2.1 model, legacy version. + * Improved version of Claude V2 with enhanced capabilities. + * + * Features: + * - Supports Bedrock Agents integration + * - Legacy model with EOL date + * - Optimized for agents + * - Best for: General language tasks, legacy applications + */ + public static readonly ANTHROPIC_CLAUDE_V2_1 = new BedrockFoundationModel( + 'anthropic.claude-v2:1', + { + supportsAgents: true, + legacy: true, + optimizedForAgents: true, + }, + ); + + /** + * Anthropic's Claude V2 model, legacy version. + * Original Claude V2 model with broad capabilities. + * + * Features: + * - Supports Bedrock Agents integration + * - Legacy model with EOL date + * - Optimized for agents + * - Best for: General language tasks, legacy applications + */ + public static readonly ANTHROPIC_CLAUDE_V2 = new BedrockFoundationModel('anthropic.claude-v2', { + supportsAgents: true, + legacy: true, + optimizedForAgents: true, + }); + + /** + * Anthropic's Claude Instant V1.2 model, legacy version. + * Fast and efficient model optimized for quick responses. + * + * Features: + * - Supports Bedrock Agents integration + * - Legacy model with EOL date + * - Optimized for agents + * - Best for: Quick responses, simple tasks, legacy applications + */ + public static readonly ANTHROPIC_CLAUDE_INSTANT_V1_2 = new BedrockFoundationModel( + 'anthropic.claude-instant-v1', + { + supportsAgents: true, + legacy: true, + optimizedForAgents: true, + }, + ); + + /**************************************************************************** + * COHERE + ***************************************************************************/ + + /** + * Cohere's English embedding model, optimized for English text embeddings. + * Specialized for semantic understanding of English content. + * + * Features: + * - Supports Knowledge Base integration + * - 1024-dimensional vectors + * - Supports both floating-point and binary vectors + * - Best for: English text embeddings, semantic search, content similarity + */ + public static readonly COHERE_EMBED_ENGLISH_V3 = new BedrockFoundationModel( + 'cohere.embed-english-v3', + { + supportsKnowledgeBase: true, + vectorDimensions: 1024, + supportedVectorType: [VectorType.FLOATING_POINT, VectorType.BINARY], + }, + ); + + /** + * Cohere's Multilingual embedding model, supporting multiple languages. + * Enables semantic understanding across different languages. + * + * Features: + * - Supports Knowledge Base integration + * - 1024-dimensional vectors + * - Supports both floating-point and binary vectors + * - Best for: Cross-lingual embeddings, multilingual semantic search + */ + public static readonly COHERE_EMBED_MULTILINGUAL_V3 = new BedrockFoundationModel( + 'cohere.embed-multilingual-v3', + { + supportsKnowledgeBase: true, + vectorDimensions: 1024, + supportedVectorType: [VectorType.FLOATING_POINT, VectorType.BINARY], + }, + ); + /**************************************************************************** + * DEEPSEEK + ***************************************************************************/ + + /** + * Deepseek's R1 model, designed for general language understanding. + * Balanced model for various language tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: General language tasks, content generation + */ + public static readonly DEEPSEEK_R1_V1 = new BedrockFoundationModel('deepseek.r1-v1:0', { + supportsAgents: true, + supportsCrossRegion: true, + }); + + /**************************************************************************** + * META + ***************************************************************************/ + + /** + * Meta's Llama 3 1.8B Instruct model, compact instruction-following model. + * Efficient model optimized for instruction-based tasks. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Lightweight instruction processing, quick responses + */ + public static readonly META_LLAMA_3_1_8B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama3-1-8b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + + /** + * Meta's Llama 3 70B Instruct model, large-scale instruction model. + * High-capacity model for complex language understanding. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Complex instructions, advanced language tasks + */ + public static readonly META_LLAMA_3_1_70B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama3-1-70b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + + /** + * Meta's Llama 3.2 11B Instruct model, mid-sized instruction model. + * Balanced model for general instruction processing. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: General instruction tasks, balanced performance + */ + public static readonly META_LLAMA_3_2_11B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama3-2-11b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + + /** + * Meta's Llama 3.2 3B Instruct model, compact efficient model. + * Lightweight model for basic instruction processing. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Basic instructions, efficient processing + */ + public static readonly META_LLAMA_3_2_3B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama3-2-3b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + + /** + * Meta's Llama 3.2 1B Instruct model, ultra-lightweight model. + * Most compact model in the Llama 3.2 series. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Simple instructions, fastest response times + */ + public static readonly META_LLAMA_3_2_1B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama3-2-1b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + + /** + * Meta's Llama 3.3 70B Instruct model, latest large-scale model. + * Advanced model with enhanced capabilities. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Complex reasoning, advanced language tasks + */ + public static readonly META_LLAMA_3_3_70B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama3-3-70b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + + /** + * Meta's Llama 4 Maverick 17B Instruct model, innovative mid-sized model. + * Specialized for creative and dynamic responses. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Creative tasks, innovative solutions + */ + public static readonly META_LLAMA_4_MAVERICK_17B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama4-maverick-17b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + + /** + * Meta's Llama 4 Scout 17B Instruct model, analytical mid-sized model. + * Focused on precise and analytical responses. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Analytical tasks, precise responses + */ + public static readonly META_LLAMA_4_SCOUT_17B_INSTRUCT_V1 = new BedrockFoundationModel( + 'meta.llama4-scout-17b-instruct-v1:0', + { + supportsAgents: true, + supportsCrossRegion: true, + }, + ); + /**************************************************************************** + * MISTRAL AI + ***************************************************************************/ + + /** + * Mistral's 7B Instruct model, efficient instruction-following model. + * Balanced performance for instruction processing. + * + * Features: + * - Supports Bedrock Agents integration + * - Optimized for instruction tasks + * - Best for: General instruction processing, balanced performance + */ + public static readonly MISTRAL_7B_INSTRUCT_V0 = new BedrockFoundationModel( + 'mistral.mistral-7b-instruct-v0:2', + { + supportsAgents: true, + optimizedForAgents: false, + supportsCrossRegion: false, + }, + ); + + /** + * Mistral's Mixtral 8x7B Instruct model, mixture-of-experts architecture. + * Advanced model combining multiple expert networks. + * + * Features: + * - Supports Bedrock Agents integration + * - Specialized expert networks + * - Best for: Complex tasks, diverse language understanding + */ + public static readonly MISTRAL_MIXTRAL_8X7B_INSTRUCT_V0 = new BedrockFoundationModel( + 'mistral.mixtral-8x7b-instruct-v0:1', + { + supportsAgents: true, + optimizedForAgents: false, + supportsCrossRegion: false, + }, + ); + + /** + * Mistral's Small 2402 model, compact efficient model. + * Optimized for quick responses and efficiency. + * + * Features: + * - Supports Bedrock Agents integration + * - Efficient processing + * - Best for: Quick responses, basic language tasks + */ + public static readonly MISTRAL_SMALL_2402_V1 = new BedrockFoundationModel( + 'mistral.mistral-small-2402-v1:0', + { + supportsAgents: true, + optimizedForAgents: false, + supportsCrossRegion: false, + }, + ); + + /** + * Mistral's Large 2402 model, high-capacity language model. + * Advanced model for complex language understanding. + * + * Features: + * - Supports Bedrock Agents integration + * - Enhanced language capabilities + * - Best for: Complex reasoning, detailed analysis + */ + public static readonly MISTRAL_LARGE_2402_V1 = new BedrockFoundationModel( + 'mistral.mistral-large-2402-v1:0', + { + supportsAgents: true, + optimizedForAgents: false, + supportsCrossRegion: false, + }, + ); + + /** + * Mistral's Large 2407 model, updated large-scale model. + * Enhanced version with improved capabilities. + * + * Features: + * - Supports Bedrock Agents integration + * - Advanced language processing + * - Best for: Sophisticated language tasks, complex analysis + */ + public static readonly MISTRAL_LARGE_2407_V1 = new BedrockFoundationModel( + 'mistral.mistral-large-2407-v1:0', + { + supportsAgents: true, + optimizedForAgents: false, + supportsCrossRegion: false, + }, + ); + + /** + * Mistral's Pixtral Large 2502 model, specialized large model. + * Advanced model with cross-region support. + * + * Features: + * - Supports Bedrock Agents integration + * - Cross-region support + * - Best for: Advanced language tasks, distributed applications + */ + public static readonly MISTRAL_PIXTRAL_LARGE_2502_V1 = new BedrockFoundationModel( + 'mistral.pixtral-large-2502-v1:0', + { + supportsAgents: true, + optimizedForAgents: false, + supportsCrossRegion: true, + }, + ); + + /** + * Creates a BedrockFoundationModel from a FoundationModelIdentifier. + * Use this method when you have a model identifier from the CDK. + * @param modelId - The foundation model identifier + * @param props - Optional properties for the model + * @returns A new BedrockFoundationModel instance + */ + public static fromCdkFoundationModelId( + modelId: FoundationModelIdentifier, + props: BedrockFoundationModelProps = {}, + ): BedrockFoundationModel { + return new BedrockFoundationModel(modelId.modelId, props); + } + /** + * Creates a BedrockFoundationModel from a FoundationModel. + * Use this method when you have a foundation model from the CDK. + * @param modelId - The foundation model + * @param props - Optional properties for the model + * @returns A new BedrockFoundationModel instance + */ + public static fromCdkFoundationModel( + modelId: FoundationModel, + props: BedrockFoundationModelProps = {}, + ): BedrockFoundationModel { + return new BedrockFoundationModel(modelId.modelId, props); + } + + /**************************************************************************** + * Constructor + ***************************************************************************/ + /** + * The unique identifier of the foundation model. + */ + public readonly modelId: string; + + /** + * The ARN of the foundation model. + * Format: arn:${Partition}:bedrock:${Region}::foundation-model/${ResourceId} + */ + public readonly modelArn: string; + + /** + * The ARN used for invoking the model. + * This is the same as modelArn for foundation models. + */ + public readonly invokableArn: string; + + /** + * Whether this model supports integration with Bedrock Agents. + * When true, the model can be used with Bedrock Agents for automated task execution. + */ + public readonly supportsAgents: boolean; + + /** + * Whether this model supports cross-region inference. + * When true, the model can be used with Cross-Region Inference Profiles. + */ + public readonly supportsCrossRegion: boolean; + + /** + * The dimensionality of the vector embeddings produced by this model. + * Only applicable for embedding models. + */ + public readonly vectorDimensions?: number; + + /** + * Whether this model supports integration with Bedrock Knowledge Base. + * When true, the model can be used for knowledge base operations. + */ + public readonly supportsKnowledgeBase: boolean; + + /** + * The vector types supported by this model for embeddings. + * Defines whether the model supports floating-point or binary vectors. + */ + public readonly supportedVectorType?: VectorType[]; + constructor(value: string, props: BedrockFoundationModelProps = {}) { + this.modelId = value; + this.modelArn = Arn.format({ + partition: Aws.PARTITION, + service: 'bedrock', + region: Aws.REGION, + account: '', + resource: 'foundation-model', + resourceName: this.modelId, + arnFormat: ArnFormat.SLASH_RESOURCE_NAME, + }); + this.invokableArn = this.modelArn; + this.supportsCrossRegion = props.supportsCrossRegion ?? false; + this.supportsAgents = props.supportsAgents ?? false; + this.vectorDimensions = props.vectorDimensions; + this.supportsKnowledgeBase = props.supportsKnowledgeBase ?? false; + this.supportedVectorType = props.supportedVectorType; + } + + toString(): string { + return this.modelId; + } + + /** + * Returns the ARN of the foundation model in the following format: + * `arn:${Partition}:bedrock:${Region}::foundation-model/${ResourceId}` + */ + asArn(): string { + return this.modelArn; + } + + /** + * Returns the IModel + */ + asIModel(): IModel { + return this; + } + + /** + * Gives the appropriate policies to invoke and use the Foundation Model in the stack region. + */ + public grantInvoke(grantee: IGrantable): Grant { + const grant = Grant.addToPrincipal({ + grantee: grantee, + actions: ['bedrock:InvokeModel*', 'bedrock:GetFoundationModel'], + resourceArns: [this.invokableArn], + }); + return grant; + } + + /** + * Gives the appropriate policies to invoke and use the Foundation Model in all regions. + */ + public grantInvokeAllRegions(grantee: IGrantable): Grant { + const invokableArn = Arn.format({ + partition: Aws.PARTITION, + service: 'bedrock', + region: '*', + account: '', + resource: 'foundation-model', + resourceName: this.modelId, + arnFormat: ArnFormat.SLASH_RESOURCE_NAME, + }); + + return Grant.addToPrincipal({ + grantee: grantee, + actions: ['bedrock:InvokeModel*', 'bedrock:GetFoundationModel'], + resourceArns: [invokableArn], + }); + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/jest.config.js b/packages/@aws-cdk/aws-bedrock-alpha/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-bedrock-alpha/lib/index.ts b/packages/@aws-cdk/aws-bedrock-alpha/lib/index.ts new file mode 100644 index 0000000000000..e99dcb121a515 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/lib/index.ts @@ -0,0 +1,6 @@ +// The index.ts files contains a list of files we want to +// include as part of the public API of this module. +// In general, all files including L2 classes will be listed here, +// while all files including only utility functions will be omitted from here. + +export * from '../bedrock'; diff --git a/packages/@aws-cdk/aws-bedrock-alpha/package.json b/packages/@aws-cdk/aws-bedrock-alpha/package.json new file mode 100644 index 0000000000000..41425242c9cdf --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/package.json @@ -0,0 +1,115 @@ +{ + "name": "@aws-cdk/aws-bedrock-alpha", + "version": "0.0.0", + "private": false, + "description": "The CDK Construct Library for Amazon Bedrock", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.services.bedrock.alpha", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "bedrock-alpha" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.AWS.Bedrock.Alpha", + "packageId": "Amazon.CDK.AWS.Bedrock.Alpha", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/main/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.aws-bedrock-alpha", + "module": "aws_cdk.aws_bedrock_alpha", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 2" + ] + }, + "go": { + "moduleName": "github.com/aws/aws-cdk-go", + "packageName": "awsbedrockalpha" + } + }, + "projectReferences": true, + "metadata": { + "jsii": { + "rosetta": { + "strict": true + } + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-bedrock-alpha" + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "integ-runner --language javascript", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "bedrock" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "aws-cdk-lib": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/integ-runner": "^2.186.0", + "@aws-cdk/pkglint": "0.0.0", + "@aws-cdk/integ-tests-alpha": "0.0.0", + "@types/jest": "^29.5.14", + "constructs": "^10.0.0", + "jest": "^29.7.0" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "aws-cdk-lib": "^0.0.0", + "constructs": "^10.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "stability": "experimental", + "maturity": "experimental", + "cdk-build": { + "env": { + "AWSLINT_BASE_CONSTRUCT": true + } + }, + "publishConfig": { + "tag": "latest" + }, + "awscdkio": { + "announce": false + }, + "pkglint": { + "exclude": [ + "naming/package-matches-directory", + "assert/assert-dependency" + ] + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-bedrock-alpha/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..bcec0539e5d28 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/rosetta/default.ts-fixture @@ -0,0 +1,19 @@ +// Fixture with packages imported, but nothing else +import * as path from 'path'; +import { Construct } from 'constructs'; +import { Stack } from 'aws-cdk-lib'; +import * as bedrock from '@aws-cdk/aws-bedrock-alpha'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { Duration, RemovalPolicy, aws_s3_deployment } from 'aws-cdk-lib'; +import { Memory } from '@aws-cdk/aws-bedrock-alpha'; + + + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/action-group.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/action-group.test.ts new file mode 100644 index 0000000000000..fa60e0454d790 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/action-group.test.ts @@ -0,0 +1,160 @@ +import { App } from 'aws-cdk-lib/core'; +import * as core from 'aws-cdk-lib/core'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import { Template, Match } from 'aws-cdk-lib/assertions'; +import * as bedrock from '../../../lib'; + +describe('AgentActionGroup', () => { + let stack: core.Stack; + let foundationModel: bedrock.IBedrockInvokable; + + beforeEach(() => { + const app = new App(); + stack = new core.Stack(app, 'test-stack'); + foundationModel = { + invokableArn: 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2', + grantInvoke: (grantee) => { + return iam.Grant.addToPrincipal({ + grantee, + actions: ['bedrock:InvokeModel*', 'bedrock:GetFoundationModel'], + resourceArns: ['arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2'], + }); + }, + }; + }); + + test('creates action group with USER_INPUT signature', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const actionGroup = new bedrock.AgentActionGroup({ + name: 'CustomAction', + enabled: true, + parentActionGroupSignature: bedrock.ParentActionGroupSignature.USER_INPUT, + }); + + agent.addActionGroup(actionGroup); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + ActionGroups: Match.arrayWith([ + Match.objectLike({ + ActionGroupName: 'CustomAction', + ActionGroupState: 'ENABLED', + ParentActionGroupSignature: 'AMAZON.UserInput', + }), + ]), + }); + }); + + test('creates action group with CODE_INTERPRETER signature', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const actionGroup = new bedrock.AgentActionGroup({ + name: 'CustomAction', + enabled: true, + parentActionGroupSignature: bedrock.ParentActionGroupSignature.CODE_INTERPRETER, + }); + + agent.addActionGroup(actionGroup); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + ActionGroups: Match.arrayWith([ + Match.objectLike({ + ActionGroupName: 'CustomAction', + ActionGroupState: 'ENABLED', + ParentActionGroupSignature: 'AMAZON.CodeInterpreter', + }), + ]), + }); + }); + + test('creates disabled action group', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const actionGroup = new bedrock.AgentActionGroup({ + name: 'CustomAction', + enabled: false, + parentActionGroupSignature: bedrock.ParentActionGroupSignature.USER_INPUT, + }); + + agent.addActionGroup(actionGroup); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + ActionGroups: Match.arrayWith([ + Match.objectLike({ + ActionGroupName: 'CustomAction', + ActionGroupState: 'DISABLED', + ParentActionGroupSignature: 'AMAZON.UserInput', + }), + ]), + }); + }); + + test('can add multiple action groups', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const actionGroup1 = new bedrock.AgentActionGroup({ + name: 'CustomAction1', + enabled: true, + parentActionGroupSignature: bedrock.ParentActionGroupSignature.USER_INPUT, + }); + + const actionGroup2 = new bedrock.AgentActionGroup({ + name: 'CustomAction2', + enabled: false, + parentActionGroupSignature: bedrock.ParentActionGroupSignature.CODE_INTERPRETER, + }); + + agent.addActionGroups(actionGroup1, actionGroup2); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + ActionGroups: Match.arrayWith([ + Match.objectLike({ + ActionGroupName: 'CustomAction1', + ActionGroupState: 'ENABLED', + ParentActionGroupSignature: 'AMAZON.UserInput', + }), + Match.objectLike({ + ActionGroupName: 'CustomAction2', + ActionGroupState: 'DISABLED', + ParentActionGroupSignature: 'AMAZON.CodeInterpreter', + }), + ]), + }); + }); + + test('throws error when adding duplicate action group names', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const actionGroup1 = new bedrock.AgentActionGroup({ + name: 'DuplicateAction', + enabled: true, + parentActionGroupSignature: bedrock.ParentActionGroupSignature.USER_INPUT, + }); + + const actionGroup2 = new bedrock.AgentActionGroup({ + name: 'DuplicateAction', + enabled: true, + parentActionGroupSignature: bedrock.ParentActionGroupSignature.USER_INPUT, + }); + + agent.addActionGroup(actionGroup1); + expect(() => { + agent.addActionGroup(actionGroup2); + }).toThrow(/Action group already exists/); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent-alias.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent-alias.test.ts new file mode 100644 index 0000000000000..702cabc62a87d --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent-alias.test.ts @@ -0,0 +1,285 @@ +import { App, ArnFormat, Stack, assertions } from 'aws-cdk-lib'; +import * as events from 'aws-cdk-lib/aws-events'; +import * as targets from 'aws-cdk-lib/aws-events-targets'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { AgentAlias } from '../../../bedrock/agents/agent-alias'; +import { IAgent } from '../../../bedrock/agents/agent'; + +describe('AgentAlias', () => { + let stack: Stack; + let mockAgent: IAgent; + + beforeEach(() => { + const app = new App(); + stack = new Stack(app, 'TestStack'); + mockAgent = { + agentId: 'test-agent-id', + agentArn: 'arn:aws:bedrock:us-east-1:123456789012:agent/test-agent-id', + lastUpdated: 'test-timestamp', + role: new iam.Role(stack, 'MockAgentRole', { + assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'), + }), + grantPrincipal: new iam.Role(stack, 'MockGrantPrincipal', { + assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'), + }), + grantInvoke: jest.fn(), + onEvent: jest.fn(), + metricCount: jest.fn(), + node: stack.node, + stack: stack, + env: { account: stack.account, region: stack.region }, + applyRemovalPolicy: jest.fn(), + }; + }); + + test('creates with minimal properties', () => { + // WHEN + const alias = new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + }); + + // THEN + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::Bedrock::AgentAlias', {}); + expect(alias.aliasName).toBe('latest'); + }); + + test('creates with all properties', () => { + // WHEN + const alias = new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + agentAliasName: 'test-alias', + agentVersion: '1.0.0', + description: 'Test description', + }); + + // THEN + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::Bedrock::AgentAlias', { + AgentAliasName: 'test-alias', + AgentId: 'test-agent-id', + Description: 'Test description', + RoutingConfiguration: [ + { + AgentVersion: '1.0.0', + }, + ], + }); + expect(alias.aliasName).toBe('test-alias'); + }); + + test('imports using fromAttributes', () => { + // WHEN + const importedAlias = AgentAlias.fromAttributes(stack, 'ImportedAlias', { + aliasId: 'test-alias-id', + aliasName: 'test-alias', + agent: mockAgent, + agentVersion: '1.0.0', + }); + + // THEN + expect(importedAlias.aliasId).toBe('test-alias-id'); + expect(importedAlias.aliasArn).toBe( + stack.formatArn({ + service: 'bedrock', + resource: 'agent-alias', + resourceName: 'test-agent-id/test-alias-id', + arnFormat: ArnFormat.SLASH_RESOURCE_NAME, + }), + ); + }); + + test('grants invoke permissions', () => { + // GIVEN + const alias = new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + }); + const role = new iam.Role(stack, 'TestRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // WHEN + alias.grantInvoke(role); + + // THEN + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'bedrock:InvokeAgent', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': assertions.Match.arrayWith([ + assertions.Match.stringLikeRegexp('TestAlias[A-Z0-9]+'), + 'AgentAliasArn', + ]), + }, + }, + ], + }, + }); + }); + + test('grants get permissions', () => { + // GIVEN + const alias = new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + }); + const role = new iam.Role(stack, 'TestRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // WHEN + alias.grantGet(role); + + // THEN + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'bedrock:GetAgentAlias', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': assertions.Match.arrayWith([ + assertions.Match.stringLikeRegexp('TestAlias[A-Z0-9]+'), + 'AgentAliasArn', + ]), + }, + }, + ], + }, + }); + }); + + test('grants custom permissions', () => { + // GIVEN + const alias = new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + }); + const role = new iam.Role(stack, 'TestRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // WHEN + alias.grant(role, 'bedrock:CustomAction'); + + // THEN + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'bedrock:CustomAction', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': assertions.Match.arrayWith([ + assertions.Match.stringLikeRegexp('TestAlias[A-Z0-9]+'), + 'AgentAliasArn', + ]), + }, + }, + ], + }, + }); + }); + + test('creates CloudTrail event rule', () => { + // GIVEN + const alias = new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + }); + const fn = new lambda.Function(stack, 'TestFunction', { + code: lambda.Code.fromInline('exports.handler = function() { }'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + }); + + // WHEN + const rule = alias.onCloudTrailEvent('TestRule', { + target: new targets.LambdaFunction(fn), + }); + + // THEN + expect(rule).toBeInstanceOf(events.Rule); + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::Rule', { + EventPattern: { + 'source': ['aws.bedrock'], + 'detail-type': ['AWS API Call via CloudTrail'], + 'detail': { + requestParameters: { + agentAliasId: [{ + 'Fn::GetAtt': assertions.Match.arrayWith([ + assertions.Match.stringLikeRegexp('TestAlias[A-Z0-9]+'), + 'AgentAliasId', + ]), + }], + }, + }, + }, + }); + }); + + test('creates CloudTrail event rule with default options', () => { + // GIVEN + const alias = new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + }); + + // WHEN + const rule = alias.onCloudTrailEvent('TestRule'); + + // THEN + expect(rule).toBeInstanceOf(events.Rule); + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::Events::Rule', { + EventPattern: { + 'source': ['aws.bedrock'], + 'detail-type': ['AWS API Call via CloudTrail'], + 'detail': { + requestParameters: { + agentAliasId: [{ + 'Fn::GetAtt': assertions.Match.arrayWith([ + assertions.Match.stringLikeRegexp('TestAlias[A-Z0-9]+'), + 'AgentAliasId', + ]), + }], + }, + }, + }, + }); + }); + + test('handles undefined agentVersion', () => { + // WHEN + new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + agentVersion: undefined, + }); + + // THEN + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::Bedrock::AgentAlias', { + AgentId: 'test-agent-id', + RoutingConfiguration: assertions.Match.absent(), + }); + }); + + test('handles undefined description', () => { + // WHEN + new AgentAlias(stack, 'TestAlias', { + agent: mockAgent, + description: undefined, + }); + + // THEN + const template = assertions.Template.fromStack(stack); + template.hasResourceProperties('AWS::Bedrock::AgentAlias', { + AgentId: 'test-agent-id', + Description: assertions.Match.absent(), + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent-collaborator.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent-collaborator.test.ts new file mode 100644 index 0000000000000..c9d953831bcc1 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent-collaborator.test.ts @@ -0,0 +1,154 @@ +import { Stack } from 'aws-cdk-lib'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import { AgentCollaborator } from '../../../bedrock/agents/agent-collaborator'; +import { IAgentAlias } from '../../../bedrock/agents/agent-alias'; + +describe('AgentCollaborator', () => { + let stack: Stack; + let mockAgentAlias: IAgentAlias; + let mockGrantInvoke: jest.Mock; + let mockGrantGet: jest.Mock; + + beforeEach(() => { + stack = new Stack(); + const mockCombine = jest.fn().mockReturnThis(); + mockGrantInvoke = jest.fn().mockReturnValue({ combine: mockCombine }); + mockGrantGet = jest.fn().mockReturnValue({ combine: mockCombine }); + + mockAgentAlias = { + aliasId: 'test-alias-id', + aliasArn: 'arn:aws:bedrock:us-east-1:123456789012:agent-alias/test-agent/test-alias-id', + agent: {} as any, + grantInvoke: mockGrantInvoke, + grantGet: mockGrantGet, + grant: jest.fn(), + onCloudTrailEvent: jest.fn(), + node: stack.node, + env: { account: stack.account, region: stack.region }, + stack: stack, + applyRemovalPolicy: jest.fn(), + }; + }); + + test('creates with valid properties', () => { + // WHEN + const collaborator = new AgentCollaborator({ + agentAlias: mockAgentAlias, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + relayConversationHistory: true, + }); + + // THEN + expect(collaborator.agentAlias).toBe(mockAgentAlias); + expect(collaborator.collaborationInstruction).toBe('Test instruction'); + expect(collaborator.collaboratorName).toBe('Test collaborator'); + expect(collaborator.relayConversationHistory).toBe(true); + }); + + test('throws error when using TSTALIASID', () => { + // GIVEN + const testAlias = { + ...mockAgentAlias, + aliasId: 'TSTALIASID', + }; + + // THEN + expect(() => { + new AgentCollaborator({ + agentAlias: testAlias, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + }); + }).toThrow('Agent cannot collaborate with TSTALIASID alias of another agent'); + }); + + test('renders with relayConversationHistory true', () => { + // GIVEN + const collaborator = new AgentCollaborator({ + agentAlias: mockAgentAlias, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + relayConversationHistory: true, + }); + + // WHEN + const rendered = collaborator._render(); + + // THEN + expect(rendered).toEqual({ + agentDescriptor: { + aliasArn: mockAgentAlias.aliasArn, + }, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + relayConversationHistory: 'TO_COLLABORATOR', + }); + }); + + test('renders with relayConversationHistory false', () => { + // GIVEN + const collaborator = new AgentCollaborator({ + agentAlias: mockAgentAlias, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + relayConversationHistory: false, + }); + + // WHEN + const rendered = collaborator._render(); + + // THEN + expect(rendered).toEqual({ + agentDescriptor: { + aliasArn: mockAgentAlias.aliasArn, + }, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + relayConversationHistory: 'DISABLED', + }); + }); + + test('renders with relayConversationHistory undefined', () => { + // GIVEN + const collaborator = new AgentCollaborator({ + agentAlias: mockAgentAlias, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + }); + + // WHEN + const rendered = collaborator._render(); + + // THEN + expect(rendered).toEqual({ + agentDescriptor: { + aliasArn: mockAgentAlias.aliasArn, + }, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + relayConversationHistory: 'DISABLED', + }); + }); + + test('grants permissions to grantee', () => { + // GIVEN + const collaborator = new AgentCollaborator({ + agentAlias: mockAgentAlias, + collaborationInstruction: 'Test instruction', + collaboratorName: 'Test collaborator', + }); + const grantee = new iam.Role(stack, 'TestRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // WHEN + collaborator.grant(grantee); + + // THEN + const checkGrantInvoke = () => expect(mockGrantInvoke).toHaveBeenCalledWith(grantee); + const checkGrantGet = () => expect(mockGrantGet).toHaveBeenCalledWith(grantee); + checkGrantInvoke(); + checkGrantGet(); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent.test.ts new file mode 100644 index 0000000000000..377d0ce51a839 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/agent.test.ts @@ -0,0 +1,603 @@ +import { App } from 'aws-cdk-lib/core'; +import * as core from 'aws-cdk-lib/core'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as kms from 'aws-cdk-lib/aws-kms'; +import { Template, Match } from 'aws-cdk-lib/assertions'; +import * as bedrock from '../../../bedrock'; + +describe('Agent', () => { + let stack: core.Stack; + let foundationModel: bedrock.IBedrockInvokable; + + beforeEach(() => { + const app = new App(); + stack = new core.Stack(app, 'test-stack'); + foundationModel = { + invokableArn: 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2', + grantInvoke: (grantee) => { + return iam.Grant.addToPrincipal({ + grantee, + actions: ['bedrock:InvokeModel*', 'bedrock:GetFoundationModel'], + resourceArns: ['arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2'], + }); + }, + }; + }); + + test('creates agent with default name when agentName is not provided', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + AgentName: Match.stringLikeRegexp('agent-teststack-testagent-8d92f3fe-bedrockagent'), + }); + }); + + test('creates agent with basic properties', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + Instruction: Match.stringLikeRegexp('.*at least 40 characters.*'), + FoundationModel: foundationModel.invokableArn, + IdleSessionTTLInSeconds: 600, + AutoPrepare: false, + Description: Match.absent(), + CustomerEncryptionKeyArn: Match.absent(), + }); + }); + + test('creates agent with all properties', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + agentName: 'MyTestAgent', + description: 'Test agent description', + shouldPrepareAgent: true, + idleSessionTTL: core.Duration.minutes(30), + userInputEnabled: true, + codeInterpreterEnabled: true, + forceDelete: true, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + AgentName: 'MyTestAgent', + Description: 'Test agent description', + Instruction: Match.stringLikeRegexp('.*at least 40 characters.*'), + FoundationModel: foundationModel.invokableArn, + IdleSessionTTLInSeconds: 1800, + AutoPrepare: true, + SkipResourceInUseCheckOnDelete: true, + }); + }); + + test('creates an IAM role with correct trust policy', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'bedrock.amazonaws.com', + }, + Condition: { + StringEquals: { + 'aws:SourceAccount': Match.objectLike({ Ref: 'AWS::AccountId' }), + }, + ArnLike: { + 'aws:SourceArn': { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':bedrock:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':agent/*', + ]], + }, + }, + }, + }, + ], + }, + }); + }); + + test('correctly adds bedrock:InvokeAgent permissions when grantInvoke() is called', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.AnyPrincipal(), + }); + + agent.grantInvoke(role); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([ + Match.objectLike({ + Action: 'bedrock:InvokeAgent', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestAgent[A-Z0-9]+'), 'AgentArn'], + }, + }), + ]), + }, + }); + }); + + test('cannot be created with instruction less than 40 characters', () => { + expect(() => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'Too short', + foundationModel, + }); + }).toThrow(/instruction must be at least 40 characters/); + }); + + test('does not fail validation if instruction is a late-bound value', () => { + const parameter = new core.CfnParameter(stack, 'Parameter'); + + new bedrock.Agent(stack, 'TestAgent', { + instruction: parameter.valueAsString, + foundationModel, + }); + }); + + describe('custom orchestration', () => { + test('sets custom orchestration and grants necessary permissions', () => { + const fn = new lambda.Function(stack, 'TestFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async () => {};'), + }); + + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + customOrchestrationExecutor: bedrock.CustomOrchestrationExecutor.fromLambda(fn), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + OrchestrationType: 'CUSTOM_ORCHESTRATION', + CustomOrchestration: { + Executor: { + Lambda: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestFunction[A-Z0-9]+'), 'Arn'], + }, + }, + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestFunction[A-Z0-9]+'), 'Arn'], + }, + Principal: 'bedrock.amazonaws.com', + SourceArn: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestAgent[A-Z0-9]+'), 'AgentArn'], + }, + SourceAccount: { + Ref: 'AWS::AccountId', + }, + }); + }); + }); + + test('sets KMS key correctly', () => { + const key = new kms.Key(stack, 'TestKey'); + + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + kmsKey: key, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + CustomerEncryptionKeyArn: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestKey[A-Z0-9]+'), 'Arn'], + }, + }); + }); + + test('uses existing role correctly', () => { + const role = new iam.Role(stack, 'ExistingRole', { + assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'), + }); + + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + existingRole: role, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + AgentResourceRoleArn: { + 'Fn::GetAtt': [Match.stringLikeRegexp('ExistingRole[A-Z0-9]+'), 'Arn'], + }, + }); + }); + + describe('static methods', () => { + test('fromAgentAttributes creates agent from attributes', () => { + const importedAgent = bedrock.Agent.fromAgentAttributes(stack, 'ImportedAgent', { + agentArn: 'arn:aws:bedrock:us-east-1:123456789012:agent/test-agent-id', + roleArn: 'arn:aws:iam::123456789012:role/test-role', + kmsKeyArn: 'arn:aws:kms:us-east-1:123456789012:key/test-key-id', + lastUpdated: '2023-01-01T00:00:00Z', + agentVersion: '1', + }); + + expect(importedAgent.agentArn).toBe('arn:aws:bedrock:us-east-1:123456789012:agent/test-agent-id'); + expect(importedAgent.agentId).toBe('test-agent-id'); + expect(importedAgent.lastUpdated).toBe('2023-01-01T00:00:00Z'); + // Note: agentVersion is not available on IAgent interface, only on concrete Agent class + expect((importedAgent as any).agentVersion).toBe('1'); + expect(importedAgent.kmsKey).toBeDefined(); + }); + + test('fromAgentAttributes uses default version when not provided', () => { + const importedAgent = bedrock.Agent.fromAgentAttributes(stack, 'ImportedAgent', { + agentArn: 'arn:aws:bedrock:us-east-1:123456789012:agent/test-agent-id', + roleArn: 'arn:aws:iam::123456789012:role/test-role', + }); + + expect((importedAgent as any).agentVersion).toBe('DRAFT'); + expect(importedAgent.kmsKey).toBeUndefined(); + expect(importedAgent.lastUpdated).toBeUndefined(); + }); + }); + + describe('event and metrics methods', () => { + test('onEvent creates EventBridge rule with default configuration', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const rule = agent.onEvent('TestRule'); + + expect(rule).toBeDefined(); + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + EventPattern: { + source: ['aws.bedrock'], + detail: { + 'agent-id': [{ 'Fn::GetAtt': [Match.stringLikeRegexp('TestAgent[A-Z0-9]+'), 'AgentId'] }], + }, + }, + }); + }); + + test('onEvent creates EventBridge rule with custom options', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const rule = agent.onEvent('TestRule', { + description: 'Custom rule description', + }); + + expect(rule).toBeDefined(); + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + Description: 'Custom rule description', + EventPattern: { + source: ['aws.bedrock'], + detail: { + 'agent-id': [{ 'Fn::GetAtt': [Match.stringLikeRegexp('TestAgent[A-Z0-9]+'), 'AgentId'] }], + }, + }, + }); + }); + + test('metricCount creates CloudWatch metric with default configuration', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const metric = agent.metricCount(); + + expect(metric.namespace).toBe('AWS/Bedrock'); + expect(metric.metricName).toBe('Invocations'); + expect(metric.dimensions).toEqual({ + AgentId: agent.agentId, + }); + }); + + test('metricCount creates CloudWatch metric with custom options', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const metric = agent.metricCount({ + statistic: 'Sum', + period: core.Duration.minutes(5), + }); + + expect(metric.namespace).toBe('AWS/Bedrock'); + expect(metric.metricName).toBe('Invocations'); + expect(metric.statistic).toBe('Sum'); + expect(metric.period?.toSeconds()).toBe(300); + }); + }); + + describe('validation', () => { + test('validates idleSessionTTL range - too low', () => { + expect(() => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + idleSessionTTL: core.Duration.seconds(30), + }); + }).toThrow(/cannot be converted into a whole number of minutes/); + }); + + test('validates idleSessionTTL range - too high', () => { + expect(() => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + idleSessionTTL: core.Duration.minutes(65), + }); + }).toThrow(/idleSessionTTL must be between 1 and 60 minutes/); + }); + + test('accepts valid idleSessionTTL values', () => { + expect(() => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + idleSessionTTL: core.Duration.minutes(30), + }); + }).not.toThrow(); + }); + }); + + describe('action groups', () => { + test('addActionGroups method adds multiple action groups', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const fn1 = new lambda.Function(stack, 'TestFunction1', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async () => {};'), + }); + + const fn2 = new lambda.Function(stack, 'TestFunction2', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async () => {};'), + }); + + const actionGroup1 = new bedrock.AgentActionGroup({ + name: 'TestActionGroup1', + description: 'Test action group 1', + executor: bedrock.ActionGroupExecutor.fromLambda(fn1), + enabled: true, + }); + + const actionGroup2 = new bedrock.AgentActionGroup({ + name: 'TestActionGroup2', + description: 'Test action group 2', + executor: bedrock.ActionGroupExecutor.fromLambda(fn2), + enabled: true, + }); + + agent.addActionGroups(actionGroup1, actionGroup2); + + expect(agent.actionGroups).toHaveLength(4); // 2 default + 2 added + }); + + test('throws error when adding duplicate action group names', () => { + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + const fn = new lambda.Function(stack, 'TestFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async () => {};'), + }); + + const actionGroup1 = new bedrock.AgentActionGroup({ + name: 'DuplicateName', + description: 'Test action group 1', + executor: bedrock.ActionGroupExecutor.fromLambda(fn), + enabled: true, + }); + + const actionGroup2 = new bedrock.AgentActionGroup({ + name: 'DuplicateName', + description: 'Test action group 2', + executor: bedrock.ActionGroupExecutor.fromLambda(fn), + enabled: true, + }); + + agent.addActionGroup(actionGroup1); + + expect(() => { + agent.addActionGroup(actionGroup2); + }).toThrow(/Action group already exists/); + }); + }); + + describe('memory configuration', () => { + test('creates agent with memory configuration', () => { + const memory = bedrock.Memory.sessionSummary({ + memoryDuration: core.Duration.days(30), + maxRecentSessions: 20, + }); + + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + memory, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + MemoryConfiguration: { + EnabledMemoryTypes: ['SESSION_SUMMARY'], + StorageDays: 30, + SessionSummaryConfiguration: { + MaxRecentSessions: 20, + }, + }, + }); + }); + + test('creates agent with default memory configuration', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + memory: bedrock.Memory.SESSION_SUMMARY, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + MemoryConfiguration: { + EnabledMemoryTypes: ['SESSION_SUMMARY'], + StorageDays: 30, + SessionSummaryConfiguration: { + MaxRecentSessions: 20, + }, + }, + }); + }); + }); + + describe('edge cases', () => { + test('handles undefined agentCollaborators', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + agentCollaboration: new bedrock.AgentCollaboration({ + type: bedrock.AgentCollaboratorType.SUPERVISOR, + collaborators: [], + }), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + AgentCollaboration: 'SUPERVISOR', + AgentCollaborators: Match.absent(), + }); + }); + + test('handles disabled default action groups', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + userInputEnabled: false, + codeInterpreterEnabled: false, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + ActionGroups: [ + { + ActionGroupName: 'UserInputAction', + ActionGroupState: 'DISABLED', + ParentActionGroupSignature: 'AMAZON.UserInput', + SkipResourceInUseCheckOnDelete: false, + }, + { + ActionGroupName: 'CodeInterpreterAction', + ActionGroupState: 'DISABLED', + ParentActionGroupSignature: 'AMAZON.CodeInterpreter', + SkipResourceInUseCheckOnDelete: false, + }, + ], + }); + }); + + test('creates agent with description', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + description: 'This is a test agent with a custom description', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + Description: 'This is a test agent with a custom description', + }); + }); + + test('creates agent with custom agent name', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + agentName: 'MyCustomAgentName', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + AgentName: 'MyCustomAgentName', + }); + }); + + test('creates agent with agent collaboration', () => { + const collaboratorAlias = bedrock.AgentAlias.fromAttributes(stack, 'CollaboratorAlias', { + aliasId: 'test-alias-id', + aliasName: 'TestAlias', + agentVersion: '1', + agent: bedrock.Agent.fromAgentAttributes(stack, 'CollaboratorAgent', { + agentArn: 'arn:aws:bedrock:us-east-1:123456789012:agent/collaborator-agent-id', + roleArn: 'arn:aws:iam::123456789012:role/collaborator-role', + }), + }); + + const collaborator = new bedrock.AgentCollaborator({ + agentAlias: collaboratorAlias, + collaborationInstruction: 'Help with data analysis tasks', + collaboratorName: 'DataAnalyst', + relayConversationHistory: true, + }); + + const agentCollaboration = new bedrock.AgentCollaboration({ + type: bedrock.AgentCollaboratorType.SUPERVISOR, + collaborators: [collaborator], + }); + + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + agentCollaboration, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + AgentCollaboration: 'SUPERVISOR', + AgentCollaborators: [ + { + AgentDescriptor: { + AliasArn: Match.objectLike({ + 'Fn::Join': Match.anyValue(), + }), + }, + CollaborationInstruction: 'Help with data analysis tasks', + CollaboratorName: 'DataAnalyst', + RelayConversationHistory: 'TO_COLLABORATOR', + }, + ], + }); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/api-executor.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/api-executor.test.ts new file mode 100644 index 0000000000000..a05764f8a2b54 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/api-executor.test.ts @@ -0,0 +1,113 @@ +import { App } from 'aws-cdk-lib/core'; +import * as core from 'aws-cdk-lib/core'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import { Template, Match } from 'aws-cdk-lib/assertions'; +import * as bedrock from '../../../lib'; + +describe('AgentActionGroupExecutor', () => { + let stack: core.Stack; + let foundationModel: bedrock.IBedrockInvokable; + + beforeEach(() => { + const app = new App(); + stack = new core.Stack(app, 'test-stack'); + foundationModel = { + invokableArn: 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2', + grantInvoke: (grantee) => { + return iam.Grant.addToPrincipal({ + grantee, + actions: ['bedrock:InvokeModel*', 'bedrock:GetFoundationModel'], + resourceArns: ['arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2'], + }); + }, + }; + }); + + test('creates action group with lambda executor', () => { + const fn = new lambda.Function(stack, 'TestFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async () => {};'), + }); + + const actionGroup = new bedrock.AgentActionGroup({ + name: 'CustomAction', + enabled: true, + executor: bedrock.ActionGroupExecutor.fromLambda(fn), + }); + + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + agent.addActionGroup(actionGroup); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + ActionGroups: Match.arrayWith([ + Match.objectLike({ + ActionGroupName: 'CustomAction', + ActionGroupState: 'ENABLED', + ActionGroupExecutor: { + Lambda: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestFunction[A-Z0-9]+'), 'Arn'], + }, + }, + }), + ]), + }); + + // Verify Lambda permissions + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestFunction[A-Z0-9]+'), 'Arn'], + }, + Principal: 'bedrock.amazonaws.com', + SourceArn: { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestAgent[A-Z0-9]+'), 'AgentArn'], + }, + SourceAccount: { + Ref: 'AWS::AccountId', + }, + }); + }); + + test('grants necessary permissions to agent role', () => { + const fn = new lambda.Function(stack, 'TestFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async () => {};'), + }); + + const actionGroup = new bedrock.AgentActionGroup({ + name: 'CustomAction', + enabled: true, + executor: bedrock.ActionGroupExecutor.fromLambda(fn), + }); + + const agent = new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + }); + + agent.addActionGroup(actionGroup); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([ + Match.objectLike({ + Action: 'lambda:InvokeFunction', + Effect: 'Allow', + Resource: Match.arrayWith([ + { + 'Fn::GetAtt': [Match.stringLikeRegexp('TestFunction[A-Z0-9]+'), 'Arn'], + }, + ]), + }), + ]), + }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/api-schema.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/api-schema.test.ts new file mode 100644 index 0000000000000..78ff647b6fd7b --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/api-schema.test.ts @@ -0,0 +1,104 @@ +import { Stack } from 'aws-cdk-lib'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { ApiSchema, AssetApiSchema, InlineApiSchema, S3ApiSchema } from '../../../bedrock/agents/api-schema'; + +describe('ApiSchema', () => { + test('fromLocalAsset creates AssetApiSchema', () => { + const schema = ApiSchema.fromLocalAsset('path/to/schema.yaml'); + expect(schema).toBeInstanceOf(AssetApiSchema); + }); + + test('fromInline creates InlineApiSchema', () => { + const schema = ApiSchema.fromInline('{"openapi": "3.0.0"}'); + expect(schema).toBeInstanceOf(InlineApiSchema); + }); + + test('fromS3File creates S3ApiSchema', () => { + const bucket = s3.Bucket.fromBucketName(new Stack(), 'TestBucket', 'test-bucket'); + const schema = ApiSchema.fromS3File(bucket, 'path/to/schema.yaml'); + expect(schema).toBeInstanceOf(S3ApiSchema); + }); +}); + +describe('AssetApiSchema', () => { + test('bind initializes asset', () => { + const stack = new Stack(); + const schema = new AssetApiSchema('test/bedrock/agents/test-schema.yaml'); + // Before binding, asset should be undefined + expect((schema as any).asset).toBeUndefined(); + schema.bind(stack); + // After binding, asset should be defined + expect((schema as any).asset).toBeDefined(); + }); + + test('bind only initializes asset once', () => { + const stack = new Stack(); + const schema = new AssetApiSchema('test/bedrock/agents/test-schema.yaml'); + schema.bind(stack); + const firstAsset = (schema as any).asset; + schema.bind(stack); + const secondAsset = (schema as any).asset; + // The asset should be the same instance + expect(firstAsset).toBe(secondAsset); + }); + + test('_render throws error if not bound', () => { + const schema = new AssetApiSchema('test/bedrock/agents/test-schema.yaml'); + expect(() => { + schema._render(); + }).toThrow('ApiSchema must be bound to a scope before rendering'); + }); + + test('_render returns correct structure after binding', () => { + const stack = new Stack(); + const schema = new AssetApiSchema('test/bedrock/agents/test-schema.yaml'); + schema.bind(stack); + const rendered = schema._render(); + expect(rendered).toHaveProperty('s3'); + expect(rendered.s3).toHaveProperty('s3BucketName'); + expect(rendered.s3).toHaveProperty('s3ObjectKey'); + }); +}); + +describe('InlineApiSchema', () => { + test('constructor sets inlineSchema', () => { + const schemaContent = '{"openapi": "3.0.0"}'; + const schema = new InlineApiSchema(schemaContent); + expect(schema.inlineSchema).toBe(schemaContent); + }); + + test('_render returns payload property', () => { + const schemaContent = '{"openapi": "3.0.0"}'; + const schema = new InlineApiSchema(schemaContent); + const rendered = schema._render(); + expect(rendered).toEqual({ + payload: schemaContent, + }); + }); +}); + +describe('S3ApiSchema', () => { + test('constructor sets s3File', () => { + const location = { + bucketName: 'test-bucket', + objectKey: 'path/to/schema.yaml', + }; + const schema = new S3ApiSchema(location); + expect(schema.s3File).toBe(location); + }); + + test('_render returns s3 property', () => { + const location = { + bucketName: 'test-bucket', + objectKey: 'path/to/schema.yaml', + }; + const schema = new S3ApiSchema(location); + const rendered = schema._render(); + expect(rendered).toEqual({ + s3: { + s3BucketName: 'test-bucket', + s3ObjectKey: 'path/to/schema.yaml', + }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/function-schema.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/function-schema.test.ts new file mode 100644 index 0000000000000..57d35eff09088 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/function-schema.test.ts @@ -0,0 +1,287 @@ +import { FunctionParameter, Function, FunctionSchema, ParameterType, RequireConfirmation } from '../../../bedrock/agents/function-schema'; +import { ValidationError } from '../../../bedrock/agents/validation-helpers'; + +describe('FunctionParameter', () => { + test('constructs with minimal properties', () => { + const param = new FunctionParameter({ + type: ParameterType.STRING, + }); + + expect(param.type).toEqual(ParameterType.STRING); + expect(param.required).toEqual(true); + expect(param.description).toBeUndefined(); + }); + + test('constructs with all properties', () => { + const param = new FunctionParameter({ + type: ParameterType.NUMBER, + required: false, + description: 'A test parameter', + }); + + expect(param.type).toEqual(ParameterType.NUMBER); + expect(param.required).toEqual(false); + expect(param.description).toEqual('A test parameter'); + }); + + test('validates description length', () => { + // Create a description that exceeds the max length of 500 + const longDescription = 'a'.repeat(501); + + expect(() => { + new FunctionParameter({ + type: ParameterType.STRING, + description: longDescription, + }); + }).toThrow(ValidationError); + }); + + test('renders correctly', () => { + const param = new FunctionParameter({ + type: ParameterType.BOOLEAN, + required: false, + description: 'A boolean parameter', + }); + + const rendered = param._render(); + expect(rendered).toEqual({ + type: ParameterType.BOOLEAN, + required: false, + description: 'A boolean parameter', + }); + }); + + test('renders without description', () => { + const param = new FunctionParameter({ + type: ParameterType.INTEGER, + required: true, + }); + + const rendered = param._render(); + expect(rendered).toEqual({ + type: ParameterType.INTEGER, + required: true, + description: undefined, + }); + }); +}); + +describe('Function', () => { + test('constructs with minimal properties', () => { + const func = new Function({ + name: 'testFunction', + description: 'A test function', + }); + + expect(func.name).toEqual('testFunction'); + expect(func.description).toEqual('A test function'); + expect(func.parameters).toEqual({}); + expect(func.requireConfirmation).toEqual(RequireConfirmation.DISABLED); + }); + + test('constructs with all properties', () => { + const func = new Function({ + name: 'testFunction', + description: 'A test function', + parameters: { + param1: { + type: ParameterType.STRING, + required: true, + description: 'A string parameter', + }, + param2: { + type: ParameterType.NUMBER, + required: false, + }, + }, + requireConfirmation: RequireConfirmation.ENABLED, + }); + + expect(func.name).toEqual('testFunction'); + expect(func.description).toEqual('A test function'); + expect(Object.keys(func.parameters)).toEqual(['param1', 'param2']); + expect(func.parameters.param1.type).toEqual(ParameterType.STRING); + expect(func.parameters.param2.required).toEqual(false); + expect(func.requireConfirmation).toEqual(RequireConfirmation.ENABLED); + }); + + test('validates function name length', () => { + // Create a name that exceeds the max length of 100 + const longName = 'a'.repeat(101); + + expect(() => { + new Function({ + name: longName, + description: 'A test function', + }); + }).toThrow(ValidationError); + }); + + test('validates function description length', () => { + // Create a description that exceeds the max length of 500 + const longDescription = 'a'.repeat(501); + + expect(() => { + new Function({ + name: 'testFunction', + description: longDescription, + }); + }).toThrow(ValidationError); + }); + + test('validates parameter name length', () => { + // Create a parameter name that exceeds the max length of 100 + const longParamName = 'a'.repeat(101); + + expect(() => { + new Function({ + name: 'testFunction', + description: 'A test function', + parameters: { + [longParamName]: { + type: ParameterType.STRING, + }, + }, + }); + }).toThrow(ValidationError); + }); + + test('renders correctly with parameters', () => { + const func = new Function({ + name: 'testFunction', + description: 'A test function', + parameters: { + param1: { + type: ParameterType.STRING, + description: 'A string parameter', + }, + param2: { + type: ParameterType.BOOLEAN, + required: false, + }, + }, + requireConfirmation: RequireConfirmation.ENABLED, + }); + + const rendered = func._render(); + expect(rendered).toEqual({ + name: 'testFunction', + description: 'A test function', + parameters: { + param1: { + type: ParameterType.STRING, + required: true, + description: 'A string parameter', + }, + param2: { + type: ParameterType.BOOLEAN, + required: false, + description: undefined, + }, + }, + requireConfirmation: RequireConfirmation.ENABLED, + }); + }); + + test('renders correctly without parameters', () => { + const func = new Function({ + name: 'testFunction', + description: 'A test function', + }); + + const rendered = func._render(); + expect(rendered).toEqual({ + name: 'testFunction', + description: 'A test function', + parameters: {}, + requireConfirmation: RequireConfirmation.DISABLED, + }); + }); +}); + +describe('FunctionSchema', () => { + test('constructs with functions', () => { + const schema = new FunctionSchema({ + functions: [ + { + name: 'function1', + description: 'First test function', + }, + { + name: 'function2', + description: 'Second test function', + parameters: { + param1: { + type: ParameterType.STRING, + }, + }, + }, + ], + }); + + expect(schema.functions.length).toEqual(2); + expect(schema.functions[0].name).toEqual('function1'); + expect(schema.functions[1].name).toEqual('function2'); + }); + + test('throws error when no functions provided', () => { + expect(() => { + new FunctionSchema({ + functions: [], + }); + }).toThrow(ValidationError); + }); + + test('renders correctly', () => { + const schema = new FunctionSchema({ + functions: [ + { + name: 'function1', + description: 'First test function', + }, + { + name: 'function2', + description: 'Second test function', + parameters: { + param1: { + type: ParameterType.STRING, + }, + }, + requireConfirmation: RequireConfirmation.ENABLED, + }, + ], + }); + + const rendered = schema._render(); + expect(rendered).toEqual({ + functions: [ + { + name: 'function1', + description: 'First test function', + parameters: {}, + requireConfirmation: RequireConfirmation.DISABLED, + }, + { + name: 'function2', + description: 'Second test function', + parameters: { + param1: { + type: ParameterType.STRING, + required: true, + description: undefined, + }, + }, + requireConfirmation: RequireConfirmation.ENABLED, + }, + ], + }); + }); + + test('handles undefined functions array', () => { + expect(() => { + new FunctionSchema({ + functions: undefined as any, + }); + }).toThrow(ValidationError); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/BedrockActionGroupDefaultTestDeployAssertE2AFA81B.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/BedrockActionGroupDefaultTestDeployAssertE2AFA81B.assets.json new file mode 100644 index 0000000000000..885ab4dd33d95 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/BedrockActionGroupDefaultTestDeployAssertE2AFA81B.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "BedrockActionGroupDefaultTestDeployAssertE2AFA81B Template", + "source": { + "path": "BedrockActionGroupDefaultTestDeployAssertE2AFA81B.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/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/BedrockActionGroupDefaultTestDeployAssertE2AFA81B.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/BedrockActionGroupDefaultTestDeployAssertE2AFA81B.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/BedrockActionGroupDefaultTestDeployAssertE2AFA81B.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/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/aws-cdk-bedrock-action-group-1.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/aws-cdk-bedrock-action-group-1.assets.json new file mode 100644 index 0000000000000..24d232f2db3d8 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/aws-cdk-bedrock-action-group-1.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "29d201f8af6439d216cfb9ba6b3eaf48b3f679dc9a03a6b09154f412a64839de": { + "displayName": "aws-cdk-bedrock-action-group-1 Template", + "source": { + "path": "aws-cdk-bedrock-action-group-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "29d201f8af6439d216cfb9ba6b3eaf48b3f679dc9a03a6b09154f412a64839de.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/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/aws-cdk-bedrock-action-group-1.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/aws-cdk-bedrock-action-group-1.template.json new file mode 100644 index 0000000000000..e9def5c443dd6 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/aws-cdk-bedrock-action-group-1.template.json @@ -0,0 +1,283 @@ +{ + "Resources": { + "ActionGroupFunctionServiceRole77660D62": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "ActionGroupFunctionFE14D1CB": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ActionGroupFunctionServiceRole77660D62", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "ActionGroupFunctionServiceRole77660D62" + ] + }, + "ActionGroupFunctionLambdaInvocationPolicyc855117c0e9b7e1e08A69654": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ActionGroupFunctionFE14D1CB", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "MyAgentRoleE8318EBB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockactiongroup1-myagent-319c695f-bedrockagent" + } + }, + "MyAgentRoleDefaultPolicy30DBC7AC": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ActionGroupFunctionFE14D1CB", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ActionGroupFunctionFE14D1CB", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyAgentRoleDefaultPolicy30DBC7AC", + "Roles": [ + { + "Ref": "MyAgentRoleE8318EBB" + } + ] + } + }, + "MyAgent039CC8B3": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "ENABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "ENABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "ActionGroupFunctionFE14D1CB", + "Arn" + ] + } + }, + "ActionGroupName": "CustomActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "Payload": "\nopenapi: 3.0.3\ninfo:\n title: Action Group API\n version: 1.0.0\npaths:\n /perform-action:\n post:\n operationId: performAction\n summary: Perform an action\n description: Perform an action with the specified parameters\n requestBody:\n required: true\n content:\n application/json:\n schema:\n type: object\n required:\n - action_type\n properties:\n action_type:\n type: string\n description: Type of action to perform\n parameters:\n type: object\n description: Additional parameters for the action\n responses:\n '200':\n description: Action performed successfully\n content:\n application/json:\n schema:\n type: object\n properties:\n success:\n type: boolean\n result:\n type: string\n details:\n type: object\n" + }, + "Description": "A custom action group for testing", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "test-action-group-agent", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "MyAgentRoleE8318EBB", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is a test instruction that must be at least 40 characters long to be valid", + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "MyAgentRoleDefaultPolicy30DBC7AC" + ] + } + }, + "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/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/cdk.out b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b3a26d44a5f73 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"44.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/integ.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/integ.json new file mode 100644 index 0000000000000..5a7d4e22c58be --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "44.0.0", + "testCases": { + "BedrockActionGroup/DefaultTest": { + "stacks": [ + "aws-cdk-bedrock-action-group-1" + ], + "assertionStack": "BedrockActionGroup/DefaultTest/DeployAssert", + "assertionStackName": "BedrockActionGroupDefaultTestDeployAssertE2AFA81B" + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/manifest.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/manifest.json new file mode 100644 index 0000000000000..63f4c882dbb00 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/manifest.json @@ -0,0 +1,264 @@ +{ + "version": "44.0.0", + "artifacts": { + "aws-cdk-bedrock-action-group-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-bedrock-action-group-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-bedrock-action-group-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-bedrock-action-group-1.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}/29d201f8af6439d216cfb9ba6b3eaf48b3f679dc9a03a6b09154f412a64839de.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-bedrock-action-group-1.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-cdk-bedrock-action-group-1.assets" + ], + "metadata": { + "/aws-cdk-bedrock-action-group-1/ActionGroupFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-action-group-1/ActionGroupFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-action-group-1/ActionGroupFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-action-group-1/ActionGroupFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ActionGroupFunctionServiceRole77660D62" + } + ], + "/aws-cdk-bedrock-action-group-1/ActionGroupFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ActionGroupFunctionFE14D1CB" + } + ], + "/aws-cdk-bedrock-action-group-1/ActionGroupFunction/LambdaInvocationPolicy-c855117c0e9b7e1e": [ + { + "type": "aws:cdk:logicalId", + "data": "ActionGroupFunctionLambdaInvocationPolicyc855117c0e9b7e1e08A69654" + } + ], + "/aws-cdk-bedrock-action-group-1/MyAgent/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-action-group-1/MyAgent/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-action-group-1/MyAgent/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyAgentRoleE8318EBB" + } + ], + "/aws-cdk-bedrock-action-group-1/MyAgent/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-action-group-1/MyAgent/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyAgentRoleDefaultPolicy30DBC7AC" + } + ], + "/aws-cdk-bedrock-action-group-1/MyAgent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyAgent039CC8B3" + } + ], + "/aws-cdk-bedrock-action-group-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-bedrock-action-group-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-bedrock-action-group-1" + }, + "BedrockActionGroupDefaultTestDeployAssertE2AFA81B.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "BedrockActionGroupDefaultTestDeployAssertE2AFA81B.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "BedrockActionGroupDefaultTestDeployAssertE2AFA81B": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BedrockActionGroupDefaultTestDeployAssertE2AFA81B.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": [ + "BedrockActionGroupDefaultTestDeployAssertE2AFA81B.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": [ + "BedrockActionGroupDefaultTestDeployAssertE2AFA81B.assets" + ], + "metadata": { + "/BedrockActionGroup/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/BedrockActionGroup/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "BedrockActionGroup/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/tree.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/tree.json new file mode 100644 index 0000000000000..64d8d781695c3 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"aws-cdk-bedrock-action-group-1":{"id":"aws-cdk-bedrock-action-group-1","path":"aws-cdk-bedrock-action-group-1","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"ActionGroupFunction":{"id":"ActionGroupFunction","path":"aws-cdk-bedrock-action-group-1/ActionGroupFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-action-group-1/ActionGroupFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-action-group-1/ActionGroupFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-action-group-1/ActionGroupFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-action-group-1/ActionGroupFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["ActionGroupFunctionServiceRole77660D62","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c855117c0e9b7e1e":{"id":"LambdaInvocationPolicy-c855117c0e9b7e1e","path":"aws-cdk-bedrock-action-group-1/ActionGroupFunction/LambdaInvocationPolicy-c855117c0e9b7e1e","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["ActionGroupFunctionFE14D1CB","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"MyAgent":{"id":"MyAgent","path":"aws-cdk-bedrock-action-group-1/MyAgent","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]},"children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-action-group-1/MyAgent/Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-action-group-1/MyAgent/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-action-group-1/MyAgent/Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockactiongroup1-myagent-319c695f-bedrockagent"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-action-group-1/MyAgent/Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-action-group-1/MyAgent/Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"lambda:InvokeFunction","Effect":"Allow","Resource":[{"Fn::GetAtt":["ActionGroupFunctionFE14D1CB","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["ActionGroupFunctionFE14D1CB","Arn"]},":*"]]}]},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"MyAgentRoleDefaultPolicy30DBC7AC","roles":[{"Ref":"MyAgentRoleE8318EBB"}]}}}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-action-group-1/MyAgent/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"ENABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"ENABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["ActionGroupFunctionFE14D1CB","Arn"]}},"actionGroupName":"CustomActionGroup","actionGroupState":"ENABLED","apiSchema":{"payload":"\nopenapi: 3.0.3\ninfo:\n title: Action Group API\n version: 1.0.0\npaths:\n /perform-action:\n post:\n operationId: performAction\n summary: Perform an action\n description: Perform an action with the specified parameters\n requestBody:\n required: true\n content:\n application/json:\n schema:\n type: object\n required:\n - action_type\n properties:\n action_type:\n type: string\n description: Type of action to perform\n parameters:\n type: object\n description: Additional parameters for the action\n responses:\n '200':\n description: Action performed successfully\n content:\n application/json:\n schema:\n type: object\n properties:\n success:\n type: boolean\n result:\n type: string\n details:\n type: object\n"},"description":"A custom action group for testing","skipResourceInUseCheckOnDelete":false}],"agentName":"test-action-group-agent","agentResourceRoleArn":{"Fn::GetAtt":["MyAgentRoleE8318EBB","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is a test instruction that must be at least 40 characters long to be valid","orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-action-group-1/MyAgent/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-bedrock-action-group-1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-bedrock-action-group-1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"BedrockActionGroup":{"id":"BedrockActionGroup","path":"BedrockActionGroup","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"BedrockActionGroup/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"BedrockActionGroup/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"BedrockActionGroup/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"BedrockActionGroup/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"BedrockActionGroup/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.ts new file mode 100644 index 0000000000000..8f12f73047461 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.action-group.ts @@ -0,0 +1,110 @@ +/* + * Integration test for Bedrock Agent Action Group construct + */ + +/// !cdk-integ aws-cdk-bedrock-action-group-1 + +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as bedrock from '../../../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-action-group-1'); + +// Create a Lambda function for the action group executor +const actionGroupFunction = new lambda.Function(stack, 'ActionGroupFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from action group' } + } + } + }; + }; + `), +}); + +// Create an API schema for the action group - using YAML format +const apiSchema = bedrock.ApiSchema.fromInline(` +openapi: 3.0.3 +info: + title: Action Group API + version: 1.0.0 +paths: + /perform-action: + post: + operationId: performAction + summary: Perform an action + description: Perform an action with the specified parameters + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - action_type + properties: + action_type: + type: string + description: Type of action to perform + parameters: + type: object + description: Additional parameters for the action + responses: + '200': + description: Action performed successfully + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + result: + type: string + details: + type: object +`); + +// Create an action group executor +const actionGroupExecutor = bedrock.ActionGroupExecutor.fromLambda(actionGroupFunction); + +// Create a Bedrock Agent with custom action groups +new bedrock.Agent(stack, 'MyAgent', { + agentName: 'test-action-group-agent', + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + // Enable built-in action groups + userInputEnabled: true, + codeInterpreterEnabled: true, + // Add a custom action group + actionGroups: [ + new bedrock.AgentActionGroup({ + name: 'CustomActionGroup', + description: 'A custom action group for testing', + apiSchema: apiSchema, + executor: actionGroupExecutor, + enabled: true, + }), + ], +}); + +new integ.IntegTest(app, 'BedrockActionGroup', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.assets.json new file mode 100644 index 0000000000000..985571ebdee78 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.assets.json @@ -0,0 +1,20 @@ +{ + "version": "41.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2 Template", + "source": { + "path": "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.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/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.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/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/aws-cdk-bedrock-agent-collaborator-1.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/aws-cdk-bedrock-agent-collaborator-1.assets.json new file mode 100644 index 0000000000000..62ae84300319b --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/aws-cdk-bedrock-agent-collaborator-1.assets.json @@ -0,0 +1,20 @@ +{ + "version": "41.0.0", + "files": { + "810add6e3357a035537eaa8699e651d4beaefe0e40808bc7afca5751de03ea88": { + "displayName": "aws-cdk-bedrock-agent-collaborator-1 Template", + "source": { + "path": "aws-cdk-bedrock-agent-collaborator-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "810add6e3357a035537eaa8699e651d4beaefe0e40808bc7afca5751de03ea88.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/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/aws-cdk-bedrock-agent-collaborator-1.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/aws-cdk-bedrock-agent-collaborator-1.template.json new file mode 100644 index 0000000000000..9f9725ae4d33b --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/aws-cdk-bedrock-agent-collaborator-1.template.json @@ -0,0 +1,351 @@ +{ + "Resources": { + "CollaboratorAgentRoleB40DB843": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockagentcollaboratoragent-bedab26c-bedrockagent" + } + }, + "CollaboratorAgentRoleDefaultPolicy40D7F24F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CollaboratorAgentRoleDefaultPolicy40D7F24F", + "Roles": [ + { + "Ref": "CollaboratorAgentRoleB40DB843" + } + ] + } + }, + "CollaboratorAgent1160D465": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "collaborator-agent", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "CollaboratorAgentRoleB40DB843", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is a collaborator agent with at least 40 characters of instruction", + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "CollaboratorAgentRoleDefaultPolicy40D7F24F" + ] + }, + "CollaboratorAliasDF4958C3": { + "Type": "AWS::Bedrock::AgentAlias", + "Properties": { + "AgentAliasName": "collaborator-alias", + "AgentId": { + "Fn::GetAtt": [ + "CollaboratorAgent1160D465", + "AgentId" + ] + } + } + }, + "CollaborativeAgentRole0E9B1104": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockagentollaborativeagent-63d793e3-bedrockagent" + } + }, + "CollaborativeAgentRoleDefaultPolicy94AAE53F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "bedrock:GetAgentAlias", + "bedrock:InvokeAgent" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "CollaboratorAliasDF4958C3", + "AgentAliasArn" + ] + } + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CollaborativeAgentRoleDefaultPolicy94AAE53F", + "Roles": [ + { + "Ref": "CollaborativeAgentRole0E9B1104" + } + ] + } + }, + "CollaborativeAgent97CD08C5": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentCollaboration": "SUPERVISOR", + "AgentCollaborators": [ + { + "AgentDescriptor": { + "AliasArn": { + "Fn::GetAtt": [ + "CollaboratorAliasDF4958C3", + "AgentAliasArn" + ] + } + }, + "CollaborationInstruction": "Help the primary agent with complex tasks and provide additional context", + "CollaboratorName": "HelperAgent", + "RelayConversationHistory": "TO_COLLABORATOR" + } + ], + "AgentName": "collaborative-agent", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "CollaborativeAgentRole0E9B1104", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is a collaborative agent with at least 40 characters of instruction", + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "CollaborativeAgentRoleDefaultPolicy94AAE53F" + ] + } + }, + "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/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/cdk.out b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/cdk.out new file mode 100644 index 0000000000000..188478b55560e --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"41.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/integ.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/integ.json new file mode 100644 index 0000000000000..562e62cf7bb5f --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "41.0.0", + "testCases": { + "BedrockAgentCollaborator/DefaultTest": { + "stacks": [ + "aws-cdk-bedrock-agent-collaborator-1" + ], + "assertionStack": "BedrockAgentCollaborator/DefaultTest/DeployAssert", + "assertionStackName": "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2" + } + }, + "minimumCliVersion": "2.1005.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/manifest.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/manifest.json new file mode 100644 index 0000000000000..fd6424370d6d4 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/manifest.json @@ -0,0 +1,326 @@ +{ + "version": "43.0.0", + "artifacts": { + "aws-cdk-bedrock-agent-collaborator-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-bedrock-agent-collaborator-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-bedrock-agent-collaborator-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-bedrock-agent-collaborator-1.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}/810add6e3357a035537eaa8699e651d4beaefe0e40808bc7afca5751de03ea88.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-bedrock-agent-collaborator-1.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-cdk-bedrock-agent-collaborator-1.assets" + ], + "metadata": { + "/aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAgentRoleB40DB843" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAgentRoleDefaultPolicy40D7F24F" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAgent1160D465" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaboratorAlias/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAliasDF4958C3" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaborativeAgentRole0E9B1104" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaborativeAgentRoleDefaultPolicy94AAE53F" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaborativeAgent97CD08C5" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-bedrock-agent-collaborator-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-bedrock-agent-collaborator-1" + }, + "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.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": [ + "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.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": [ + "BedrockAgentCollaboratorDefaultTestDeployAssertB2859CB2.assets" + ], + "metadata": { + "/BedrockAgentCollaborator/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/BedrockAgentCollaborator/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "BedrockAgentCollaborator/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1015.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/tree.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/tree.json new file mode 100644 index 0000000000000..dd91302704275 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","children":{"aws-cdk-bedrock-agent-collaborator-1":{"id":"aws-cdk-bedrock-agent-collaborator-1","path":"aws-cdk-bedrock-agent-collaborator-1","children":{"CollaboratorAgent":{"id":"CollaboratorAgent","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent","children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role","children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockagentcollaboratoragent-bedab26c-bedrockagent"}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Role/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"CollaboratorAgentRoleDefaultPolicy40D7F24F","roles":[{"Ref":"CollaboratorAgentRoleB40DB843"}]}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]}]}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]}]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false}],"agentName":"collaborator-agent","agentResourceRoleArn":{"Fn::GetAtt":["CollaboratorAgentRoleB40DB843","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is a collaborator agent with at least 40 characters of instruction","orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}},"constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAgent/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}},"constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]}},"CollaboratorAlias":{"id":"CollaboratorAlias","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAlias","children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-collaborator-1/CollaboratorAlias/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::AgentAlias","aws:cdk:cloudformation:props":{"agentAliasName":"collaborator-alias","agentId":{"Fn::GetAtt":["CollaboratorAgent1160D465","AgentId"]}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgentAlias","version":"0.0.0"}}},"constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAlias","version":"0.0.0","metadata":[]}},"CollaborativeAgent":{"id":"CollaborativeAgent","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent","children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role","children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockagentollaborativeagent-63d793e3-bedrockagent"}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Role/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["bedrock:GetAgentAlias","bedrock:InvokeAgent"],"Effect":"Allow","Resource":{"Fn::GetAtt":["CollaboratorAliasDF4958C3","AgentAliasArn"]}},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"CollaborativeAgentRoleDefaultPolicy94AAE53F","roles":[{"Ref":"CollaborativeAgentRole0E9B1104"}]}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]}]}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]}]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false}],"agentCollaboration":"SUPERVISOR","agentCollaborators":[{"agentDescriptor":{"aliasArn":{"Fn::GetAtt":["CollaboratorAliasDF4958C3","AgentAliasArn"]}},"collaborationInstruction":"Help the primary agent with complex tasks and provide additional context","collaboratorName":"HelperAgent","relayConversationHistory":"TO_COLLABORATOR"}],"agentName":"collaborative-agent","agentResourceRoleArn":{"Fn::GetAtt":["CollaborativeAgentRole0E9B1104","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is a collaborative agent with at least 40 characters of instruction","orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}},"constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-agent-collaborator-1/CollaborativeAgent/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}},"constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-bedrock-agent-collaborator-1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-bedrock-agent-collaborator-1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}},"constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"}},"BedrockAgentCollaborator":{"id":"BedrockAgentCollaborator","path":"BedrockAgentCollaborator","children":{"DefaultTest":{"id":"DefaultTest","path":"BedrockAgentCollaborator/DefaultTest","children":{"Default":{"id":"Default","path":"BedrockAgentCollaborator/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"BedrockAgentCollaborator/DefaultTest/DeployAssert","children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"BedrockAgentCollaborator/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"BedrockAgentCollaborator/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.4.2"}}},"constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"}}} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.ts new file mode 100644 index 0000000000000..8215695464ed3 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent-collaborator.ts @@ -0,0 +1,53 @@ +/* + * Integration test for Bedrock Agent Collaborator construct + */ + +/// !cdk-integ aws-cdk-bedrock-agent-collaborator-1 + +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as bedrock from '../../../bedrock'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-agent-collaborator-1'); + +// Create a collaborator agent +const collaboratorAgent = new bedrock.Agent(stack, 'CollaboratorAgent', { + agentName: 'collaborator-agent', + instruction: 'This is a collaborator agent with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, +}); + +// Create a custom alias for the collaborator agent (not using the test alias) +const collaboratorAlias = new bedrock.AgentAlias(stack, 'CollaboratorAlias', { + agentAliasName: 'collaborator-alias', + agent: collaboratorAgent, +}); + +// Create a primary agent with collaboration enabled +new bedrock.Agent(stack, 'CollaborativeAgent', { + agentName: 'collaborative-agent', + instruction: 'This is a collaborative agent with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + // Configure collaboration + agentCollaboration: new bedrock.AgentCollaboration({ + type: bedrock.AgentCollaboratorType.SUPERVISOR, + collaborators: [ + new bedrock.AgentCollaborator({ + agentAlias: collaboratorAlias, + collaborationInstruction: 'Help the primary agent with complex tasks and provide additional context', + collaboratorName: 'HelperAgent', + relayConversationHistory: true, + }), + ], + }), +}); + +new integ.IntegTest(app, 'BedrockAgentCollaborator', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/BedrockAgentDefaultTestDeployAssertB292ADF7.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/BedrockAgentDefaultTestDeployAssertB292ADF7.assets.json new file mode 100644 index 0000000000000..18f4f27a25ebc --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/BedrockAgentDefaultTestDeployAssertB292ADF7.assets.json @@ -0,0 +1,20 @@ +{ + "version": "41.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "BedrockAgentDefaultTestDeployAssertB292ADF7 Template", + "source": { + "path": "BedrockAgentDefaultTestDeployAssertB292ADF7.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/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/BedrockAgentDefaultTestDeployAssertB292ADF7.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/BedrockAgentDefaultTestDeployAssertB292ADF7.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/BedrockAgentDefaultTestDeployAssertB292ADF7.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/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/aws-cdk-bedrock-agent-1.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/aws-cdk-bedrock-agent-1.assets.json new file mode 100644 index 0000000000000..cef1ea5c13b68 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/aws-cdk-bedrock-agent-1.assets.json @@ -0,0 +1,20 @@ +{ + "version": "41.0.0", + "files": { + "1ccef654855f0ab36b3d105c6acf64655d82a459ca134a8780abe8fd415fe90f": { + "displayName": "aws-cdk-bedrock-agent-1 Template", + "source": { + "path": "aws-cdk-bedrock-agent-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "1ccef654855f0ab36b3d105c6acf64655d82a459ca134a8780abe8fd415fe90f.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/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/aws-cdk-bedrock-agent-1.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/aws-cdk-bedrock-agent-1.template.json new file mode 100644 index 0000000000000..8a9fe4612dec1 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/aws-cdk-bedrock-agent-1.template.json @@ -0,0 +1,351 @@ +{ + "Resources": { + "CollaboratorAgentRoleB40DB843": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockagentcollaboratoragent-c03c736b-bedrockagent" + } + }, + "CollaboratorAgentRoleDefaultPolicy40D7F24F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CollaboratorAgentRoleDefaultPolicy40D7F24F", + "Roles": [ + { + "Ref": "CollaboratorAgentRoleB40DB843" + } + ] + } + }, + "CollaboratorAgent1160D465": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "collaborator-agent", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "CollaboratorAgentRoleB40DB843", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is a collaborator agent with at least 40 characters of instruction", + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "CollaboratorAgentRoleDefaultPolicy40D7F24F" + ] + }, + "CollaboratorAliasDF4958C3": { + "Type": "AWS::Bedrock::AgentAlias", + "Properties": { + "AgentAliasName": "collaborator-alias", + "AgentId": { + "Fn::GetAtt": [ + "CollaboratorAgent1160D465", + "AgentId" + ] + } + } + }, + "MyAgentRoleE8318EBB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockagent1-myagent-ed4c69ab-bedrockagent" + } + }, + "MyAgentRoleDefaultPolicy30DBC7AC": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "bedrock:GetAgentAlias", + "bedrock:InvokeAgent" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "CollaboratorAliasDF4958C3", + "AgentAliasArn" + ] + } + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyAgentRoleDefaultPolicy30DBC7AC", + "Roles": [ + { + "Ref": "MyAgentRoleE8318EBB" + } + ] + } + }, + "MyAgent039CC8B3": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentCollaboration": "SUPERVISOR", + "AgentCollaborators": [ + { + "AgentDescriptor": { + "AliasArn": { + "Fn::GetAtt": [ + "CollaboratorAliasDF4958C3", + "AgentAliasArn" + ] + } + }, + "CollaborationInstruction": "Help the primary agent with complex tasks and provide additional context", + "CollaboratorName": "HelperAgent", + "RelayConversationHistory": "TO_COLLABORATOR" + } + ], + "AgentName": "test-agent-1", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "MyAgentRoleE8318EBB", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is a test instruction that must be at least 40 characters long to be valid", + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "MyAgentRoleDefaultPolicy30DBC7AC" + ] + } + }, + "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/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/cdk.out b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/cdk.out new file mode 100644 index 0000000000000..188478b55560e --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"41.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/integ.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/integ.json new file mode 100644 index 0000000000000..4abde9b0edb7f --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "41.0.0", + "testCases": { + "BedrockAgent/DefaultTest": { + "stacks": [ + "aws-cdk-bedrock-agent-1" + ], + "assertionStack": "BedrockAgent/DefaultTest/DeployAssert", + "assertionStackName": "BedrockAgentDefaultTestDeployAssertB292ADF7" + } + }, + "minimumCliVersion": "2.1005.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/manifest.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/manifest.json new file mode 100644 index 0000000000000..8322b07996474 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/manifest.json @@ -0,0 +1,326 @@ +{ + "version": "43.0.0", + "artifacts": { + "aws-cdk-bedrock-agent-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-bedrock-agent-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-bedrock-agent-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-bedrock-agent-1.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}/1ccef654855f0ab36b3d105c6acf64655d82a459ca134a8780abe8fd415fe90f.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-bedrock-agent-1.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-cdk-bedrock-agent-1.assets" + ], + "metadata": { + "/aws-cdk-bedrock-agent-1/CollaboratorAgent/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + } + ], + "/aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAgentRoleB40DB843" + } + ], + "/aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAgentRoleDefaultPolicy40D7F24F" + } + ], + "/aws-cdk-bedrock-agent-1/CollaboratorAgent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAgent1160D465" + } + ], + "/aws-cdk-bedrock-agent-1/CollaboratorAlias/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CollaboratorAliasDF4958C3" + } + ], + "/aws-cdk-bedrock-agent-1/MyAgent/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-agent-1/MyAgent/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-agent-1/MyAgent/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyAgentRoleE8318EBB" + } + ], + "/aws-cdk-bedrock-agent-1/MyAgent/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-agent-1/MyAgent/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyAgentRoleDefaultPolicy30DBC7AC" + } + ], + "/aws-cdk-bedrock-agent-1/MyAgent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyAgent039CC8B3" + } + ], + "/aws-cdk-bedrock-agent-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-bedrock-agent-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-bedrock-agent-1" + }, + "BedrockAgentDefaultTestDeployAssertB292ADF7.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "BedrockAgentDefaultTestDeployAssertB292ADF7.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "BedrockAgentDefaultTestDeployAssertB292ADF7": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BedrockAgentDefaultTestDeployAssertB292ADF7.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": [ + "BedrockAgentDefaultTestDeployAssertB292ADF7.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": [ + "BedrockAgentDefaultTestDeployAssertB292ADF7.assets" + ], + "metadata": { + "/BedrockAgent/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/BedrockAgent/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "BedrockAgent/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1015.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/tree.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/tree.json new file mode 100644 index 0000000000000..cddc3070fe1cd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","children":{"aws-cdk-bedrock-agent-1":{"id":"aws-cdk-bedrock-agent-1","path":"aws-cdk-bedrock-agent-1","children":{"CollaboratorAgent":{"id":"CollaboratorAgent","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent","children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent/Role","children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockagentcollaboratoragent-c03c736b-bedrockagent"}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent/Role/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"CollaboratorAgentRoleDefaultPolicy40D7F24F","roles":[{"Ref":"CollaboratorAgentRoleB40DB843"}]}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]}]}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]}]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false}],"agentName":"collaborator-agent","agentResourceRoleArn":{"Fn::GetAtt":["CollaboratorAgentRoleB40DB843","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is a collaborator agent with at least 40 characters of instruction","orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}},"constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-agent-1/CollaboratorAgent/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}},"constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]}},"CollaboratorAlias":{"id":"CollaboratorAlias","path":"aws-cdk-bedrock-agent-1/CollaboratorAlias","children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-1/CollaboratorAlias/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::AgentAlias","aws:cdk:cloudformation:props":{"agentAliasName":"collaborator-alias","agentId":{"Fn::GetAtt":["CollaboratorAgent1160D465","AgentId"]}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgentAlias","version":"0.0.0"}}},"constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAlias","version":"0.0.0","metadata":[]}},"MyAgent":{"id":"MyAgent","path":"aws-cdk-bedrock-agent-1/MyAgent","children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-agent-1/MyAgent/Role","children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-agent-1/MyAgent/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-1/MyAgent/Role/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockagent1-myagent-ed4c69ab-bedrockagent"}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-agent-1/MyAgent/Role/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-1/MyAgent/Role/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["bedrock:GetAgentAlias","bedrock:InvokeAgent"],"Effect":"Allow","Resource":{"Fn::GetAtt":["CollaboratorAliasDF4958C3","AgentAliasArn"]}},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"MyAgentRoleDefaultPolicy30DBC7AC","roles":[{"Ref":"MyAgentRoleE8318EBB"}]}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]}]}}},"constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]}]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-agent-1/MyAgent/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false}],"agentCollaboration":"SUPERVISOR","agentCollaborators":[{"agentDescriptor":{"aliasArn":{"Fn::GetAtt":["CollaboratorAliasDF4958C3","AgentAliasArn"]}},"collaborationInstruction":"Help the primary agent with complex tasks and provide additional context","collaboratorName":"HelperAgent","relayConversationHistory":"TO_COLLABORATOR"}],"agentName":"test-agent-1","agentResourceRoleArn":{"Fn::GetAtt":["MyAgentRoleE8318EBB","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is a test instruction that must be at least 40 characters long to be valid","orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}},"constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-agent-1/MyAgent/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}},"constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-bedrock-agent-1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-bedrock-agent-1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}},"constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"}},"BedrockAgent":{"id":"BedrockAgent","path":"BedrockAgent","children":{"DefaultTest":{"id":"DefaultTest","path":"BedrockAgent/DefaultTest","children":{"Default":{"id":"Default","path":"BedrockAgent/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"BedrockAgent/DefaultTest/DeployAssert","children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"BedrockAgent/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"BedrockAgent/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.4.2"}}},"constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"}}} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.ts new file mode 100644 index 0000000000000..5e02af1a83d4a --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.agent.ts @@ -0,0 +1,53 @@ +/* + * Integration test for Bedrock Agent construct + */ + +/// !cdk-integ aws-cdk-bedrock-agent-1 + +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as bedrock from '../../../bedrock'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-agent-1'); + +// Create a collaborator agent +const collaboratorAgent = new bedrock.Agent(stack, 'CollaboratorAgent', { + agentName: 'collaborator-agent', + instruction: 'This is a collaborator agent with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, +}); + +// Create a custom alias for the collaborator agent +const collaboratorAlias = new bedrock.AgentAlias(stack, 'CollaboratorAlias', { + agentAliasName: 'collaborator-alias', + agent: collaboratorAgent, +}); + +// Create a Bedrock Agent with collaboration enabled +new bedrock.Agent(stack, 'MyAgent', { + agentName: 'test-agent-1', + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + // Configure collaboration + agentCollaboration: new bedrock.AgentCollaboration({ + type: bedrock.AgentCollaboratorType.SUPERVISOR, + collaborators: [ + new bedrock.AgentCollaborator({ + agentAlias: collaboratorAlias, + collaborationInstruction: 'Help the primary agent with complex tasks and provide additional context', + collaboratorName: 'HelperAgent', + relayConversationHistory: true, + }), + ], + }), +}); + +new integ.IntegTest(app, 'BedrockAgent', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.assets.json new file mode 100644 index 0000000000000..b1a778eed5153 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57 Template", + "source": { + "path": "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.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/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.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/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.049f5de90fd9c8b8d2580a7b668c1c5368e67ef5bd0397322e3a90349b740e8f/schema/s3-api-schema.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.049f5de90fd9c8b8d2580a7b668c1c5368e67ef5bd0397322e3a90349b740e8f/schema/s3-api-schema.json new file mode 100644 index 0000000000000..a9d7497c0610b --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.049f5de90fd9c8b8d2580a7b668c1c5368e67ef5bd0397322e3a90349b740e8f/schema/s3-api-schema.json @@ -0,0 +1,33 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "S3 API Schema", + "version": "1.0.0" + }, + "paths": { + "/s3hello": { + "get": { + "operationId": "s3HelloWorld", + "summary": "Say hello from S3", + "description": "Returns a greeting message from S3-stored schema", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js new file mode 100644 index 0000000000000..1002ba018e9fb --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js @@ -0,0 +1 @@ +"use strict";var f=Object.create;var i=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var A=(t,e)=>{for(var o in e)i(t,o,{get:e[o],enumerable:!0})},d=(t,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of C(e))!P.call(t,s)&&s!==o&&i(t,s,{get:()=>e[s],enumerable:!(r=I(e,s))||r.enumerable});return t};var l=(t,e,o)=>(o=t!=null?f(w(t)):{},d(e||!t||!t.__esModule?i(o,"default",{value:t,enumerable:!0}):o,t)),B=t=>d(i({},"__esModule",{value:!0}),t);var q={};A(q,{autoDeleteHandler:()=>S,handler:()=>H});module.exports=B(q);var h=require("@aws-sdk/client-s3");var y=l(require("https")),m=l(require("url")),a={sendHttpRequest:D,log:T,includeStackTraces:!0,userHandlerIndex:"./index"},p="AWSCDK::CustomResourceProviderFramework::CREATE_FAILED",L="AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID";function R(t){return async(e,o)=>{let r={...e,ResponseURL:"..."};if(a.log(JSON.stringify(r,void 0,2)),e.RequestType==="Delete"&&e.PhysicalResourceId===p){a.log("ignoring DELETE event caused by a failed CREATE event"),await u("SUCCESS",e);return}try{let s=await t(r,o),n=k(e,s);await u("SUCCESS",n)}catch(s){let n={...e,Reason:a.includeStackTraces?s.stack:s.message};n.PhysicalResourceId||(e.RequestType==="Create"?(a.log("CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored"),n.PhysicalResourceId=p):a.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(e)}`)),await u("FAILED",n)}}}function k(t,e={}){let o=e.PhysicalResourceId??t.PhysicalResourceId??t.RequestId;if(t.RequestType==="Delete"&&o!==t.PhysicalResourceId)throw new Error(`DELETE: cannot change the physical resource ID from "${t.PhysicalResourceId}" to "${e.PhysicalResourceId}" during deletion`);return{...t,...e,PhysicalResourceId:o}}async function u(t,e){let o={Status:t,Reason:e.Reason??t,StackId:e.StackId,RequestId:e.RequestId,PhysicalResourceId:e.PhysicalResourceId||L,LogicalResourceId:e.LogicalResourceId,NoEcho:e.NoEcho,Data:e.Data},r=m.parse(e.ResponseURL),s=`${r.protocol}//${r.hostname}/${r.pathname}?***`;a.log("submit response to cloudformation",s,o);let n=JSON.stringify(o),E={hostname:r.hostname,path:r.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(n,"utf8")}};await O({attempts:5,sleep:1e3},a.sendHttpRequest)(E,n)}async function D(t,e){return new Promise((o,r)=>{try{let s=y.request(t,n=>{n.resume(),!n.statusCode||n.statusCode>=400?r(new Error(`Unsuccessful HTTP response: ${n.statusCode}`)):o()});s.on("error",r),s.write(e),s.end()}catch(s){r(s)}})}function T(t,...e){console.log(t,...e)}function O(t,e){return async(...o)=>{let r=t.attempts,s=t.sleep;for(;;)try{return await e(...o)}catch(n){if(r--<=0)throw n;await b(Math.floor(Math.random()*s)),s*=2}}}async function b(t){return new Promise(e=>setTimeout(e,t))}var g="aws-cdk:auto-delete-objects",x=JSON.stringify({Version:"2012-10-17",Statement:[]}),c=new h.S3({}),H=R(S);async function S(t){switch(t.RequestType){case"Create":return;case"Update":return{PhysicalResourceId:(await F(t)).PhysicalResourceId};case"Delete":return N(t.ResourceProperties?.BucketName)}}async function F(t){let e=t,o=e.OldResourceProperties?.BucketName;return{PhysicalResourceId:e.ResourceProperties?.BucketName??o}}async function _(t){try{let e=(await c.getBucketPolicy({Bucket:t}))?.Policy??x,o=JSON.parse(e);o.Statement.push({Principal:"*",Effect:"Deny",Action:["s3:PutObject"],Resource:[`arn:aws:s3:::${t}/*`]}),await c.putBucketPolicy({Bucket:t,Policy:JSON.stringify(o)})}catch(e){if(e.name==="NoSuchBucket")throw e;console.log(`Could not set new object deny policy on bucket '${t}' prior to deletion.`)}}async function U(t){let e;do{e=await c.listObjectVersions({Bucket:t});let o=[...e.Versions??[],...e.DeleteMarkers??[]];if(o.length===0)return;let r=o.map(s=>({Key:s.Key,VersionId:s.VersionId}));await c.deleteObjects({Bucket:t,Delete:{Objects:r}})}while(e?.IsTruncated)}async function N(t){if(!t)throw new Error("No BucketName was provided.");try{if(!await W(t)){console.log(`Bucket does not have '${g}' tag, skipping cleaning.`);return}await _(t),await U(t)}catch(e){if(e.name==="NoSuchBucket"){console.log(`Bucket '${t}' does not exist.`);return}throw e}}async function W(t){return(await c.getBucketTagging({Bucket:t})).TagSet?.some(o=>o.Key===g&&o.Value==="true")}0&&(module.exports={autoDeleteHandler,handler}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d/index.py b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d/index.py new file mode 100644 index 0000000000000..aeb2132fc67bb --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d/index.py @@ -0,0 +1,388 @@ +import contextlib +import json +import logging +import os +import shutil +import subprocess +import tempfile +import urllib.parse +from urllib.request import Request, urlopen +from uuid import uuid4 +from zipfile import ZipFile + +import boto3 + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +cloudfront = boto3.client('cloudfront') +s3 = boto3.client('s3') + +CFN_SUCCESS = "SUCCESS" +CFN_FAILED = "FAILED" +ENV_KEY_MOUNT_PATH = "MOUNT_PATH" +ENV_KEY_SKIP_CLEANUP = "SKIP_CLEANUP" + +AWS_CLI_CONFIG_FILE = "/tmp/aws_cli_config" +CUSTOM_RESOURCE_OWNER_TAG = "aws-cdk:cr-owned" + +os.putenv('AWS_CONFIG_FILE', AWS_CLI_CONFIG_FILE) + +def handler(event, context): + + def cfn_error(message=None): + if message: + logger.error("| cfn_error: %s" % message.encode()) + cfn_send(event, context, CFN_FAILED, reason=message, physicalResourceId=event.get('PhysicalResourceId', None)) + + + try: + # We are not logging ResponseURL as this is a pre-signed S3 URL, and could be used to tamper + # with the response CloudFormation sees from this Custom Resource execution. + logger.info({ key:value for (key, value) in event.items() if key != 'ResponseURL'}) + + # cloudformation request type (create/update/delete) + request_type = event['RequestType'] + + # extract resource properties + props = event['ResourceProperties'] + old_props = event.get('OldResourceProperties', {}) + physical_id = event.get('PhysicalResourceId', None) + + try: + source_bucket_names = props['SourceBucketNames'] + source_object_keys = props['SourceObjectKeys'] + source_markers = props.get('SourceMarkers', None) + source_markers_config = props.get('SourceMarkersConfig', None) + dest_bucket_name = props['DestinationBucketName'] + dest_bucket_prefix = props.get('DestinationBucketKeyPrefix', '') + extract = props.get('Extract', 'true') == 'true' + retain_on_delete = props.get('RetainOnDelete', "true") == "true" + distribution_id = props.get('DistributionId', '') + user_metadata = props.get('UserMetadata', {}) + system_metadata = props.get('SystemMetadata', {}) + prune = props.get('Prune', 'true').lower() == 'true' + exclude = props.get('Exclude', []) + include = props.get('Include', []) + sign_content = props.get('SignContent', 'false').lower() == 'true' + output_object_keys = props.get('OutputObjectKeys', 'true') == 'true' + + # backwards compatibility - if "SourceMarkers" is not specified, + # assume all sources have an empty market map + if source_markers is None: + source_markers = [{} for i in range(len(source_bucket_names))] + if source_markers_config is None: + source_markers_config = [{} for i in range(len(source_bucket_names))] + + default_distribution_path = dest_bucket_prefix + if not default_distribution_path.endswith("/"): + default_distribution_path += "/" + if not default_distribution_path.startswith("/"): + default_distribution_path = "/" + default_distribution_path + default_distribution_path += "*" + + distribution_paths = props.get('DistributionPaths', [default_distribution_path]) + except KeyError as e: + cfn_error("missing request resource property %s. props: %s" % (str(e), props)) + return + + # configure aws cli options after resetting back to the defaults for each request + if os.path.exists(AWS_CLI_CONFIG_FILE): + os.remove(AWS_CLI_CONFIG_FILE) + if sign_content: + aws_command("configure", "set", "default.s3.payload_signing_enabled", "true") + + # treat "/" as if no prefix was specified + if dest_bucket_prefix == "/": + dest_bucket_prefix = "" + + s3_source_zips = list(map(lambda name, key: "s3://%s/%s" % (name, key), source_bucket_names, source_object_keys)) + s3_dest = "s3://%s/%s" % (dest_bucket_name, dest_bucket_prefix) + old_s3_dest = "s3://%s/%s" % (old_props.get("DestinationBucketName", ""), old_props.get("DestinationBucketKeyPrefix", "")) + + + # obviously this is not + if old_s3_dest == "s3:///": + old_s3_dest = None + + logger.info("| s3_dest: %s" % sanitize_message(s3_dest)) + logger.info("| old_s3_dest: %s" % sanitize_message(old_s3_dest)) + + # if we are creating a new resource, allocate a physical id for it + # otherwise, we expect physical id to be relayed by cloudformation + if request_type == "Create": + physical_id = "aws.cdk.s3deployment.%s" % str(uuid4()) + else: + if not physical_id: + cfn_error("invalid request: request type is '%s' but 'PhysicalResourceId' is not defined" % request_type) + return + + # delete or create/update (only if "retain_on_delete" is false) + if request_type == "Delete" and not retain_on_delete: + if not bucket_owned(dest_bucket_name, dest_bucket_prefix): + aws_command("s3", "rm", s3_dest, "--recursive") + + # if we are updating without retention and the destination changed, delete first + if request_type == "Update" and not retain_on_delete and old_s3_dest != s3_dest: + if not old_s3_dest: + logger.warn("cannot delete old resource without old resource properties") + return + + aws_command("s3", "rm", old_s3_dest, "--recursive") + + if request_type == "Update" or request_type == "Create": + s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers, extract, source_markers_config) + + if distribution_id: + cloudfront_invalidate(distribution_id, distribution_paths) + + cfn_send(event, context, CFN_SUCCESS, physicalResourceId=physical_id, responseData={ + # Passing through the ARN sequences dependencees on the deployment + 'DestinationBucketArn': props.get('DestinationBucketArn'), + **({'SourceObjectKeys': props.get('SourceObjectKeys')} if output_object_keys else {'SourceObjectKeys': []}) + }) + except KeyError as e: + cfn_error("invalid request. Missing key %s" % str(e)) + except Exception as e: + logger.exception(e) + cfn_error(str(e)) + +#--------------------------------------------------------------------------------------------------- +# Sanitize the message to mitigate CWE-117 and CWE-93 vulnerabilities +def sanitize_message(message): + if not message: + return message + + # Sanitize the message to prevent log injection and HTTP response splitting + sanitized_message = message.replace('\n', '').replace('\r', '') + + # Encode the message to handle special characters + encoded_message = urllib.parse.quote(sanitized_message) + + return encoded_message + +#--------------------------------------------------------------------------------------------------- +# populate all files from s3_source_zips to a destination bucket +def s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers, extract, source_markers_config): + # list lengths are equal + if len(s3_source_zips) != len(source_markers): + raise Exception("'source_markers' and 's3_source_zips' must be the same length") + + # create a temporary working directory in /tmp or if enabled an attached efs volume + if ENV_KEY_MOUNT_PATH in os.environ: + workdir = os.getenv(ENV_KEY_MOUNT_PATH) + "/" + str(uuid4()) + os.mkdir(workdir) + else: + workdir = tempfile.mkdtemp() + + logger.info("| workdir: %s" % workdir) + + # create a directory into which we extract the contents of the zip file + contents_dir=os.path.join(workdir, 'contents') + os.mkdir(contents_dir) + + try: + # download the archive from the source and extract to "contents" + for i in range(len(s3_source_zips)): + s3_source_zip = s3_source_zips[i] + markers = source_markers[i] + markers_config = source_markers_config[i] + + if extract: + archive=os.path.join(workdir, str(uuid4())) + logger.info("archive: %s" % archive) + aws_command("s3", "cp", s3_source_zip, archive) + logger.info("| extracting archive to: %s\n" % contents_dir) + logger.info("| markers: %s" % markers) + extract_and_replace_markers(archive, contents_dir, markers, markers_config) + else: + logger.info("| copying archive to: %s\n" % contents_dir) + aws_command("s3", "cp", s3_source_zip, contents_dir) + + # sync from "contents" to destination + + s3_command = ["s3", "sync"] + + if prune: + s3_command.append("--delete") + + if exclude: + for filter in exclude: + s3_command.extend(["--exclude", filter]) + + if include: + for filter in include: + s3_command.extend(["--include", filter]) + + s3_command.extend([contents_dir, s3_dest]) + s3_command.extend(create_metadata_args(user_metadata, system_metadata)) + aws_command(*s3_command) + finally: + if not os.getenv(ENV_KEY_SKIP_CLEANUP): + shutil.rmtree(workdir) + +#--------------------------------------------------------------------------------------------------- +# invalidate files in the CloudFront distribution edge caches +def cloudfront_invalidate(distribution_id, distribution_paths): + invalidation_resp = cloudfront.create_invalidation( + DistributionId=distribution_id, + InvalidationBatch={ + 'Paths': { + 'Quantity': len(distribution_paths), + 'Items': distribution_paths + }, + 'CallerReference': str(uuid4()), + }) + # by default, will wait up to 10 minutes + cloudfront.get_waiter('invalidation_completed').wait( + DistributionId=distribution_id, + Id=invalidation_resp['Invalidation']['Id']) + +#--------------------------------------------------------------------------------------------------- +# set metadata +def create_metadata_args(raw_user_metadata, raw_system_metadata): + if len(raw_user_metadata) == 0 and len(raw_system_metadata) == 0: + return [] + + format_system_metadata_key = lambda k: k.lower() + format_user_metadata_key = lambda k: k.lower() + + system_metadata = { format_system_metadata_key(k): v for k, v in raw_system_metadata.items() } + user_metadata = { format_user_metadata_key(k): v for k, v in raw_user_metadata.items() } + + flatten = lambda l: [item for sublist in l for item in sublist] + system_args = flatten([[f"--{k}", v] for k, v in system_metadata.items()]) + user_args = ["--metadata", json.dumps(user_metadata, separators=(',', ':'))] if len(user_metadata) > 0 else [] + + return system_args + user_args + ["--metadata-directive", "REPLACE"] + +#--------------------------------------------------------------------------------------------------- +# executes an "aws" cli command +def aws_command(*args): + aws="/opt/awscli/aws" # from AwsCliLayer + logger.info("| aws %s" % ' '.join(args)) + subprocess.check_call([aws] + list(args)) + +#--------------------------------------------------------------------------------------------------- +# sends a response to cloudformation +def cfn_send(event, context, responseStatus, responseData={}, physicalResourceId=None, noEcho=False, reason=None): + + responseUrl = event['ResponseURL'] + + responseBody = {} + responseBody['Status'] = responseStatus + responseBody['Reason'] = reason or ('See the details in CloudWatch Log Stream: ' + context.log_stream_name) + responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name + responseBody['StackId'] = event['StackId'] + responseBody['RequestId'] = event['RequestId'] + responseBody['LogicalResourceId'] = event['LogicalResourceId'] + responseBody['NoEcho'] = noEcho + responseBody['Data'] = responseData + + body = json.dumps(responseBody) + logger.info("| response body:\n" + body) + + headers = { + 'content-type' : '', + 'content-length' : str(len(body)) + } + + try: + request = Request(responseUrl, method='PUT', data=bytes(body.encode('utf-8')), headers=headers) + with contextlib.closing(urlopen(request)) as response: + logger.info("| status code: " + response.reason) + except Exception as e: + logger.error("| unable to send response to CloudFormation") + logger.exception(e) + + +#--------------------------------------------------------------------------------------------------- +# check if bucket is owned by a custom resource +# if it is then we don't want to delete content +def bucket_owned(bucketName, keyPrefix): + tag = CUSTOM_RESOURCE_OWNER_TAG + if keyPrefix != "": + tag = tag + ':' + keyPrefix + try: + request = s3.get_bucket_tagging( + Bucket=bucketName, + ) + return any((x["Key"].startswith(tag)) for x in request["TagSet"]) + except Exception as e: + logger.info("| error getting tags from bucket") + logger.exception(e) + return False + +# extract archive and replace markers in output files +def extract_and_replace_markers(archive, contents_dir, markers, markers_config): + with ZipFile(archive, "r") as zip: + zip.extractall(contents_dir) + + # replace markers for this source + for file in zip.namelist(): + file_path = os.path.join(contents_dir, file) + if os.path.isdir(file_path): continue + replace_markers(file_path, markers, markers_config) + +def prepare_json_safe_markers(markers): + """Pre-process markers to ensure JSON-safe values""" + safe_markers = {} + for key, value in markers.items(): + # Serialize the value as JSON to handle escaping if the value is a string + serialized = json.dumps(value) + if serialized.startswith('"') and serialized.endswith('"'): + json_safe_value = json.dumps(value)[1:-1] # Remove surrounding quotes + else: + json_safe_value = serialized + safe_markers[key.encode('utf-8')] = json_safe_value.encode('utf-8') + return safe_markers + +def replace_markers(filename, markers, markers_config): + """Replace markers in a file, with special handling for JSON files.""" + # if there are no markers, skip + if not markers: + return + + outfile = filename + '.new' + json_escape = markers_config.get('jsonEscape', 'false').lower() + if json_escape == 'true': + replace_tokens = prepare_json_safe_markers(markers) + else: + replace_tokens = dict([(k.encode('utf-8'), v.encode('utf-8')) for k, v in markers.items()]) + + # Handle content with line-by-line binary replacement + with open(filename, 'rb') as fi, open(outfile, 'wb') as fo: + # Process line by line to handle large files + for line in fi: + for token, replacement in replace_tokens.items(): + line = line.replace(token, replacement) + fo.write(line) + + # Delete the original file and rename the new one to the original + os.remove(filename) + os.rename(outfile, filename) + +def replace_markers_in_json(json_object, replace_tokens): + """Replace markers in JSON content with proper escaping.""" + try: + def replace_in_structure(obj): + if isinstance(obj, str): + # Convert string to bytes for consistent replacement + result = obj.encode('utf-8') + for token, replacement in replace_tokens.items(): + result = result.replace(token, replacement) + # Convert back to string + return result.decode('utf-8') + elif isinstance(obj, dict): + return {k: replace_in_structure(v) for k, v in obj.items()} + elif isinstance(obj, list): + return [replace_in_structure(item) for item in obj] + return obj + + # Process the whole structure + processed = replace_in_structure(json_object) + return json.dumps(processed) + except Exception as e: + logger.error(f'Error processing JSON: {e}') + logger.exception(e) + return json_object diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml new file mode 100644 index 0000000000000..4accd4cadb267 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml @@ -0,0 +1,20 @@ +openapi: 3.0.3 +info: + title: Asset API Schema + version: 1.0.0 +paths: + /asset: + get: + operationId: assetHelloWorld + summary: Say hello from asset + description: Returns a greeting message from asset-stored schema + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + message: + type: string diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e.zip b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e.zip new file mode 100644 index 0000000000000..42b96d8fc1b3c --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/asset.b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ffc63a5b65bd5c8f0e3819f5c9f3b9f7335f35f35fac6ce8829606a6dc52ff0b +size 19940332 diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/aws-cdk-bedrock-api-schema-1.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/aws-cdk-bedrock-api-schema-1.assets.json new file mode 100644 index 0000000000000..d75a14064f8e2 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/aws-cdk-bedrock-api-schema-1.assets.json @@ -0,0 +1,90 @@ +{ + "version": "44.0.0", + "files": { + "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61": { + "displayName": "aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider Code", + "source": { + "path": "asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e": { + "displayName": "DeploySchema/AwsCliLayer/Code", + "source": { + "path": "asset.b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e.zip", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d": { + "displayName": "Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code", + "source": { + "path": "asset.9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "049f5de90fd9c8b8d2580a7b668c1c5368e67ef5bd0397322e3a90349b740e8f": { + "displayName": "DeploySchema/Asset1", + "source": { + "path": "asset.049f5de90fd9c8b8d2580a7b668c1c5368e67ef5bd0397322e3a90349b740e8f", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "049f5de90fd9c8b8d2580a7b668c1c5368e67ef5bd0397322e3a90349b740e8f.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0": { + "displayName": "Schema", + "source": { + "path": "asset.a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "7088b3cc688c2990cc3e59c4636a433a6fab1500854d9c74aa84e5ac1a2dc582": { + "displayName": "aws-cdk-bedrock-api-schema-1 Template", + "source": { + "path": "aws-cdk-bedrock-api-schema-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "7088b3cc688c2990cc3e59c4636a433a6fab1500854d9c74aa84e5ac1a2dc582.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/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/aws-cdk-bedrock-api-schema-1.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/aws-cdk-bedrock-api-schema-1.template.json new file mode 100644 index 0000000000000..5cd3748c8be11 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/aws-cdk-bedrock-api-schema-1.template.json @@ -0,0 +1,1065 @@ +{ + "Resources": { + "AssetActionGroupFunctionServiceRoleC53BA920": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "AssetActionGroupFunction98EC70AB": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from asset action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "AssetActionGroupFunctionServiceRoleC53BA920", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "AssetActionGroupFunctionServiceRoleC53BA920" + ] + }, + "AssetActionGroupFunctionLambdaInvocationPolicyc8dfda1d62217f4203A2E0A7": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "AssetActionGroupFunction98EC70AB", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "InlineActionGroupFunctionServiceRole5543D9A3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "InlineActionGroupFunction566CD00A": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from inline action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "InlineActionGroupFunctionServiceRole5543D9A3", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "InlineActionGroupFunctionServiceRole5543D9A3" + ] + }, + "InlineActionGroupFunctionLambdaInvocationPolicyc8dfda1d62217f42CE4591EF": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "InlineActionGroupFunction566CD00A", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "S3ActionGroupFunctionServiceRole7E4C5A58": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "S3ActionGroupFunctionA4648C25": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from S3 action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "S3ActionGroupFunctionServiceRole7E4C5A58", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "S3ActionGroupFunctionServiceRole7E4C5A58" + ] + }, + "S3ActionGroupFunctionLambdaInvocationPolicyc8dfda1d62217f4210E2D0E3": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "S3ActionGroupFunctionA4648C25", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "SchemaBucket79EE2269": { + "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + }, + { + "Key": "aws-cdk:cr-owned:911f5017", + "Value": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SchemaBucketPolicy557840E2": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "SchemaBucket79EE2269" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "SchemaBucket79EE2269", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SchemaBucket79EE2269", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "SchemaBucketAutoDeleteObjectsCustomResource0F518746": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "SchemaBucket79EE2269" + } + }, + "DependsOn": [ + "SchemaBucketPolicy557840E2" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] + } + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": { + "Fn::FindInMap": [ + "LatestNodeRuntimeMap", + { + "Ref": "AWS::Region" + }, + "value" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "SchemaBucket79EE2269" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ] + }, + "DeploySchemaAwsCliLayerD0D0BA6E": { + "Type": "AWS::Lambda::LayerVersion", + "Properties": { + "Content": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e.zip" + }, + "Description": "/opt/awscli/aws" + } + }, + "DeploySchemaCustomResource277E9836": { + "Type": "Custom::CDKBucketDeployment", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536", + "Arn" + ] + }, + "SourceBucketNames": [ + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + } + ], + "SourceObjectKeys": [ + "049f5de90fd9c8b8d2580a7b668c1c5368e67ef5bd0397322e3a90349b740e8f.zip" + ], + "SourceMarkers": [ + {} + ], + "DestinationBucketName": { + "Ref": "SchemaBucket79EE2269" + }, + "Prune": true, + "OutputObjectKeys": true + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + } + ] + ] + } + ] + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SchemaBucket79EE2269", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SchemaBucket79EE2269", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", + "Roles": [ + { + "Ref": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" + } + ] + } + }, + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d.zip" + }, + "Environment": { + "Variables": { + "AWS_CA_BUNDLE": "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" + } + }, + "Handler": "index.handler", + "Layers": [ + { + "Ref": "DeploySchemaAwsCliLayerD0D0BA6E" + } + ], + "Role": { + "Fn::GetAtt": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265", + "Arn" + ] + }, + "Runtime": "python3.11", + "Timeout": 900 + }, + "DependsOn": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" + ] + }, + "ApiSchemaAgentRole636AC572": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockapisca1-apischemaagent-b0e9b051-bedrockagent" + }, + "DependsOn": [ + "DeploySchemaAwsCliLayerD0D0BA6E", + "DeploySchemaCustomResource277E9836" + ] + }, + "ApiSchemaAgentRoleDefaultPolicy343EA6FE": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "AssetActionGroupFunction98EC70AB", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "InlineActionGroupFunction566CD00A", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "S3ActionGroupFunctionA4648C25", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "AssetActionGroupFunction98EC70AB", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "InlineActionGroupFunction566CD00A", + "Arn" + ] + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "S3ActionGroupFunctionA4648C25", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + } + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "SchemaBucket79EE2269" + }, + "/schema/s3-api-schema.json" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "SchemaBucket79EE2269" + } + ] + ] + } + ] + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ApiSchemaAgentRoleDefaultPolicy343EA6FE", + "Roles": [ + { + "Ref": "ApiSchemaAgentRole636AC572" + } + ] + }, + "DependsOn": [ + "DeploySchemaAwsCliLayerD0D0BA6E", + "DeploySchemaCustomResource277E9836" + ] + }, + "ApiSchemaAgent8E965D9C": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "AssetActionGroupFunction98EC70AB", + "Arn" + ] + } + }, + "ActionGroupName": "AssetApiSchemaActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "S3": { + "S3BucketName": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3ObjectKey": "a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml" + } + }, + "Description": "An action group using a local asset API schema", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "InlineActionGroupFunction566CD00A", + "Arn" + ] + } + }, + "ActionGroupName": "InlineApiSchemaActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "Payload": "\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n" + }, + "Description": "An action group using an inline API schema", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "S3ActionGroupFunctionA4648C25", + "Arn" + ] + } + }, + "ActionGroupName": "S3ApiSchemaActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "S3": { + "S3BucketName": { + "Ref": "SchemaBucket79EE2269" + }, + "S3ObjectKey": "schema/s3-api-schema.json" + } + }, + "Description": "An action group using an S3-based API schema", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "api-schema-agent", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "ApiSchemaAgentRole636AC572", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is an agent using an API schema with at least 40 characters of instruction", + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "ApiSchemaAgentRoleDefaultPolicy343EA6FE", + "DeploySchemaAwsCliLayerD0D0BA6E", + "DeploySchemaCustomResource277E9836" + ] + } + }, + "Mappings": { + "LatestNodeRuntimeMap": { + "af-south-1": { + "value": "nodejs22.x" + }, + "ap-east-1": { + "value": "nodejs22.x" + }, + "ap-east-2": { + "value": "nodejs22.x" + }, + "ap-northeast-1": { + "value": "nodejs22.x" + }, + "ap-northeast-2": { + "value": "nodejs22.x" + }, + "ap-northeast-3": { + "value": "nodejs22.x" + }, + "ap-south-1": { + "value": "nodejs22.x" + }, + "ap-south-2": { + "value": "nodejs22.x" + }, + "ap-southeast-1": { + "value": "nodejs22.x" + }, + "ap-southeast-2": { + "value": "nodejs22.x" + }, + "ap-southeast-3": { + "value": "nodejs22.x" + }, + "ap-southeast-4": { + "value": "nodejs22.x" + }, + "ap-southeast-5": { + "value": "nodejs22.x" + }, + "ap-southeast-7": { + "value": "nodejs22.x" + }, + "ca-central-1": { + "value": "nodejs22.x" + }, + "ca-west-1": { + "value": "nodejs22.x" + }, + "cn-north-1": { + "value": "nodejs22.x" + }, + "cn-northwest-1": { + "value": "nodejs22.x" + }, + "eu-central-1": { + "value": "nodejs22.x" + }, + "eu-central-2": { + "value": "nodejs22.x" + }, + "eu-isoe-west-1": { + "value": "nodejs18.x" + }, + "eu-north-1": { + "value": "nodejs22.x" + }, + "eu-south-1": { + "value": "nodejs22.x" + }, + "eu-south-2": { + "value": "nodejs22.x" + }, + "eu-west-1": { + "value": "nodejs22.x" + }, + "eu-west-2": { + "value": "nodejs22.x" + }, + "eu-west-3": { + "value": "nodejs22.x" + }, + "il-central-1": { + "value": "nodejs22.x" + }, + "me-central-1": { + "value": "nodejs22.x" + }, + "me-south-1": { + "value": "nodejs22.x" + }, + "mx-central-1": { + "value": "nodejs22.x" + }, + "sa-east-1": { + "value": "nodejs22.x" + }, + "us-east-1": { + "value": "nodejs22.x" + }, + "us-east-2": { + "value": "nodejs22.x" + }, + "us-gov-east-1": { + "value": "nodejs22.x" + }, + "us-gov-west-1": { + "value": "nodejs22.x" + }, + "us-iso-east-1": { + "value": "nodejs18.x" + }, + "us-iso-west-1": { + "value": "nodejs18.x" + }, + "us-isob-east-1": { + "value": "nodejs18.x" + }, + "us-isob-west-1": { + "value": "nodejs18.x" + }, + "us-west-1": { + "value": "nodejs22.x" + }, + "us-west-2": { + "value": "nodejs22.x" + } + } + }, + "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/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/cdk.out b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b3a26d44a5f73 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"44.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/integ.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/integ.json new file mode 100644 index 0000000000000..fac5585fa2c50 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "44.0.0", + "testCases": { + "BedrockApiSchema/DefaultTest": { + "stacks": [ + "aws-cdk-bedrock-api-schema-1" + ], + "assertionStack": "BedrockApiSchema/DefaultTest/DeployAssert", + "assertionStackName": "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57" + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/manifest.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/manifest.json new file mode 100644 index 0000000000000..cceb514c146b7 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/manifest.json @@ -0,0 +1,716 @@ +{ + "version": "44.0.0", + "artifacts": { + "aws-cdk-bedrock-api-schema-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-bedrock-api-schema-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-bedrock-api-schema-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-bedrock-api-schema-1.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}/7088b3cc688c2990cc3e59c4636a433a6fab1500854d9c74aa84e5ac1a2dc582.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-bedrock-api-schema-1.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-cdk-bedrock-api-schema-1.assets" + ], + "metadata": { + "/aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetActionGroupFunctionServiceRoleC53BA920" + } + ], + "/aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetActionGroupFunction98EC70AB" + } + ], + "/aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/LambdaInvocationPolicy-c8dfda1d62217f42": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetActionGroupFunctionLambdaInvocationPolicyc8dfda1d62217f4203A2E0A7" + } + ], + "/aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "InlineActionGroupFunctionServiceRole5543D9A3" + } + ], + "/aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "InlineActionGroupFunction566CD00A" + } + ], + "/aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/LambdaInvocationPolicy-c8dfda1d62217f42": [ + { + "type": "aws:cdk:logicalId", + "data": "InlineActionGroupFunctionLambdaInvocationPolicyc8dfda1d62217f42CE4591EF" + } + ], + "/aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "S3ActionGroupFunctionServiceRole7E4C5A58" + } + ], + "/aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "S3ActionGroupFunctionA4648C25" + } + ], + "/aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/LambdaInvocationPolicy-c8dfda1d62217f42": [ + { + "type": "aws:cdk:logicalId", + "data": "S3ActionGroupFunctionLambdaInvocationPolicyc8dfda1d62217f4210E2D0E3" + } + ], + "/aws-cdk-bedrock-api-schema-1/SchemaBucket": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "removalPolicy": "destroy", + "autoDeleteObjects": true + } + } + ], + "/aws-cdk-bedrock-api-schema-1/SchemaBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SchemaBucket79EE2269" + } + ], + "/aws-cdk-bedrock-api-schema-1/SchemaBucket/Policy": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "bucket": "*" + } + } + ], + "/aws-cdk-bedrock-api-schema-1/SchemaBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SchemaBucketPolicy557840E2" + } + ], + "/aws-cdk-bedrock-api-schema-1/SchemaBucket/AutoDeleteObjectsCustomResource": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-api-schema-1/SchemaBucket/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "SchemaBucketAutoDeleteObjectsCustomResource0F518746" + } + ], + "/aws-cdk-bedrock-api-schema-1/LatestNodeRuntimeMap": [ + { + "type": "aws:cdk:logicalId", + "data": "LatestNodeRuntimeMap" + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider": [ + { + "type": "aws:cdk:is-custom-resource-handler-customResourceProvider", + "data": true + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/aws-cdk-bedrock-api-schema-1/DeploySchema/AwsCliLayer": [ + { + "type": "aws:cdk:analytics:construct", + "data": {} + } + ], + "/aws-cdk-bedrock-api-schema-1/DeploySchema/AwsCliLayer/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DeploySchemaAwsCliLayerD0D0BA6E" + } + ], + "/aws-cdk-bedrock-api-schema-1/DeploySchema/CustomResourceHandler": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "uuid": "*", + "layers": [ + "*" + ], + "environment": "*", + "lambdaPurpose": "*", + "timeout": "*", + "role": "*", + "memorySize": "*", + "ephemeralStorageSize": "*", + "vpc": "*", + "vpcSubnets": "*", + "filesystem": "*", + "logGroup": "*", + "code": "*", + "handler": "*", + "runtime": "*" + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addMetadata": [ + "*", + true + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addMetadata": [ + "*", + "*" + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/DeploySchema/CustomResource": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-api-schema-1/DeploySchema/CustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "DeploySchemaCustomResource277E9836" + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "layers": [ + "*" + ], + "environment": "*", + "timeout": "*", + "role": "*", + "memorySize": "*", + "ephemeralStorageSize": "*", + "vpc": "*", + "vpcSubnets": "*", + "filesystem": "*", + "logGroup": "*", + "code": "*", + "handler": "*", + "runtime": "*" + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addEnvironment": [ + "*", + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addLayers": [ + "*" + ] + } + }, + { + "type": "aws:cdk:is-custom-resource-handler-singleton", + "data": true + }, + { + "type": "aws:cdk:is-custom-resource-handler-runtime-family", + "data": 2 + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF" + } + ], + "/aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536" + } + ], + "/aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ApiSchemaAgentRole636AC572" + } + ], + "/aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ApiSchemaAgentRoleDefaultPolicy343EA6FE" + } + ], + "/aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ApiSchemaAgent8E965D9C" + } + ], + "/aws-cdk-bedrock-api-schema-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-bedrock-api-schema-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-bedrock-api-schema-1" + }, + "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.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": [ + "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.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": [ + "BedrockApiSchemaDefaultTestDeployAssert1DDDDC57.assets" + ], + "metadata": { + "/BedrockApiSchema/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/BedrockApiSchema/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "BedrockApiSchema/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/tree.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/tree.json new file mode 100644 index 0000000000000..f721c41c640b9 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"aws-cdk-bedrock-api-schema-1":{"id":"aws-cdk-bedrock-api-schema-1","path":"aws-cdk-bedrock-api-schema-1","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"AssetActionGroupFunction":{"id":"AssetActionGroupFunction","path":"aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from asset action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["AssetActionGroupFunctionServiceRoleC53BA920","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c8dfda1d62217f42":{"id":"LambdaInvocationPolicy-c8dfda1d62217f42","path":"aws-cdk-bedrock-api-schema-1/AssetActionGroupFunction/LambdaInvocationPolicy-c8dfda1d62217f42","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["AssetActionGroupFunction98EC70AB","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"InlineActionGroupFunction":{"id":"InlineActionGroupFunction","path":"aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from inline action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["InlineActionGroupFunctionServiceRole5543D9A3","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c8dfda1d62217f42":{"id":"LambdaInvocationPolicy-c8dfda1d62217f42","path":"aws-cdk-bedrock-api-schema-1/InlineActionGroupFunction/LambdaInvocationPolicy-c8dfda1d62217f42","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["InlineActionGroupFunction566CD00A","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"S3ActionGroupFunction":{"id":"S3ActionGroupFunction","path":"aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from S3 action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["S3ActionGroupFunctionServiceRole7E4C5A58","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c8dfda1d62217f42":{"id":"LambdaInvocationPolicy-c8dfda1d62217f42","path":"aws-cdk-bedrock-api-schema-1/S3ActionGroupFunction/LambdaInvocationPolicy-c8dfda1d62217f42","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["S3ActionGroupFunctionA4648C25","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"SchemaBucket":{"id":"SchemaBucket","path":"aws-cdk-bedrock-api-schema-1/SchemaBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.Bucket","version":"0.0.0","metadata":[{"removalPolicy":"destroy","autoDeleteObjects":true}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/SchemaBucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucket","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::Bucket","aws:cdk:cloudformation:props":{"tags":[{"key":"aws-cdk:auto-delete-objects","value":"true"},{"key":"aws-cdk:cr-owned:911f5017","value":"true"}]}}},"Policy":{"id":"Policy","path":"aws-cdk-bedrock-api-schema-1/SchemaBucket/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketPolicy","version":"0.0.0","metadata":[{"bucket":"*"}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/SchemaBucket/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucketPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::BucketPolicy","aws:cdk:cloudformation:props":{"bucket":{"Ref":"SchemaBucket79EE2269"},"policyDocument":{"Statement":[{"Action":["s3:DeleteObject*","s3:GetBucket*","s3:List*","s3:PutBucketPolicy"],"Effect":"Allow","Principal":{"AWS":{"Fn::GetAtt":["CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092","Arn"]}},"Resource":[{"Fn::GetAtt":["SchemaBucket79EE2269","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["SchemaBucket79EE2269","Arn"]},"/*"]]}]}],"Version":"2012-10-17"}}}}}},"AutoDeleteObjectsCustomResource":{"id":"AutoDeleteObjectsCustomResource","path":"aws-cdk-bedrock-api-schema-1/SchemaBucket/AutoDeleteObjectsCustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"aws-cdk-bedrock-api-schema-1/SchemaBucket/AutoDeleteObjectsCustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}}}},"LatestNodeRuntimeMap":{"id":"LatestNodeRuntimeMap","path":"aws-cdk-bedrock-api-schema-1/LatestNodeRuntimeMap","constructInfo":{"fqn":"aws-cdk-lib.CfnMapping","version":"0.0.0"}},"Custom::S3AutoDeleteObjectsCustomResourceProvider":{"id":"Custom::S3AutoDeleteObjectsCustomResourceProvider","path":"aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider","constructInfo":{"fqn":"aws-cdk-lib.CustomResourceProviderBase","version":"0.0.0"},"children":{"Staging":{"id":"Staging","path":"aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"Role":{"id":"Role","path":"aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}},"Handler":{"id":"Handler","path":"aws-cdk-bedrock-api-schema-1/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}},"DeploySchema":{"id":"DeploySchema","path":"aws-cdk-bedrock-api-schema-1/DeploySchema","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_deployment.BucketDeployment","version":"0.0.0"},"children":{"AwsCliLayer":{"id":"AwsCliLayer","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/AwsCliLayer","constructInfo":{"fqn":"aws-cdk-lib.lambda_layer_awscli.AwsCliLayer","version":"0.0.0","metadata":[{}]},"children":{"Code":{"id":"Code","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/AwsCliLayer/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"0.0.0"},"children":{"Stage":{"id":"Stage","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/AwsCliLayer/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"AssetBucket":{"id":"AssetBucket","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/AwsCliLayer/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/AwsCliLayer/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnLayerVersion","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::LayerVersion","aws:cdk:cloudformation:props":{"content":{"s3Bucket":{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"s3Key":"b8ab94266984268614c3fb2824a1c3a55395746c48b28c003b08bc1d08688f3e.zip"},"description":"/opt/awscli/aws"}}}}},"CustomResourceHandler":{"id":"CustomResourceHandler","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/CustomResourceHandler","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.SingletonFunction","version":"0.0.0","metadata":[{"uuid":"*","layers":["*"],"environment":"*","lambdaPurpose":"*","timeout":"*","role":"*","memorySize":"*","ephemeralStorageSize":"*","vpc":"*","vpcSubnets":"*","filesystem":"*","logGroup":"*","code":"*","handler":"*","runtime":"*"},{"addMetadata":["*",true]},{"addMetadata":["*","*"]}]}},"Asset1":{"id":"Asset1","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/Asset1","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"0.0.0"},"children":{"Stage":{"id":"Stage","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/Asset1/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"AssetBucket":{"id":"AssetBucket","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/Asset1/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}}}},"CustomResource":{"id":"CustomResource","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/CustomResource","constructInfo":{"fqn":"aws-cdk-lib.CustomResource","version":"0.0.0","metadata":["*"]},"children":{"Default":{"id":"Default","path":"aws-cdk-bedrock-api-schema-1/DeploySchema/CustomResource/Default","constructInfo":{"fqn":"aws-cdk-lib.CfnResource","version":"0.0.0"}}}}}},"Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C":{"id":"Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"layers":["*"],"environment":"*","timeout":"*","role":"*","memorySize":"*","ephemeralStorageSize":"*","vpc":"*","vpcSubnets":"*","filesystem":"*","logGroup":"*","code":"*","handler":"*","runtime":"*"},{"addEnvironment":["*","*"]},{"addLayers":["*"]}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["s3:GetBucket*","s3:GetObject*","s3:List*"],"Effect":"Allow","Resource":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::",{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"/*"]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::",{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"}]]}]},{"Action":["s3:Abort*","s3:DeleteObject*","s3:GetBucket*","s3:GetObject*","s3:List*","s3:PutObject","s3:PutObjectLegalHold","s3:PutObjectRetention","s3:PutObjectTagging","s3:PutObjectVersionTagging"],"Effect":"Allow","Resource":[{"Fn::GetAtt":["SchemaBucket79EE2269","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["SchemaBucket79EE2269","Arn"]},"/*"]]}]}],"Version":"2012-10-17"},"policyName":"CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF","roles":[{"Ref":"CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265"}]}}}}}}},"Code":{"id":"Code","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"0.0.0"},"children":{"Stage":{"id":"Stage","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"AssetBucket":{"id":"AssetBucket","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"s3Bucket":{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"s3Key":"9a1fcb4a7ecba81ad70e9d3fb241f6794497da945dae5f25924e4dd002b65f2d.zip"},"environment":{"variables":{"AWS_CA_BUNDLE":"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"}},"handler":"index.handler","layers":[{"Ref":"DeploySchemaAwsCliLayerD0D0BA6E"}],"role":{"Fn::GetAtt":["CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265","Arn"]},"runtime":"python3.11","timeout":900}}}}},"Schema":{"id":"Schema","path":"aws-cdk-bedrock-api-schema-1/Schema","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"0.0.0"},"children":{"Stage":{"id":"Stage","path":"aws-cdk-bedrock-api-schema-1/Schema/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"AssetBucket":{"id":"AssetBucket","path":"aws-cdk-bedrock-api-schema-1/Schema/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}}}},"ApiSchemaAgent":{"id":"ApiSchemaAgent","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]},"children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockapisca1-apischemaagent-b0e9b051-bedrockagent"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"lambda:InvokeFunction","Effect":"Allow","Resource":[{"Fn::GetAtt":["AssetActionGroupFunction98EC70AB","Arn"]},{"Fn::GetAtt":["InlineActionGroupFunction566CD00A","Arn"]},{"Fn::GetAtt":["S3ActionGroupFunctionA4648C25","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["AssetActionGroupFunction98EC70AB","Arn"]},":*"]]},{"Fn::Join":["",[{"Fn::GetAtt":["InlineActionGroupFunction566CD00A","Arn"]},":*"]]},{"Fn::Join":["",[{"Fn::GetAtt":["S3ActionGroupFunctionA4648C25","Arn"]},":*"]]}]},{"Action":["s3:GetBucket*","s3:GetObject*","s3:List*"],"Effect":"Allow","Resource":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::",{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"/a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml"]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::",{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"}]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::",{"Ref":"SchemaBucket79EE2269"},"/schema/s3-api-schema.json"]]},{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":s3:::",{"Ref":"SchemaBucket79EE2269"}]]}]},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"ApiSchemaAgentRoleDefaultPolicy343EA6FE","roles":[{"Ref":"ApiSchemaAgentRole636AC572"}]}}}}}}},"AssetApiSchemaActionGroupSchemaBucket":{"id":"AssetApiSchemaActionGroupSchemaBucket","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/AssetApiSchemaActionGroupSchemaBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}},"S3ApiSchemaActionGroupSchemaBucket":{"id":"S3ApiSchemaActionGroupSchemaBucket","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/S3ApiSchemaActionGroupSchemaBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["AssetActionGroupFunction98EC70AB","Arn"]}},"actionGroupName":"AssetApiSchemaActionGroup","actionGroupState":"ENABLED","apiSchema":{"s3":{"s3BucketName":{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"s3ObjectKey":"a7172fea4e8cb73c2182ab93fc10509de03c96781054237fcbc52220fed232a0.yaml"}},"description":"An action group using a local asset API schema","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["InlineActionGroupFunction566CD00A","Arn"]}},"actionGroupName":"InlineApiSchemaActionGroup","actionGroupState":"ENABLED","apiSchema":{"payload":"\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n"},"description":"An action group using an inline API schema","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["S3ActionGroupFunctionA4648C25","Arn"]}},"actionGroupName":"S3ApiSchemaActionGroup","actionGroupState":"ENABLED","apiSchema":{"s3":{"s3BucketName":{"Ref":"SchemaBucket79EE2269"},"s3ObjectKey":"schema/s3-api-schema.json"}},"description":"An action group using an S3-based API schema","skipResourceInUseCheckOnDelete":false}],"agentName":"api-schema-agent","agentResourceRoleArn":{"Fn::GetAtt":["ApiSchemaAgentRole636AC572","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is an agent using an API schema with at least 40 characters of instruction","orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-api-schema-1/ApiSchemaAgent/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-bedrock-api-schema-1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-bedrock-api-schema-1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"BedrockApiSchema":{"id":"BedrockApiSchema","path":"BedrockApiSchema","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"BedrockApiSchema/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"BedrockApiSchema/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"BedrockApiSchema/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"BedrockApiSchema/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"BedrockApiSchema/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.ts new file mode 100644 index 0000000000000..1f71ec44eb0af --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.api-schema.ts @@ -0,0 +1,203 @@ +/* + * Integration test for Bedrock Agent API Schema construct + */ + +/// !cdk-integ aws-cdk-bedrock-api-schema-1 + +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment'; +import * as bedrock from '../../../bedrock'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-api-schema-1'); + +// Create Lambda functions for the action group executors +// Create Lambda functions for the action group executors +const assetActionGroupFunction = new lambda.Function(stack, 'AssetActionGroupFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from asset action group' } + } + } + }; + }; + `), +}); + +const inlineActionGroupFunction = new lambda.Function(stack, 'InlineActionGroupFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from inline action group' } + } + } + }; + }; + `), +}); + +const s3ActionGroupFunction = new lambda.Function(stack, 'S3ActionGroupFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from S3 action group' } + } + } + }; + }; + `), +}); + +// Create action group executors +const assetActionGroupExecutor = bedrock.ActionGroupExecutor.fromLambda(assetActionGroupFunction); +const inlineActionGroupExecutor = bedrock.ActionGroupExecutor.fromLambda(inlineActionGroupFunction); +const s3ActionGroupExecutor = bedrock.ActionGroupExecutor.fromLambda(s3ActionGroupFunction); + +// Create an API schema from a local asset file +const assetApiSchema = bedrock.ApiSchema.fromLocalAsset('test-schema.yaml'); + +// Create a simple inline API schema +const inlineApiSchema = bedrock.ApiSchema.fromInline(` +openapi: 3.0.3 +info: + title: Simple API + version: 1.0.0 +paths: + /hello: + get: + operationId: helloWorld + summary: Say hello + description: Returns a greeting message + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + message: + type: string +`); + +// Create an S3 bucket for storing the API schema +const schemaBucket = new s3.Bucket(stack, 'SchemaBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, +}); + +// Deploy the schema file to S3 +const schemaDeployment = new s3deploy.BucketDeployment(stack, 'DeploySchema', { + sources: [s3deploy.Source.data('schema/s3-api-schema.json', `{ + "openapi": "3.0.3", + "info": { + "title": "S3 API Schema", + "version": "1.0.0" + }, + "paths": { + "/s3hello": { + "get": { + "operationId": "s3HelloWorld", + "summary": "Say hello from S3", + "description": "Returns a greeting message from S3-stored schema", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }`)], + destinationBucket: schemaBucket, +}); + +// Create an API schema from the S3 file +const s3ApiSchema = bedrock.ApiSchema.fromS3File(schemaBucket, 'schema/s3-api-schema.json'); + +// Bind the asset schema before using it in action groups +assetApiSchema.bind(stack); + +// Create a Bedrock Agent with action groups using all three API schema types +const agent = new bedrock.Agent(stack, 'ApiSchemaAgent', { + agentName: 'api-schema-agent', + instruction: 'This is an agent using an API schema with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + actionGroups: [ + new bedrock.AgentActionGroup({ + name: 'AssetApiSchemaActionGroup', + description: 'An action group using a local asset API schema', + apiSchema: assetApiSchema, + executor: assetActionGroupExecutor, + }), + new bedrock.AgentActionGroup({ + name: 'InlineApiSchemaActionGroup', + description: 'An action group using an inline API schema', + apiSchema: inlineApiSchema, + executor: inlineActionGroupExecutor, + }), + new bedrock.AgentActionGroup({ + name: 'S3ApiSchemaActionGroup', + description: 'An action group using an S3-based API schema', + apiSchema: s3ApiSchema, + executor: s3ActionGroupExecutor, + }), + ], +}); + +// Add dependency for the agent on the S3 deployment +agent.node.addDependency(schemaDeployment); + +new integ.IntegTest(app, 'BedrockApiSchema', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/BedrockMemoryDefaultTestDeployAssert5AD90360.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/BedrockMemoryDefaultTestDeployAssert5AD90360.assets.json new file mode 100644 index 0000000000000..01b953bb1fa4c --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/BedrockMemoryDefaultTestDeployAssert5AD90360.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "BedrockMemoryDefaultTestDeployAssert5AD90360 Template", + "source": { + "path": "BedrockMemoryDefaultTestDeployAssert5AD90360.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/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/BedrockMemoryDefaultTestDeployAssert5AD90360.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/BedrockMemoryDefaultTestDeployAssert5AD90360.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/BedrockMemoryDefaultTestDeployAssert5AD90360.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/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/aws-cdk-bedrock-memory-1.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/aws-cdk-bedrock-memory-1.assets.json new file mode 100644 index 0000000000000..d16735b491c34 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/aws-cdk-bedrock-memory-1.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "4b5e46dd6d910a7f3b3a80b002f4430d97635faacd166974de5d6a066d216524": { + "displayName": "aws-cdk-bedrock-memory-1 Template", + "source": { + "path": "aws-cdk-bedrock-memory-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "4b5e46dd6d910a7f3b3a80b002f4430d97635faacd166974de5d6a066d216524.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/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/aws-cdk-bedrock-memory-1.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/aws-cdk-bedrock-memory-1.template.json new file mode 100644 index 0000000000000..e0d85494ad511 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/aws-cdk-bedrock-memory-1.template.json @@ -0,0 +1,546 @@ +{ + "Resources": { + "DefaultMemoryFunctionServiceRoleD8C5CDAF": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "DefaultMemoryFunctionAC6D5374": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from default memory action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "DefaultMemoryFunctionServiceRoleD8C5CDAF", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "DefaultMemoryFunctionServiceRoleD8C5CDAF" + ] + }, + "DefaultMemoryFunctionLambdaInvocationPolicyc809bacfbaa9d9a5AC2FFF6B": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "DefaultMemoryFunctionAC6D5374", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "CustomMemoryFunctionServiceRoleA64B0AD5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "CustomMemoryFunctionB4B5CB9A": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from custom memory action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomMemoryFunctionServiceRoleA64B0AD5", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "CustomMemoryFunctionServiceRoleA64B0AD5" + ] + }, + "CustomMemoryFunctionLambdaInvocationPolicyc8492664c8e1cb16AC1ED6E1": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "CustomMemoryFunctionB4B5CB9A", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "AgentWithDefaultMemoryRole0AEE1FD1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockmemorwithdefaultmemory-230a5dbf-bedrockagent" + } + }, + "AgentWithDefaultMemoryRoleDefaultPolicyCF8B3F25": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "DefaultMemoryFunctionAC6D5374", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "DefaultMemoryFunctionAC6D5374", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "AgentWithDefaultMemoryRoleDefaultPolicyCF8B3F25", + "Roles": [ + { + "Ref": "AgentWithDefaultMemoryRole0AEE1FD1" + } + ] + } + }, + "AgentWithDefaultMemoryA1F31830": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "DefaultMemoryFunctionAC6D5374", + "Arn" + ] + } + }, + "ActionGroupName": "DefaultMemoryActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "Payload": "\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n" + }, + "Description": "An action group for testing default memory configuration", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "agent-with-default-memory", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "AgentWithDefaultMemoryRole0AEE1FD1", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is an agent using default memory configuration with at least 40 characters of instruction", + "MemoryConfiguration": { + "EnabledMemoryTypes": [ + "SESSION_SUMMARY" + ], + "SessionSummaryConfiguration": { + "MaxRecentSessions": 20 + }, + "StorageDays": 30 + }, + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "AgentWithDefaultMemoryRoleDefaultPolicyCF8B3F25" + ] + }, + "AgentWithCustomMemoryRole3B7BD09F": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockmemortwithcustommemory-12bba032-bedrockagent" + } + }, + "AgentWithCustomMemoryRoleDefaultPolicyB8F9AA78": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "CustomMemoryFunctionB4B5CB9A", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "CustomMemoryFunctionB4B5CB9A", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "AgentWithCustomMemoryRoleDefaultPolicyB8F9AA78", + "Roles": [ + { + "Ref": "AgentWithCustomMemoryRole3B7BD09F" + } + ] + } + }, + "AgentWithCustomMemoryD0BD498B": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "CustomMemoryFunctionB4B5CB9A", + "Arn" + ] + } + }, + "ActionGroupName": "CustomMemoryActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "Payload": "\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n" + }, + "Description": "An action group for testing custom memory configuration", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "agent-with-custom-memory", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "AgentWithCustomMemoryRole3B7BD09F", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is an agent using custom memory configuration with at least 40 characters of instruction", + "MemoryConfiguration": { + "EnabledMemoryTypes": [ + "SESSION_SUMMARY" + ], + "SessionSummaryConfiguration": { + "MaxRecentSessions": 5 + }, + "StorageDays": 15 + }, + "OrchestrationType": "DEFAULT", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "AgentWithCustomMemoryRoleDefaultPolicyB8F9AA78" + ] + } + }, + "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/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/cdk.out b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b3a26d44a5f73 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"44.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/integ.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/integ.json new file mode 100644 index 0000000000000..55e92d6943e0e --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "44.0.0", + "testCases": { + "BedrockMemory/DefaultTest": { + "stacks": [ + "aws-cdk-bedrock-memory-1" + ], + "assertionStack": "BedrockMemory/DefaultTest/DeployAssert", + "assertionStackName": "BedrockMemoryDefaultTestDeployAssert5AD90360" + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/manifest.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/manifest.json new file mode 100644 index 0000000000000..fe0f12beca6b4 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/manifest.json @@ -0,0 +1,420 @@ +{ + "version": "44.0.0", + "artifacts": { + "aws-cdk-bedrock-memory-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-bedrock-memory-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-bedrock-memory-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-bedrock-memory-1.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}/4b5e46dd6d910a7f3b3a80b002f4430d97635faacd166974de5d6a066d216524.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-bedrock-memory-1.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-cdk-bedrock-memory-1.assets" + ], + "metadata": { + "/aws-cdk-bedrock-memory-1/DefaultMemoryFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-memory-1/DefaultMemoryFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-memory-1/DefaultMemoryFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-memory-1/DefaultMemoryFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DefaultMemoryFunctionServiceRoleD8C5CDAF" + } + ], + "/aws-cdk-bedrock-memory-1/DefaultMemoryFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DefaultMemoryFunctionAC6D5374" + } + ], + "/aws-cdk-bedrock-memory-1/DefaultMemoryFunction/LambdaInvocationPolicy-c809bacfbaa9d9a5": [ + { + "type": "aws:cdk:logicalId", + "data": "DefaultMemoryFunctionLambdaInvocationPolicyc809bacfbaa9d9a5AC2FFF6B" + } + ], + "/aws-cdk-bedrock-memory-1/CustomMemoryFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-memory-1/CustomMemoryFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-memory-1/CustomMemoryFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-memory-1/CustomMemoryFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomMemoryFunctionServiceRoleA64B0AD5" + } + ], + "/aws-cdk-bedrock-memory-1/CustomMemoryFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomMemoryFunctionB4B5CB9A" + } + ], + "/aws-cdk-bedrock-memory-1/CustomMemoryFunction/LambdaInvocationPolicy-c8492664c8e1cb16": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomMemoryFunctionLambdaInvocationPolicyc8492664c8e1cb16AC1ED6E1" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithDefaultMemoryRole0AEE1FD1" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithDefaultMemoryRoleDefaultPolicyCF8B3F25" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithDefaultMemoryA1F31830" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithCustomMemoryRole3B7BD09F" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithCustomMemoryRoleDefaultPolicyB8F9AA78" + } + ], + "/aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithCustomMemoryD0BD498B" + } + ], + "/aws-cdk-bedrock-memory-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-bedrock-memory-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-bedrock-memory-1" + }, + "BedrockMemoryDefaultTestDeployAssert5AD90360.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "BedrockMemoryDefaultTestDeployAssert5AD90360.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "BedrockMemoryDefaultTestDeployAssert5AD90360": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BedrockMemoryDefaultTestDeployAssert5AD90360.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": [ + "BedrockMemoryDefaultTestDeployAssert5AD90360.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": [ + "BedrockMemoryDefaultTestDeployAssert5AD90360.assets" + ], + "metadata": { + "/BedrockMemory/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/BedrockMemory/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "BedrockMemory/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/tree.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/tree.json new file mode 100644 index 0000000000000..03b862c136195 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"aws-cdk-bedrock-memory-1":{"id":"aws-cdk-bedrock-memory-1","path":"aws-cdk-bedrock-memory-1","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"DefaultMemoryFunction":{"id":"DefaultMemoryFunction","path":"aws-cdk-bedrock-memory-1/DefaultMemoryFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-memory-1/DefaultMemoryFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-memory-1/DefaultMemoryFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/DefaultMemoryFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/DefaultMemoryFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from default memory action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["DefaultMemoryFunctionServiceRoleD8C5CDAF","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c809bacfbaa9d9a5":{"id":"LambdaInvocationPolicy-c809bacfbaa9d9a5","path":"aws-cdk-bedrock-memory-1/DefaultMemoryFunction/LambdaInvocationPolicy-c809bacfbaa9d9a5","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["DefaultMemoryFunctionAC6D5374","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"CustomMemoryFunction":{"id":"CustomMemoryFunction","path":"aws-cdk-bedrock-memory-1/CustomMemoryFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-memory-1/CustomMemoryFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-memory-1/CustomMemoryFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/CustomMemoryFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/CustomMemoryFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from custom memory action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["CustomMemoryFunctionServiceRoleA64B0AD5","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c8492664c8e1cb16":{"id":"LambdaInvocationPolicy-c8492664c8e1cb16","path":"aws-cdk-bedrock-memory-1/CustomMemoryFunction/LambdaInvocationPolicy-c8492664c8e1cb16","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["CustomMemoryFunctionB4B5CB9A","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"AgentWithDefaultMemory":{"id":"AgentWithDefaultMemory","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]},"children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockmemorwithdefaultmemory-230a5dbf-bedrockagent"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"lambda:InvokeFunction","Effect":"Allow","Resource":[{"Fn::GetAtt":["DefaultMemoryFunctionAC6D5374","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["DefaultMemoryFunctionAC6D5374","Arn"]},":*"]]}]},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"AgentWithDefaultMemoryRoleDefaultPolicyCF8B3F25","roles":[{"Ref":"AgentWithDefaultMemoryRole0AEE1FD1"}]}}}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["DefaultMemoryFunctionAC6D5374","Arn"]}},"actionGroupName":"DefaultMemoryActionGroup","actionGroupState":"ENABLED","apiSchema":{"payload":"\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n"},"description":"An action group for testing default memory configuration","skipResourceInUseCheckOnDelete":false}],"agentName":"agent-with-default-memory","agentResourceRoleArn":{"Fn::GetAtt":["AgentWithDefaultMemoryRole0AEE1FD1","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is an agent using default memory configuration with at least 40 characters of instruction","memoryConfiguration":{"enabledMemoryTypes":["SESSION_SUMMARY"],"storageDays":30,"sessionSummaryConfiguration":{"maxRecentSessions":20}},"orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-memory-1/AgentWithDefaultMemory/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}}},"AgentWithCustomMemory":{"id":"AgentWithCustomMemory","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]},"children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockmemortwithcustommemory-12bba032-bedrockagent"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"lambda:InvokeFunction","Effect":"Allow","Resource":[{"Fn::GetAtt":["CustomMemoryFunctionB4B5CB9A","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["CustomMemoryFunctionB4B5CB9A","Arn"]},":*"]]}]},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"AgentWithCustomMemoryRoleDefaultPolicyB8F9AA78","roles":[{"Ref":"AgentWithCustomMemoryRole3B7BD09F"}]}}}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["CustomMemoryFunctionB4B5CB9A","Arn"]}},"actionGroupName":"CustomMemoryActionGroup","actionGroupState":"ENABLED","apiSchema":{"payload":"\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n"},"description":"An action group for testing custom memory configuration","skipResourceInUseCheckOnDelete":false}],"agentName":"agent-with-custom-memory","agentResourceRoleArn":{"Fn::GetAtt":["AgentWithCustomMemoryRole3B7BD09F","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is an agent using custom memory configuration with at least 40 characters of instruction","memoryConfiguration":{"enabledMemoryTypes":["SESSION_SUMMARY"],"storageDays":15,"sessionSummaryConfiguration":{"maxRecentSessions":5}},"orchestrationType":"DEFAULT","skipResourceInUseCheckOnDelete":true}}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-memory-1/AgentWithCustomMemory/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-bedrock-memory-1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-bedrock-memory-1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"BedrockMemory":{"id":"BedrockMemory","path":"BedrockMemory","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"BedrockMemory/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"BedrockMemory/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"BedrockMemory/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"BedrockMemory/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"BedrockMemory/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.ts new file mode 100644 index 0000000000000..8740062756aa6 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.memory.ts @@ -0,0 +1,131 @@ +/* + * Integration test for Bedrock Agent Memory configuration + */ + +/// !cdk-integ aws-cdk-bedrock-memory-1 + +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as bedrock from '../../../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-memory-1'); + +// Create Lambda functions for the action group executors +const defaultMemoryFunction = new lambda.Function(stack, 'DefaultMemoryFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from default memory action group' } + } + } + }; + }; + `), +}); + +const customMemoryFunction = new lambda.Function(stack, 'CustomMemoryFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from custom memory action group' } + } + } + }; + }; + `), +}); + +// Create action group executors +const defaultMemoryExecutor = bedrock.ActionGroupExecutor.fromLambda(defaultMemoryFunction); +const customMemoryExecutor = bedrock.ActionGroupExecutor.fromLambda(customMemoryFunction); + +// Create a simple API schema +const apiSchema = bedrock.ApiSchema.fromInline(` +openapi: 3.0.3 +info: + title: Simple API + version: 1.0.0 +paths: + /hello: + get: + operationId: helloWorld + summary: Say hello + description: Returns a greeting message + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + message: + type: string +`); + +// Create action groups +const defaultMemoryActionGroup = new bedrock.AgentActionGroup({ + name: 'DefaultMemoryActionGroup', + description: 'An action group for testing default memory configuration', + apiSchema: apiSchema, + executor: defaultMemoryExecutor, +}); + +const customMemoryActionGroup = new bedrock.AgentActionGroup({ + name: 'CustomMemoryActionGroup', + description: 'An action group for testing custom memory configuration', + apiSchema: apiSchema, + executor: customMemoryExecutor, +}); + +// Test 1: Create an agent with default memory configuration +new bedrock.Agent(stack, 'AgentWithDefaultMemory', { + agentName: 'agent-with-default-memory', + instruction: 'This is an agent using default memory configuration with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + actionGroups: [defaultMemoryActionGroup], + memory: bedrock.Memory.SESSION_SUMMARY, +}); + +// Test 2: Create an agent with custom memory configuration +new bedrock.Agent(stack, 'AgentWithCustomMemory', { + agentName: 'agent-with-custom-memory', + instruction: 'This is an agent using custom memory configuration with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + actionGroups: [customMemoryActionGroup], + memory: bedrock.Memory.sessionSummary({ + memoryDuration: cdk.Duration.days(15), + maxRecentSessions: 5, + }), +}); + +new integ.IntegTest(app, 'BedrockMemory', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/BedrockOrchestrationDefaultTestDeployAssertACFAFF30.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/BedrockOrchestrationDefaultTestDeployAssertACFAFF30.assets.json new file mode 100644 index 0000000000000..2c0c2e239e7d8 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/BedrockOrchestrationDefaultTestDeployAssertACFAFF30.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "BedrockOrchestrationDefaultTestDeployAssertACFAFF30 Template", + "source": { + "path": "BedrockOrchestrationDefaultTestDeployAssertACFAFF30.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/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/BedrockOrchestrationDefaultTestDeployAssertACFAFF30.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/BedrockOrchestrationDefaultTestDeployAssertACFAFF30.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/BedrockOrchestrationDefaultTestDeployAssertACFAFF30.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/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/aws-cdk-bedrock-orchestration-1.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/aws-cdk-bedrock-orchestration-1.assets.json new file mode 100644 index 0000000000000..33a7aa00090f2 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/aws-cdk-bedrock-orchestration-1.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "8e22484e104d03bb8c381c662bca5f9251022e01bbb67e62d371b418eac0e88d": { + "displayName": "aws-cdk-bedrock-orchestration-1 Template", + "source": { + "path": "aws-cdk-bedrock-orchestration-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "8e22484e104d03bb8c381c662bca5f9251022e01bbb67e62d371b418eac0e88d.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/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/aws-cdk-bedrock-orchestration-1.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/aws-cdk-bedrock-orchestration-1.template.json new file mode 100644 index 0000000000000..c737305fb8782 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/aws-cdk-bedrock-orchestration-1.template.json @@ -0,0 +1,282 @@ +{ + "Resources": { + "OrchestrationFunctionServiceRole12D0673A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "OrchestrationFunction2F3851C6": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Orchestration Event:', JSON.stringify(event));\n \n // Example orchestration logic\n const response = {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup || 'default',\n apiPath: event.apiPath || '/default',\n httpMethod: event.httpMethod || 'GET',\n httpStatusCode: 200,\n responseBody: {\n application_json: { \n result: 'Custom orchestration response',\n timestamp: new Date().toISOString()\n }\n }\n }\n };\n \n return response;\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "OrchestrationFunctionServiceRole12D0673A", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "OrchestrationFunctionServiceRole12D0673A" + ] + }, + "OrchestrationFunctionOrchestrationLambdaInvocationPolicyc8f49862985034a7EC14F6D5": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "OrchestrationFunction2F3851C6", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + }, + "SourceArn": { + "Fn::GetAtt": [ + "CustomOrchestrationAgentDC6CC131", + "AgentArn" + ] + } + } + }, + "CustomOrchestrationAgentRole85710213": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockorcherchestrationagent-e769c494-bedrockagent" + } + }, + "CustomOrchestrationAgentRoleDefaultPolicy33EDF7E6": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "OrchestrationFunction2F3851C6", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "OrchestrationFunction2F3851C6", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CustomOrchestrationAgentRoleDefaultPolicy33EDF7E6", + "Roles": [ + { + "Ref": "CustomOrchestrationAgentRole85710213" + } + ] + } + }, + "CustomOrchestrationAgentDC6CC131": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "custom-orchestration-agent", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "CustomOrchestrationAgentRole85710213", + "Arn" + ] + }, + "AutoPrepare": false, + "CustomOrchestration": { + "Executor": { + "Lambda": { + "Fn::GetAtt": [ + "OrchestrationFunction2F3851C6", + "Arn" + ] + } + } + }, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is an agent using custom orchestration with at least 40 characters of instruction", + "OrchestrationType": "CUSTOM_ORCHESTRATION", + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "CustomOrchestrationAgentRoleDefaultPolicy33EDF7E6" + ] + } + }, + "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/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/cdk.out b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b3a26d44a5f73 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"44.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/integ.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/integ.json new file mode 100644 index 0000000000000..f0500d69a0e0f --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "44.0.0", + "testCases": { + "BedrockOrchestration/DefaultTest": { + "stacks": [ + "aws-cdk-bedrock-orchestration-1" + ], + "assertionStack": "BedrockOrchestration/DefaultTest/DeployAssert", + "assertionStackName": "BedrockOrchestrationDefaultTestDeployAssertACFAFF30" + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/manifest.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/manifest.json new file mode 100644 index 0000000000000..f1a16c34b09e0 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/manifest.json @@ -0,0 +1,264 @@ +{ + "version": "44.0.0", + "artifacts": { + "aws-cdk-bedrock-orchestration-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-bedrock-orchestration-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-bedrock-orchestration-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-bedrock-orchestration-1.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}/8e22484e104d03bb8c381c662bca5f9251022e01bbb67e62d371b418eac0e88d.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-bedrock-orchestration-1.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-cdk-bedrock-orchestration-1.assets" + ], + "metadata": { + "/aws-cdk-bedrock-orchestration-1/OrchestrationFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-orchestration-1/OrchestrationFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-orchestration-1/OrchestrationFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-orchestration-1/OrchestrationFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OrchestrationFunctionServiceRole12D0673A" + } + ], + "/aws-cdk-bedrock-orchestration-1/OrchestrationFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OrchestrationFunction2F3851C6" + } + ], + "/aws-cdk-bedrock-orchestration-1/OrchestrationFunction/OrchestrationLambdaInvocationPolicy-c8f49862985034a7": [ + { + "type": "aws:cdk:logicalId", + "data": "OrchestrationFunctionOrchestrationLambdaInvocationPolicyc8f49862985034a7EC14F6D5" + } + ], + "/aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomOrchestrationAgentRole85710213" + } + ], + "/aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomOrchestrationAgentRoleDefaultPolicy33EDF7E6" + } + ], + "/aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomOrchestrationAgentDC6CC131" + } + ], + "/aws-cdk-bedrock-orchestration-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-bedrock-orchestration-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-bedrock-orchestration-1" + }, + "BedrockOrchestrationDefaultTestDeployAssertACFAFF30.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "BedrockOrchestrationDefaultTestDeployAssertACFAFF30.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "BedrockOrchestrationDefaultTestDeployAssertACFAFF30": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BedrockOrchestrationDefaultTestDeployAssertACFAFF30.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": [ + "BedrockOrchestrationDefaultTestDeployAssertACFAFF30.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": [ + "BedrockOrchestrationDefaultTestDeployAssertACFAFF30.assets" + ], + "metadata": { + "/BedrockOrchestration/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/BedrockOrchestration/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "BedrockOrchestration/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/tree.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/tree.json new file mode 100644 index 0000000000000..4831859ec2a6e --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"aws-cdk-bedrock-orchestration-1":{"id":"aws-cdk-bedrock-orchestration-1","path":"aws-cdk-bedrock-orchestration-1","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"OrchestrationFunction":{"id":"OrchestrationFunction","path":"aws-cdk-bedrock-orchestration-1/OrchestrationFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-orchestration-1/OrchestrationFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-orchestration-1/OrchestrationFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-orchestration-1/OrchestrationFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-orchestration-1/OrchestrationFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Orchestration Event:', JSON.stringify(event));\n \n // Example orchestration logic\n const response = {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup || 'default',\n apiPath: event.apiPath || '/default',\n httpMethod: event.httpMethod || 'GET',\n httpStatusCode: 200,\n responseBody: {\n application_json: { \n result: 'Custom orchestration response',\n timestamp: new Date().toISOString()\n }\n }\n }\n };\n \n return response;\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["OrchestrationFunctionServiceRole12D0673A","Arn"]},"runtime":"nodejs18.x"}}},"OrchestrationLambdaInvocationPolicy-c8f49862985034a7":{"id":"OrchestrationLambdaInvocationPolicy-c8f49862985034a7","path":"aws-cdk-bedrock-orchestration-1/OrchestrationFunction/OrchestrationLambdaInvocationPolicy-c8f49862985034a7","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["OrchestrationFunction2F3851C6","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"},"sourceArn":{"Fn::GetAtt":["CustomOrchestrationAgentDC6CC131","AgentArn"]}}}}}},"CustomOrchestrationAgent":{"id":"CustomOrchestrationAgent","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]},"children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockorcherchestrationagent-e769c494-bedrockagent"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"lambda:InvokeFunction","Effect":"Allow","Resource":[{"Fn::GetAtt":["OrchestrationFunction2F3851C6","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["OrchestrationFunction2F3851C6","Arn"]},":*"]]}]},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"CustomOrchestrationAgentRoleDefaultPolicy33EDF7E6","roles":[{"Ref":"CustomOrchestrationAgentRole85710213"}]}}}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false}],"agentName":"custom-orchestration-agent","agentResourceRoleArn":{"Fn::GetAtt":["CustomOrchestrationAgentRole85710213","Arn"]},"autoPrepare":false,"customOrchestration":{"executor":{"lambda":{"Fn::GetAtt":["OrchestrationFunction2F3851C6","Arn"]}}},"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is an agent using custom orchestration with at least 40 characters of instruction","orchestrationType":"CUSTOM_ORCHESTRATION","skipResourceInUseCheckOnDelete":true}}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-orchestration-1/CustomOrchestrationAgent/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-bedrock-orchestration-1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-bedrock-orchestration-1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"BedrockOrchestration":{"id":"BedrockOrchestration","path":"BedrockOrchestration","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"BedrockOrchestration/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"BedrockOrchestration/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"BedrockOrchestration/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"BedrockOrchestration/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"BedrockOrchestration/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.ts new file mode 100644 index 0000000000000..5465bab9f4311 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.orchestration.ts @@ -0,0 +1,63 @@ +/* + * Integration test for Bedrock Agent Orchestration construct + */ + +/// !cdk-integ aws-cdk-bedrock-orchestration-1 + +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as bedrock from '../../../bedrock'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-orchestration-1'); + +// Create a Lambda function for custom orchestration +const orchestrationFunction = new lambda.Function(stack, 'OrchestrationFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Orchestration Event:', JSON.stringify(event)); + + // Example orchestration logic + const response = { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup || 'default', + apiPath: event.apiPath || '/default', + httpMethod: event.httpMethod || 'GET', + httpStatusCode: 200, + responseBody: { + application_json: { + result: 'Custom orchestration response', + timestamp: new Date().toISOString() + } + } + } + }; + + return response; + }; + `), +}); + +// Create an orchestration executor using the Lambda function +const customOrchestrationExecutor = bedrock.CustomOrchestrationExecutor.fromLambda(orchestrationFunction); + +// Create a Bedrock Agent with custom orchestration +new bedrock.Agent(stack, 'CustomOrchestrationAgent', { + agentName: 'custom-orchestration-agent', + instruction: 'This is an agent using custom orchestration with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + // Specify orchestration executor + customOrchestrationExecutor: customOrchestrationExecutor, +}); + +new integ.IntegTest(app, 'BedrockOrchestration', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.assets.json new file mode 100644 index 0000000000000..606380e1ff833 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4 Template", + "source": { + "path": "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.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/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.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/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/aws-cdk-bedrock-prompt-override-1.assets.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/aws-cdk-bedrock-prompt-override-1.assets.json new file mode 100644 index 0000000000000..c8dd3f8fea267 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/aws-cdk-bedrock-prompt-override-1.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "965de1cced7bc670a8a398eec58c7e6bab6f5cac604e56e0b2acb86253126514": { + "displayName": "aws-cdk-bedrock-prompt-override-1 Template", + "source": { + "path": "aws-cdk-bedrock-prompt-override-1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "965de1cced7bc670a8a398eec58c7e6bab6f5cac604e56e0b2acb86253126514.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/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/aws-cdk-bedrock-prompt-override-1.template.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/aws-cdk-bedrock-prompt-override-1.template.json new file mode 100644 index 0000000000000..69b1f2a548dd4 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/aws-cdk-bedrock-prompt-override-1.template.json @@ -0,0 +1,644 @@ +{ + "Resources": { + "PromptOverrideFunctionServiceRoleB1ACDEAD": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "PromptOverrideFunctionD82AB437": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from prompt override action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "PromptOverrideFunctionServiceRoleB1ACDEAD", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "PromptOverrideFunctionServiceRoleB1ACDEAD" + ] + }, + "PromptOverrideFunctionLambdaInvocationPolicyc8b9aaceca433c559F5E0C1B": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "PromptOverrideFunctionD82AB437", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "CustomParserActionFunctionServiceRoleEE676A1C": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "CustomParserActionFunction3DAF0C7A": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from custom parser action group' }\n }\n }\n };\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomParserActionFunctionServiceRoleEE676A1C", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "CustomParserActionFunctionServiceRoleEE676A1C" + ] + }, + "CustomParserActionFunctionLambdaInvocationPolicyc8cded76e8ed1a7503EDC886": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "CustomParserActionFunction3DAF0C7A", + "Arn" + ] + }, + "Principal": "bedrock.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "ParserFunctionServiceRole59DD83FB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "ParserFunctionE8A187F2": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n exports.handler = async (event) => {\n console.log('Parser Event:', JSON.stringify(event));\n // Extract the raw model response\n const rawResponse = event.invokeModelRawResponse;\n \n // Simple parsing logic - in a real scenario, this would be more sophisticated\n const parsedResponse = {\n messageVersion: '1.0',\n response: rawResponse\n };\n \n return parsedResponse;\n };\n " + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ParserFunctionServiceRole59DD83FB", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "ParserFunctionServiceRole59DD83FB" + ] + }, + "AgentWithPromptOverrideRoleA0EB6013": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockprompithpromptoverride-1d113fbe-bedrockagent" + } + }, + "AgentWithPromptOverrideRoleDefaultPolicy348076D7": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PromptOverrideFunctionD82AB437", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PromptOverrideFunctionD82AB437", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "AgentWithPromptOverrideRoleDefaultPolicy348076D7", + "Roles": [ + { + "Ref": "AgentWithPromptOverrideRoleA0EB6013" + } + ] + } + }, + "AgentWithPromptOverride13B28AED": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "PromptOverrideFunctionD82AB437", + "Arn" + ] + } + }, + "ActionGroupName": "PromptOverrideActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "Payload": "\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n" + }, + "Description": "An action group for testing prompt override configuration", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "agent-with-prompt-override", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "AgentWithPromptOverrideRoleA0EB6013", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is an agent using prompt override configuration with at least 40 characters of instruction", + "OrchestrationType": "DEFAULT", + "PromptOverrideConfiguration": { + "PromptConfigurations": [ + { + "BasePromptTemplate": "{\"messages\":[{\"role\":\"user\",\"content\":\"Process this user request: {{user_input}}\"}]}", + "InferenceConfiguration": { + "MaximumLength": 2048, + "StopSequences": [], + "Temperature": 0.2, + "TopK": 250, + "TopP": 0.9 + }, + "PromptCreationMode": "OVERRIDDEN", + "PromptState": "ENABLED", + "PromptType": "PRE_PROCESSING" + }, + { + "BasePromptTemplate": "{\"messages\":[{\"role\":\"user\",\"content\":\"Refine this response to be more concise and helpful: {{response}}\"}]}", + "InferenceConfiguration": { + "MaximumLength": 1024, + "StopSequences": [], + "Temperature": 0.1, + "TopK": 100, + "TopP": 0.95 + }, + "PromptCreationMode": "OVERRIDDEN", + "PromptState": "ENABLED", + "PromptType": "POST_PROCESSING" + } + ] + }, + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "AgentWithPromptOverrideRoleDefaultPolicy348076D7" + ] + }, + "AgentWithCustomParserRole29295FCD": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + }, + "ArnLike": { + "aws:SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":agent/*" + ] + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "bedrock.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "agent-awscdkbedrockpromptwithcustomparser-6ab08a50-bedrockagent" + } + }, + "AgentWithCustomParserRoleDefaultPolicy00D4B90E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "CustomParserActionFunction3DAF0C7A", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "CustomParserActionFunction3DAF0C7A", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "bedrock:GetFoundationModel", + "bedrock:InvokeModel*" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "AgentWithCustomParserRoleDefaultPolicy00D4B90E", + "Roles": [ + { + "Ref": "AgentWithCustomParserRole29295FCD" + } + ] + } + }, + "AgentWithCustomParser73E443B8": { + "Type": "AWS::Bedrock::Agent", + "Properties": { + "ActionGroups": [ + { + "ActionGroupName": "UserInputAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.UserInput", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupName": "CodeInterpreterAction", + "ActionGroupState": "DISABLED", + "ParentActionGroupSignature": "AMAZON.CodeInterpreter", + "SkipResourceInUseCheckOnDelete": false + }, + { + "ActionGroupExecutor": { + "Lambda": { + "Fn::GetAtt": [ + "CustomParserActionFunction3DAF0C7A", + "Arn" + ] + } + }, + "ActionGroupName": "CustomParserActionGroup", + "ActionGroupState": "ENABLED", + "ApiSchema": { + "Payload": "\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n" + }, + "Description": "An action group for testing custom parser configuration", + "SkipResourceInUseCheckOnDelete": false + } + ], + "AgentName": "agent-with-custom-parser", + "AgentResourceRoleArn": { + "Fn::GetAtt": [ + "AgentWithCustomParserRole29295FCD", + "Arn" + ] + }, + "AutoPrepare": false, + "FoundationModel": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":bedrock:", + { + "Ref": "AWS::Region" + }, + "::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0" + ] + ] + }, + "IdleSessionTTLInSeconds": 600, + "Instruction": "This is an agent using custom parser with at least 40 characters of instruction", + "OrchestrationType": "DEFAULT", + "PromptOverrideConfiguration": { + "OverrideLambda": { + "Fn::GetAtt": [ + "ParserFunctionE8A187F2", + "Arn" + ] + }, + "PromptConfigurations": [ + { + "BasePromptTemplate": "{\"messages\":[{\"role\":\"user\",\"content\":\"Process this user input and prepare it for orchestration: {{user_input}}\"}]}", + "InferenceConfiguration": { + "MaximumLength": 2048, + "StopSequences": [], + "Temperature": 0.2, + "TopK": 250, + "TopP": 0.9 + }, + "ParserMode": "OVERRIDDEN", + "PromptCreationMode": "OVERRIDDEN", + "PromptType": "PRE_PROCESSING" + }, + { + "BasePromptTemplate": "{\"messages\":[{\"role\":\"user\",\"content\":\"Summarize this conversation for memory: {{conversation_history}}\"}]}", + "InferenceConfiguration": { + "MaximumLength": 1024, + "StopSequences": [], + "Temperature": 0.1, + "TopK": 100, + "TopP": 0.95 + }, + "ParserMode": "OVERRIDDEN", + "PromptCreationMode": "OVERRIDDEN", + "PromptType": "MEMORY_SUMMARIZATION" + } + ] + }, + "SkipResourceInUseCheckOnDelete": true + }, + "DependsOn": [ + "AgentWithCustomParserRoleDefaultPolicy00D4B90E" + ] + } + }, + "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/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/cdk.out b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b3a26d44a5f73 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"44.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/integ.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/integ.json new file mode 100644 index 0000000000000..d1dd12b15ecb5 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "44.0.0", + "testCases": { + "BedrockPromptOverride/DefaultTest": { + "stacks": [ + "aws-cdk-bedrock-prompt-override-1" + ], + "assertionStack": "BedrockPromptOverride/DefaultTest/DeployAssert", + "assertionStackName": "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4" + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/manifest.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/manifest.json new file mode 100644 index 0000000000000..f1bde0297eaa5 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/manifest.json @@ -0,0 +1,464 @@ +{ + "version": "44.0.0", + "artifacts": { + "aws-cdk-bedrock-prompt-override-1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-bedrock-prompt-override-1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-bedrock-prompt-override-1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-bedrock-prompt-override-1.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}/965de1cced7bc670a8a398eec58c7e6bab6f5cac604e56e0b2acb86253126514.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-bedrock-prompt-override-1.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-cdk-bedrock-prompt-override-1.assets" + ], + "metadata": { + "/aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PromptOverrideFunctionServiceRoleB1ACDEAD" + } + ], + "/aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PromptOverrideFunctionD82AB437" + } + ], + "/aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/LambdaInvocationPolicy-c8b9aaceca433c55": [ + { + "type": "aws:cdk:logicalId", + "data": "PromptOverrideFunctionLambdaInvocationPolicyc8b9aaceca433c559F5E0C1B" + } + ], + "/aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomParserActionFunctionServiceRoleEE676A1C" + } + ], + "/aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomParserActionFunction3DAF0C7A" + } + ], + "/aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/LambdaInvocationPolicy-c8cded76e8ed1a75": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomParserActionFunctionLambdaInvocationPolicyc8cded76e8ed1a7503EDC886" + } + ], + "/aws-cdk-bedrock-prompt-override-1/ParserFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "runtime": "*", + "handler": "*", + "code": "*" + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/ParserFunction/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "managedPolicies": [ + { + "managedPolicyArn": "*" + } + ] + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/ParserFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-prompt-override-1/ParserFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ParserFunctionServiceRole59DD83FB" + } + ], + "/aws-cdk-bedrock-prompt-override-1/ParserFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ParserFunctionE8A187F2" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithPromptOverrideRoleA0EB6013" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithPromptOverrideRoleDefaultPolicy348076D7" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithPromptOverride13B28AED" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "roleName": "*", + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + } + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithCustomParserRole29295FCD" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithCustomParserRoleDefaultPolicy00D4B90E" + } + ], + "/aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AgentWithCustomParser73E443B8" + } + ], + "/aws-cdk-bedrock-prompt-override-1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-bedrock-prompt-override-1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-bedrock-prompt-override-1" + }, + "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.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": [ + "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.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": [ + "BedrockPromptOverrideDefaultTestDeployAssert7D38F1F4.assets" + ], + "metadata": { + "/BedrockPromptOverride/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/BedrockPromptOverride/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "BedrockPromptOverride/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1017.1" +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/tree.json b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/tree.json new file mode 100644 index 0000000000000..14fab40b76a6e --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"aws-cdk-bedrock-prompt-override-1":{"id":"aws-cdk-bedrock-prompt-override-1","path":"aws-cdk-bedrock-prompt-override-1","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"PromptOverrideFunction":{"id":"PromptOverrideFunction","path":"aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from prompt override action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["PromptOverrideFunctionServiceRoleB1ACDEAD","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c8b9aaceca433c55":{"id":"LambdaInvocationPolicy-c8b9aaceca433c55","path":"aws-cdk-bedrock-prompt-override-1/PromptOverrideFunction/LambdaInvocationPolicy-c8b9aaceca433c55","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["PromptOverrideFunctionD82AB437","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"CustomParserActionFunction":{"id":"CustomParserActionFunction","path":"aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Event:', JSON.stringify(event));\n return {\n messageVersion: '1.0',\n response: {\n actionGroup: event.actionGroup,\n apiPath: event.apiPath,\n httpMethod: event.httpMethod,\n httpStatusCode: 200,\n responseBody: {\n application_json: { result: 'Success from custom parser action group' }\n }\n }\n };\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["CustomParserActionFunctionServiceRoleEE676A1C","Arn"]},"runtime":"nodejs18.x"}}},"LambdaInvocationPolicy-c8cded76e8ed1a75":{"id":"LambdaInvocationPolicy-c8cded76e8ed1a75","path":"aws-cdk-bedrock-prompt-override-1/CustomParserActionFunction/LambdaInvocationPolicy-c8cded76e8ed1a75","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnPermission","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["CustomParserActionFunction3DAF0C7A","Arn"]},"principal":"bedrock.amazonaws.com","sourceAccount":{"Ref":"AWS::AccountId"}}}}}},"ParserFunction":{"id":"ParserFunction","path":"aws-cdk-bedrock-prompt-override-1/ParserFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"runtime":"*","handler":"*","code":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"aws-cdk-bedrock-prompt-override-1/ParserFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"managedPolicies":[{"managedPolicyArn":"*"}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"aws-cdk-bedrock-prompt-override-1/ParserFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/ParserFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/ParserFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"\n exports.handler = async (event) => {\n console.log('Parser Event:', JSON.stringify(event));\n // Extract the raw model response\n const rawResponse = event.invokeModelRawResponse;\n \n // Simple parsing logic - in a real scenario, this would be more sophisticated\n const parsedResponse = {\n messageVersion: '1.0',\n response: rawResponse\n };\n \n return parsedResponse;\n };\n "},"handler":"index.handler","role":{"Fn::GetAtt":["ParserFunctionServiceRole59DD83FB","Arn"]},"runtime":"nodejs18.x"}}}}},"AgentWithPromptOverride":{"id":"AgentWithPromptOverride","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]},"children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockprompithpromptoverride-1d113fbe-bedrockagent"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"lambda:InvokeFunction","Effect":"Allow","Resource":[{"Fn::GetAtt":["PromptOverrideFunctionD82AB437","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["PromptOverrideFunctionD82AB437","Arn"]},":*"]]}]},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"AgentWithPromptOverrideRoleDefaultPolicy348076D7","roles":[{"Ref":"AgentWithPromptOverrideRoleA0EB6013"}]}}}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["PromptOverrideFunctionD82AB437","Arn"]}},"actionGroupName":"PromptOverrideActionGroup","actionGroupState":"ENABLED","apiSchema":{"payload":"\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n"},"description":"An action group for testing prompt override configuration","skipResourceInUseCheckOnDelete":false}],"agentName":"agent-with-prompt-override","agentResourceRoleArn":{"Fn::GetAtt":["AgentWithPromptOverrideRoleA0EB6013","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is an agent using prompt override configuration with at least 40 characters of instruction","orchestrationType":"DEFAULT","promptOverrideConfiguration":{"promptConfigurations":[{"promptType":"PRE_PROCESSING","promptState":"ENABLED","promptCreationMode":"OVERRIDDEN","basePromptTemplate":"{\"messages\":[{\"role\":\"user\",\"content\":\"Process this user request: {{user_input}}\"}]}","inferenceConfiguration":{"temperature":0.2,"topP":0.9,"topK":250,"maximumLength":2048,"stopSequences":[]}},{"promptType":"POST_PROCESSING","promptState":"ENABLED","promptCreationMode":"OVERRIDDEN","basePromptTemplate":"{\"messages\":[{\"role\":\"user\",\"content\":\"Refine this response to be more concise and helpful: {{response}}\"}]}","inferenceConfiguration":{"temperature":0.1,"topP":0.95,"topK":100,"maximumLength":1024,"stopSequences":[]}}]},"skipResourceInUseCheckOnDelete":true}}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-prompt-override-1/AgentWithPromptOverride/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}}},"AgentWithCustomParser":{"id":"AgentWithCustomParser","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.Agent","version":"0.0.0","metadata":[]},"children":{"Role":{"id":"Role","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"roleName":"*","assumedBy":{"principalAccount":"*","assumeRoleAction":"*"}},{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportRole":{"id":"ImportRole","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/ImportRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Condition":{"StringEquals":{"aws:SourceAccount":{"Ref":"AWS::AccountId"}},"ArnLike":{"aws:SourceArn":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":agent/*"]]}}},"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"}}],"Version":"2012-10-17"},"roleName":"agent-awscdkbedrockpromptwithcustomparser-6ab08a50-bedrockagent"}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Role/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"lambda:InvokeFunction","Effect":"Allow","Resource":[{"Fn::GetAtt":["CustomParserActionFunction3DAF0C7A","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["CustomParserActionFunction3DAF0C7A","Arn"]},":*"]]}]},{"Action":["bedrock:GetFoundationModel","bedrock:InvokeModel*"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]}}],"Version":"2012-10-17"},"policyName":"AgentWithCustomParserRoleDefaultPolicy00D4B90E","roles":[{"Ref":"AgentWithCustomParserRole29295FCD"}]}}}}}}},"Resource":{"id":"Resource","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_bedrock.CfnAgent","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Bedrock::Agent","aws:cdk:cloudformation:props":{"actionGroups":[{"actionGroupName":"UserInputAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.UserInput","skipResourceInUseCheckOnDelete":false},{"actionGroupName":"CodeInterpreterAction","actionGroupState":"DISABLED","parentActionGroupSignature":"AMAZON.CodeInterpreter","skipResourceInUseCheckOnDelete":false},{"actionGroupExecutor":{"lambda":{"Fn::GetAtt":["CustomParserActionFunction3DAF0C7A","Arn"]}},"actionGroupName":"CustomParserActionGroup","actionGroupState":"ENABLED","apiSchema":{"payload":"\nopenapi: 3.0.3\ninfo:\n title: Simple API\n version: 1.0.0\npaths:\n /hello:\n get:\n operationId: helloWorld\n summary: Say hello\n description: Returns a greeting message\n responses:\n '200':\n description: Successful response\n content:\n application/json:\n schema:\n type: object\n properties:\n message:\n type: string\n"},"description":"An action group for testing custom parser configuration","skipResourceInUseCheckOnDelete":false}],"agentName":"agent-with-custom-parser","agentResourceRoleArn":{"Fn::GetAtt":["AgentWithCustomParserRole29295FCD","Arn"]},"autoPrepare":false,"foundationModel":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":bedrock:",{"Ref":"AWS::Region"},"::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"]]},"idleSessionTtlInSeconds":600,"instruction":"This is an agent using custom parser with at least 40 characters of instruction","orchestrationType":"DEFAULT","promptOverrideConfiguration":{"overrideLambda":{"Fn::GetAtt":["ParserFunctionE8A187F2","Arn"]},"promptConfigurations":[{"promptType":"PRE_PROCESSING","parserMode":"OVERRIDDEN","promptCreationMode":"OVERRIDDEN","basePromptTemplate":"{\"messages\":[{\"role\":\"user\",\"content\":\"Process this user input and prepare it for orchestration: {{user_input}}\"}]}","inferenceConfiguration":{"temperature":0.2,"topP":0.9,"topK":250,"maximumLength":2048,"stopSequences":[]}},{"promptType":"MEMORY_SUMMARIZATION","parserMode":"OVERRIDDEN","promptCreationMode":"OVERRIDDEN","basePromptTemplate":"{\"messages\":[{\"role\":\"user\",\"content\":\"Summarize this conversation for memory: {{conversation_history}}\"}]}","inferenceConfiguration":{"temperature":0.1,"topP":0.95,"topK":100,"maximumLength":1024,"stopSequences":[]}}]},"skipResourceInUseCheckOnDelete":true}}},"DefaultAlias":{"id":"DefaultAlias","path":"aws-cdk-bedrock-prompt-override-1/AgentWithCustomParser/DefaultAlias","constructInfo":{"fqn":"@aws-cdk/aws-bedrock-alpha.AgentAliasBase","version":"0.0.0","metadata":[]}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"aws-cdk-bedrock-prompt-override-1/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"aws-cdk-bedrock-prompt-override-1/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"BedrockPromptOverride":{"id":"BedrockPromptOverride","path":"BedrockPromptOverride","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"BedrockPromptOverride/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"BedrockPromptOverride/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"BedrockPromptOverride/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"BedrockPromptOverride/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"BedrockPromptOverride/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.ts new file mode 100644 index 0000000000000..25b45799b7ebe --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/integ.prompt-override.ts @@ -0,0 +1,200 @@ +/* + * Integration test for Bedrock Agent Prompt Override configuration + */ + +/// !cdk-integ aws-cdk-bedrock-prompt-override-1 + +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as bedrock from '../../../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-prompt-override-1'); + +// Create Lambda functions for the action group executors +const promptOverrideFunction = new lambda.Function(stack, 'PromptOverrideFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from prompt override action group' } + } + } + }; + }; + `), +}); + +const customParserActionFunction = new lambda.Function(stack, 'CustomParserActionFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Event:', JSON.stringify(event)); + return { + messageVersion: '1.0', + response: { + actionGroup: event.actionGroup, + apiPath: event.apiPath, + httpMethod: event.httpMethod, + httpStatusCode: 200, + responseBody: { + application_json: { result: 'Success from custom parser action group' } + } + } + }; + }; + `), +}); + +// Create a Lambda function for the custom parser +const parserFunction = new lambda.Function(stack, 'ParserFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline(` + exports.handler = async (event) => { + console.log('Parser Event:', JSON.stringify(event)); + // Extract the raw model response + const rawResponse = event.invokeModelRawResponse; + + // Simple parsing logic - in a real scenario, this would be more sophisticated + const parsedResponse = { + messageVersion: '1.0', + response: rawResponse + }; + + return parsedResponse; + }; + `), +}); + +// Create action group executors +const promptOverrideExecutor = bedrock.ActionGroupExecutor.fromLambda(promptOverrideFunction); +const customParserExecutor = bedrock.ActionGroupExecutor.fromLambda(customParserActionFunction); + +// Create a simple API schema +const apiSchema = bedrock.ApiSchema.fromInline(` +openapi: 3.0.3 +info: + title: Simple API + version: 1.0.0 +paths: + /hello: + get: + operationId: helloWorld + summary: Say hello + description: Returns a greeting message + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + message: + type: string +`); + +// Create action groups +const promptOverrideActionGroup = new bedrock.AgentActionGroup({ + name: 'PromptOverrideActionGroup', + description: 'An action group for testing prompt override configuration', + apiSchema: apiSchema, + executor: promptOverrideExecutor, +}); + +const customParserActionGroup = new bedrock.AgentActionGroup({ + name: 'CustomParserActionGroup', + description: 'An action group for testing custom parser configuration', + apiSchema: apiSchema, + executor: customParserExecutor, +}); + +// Test 1: Create an agent with prompt override configuration using fromSteps +new bedrock.Agent(stack, 'AgentWithPromptOverride', { + agentName: 'agent-with-prompt-override', + instruction: 'This is an agent using prompt override configuration with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + actionGroups: [promptOverrideActionGroup], + promptOverrideConfiguration: bedrock.PromptOverrideConfiguration.fromSteps([ + { + stepType: bedrock.AgentStepType.PRE_PROCESSING, + stepEnabled: true, + customPromptTemplate: '{"messages":[{"role":"user","content":"Process this user request: {{user_input}}"}]}', + inferenceConfig: { + temperature: 0.2, + topP: 0.9, + topK: 250, + maximumLength: 2048, + stopSequences: [], + }, + }, + { + stepType: bedrock.AgentStepType.POST_PROCESSING, + stepEnabled: true, + customPromptTemplate: '{"messages":[{"role":"user","content":"Refine this response to be more concise and helpful: {{response}}"}]}', + inferenceConfig: { + temperature: 0.1, + topP: 0.95, + topK: 100, + maximumLength: 1024, + stopSequences: [], + }, + }, + ]), +}); + +// Test 2: Create an agent with prompt override configuration using withCustomParser +new bedrock.Agent(stack, 'AgentWithCustomParser', { + agentName: 'agent-with-custom-parser', + instruction: 'This is an agent using custom parser with at least 40 characters of instruction', + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, + forceDelete: true, + actionGroups: [customParserActionGroup], + promptOverrideConfiguration: bedrock.PromptOverrideConfiguration.withCustomParser({ + parser: parserFunction, + preProcessingStep: { + stepType: bedrock.AgentStepType.PRE_PROCESSING, + useCustomParser: true, + customPromptTemplate: '{"messages":[{"role":"user","content":"Process this user input and prepare it for orchestration: {{user_input}}"}]}', + inferenceConfig: { + temperature: 0.2, + topP: 0.9, + topK: 250, + maximumLength: 2048, + stopSequences: [], + }, + }, + memorySummarizationStep: { + stepType: bedrock.AgentStepType.MEMORY_SUMMARIZATION, + useCustomParser: true, + customPromptTemplate: '{"messages":[{"role":"user","content":"Summarize this conversation for memory: {{conversation_history}}"}]}', + inferenceConfig: { + temperature: 0.1, + topP: 0.95, + topK: 100, + maximumLength: 1024, + stopSequences: [], + }, + }, + }), +}); + +new integ.IntegTest(app, 'BedrockPromptOverride', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/memory.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/memory.test.ts new file mode 100644 index 0000000000000..56788495884ac --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/memory.test.ts @@ -0,0 +1,112 @@ +import { App } from 'aws-cdk-lib/core'; +import * as core from 'aws-cdk-lib/core'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import { Memory } from '../../../bedrock/agents/memory'; +import { Template } from 'aws-cdk-lib/assertions'; +import * as bedrock from '../../../lib'; + +describe('Memory', () => { + let stack: core.Stack; + let foundationModel: bedrock.IBedrockInvokable; + + beforeEach(() => { + const app = new App(); + stack = new core.Stack(app, 'test-stack'); + foundationModel = { + invokableArn: 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2', + grantInvoke: (grantee) => { + return iam.Grant.addToPrincipal({ + grantee, + actions: ['bedrock:InvokeModel*', 'bedrock:GetFoundationModel'], + resourceArns: ['arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2'], + }); + }, + }; + }); + + describe('sessionSummary', () => { + test('sets session summary memory configuration correctly', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + memory: Memory.sessionSummary({ + memoryDuration: core.Duration.days(30), + maxRecentSessions: 20, + }), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + MemoryConfiguration: { + EnabledMemoryTypes: ['SESSION_SUMMARY'], + StorageDays: 30, + SessionSummaryConfiguration: { + MaxRecentSessions: 20, + }, + }, + }); + }); + + test('validates memory duration days range', () => { + expect(() => { + Memory.sessionSummary({ + memoryDuration: core.Duration.days(0), + maxRecentSessions: 20, + }); + }).toThrow(/memoryDuration must be between 1 and 365 days/); + + expect(() => { + Memory.sessionSummary({ + memoryDuration: core.Duration.days(366), + maxRecentSessions: 20, + }); + }).toThrow(/memoryDuration must be between 1 and 365 days/); + }); + + test('validates maxRecentSessions range', () => { + expect(() => { + Memory.sessionSummary({ + memoryDuration: core.Duration.days(30), + maxRecentSessions: 0, + }); + }).toThrow(/maxRecentSessions must be greater than 0/); + }); + + test('uses default values when not provided', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + memory: Memory.sessionSummary({}), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + MemoryConfiguration: { + EnabledMemoryTypes: ['SESSION_SUMMARY'], + StorageDays: 30, + SessionSummaryConfiguration: { + MaxRecentSessions: 20, + }, + }, + }); + }); + }); + + describe('SESSION_SUMMARY', () => { + test('uses static SESSION_SUMMARY property', () => { + new bedrock.Agent(stack, 'TestAgent', { + instruction: 'This is a test instruction that must be at least 40 characters long to be valid', + foundationModel, + memory: Memory.SESSION_SUMMARY, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::Bedrock::Agent', { + MemoryConfiguration: { + EnabledMemoryTypes: ['SESSION_SUMMARY'], + StorageDays: 30, + SessionSummaryConfiguration: { + MaxRecentSessions: 20, + }, + }, + }); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/models.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/models.test.ts new file mode 100644 index 0000000000000..0395ad37967ea --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/models.test.ts @@ -0,0 +1,271 @@ +import { Stack } from 'aws-cdk-lib'; +import { Template } from 'aws-cdk-lib/assertions'; +import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; +import { FoundationModel, FoundationModelIdentifier } from 'aws-cdk-lib/aws-bedrock'; +import { BedrockFoundationModel, VectorType } from '../../../bedrock/models'; + +describe('BedrockFoundationModel', () => { + test('creates model with default properties', () => { + // GIVEN + const model = new BedrockFoundationModel('test.model-v1'); + + // THEN + expect(model.modelId).toBe('test.model-v1'); + expect(model.supportsAgents).toBe(false); + expect(model.supportsCrossRegion).toBe(false); + expect(model.supportsKnowledgeBase).toBe(false); + expect(model.vectorDimensions).toBeUndefined(); + expect(model.supportedVectorType).toBeUndefined(); + }); + + test('creates model with custom properties', () => { + // GIVEN + const model = new BedrockFoundationModel('test.model-v1', { + supportsAgents: true, + supportsCrossRegion: true, + supportsKnowledgeBase: true, + vectorDimensions: 1024, + supportedVectorType: [VectorType.FLOATING_POINT, VectorType.BINARY], + }); + + // THEN + expect(model.modelId).toBe('test.model-v1'); + expect(model.supportsAgents).toBe(true); + expect(model.supportsCrossRegion).toBe(true); + expect(model.supportsKnowledgeBase).toBe(true); + expect(model.vectorDimensions).toBe(1024); + expect(model.supportedVectorType).toEqual([VectorType.FLOATING_POINT, VectorType.BINARY]); + }); + + test('grants invoke permissions', () => { + // GIVEN + const stack = new Stack(); + const role = new Role(stack, 'TestRole', { + assumedBy: new ServicePrincipal('lambda.amazonaws.com'), + }); + const model = new BedrockFoundationModel('test.model-v1'); + + // WHEN + model.grantInvoke(role); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'bedrock:InvokeModel*', + 'bedrock:GetFoundationModel', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':bedrock:', + { Ref: 'AWS::Region' }, + '::foundation-model/test.model-v1', + ], + ], + }, + }, + ], + }, + }); + }); + + test('grants invoke permissions for all regions', () => { + // GIVEN + const stack = new Stack(); + const role = new Role(stack, 'TestRole', { + assumedBy: new ServicePrincipal('lambda.amazonaws.com'), + }); + const model = new BedrockFoundationModel('test.model-v1'); + + // WHEN + model.grantInvokeAllRegions(role); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'bedrock:InvokeModel*', + 'bedrock:GetFoundationModel', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':bedrock:*::foundation-model/test.model-v1', + ], + ], + }, + }, + ], + }, + }); + }); + + test('toString returns modelId', () => { + // GIVEN + const model = new BedrockFoundationModel('test.model-v1'); + + // THEN + expect(model.toString()).toBe('test.model-v1'); + }); + + test('asIModel returns self', () => { + // GIVEN + const model = new BedrockFoundationModel('test.model-v1'); + + // THEN + expect(model.asIModel()).toBe(model); + }); + + test('fromCdkFoundationModelId creates model correctly', () => { + // GIVEN + const modelId = new FoundationModelIdentifier('test.model-v1'); + + // WHEN + const model = BedrockFoundationModel.fromCdkFoundationModelId(modelId, { + supportsAgents: true, + supportsCrossRegion: true, + }); + + // THEN + expect(model.modelId).toBe('test.model-v1'); + expect(model.supportsAgents).toBe(true); + expect(model.supportsCrossRegion).toBe(true); + }); + + test('fromCdkFoundationModelId creates model with default properties', () => { + // GIVEN + const modelId = new FoundationModelIdentifier('test.model-v1'); + + // WHEN + const model = BedrockFoundationModel.fromCdkFoundationModelId(modelId); + + // THEN + expect(model.modelId).toBe('test.model-v1'); + expect(model.supportsAgents).toBe(false); + expect(model.supportsCrossRegion).toBe(false); + expect(model.supportsKnowledgeBase).toBe(false); + expect(model.vectorDimensions).toBeUndefined(); + expect(model.supportedVectorType).toBeUndefined(); + }); + + test('fromCdkFoundationModel creates model correctly', () => { + // GIVEN + const modelId = new FoundationModelIdentifier('test.model-v1'); + const stack = new Stack(); + const foundationModel = FoundationModel.fromFoundationModelId(stack, 'TestModel', modelId); + + // WHEN + const model = BedrockFoundationModel.fromCdkFoundationModel(foundationModel, { + supportsAgents: true, + supportsCrossRegion: true, + }); + + // THEN + expect(model.modelId).toBe(modelId.modelId); + expect(model.supportsAgents).toBe(true); + expect(model.supportsCrossRegion).toBe(true); + }); + + test('fromCdkFoundationModel creates model with default properties', () => { + // GIVEN + const modelId = new FoundationModelIdentifier('test.model-v1'); + const stack = new Stack(); + const foundationModel = FoundationModel.fromFoundationModelId(stack, 'TestModel', modelId); + + // WHEN + const model = BedrockFoundationModel.fromCdkFoundationModel(foundationModel); + + // THEN + expect(model.modelId).toBe(modelId.modelId); + expect(model.supportsAgents).toBe(false); + expect(model.supportsCrossRegion).toBe(false); + expect(model.supportsKnowledgeBase).toBe(false); + expect(model.vectorDimensions).toBeUndefined(); + expect(model.supportedVectorType).toBeUndefined(); + }); + + describe('static model instances', () => { + test('AI21 models are configured correctly', () => { + expect(BedrockFoundationModel.AI21_JAMBA_1_5_LARGE_V1.modelId).toBe('ai21.jamba-1-5-large-v1:0'); + expect(BedrockFoundationModel.AI21_JAMBA_1_5_LARGE_V1.supportsAgents).toBe(true); + + expect(BedrockFoundationModel.AI21_JAMBA_1_5_MINI_V1.modelId).toBe('ai21.jamba-1-5-mini-v1:0'); + expect(BedrockFoundationModel.AI21_JAMBA_1_5_MINI_V1.supportsAgents).toBe(true); + + expect(BedrockFoundationModel.AI21_JAMBA_INSTRUCT_V1.modelId).toBe('ai21.jamba-instruct-v1:0'); + expect(BedrockFoundationModel.AI21_JAMBA_INSTRUCT_V1.supportsAgents).toBe(true); + }); + + test('Amazon models are configured correctly', () => { + expect(BedrockFoundationModel.AMAZON_TITAN_TEXT_EXPRESS_V1.modelId).toBe('amazon.titan-text-express-v1'); + expect(BedrockFoundationModel.AMAZON_TITAN_TEXT_EXPRESS_V1.supportsAgents).toBe(true); + + expect(BedrockFoundationModel.AMAZON_NOVA_MICRO_V1.modelId).toBe('amazon.nova-micro-v1:0'); + expect(BedrockFoundationModel.AMAZON_NOVA_MICRO_V1.supportsAgents).toBe(true); + expect(BedrockFoundationModel.AMAZON_NOVA_MICRO_V1.supportsCrossRegion).toBe(true); + + expect(BedrockFoundationModel.TITAN_EMBED_TEXT_V1.modelId).toBe('amazon.titan-embed-text-v1'); + expect(BedrockFoundationModel.TITAN_EMBED_TEXT_V1.supportsKnowledgeBase).toBe(true); + expect(BedrockFoundationModel.TITAN_EMBED_TEXT_V1.vectorDimensions).toBe(1536); + expect(BedrockFoundationModel.TITAN_EMBED_TEXT_V1.supportedVectorType).toEqual([VectorType.FLOATING_POINT]); + }); + + test('Anthropic models are configured correctly', () => { + expect(BedrockFoundationModel.ANTHROPIC_CLAUDE_3_7_SONNET_V1_0.modelId).toBe('anthropic.claude-3-7-sonnet-20250219-v1:0'); + expect(BedrockFoundationModel.ANTHROPIC_CLAUDE_3_7_SONNET_V1_0.supportsAgents).toBe(true); + expect(BedrockFoundationModel.ANTHROPIC_CLAUDE_3_7_SONNET_V1_0.supportsCrossRegion).toBe(true); + + expect(BedrockFoundationModel.ANTHROPIC_CLAUDE_V2.modelId).toBe('anthropic.claude-v2'); + expect(BedrockFoundationModel.ANTHROPIC_CLAUDE_V2.supportsAgents).toBe(true); + }); + + test('Cohere models are configured correctly', () => { + expect(BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3.modelId).toBe('cohere.embed-english-v3'); + expect(BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3.supportsKnowledgeBase).toBe(true); + expect(BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3.vectorDimensions).toBe(1024); + expect(BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3.supportedVectorType).toEqual([ + VectorType.FLOATING_POINT, + VectorType.BINARY, + ]); + + expect(BedrockFoundationModel.COHERE_EMBED_MULTILINGUAL_V3.modelId).toBe('cohere.embed-multilingual-v3'); + expect(BedrockFoundationModel.COHERE_EMBED_MULTILINGUAL_V3.supportsKnowledgeBase).toBe(true); + expect(BedrockFoundationModel.COHERE_EMBED_MULTILINGUAL_V3.vectorDimensions).toBe(1024); + }); + + test('Meta models are configured correctly', () => { + expect(BedrockFoundationModel.META_LLAMA_3_1_8B_INSTRUCT_V1.modelId).toBe('meta.llama3-1-8b-instruct-v1:0'); + expect(BedrockFoundationModel.META_LLAMA_3_1_8B_INSTRUCT_V1.supportsAgents).toBe(true); + expect(BedrockFoundationModel.META_LLAMA_3_1_8B_INSTRUCT_V1.supportsCrossRegion).toBe(true); + + expect(BedrockFoundationModel.META_LLAMA_4_MAVERICK_17B_INSTRUCT_V1.modelId).toBe('meta.llama4-maverick-17b-instruct-v1:0'); + expect(BedrockFoundationModel.META_LLAMA_4_MAVERICK_17B_INSTRUCT_V1.supportsAgents).toBe(true); + expect(BedrockFoundationModel.META_LLAMA_4_MAVERICK_17B_INSTRUCT_V1.supportsCrossRegion).toBe(true); + }); + + test('Mistral models are configured correctly', () => { + expect(BedrockFoundationModel.MISTRAL_7B_INSTRUCT_V0.modelId).toBe('mistral.mistral-7b-instruct-v0:2'); + expect(BedrockFoundationModel.MISTRAL_7B_INSTRUCT_V0.supportsAgents).toBe(true); + expect(BedrockFoundationModel.MISTRAL_7B_INSTRUCT_V0.supportsCrossRegion).toBe(false); + + expect(BedrockFoundationModel.MISTRAL_LARGE_2402_V1.modelId).toBe('mistral.mistral-large-2402-v1:0'); + expect(BedrockFoundationModel.MISTRAL_LARGE_2402_V1.supportsAgents).toBe(true); + expect(BedrockFoundationModel.MISTRAL_LARGE_2402_V1.supportsCrossRegion).toBe(false); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/orchestration-executor.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/orchestration-executor.test.ts new file mode 100644 index 0000000000000..e523d3924ebf6 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/orchestration-executor.test.ts @@ -0,0 +1,130 @@ +import { Stack } from 'aws-cdk-lib'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { CustomOrchestrationExecutor } from '../../../bedrock/agents/orchestration-executor'; + +describe('CustomOrchestrationExecutor', () => { + let stack: Stack; + let testFunction: lambda.Function; + + beforeEach(() => { + stack = new Stack(); + testFunction = new lambda.Function(stack, 'TestFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function() { }'), + }); + }); + + test('can create from lambda function', () => { + // WHEN + const executor = CustomOrchestrationExecutor.fromLambda(testFunction); + + // THEN + expect(executor).toBeInstanceOf(CustomOrchestrationExecutor); + expect(executor.lambdaFunction).toBe(testFunction); + }); + + test('renders CFN properties correctly', () => { + // GIVEN + const executor = CustomOrchestrationExecutor.fromLambda(testFunction); + + // WHEN + const rendered = executor._render(); + + // THEN + expect(rendered).toEqual({ + lambda: testFunction.functionArn, + }); + }); + + test('handles undefined lambda function gracefully', () => { + // GIVEN + const executor = CustomOrchestrationExecutor.fromLambda(undefined as any); + + // WHEN + const rendered = executor._render(); + + // THEN + expect(rendered).toEqual({ + lambda: undefined, + }); + }); + + test('handles null lambda function gracefully', () => { + // GIVEN + const executor = CustomOrchestrationExecutor.fromLambda(null as any); + + // WHEN + const rendered = executor._render(); + + // THEN + expect(rendered).toEqual({ + lambda: undefined, + }); + }); + + test('handles lambda function with undefined functionArn', () => { + // GIVEN + const mockFunction = {} as lambda.IFunction; + const executor = CustomOrchestrationExecutor.fromLambda(mockFunction); + + // WHEN + const rendered = executor._render(); + + // THEN + expect(rendered).toEqual({ + lambda: undefined, + }); + }); + + test('handles non-function input', () => { + // GIVEN + const nonFunction = { someProperty: 'value' }; + + // THEN + expect(() => { + CustomOrchestrationExecutor.fromLambda(nonFunction as any); + }).not.toThrow(); + }); + + test('handles lambda function with null functionArn', () => { + // GIVEN + const mockFunction = { + functionArn: null, + } as any as lambda.IFunction; + const executor = CustomOrchestrationExecutor.fromLambda(mockFunction); + + // WHEN + const rendered = executor._render(); + + // THEN + expect(rendered).toEqual({ + lambda: null, + }); + }); + + test('preserves lambda function reference', () => { + // GIVEN + const executor = CustomOrchestrationExecutor.fromLambda(testFunction); + const anotherExecutor = CustomOrchestrationExecutor.fromLambda(testFunction); + + // THEN + expect(executor.lambdaFunction).toBe(anotherExecutor.lambdaFunction); + }); + + test('renders with mock lambda function', () => { + // GIVEN + const mockFunction = { + functionArn: 'arn:aws:lambda:us-west-2:123456789012:function:test', + } as lambda.IFunction; + const executor = CustomOrchestrationExecutor.fromLambda(mockFunction); + + // WHEN + const rendered = executor._render(); + + // THEN + expect(rendered).toEqual({ + lambda: 'arn:aws:lambda:us-west-2:123456789012:function:test', + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/prompt-override.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/prompt-override.test.ts new file mode 100644 index 0000000000000..9d91a997ab5e7 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/prompt-override.test.ts @@ -0,0 +1,405 @@ +import { Stack } from 'aws-cdk-lib'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { + AgentStepType, + PromptOverrideConfiguration, + PromptRoutingClassifierConfigCustomParser, + PromptPreProcessingConfigCustomParser, + PromptOrchestrationConfigCustomParser, + PromptPostProcessingConfigCustomParser, +} from '../../../bedrock/agents/prompt-override'; +import { IBedrockInvokable } from '../../../bedrock/models'; + +describe('PromptOverrideConfiguration', () => { + let stack: Stack; + let mockFoundationModel: IBedrockInvokable; + + beforeEach(() => { + stack = new Stack(); + mockFoundationModel = { + invokableArn: 'arn:aws:bedrock:us-east-1:123456789012:foundation-model/anthropic.claude-v2', + grantInvoke: jest.fn(), + }; + }); + + describe('fromSteps', () => { + test('creates with valid steps', () => { + // WHEN + const config = PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + stepEnabled: true, + customPromptTemplate: 'test template', + inferenceConfig: { + temperature: 0.5, + topP: 0.5, + topK: 250, + stopSequences: ['stop'], + maximumLength: 2048, + }, + }, + ]); + + // THEN + const rendered = config._render(); + expect(rendered.promptConfigurations).toHaveLength(1); + const configs = rendered.promptConfigurations as any[]; + expect(configs[0]).toEqual({ + promptType: AgentStepType.PRE_PROCESSING, + promptState: 'ENABLED', + parserMode: undefined, + promptCreationMode: 'OVERRIDDEN', + basePromptTemplate: 'test template', + inferenceConfiguration: { + temperature: 0.5, + topP: 0.5, + topK: 250, + stopSequences: ['stop'], + maximumLength: 2048, + }, + foundationModel: undefined, + }); + }); + + test('creates with multiple steps', () => { + // WHEN + const config = PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + stepEnabled: true, + customPromptTemplate: 'pre template', + }, + { + stepType: AgentStepType.ORCHESTRATION, + stepEnabled: true, + customPromptTemplate: 'orchestration template', + }, + { + stepType: AgentStepType.POST_PROCESSING, + stepEnabled: false, + customPromptTemplate: 'post template', + }, + ]); + + // THEN + const rendered = config._render(); + expect(rendered.promptConfigurations).toHaveLength(3); + const configs = rendered.promptConfigurations as any[]; + expect(configs[0].promptType).toBe(AgentStepType.PRE_PROCESSING); + expect(configs[1].promptType).toBe(AgentStepType.ORCHESTRATION); + expect(configs[2].promptType).toBe(AgentStepType.POST_PROCESSING); + }); + + test('creates with all step types', () => { + // WHEN + const config = PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + stepEnabled: true, + }, + { + stepType: AgentStepType.ORCHESTRATION, + stepEnabled: true, + }, + { + stepType: AgentStepType.POST_PROCESSING, + stepEnabled: true, + }, + { + stepType: AgentStepType.ROUTING_CLASSIFIER, + stepEnabled: true, + foundationModel: mockFoundationModel, + } as PromptRoutingClassifierConfigCustomParser, + { + stepType: AgentStepType.MEMORY_SUMMARIZATION, + stepEnabled: true, + }, + { + stepType: AgentStepType.KNOWLEDGE_BASE_RESPONSE_GENERATION, + stepEnabled: true, + }, + ]); + + // THEN + const rendered = config._render(); + expect(rendered.promptConfigurations).toHaveLength(6); + const configs = rendered.promptConfigurations as any[]; + expect(configs.map(c => c.promptType)).toEqual([ + AgentStepType.PRE_PROCESSING, + AgentStepType.ORCHESTRATION, + AgentStepType.POST_PROCESSING, + AgentStepType.ROUTING_CLASSIFIER, + AgentStepType.MEMORY_SUMMARIZATION, + AgentStepType.KNOWLEDGE_BASE_RESPONSE_GENERATION, + ]); + }); + + test('throws error for empty steps', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([]); + }).toThrow('Steps array cannot be empty'); + }); + }); + + describe('withCustomParser', () => { + test('creates with valid parser and steps', () => { + // GIVEN + const parser = new lambda.Function(stack, 'TestParser', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = () => {}'), + }); + + // WHEN + const config = PromptOverrideConfiguration.withCustomParser({ + parser, + preProcessingStep: { + stepType: AgentStepType.PRE_PROCESSING, + useCustomParser: true, + } as PromptPreProcessingConfigCustomParser, + }); + + // THEN + const rendered = config._render(); + expect(rendered.overrideLambda).toBeDefined(); + const configs = rendered.promptConfigurations as any[]; + expect(configs[0].parserMode).toBe('OVERRIDDEN'); + }); + + test('throws error when no step uses custom parser', () => { + // GIVEN + const parser = new lambda.Function(stack, 'TestParser', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = () => {}'), + }); + + // THEN + expect(() => { + PromptOverrideConfiguration.withCustomParser({ + parser, + preProcessingStep: { + stepType: AgentStepType.PRE_PROCESSING, + useCustomParser: false, + } as PromptPreProcessingConfigCustomParser, + }); + }).toThrow('At least one step must use custom parser'); + }); + }); + + describe('inference configuration validation', () => { + test('validates temperature range', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + inferenceConfig: { + temperature: 1.5, + topP: 0.5, + topK: 250, + stopSequences: ['stop'], + maximumLength: 2048, + }, + }, + ]); + }).toThrow('Temperature must be between 0 and 1'); + }); + + test('validates topP range', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + inferenceConfig: { + temperature: 0.5, + topP: 1.5, + topK: 250, + stopSequences: ['stop'], + maximumLength: 2048, + }, + }, + ]); + }).toThrow('TopP must be between 0 and 1'); + }); + + test('validates topK range', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + inferenceConfig: { + temperature: 0.5, + topP: 0.5, + topK: 501, + stopSequences: ['stop'], + maximumLength: 2048, + }, + }, + ]); + }).toThrow('TopK must be between 0 and 500'); + }); + + test('validates stopSequences length', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + inferenceConfig: { + temperature: 0.5, + topP: 0.5, + topK: 250, + stopSequences: ['stop1', 'stop2', 'stop3', 'stop4', 'stop5'], + maximumLength: 2048, + }, + }, + ]); + }).toThrow('Maximum 4 stop sequences allowed'); + }); + + test('validates maximumLength range', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + inferenceConfig: { + temperature: 0.5, + topP: 0.5, + topK: 250, + stopSequences: ['stop'], + maximumLength: 5000, + }, + }, + ]); + }).toThrow('MaximumLength must be between 0 and 4096'); + }); + }); + + describe('foundation model validation', () => { + test('allows foundation model for ROUTING_CLASSIFIER', () => { + // WHEN + const config = PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.ROUTING_CLASSIFIER, + foundationModel: mockFoundationModel, + } as PromptRoutingClassifierConfigCustomParser, + ]); + + // THEN + const rendered = config._render(); + const configs = rendered.promptConfigurations as any[]; + expect(configs[0].foundationModel).toBe(mockFoundationModel.invokableArn); + }); + + test('throws error for foundation model in non-ROUTING_CLASSIFIER step', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + foundationModel: mockFoundationModel, + } as PromptPreProcessingConfigCustomParser, + ]); + }).toThrow('Foundation model can only be specified for ROUTING_CLASSIFIER step type'); + }); + + test('throws error for invalid foundation model', () => { + // THEN + expect(() => { + PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.ROUTING_CLASSIFIER, + foundationModel: {} as IBedrockInvokable, + } as PromptRoutingClassifierConfigCustomParser, + ]); + }).toThrow('Foundation model must be a valid IBedrockInvokable with an invokableArn'); + }); + }); + + describe('rendering', () => { + test('renders step states correctly', () => { + // WHEN + const config = PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + stepEnabled: true, + }, + { + stepType: AgentStepType.ORCHESTRATION, + stepEnabled: false, + }, + { + stepType: AgentStepType.POST_PROCESSING, + stepEnabled: undefined, + }, + ]); + + // THEN + const rendered = config._render(); + const configs = rendered.promptConfigurations as any[]; + expect(configs[0].promptState).toBe('ENABLED'); + expect(configs[1].promptState).toBe('DISABLED'); + expect(configs[2].promptState).toBeUndefined(); + }); + + test('renders prompt creation modes correctly', () => { + // WHEN + const config = PromptOverrideConfiguration.fromSteps([ + { + stepType: AgentStepType.PRE_PROCESSING, + customPromptTemplate: 'custom template', + }, + { + stepType: AgentStepType.ORCHESTRATION, + customPromptTemplate: '', + }, + { + stepType: AgentStepType.POST_PROCESSING, + customPromptTemplate: undefined, + }, + ]); + + // THEN + const rendered = config._render(); + const configs = rendered.promptConfigurations as any[]; + expect(configs[0].promptCreationMode).toBe('OVERRIDDEN'); + expect(configs[1].promptCreationMode).toBe('DEFAULT'); + expect(configs[2].promptCreationMode).toBeUndefined(); + }); + + test('renders parser modes correctly', () => { + // WHEN + const config = PromptOverrideConfiguration.withCustomParser({ + parser: new lambda.Function(stack, 'TestParser', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = () => {}'), + }), + preProcessingStep: { + stepType: AgentStepType.PRE_PROCESSING, + useCustomParser: true, + } as PromptPreProcessingConfigCustomParser, + orchestrationStep: { + stepType: AgentStepType.ORCHESTRATION, + useCustomParser: false, + } as PromptOrchestrationConfigCustomParser, + postProcessingStep: { + stepType: AgentStepType.POST_PROCESSING, + useCustomParser: undefined, + } as PromptPostProcessingConfigCustomParser, + }); + + // THEN + const rendered = config._render(); + const configs = rendered.promptConfigurations as any[]; + expect(configs[0].parserMode).toBe('OVERRIDDEN'); + expect(configs[1].parserMode).toBe('DEFAULT'); + expect(configs[2].parserMode).toBeUndefined(); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/test-schema.yaml b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/test-schema.yaml new file mode 100644 index 0000000000000..4accd4cadb267 --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/test-schema.yaml @@ -0,0 +1,20 @@ +openapi: 3.0.3 +info: + title: Asset API Schema + version: 1.0.0 +paths: + /asset: + get: + operationId: assetHelloWorld + summary: Say hello from asset + description: Returns a greeting message from asset-stored schema + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + message: + type: string diff --git a/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/validation-helpers.test.ts b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/validation-helpers.test.ts new file mode 100644 index 0000000000000..51d833119364e --- /dev/null +++ b/packages/@aws-cdk/aws-bedrock-alpha/test/bedrock/agents/validation-helpers.test.ts @@ -0,0 +1,126 @@ +import { Token } from 'aws-cdk-lib'; +import { validateStringFieldLength, validateFieldPattern, throwIfInvalid } from '../../../bedrock/agents/validation-helpers'; + +describe('validation-helpers', () => { + describe('validateStringFieldLength', () => { + test('returns empty array for valid string length', () => { + const result = validateStringFieldLength({ + value: 'test', + fieldName: 'testField', + minLength: 2, + maxLength: 10, + }); + expect(result).toEqual([]); + }); + + test('returns error when string is too short', () => { + const result = validateStringFieldLength({ + value: 'a', + fieldName: 'testField', + minLength: 2, + maxLength: 10, + }); + expect(result).toHaveLength(1); + expect(result[0]).toContain('must be at least 2 characters'); + }); + + test('returns error when string is too long', () => { + const result = validateStringFieldLength({ + value: 'this is a very long string', + fieldName: 'testField', + minLength: 2, + maxLength: 10, + }); + expect(result).toHaveLength(1); + expect(result[0]).toContain('must be less than or equal to 10 characters'); + }); + + test('skips validation for unresolved tokens', () => { + const tokenValue = Token.asString({ Ref: 'SomeParameter' }); + const result = validateStringFieldLength({ + value: tokenValue, + fieldName: tokenValue, + minLength: 2, + maxLength: 10, + }); + expect(result).toEqual([]); + }); + }); + + describe('validateFieldPattern', () => { + test('returns empty array for valid pattern match', () => { + const result = validateFieldPattern( + 'test123', + 'testField', + /^[a-z0-9]+$/, + ); + expect(result).toEqual([]); + }); + + test('returns error for invalid pattern match', () => { + const result = validateFieldPattern( + 'test@123', + 'testField', + /^[a-z0-9]+$/, + ); + expect(result).toHaveLength(1); + expect(result[0]).toContain('does not match the required pattern'); + }); + + test('uses custom error message when provided', () => { + const customMessage = 'Custom validation error'; + const result = validateFieldPattern( + 'test@123', + 'testField', + /^[a-z0-9]+$/, + customMessage, + ); + expect(result).toEqual([customMessage]); + }); + + test('returns error for non-string value', () => { + const result = validateFieldPattern( + 42 as any, + 'testField', + /^[0-9]+$/, + ); + expect(result).toHaveLength(1); + expect(result[0]).toContain('Expected string'); + }); + + test('skips validation for unresolved tokens', () => { + const tokenValue = Token.asString({ Ref: 'SomeParameter' }); + const result = validateFieldPattern( + tokenValue, + 'testField', + /^[a-z0-9]+$/, + ); + expect(result).toEqual([]); + }); + }); + + describe('throwIfInvalid', () => { + test('returns parameter when validation passes', () => { + const param = { value: 'test', fieldName: 'testField', minLength: 2, maxLength: 10 }; + const result = throwIfInvalid(validateStringFieldLength, param); + expect(result).toBe(param); + }); + + test('throws error when validation fails', () => { + const param = { value: 'a', fieldName: 'testField', minLength: 2, maxLength: 10 }; + expect(() => { + throwIfInvalid(validateStringFieldLength, param); + }).toThrow('must be at least 2 characters'); + }); + + test('throws combined error messages when multiple validations fail', () => { + const validationFn = () => [ + 'Error 1', + 'Error 2', + ]; + expect(() => { + throwIfInvalid(validationFn, 'test'); + }).toThrow('Error 1\nError 2'); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index a1af86149f23e..6cc1552216ea3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -58,6 +58,12 @@ resolved "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz#6d3c7860354d4856a7e75375f2f0ecab313b4989" integrity sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A== +"@aws-cdk/aws-bedrock-alpha@file:packages/@aws-cdk/aws-bedrock-alpha": + version "0.0.0" + +"@aws-cdk/aws-lambda-python-alpha@file:packages/@aws-cdk/aws-lambda-python-alpha": + version "0.0.0" + "@aws-cdk/aws-service-spec@0.1.76": version "0.1.76" resolved "https://registry.npmjs.org/@aws-cdk/aws-service-spec/-/aws-service-spec-0.1.76.tgz#bbca16e92a824a10616b9d31a9d289a4bb741f6c" @@ -82,7 +88,7 @@ jsonschema "~1.4.1" semver "^7.7.2" -"@aws-cdk/integ-runner@^2.186.11": +"@aws-cdk/integ-runner@^2.186.0", "@aws-cdk/integ-runner@^2.186.11": version "2.186.11" resolved "https://registry.npmjs.org/@aws-cdk/integ-runner/-/integ-runner-2.186.11.tgz#1174047d4227bde08a9d411310273b63d502bce6" integrity sha512-dfp1/MZqhP2m3GLnkap/rMkLUdew5XLFNIlTkB5v+Ntdqj4OEiwmcI0diSVS2kmI5em3FOfJ70n0GE9xJatDVA== @@ -4469,7 +4475,7 @@ dependencies: tslib "^2.4.0" -"@types/aws-lambda@^8.10.149": +"@types/aws-lambda@^8.10.136", "@types/aws-lambda@^8.10.149": version "8.10.149" resolved "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.149.tgz#77c7bde809425546d03626e51bab8181bc5d24c9" integrity sha512-NXSZIhfJjnXqJgtS7IwutqIF/SOy1Wz5Px4gUY1RWITp3AYTyuJS4xaXr/bIJY1v15XMzrJ5soGnPM+7uigZjA== @@ -4681,6 +4687,13 @@ resolved "https://registry.npmjs.org/@types/node/-/node-18.11.19.tgz#35e26df9ec441ab99d73e99e9aca82935eea216d" integrity sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw== +"@types/node@22.7.9": + version "22.7.9" + resolved "https://registry.npmjs.org/@types/node/-/node-22.7.9.tgz#2bf2797b5e84702d8262ea2cf843c3c3c880d0e9" + integrity sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg== + dependencies: + undici-types "~6.19.2" + "@types/node@^16": version "16.18.126" resolved "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz#27875faa2926c0f475b39a8bb1e546c0176f8d4b" @@ -5348,6 +5361,13 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +aws-cdk@2.1007.0: + version "2.1007.0" + resolved "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1007.0.tgz#cdeca2bd3a4a628c73c9dab3ac37f29d3f63b223" + integrity sha512-/UOYOTGWUm+pP9qxg03tID5tL6euC+pb+xo0RBue+xhnUWwj/Bbsw6DbqbpOPMrNzTUxmM723/uMEQmM6S26dw== + optionalDependencies: + fsevents "2.3.2" + aws-cdk@2.1017.1: version "2.1017.1" resolved "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1017.1.tgz#3091e8f295c3fda397f3e691f5ffad8ad4be5d96" @@ -5831,6 +5851,11 @@ cdk-generate-synthetic-examples@^0.2.26: jsii-reflect "^1.112.0" yargs "^17.7.2" +cdk-nag@2.28.13: + version "2.28.13" + resolved "https://registry.npmjs.org/cdk-nag/-/cdk-nag-2.28.13.tgz#bef1b6c65496d99ef2e110f1a28f5260f9efef80" + integrity sha512-f+fteEq09+N7H2heqls0NcTC+MFcXl6fztEjjpKK0qTo5eFAKmDekEHLRGY5LX8v/JlueoVyhttsjaULNwnoSg== + cdk8s-plus-27@2.9.5: version "2.9.5" resolved "https://registry.npmjs.org/cdk8s-plus-27/-/cdk8s-plus-27-2.9.5.tgz#a2d7942a7aba001c0a07705627314d780cde7265" @@ -13713,7 +13738,7 @@ ts-api-utils@^2.1.0: resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== -ts-jest@^29, ts-jest@^29.3.4: +ts-jest@^29, ts-jest@^29.2.5, ts-jest@^29.3.4: version "29.3.4" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.3.4.tgz#9354472aceae1d3867a80e8e02014ea5901aee41" integrity sha512-Iqbrm8IXOmV+ggWHOTEbjwyCf2xZlUMv5npExksXohL+tk8va4Fjhb+X2+Rt9NBmgO7bJ8WpnMLOwih/DnMlFA== @@ -13968,6 +13993,11 @@ typescript@~5.5.0, typescript@~5.5.4: resolved "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== +typescript@~5.6.3: + version "5.6.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + typescript@~5.7: version "5.7.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e" @@ -13998,6 +14028,11 @@ undici-types@~5.26.4: resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + undici-types@~6.21.0: version "6.21.0" resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"