diff --git a/python/03-integrate/scheduling/README.md b/python/03-integrate/scheduling/README.md new file mode 100644 index 00000000..0cfa0789 --- /dev/null +++ b/python/03-integrate/scheduling/README.md @@ -0,0 +1,94 @@ +# Scheduled Agents — EventBridge Scheduler + AgentCore + +Invoke a [Strands Agents](https://github.com/strands-agents/sdk-python) agent running on [Bedrock AgentCore](https://docs.aws.amazon.com/bedrock/latest/userguide/agentcore.html) on a recurring schedule using **Amazon EventBridge Scheduler**. + +## Architecture + +``` +EventBridge Scheduler ──▶ EventBridge Bus ──▶ Rule + InputTransformer ──▶ API Destination ──▶ AgentCore Runtime + │ + Cognito OAuth + (client_credentials) +``` + +1. **EventBridge Scheduler** fires on a cron/rate expression and puts an event on a custom EventBridge bus +2. A **Rule** matches events from `scheduler.agentcore` with detail-type `ScheduledAgentInvocation` +3. An **InputTransformer** extracts `$.detail.prompt` into `{"prompt": ""}` +4. An **EventBridge Connection** acquires a Cognito OAuth token via `client_credentials` +5. An **API Destination** POSTs to the AgentCore `/invocations` endpoint with `Authorization: Bearer ` +6. **AgentCore** validates the JWT and runs the Strands agent + +> **Why the extra hop?** EventBridge Scheduler can't target API Destinations directly. +> Scheduler puts an event on a bus, then a Rule routes it to the API Destination. + +## Prerequisites + +- AWS CLI v2, SAM CLI, Docker (with buildx) +- A Bedrock AgentCore–enabled AWS account + +## Project Structure + +``` +scheduling/ +├── agent/ +│ ├── agent.py # Strands agent with get_current_time tool +│ ├── Dockerfile +│ └── requirements.txt +├── deploy.sh # Full deployment script (7 steps) +├── template.yaml # SAM template (Cognito, EventBridge bus, DLQ) +└── README.md +``` + +## Deploy + +```bash +# Defaults: rate(1 hour), us-east-1 +./deploy.sh + +# Custom schedule and region +SCHEDULE_EXPR="cron(0 9 * * ? *)" AWS_REGION=us-west-2 ./deploy.sh +``` + +The deploy script handles everything in 7 steps: +1. Creates an ECR repository +2. Builds and pushes the agent container (ARM64) +3. Creates the AgentCore execution IAM role +4. Creates the AgentCore Runtime +5. Deploys the SAM stack (Cognito + EventBridge bus + DLQ) +6. Wires up the EventBridge Connection, API Destination, and Rule +7. Creates the EventBridge Schedule + +### Environment Variables + +| Variable | Default | Description | +|---|---|---| +| `STACK_NAME` | `scheduled-agentcore` | CloudFormation stack name | +| `AGENT_NAME` | `scheduled_agentcore_agent` | AgentCore runtime name | +| `AWS_REGION` | `us-east-1` | AWS region | +| `SCHEDULE_EXPR` | `rate(1 hour)` | EventBridge schedule expression | + +## Post-Deploy + +After deployment, configure the AgentCore JWT authorizer with the Cognito values printed at the end of the deploy script output. + +## Test Manually + +```bash +aws events put-events --entries '[{ + "EventBusName": "scheduled-agentcore-bus", + "Source": "scheduler.agentcore", + "DetailType": "ScheduledAgentInvocation", + "Detail": "{\"prompt\": \"Hello from manual test!\"}" +}]' --region us-east-1 +``` + +## Cleanup + +```bash +STACK_NAME=scheduled-agentcore +REGION=us-east-1 + +aws scheduler delete-schedule --name ${STACK_NAME}-schedule --region ${REGION} +aws events delete-connection --name ${STACK_NAME}-connection --region ${REGION} +aws cloudformation delete-stack --stack-name ${STACK_NAME} --region ${REGION} +``` diff --git a/python/03-integrate/scheduling/agent/Dockerfile b/python/03-integrate/scheduling/agent/Dockerfile new file mode 100644 index 00000000..bc01d0f5 --- /dev/null +++ b/python/03-integrate/scheduling/agent/Dockerfile @@ -0,0 +1,9 @@ +FROM --platform=linux/arm64 ghcr.io/astral-sh/uv:python3.11-bookworm-slim + +WORKDIR /app +COPY requirements.txt . +RUN uv pip install --system -r requirements.txt +COPY agent.py . + +EXPOSE 8080 +CMD ["python", "agent.py"] diff --git a/python/03-integrate/scheduling/agent/agent.py b/python/03-integrate/scheduling/agent/agent.py new file mode 100644 index 00000000..19ce0419 --- /dev/null +++ b/python/03-integrate/scheduling/agent/agent.py @@ -0,0 +1,28 @@ +import json +from datetime import datetime, timezone +from strands import Agent, tool +from bedrock_agentcore.runtime import BedrockAgentCoreApp +from strands.models.bedrock import BedrockModel + +app = BedrockAgentCoreApp() +model = BedrockModel(model_id="amazon.nova-pro-v1:0") + + +@tool +def get_current_time() -> str: + """Return the current UTC timestamp.""" + return datetime.now(timezone.utc).isoformat() + + +agent = Agent(model=model, tools=[get_current_time]) + + +@app.entrypoint +def invoke(payload): + prompt = payload.get("prompt", "You were triggered by a schedule. Summarize what time it is and confirm you are running.") + result = agent(prompt) + return {"message": result.message} + + +if __name__ == "__main__": + app.run() diff --git a/python/03-integrate/scheduling/agent/requirements.txt b/python/03-integrate/scheduling/agent/requirements.txt new file mode 100644 index 00000000..2bdadd46 --- /dev/null +++ b/python/03-integrate/scheduling/agent/requirements.txt @@ -0,0 +1,2 @@ +strands-agents +bedrock-agentcore diff --git a/python/03-integrate/scheduling/deploy.sh b/python/03-integrate/scheduling/deploy.sh new file mode 100755 index 00000000..6a8d9f32 --- /dev/null +++ b/python/03-integrate/scheduling/deploy.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ── Configuration ────────────────────────────────────────────── +STACK_NAME="${STACK_NAME:-scheduled-agentcore}" +AGENT_NAME="${AGENT_NAME:-scheduled_agentcore_agent}" +REGION="${AWS_REGION:-us-east-1}" +SCHEDULE_EXPR="${SCHEDULE_EXPR:-rate(1 hour)}" +SCHEDULE_PAYLOAD="${SCHEDULE_PAYLOAD:-{\"prompt\":\"You are triggered by a schedule. Report the current time and confirm you are running.\"}}" +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +ECR_REPO="${STACK_NAME}-agent" +ECR_URI="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${ECR_REPO}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +echo "══════════════════════════════════════════════════════════" +echo " Account: ${ACCOUNT_ID}" +echo " Region: ${REGION}" +echo " Stack: ${STACK_NAME}" +echo " Schedule: ${SCHEDULE_EXPR}" +echo "══════════════════════════════════════════════════════════" + +# ── Step 1: ECR ──────────────────────────────────────────────── +echo -e "\n▶ Step 1/5: ECR repository..." +aws ecr describe-repositories --repository-names "${ECR_REPO}" --region "${REGION}" >/dev/null 2>&1 \ + || aws ecr create-repository --repository-name "${ECR_REPO}" --region "${REGION}" --output text >/dev/null + +aws ecr get-login-password --region "${REGION}" \ + | docker login --username AWS --password-stdin "${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com" 2>/dev/null + +# ── Step 2: Build & push container ───────────────────────────── +echo -e "\n▶ Step 2/5: Building agent container (ARM64)..." +docker buildx build --platform linux/arm64 \ + -t "${ECR_URI}:latest" --push "${SCRIPT_DIR}/agent" + +# ── Step 3: AgentCore execution role ─────────────────────────── +echo -e "\n▶ Step 3/5: AgentCore execution role..." +ROLE_NAME="${STACK_NAME}-AgentCoreRole" + +ROLE_ARN=$(aws iam get-role --role-name "${ROLE_NAME}" --query 'Role.Arn' --output text 2>/dev/null || echo "") +if [ -z "${ROLE_ARN}" ] || [ "${ROLE_ARN}" = "None" ]; then + ROLE_ARN=$(aws iam create-role \ + --role-name "${ROLE_NAME}" \ + --assume-role-policy-document "{ + \"Version\":\"2012-10-17\", + \"Statement\":[{ + \"Effect\":\"Allow\", + \"Principal\":{\"Service\":\"bedrock-agentcore.amazonaws.com\"}, + \"Action\":\"sts:AssumeRole\", + \"Condition\":{ + \"StringEquals\":{\"aws:SourceAccount\":\"${ACCOUNT_ID}\"}, + \"ArnLike\":{\"aws:SourceArn\":\"arn:aws:bedrock-agentcore:${REGION}:${ACCOUNT_ID}:*\"} + } + }] + }" --query 'Role.Arn' --output text) + echo " Created: ${ROLE_ARN}" +else + echo " Exists: ${ROLE_ARN}" +fi + +aws iam put-role-policy --role-name "${ROLE_NAME}" \ + --policy-name AgentCorePolicy \ + --policy-document "{ + \"Version\":\"2012-10-17\", + \"Statement\":[ + {\"Effect\":\"Allow\",\"Action\":[\"ecr:BatchGetImage\",\"ecr:GetDownloadUrlForLayer\"],\"Resource\":\"arn:aws:ecr:${REGION}:${ACCOUNT_ID}:repository/${ECR_REPO}\"}, + {\"Effect\":\"Allow\",\"Action\":\"ecr:GetAuthorizationToken\",\"Resource\":\"*\"}, + {\"Effect\":\"Allow\",\"Action\":[\"logs:CreateLogGroup\",\"logs:DescribeLogStreams\"],\"Resource\":\"arn:aws:logs:${REGION}:${ACCOUNT_ID}:log-group:/aws/bedrock-agentcore/runtimes/*\"}, + {\"Effect\":\"Allow\",\"Action\":\"logs:DescribeLogGroups\",\"Resource\":\"arn:aws:logs:${REGION}:${ACCOUNT_ID}:log-group:*\"}, + {\"Effect\":\"Allow\",\"Action\":[\"logs:CreateLogStream\",\"logs:PutLogEvents\"],\"Resource\":\"arn:aws:logs:${REGION}:${ACCOUNT_ID}:log-group:/aws/bedrock-agentcore/runtimes/*:log-stream:*\"}, + {\"Effect\":\"Allow\",\"Action\":[\"xray:PutTraceSegments\",\"xray:PutTelemetryRecords\",\"xray:GetSamplingRules\",\"xray:GetSamplingTargets\"],\"Resource\":\"*\"}, + {\"Effect\":\"Allow\",\"Action\":\"cloudwatch:PutMetricData\",\"Resource\":\"*\",\"Condition\":{\"StringEquals\":{\"cloudwatch:namespace\":\"bedrock-agentcore\"}}}, + {\"Effect\":\"Allow\",\"Action\":[\"bedrock:InvokeModel\",\"bedrock:InvokeModelWithResponseStream\"],\"Resource\":[\"arn:aws:bedrock:*::foundation-model/*\",\"arn:aws:bedrock:${REGION}:${ACCOUNT_ID}:*\"]} + ] + }" + +sleep 10 + +# ── Step 4: Create AgentCore Runtime ────────────────────────── +echo -e "\n▶ Step 4/5: AgentCore Runtime..." +AGENT_ARN="" +RUNTIMES=$(aws bedrock-agentcore-control list-agent-runtimes --region "${REGION}" --query "agentRuntimes[?agentRuntimeName=='${AGENT_NAME}'].agentRuntimeArn" --output text 2>/dev/null || echo "") +if [ -n "${RUNTIMES}" ] && [ "${RUNTIMES}" != "None" ]; then + AGENT_ARN="${RUNTIMES}" + echo " Exists: ${AGENT_ARN}" +else + AGENT_ARN=$(aws bedrock-agentcore-control create-agent-runtime \ + --agent-runtime-name "${AGENT_NAME}" \ + --agent-runtime-artifact "{\"containerConfiguration\":{\"containerUri\":\"${ECR_URI}:latest\"}}" \ + --network-configuration '{"networkMode":"PUBLIC"}' \ + --role-arn "${ROLE_ARN}" \ + --region "${REGION}" \ + --query 'agentRuntimeArn' --output text) + echo " Created: ${AGENT_ARN}" + + echo " Waiting for ACTIVE status..." + for i in $(seq 1 30); do + STATUS=$(aws bedrock-agentcore-control get-agent-runtime \ + --agent-runtime-id "${AGENT_ARN}" --region "${REGION}" \ + --query 'status' --output text 2>/dev/null || echo "CREATING") + printf " [%02d/30] %s\n" "$i" "${STATUS}" + [ "${STATUS}" = "ACTIVE" ] && break + sleep 10 + done +fi + +ENCODED_ARN=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${AGENT_ARN}', safe=''))") +AGENT_ENDPOINT="https://bedrock-agentcore.${REGION}.amazonaws.com/runtimes/${ENCODED_ARN}/invocations" + +# ── Step 5: SAM deploy (all infrastructure) ──────────────────── +echo -e "\n▶ Step 5/5: Deploying SAM stack..." +cd "${SCRIPT_DIR}" +sam build --use-container 2>/dev/null || sam build +sam deploy \ + --stack-name "${STACK_NAME}" \ + --region "${REGION}" \ + --resolve-s3 \ + --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ + --parameter-overrides \ + "ParameterKey=AgentCoreEndpoint,ParameterValue=${AGENT_ENDPOINT}" \ + "ParameterKey=AgentName,ParameterValue=${AGENT_NAME}" \ + "ParameterKey=ScheduleExpression,ParameterValue='${SCHEDULE_EXPR}'" \ + "ParameterKey=SchedulePayload,ParameterValue='${SCHEDULE_PAYLOAD}'" \ + --no-confirm-changeset + +# ── Read outputs ─────────────────────────────────────────────── +get_output() { + aws cloudformation describe-stacks --stack-name "${STACK_NAME}" --region "${REGION}" \ + --query "Stacks[0].Outputs[?OutputKey=='$1'].OutputValue" --output text +} + +POOL_ID=$(get_output CognitoUserPoolId) +CLIENT_ID=$(get_output CognitoAppClientId) +EVENT_BUS_NAME="${STACK_NAME}-bus" + +# ── Done ────────────────────────────────────────────────────── +echo "" +echo "══════════════════════════════════════════════════════════" +echo " ✅ Deployment complete!" +echo "" +echo " AgentCore ARN: ${AGENT_ARN}" +echo " Schedule: ${STACK_NAME}-schedule (${SCHEDULE_EXPR})" +echo " EventBus: ${EVENT_BUS_NAME}" +echo " Connection: ${STACK_NAME}-connection" +echo " API Dest: ${STACK_NAME}-dest" +echo "" +echo " Test manually:" +echo " aws events put-events --entries '[{" +echo " \"EventBusName\":\"${EVENT_BUS_NAME}\"," +echo " \"Source\":\"scheduler.agentcore\"," +echo " \"DetailType\":\"ScheduledAgentInvocation\"," +echo " \"Detail\":\"{\\\"prompt\\\":\\\"Hello from manual test!\\\"}\"}" +echo " }]' --region ${REGION}" +echo "" +echo " Manage schedule:" +echo " aws scheduler get-schedule --name ${STACK_NAME}-schedule --region ${REGION}" +echo " aws scheduler update-schedule --name ${STACK_NAME}-schedule --state DISABLED ... # pause" +echo "" +echo " ⚠️ Configure AgentCore JWT authorizer:" +echo " Discovery URL: https://cognito-idp.${REGION}.amazonaws.com/${POOL_ID}/.well-known/openid-configuration" +echo " Allowed Audiences: ${CLIENT_ID}" +echo " Allowed Clients: ${CLIENT_ID}" +echo " Allowed Scopes: ${AGENT_NAME}/invoke" +echo "══════════════════════════════════════════════════════════" diff --git a/python/03-integrate/scheduling/template.yaml b/python/03-integrate/scheduling/template.yaml new file mode 100644 index 00000000..49faf84f --- /dev/null +++ b/python/03-integrate/scheduling/template.yaml @@ -0,0 +1,277 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Cognito + EventBridge Scheduler -> EventBridge Bus -> API Destination -> AgentCore Runtime. + Invokes an AgentCore agent on a recurring schedule. + +Parameters: + AgentCoreEndpoint: + Type: String + Description: AgentCore Runtime invocation URL + AgentName: + Type: String + Default: scheduled_agentcore_agent + ScheduleExpression: + Type: String + Default: 'rate(1 hour)' + Description: 'Schedule expression (e.g. rate(1 hour), cron(0 9 * * ? *))' + SchedulePayload: + Type: String + Default: '{"prompt":"You are triggered by a schedule. Report the current time and confirm you are running."}' + Description: JSON payload sent to the agent on each invocation + +Resources: + # ── Cognito ────────────────────────────────────────────────── + CognitoUserPool: + Type: AWS::Cognito::UserPool + Properties: + UserPoolName: !Sub '${AWS::StackName}-pool' + + CognitoDomain: + Type: AWS::Cognito::UserPoolDomain + Properties: + Domain: !Sub '${AWS::StackName}-${AWS::AccountId}' + UserPoolId: !Ref CognitoUserPool + + CognitoResourceServer: + Type: AWS::Cognito::UserPoolResourceServer + Properties: + Identifier: !Ref AgentName + Name: !Sub '${AgentName}-api' + UserPoolId: !Ref CognitoUserPool + Scopes: + - ScopeName: invoke + ScopeDescription: Invoke the AgentCore agent + + CognitoAppClient: + Type: AWS::Cognito::UserPoolClient + DependsOn: CognitoResourceServer + Properties: + ClientName: !Sub '${AWS::StackName}-client' + UserPoolId: !Ref CognitoUserPool + GenerateSecret: true + AllowedOAuthFlows: + - client_credentials + AllowedOAuthFlowsUserPoolClient: true + AllowedOAuthScopes: + - !Sub '${AgentName}/invoke' + SupportedIdentityProviders: + - COGNITO + + # ── EventBridge Bus ────────────────────────────────────────── + AgentEventBus: + Type: AWS::Events::EventBus + Properties: + Name: !Sub '${AWS::StackName}-bus' + + # ── DLQ ────────────────────────────────────────────────────── + DeadLetterQueue: + Type: AWS::SQS::Queue + Properties: + QueueName: !Sub '${AWS::StackName}-dlq' + MessageRetentionPeriod: 1209600 + + # ── EventBridge Connection (OAuth via Cognito) ─────────────── + AgentCoreConnection: + Type: AWS::Events::Connection + Properties: + Name: !Sub '${AWS::StackName}-connection' + AuthorizationType: OAUTH_CLIENT_CREDENTIALS + AuthParameters: + OAuthParameters: + AuthorizationEndpoint: !Sub + - 'https://${Domain}.auth.${AWS::Region}.amazoncognito.com/oauth2/token' + - Domain: !Sub '${AWS::StackName}-${AWS::AccountId}' + HttpMethod: POST + ClientParameters: + ClientID: !Ref CognitoAppClient + ClientSecret: !GetAtt CognitoAppClientSecret.ClientSecret + OAuthHttpParameters: + BodyParameters: + - Key: grant_type + Value: client_credentials + IsValueSecret: false + - Key: scope + Value: !Sub '${AgentName}/invoke' + IsValueSecret: false + + # ── Lambda to retrieve Cognito client secret ───────────────── + CognitoAppClientSecret: + Type: Custom::CognitoClientSecret + Properties: + ServiceToken: !GetAtt GetClientSecretFunction.Arn + UserPoolId: !Ref CognitoUserPool + ClientId: !Ref CognitoAppClient + + GetClientSecretFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: python3.12 + Handler: index.handler + Timeout: 30 + Policies: + - Version: '2012-10-17' + Statement: + - Effect: Allow + Action: cognito-idp:DescribeUserPoolClient + Resource: !GetAtt CognitoUserPool.Arn + InlineCode: | + import boto3 + import cfnresponse + def handler(event, context): + try: + if event['RequestType'] == 'Delete': + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) + return + client = boto3.client('cognito-idp') + resp = client.describe_user_pool_client( + UserPoolId=event['ResourceProperties']['UserPoolId'], + ClientId=event['ResourceProperties']['ClientId'] + ) + cfnresponse.send(event, context, cfnresponse.SUCCESS, + {'ClientSecret': resp['UserPoolClient']['ClientSecret']}) + except Exception as e: + cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)}) + + # ── API Destination ────────────────────────────────────────── + AgentCoreApiDestination: + Type: AWS::Events::ApiDestination + Properties: + Name: !Sub '${AWS::StackName}-dest' + ConnectionArn: !GetAtt AgentCoreConnection.Arn + InvocationEndpoint: !Ref AgentCoreEndpoint + HttpMethod: POST + InvocationRateLimitPerSecond: 10 + + # ── IAM Role: EventBridge Rule -> API Destination ──────────── + EventBridgeApiDestRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${AWS::StackName}-EBApiDestRole' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: events.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: InvokeApiDest + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: events:InvokeApiDestination + Resource: !GetAtt AgentCoreApiDestination.Arn + + # ── EventBridge Rule (Bus -> API Destination) ──────────────── + AgentInvocationRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub '${AWS::StackName}-rule' + EventBusName: !Ref AgentEventBus + State: ENABLED + EventPattern: + source: + - scheduler.agentcore + detail-type: + - ScheduledAgentInvocation + Targets: + - Id: AgentCoreTarget + Arn: !GetAtt AgentCoreApiDestination.Arn + RoleArn: !GetAtt EventBridgeApiDestRole.Arn + InputTransformer: + InputPathsMap: + prompt: $.detail.prompt + InputTemplate: '{"prompt": }' + DeadLetterConfig: + Arn: !GetAtt DeadLetterQueue.Arn + + # ── DLQ Policy (allow EventBridge to send to DLQ) ──────────── + DeadLetterQueuePolicy: + Type: AWS::SQS::QueuePolicy + Properties: + Queues: + - !Ref DeadLetterQueue + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: events.amazonaws.com + Action: sqs:SendMessage + Resource: !GetAtt DeadLetterQueue.Arn + Condition: + ArnEquals: + aws:SourceArn: !GetAtt AgentInvocationRule.Arn + + # ── IAM Role: Scheduler -> PutEvents ───────────────────────── + SchedulerRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${AWS::StackName}-SchedulerRole' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: scheduler.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: SchedulerPutEvents + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: events:PutEvents + Resource: !GetAtt AgentEventBus.Arn + + # ── EventBridge Scheduler ──────────────────────────────────── + AgentSchedule: + Type: AWS::Scheduler::Schedule + Properties: + Name: !Sub '${AWS::StackName}-schedule' + ScheduleExpression: !Ref ScheduleExpression + FlexibleTimeWindow: + Mode: 'OFF' + State: ENABLED + Target: + Arn: !GetAtt AgentEventBus.Arn + RoleArn: !GetAtt SchedulerRole.Arn + EventBridgeParameters: + Source: scheduler.agentcore + DetailType: ScheduledAgentInvocation + Input: !Ref SchedulePayload + +Outputs: + EventBusName: + Value: !Ref AgentEventBus + EventBusArn: + Value: !GetAtt AgentEventBus.Arn + ConnectionName: + Value: !Sub '${AWS::StackName}-connection' + ApiDestinationName: + Value: !Sub '${AWS::StackName}-dest' + ScheduleName: + Value: !Sub '${AWS::StackName}-schedule' + CognitoUserPoolId: + Value: !Ref CognitoUserPool + CognitoAppClientId: + Value: !Ref CognitoAppClient + CognitoDomain: + Value: !Sub '${AWS::StackName}-${AWS::AccountId}' + CognitoTokenEndpoint: + Value: !Sub + - 'https://${Domain}.auth.${AWS::Region}.amazoncognito.com/oauth2/token' + - Domain: !Sub '${AWS::StackName}-${AWS::AccountId}' + CognitoOIDCDiscovery: + Description: Use as Discovery URL for AgentCore JWT authorizer + Value: !Sub 'https://cognito-idp.${AWS::Region}.amazonaws.com/${CognitoUserPool}/.well-known/openid-configuration' + AgentCoreEndpoint: + Value: !Ref AgentCoreEndpoint + AgentName: + Value: !Ref AgentName + ScheduleExpression: + Value: !Ref ScheduleExpression + DLQUrl: + Value: !Ref DeadLetterQueue