From 323f016eabc2bbef09932e6de18d11e5069ecb79 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 9 Sep 2026 14:26:41 -0700 Subject: [PATCH 01/77] Document Serverless Workers on AgentCore Runtime --- .../workers/serverless-workers/index.mdx | 30 ++++--- .../serverless-workers-agentcore.mdx | 90 +++++++++++++++++++ sidebars.js | 1 + 3 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx diff --git a/docs/encyclopedia/workers/serverless-workers/index.mdx b/docs/encyclopedia/workers/serverless-workers/index.mdx index ff394ec70a..657fb5f378 100644 --- a/docs/encyclopedia/workers/serverless-workers/index.mdx +++ b/docs/encyclopedia/workers/serverless-workers/index.mdx @@ -14,10 +14,10 @@ tags: import { CaptionedImage, ReleaseNoteHeader } from '@site/src/components'; - AWS Lambda support is in Public Preview. GCP Cloud Run support is in Pre-release, and its APIs may change in - backwards-incompatible ways. To request Cloud Run access, create a [support ticket](/cloud/support#support-ticket) or - contact your account team, and [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear - when Cloud Run reaches Public Preview. + AWS Lambda support is in Public Preview. Amazon Bedrock AgentCore Runtime and GCP Cloud Run support are in + Pre-release, and their APIs may change in backwards-incompatible ways. To request Cloud Run access, create a + [support ticket](/cloud/support#support-ticket) or contact your account team, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. This page covers the following: @@ -39,8 +39,9 @@ in response to work on a Task Queue. A Serverless Worker uses the same Temporal SDKs as a traditional long-lived Worker, and registers Workflows and Activities the same way. What differs is that Temporal manages the Worker's lifecycle rather than you running a Worker -process. How that lifecycle works depends on the compute provider: AWS Lambda runs short-lived invocations, while GCP -Cloud Run runs a pool of long-lived instances. See [Worker lifecycle](#worker-lifecycle). +process. How that lifecycle works depends on the compute provider: AWS Lambda runs short-lived invocations, Amazon +Bedrock AgentCore Runtime runs sessions with idle and maximum-lifetime limits, and GCP Cloud Run runs a pool of +long-lived instances. See [Worker lifecycle](#worker-lifecycle). Serverless Workers require [Worker Versioning](/worker-versioning). Each Serverless Worker must be associated with a [Worker Deployment Version](/worker-versioning#deployment-versions) that has a compute provider configured. @@ -69,12 +70,13 @@ Temporal impersonates to scale it. Compute providers are only needed for Serverless Workers. Traditional long-lived Workers do not require a compute provider because the Worker process lifecycle is not managed by the Temporal server. -Temporal supports two compute providers: +Temporal supports three compute providers: -| Provider | Description | -| ------------- | ----------------------------------------------------------------------------- | -| AWS Lambda | Temporal assumes an IAM role in your AWS account to invoke a Lambda function. | -| GCP Cloud Run | Temporal scales a Cloud Run [Worker Pool](https://cloud.google.com/run/docs/resource-model#worker-pools) through the Cloud Run admin API. A Worker Pool is its own Cloud Run resource type, distinct from a Service or a Job. | +| Provider | Description | +| ------------------------------ | ----------- | +| AWS Lambda | Temporal assumes an IAM role in your AWS account to invoke a Lambda function. | +| Amazon Bedrock AgentCore Runtime | Temporal assumes an IAM role in your AWS account to invoke an AgentCore Runtime endpoint. | +| GCP Cloud Run | Temporal scales a Cloud Run [Worker Pool](https://cloud.google.com/run/docs/resource-model#worker-pools) through the Cloud Run admin API. A Worker Pool is its own Cloud Run resource type, distinct from a Service or a Job. | ## How Serverless invocation works {/* #how-invocation-works */} @@ -167,6 +169,7 @@ short-lived invocations on AWS Lambda, or long-lived pool instances on GCP Cloud Refer to the lifecycle section for your compute provider: - [AWS Lambda lifecycle](/serverless-workers/aws-lambda#lifecycle) +- [Amazon Bedrock AgentCore Runtime lifecycle](/serverless-workers/agentcore#lifecycle) - [GCP Cloud Run lifecycle](/serverless-workers/cloud-run#lifecycle) ## Failure handling {/* #failure-handling */} @@ -207,9 +210,9 @@ With single-slot configuration, each Activity gets a dedicated execution environ | Constraint | Detail | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Activity duration | Depends on the compute provider. On AWS Lambda, an Activity must finish within the invocation limit (15 minutes maximum), minus the shutdown deadline buffer. On GCP Cloud Run, instances are long-lived, so no per-invocation limit applies. See [Worker lifecycle](#worker-lifecycle). | +| Activity duration | Depends on the compute provider. On AWS Lambda, an Activity must finish within the invocation limit (15 minutes maximum), minus the shutdown deadline buffer. On Amazon Bedrock AgentCore Runtime, a microVM session has a maximum lifetime of 8 hours. On GCP Cloud Run, instances are long-lived, so no per-invocation limit applies. See [Worker lifecycle](#worker-lifecycle). | | Workflow duration | No limit. Workflows of any duration work. A Workflow runs across as many Workers as needed. | -| Worker code | Same Temporal SDK Worker code, using the serverless Worker package for your SDK. | +| Worker code | Depends on the compute provider. AWS Lambda uses a serverless Worker package for your SDK. Amazon Bedrock AgentCore Runtime and GCP Cloud Run run standard long-lived Temporal Workers inside provider-specific runtime infrastructure. | | Versioning | [Worker Versioning](/worker-versioning) is required. Each Workflow must have an `AutoUpgrade` or `Pinned` behavior, set per-Workflow or as a Worker-level default. See [Worker Versioning](/worker-versioning) for rollout strategies such as ramping, and [Worker Versioning with Serverless Workers](#worker-versioning-with-serverless-workers) for how Worker Deployment Versions map to compute provider primitives. | | High Availability | On failover of a Namespace with [Multi-region or Multi-cloud Replication](/cloud/high-availability), the WCI keeps invoking Workers in the original region unless you manually repoint the compute provider. Compute provider configuration, such as a Lambda ARN or a Cloud Run Worker Pool, is scoped to a single region. See [Serverless Workers and High Availability](/cloud/high-availability#serverless-workers). | @@ -221,4 +224,5 @@ How Worker Deployment Versions map to compute provider primitives differs by pro Refer to the versioning section for your compute provider: - [AWS Lambda versioning](/serverless-workers/aws-lambda#worker-versioning) +- [Amazon Bedrock AgentCore Runtime versioning](/serverless-workers/agentcore#worker-versioning) - [GCP Cloud Run versioning](/serverless-workers/cloud-run#worker-versioning) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx new file mode 100644 index 0000000000..5d7abb99e2 --- /dev/null +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -0,0 +1,90 @@ +--- +id: serverless-workers-agentcore +title: Serverless Workers on Amazon Bedrock AgentCore Runtime +sidebar_label: Amazon Bedrock AgentCore +description: + How Serverless Workers run on Amazon Bedrock AgentCore Runtime, including Worker Versioning and Runtime session + lifecycle. +slug: /serverless-workers/agentcore +toc_max_heading_level: 4 +tags: + - Workers + - Concepts + - Serverless + - Amazon Bedrock AgentCore +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. + + +This page covers how Serverless Workers run on Amazon Bedrock AgentCore Runtime, including Worker Versioning and the +Runtime session lifecycle. + +On AgentCore Runtime, a Serverless Worker is a standard long-running Temporal Worker that runs inside an AgentCore +Runtime session. When the [Worker Controller Instance (WCI)](/serverless-workers#worker-controller-instance) needs +capacity, it invokes an AgentCore Runtime endpoint. The Runtime starts a Worker, which connects to the Temporal Service +and polls its Task Queue. + +AgentCore Runtime uses the same event-driven autoscaling model as AWS Lambda. The WCI invokes individual Runtime +sessions when it needs more capacity; it does not manage a target-sized pool of Runtime sessions. + +## Worker Versioning {/* #worker-versioning */} + +Serverless Workers require [Worker Versioning](/worker-versioning). Associate each Worker Deployment Version with a +named AgentCore Runtime endpoint that points to one AgentCore Runtime version. + +AgentCore creates an immutable Runtime version when you create or update a Runtime. A named endpoint has a stable ARN +and points to a chosen Runtime version. Configure the endpoint ARN as the compute provider for the corresponding Worker +Deployment Version: + +```bash +temporal worker deployment create-version \ + --deployment-name my-worker \ + --build-id v1 \ + --aws-agentcore-endpoint-arn \ + --aws-agentcore-assume-role-arn \ + --aws-agentcore-assume-role-external-id +``` + +Use one named endpoint for each Worker Deployment Version. For example, point an endpoint named `temporal-v1` at +AgentCore Runtime version `1` and use its ARN for Temporal Worker Deployment Version `my-worker/v1`. + +When you deploy new Worker code, AgentCore creates a new Runtime version. Create another endpoint that points to that +new Runtime version and configure it on a new Worker Deployment Version. Keep the older endpoint while Pinned +Workflows can still need the older Worker code. + +:::caution + +Do not configure a live Worker Deployment Version with AgentCore's `DEFAULT` endpoint. That endpoint moves to the +latest Runtime version whenever you update the Runtime. Updating code behind a Worker Deployment Version can cause +non-determinism errors for in-flight Workflows, including Pinned Workflows. + +::: + +For details about AgentCore Runtime versions and endpoints, see [AgentCore Runtime versioning and +endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-runtime-versioning.html). + +## Lifecycle {/* #lifecycle */} + +The Runtime session provides the compute that hosts a Worker. It is not the durable identity of a Workflow, and Temporal +can route a later Workflow or Activity Task to another Worker. + +Unlike an AWS Lambda Worker, an AgentCore Worker does not run within a fixed Lambda invocation deadline. Your Runtime +handler starts the Worker as background work, and the Worker continues polling until it drains or AgentCore terminates +the Runtime session. + +AgentCore applies lifecycle settings to each microVM Runtime session: + +- **Idle Runtime session timeout**: Ends an idle session. The default is 15 minutes. +- **Maximum lifetime**: Ends a microVM session after a fixed lifetime. The default and maximum is 8 hours. + +Set the Worker’s own idle and graceful-shutdown policy so it stops polling and drains in-flight Tasks before its Runtime +session is no longer needed. The AgentCore maximum lifetime remains a hard termination boundary. Configure Activity +timeouts and, for long-running Activities, [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) +so a retry can recover after a Worker is interrupted. + +For the lifecycle setting ranges and defaults, see [Configure Amazon Bedrock AgentCore lifecycle +settings](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-lifecycle-settings.html). diff --git a/sidebars.js b/sidebars.js index ba42163641..a939fb2209 100644 --- a/sidebars.js +++ b/sidebars.js @@ -2014,6 +2014,7 @@ module.exports = { link: { type: 'doc', id: 'encyclopedia/workers/serverless-workers/serverless-workers' }, items: [ 'encyclopedia/workers/serverless-workers/serverless-workers-aws-lambda', + 'encyclopedia/workers/serverless-workers/serverless-workers-agentcore', 'encyclopedia/workers/serverless-workers/serverless-workers-cloud-run', ], }, From c5f26a7c7bef9f0cdfaeb43f912b30d1794ec467 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 9 Sep 2026 14:31:23 -0700 Subject: [PATCH 02/77] Clarify AgentCore Runtime session lifecycle --- .../serverless-workers/serverless-workers-agentcore.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 5d7abb99e2..1bf519fd50 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -69,8 +69,9 @@ endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-r ## Lifecycle {/* #lifecycle */} -The Runtime session provides the compute that hosts a Worker. It is not the durable identity of a Workflow, and Temporal -can route a later Workflow or Activity Task to another Worker. +An AgentCore Runtime session is only the compute that runs a Worker. It can end because of its idle timeout or maximum +lifetime. A later Task for the same Workflow can run on another Worker in another Runtime session. Keep state that the +Workflow needs in the Workflow or another durable store, not only in the Runtime session. Unlike an AWS Lambda Worker, an AgentCore Worker does not run within a fixed Lambda invocation deadline. Your Runtime handler starts the Worker as background work, and the Worker continues polling until it drains or AgentCore terminates From e8933a8455226d8233932cf4db1fea8c6b1d1c20 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 9 Sep 2026 14:41:39 -0700 Subject: [PATCH 03/77] Explain AgentCore Worker idle shutdown --- .../serverless-workers-agentcore.mdx | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 1bf519fd50..52b1e8ca21 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -69,23 +69,29 @@ endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-r ## Lifecycle {/* #lifecycle */} -An AgentCore Runtime session is only the compute that runs a Worker. It can end because of its idle timeout or maximum -lifetime. A later Task for the same Workflow can run on another Worker in another Runtime session. Keep state that the -Workflow needs in the Workflow or another durable store, not only in the Runtime session. +An AgentCore Runtime session is the compute that runs a Worker, not a durable place to store Workflow state. AgentCore +can resume a session on new compute after the previous compute ends, and a later Task can run on another Worker. Keep +state that a Workflow needs in the Workflow or another durable store. -Unlike an AWS Lambda Worker, an AgentCore Worker does not run within a fixed Lambda invocation deadline. Your Runtime -handler starts the Worker as background work, and the Worker continues polling until it drains or AgentCore terminates -the Runtime session. +Unlike an AWS Lambda Worker, an AgentCore Worker does not have a fixed Lambda invocation deadline. Your Runtime handler +starts the Worker as background work. The Worker polls until it drains or AgentCore ends its compute. -AgentCore applies lifecycle settings to each microVM Runtime session: +AgentCore has two lifecycle settings: -- **Idle Runtime session timeout**: Ends an idle session. The default is 15 minutes. -- **Maximum lifetime**: Ends a microVM session after a fixed lifetime. The default and maximum is 8 hours. +- **Idle Runtime session timeout**: Ends a Runtime session after it has not received an AgentCore Runtime invocation for + the configured duration. The default is 15 minutes. This is not a Temporal Worker idle timer: polling the Temporal + Service does not reset it. +- **Maximum lifetime**: Ends the compute running a Runtime session after the configured duration. The default and + maximum is 8 hours. AgentCore can resume the session on new compute after that. -Set the Worker’s own idle and graceful-shutdown policy so it stops polling and drains in-flight Tasks before its Runtime -session is no longer needed. The AgentCore maximum lifetime remains a hard termination boundary. Configure Activity -timeouts and, for long-running Activities, [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) -so a retry can recover after a Worker is interrupted. +Implement a separate idle policy in the Worker to release capacity before either AgentCore limit. The AgentCore Runtime +sample starts a Worker on invocation, then waits for 60 seconds with no Activity starting or completing. It stops +polling, allows up to two minutes for in-flight Activities to complete, and then returns from the Runtime handler. +Choose values that fit your workload, and keep them within the AgentCore maximum lifetime. + +Configure Activity timeouts and, for long-running Activities, +[Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) so a retry can recover if AgentCore +ends the compute before an Activity completes. For the lifecycle setting ranges and defaults, see [Configure Amazon Bedrock AgentCore lifecycle settings](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-lifecycle-settings.html). From ae4df10671232aa3da034d9723f94cf1f7e105e5 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 9 Sep 2026 14:45:05 -0700 Subject: [PATCH 04/77] Lead AgentCore lifecycle with Worker shutdown policy --- .../serverless-workers-agentcore.mdx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 52b1e8ca21..5ed2702157 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -76,7 +76,13 @@ state that a Workflow needs in the Workflow or another durable store. Unlike an AWS Lambda Worker, an AgentCore Worker does not have a fixed Lambda invocation deadline. Your Runtime handler starts the Worker as background work. The Worker polls until it drains or AgentCore ends its compute. -AgentCore has two lifecycle settings: +Two sets of controls determine when that Worker stops: + +- **Worker idle and graceful-shutdown policy**: Your Worker implementation decides when it has been idle, stops + polling, and waits for in-flight Activities to complete. +- **AgentCore lifecycle settings**: AgentCore can end the session or its compute before the Worker policy does. + +The AgentCore lifecycle settings are: - **Idle Runtime session timeout**: Ends a Runtime session after it has not received an AgentCore Runtime invocation for the configured duration. The default is 15 minutes. This is not a Temporal Worker idle timer: polling the Temporal @@ -84,10 +90,10 @@ AgentCore has two lifecycle settings: - **Maximum lifetime**: Ends the compute running a Runtime session after the configured duration. The default and maximum is 8 hours. AgentCore can resume the session on new compute after that. -Implement a separate idle policy in the Worker to release capacity before either AgentCore limit. The AgentCore Runtime -sample starts a Worker on invocation, then waits for 60 seconds with no Activity starting or completing. It stops -polling, allows up to two minutes for in-flight Activities to complete, and then returns from the Runtime handler. -Choose values that fit your workload, and keep them within the AgentCore maximum lifetime. +Implement the Worker idle policy to release capacity before either AgentCore limit. The AgentCore Runtime sample starts +a Worker on invocation, then waits for 60 seconds with no Activity starting or completing. It stops polling, allows up +to two minutes for in-flight Activities to complete, and then returns from the Runtime handler. Choose values that fit +your workload, and keep them within the AgentCore maximum lifetime. Configure Activity timeouts and, for long-running Activities, [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) so a retry can recover if AgentCore From 159c66fec058c6bbacd5ae5756165bdd862410bd Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 9 Sep 2026 14:46:30 -0700 Subject: [PATCH 05/77] Clarify AgentCore idle policy guidance --- .../serverless-workers/serverless-workers-agentcore.mdx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 5ed2702157..c1d43968ab 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -90,10 +90,11 @@ The AgentCore lifecycle settings are: - **Maximum lifetime**: Ends the compute running a Runtime session after the configured duration. The default and maximum is 8 hours. AgentCore can resume the session on new compute after that. -Implement the Worker idle policy to release capacity before either AgentCore limit. The AgentCore Runtime sample starts -a Worker on invocation, then waits for 60 seconds with no Activity starting or completing. It stops polling, allows up -to two minutes for in-flight Activities to complete, and then returns from the Runtime handler. Choose values that fit -your workload, and keep them within the AgentCore maximum lifetime. +The Worker can use an idle policy based on Temporal work rather than on AgentCore Runtime invocations. The AgentCore +Runtime sample starts a Worker on invocation, then waits for 60 seconds with no Activity starting or completing. It +stops polling, allows up to two minutes for in-flight Activities to complete, and then returns from the Runtime handler. +This is the sample's policy, not a required setting. Choose values that fit your workload and account for the AgentCore +maximum lifetime. Configure Activity timeouts and, for long-running Activities, [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) so a retry can recover if AgentCore From 8ab5cf93647aca5417587822eddf9ca346538192 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 9 Sep 2026 14:47:08 -0700 Subject: [PATCH 06/77] Document AgentCore Worker shutdown policy --- .../serverless-workers/serverless-workers-agentcore.mdx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index c1d43968ab..197d2db711 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -90,11 +90,10 @@ The AgentCore lifecycle settings are: - **Maximum lifetime**: Ends the compute running a Runtime session after the configured duration. The default and maximum is 8 hours. AgentCore can resume the session on new compute after that. -The Worker can use an idle policy based on Temporal work rather than on AgentCore Runtime invocations. The AgentCore -Runtime sample starts a Worker on invocation, then waits for 60 seconds with no Activity starting or completing. It -stops polling, allows up to two minutes for in-flight Activities to complete, and then returns from the Runtime handler. -This is the sample's policy, not a required setting. Choose values that fit your workload and account for the AgentCore -maximum lifetime. +AgentCore's session idle timeout does not replace a Worker idle policy. It resets with AgentCore Runtime invocations +and does not measure Task Queue activity. To control how long an unused Worker polls, implement a separate shutdown +policy: when its idle condition is met, stop polling and drain in-flight Activities before the Runtime handler returns. +Choose the idle period and drain timeout for your workload, and account for the AgentCore maximum lifetime. Configure Activity timeouts and, for long-running Activities, [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) so a retry can recover if AgentCore From 573b08df2557923755011d8c3a3863009d206fb6 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 9 Sep 2026 14:49:41 -0700 Subject: [PATCH 07/77] Share Serverless Worker autoscaling guidance --- .../workers/serverless-workers/aws-lambda.mdx | 36 ++++++++++++------- .../serverless-workers-agentcore.mdx | 5 ++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx b/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx index 4547762d57..fca5bec7c3 100644 --- a/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx +++ b/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx @@ -24,26 +24,38 @@ For a step-by-step deployment guide, see [Deploy a Serverless Worker on AWS Lamb ## Autoscaling {/* #autoscaling */} -The Lambda autoscaling algorithm is event-driven and reactive. +The autoscaling algorithm in this section applies to Serverless Workers on AWS Lambda and Amazon Bedrock AgentCore +Runtime. The compute providers have different Worker lifecycles after a scale-out action. For AgentCore Runtime +lifecycle details, see [Serverless Workers on Amazon Bedrock AgentCore Runtime](/serverless-workers/agentcore#lifecycle). + +The autoscaling algorithm is event-driven and reactive. Sync match failure is the primary control signal, and backlog aids sizing. -When the [WCI](/serverless-workers#worker-controller-instance) needs more capacity, it calls the Lambda `InvokeFunction` API to start new Workers. -Each call is a discrete action ("invoke N more functions"), not a target state. -Temporal calls that API from outside your network, so no inbound connection to the function is needed. -The WCI does not manage a fleet of instances. +When the [WCI](/serverless-workers#worker-controller-instance) needs more capacity, it invokes the compute provider to +start new Workers: the Lambda `InvokeFunction` API for Lambda or an AgentCore Runtime endpoint for AgentCore Runtime. +Each call is a discrete action ("start N more Workers"), not a target state. Temporal calls the provider API from +outside your network, so no inbound connection to the Worker is needed. The WCI does not manage a fleet of instances. ### Scale-out {/* #scale-out */} -On sync match failure, the WCI invokes new Lambda functions. -Because Lambda cold start is sub-second to low single-digit seconds, reactive-only control does not create meaningful backlog overshoot. -The WCI can scale from zero with low latency. +On sync match failure, the WCI starts new Workers through the compute provider API. + +For Lambda, cold start is sub-second to low single-digit seconds, so reactive-only control does not create meaningful +backlog overshoot. The WCI can scale from zero with low latency. + +For AgentCore Runtime startup and session behavior, see +[Lifecycle](/serverless-workers/agentcore#lifecycle). ### Scale-in {/* #scale-in */} -Scale-in is automatic. -Each Lambda invocation runs until the Worker has finished processing available Tasks or approaches the 15-minute execution time limit, then shuts down. -There is no drain logic or stabilization window. -The WCI does not need to actively remove capacity. +The WCI does not maintain a target number of Workers or actively remove capacity. The provider and Worker lifecycle +determine when a Worker stops. + +On Lambda, each invocation runs until the Worker has finished processing available Tasks or approaches the 15-minute +execution time limit, then shuts down. There is no drain logic or stabilization window. + +On AgentCore Runtime, Worker shutdown and AgentCore session lifecycle settings determine when a Worker stops. See +[Lifecycle](/serverless-workers/agentcore#lifecycle). ### Instance model {/* #instance-model */} diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 197d2db711..5414e3a149 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -28,8 +28,11 @@ Runtime session. When the [Worker Controller Instance (WCI)](/serverless-workers capacity, it invokes an AgentCore Runtime endpoint. The Runtime starts a Worker, which connects to the Temporal Service and polls its Task Queue. +## Autoscaling {/* #autoscaling */} + AgentCore Runtime uses the same event-driven autoscaling model as AWS Lambda. The WCI invokes individual Runtime -sessions when it needs more capacity; it does not manage a target-sized pool of Runtime sessions. +sessions when it needs more capacity; it does not manage a target-sized pool of Runtime sessions. For the shared +autoscaling behavior, see [Autoscaling for Serverless Workers on AWS Lambda](/serverless-workers/aws-lambda#autoscaling). ## Worker Versioning {/* #worker-versioning */} From 0c051e26348fb347365af11612b3b991ec7db752 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 09:58:04 -0700 Subject: [PATCH 08/77] Add Python AgentCore Serverless Worker guide --- .../workers/serverless-workers/agentcore.mdx | 156 ++++++++++++++++++ .../workers/serverless-workers/index.mdx | 9 +- sidebars.js | 1 + 3 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 docs/develop/python/workers/serverless-workers/agentcore.mdx diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx new file mode 100644 index 0000000000..052ab68557 --- /dev/null +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -0,0 +1,156 @@ +--- +id: agentcore +title: Serverless Workers on Amazon Bedrock AgentCore Runtime - Python SDK +sidebar_label: Amazon Bedrock AgentCore +description: Run a Temporal Worker on Amazon Bedrock AgentCore Runtime using the Python SDK. +slug: /develop/python/workers/serverless-workers/agentcore +toc_max_heading_level: 4 +tags: + - Workers + - Python SDK + - Serverless + - Amazon Bedrock AgentCore +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. + + +On Amazon Bedrock AgentCore Runtime, you run a standard long-lived Python Worker inside an AgentCore Runtime handler. +Temporal starts the handler when the Worker Controller Instance needs capacity. The handler starts a Worker that polls +the Task Queue, then stops it when your idle policy decides to release capacity. + +The Worker uses the normal Python SDK. The handler uses the `bedrock-agentcore` package to receive AgentCore Runtime +invocations. + +For the provider behavior, including autoscaling, Worker Versioning, and the Runtime session lifecycle, see +[Serverless Workers on Amazon Bedrock AgentCore Runtime](/serverless-workers/agentcore). + +## Install the AgentCore Runtime SDK {/* #install-agentcore-runtime-sdk */} + +Install the AgentCore Runtime SDK alongside the Temporal Python SDK: + +```bash +pip install bedrock-agentcore +``` + +## Create a versioned Worker {/* #versioned-worker */} + +Serverless Workers require [Worker Versioning](/worker-versioning). Create the Worker as you would any long-lived +Python Worker, then set `deployment_config` to declare its Worker Deployment Version and enable versioning: + +```python +import os + +from temporalio.client import Client +from temporalio.common import VersioningBehavior, WorkerDeploymentVersion +from temporalio.worker import Worker, WorkerDeploymentConfig + +from my_activities import my_activity +from my_workflows import MyWorkflow + + +def create_worker(client: Client) -> Worker: + return Worker( + client, + task_queue=os.environ["TEMPORAL_TASK_QUEUE"], + workflows=[MyWorkflow], + activities=[my_activity], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=os.environ["TEMPORAL_DEPLOYMENT_NAME"], + build_id=os.environ["TEMPORAL_BUILD_ID"], + ), + use_worker_versioning=True, + default_versioning_behavior=VersioningBehavior.PINNED, + ), + ) +``` + +`TEMPORAL_DEPLOYMENT_NAME` and `TEMPORAL_BUILD_ID` must match the Worker Deployment Version that you create with +`temporal worker deployment create-version`. Configure that Worker Deployment Version with the AgentCore Runtime +endpoint that Temporal invokes. For the endpoint configuration, see +[Worker Versioning](/serverless-workers/agentcore#worker-versioning). + +Every Workflow needs a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or +`AUTO_UPGRADE`. Setting `default_versioning_behavior` as shown applies `PINNED` behavior to every Workflow on the +Worker. To set the behavior per Workflow instead, pass `versioning_behavior` to the `@workflow.defn` decorator. + +## Start the Worker from the Runtime handler {/* #runtime-handler */} + +AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler, and use `async_task` so +AgentCore keeps the Runtime active while the Worker polls. The following is a handler pattern; its idle policy is +application-specific: + +```python +from bedrock_agentcore.runtime import BedrockAgentCoreApp +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + +app = BedrockAgentCoreApp() + + +@app.entrypoint +@app.async_task +async def invoke(_: dict) -> dict: + client = await Client.connect(**ClientConfig.load_client_connect_config()) + worker = create_worker(client) + + async with worker: + # Implement how your application decides that this Worker is idle. + await wait_until_idle() + + return {"message": "Worker drained"} +``` + +The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker +capacity. Applications start Workflows through the Temporal Client, as usual. + +`wait_until_idle()` represents the idle policy that you define for the Worker. See +[Stop and drain the Worker](#stop-and-drain-the-worker). + +## Configure the Temporal connection {/* #configure-connection */} + +The `temporalio.envconfig` package loads [Temporal Client](/develop/python/client/temporal-client) configuration from +environment variables and an optional TOML configuration file. Set the Temporal address, Namespace, Task Queue, and +Worker Deployment Version values as Runtime environment variables. Store a Temporal Cloud API key or TLS material in a +secret store rather than in the Runtime definition. + +For the supported connection variables, config-file format, and profiles, see +[Environment configuration](/develop/environment-configuration). + +## Stop and drain the Worker {/* #stop-and-drain-the-worker */} + +An AgentCore Runtime invocation is not a measure of Task Queue idleness. Add an idle policy that decides when the +Worker should stop polling. When that condition is met, leave the `async with worker` block. The Python SDK stops +polling and waits for in-flight Activities to finish before the handler returns. + +Set `graceful_shutdown_timeout` on `Worker()` to limit how long the Worker waits for in-flight Activities. Choose an +idle period and shutdown timeout that fit the workload, and account for AgentCore's maximum Runtime lifetime. For the +AgentCore lifecycle settings, see [Lifecycle](/serverless-workers/agentcore#lifecycle). + +## Keep Activities safe across Worker termination {/* #activity-recovery */} + +AgentCore can end the compute that runs a Worker. An Activity running at that time can be interrupted and retried. +Use [Activity Heartbeats](/develop/python/activities/timeouts#activity-heartbeats) so a retry resumes from its last +recorded progress instead of starting over: + +```python +from temporalio import activity + + +@activity.defn +async def my_activity(items: list[str]) -> str: + for i, item in enumerate(items): + activity.heartbeat(i) + # ... process item + return "done" +``` + +## Add observability {/* #add-observability */} + +An AgentCore Runtime Worker emits the same traces and metrics as a Worker on other compute. For metrics export and +OpenTelemetry tracing interceptors, see [Observability - Python SDK](/develop/python/platform/observability) and the +[SDK metrics reference](/references/sdk-metrics). diff --git a/docs/develop/python/workers/serverless-workers/index.mdx b/docs/develop/python/workers/serverless-workers/index.mdx index 6a1299e5cc..c0d1d55f52 100644 --- a/docs/develop/python/workers/serverless-workers/index.mdx +++ b/docs/develop/python/workers/serverless-workers/index.mdx @@ -14,10 +14,10 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - AWS Lambda support is in Public Preview. GCP Cloud Run support is in Pre-release, and its APIs may change in - backwards-incompatible ways. To request Cloud Run access, create a [support ticket](/cloud/support#support-ticket) or - contact your account team, and [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear - when Cloud Run reaches Public Preview. + AWS Lambda support is in Public Preview. Amazon Bedrock AgentCore Runtime and GCP Cloud Run support are in + Pre-release, and their APIs may change in backwards-incompatible ways. To request Cloud Run access, create a + [support ticket](/cloud/support#support-ticket) or contact your account team, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. Serverless Workers run on ephemeral, on-demand compute rather than long-lived processes. @@ -29,4 +29,5 @@ For the end-to-end deployment guide, see [Deploy a Serverless Worker](/productio ## Supported providers - [**AWS Lambda**](/develop/python/workers/serverless-workers/aws-lambda) - Use the `lambda_worker` contrib package to run a Worker as a Lambda function. Covers setup, configuration, Lambda-tuned defaults, and observability. +- [**Amazon Bedrock AgentCore Runtime**](/develop/python/workers/serverless-workers/agentcore) - Run a standard Worker from an AgentCore Runtime handler. Covers the handler, Worker Versioning, connection configuration, and Worker shutdown. - [**GCP Cloud Run**](/develop/python/workers/serverless-workers/cloud-run) - Run a standard Worker on a Cloud Run worker pool. Covers the versioned Worker setup, connection configuration, and handling scale-in. diff --git a/sidebars.js b/sidebars.js index a939fb2209..35f2165256 100644 --- a/sidebars.js +++ b/sidebars.js @@ -638,6 +638,7 @@ const developPythonCategory = { }, items: [ 'develop/python/workers/serverless-workers/aws-lambda', + 'develop/python/workers/serverless-workers/agentcore', 'develop/python/workers/serverless-workers/cloud-run', ], }, From 3a4455c8cad856301af89b0415f160544fdb4da0 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 11:22:49 -0700 Subject: [PATCH 09/77] Add AgentCore Worker idle policy example --- .../workers/serverless-workers/agentcore.mdx | 83 +++++++++++++++---- 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 052ab68557..467d9170cd 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -12,7 +12,7 @@ tags: - Amazon Bedrock AgentCore --- -import { ReleaseNoteHeader } from '@site/src/components'; +import { ReleaseNoteHeader } from '@site/src/components' Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. @@ -42,22 +42,70 @@ Serverless Workers require [Worker Versioning](/worker-versioning). Create the W Python Worker, then set `deployment_config` to declare its Worker Deployment Version and enable versioning: ```python +import asyncio import os +from datetime import timedelta from temporalio.client import Client from temporalio.common import VersioningBehavior, WorkerDeploymentVersion -from temporalio.worker import Worker, WorkerDeploymentConfig +from temporalio.worker import ( + ActivityInboundInterceptor, + ExecuteActivityInput, + Interceptor, + Worker, + WorkerDeploymentConfig, +) from my_activities import my_activity from my_workflows import MyWorkflow +DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) +DRAIN = timedelta(seconds=120) -def create_worker(client: Client) -> Worker: + +class ActivityTracker(Interceptor): + def __init__(self) -> None: + self.inflight = 0 + self.changed = asyncio.Event() + + def intercept_activity( + self, next: ActivityInboundInterceptor + ) -> ActivityInboundInterceptor: + return TrackedActivity(next, self) + + async def wait_until_idle(self, debounce: float) -> None: + while True: + self.changed.clear() + try: + await asyncio.wait_for(self.changed.wait(), timeout=debounce) + except asyncio.TimeoutError: + if self.inflight == 0: + return + + +class TrackedActivity(ActivityInboundInterceptor): + def __init__(self, next: ActivityInboundInterceptor, tracker: ActivityTracker): + super().__init__(next) + self.tracker = tracker + + async def execute_activity(self, input: ExecuteActivityInput): + self.tracker.inflight += 1 + self.tracker.changed.set() + try: + return await self.next.execute_activity(input) + finally: + self.tracker.inflight -= 1 + self.tracker.changed.set() + + +def create_worker(client: Client, tracker: ActivityTracker) -> Worker: return Worker( client, task_queue=os.environ["TEMPORAL_TASK_QUEUE"], workflows=[MyWorkflow], activities=[my_activity], + interceptors=[tracker], + graceful_shutdown_timeout=DRAIN, deployment_config=WorkerDeploymentConfig( version=WorkerDeploymentVersion( deployment_name=os.environ["TEMPORAL_DEPLOYMENT_NAME"], @@ -81,8 +129,7 @@ Worker. To set the behavior per Workflow instead, pass `versioning_behavior` to ## Start the Worker from the Runtime handler {/* #runtime-handler */} AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler, and use `async_task` so -AgentCore keeps the Runtime active while the Worker polls. The following is a handler pattern; its idle policy is -application-specific: +AgentCore keeps the Runtime active while the Worker polls: ```python from bedrock_agentcore.runtime import BedrockAgentCoreApp @@ -96,11 +143,11 @@ app = BedrockAgentCoreApp() @app.async_task async def invoke(_: dict) -> dict: client = await Client.connect(**ClientConfig.load_client_connect_config()) - worker = create_worker(client) + tracker = ActivityTracker() + worker = create_worker(client, tracker) async with worker: - # Implement how your application decides that this Worker is idle. - await wait_until_idle() + await tracker.wait_until_idle(DEBOUNCE) return {"message": "Worker drained"} ``` @@ -108,9 +155,6 @@ async def invoke(_: dict) -> dict: The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker capacity. Applications start Workflows through the Temporal Client, as usual. -`wait_until_idle()` represents the idle policy that you define for the Worker. See -[Stop and drain the Worker](#stop-and-drain-the-worker). - ## Configure the Temporal connection {/* #configure-connection */} The `temporalio.envconfig` package loads [Temporal Client](/develop/python/client/temporal-client) configuration from @@ -123,13 +167,18 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} -An AgentCore Runtime invocation is not a measure of Task Queue idleness. Add an idle policy that decides when the -Worker should stop polling. When that condition is met, leave the `async with worker` block. The Python SDK stops -polling and waits for in-flight Activities to finish before the handler returns. +The example uses `ActivityTracker` as its idle policy. It starts a 60-second timer when no Activity is running. Starting +or completing an Activity resets the timer. When the timer expires, the Worker leaves the `async with` block, stops +polling, and waits up to two minutes for in-flight Activities to complete. + +This policy is appropriate when Activities represent the work that should keep the Worker available. For example, the +AgentCore sample runs model and tool calls as Activities. It is not a universal definition of idleness. If your Worker +has a different signal for useful work, use that signal instead. -Set `graceful_shutdown_timeout` on `Worker()` to limit how long the Worker waits for in-flight Activities. Choose an -idle period and shutdown timeout that fit the workload, and account for AgentCore's maximum Runtime lifetime. For the -AgentCore lifecycle settings, see [Lifecycle](/serverless-workers/agentcore#lifecycle). +`AGENTCORE_DEBOUNCE_SECONDS` controls the idle period. `graceful_shutdown_timeout` controls how long the Worker waits +for in-flight Activities after it stops polling. Choose both values for your workload, and account for AgentCore's +maximum Runtime lifetime. For the AgentCore lifecycle settings, see +[Lifecycle](/serverless-workers/agentcore#lifecycle). ## Keep Activities safe across Worker termination {/* #activity-recovery */} From 13fcfd41fa906087870251742ff43dc55971ae74 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 11:48:57 -0700 Subject: [PATCH 10/77] Use periods in AgentCore prose --- .../workers/serverless-workers/serverless-workers-agentcore.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 5414e3a149..9fd3328801 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -31,7 +31,7 @@ and polls its Task Queue. ## Autoscaling {/* #autoscaling */} AgentCore Runtime uses the same event-driven autoscaling model as AWS Lambda. The WCI invokes individual Runtime -sessions when it needs more capacity; it does not manage a target-sized pool of Runtime sessions. For the shared +sessions when it needs more capacity. It does not manage a target-sized pool of Runtime sessions. For the shared autoscaling behavior, see [Autoscaling for Serverless Workers on AWS Lambda](/serverless-workers/aws-lambda#autoscaling). ## Worker Versioning {/* #worker-versioning */} From 0817f1688acca8187cdd7f6497738c24cc369ad5 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:04:23 -0700 Subject: [PATCH 11/77] Make AgentCore idle policy self-contained --- .../workers/serverless-workers/agentcore.mdx | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 467d9170cd..6cf649d180 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -167,13 +167,27 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} -The example uses `ActivityTracker` as its idle policy. It starts a 60-second timer when no Activity is running. Starting -or completing an Activity resets the timer. When the timer expires, the Worker leaves the `async with` block, stops -polling, and waits up to two minutes for in-flight Activities to complete. +Use `ActivityTracker` to keep a Worker available while it runs Activities and stop it after a period with no Activity +work: -This policy is appropriate when Activities represent the work that should keep the Worker available. For example, the -AgentCore sample runs model and tool calls as Activities. It is not a universal definition of idleness. If your Worker -has a different signal for useful work, use that signal instead. +```python +DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) +DRAIN = timedelta(seconds=120) + +tracker = ActivityTracker() +worker = create_worker(client, tracker) + +async with worker: + await tracker.wait_until_idle(DEBOUNCE) +``` + +`ActivityTracker` starts a 60-second timer when no Activity is running. Starting or completing an Activity resets the +timer. When the timer expires, the Worker leaves the `async with` block, stops polling, and waits up to two minutes for +in-flight Activities to complete. + +This policy is appropriate when Activities represent the work that should keep the Worker available. The AgentCore +sample runs model and tool calls as Activities. It is not a universal definition of idleness. If your Worker has a +different signal for useful work, use that signal instead. `AGENTCORE_DEBOUNCE_SECONDS` controls the idle period. `graceful_shutdown_timeout` controls how long the Worker waits for in-flight Activities after it stops polling. Choose both values for your workload, and account for AgentCore's From 9f1d16e4c4b6c4ef47683ec59335bb16ad1321a3 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:13:33 -0700 Subject: [PATCH 12/77] Give an AgentCore Worker idle signal example --- docs/develop/python/workers/serverless-workers/agentcore.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 6cf649d180..d30cf38927 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -187,7 +187,9 @@ in-flight Activities to complete. This policy is appropriate when Activities represent the work that should keep the Worker available. The AgentCore sample runs model and tool calls as Activities. It is not a universal definition of idleness. If your Worker has a -different signal for useful work, use that signal instead. +different signal, use that instead. For example, a Worker that performs meaningful Workflow Task work without +scheduling Activities can track active Workflow Task handlers as well as Activities. Start its idle timer only when +both counts reach zero. `AGENTCORE_DEBOUNCE_SECONDS` controls the idle period. `graceful_shutdown_timeout` controls how long the Worker waits for in-flight Activities after it stops polling. Choose both values for your workload, and account for AgentCore's From 702f80186ec4d9db6b3e101fb375b50618b55d4f Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:14:34 -0700 Subject: [PATCH 13/77] Remove unsupported Workflow Task idle guidance --- docs/develop/python/workers/serverless-workers/agentcore.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index d30cf38927..a2afe5734b 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -187,9 +187,7 @@ in-flight Activities to complete. This policy is appropriate when Activities represent the work that should keep the Worker available. The AgentCore sample runs model and tool calls as Activities. It is not a universal definition of idleness. If your Worker has a -different signal, use that instead. For example, a Worker that performs meaningful Workflow Task work without -scheduling Activities can track active Workflow Task handlers as well as Activities. Start its idle timer only when -both counts reach zero. +different signal, implement an idle policy based on that signal. `AGENTCORE_DEBOUNCE_SECONDS` controls the idle period. `graceful_shutdown_timeout` controls how long the Worker waits for in-flight Activities after it stops polling. Choose both values for your workload, and account for AgentCore's From b0e0e5e9168627331a29da4dd70865cd1b5afd25 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:18:16 -0700 Subject: [PATCH 14/77] Add fixed lease idle policy example --- .../workers/serverless-workers/agentcore.mdx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index a2afe5734b..538b3134cc 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -186,8 +186,21 @@ timer. When the timer expires, the Worker leaves the `async with` block, stops p in-flight Activities to complete. This policy is appropriate when Activities represent the work that should keep the Worker available. The AgentCore -sample runs model and tool calls as Activities. It is not a universal definition of idleness. If your Worker has a -different signal, implement an idle policy based on that signal. +sample runs model and tool calls as Activities. It is not a universal definition of idleness. + +If your workload does not have a useful Activity-based signal, use a fixed Worker lease instead. Start a lease when +AgentCore invokes the Runtime. When it expires, stop polling and drain the Worker: + +```python +LEASE_SECONDS = 300 + +async with worker: + await asyncio.sleep(LEASE_SECONDS) +``` + +A shorter lease releases capacity sooner but causes more Worker starts. A longer lease keeps capacity available longer +but can leave it idle. After the Worker drains, the next Task that needs capacity causes the WCI to invoke another +Runtime session. `AGENTCORE_DEBOUNCE_SECONDS` controls the idle period. `graceful_shutdown_timeout` controls how long the Worker waits for in-flight Activities after it stops polling. Choose both values for your workload, and account for AgentCore's From a47de75c1b179e409654234a7f9942a6a78f0e04 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:19:21 -0700 Subject: [PATCH 15/77] Remove unsupported AgentCore lease guidance --- .../workers/serverless-workers/agentcore.mdx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 538b3134cc..51557d0c0c 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -188,20 +188,6 @@ in-flight Activities to complete. This policy is appropriate when Activities represent the work that should keep the Worker available. The AgentCore sample runs model and tool calls as Activities. It is not a universal definition of idleness. -If your workload does not have a useful Activity-based signal, use a fixed Worker lease instead. Start a lease when -AgentCore invokes the Runtime. When it expires, stop polling and drain the Worker: - -```python -LEASE_SECONDS = 300 - -async with worker: - await asyncio.sleep(LEASE_SECONDS) -``` - -A shorter lease releases capacity sooner but causes more Worker starts. A longer lease keeps capacity available longer -but can leave it idle. After the Worker drains, the next Task that needs capacity causes the WCI to invoke another -Runtime session. - `AGENTCORE_DEBOUNCE_SECONDS` controls the idle period. `graceful_shutdown_timeout` controls how long the Worker waits for in-flight Activities after it stops polling. Choose both values for your workload, and account for AgentCore's maximum Runtime lifetime. For the AgentCore lifecycle settings, see From ad43d78d623fa8212c5da928365669c778bdd740 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:21:09 -0700 Subject: [PATCH 16/77] Clarify Python Worker idle detection --- docs/develop/python/workers/serverless-workers/agentcore.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 51557d0c0c..fc8dc1258d 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -167,6 +167,10 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} +The Python SDK provides Worker shutdown and draining. It does not provide a general signal that a Worker is idle. +`ActivityTracker` is application code that uses an [Activity inbound Interceptor](/develop/python/workers/interceptors) +to define that signal. + Use `ActivityTracker` to keep a Worker available while it runs Activities and stop it after a period with no Activity work: From 9f07493df5cfbfb05126dff2a7df6bd7a1683f6e Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:26:59 -0700 Subject: [PATCH 17/77] Explain AgentCore sample ActivityTracker --- .../develop/python/workers/serverless-workers/agentcore.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index fc8dc1258d..30d597eb4e 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -167,9 +167,9 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} -The Python SDK provides Worker shutdown and draining. It does not provide a general signal that a Worker is idle. -`ActivityTracker` is application code that uses an [Activity inbound Interceptor](/develop/python/workers/interceptors) -to define that signal. +`ActivityTracker` is custom code from the AgentCore sample. It uses an +[Activity inbound Interceptor](/develop/python/workers/interceptors) to count Activity work and decide when the Worker +can stop. Use `ActivityTracker` to keep a Worker available while it runs Activities and stop it after a period with no Activity work: From 60d919a88616518b7e0063df785d6f0cff8275eb Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:30:14 -0700 Subject: [PATCH 18/77] Explain AgentCore Worker retirement policies --- .../workers/serverless-workers/agentcore.mdx | 148 ++++++++++-------- 1 file changed, 81 insertions(+), 67 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 30d597eb4e..54c478f9c5 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -41,13 +41,81 @@ pip install bedrock-agentcore Serverless Workers require [Worker Versioning](/worker-versioning). Create the Worker as you would any long-lived Python Worker, then set `deployment_config` to declare its Worker Deployment Version and enable versioning: +```python +import os + +from temporalio.client import Client +from temporalio.common import VersioningBehavior, WorkerDeploymentVersion +from temporalio.worker import Worker, WorkerDeploymentConfig + +from my_activities import my_activity +from my_workflows import MyWorkflow + +def create_worker(client: Client) -> Worker: + return Worker( + client, + task_queue=os.environ["TEMPORAL_TASK_QUEUE"], + workflows=[MyWorkflow], + activities=[my_activity], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=os.environ["TEMPORAL_DEPLOYMENT_NAME"], + build_id=os.environ["TEMPORAL_BUILD_ID"], + ), + use_worker_versioning=True, + default_versioning_behavior=VersioningBehavior.PINNED, + ), + ) +``` + +`TEMPORAL_DEPLOYMENT_NAME` and `TEMPORAL_BUILD_ID` must match the Worker Deployment Version that you create with +`temporal worker deployment create-version`. Configure that Worker Deployment Version with the AgentCore Runtime +endpoint that Temporal invokes. For the endpoint configuration, see +[Worker Versioning](/serverless-workers/agentcore#worker-versioning). + +Every Workflow needs a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or +`AUTO_UPGRADE`. Setting `default_versioning_behavior` as shown applies `PINNED` behavior to every Workflow on the +Worker. To set the behavior per Workflow instead, pass `versioning_behavior` to the `@workflow.defn` decorator. + +## Start the Worker from the Runtime handler {/* #runtime-handler */} + +AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler, and use `async_task` so +AgentCore keeps the Runtime active while the Worker polls. The complete handler in +[Stop and drain the Worker](#stop-and-drain-the-worker) shows how to add a retirement policy. + +The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker +capacity. Applications start Workflows through the Temporal Client, as usual. + +## Configure the Temporal connection {/* #configure-connection */} + +The `temporalio.envconfig` package loads [Temporal Client](/develop/python/client/temporal-client) configuration from +environment variables and an optional TOML configuration file. Set the Temporal address, Namespace, Task Queue, and +Worker Deployment Version values as Runtime environment variables. Store a Temporal Cloud API key or TLS material in a +secret store rather than in the Runtime definition. + +For the supported connection variables, config-file format, and profiles, see +[Environment configuration](/develop/environment-configuration). + +## Stop and drain the Worker {/* #stop-and-drain-the-worker */} + +Decide what condition means that a Worker can retire. Observe that condition in the Runtime handler. When it remains +true for an idle period, stop polling and drain the Worker. The Temporal Python SDK handles the draining after you leave +the `async with worker` block. + +`ActivityTracker` is one example. It is custom code from the AgentCore sample. It uses an +[Activity inbound Interceptor](/develop/python/workers/interceptors) to count running Activities. This is appropriate +when Activities represent work that should keep the Worker available, such as the model and tool calls in the AgentCore +sample. + ```python import asyncio import os from datetime import timedelta +from bedrock_agentcore.runtime import BedrockAgentCoreApp from temporalio.client import Client from temporalio.common import VersioningBehavior, WorkerDeploymentVersion +from temporalio.envconfig import ClientConfig from temporalio.worker import ( ActivityInboundInterceptor, ExecuteActivityInput, @@ -98,8 +166,15 @@ class TrackedActivity(ActivityInboundInterceptor): self.tracker.changed.set() -def create_worker(client: Client, tracker: ActivityTracker) -> Worker: - return Worker( +app = BedrockAgentCoreApp() + + +@app.entrypoint +@app.async_task +async def invoke(_: dict) -> dict: + client = await Client.connect(**ClientConfig.load_client_connect_config()) + tracker = ActivityTracker() + worker = Worker( client, task_queue=os.environ["TEMPORAL_TASK_QUEUE"], workflows=[MyWorkflow], @@ -115,36 +190,6 @@ def create_worker(client: Client, tracker: ActivityTracker) -> Worker: default_versioning_behavior=VersioningBehavior.PINNED, ), ) -``` - -`TEMPORAL_DEPLOYMENT_NAME` and `TEMPORAL_BUILD_ID` must match the Worker Deployment Version that you create with -`temporal worker deployment create-version`. Configure that Worker Deployment Version with the AgentCore Runtime -endpoint that Temporal invokes. For the endpoint configuration, see -[Worker Versioning](/serverless-workers/agentcore#worker-versioning). - -Every Workflow needs a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or -`AUTO_UPGRADE`. Setting `default_versioning_behavior` as shown applies `PINNED` behavior to every Workflow on the -Worker. To set the behavior per Workflow instead, pass `versioning_behavior` to the `@workflow.defn` decorator. - -## Start the Worker from the Runtime handler {/* #runtime-handler */} - -AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler, and use `async_task` so -AgentCore keeps the Runtime active while the Worker polls: - -```python -from bedrock_agentcore.runtime import BedrockAgentCoreApp -from temporalio.client import Client -from temporalio.envconfig import ClientConfig - -app = BedrockAgentCoreApp() - - -@app.entrypoint -@app.async_task -async def invoke(_: dict) -> dict: - client = await Client.connect(**ClientConfig.load_client_connect_config()) - tracker = ActivityTracker() - worker = create_worker(client, tracker) async with worker: await tracker.wait_until_idle(DEBOUNCE) @@ -152,45 +197,14 @@ async def invoke(_: dict) -> dict: return {"message": "Worker drained"} ``` -The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker -capacity. Applications start Workflows through the Temporal Client, as usual. - -## Configure the Temporal connection {/* #configure-connection */} - -The `temporalio.envconfig` package loads [Temporal Client](/develop/python/client/temporal-client) configuration from -environment variables and an optional TOML configuration file. Set the Temporal address, Namespace, Task Queue, and -Worker Deployment Version values as Runtime environment variables. Store a Temporal Cloud API key or TLS material in a -secret store rather than in the Runtime definition. - -For the supported connection variables, config-file format, and profiles, see -[Environment configuration](/develop/environment-configuration). - -## Stop and drain the Worker {/* #stop-and-drain-the-worker */} - -`ActivityTracker` is custom code from the AgentCore sample. It uses an -[Activity inbound Interceptor](/develop/python/workers/interceptors) to count Activity work and decide when the Worker -can stop. - -Use `ActivityTracker` to keep a Worker available while it runs Activities and stop it after a period with no Activity -work: - -```python -DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) -DRAIN = timedelta(seconds=120) - -tracker = ActivityTracker() -worker = create_worker(client, tracker) - -async with worker: - await tracker.wait_until_idle(DEBOUNCE) -``` - `ActivityTracker` starts a 60-second timer when no Activity is running. Starting or completing an Activity resets the timer. When the timer expires, the Worker leaves the `async with` block, stops polling, and waits up to two minutes for in-flight Activities to complete. -This policy is appropriate when Activities represent the work that should keep the Worker available. The AgentCore -sample runs model and tool calls as Activities. It is not a universal definition of idleness. +Memory pressure can be another retirement condition. For example, the Runtime handler can monitor process memory and +initiate the same graceful shutdown when usage crosses a threshold. Memory usage is not an idle signal. It tells you +when to recycle a Worker, not whether it has work to do. Test any memory-based policy against the Runtime's memory +limit and your Activity retry behavior. `AGENTCORE_DEBOUNCE_SECONDS` controls the idle period. `graceful_shutdown_timeout` controls how long the Worker waits for in-flight Activities after it stops polling. Choose both values for your workload, and account for AgentCore's From 162b2379c31e408d55282245a55520857e90a0b4 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:33:29 -0700 Subject: [PATCH 19/77] Explain ActivityTracker idle behavior --- .../python/workers/serverless-workers/agentcore.mdx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 54c478f9c5..250d25464d 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -102,10 +102,8 @@ Decide what condition means that a Worker can retire. Observe that condition in true for an idle period, stop polling and drain the Worker. The Temporal Python SDK handles the draining after you leave the `async with worker` block. -`ActivityTracker` is one example. It is custom code from the AgentCore sample. It uses an -[Activity inbound Interceptor](/develop/python/workers/interceptors) to count running Activities. This is appropriate -when Activities represent work that should keep the Worker available, such as the model and tool calls in the AgentCore -sample. +The following example defines an `ActivityTracker`. It uses an +[Activity inbound Interceptor](/develop/python/workers/interceptors) to count running Activities. ```python import asyncio @@ -197,9 +195,10 @@ async def invoke(_: dict) -> dict: return {"message": "Worker drained"} ``` -`ActivityTracker` starts a 60-second timer when no Activity is running. Starting or completing an Activity resets the -timer. When the timer expires, the Worker leaves the `async with` block, stops polling, and waits up to two minutes for -in-flight Activities to complete. +`ActivityTracker` retires the Worker only after 60 seconds without an Activity starting or completing and with no +Activity running. A long-running Activity keeps the count above zero, so the Worker continues polling. After that +Activity completes, the tracker waits another 60 seconds before it retires the Worker. The two-minute +`graceful_shutdown_timeout` is a safety limit for any Activity still in flight when shutdown starts. Memory pressure can be another retirement condition. For example, the Runtime handler can monitor process memory and initiate the same graceful shutdown when usage crosses a threshold. Memory usage is not an idle signal. It tells you From a3752a61ac06f4a61fab271fe4a0c42525079a49 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:34:54 -0700 Subject: [PATCH 20/77] State exact AgentCore idle condition --- docs/develop/python/workers/serverless-workers/agentcore.mdx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 250d25464d..2abf7f8ec5 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -196,9 +196,8 @@ async def invoke(_: dict) -> dict: ``` `ActivityTracker` retires the Worker only after 60 seconds without an Activity starting or completing and with no -Activity running. A long-running Activity keeps the count above zero, so the Worker continues polling. After that -Activity completes, the tracker waits another 60 seconds before it retires the Worker. The two-minute -`graceful_shutdown_timeout` is a safety limit for any Activity still in flight when shutdown starts. +Activity running. A long-running Activity keeps the count above zero, so the idle policy does not interrupt it. The +two-minute `graceful_shutdown_timeout` is a safety limit for any Activity still in flight when shutdown starts. Memory pressure can be another retirement condition. For example, the Runtime handler can monitor process memory and initiate the same graceful shutdown when usage crosses a threshold. Memory usage is not an idle signal. It tells you From b5d85dc8afbf2a69ce6fa31db5d82c1f498f11b6 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 12:49:16 -0700 Subject: [PATCH 21/77] Focus AgentCore Worker lifecycle examples --- .../workers/serverless-workers/agentcore.mdx | 133 ++++++++---------- 1 file changed, 57 insertions(+), 76 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 2abf7f8ec5..5bb2d8ae9b 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -42,30 +42,17 @@ Serverless Workers require [Worker Versioning](/worker-versioning). Create the W Python Worker, then set `deployment_config` to declare its Worker Deployment Version and enable versioning: ```python -import os - -from temporalio.client import Client -from temporalio.common import VersioningBehavior, WorkerDeploymentVersion -from temporalio.worker import Worker, WorkerDeploymentConfig - -from my_activities import my_activity -from my_workflows import MyWorkflow - -def create_worker(client: Client) -> Worker: - return Worker( - client, - task_queue=os.environ["TEMPORAL_TASK_QUEUE"], - workflows=[MyWorkflow], - activities=[my_activity], - deployment_config=WorkerDeploymentConfig( - version=WorkerDeploymentVersion( - deployment_name=os.environ["TEMPORAL_DEPLOYMENT_NAME"], - build_id=os.environ["TEMPORAL_BUILD_ID"], - ), - use_worker_versioning=True, - default_versioning_behavior=VersioningBehavior.PINNED, +worker = Worker( + # ... + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=DEPLOYMENT_NAME, + build_id=BUILD_ID, ), - ) + use_worker_versioning=True, + default_versioning_behavior=VersioningBehavior.PINNED, + ), +) ``` `TEMPORAL_DEPLOYMENT_NAME` and `TEMPORAL_BUILD_ID` must match the Worker Deployment Version that you create with @@ -80,8 +67,29 @@ Worker. To set the behavior per Workflow instead, pass `versioning_behavior` to ## Start the Worker from the Runtime handler {/* #runtime-handler */} AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler, and use `async_task` so -AgentCore keeps the Runtime active while the Worker polls. The complete handler in -[Stop and drain the Worker](#stop-and-drain-the-worker) shows how to add a retirement policy. +AgentCore keeps the Runtime active while the Worker polls: + +```python +@app.entrypoint +@app.async_task +async def invoke(payload: dict) -> dict: + client = await Client.connect(...) + tracker = ActivityTracker() + worker = Worker( + client, + task_queue=task_queue, + workflows=[MyWorkflow], + activities=[my_activity], + interceptors=[tracker], + graceful_shutdown_timeout=DRAIN, + deployment_config=deployment_config, + ) + + async with worker: + await tracker.wait_until_idle(DEBOUNCE) + + return {"message": "Worker drained"} +``` The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker capacity. Applications start Workflows through the Temporal Client, as usual. @@ -98,33 +106,22 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} -Decide what condition means that a Worker can retire. Observe that condition in the Runtime handler. When it remains -true for an idle period, stop polling and drain the Worker. The Temporal Python SDK handles the draining after you leave -the `async with worker` block. +The `async_task` decorator reports the Runtime as busy while the handler is running. If a Worker continues polling after +the available Temporal work is complete, AgentCore cannot tell from the handler status that the Worker is no longer +needed. The compute can remain active until it reaches its maximum lifetime, which is eight hours by default. -The following example defines an `ActivityTracker`. It uses an -[Activity inbound Interceptor](/develop/python/workers/interceptors) to count running Activities. +To release unused capacity sooner, decide how the Worker recognizes that it has no useful work. Observe that condition +in the Runtime handler. -```python -import asyncio -import os -from datetime import timedelta - -from bedrock_agentcore.runtime import BedrockAgentCoreApp -from temporalio.client import Client -from temporalio.common import VersioningBehavior, WorkerDeploymentVersion -from temporalio.envconfig import ClientConfig -from temporalio.worker import ( - ActivityInboundInterceptor, - ExecuteActivityInput, - Interceptor, - Worker, - WorkerDeploymentConfig, -) +When the condition remains true for an idle period, leave the `async with worker` block. The Worker stops polling for +new Tasks and gives in-flight Activities time to complete before the Runtime handler returns. -from my_activities import my_activity -from my_workflows import MyWorkflow +The following example from the +[AgentCore sample Worker](https://github.com/temporalio/samples-python/blob/77768ed87676359823736a40b68ca988a7344543/bedrock_agentcore/strands-agent/agentcore_worker.py) +defines an `ActivityTracker`. It uses an [Activity inbound Interceptor](/develop/python/workers/interceptors) to count +running Activities. +```python DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) DRAIN = timedelta(seconds=120) @@ -162,37 +159,21 @@ class TrackedActivity(ActivityInboundInterceptor): finally: self.tracker.inflight -= 1 self.tracker.changed.set() +``` +Register the tracker as a Worker Interceptor and wait for it inside the Worker context: -app = BedrockAgentCoreApp() - - -@app.entrypoint -@app.async_task -async def invoke(_: dict) -> dict: - client = await Client.connect(**ClientConfig.load_client_connect_config()) - tracker = ActivityTracker() - worker = Worker( - client, - task_queue=os.environ["TEMPORAL_TASK_QUEUE"], - workflows=[MyWorkflow], - activities=[my_activity], - interceptors=[tracker], - graceful_shutdown_timeout=DRAIN, - deployment_config=WorkerDeploymentConfig( - version=WorkerDeploymentVersion( - deployment_name=os.environ["TEMPORAL_DEPLOYMENT_NAME"], - build_id=os.environ["TEMPORAL_BUILD_ID"], - ), - use_worker_versioning=True, - default_versioning_behavior=VersioningBehavior.PINNED, - ), - ) - - async with worker: - await tracker.wait_until_idle(DEBOUNCE) +```python +tracker = ActivityTracker() +worker = Worker( + client, + # ... + interceptors=[tracker], + graceful_shutdown_timeout=DRAIN, +) - return {"message": "Worker drained"} +async with worker: + await tracker.wait_until_idle(DEBOUNCE) ``` `ActivityTracker` retires the Worker only after 60 seconds without an Activity starting or completing and with no From 167adcb1c5bc37c9b5a39e5cb037a42aa8ad40ec Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 13:01:06 -0700 Subject: [PATCH 22/77] Sync AgentCore Worker examples from sample --- .../workers/serverless-workers/agentcore.mdx | 86 +++++++++++++------ 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 5bb2d8ae9b..08ef2625d6 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -69,27 +69,50 @@ Worker. To set the behavior per Workflow instead, pass `versioning_behavior` to AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler, and use `async_task` so AgentCore keeps the Runtime active while the Worker polls: -```python + +[bedrock_agentcore/strands-agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/5b0fe65efe934388d35eda430fb11df6899ce1d3/bedrock_agentcore/strands-agent/agentcore_worker.py) +```py @app.entrypoint -@app.async_task +@app.async_task # keeps /ping on "HealthyBusy" until this returns async def invoke(payload: dict) -> dict: - client = await Client.connect(...) - tracker = ActivityTracker() - worker = Worker( - client, - task_queue=task_queue, - workflows=[MyWorkflow], - activities=[my_activity], - interceptors=[tracker], - graceful_shutdown_timeout=DRAIN, - deployment_config=deployment_config, + """Poll until idle, then drain. The payload is unused: every call is a new session and new worker.""" + api_key = os.environ.get("TEMPORAL_API_KEY") or None + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + namespace=os.environ.get("TEMPORAL_NAMESPACE", "default"), + api_key=api_key, + tls=bool(api_key), + plugins=[StrandsPlugin()], ) - async with worker: - await tracker.wait_until_idle(DEBOUNCE) + task_queue = os.environ.get("TEMPORAL_TASK_QUEUE", workflows.TASK_QUEUE) + tracker = ActivityTracker() - return {"message": "Worker drained"} + log.info("polling %s as %s/%s", task_queue, DEPLOYMENT_NAME, BUILD_ID) + # execute_code is a sync Activity, so it needs an executor to block on. + with ThreadPoolExecutor(max_workers=4) as activity_executor: + worker = Worker( + client, + task_queue=task_queue, + workflows=[workflows.StrandsAgentWorkflow], + activities=[execute_code], + activity_executor=activity_executor, + interceptors=[tracker], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=DEPLOYMENT_NAME, build_id=BUILD_ID + ), + use_worker_versioning=True, + default_versioning_behavior=VersioningBehavior.PINNED, + ), + graceful_shutdown_timeout=DRAIN, + ) + async with worker: + await tracker.wait_until_idle(DEBOUNCE) + log.info("worker idle for %ss; drained", DEBOUNCE) + return {"message": "worker drained", "task_queue": task_queue} ``` + The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker capacity. Applications start Workflows through the Temporal Client, as usual. @@ -117,16 +140,22 @@ When the condition remains true for an idle period, leave the `async with worker new Tasks and gives in-flight Activities time to complete before the Runtime handler returns. The following example from the -[AgentCore sample Worker](https://github.com/temporalio/samples-python/blob/77768ed87676359823736a40b68ca988a7344543/bedrock_agentcore/strands-agent/agentcore_worker.py) +[AgentCore sample Worker](https://github.com/temporalio/samples-python/blob/5b0fe65efe934388d35eda430fb11df6899ce1d3/bedrock_agentcore/strands-agent/agentcore_worker.py) defines an `ActivityTracker`. It uses an [Activity inbound Interceptor](/develop/python/workers/interceptors) to count running Activities. -```python + +[bedrock_agentcore/strands-agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/5b0fe65efe934388d35eda430fb11df6899ce1d3/bedrock_agentcore/strands-agent/agentcore_worker.py) +```py +# How long the Worker keeps polling after it goes idle. DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) +# How long the drain waits for in-flight Activities (a model or tool call). DRAIN = timedelta(seconds=120) class ActivityTracker(Interceptor): + """Tracks in-flight activities and blocks until AGENTCORE_DEBOUNCE_SECONDS elapses with no events.""" + def __init__(self) -> None: self.inflight = 0 self.changed = asyncio.Event() @@ -134,32 +163,39 @@ class ActivityTracker(Interceptor): def intercept_activity( self, next: ActivityInboundInterceptor ) -> ActivityInboundInterceptor: - return TrackedActivity(next, self) + return _TrackedActivity(next, self) async def wait_until_idle(self, debounce: float) -> None: + """Return once no Activity has run for ``debounce`` seconds.""" while True: self.changed.clear() try: + # Wake the moment an Activity starts or finishes; a timeout + # instead means nothing has happened for the whole window. await asyncio.wait_for(self.changed.wait(), timeout=debounce) except asyncio.TimeoutError: if self.inflight == 0: return -class TrackedActivity(ActivityInboundInterceptor): - def __init__(self, next: ActivityInboundInterceptor, tracker: ActivityTracker): +class _TrackedActivity(ActivityInboundInterceptor): + def __init__( + self, next: ActivityInboundInterceptor, tracker: ActivityTracker + ) -> None: super().__init__(next) - self.tracker = tracker + self._tracker = tracker async def execute_activity(self, input: ExecuteActivityInput): - self.tracker.inflight += 1 - self.tracker.changed.set() + self._tracker.inflight += 1 + self._tracker.changed.set() + log.info("activity in flight: %d", self._tracker.inflight) try: return await self.next.execute_activity(input) finally: - self.tracker.inflight -= 1 - self.tracker.changed.set() + self._tracker.inflight -= 1 + self._tracker.changed.set() ``` + Register the tracker as a Worker Interceptor and wait for it inside the Worker context: From ce637085897a88ed2551e6e7e46d9d2ede5325e5 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 13:14:04 -0700 Subject: [PATCH 23/77] Tighten AgentCore idle policy context --- .../python/workers/serverless-workers/agentcore.mdx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 08ef2625d6..f3cae542a4 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -129,12 +129,10 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} -The `async_task` decorator reports the Runtime as busy while the handler is running. If a Worker continues polling after -the available Temporal work is complete, AgentCore cannot tell from the handler status that the Worker is no longer -needed. The compute can remain active until it reaches its maximum lifetime, which is eight hours by default. - -To release unused capacity sooner, decide how the Worker recognizes that it has no useful work. Observe that condition -in the Runtime handler. +The `async_task` decorator reports the Runtime as busy while the handler is running, so AgentCore cannot tell when a +Worker that is still polling has no Temporal work. Without an application idle policy, the Runtime can remain active +until its maximum lifetime of eight hours. To release capacity sooner, have the Runtime handler detect when the Worker +has no useful work. When the condition remains true for an idle period, leave the `async with worker` block. The Worker stops polling for new Tasks and gives in-flight Activities time to complete before the Runtime handler returns. From b5c80b8e6e7f5b48664d5b0e29e960a1e88571fc Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 13:25:59 -0700 Subject: [PATCH 24/77] Lead AgentCore lifecycle guidance with impact --- .../python/workers/serverless-workers/agentcore.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index f3cae542a4..fba823313e 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -129,10 +129,9 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} -The `async_task` decorator reports the Runtime as busy while the handler is running, so AgentCore cannot tell when a -Worker that is still polling has no Temporal work. Without an application idle policy, the Runtime can remain active -until its maximum lifetime of eight hours. To release capacity sooner, have the Runtime handler detect when the Worker -has no useful work. +AgentCore cannot tell when a Worker that is still polling has no Temporal work. The Runtime remains busy while the +`async_task` handler runs, so it can remain active until its eight-hour maximum lifetime. To release capacity sooner, +have the handler detect when the Worker has no useful work and return. When the condition remains true for an idle period, leave the `async with worker` block. The Worker stops polling for new Tasks and gives in-flight Activities time to complete before the Runtime handler returns. From be60a1e32c9ea865ffddceddcfbee46ec74ee58a Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 13:40:18 -0700 Subject: [PATCH 25/77] Add AgentCore Serverless Worker deployment guide --- .../workers/serverless-workers/agentcore.mdx | 2 + .../serverless-workers-agentcore.mdx | 3 + .../worker-deployments/index.mdx | 2 +- .../serverless-workers/agentcore.mdx | 331 ++++++++++++++++++ .../serverless-workers/index.mdx | 15 +- sidebars.js | 1 + 6 files changed, 346 insertions(+), 8 deletions(-) create mode 100644 docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index fba823313e..2c5605ec7a 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -27,6 +27,8 @@ invocations. For the provider behavior, including autoscaling, Worker Versioning, and the Runtime session lifecycle, see [Serverless Workers on Amazon Bedrock AgentCore Runtime](/serverless-workers/agentcore). +For the infrastructure procedure, see +[Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore). ## Install the AgentCore Runtime SDK {/* #install-agentcore-runtime-sdk */} diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 9fd3328801..6f0577e42a 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -23,6 +23,9 @@ import { ReleaseNoteHeader } from '@site/src/components'; This page covers how Serverless Workers run on Amazon Bedrock AgentCore Runtime, including Worker Versioning and the Runtime session lifecycle. +To deploy a Worker, see +[Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore). + On AgentCore Runtime, a Serverless Worker is a standard long-running Temporal Worker that runs inside an AgentCore Runtime session. When the [Worker Controller Instance (WCI)](/serverless-workers#worker-controller-instance) needs capacity, it invokes an AgentCore Runtime endpoint. The Runtime starts a Worker, which connects to the Temporal Service diff --git a/docs/production-deployment/worker-deployments/index.mdx b/docs/production-deployment/worker-deployments/index.mdx index 4a4ecb9a1f..f70742770f 100644 --- a/docs/production-deployment/worker-deployments/index.mdx +++ b/docs/production-deployment/worker-deployments/index.mdx @@ -30,7 +30,7 @@ You can optionally use the Temporal [Worker Controller](/production-deployment/w This section also covers specific Worker Deployment examples: - [**Serverless Workers**](/production-deployment/worker-deployments/serverless-workers) - Deploy Serverless Workers on serverless compute like AWS Lambda. + Deploy Serverless Workers on AWS Lambda, GCP Cloud Run, or Amazon Bedrock AgentCore Runtime. Temporal invokes your Worker when Tasks arrive, with no long-lived processes to manage. - [**Deploy Workers to Amazon EKS**](/production-deployment/worker-deployments/deploy-workers-to-aws-eks) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx new file mode 100644 index 0000000000..3dc8c6ee45 --- /dev/null +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -0,0 +1,331 @@ +--- +id: agentcore +title: Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime +sidebar_label: Amazon Bedrock AgentCore +description: Deploy a Python Serverless Worker to AgentCore Runtime and configure Temporal Cloud to invoke its endpoint. +slug: /production-deployment/worker-deployments/serverless-workers/agentcore +toc_max_heading_level: 4 +tags: + - Workers + - Deploy + - Serverless + - Amazon Bedrock AgentCore +--- + +import { ReleaseNoteHeader } from '@site/src/components'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. + + +This guide walks through deploying a Python [Serverless Worker](/serverless-workers) to Amazon Bedrock AgentCore +Runtime. Temporal invokes the Runtime endpoint when the Worker Controller Instance needs Worker capacity. + +The guide uses the +[Python Strands AgentCore sample](https://github.com/temporalio/samples-python/tree/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent). +The deployment procedure applies to other Python Workers that use the same AgentCore Runtime handler. For the Worker +implementation and lifecycle, see +[Serverless Workers on Amazon Bedrock AgentCore Runtime - Python SDK](/develop/python/workers/serverless-workers/agentcore). + +## Prerequisites {/* #prerequisites */} + +- A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release. +- A Temporal Cloud API key that can connect to the Namespace. +- [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later, configured for your Namespace. +- An AWS account in an [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). +- The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed and configured + with credentials for that account. +- Node.js 20 or later and the [AgentCore CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html) + installed with `npm install -g @aws/agentcore`. +- The [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed and bootstrapped in the target + account and Region. +- Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/) installed. +- Permission to create AgentCore resources, CloudFormation stacks, and IAM roles. See + [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). + +The sample agent calls an Amazon Bedrock model and uses AgentCore Code Interpreter. To run the sample without changing +it, make sure both services are available to your AWS account in the target Region. + +## 1. Prepare the Worker {/* #prepare-worker */} + +Clone the sample repository and check out the AgentCore sample branch: + +```bash +git clone https://github.com/temporalio/samples-python.git +cd samples-python +git checkout schoeff/strands-agent +cd bedrock_agentcore/strands-agent +``` + +The sample contains these deployment files: + +| File | Purpose | +| --- | --- | +| [`agentcore_worker.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/agentcore_worker.py) | Defines the AgentCore Runtime handler and starts the Temporal Worker. | +| [`workflows.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/workflows.py) | Defines the sample Workflow. | +| [`activities.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/activities.py) | Defines the sample Activity. | +| [`agentcore/agentcore.json`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/agentcore/agentcore.json) | Configures the Runtime, endpoint, environment, and lifecycle. | +| [`agentcore/aws-targets.json`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/agentcore/aws-targets.json) | Selects the AWS account and Region. | + +The Runtime handler registers `StrandsAgentWorkflow` and `execute_code` on the Worker. To deploy your own application, +replace those registrations with your Workflow and Activity Definitions. Keep the AgentCore handler, Worker Versioning +configuration, and shutdown policy. Every Workflow must declare a +[versioning behavior](/worker-versioning/#versioning-behaviors), or the Worker must set a default behavior. + +## 2. Configure the AgentCore project {/* #configure-project */} + +The AgentCore CLI reads the project from `agentcore/agentcore.json` and deploys it to a target in +`agentcore/aws-targets.json`. + +### Select the AWS account and Region {/* #select-account-region */} + +Replace the account and Region in `agentcore/aws-targets.json`: + +```json +[ + { + "name": "default", + "account": "", + "region": "" + } +] +``` + +The Region must support AgentCore Runtime and any AWS services that the Worker's Activities call. + +### Configure the Runtime {/* #configure-runtime */} + +In `agentcore/agentcore.json`, set the Temporal connection, Task Queue, Worker Deployment name, and Build ID under +`envVars`: + +```json +{ + "name": "TEMPORAL_ADDRESS", + "value": "..tmprl.cloud:7233" +}, +{ + "name": "TEMPORAL_NAMESPACE", + "value": "." +}, +{ + "name": "TEMPORAL_API_KEY", + "value": "" +}, +{ + "name": "TEMPORAL_TASK_QUEUE", + "value": "agentcore-strands-task-queue" +}, +{ + "name": "TEMPORAL_DEPLOYMENT_NAME", + "value": "agentcore-strands-agent-python" +}, +{ + "name": "TEMPORAL_BUILD_ID", + "value": "1.0.0" +} +``` + +The deployment name and Build ID must match the values you use when you create the Worker Deployment Version in +[Step 5](#create-worker-deployment-version). The Task Queue must match the Task Queue used to start the Workflow. +For the sample, also set `AWS_REGION` to the Region in `aws-targets.json` so its Bedrock model and Code Interpreter +calls stay in that Region. + +The sample stores the Temporal Cloud API key in `envVars` to keep the example short. Do not commit a populated API key. +For a production deployment, store the key in AWS Secrets Manager, grant the Runtime execution role permission to read +it, and load it in the Runtime handler. The AgentCore CLI creates the Runtime execution role during deployment. This +role is separate from the invocation role that Temporal assumes in [Step 4](#configure-iam). + +The sample uses a CodeZip build and a public network: + +```json +{ + "build": "CodeZip", + "entrypoint": "agentcore_worker.py", + "codeLocation": ".", + "runtimeVersion": "PYTHON_3_12", + "networkMode": "PUBLIC", + "protocol": "HTTP", + "authorizerType": "AWS_IAM" +} +``` + +`CodeZip` lets the AgentCore CLI package the Python code without Docker. `PUBLIC` gives the Worker outbound network +access to Temporal Cloud. The `AWS_IAM` authorizer lets Temporal invoke the endpoint by assuming an IAM role in your +AWS account. + +Keep the named `temporal` endpoint in the sample configuration. Temporal invokes this endpoint rather than AgentCore's +`DEFAULT` endpoint. For the endpoint and Runtime version relationship, see +[Worker Versioning on AgentCore Runtime](/serverless-workers/agentcore/#worker-versioning). + +## 3. Deploy the Runtime and endpoint {/* #deploy-runtime */} + +From the sample directory, run: + +```bash +./bin/create-runtime.sh +``` + +The script creates the AgentCore CDK scaffold on its first run. It then validates the project, packages the Worker and +its dependencies, and runs `agentcore deploy`. AgentCore creates the Runtime execution role, Runtime version, named +endpoint, and CloudWatch log group. + +Check the deployed resources: + +```bash +agentcore status --runtime temporal_strands_worker --json +agentcore status --type runtime-endpoint --json +``` + +Record both of these values from the output: + +- The **Runtime ARN**, which you use to scope the invocation role in [Step 4](#configure-iam). +- The **Runtime endpoint ARN** for the named `temporal` endpoint, which you give Temporal in + [Step 5](#create-worker-deployment-version). + +## 4. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} + +Temporal Cloud assumes an IAM role in your AWS account to get the named endpoint and invoke the Runtime. The role is +not the Runtime execution role and does not run your Worker code. + +Choose an External ID of at least five characters. Use the same value in the role trust policy and the Worker +Deployment Version. The External ID prevents a +[confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attack. + +The sample includes a +[CloudFormation template](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/iam-role-for-temporal-agentcore-invoke.yaml) +and a script that deploys it. Pass the Runtime ARN with a trailing wildcard so the policy covers the Runtime and its +endpoints: + +```bash +AWS_REGION= ./bin/mk-invoke-role.sh \ + temporal-agentcore-invoke \ + \ + '*' +``` + +Wait for the CloudFormation stack to finish: + +```bash +aws cloudformation wait stack-create-complete \ + --stack-name temporal-agentcore-invoke \ + --region +``` + +Then retrieve the invocation role ARN: + +```bash +aws cloudformation describe-stacks \ + --stack-name temporal-agentcore-invoke \ + --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' \ + --output text \ + --region +``` + +The role grants `bedrock-agentcore:InvokeAgentRuntime` and `bedrock-agentcore:GetAgentRuntimeEndpoint` on the configured +Runtime resources. Record the role ARN for the next step. + +## 5. Create the Worker Deployment Version {/* #create-worker-deployment-version */} + +Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) whose compute +configuration points to the named AgentCore Runtime endpoint. The deployment name and Build ID must match the Runtime +environment variables from [Step 2](#configure-runtime). + + + + +In the Temporal Cloud UI, open your Namespace and select **Workers** > **Create Worker Deployment**. Provide these +values: + +- **Name**: `agentcore-strands-agent-python`. +- **Build ID**: `1.0.0`. +- **Compute Provider**: select **Amazon Bedrock AgentCore Runtime**. +- **Runtime endpoint ARN**: the named endpoint ARN from [Step 3](#deploy-runtime). +- **IAM role ARN**: the invocation role ARN from [Step 4](#configure-iam). +- **External ID**: the External ID from [Step 4](#configure-iam). + +Save the Worker Deployment. When you create a version through the UI, the version is automatically current. Continue +to [Step 7](#verify-deployment). + + + + +First, create the Worker Deployment if it does not already exist: + +```bash +temporal worker deployment create \ + --namespace \ + --name agentcore-strands-agent-python +``` + +Then create the version with the AgentCore compute configuration: + +```bash +temporal worker deployment create-version \ + --namespace \ + --deployment-name agentcore-strands-agent-python \ + --build-id 1.0.0 \ + --aws-agentcore-endpoint-arn \ + --aws-agentcore-assume-role-arn \ + --aws-agentcore-assume-role-external-id +``` + +| Flag | Description | +| --- | --- | +| `--deployment-name` | Worker Deployment name. Must match `TEMPORAL_DEPLOYMENT_NAME` in the Runtime environment. | +| `--build-id` | Worker Deployment Version Build ID. Must match `TEMPORAL_BUILD_ID` in the Runtime environment. | +| `--aws-agentcore-endpoint-arn` | ARN of the named AgentCore Runtime endpoint that Temporal invokes. | +| `--aws-agentcore-assume-role-arn` | IAM role Temporal assumes to invoke the endpoint. This is the CloudFormation stack output from Step 4, not the Runtime execution role. | +| `--aws-agentcore-assume-role-external-id` | External ID configured in the invocation role trust policy. | + + + + +To check whether Temporal can reach the endpoint, open the Worker Deployment Version in the Temporal Cloud UI and +select **Actions** > **Validate Connection**. This checks that Temporal can assume the invocation role, get the named +endpoint, and invoke the Runtime. + +## 6. Set the version as current {/* #set-current-version */} + +If you used the Temporal CLI, set the version as current: + +```bash +temporal worker deployment set-current-version \ + --namespace \ + --deployment-name agentcore-strands-agent-python \ + --build-id 1.0.0 +``` + +This command asks you to confirm because it changes which version receives new Tasks. Pass `--yes` to skip the prompt. +If you created the version in the Temporal Cloud UI, it is already current. + +## 7. Verify the deployment {/* #verify-deployment */} + +Install the sample dependencies and export the same Temporal connection values that you configured for the Runtime: + +```bash +uv sync +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_API_KEY= +``` + +Start the sample Workflow from your local machine: + +```bash +uv run python starter.py "Calculate the first 10 Fibonacci numbers." +``` + +The starter sends the Workflow to `agentcore-strands-task-queue`. When no Worker is polling, Temporal invokes +the AgentCore Runtime endpoint. The Runtime starts the Worker, and the Worker processes the Workflow and its Activities. + +You can confirm the deployment in these places: + +- **Temporal Cloud UI**: Open the Workflow Execution and confirm that its Event History progresses. +- **AgentCore logs**: Run `agentcore logs --runtime temporal_strands_worker` to see the Worker start and process Tasks. +- **Temporal CLI**: Run `temporal workflow show --workflow-id agentcore-strands-workflow-id-1` to inspect the Event + History. + +For the sample Workflow and agent implementation, see +[`workflows.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/workflows.py). diff --git a/docs/production-deployment/worker-deployments/serverless-workers/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx index 1a80f95fcc..8e15a56982 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/index.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx @@ -15,10 +15,9 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - AWS Lambda support is in Public Preview. GCP Cloud Run support is in Pre-release, and its APIs may change in - backwards-incompatible ways. To request Cloud Run access, create a [support ticket](/cloud/support#support-ticket) or - contact your account team, and [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear - when Cloud Run reaches Public Preview. + AWS Lambda support is in Public Preview. Support for GCP Cloud Run and Amazon Bedrock AgentCore Runtime is in + Pre-release, and their APIs may change in backwards-incompatible ways. To request access, create a + [support ticket](/cloud/support#support-ticket) or contact your account team. Serverless Workers let you run Temporal Workers on serverless compute. Deploy your Worker code to a serverless provider, @@ -27,9 +26,8 @@ work on the Task Queue. There is no always-on Worker fleet to provision or scale Temporal monitors Task Queues that have a compute provider configured. When a Task arrives and no Worker is free to take it, the [Worker Controller Instance (WCI)](/serverless-workers#how-invocation-works) starts compute. How it starts -compute is where the providers differ. On AWS Lambda the WCI invokes a function per unit of work, and the Worker exits -when the invocation window ends. On GCP Cloud Run it resizes a Worker Pool of long-lived instances that poll -continuously. +compute is where the providers differ. On AWS Lambda and AgentCore Runtime, the WCI invokes compute in response to +unmet Task Queue demand. On GCP Cloud Run, it resizes a Worker Pool of long-lived instances that poll continuously. ## Supported providers @@ -38,3 +36,6 @@ continuously. - [**GCP Cloud Run**](/production-deployment/worker-deployments/serverless-workers/cloud-run) - Deploy a Serverless Worker to a Cloud Run Worker Pool. Temporal impersonates a service account in your GCP project to scale the pool as Tasks arrive and drain. +- [**Amazon Bedrock AgentCore Runtime**](/production-deployment/worker-deployments/serverless-workers/agentcore) - + Deploy a Serverless Worker to AgentCore Runtime. Temporal assumes an IAM role in your AWS account to invoke the + Runtime endpoint as Tasks arrive. diff --git a/sidebars.js b/sidebars.js index 35f2165256..f30fabd864 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1607,6 +1607,7 @@ module.exports = { 'production-deployment/worker-deployments/serverless-workers/aws-lambda/self-hosted-setup', ], }, + 'production-deployment/worker-deployments/serverless-workers/agentcore', { type: 'category', label: 'GCP Cloud Run', From cb56f06f158f1acdb9a74bc8bf7da05b3a9c89bb Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Thu, 10 Sep 2026 16:56:51 -0700 Subject: [PATCH 26/77] Document durable agents on AgentCore --- docs/guides/durable-agent-on-agentcore.mdx | 428 ++++++++++++++++++ .../serverless-workers/agentcore.mdx | 245 ++++------ sidebars.js | 1 + snipsync.config.yaml | 3 + src/components/GuidesGrid/guides-data.json | 9 + ...loud-serverless-worker-agentcore-role.yaml | 69 +++ 6 files changed, 593 insertions(+), 162 deletions(-) create mode 100644 docs/guides/durable-agent-on-agentcore.mdx create mode 100644 static/files/temporal-cloud-serverless-worker-agentcore-role.yaml diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx new file mode 100644 index 0000000000..b996fae4d7 --- /dev/null +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -0,0 +1,428 @@ +--- +id: durable-agent-on-agentcore +title: Build a durable agent on Amazon Bedrock AgentCore +sidebar_label: Durable agent on AgentCore +description: A Temporal Workflow preserves conversation state while AgentCore Runtime supplies serverless Worker compute for a Strands agent. +toc_max_heading_level: 3 +author: n/a +tags: + - Workflows + - Activities + - Workers + - Python SDK + - Strands Agents + - Serverless +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. + + +This guide builds a data-analysis agent that can continue a conversation after the compute running it has stopped. A +Temporal Workflow holds the conversation and coordinates each turn. Strands defines how the agent uses a model and +tools. Amazon Bedrock AgentCore Runtime supplies serverless compute for the Temporal Worker, and AgentCore Code +Interpreter supplies an isolated environment for running code. + +The result separates the lifetime of the agent from the lifetime of its compute. The Workflow can remain open for days +or months without keeping an AgentCore Runtime active. + +## See what you will build + +The agent has one Workflow Execution for each conversation. A client sends prompts to an `ask` Update handler and +receives the agent's answer as the Update result. The Workflow waits without using Worker compute between prompts. + +When a prompt arrives and no Worker is polling, Temporal Cloud starts Worker capacity on AgentCore Runtime. The Worker +reconstructs the Workflow from its Event History, runs the next agent turn, and retires after it becomes idle. A later +prompt can run on a different Worker without starting a new conversation. + +```mermaid +sequenceDiagram + participant Client + participant Temporal as Temporal Cloud + participant Runtime1 as AgentCore Runtime A + participant AWS as Bedrock and Code Interpreter + participant Runtime2 as AgentCore Runtime B + + Client->>Temporal: Start conversation Workflow + Temporal->>Runtime1: Start Worker capacity + Client->>Temporal: Update: ask first question + Runtime1->>AWS: Model and tool Activities + AWS-->>Runtime1: Results + Runtime1-->>Temporal: Update result + Temporal-->>Client: First answer + Runtime1-->>Runtime1: Become idle and drain + Note over Temporal: Workflow waits without Worker compute + Client->>Temporal: Update: ask follow-up question + Temporal->>Runtime2: Start new Worker capacity + Runtime2->>Temporal: Replay Event History + Runtime2->>AWS: Model and tool Activities + AWS-->>Runtime2: Results + Runtime2-->>Temporal: Update result + Temporal-->>Client: Follow-up answer +``` + +Start with the +[durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent). +It contains the AgentCore project, Runtime handler, IAM policy, and Code Interpreter Activity used in this guide. + +You need Python 3.10 or later, `uv`, AWS credentials, access to a Bedrock model, and a local Temporal development server. +Follow [Set up your local Python environment](/develop/python/set-up-your-local-python) before continuing. + +Clone the sample repository and install the application dependencies: + +```bash +git clone https://github.com/temporalio/documentation-sdk-code-examples.git +cd documentation-sdk-code-examples/python-agentcore-durable-agent +uv sync +``` + +## Give each system one job + +The three systems operate at different levels: + +| System | Job in this application | +|---|---| +| Strands Agents | Defines the system prompt, tools, model interaction, and agent loop for one turn. | +| Temporal | Gives the conversation a durable identity, persists its progress, delivers later prompts, and retries model and tool calls as Activities. | +| AgentCore Runtime | Starts isolated AWS compute that hosts a Temporal Worker when the Task Queue needs capacity. | + +Amazon Bedrock performs model inference. AgentCore Code Interpreter runs code in a managed sandbox when the model +chooses that tool. + +The Workflow Id is the durable identity of the agent conversation. An AgentCore Runtime session is compute that can +host a Worker for part of that conversation. Do not require the same Runtime session or Worker process to handle every +turn. + +## Build the agent locally + +The [durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent) +defines `execute_code` as a Temporal Activity. It uses the Workflow Id as the Code Interpreter session name so two +Workflow Executions handled by the same process do not share a sandbox. The name does not make the sandbox durable +across Worker replacement. + + +[python-agentcore-durable-agent/activities.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/activities.py) +```py +@activity.defn +def execute_code( + code: str, language: LanguageType = LanguageType.PYTHON +) -> dict[str, Any]: + interpreter = AgentCoreCodeInterpreter( + region=os.environ.get("AWS_REGION", "us-west-2"), + session_name=activity.info().workflow_id, + ) + return interpreter.execute_code( + ExecuteCodeAction(type="executeCode", code=code, language=language) + ) + + +``` + + +The Activity boundary gives the tool call a separate timeout, Retry Policy, and result in Event History. It also keeps +AWS calls out of deterministic Workflow code. + +Define a Workflow that accepts multiple prompts: + + +[python-agentcore-durable-agent/workflows.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/workflows.py) +```py +@workflow.defn +class DurableAgentWorkflow: + def __init__(self) -> None: + self._done = False + self._lock = asyncio.Lock() + self._agent = TemporalAgent( + model="bedrock", + start_to_close_timeout=timedelta(seconds=60), + system_prompt=SYSTEM_PROMPT, + tools=[ + activity_as_tool( + execute_code, + start_to_close_timeout=timedelta(minutes=2), + ) + ], + ) + + @workflow.update + async def ask(self, prompt: str) -> str: + async with self._lock: + result = await self._agent.invoke_async(prompt) + return str(result).strip() + + @workflow.signal + def finish(self) -> None: + self._done = True + + @workflow.run + async def run(self) -> None: + await workflow.wait_condition(lambda: self._done) + await workflow.wait_condition(workflow.all_handlers_finished) + + +``` + + +`TemporalAgent` is a Strands `Agent` adapted to run inside a Workflow. It retains the Strands message list between +calls to `invoke_async`. The Temporal Strands plugin runs model calls as Activities, and `activity_as_tool` runs the +Code Interpreter tool as an Activity. Configure retries through Temporal Activity Retry Policies rather than a Strands +retry strategy. + +The lock makes the agent process one prompt at a time. The `run` method waits until the `finish` Signal arrives, so the +Workflow remains available between turns. This wait is durable and does not keep a Python process running. + +Register `DurableAgentWorkflow`, `execute_code`, and `StrandsPlugin` on a local Worker. The +[sample Worker](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/local_worker.py) +also creates the executor required by the synchronous `execute_code` Activity: + + +[python-agentcore-durable-agent/local_worker.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/local_worker.py) +```py +async def main() -> None: + client = await Client.connect( + "localhost:7233", + plugins=[StrandsPlugin()], + ) + + with ThreadPoolExecutor(max_workers=4) as activity_executor: + worker = Worker( + client, + task_queue=TASK_QUEUE, + workflows=[DurableAgentWorkflow], + activities=[execute_code], + activity_executor=activity_executor, + ) + await worker.run() + + +``` + + +Start the Temporal development server, then start the Worker in another terminal: + +```bash +temporal server start-dev +``` + +```bash +uv run python local_worker.py +``` + +The sample's chat client starts a Workflow and sends each prompt as an Update: + + +[python-agentcore-durable-agent/chat.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/chat.py) +```py +async def main() -> None: + client = await Client.connect( + "localhost:7233", + plugins=[StrandsPlugin()], + ) + handle = await client.start_workflow( + DurableAgentWorkflow.run, + id=f"durable-agent-{uuid.uuid4()}", + task_queue=TASK_QUEUE, + ) + + while prompt := input("You: "): + if prompt == "/finish": + await handle.signal(DurableAgentWorkflow.finish) + return + answer = await handle.execute_update(DurableAgentWorkflow.ask, prompt) + print(f"Agent: {answer}") + + +``` + + +Run the client in a third terminal: + +```bash +uv run python chat.py +``` + +Ask a question that requires calculation, then ask a follow-up that depends on the first answer. Enter `/finish` to +close the Workflow. In the Temporal Web UI, the Event History shows the `ask` Update, model Activities, and +`execute_code` Activity for each turn. + +## Run the Worker on AgentCore Runtime + +Local development uses a continuously running Worker. On AgentCore Runtime, the Worker starts inside the Runtime's HTTP +handler and returns when its idle policy decides to release the compute. + +The AgentCore Runtime handler registers the `DurableAgentWorkflow` and `execute_code` definitions from +[Build the agent locally](#build-the-agent-locally). It adds Worker Versioning and the Activity-based idle tracker from +the [Python AgentCore Worker guide](/develop/python/workers/serverless-workers/agentcore#stop-and-drain-the-worker), then +runs the Worker inside the Runtime handler: + + +[python-agentcore-durable-agent/agentcore_worker.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/agentcore_worker.py) +```py +@app.entrypoint +@app.async_task +async def invoke(payload: dict) -> dict: + client = await Client.connect( + required_env("TEMPORAL_ADDRESS"), + namespace=required_env("TEMPORAL_NAMESPACE"), + api_key=required_env("TEMPORAL_API_KEY"), + tls=True, + plugins=[StrandsPlugin()], + ) + tracker = ActivityTracker() + + with ThreadPoolExecutor(max_workers=4) as activity_executor: + worker = Worker( + client, + task_queue=os.environ.get("TEMPORAL_TASK_QUEUE", TASK_QUEUE), + workflows=[DurableAgentWorkflow], + activities=[execute_code], + activity_executor=activity_executor, + interceptors=[tracker], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=os.environ.get( + "TEMPORAL_DEPLOYMENT_NAME", DEPLOYMENT_NAME + ), + build_id=os.environ.get("TEMPORAL_BUILD_ID", BUILD_ID), + ), + use_worker_versioning=True, + default_versioning_behavior=VersioningBehavior.PINNED, + ), + graceful_shutdown_timeout=DRAIN, + ) + async with worker: + await tracker.wait_until_idle(DEBOUNCE) + + return {"message": "Worker drained"} + + +``` + + +The invocation payload does not contain a user prompt. Temporal invokes the Runtime endpoint to add Worker capacity. +Clients continue to start and message Workflows through the Temporal Client. + +The Runtime does not need a copy of the conversation in a local file or global variable. When a new Worker receives a +Workflow Task, Temporal replays the Workflow's Event History and restores the `TemporalAgent` message list before new +model or tool calls run. + +## Deploy the Serverless Worker + +Install the AgentCore CLI and generate the CDK project used by the sample's Runtime definition: + +```bash +npm install -g @aws/agentcore +./bootstrap-agentcore-project.sh +``` + +Follow [Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore) +to deploy the existing AgentCore project and configure its Worker Deployment Version. + +For this application, use the same values in each place: + +| Setting | Tutorial value | +|---|---| +| Runtime entrypoint | `agentcore_worker.py` | +| Task Queue | `durable-agent` | +| Worker Deployment name | `durable-agent-agentcore` | +| Build ID | A version for this code, such as `1.0.0` | + +The AgentCore Runtime execution role needs permission to invoke Bedrock and Code Interpreter. The separate role that +Temporal Cloud assumes needs permission to invoke the AgentCore Runtime endpoint. The deployment guide creates and +configures the second role. + +## Talk to the deployed agent + +Start one conversation Workflow. This command returns immediately while the Workflow remains open: + +```bash +temporal workflow start \ + --workflow-id durable-agent-alice \ + --type DurableAgentWorkflow \ + --task-queue durable-agent +``` + +Send the first prompt as an Update and wait for the reply: + +```bash +temporal workflow update execute \ + --workflow-id durable-agent-alice \ + --name ask \ + --input '"A film festival has 7 screens with 4 showings per screen. How many screenings can it schedule?"' +``` + +Temporal starts AgentCore Worker capacity because the Task Queue has work. After the turn completes and the idle period +expires, the Runtime handler drains the Worker and returns. Confirm this in the AgentCore logs: + +```bash +agentcore logs --runtime +``` + +After the Worker has retired, send a follow-up that depends on the first turn: + +```bash +temporal workflow update execute \ + --workflow-id durable-agent-alice \ + --name ask \ + --input '"If we add two screenings to the total you calculated, what is the new total?"' +``` + +Temporal starts capacity again. The new Worker reconstructs the existing Workflow and its Strands messages, so the +agent can interpret "the total you calculated" without depending on the previous Worker process. + +End the conversation when it no longer needs to accept prompts: + +```bash +temporal workflow signal \ + --workflow-id durable-agent-alice \ + --name finish +``` + +## Test recovery + +Worker retirement between turns tests one form of recovery. You can also interrupt compute while a model or tool +Activity is running. Start a prompt that takes long enough to observe, find the active Runtime session identifier in the +AgentCore logs, and stop that session: + +```bash +aws bedrock-agentcore stop-runtime-session \ + --agent-runtime-arn \ + --runtime-session-id \ + --region +``` + +For the required IAM permission and API behavior, see +[Stop a running session](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-stop-session.html). + +The Activity attempt running on that Worker is interrupted. Temporal keeps the Workflow state and schedules the +Activity again according to its Retry Policy. Serverless Workers starts new AgentCore capacity to process the Task. In +the Temporal Web UI, inspect the Activity attempts and confirm that the Workflow continues without restarting the +conversation. + +An Activity can run more than once if its Worker stops after making an external change but before reporting completion. +Use an idempotency key for tools that change external state. The Workflow Id plus a stable operation identifier is a +common choice. Code execution used only to calculate an answer does not make an external business change, so it is a +safe recovery demonstration. + +## Decide where state belongs + +Place state according to how long it must survive and which system uses it: + +| State | Location | Reason | +|---|---|---| +| Current conversation and agent progress | Temporal Workflow | It must survive Worker and Runtime replacement. | +| Completed model and tool call results | Temporal Event History | Activity results let replay restore completed progress without repeating successful calls. | +| Approvals, timers, and long waits | Temporal Workflow | These are part of the agent's durable control flow. | +| Knowledge shared across conversations | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html), accessed from an Activity | It belongs to the user or application rather than one Workflow Execution. | +| Credentials for AWS and external systems | [AgentCore Identity](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/identity.html) or an AWS secret store | Workflow state should not contain credentials. | +| Tool access and authorization | [AgentCore Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html) and [Policy](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy.html) | These services control how tools are reached and whether a call is allowed. | +| Temporary Worker caches | AgentCore Runtime session | They can improve performance but must be safe to lose. | +| Code Interpreter variables and files | Code Interpreter session | They last only for that tool session. Store required outputs durably before relying on them later. | +| Large files and datasets | Object storage, with a reference in the Workflow | Event History is not intended for large application objects. | + +The Strands message list is Workflow state in this design. Temporal reconstructs it through Event History when another +Worker continues the Workflow. Do not use Event History as unlimited chat or object storage. For conversations that +accumulate many turns, use [Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) +to start a new Event History while carrying forward the messages the next execution needs. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 3dc8c6ee45..4655bfde08 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -2,7 +2,7 @@ id: agentcore title: Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime sidebar_label: Amazon Bedrock AgentCore -description: Deploy a Python Serverless Worker to AgentCore Runtime and configure Temporal Cloud to invoke its endpoint. +description: Deploy an existing Python Worker to AgentCore Runtime and configure Temporal Cloud to start capacity when Task Queue demand increases. slug: /production-deployment/worker-deployments/serverless-workers/agentcore toc_max_heading_level: 4 tags: @@ -20,20 +20,24 @@ import TabItem from '@theme/TabItem'; Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. -This guide walks through deploying a Python [Serverless Worker](/serverless-workers) to Amazon Bedrock AgentCore -Runtime. Temporal invokes the Runtime endpoint when the Worker Controller Instance needs Worker capacity. - -The guide uses the -[Python Strands AgentCore sample](https://github.com/temporalio/samples-python/tree/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent). -The deployment procedure applies to other Python Workers that use the same AgentCore Runtime handler. For the Worker -implementation and lifecycle, see +This guide deploys an existing Python [Serverless Worker](/serverless-workers) to Amazon Bedrock AgentCore Runtime and +configures Temporal Cloud to start Worker capacity. It assumes that you already have a Temporal Worker and an AgentCore +project. For the Worker implementation and lifecycle, see [Serverless Workers on Amazon Bedrock AgentCore Runtime - Python SDK](/develop/python/workers/serverless-workers/agentcore). +If you are still deciding how to structure your agent, Workflow, and Activities, see the +[Python Strands AgentCore sample](https://github.com/temporalio/samples-python/tree/schoeff/strands-agent/bedrock_agentcore/strands-agent) +for a complete application. + ## Prerequisites {/* #prerequisites */} - A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release. - A Temporal Cloud API key that can connect to the Namespace. - [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later, configured for your Namespace. +- An existing Python Temporal Worker with an + [AgentCore Runtime handler](/develop/python/workers/serverless-workers/agentcore#runtime-handler). +- An AgentCore project that packages the Worker and contains `agentcore/agentcore.json`, `agentcore/aws-targets.json`, + and the generated AgentCore CDK project. - An AWS account in an [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). - The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed and configured with credentials for that account. @@ -41,64 +45,13 @@ implementation and lifecycle, see installed with `npm install -g @aws/agentcore`. - The [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed and bootstrapped in the target account and Region. -- Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/) installed. - Permission to create AgentCore resources, CloudFormation stacks, and IAM roles. See [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). -The sample agent calls an Amazon Bedrock model and uses AgentCore Code Interpreter. To run the sample without changing -it, make sure both services are available to your AWS account in the target Region. - -## 1. Prepare the Worker {/* #prepare-worker */} - -Clone the sample repository and check out the AgentCore sample branch: - -```bash -git clone https://github.com/temporalio/samples-python.git -cd samples-python -git checkout schoeff/strands-agent -cd bedrock_agentcore/strands-agent -``` - -The sample contains these deployment files: - -| File | Purpose | -| --- | --- | -| [`agentcore_worker.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/agentcore_worker.py) | Defines the AgentCore Runtime handler and starts the Temporal Worker. | -| [`workflows.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/workflows.py) | Defines the sample Workflow. | -| [`activities.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/activities.py) | Defines the sample Activity. | -| [`agentcore/agentcore.json`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/agentcore/agentcore.json) | Configures the Runtime, endpoint, environment, and lifecycle. | -| [`agentcore/aws-targets.json`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/agentcore/aws-targets.json) | Selects the AWS account and Region. | - -The Runtime handler registers `StrandsAgentWorkflow` and `execute_code` on the Worker. To deploy your own application, -replace those registrations with your Workflow and Activity Definitions. Keep the AgentCore handler, Worker Versioning -configuration, and shutdown policy. Every Workflow must declare a -[versioning behavior](/worker-versioning/#versioning-behaviors), or the Worker must set a default behavior. - -## 2. Configure the AgentCore project {/* #configure-project */} - -The AgentCore CLI reads the project from `agentcore/agentcore.json` and deploys it to a target in -`agentcore/aws-targets.json`. - -### Select the AWS account and Region {/* #select-account-region */} - -Replace the account and Region in `agentcore/aws-targets.json`: - -```json -[ - { - "name": "default", - "account": "", - "region": "" - } -] -``` - -The Region must support AgentCore Runtime and any AWS services that the Worker's Activities call. - -### Configure the Runtime {/* #configure-runtime */} +## 1. Configure the Worker Runtime {/* #configure-worker-runtime */} -In `agentcore/agentcore.json`, set the Temporal connection, Task Queue, Worker Deployment name, and Build ID under -`envVars`: +In `agentcore/agentcore.json`, configure the Runtime with the Temporal connection, Task Queue, Worker Deployment name, +and Build ID: ```json { @@ -115,101 +68,93 @@ In `agentcore/agentcore.json`, set the Temporal connection, Task Queue, Worker D }, { "name": "TEMPORAL_TASK_QUEUE", - "value": "agentcore-strands-task-queue" + "value": "" }, { "name": "TEMPORAL_DEPLOYMENT_NAME", - "value": "agentcore-strands-agent-python" + "value": "" }, { "name": "TEMPORAL_BUILD_ID", - "value": "1.0.0" + "value": "" } ``` -The deployment name and Build ID must match the values you use when you create the Worker Deployment Version in -[Step 5](#create-worker-deployment-version). The Task Queue must match the Task Queue used to start the Workflow. -For the sample, also set `AWS_REGION` to the Region in `aws-targets.json` so its Bedrock model and Code Interpreter -calls stay in that Region. +The Task Queue must match the Task Queue used by your application. The deployment name and Build ID must match the +Worker Deployment Version that you create in [Step 4](#create-worker-deployment-version). -The sample stores the Temporal Cloud API key in `envVars` to keep the example short. Do not commit a populated API key. -For a production deployment, store the key in AWS Secrets Manager, grant the Runtime execution role permission to read -it, and load it in the Runtime handler. The AgentCore CLI creates the Runtime execution role during deployment. This -role is separate from the invocation role that Temporal assumes in [Step 4](#configure-iam). - -The sample uses a CodeZip build and a public network: +The Runtime definition must use your Worker handler as its entrypoint and provide a named endpoint for Temporal. The +following fragment uses a public network so the Worker can reach Temporal Cloud: ```json { - "build": "CodeZip", "entrypoint": "agentcore_worker.py", - "codeLocation": ".", - "runtimeVersion": "PYTHON_3_12", "networkMode": "PUBLIC", "protocol": "HTTP", - "authorizerType": "AWS_IAM" + "authorizerType": "AWS_IAM", + "endpoints": { + "temporal": { + "version": 1, + "description": "Invoked by Temporal Cloud Serverless Workers" + } + } } ``` -`CodeZip` lets the AgentCore CLI package the Python code without Docker. `PUBLIC` gives the Worker outbound network -access to Temporal Cloud. The `AWS_IAM` authorizer lets Temporal invoke the endpoint by assuming an IAM role in your -AWS account. +If you use a VPC instead, configure outbound access from the VPC to your Temporal Cloud Namespace. Temporal invokes the +named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). -Keep the named `temporal` endpoint in the sample configuration. Temporal invokes this endpoint rather than AgentCore's -`DEFAULT` endpoint. For the endpoint and Runtime version relationship, see -[Worker Versioning on AgentCore Runtime](/serverless-workers/agentcore/#worker-versioning). +Do not commit a populated Temporal Cloud API key. For a production deployment, store it in AWS Secrets Manager, grant +the Runtime execution role permission to read it, and load it in the Runtime handler. The Runtime execution role is +separate from the invocation role that Temporal assumes. -## 3. Deploy the Runtime and endpoint {/* #deploy-runtime */} +## 2. Deploy the Worker Runtime {/* #deploy-runtime */} -From the sample directory, run: +From the AgentCore project directory, validate and deploy the project: ```bash -./bin/create-runtime.sh +agentcore validate +agentcore deploy --target -y ``` -The script creates the AgentCore CDK scaffold on its first run. It then validates the project, packages the Worker and -its dependencies, and runs `agentcore deploy`. AgentCore creates the Runtime execution role, Runtime version, named -endpoint, and CloudWatch log group. +AgentCore packages the Worker and its dependencies, deploys the Runtime, and creates the named endpoint. Check the deployed resources: ```bash -agentcore status --runtime temporal_strands_worker --json +agentcore status --runtime --json agentcore status --type runtime-endpoint --json ``` -Record both of these values from the output: +Record the Runtime ARN and the ARN of the named endpoint. You use the Runtime ARN to scope the invocation role and give +the endpoint ARN to Temporal Cloud. -- The **Runtime ARN**, which you use to scope the invocation role in [Step 4](#configure-iam). -- The **Runtime endpoint ARN** for the named `temporal` endpoint, which you give Temporal in - [Step 5](#create-worker-deployment-version). +## 3. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} -## 4. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} +Temporal Cloud assumes an IAM role in your AWS account to get the named endpoint and invoke the Runtime. Choose an +External ID of at least five characters. Use the same value in the role trust policy and the Worker Deployment Version. +The External ID prevents a [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) +attack. -Temporal Cloud assumes an IAM role in your AWS account to get the named endpoint and invoke the Runtime. The role is -not the Runtime execution role and does not run your Worker code. - -Choose an External ID of at least five characters. Use the same value in the role trust policy and the Worker -Deployment Version. The External ID prevents a -[confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attack. - -The sample includes a -[CloudFormation template](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/iam-role-for-temporal-agentcore-invoke.yaml) -and a script that deploys it. Pass the Runtime ARN with a trailing wildcard so the policy covers the Runtime and its -endpoints: +[Download the CloudFormation template](/files/temporal-cloud-serverless-worker-agentcore-role.yaml), then deploy it. +Pass the Runtime ARN with a trailing wildcard so the policy covers the Runtime and its endpoints: ```bash -AWS_REGION= ./bin/mk-invoke-role.sh \ - temporal-agentcore-invoke \ - \ - '*' +aws cloudformation create-stack \ + --stack-name \ + --template-body file://temporal-cloud-serverless-worker-agentcore-role.yaml \ + --parameters \ + ParameterKey=AssumeRoleExternalId,ParameterValue= \ + ParameterKey=AgentRuntimeARNs,ParameterValue='*' \ + --capabilities CAPABILITY_NAMED_IAM \ + --region ``` Wait for the CloudFormation stack to finish: ```bash aws cloudformation wait stack-create-complete \ - --stack-name temporal-agentcore-invoke \ + --stack-name \ --region ``` @@ -217,20 +162,19 @@ Then retrieve the invocation role ARN: ```bash aws cloudformation describe-stacks \ - --stack-name temporal-agentcore-invoke \ + --stack-name \ --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' \ --output text \ --region ``` The role grants `bedrock-agentcore:InvokeAgentRuntime` and `bedrock-agentcore:GetAgentRuntimeEndpoint` on the configured -Runtime resources. Record the role ARN for the next step. +Runtime resources. This role does not run the Worker code. -## 5. Create the Worker Deployment Version {/* #create-worker-deployment-version */} +## 4. Create the Worker Deployment Version {/* #create-worker-deployment-version */} Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) whose compute -configuration points to the named AgentCore Runtime endpoint. The deployment name and Build ID must match the Runtime -environment variables from [Step 2](#configure-runtime). +configuration points to the named AgentCore Runtime endpoint. @@ -238,15 +182,15 @@ environment variables from [Step 2](#configure-runtime). In the Temporal Cloud UI, open your Namespace and select **Workers** > **Create Worker Deployment**. Provide these values: -- **Name**: `agentcore-strands-agent-python`. -- **Build ID**: `1.0.0`. +- **Name**: the value of `TEMPORAL_DEPLOYMENT_NAME` in the Runtime environment. +- **Build ID**: the value of `TEMPORAL_BUILD_ID` in the Runtime environment. - **Compute Provider**: select **Amazon Bedrock AgentCore Runtime**. -- **Runtime endpoint ARN**: the named endpoint ARN from [Step 3](#deploy-runtime). -- **IAM role ARN**: the invocation role ARN from [Step 4](#configure-iam). -- **External ID**: the External ID from [Step 4](#configure-iam). +- **Runtime endpoint ARN**: the named endpoint ARN from [Step 2](#deploy-runtime). +- **IAM role ARN**: the invocation role ARN from [Step 3](#configure-iam). +- **External ID**: the External ID from [Step 3](#configure-iam). Save the Worker Deployment. When you create a version through the UI, the version is automatically current. Continue -to [Step 7](#verify-deployment). +to [Step 6](#verify-worker-startup). @@ -256,7 +200,7 @@ First, create the Worker Deployment if it does not already exist: ```bash temporal worker deployment create \ --namespace \ - --name agentcore-strands-agent-python + --name ``` Then create the version with the AgentCore compute configuration: @@ -264,20 +208,14 @@ Then create the version with the AgentCore compute configuration: ```bash temporal worker deployment create-version \ --namespace \ - --deployment-name agentcore-strands-agent-python \ - --build-id 1.0.0 \ + --deployment-name \ + --build-id \ --aws-agentcore-endpoint-arn \ --aws-agentcore-assume-role-arn \ --aws-agentcore-assume-role-external-id ``` -| Flag | Description | -| --- | --- | -| `--deployment-name` | Worker Deployment name. Must match `TEMPORAL_DEPLOYMENT_NAME` in the Runtime environment. | -| `--build-id` | Worker Deployment Version Build ID. Must match `TEMPORAL_BUILD_ID` in the Runtime environment. | -| `--aws-agentcore-endpoint-arn` | ARN of the named AgentCore Runtime endpoint that Temporal invokes. | -| `--aws-agentcore-assume-role-arn` | IAM role Temporal assumes to invoke the endpoint. This is the CloudFormation stack output from Step 4, not the Runtime execution role. | -| `--aws-agentcore-assume-role-external-id` | External ID configured in the invocation role trust policy. | +The deployment name and Build ID must match the values in the Runtime environment. @@ -286,46 +224,29 @@ To check whether Temporal can reach the endpoint, open the Worker Deployment Ver select **Actions** > **Validate Connection**. This checks that Temporal can assume the invocation role, get the named endpoint, and invoke the Runtime. -## 6. Set the version as current {/* #set-current-version */} +## 5. Set the version as current {/* #set-current-version */} If you used the Temporal CLI, set the version as current: ```bash temporal worker deployment set-current-version \ --namespace \ - --deployment-name agentcore-strands-agent-python \ - --build-id 1.0.0 + --deployment-name \ + --build-id ``` This command asks you to confirm because it changes which version receives new Tasks. Pass `--yes` to skip the prompt. If you created the version in the Temporal Cloud UI, it is already current. -## 7. Verify the deployment {/* #verify-deployment */} +## 6. Verify Worker startup {/* #verify-worker-startup */} -Install the sample dependencies and export the same Temporal connection values that you configured for the Runtime: - -```bash -uv sync -export TEMPORAL_ADDRESS=..tmprl.cloud:7233 -export TEMPORAL_NAMESPACE=. -export TEMPORAL_API_KEY= -``` - -Start the sample Workflow from your local machine: - -```bash -uv run python starter.py "Calculate the first 10 Fibonacci numbers." -``` - -The starter sends the Workflow to `agentcore-strands-task-queue`. When no Worker is polling, Temporal invokes -the AgentCore Runtime endpoint. The Runtime starts the Worker, and the Worker processes the Workflow and its Activities. +Submit work to the configured Task Queue using your application. When no Worker is polling, Temporal invokes the named +AgentCore Runtime endpoint. The Runtime starts the Worker, and the Worker polls and processes Tasks. You can confirm the deployment in these places: -- **Temporal Cloud UI**: Open the Workflow Execution and confirm that its Event History progresses. -- **AgentCore logs**: Run `agentcore logs --runtime temporal_strands_worker` to see the Worker start and process Tasks. -- **Temporal CLI**: Run `temporal workflow show --workflow-id agentcore-strands-workflow-id-1` to inspect the Event - History. - -For the sample Workflow and agent implementation, see -[`workflows.py`](https://github.com/temporalio/samples-python/blob/6fd0c9e879e85c4403bf8c1c591f7394fa60bed2/bedrock_agentcore/strands-agent/workflows.py). +- **Temporal Cloud UI**: Open the Worker Deployment Version and confirm that the connection is valid and a Worker has + polled the Task Queue. +- **AgentCore logs**: Run `agentcore logs --runtime ` to see the Worker start and process Tasks. +- **Temporal CLI**: Run `temporal worker deployment describe --name ` to inspect the deployment and + current version. diff --git a/sidebars.js b/sidebars.js index f30fabd864..459d22e436 100644 --- a/sidebars.js +++ b/sidebars.js @@ -2179,6 +2179,7 @@ module.exports = { id: 'guides/index', }, items: [ + 'guides/durable-agent-on-agentcore', 'guides/entity-pattern-loyalty-points', 'guides/recover-without-restart', 'guides/route-specialized-workloads', diff --git a/snipsync.config.yaml b/snipsync.config.yaml index a1b6ba5c4f..5968edbb38 100644 --- a/snipsync.config.yaml +++ b/snipsync.config.yaml @@ -39,6 +39,9 @@ origins: ref: 'main' - owner: temporalio repo: sdk-go + - owner: temporalio + repo: documentation-sdk-code-examples + ref: docs/durable-agent-agentcore-sample targets: - docs diff --git a/src/components/GuidesGrid/guides-data.json b/src/components/GuidesGrid/guides-data.json index 9f05d5194e..8e6641a888 100644 --- a/src/components/GuidesGrid/guides-data.json +++ b/src/components/GuidesGrid/guides-data.json @@ -1,4 +1,13 @@ [ + { + "name": "Durable agent on AgentCore", + "description": + "Run a long-lived Strands agent with Temporal and serverless Worker compute on Amazon Bedrock AgentCore.", + "tags": ["AI agents"], + "sdk": "Python", + "href": "/guides/durable-agent-on-agentcore" + }, + { "name": "Customer loyalty program", "description": diff --git a/static/files/temporal-cloud-serverless-worker-agentcore-role.yaml b/static/files/temporal-cloud-serverless-worker-agentcore-role.yaml new file mode 100644 index 0000000000..a4d5b16504 --- /dev/null +++ b/static/files/temporal-cloud-serverless-worker-agentcore-role.yaml @@ -0,0 +1,69 @@ +# CloudFormation template for creating an IAM role that Temporal Cloud can assume to invoke AgentCore runtimes. +AWSTemplateFormatVersion: '2010-09-09' +Description: + Creates an IAM role that Temporal Cloud can assume to invoke Amazon Bedrock AgentCore runtimes for Serverless Workers. + +Parameters: + AssumeRoleExternalId: + Type: String + Description: A string you choose. Use the same value when creating the Worker Deployment Version. + AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' + MinLength: 5 + MaxLength: 45 + + AgentRuntimeARNs: + Type: CommaDelimitedList + Description: >- + Comma-separated list of AgentCore Runtime ARNs that Temporal may invoke. Append a wildcard to each Runtime ARN + to include its endpoints. + + RoleName: + Type: String + Default: 'Temporal-Cloud-Serverless-Worker' + +Resources: + TemporalCloudServerlessWorker: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${RoleName}-${AWS::StackName}' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: + - arn:aws:iam::902542641901:role/wci-lambda-invoke + - arn:aws:iam::160190466495:role/wci-lambda-invoke + - arn:aws:iam::819232936619:role/wci-lambda-invoke + - arn:aws:iam::829909441867:role/wci-lambda-invoke + - arn:aws:iam::354116250941:role/wci-lambda-invoke + Action: sts:AssumeRole + Condition: + StringEquals: + 'sts:ExternalId': !Ref AssumeRoleExternalId + Description: The role Temporal Cloud uses to invoke AgentCore runtimes for Serverless Workers + MaxSessionDuration: 3600 + + TemporalCloudAgentCoreInvokePermissions: + Type: AWS::IAM::Policy + Properties: + PolicyName: 'Temporal-Cloud-AgentCore-Invoke-Permissions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - bedrock-agentcore:InvokeAgentRuntime + - bedrock-agentcore:GetAgentRuntimeEndpoint + Resource: !Ref AgentRuntimeARNs + Roles: + - !Ref TemporalCloudServerlessWorker + +Outputs: + RoleARN: + Description: The ARN of the IAM role created for Temporal Cloud + Value: !GetAtt TemporalCloudServerlessWorker.Arn + + AgentRuntimeARNs: + Description: The AgentCore Runtime ARNs that Temporal may invoke + Value: !Join [', ', !Ref AgentRuntimeARNs] From 76f64fee22188ba503d0df7d303a819758aa28ba Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Fri, 11 Sep 2026 12:35:22 -0700 Subject: [PATCH 27/77] Clarify durable AgentCore tutorial architecture --- docs/guides/durable-agent-on-agentcore.mdx | 189 ++++++++++++--------- 1 file changed, 106 insertions(+), 83 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index b996fae4d7..157250f2a3 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -28,74 +28,118 @@ Interpreter supplies an isolated environment for running code. The result separates the lifetime of the agent from the lifetime of its compute. The Workflow can remain open for days or months without keeping an AgentCore Runtime active. -## See what you will build - -The agent has one Workflow Execution for each conversation. A client sends prompts to an `ask` Update handler and -receives the agent's answer as the Update result. The Workflow waits without using Worker compute between prompts. - -When a prompt arrives and no Worker is polling, Temporal Cloud starts Worker capacity on AgentCore Runtime. The Worker -reconstructs the Workflow from its Event History, runs the next agent turn, and retires after it becomes idle. A later -prompt can run on a different Worker without starting a new conversation. - -```mermaid -sequenceDiagram - participant Client - participant Temporal as Temporal Cloud - participant Runtime1 as AgentCore Runtime A - participant AWS as Bedrock and Code Interpreter - participant Runtime2 as AgentCore Runtime B - - Client->>Temporal: Start conversation Workflow - Temporal->>Runtime1: Start Worker capacity - Client->>Temporal: Update: ask first question - Runtime1->>AWS: Model and tool Activities - AWS-->>Runtime1: Results - Runtime1-->>Temporal: Update result - Temporal-->>Client: First answer - Runtime1-->>Runtime1: Become idle and drain - Note over Temporal: Workflow waits without Worker compute - Client->>Temporal: Update: ask follow-up question - Temporal->>Runtime2: Start new Worker capacity - Runtime2->>Temporal: Replay Event History - Runtime2->>AWS: Model and tool Activities - AWS-->>Runtime2: Results - Runtime2-->>Temporal: Update result - Temporal-->>Client: Follow-up answer -``` - -Start with the -[durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent). -It contains the AgentCore project, Runtime handler, IAM policy, and Code Interpreter Activity used in this guide. - -You need Python 3.10 or later, `uv`, AWS credentials, access to a Bedrock model, and a local Temporal development server. -Follow [Set up your local Python environment](/develop/python/set-up-your-local-python) before continuing. +## What you will build -Clone the sample repository and install the application dependencies: +The agent has one Workflow Execution for each conversation. The application starts that Workflow and sends prompts to +an `ask` Update handler through Temporal. It does not send prompts to the AgentCore Runtime endpoint. Each Update +returns the agent's answer to the application. -```bash -git clone https://github.com/temporalio/documentation-sdk-code-examples.git -cd documentation-sdk-code-examples/python-agentcore-durable-agent -uv sync -``` +The agent uses Amazon Bedrock for model inference and AgentCore Code Interpreter for calculations. After a turn, its +Worker retires while the Workflow remains open. A later prompt starts new Worker capacity and continues the same +conversation. -## Give each system one job +## Architecture -The three systems operate at different levels: +The application combines several pieces, but each one has a separate responsibility: | System | Job in this application | |---|---| -| Strands Agents | Defines the system prompt, tools, model interaction, and agent loop for one turn. | -| Temporal | Gives the conversation a durable identity, persists its progress, delivers later prompts, and retries model and tool calls as Activities. | -| AgentCore Runtime | Starts isolated AWS compute that hosts a Temporal Worker when the Task Queue needs capacity. | +| Application client | Starts and sends prompts to the Workflow through the Temporal Client. | +| Temporal Workflow | Represents one conversation and coordinates its turns, waits, and recovery. | +| Strands Agents | Defines the system prompt, tools, model interaction, and agent loop for each turn. | +| Temporal Worker | Runs Workflow Tasks and Activities from the Task Queue. | +| AgentCore Runtime | Supplies isolated AWS compute that hosts the Worker when the Task Queue needs capacity. | +| Amazon Bedrock | Performs model inference when the Workflow runs a model Activity. | +| AgentCore Code Interpreter | Runs code in a managed sandbox when the model selects that tool. | + +A conversation turn moves through those pieces as follows: + +1. Temporal records the prompt and places a Workflow Task on the Task Queue. +2. If no Worker is polling, Temporal starts Worker capacity on AgentCore Runtime. +3. The Worker processes the Workflow Task. Strands determines whether the turn needs a model call or tool call, and the + Workflow schedules each call as an Activity. +4. The Worker returns the answer through the Update. The Workflow then waits without using Worker compute. +5. After the Worker becomes idle, it drains and the AgentCore Runtime handler returns. +6. A later prompt repeats the process. Another Worker can reconstruct the Workflow from Event History and continue the + same conversation. + +### Keep the conversation in the Workflow + +Use the Workflow Id as the durable identity of the conversation. The Workflow holds the Strands message list and the +current control state. Temporal records the events needed to reconstruct that state, including prompts and completed +model and tool Activity results. + +The Workflow is not a continuously running Python process. After a turn, it can wait for the next Update without a +Worker assigned to it. When another Workflow Task arrives, any compatible Worker polling the Task Queue can process +it. Temporal replays Event History on that Worker before the Workflow continues. + +### Separate agent behavior from external calls + +Strands defines the behavior within a turn. You configure the agent's instructions and available tools, then Strands +decides when to call the model, select a tool, or return an answer. + +The Temporal Strands plugin changes where those calls execute. Model calls and tools that perform I/O run as Temporal +Activities instead of running directly in Workflow code. Temporal records each completed result and gives each call its +own timeout, Retry Policy, and failure boundary. + +### Treat AgentCore Runtime as Worker compute -Amazon Bedrock performs model inference. AgentCore Code Interpreter runs code in a managed sandbox when the model -chooses that tool. +An AgentCore Runtime session hosts a Temporal Worker. The Runtime session is not the conversation and does not need to +remain active while the Workflow waits. One Runtime session can process Tasks for multiple Workflow Executions, and +later Tasks for one Workflow Execution can run in another Runtime session. -The Workflow Id is the durable identity of the agent conversation. An AgentCore Runtime session is compute that can -host a Worker for part of that conversation. Do not require the same Runtime session or Worker process to handle every -turn. +This means the Worker process and its local files or variables must be safe to replace. State that the conversation +needs after replacement belongs in the Workflow or another durable store. AgentCore services such as Code Interpreter +and Memory remain available to Activities, but they do not replace the Workflow's execution state. -## Build the agent locally +### Place state according to its lifetime + +| State | Location | Reason | +|---|---|---| +| Current conversation and agent progress | Temporal Workflow | It must survive Worker and Runtime replacement. | +| Completed model and tool call results | Temporal Event History | Activity results let replay restore completed progress without repeating successful calls. | +| Approvals, timers, and long waits | Temporal Workflow | These are part of the agent's durable control flow. | +| Knowledge shared across conversations | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html), accessed from an Activity | It belongs to the user or application rather than one Workflow Execution. | +| Credentials for AWS and external systems | [AgentCore Identity](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/identity.html) or an AWS secret store | Workflow state should not contain credentials. | +| Tool access and authorization | [AgentCore Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html) and [Policy](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy.html) | These services control how tools are reached and whether a call is allowed. | +| Temporary Worker caches | AgentCore Runtime session | They can improve performance but must be safe to lose. | +| Code Interpreter variables and files | Code Interpreter session | They last only for that tool session. Store required outputs durably before relying on them later. | +| Large files and datasets | Object storage, with a reference in the Workflow | Event History is not intended for large application objects. | + +The Strands message list is Workflow state in this design. Temporal reconstructs it through Event History when another +Worker continues the Workflow. Do not use Event History as unlimited chat or object storage. For conversations that +accumulate many turns, use [Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) +to start a new Event History while carrying forward the messages the next execution needs. + +## Prerequisites + +To build and run the agent locally, you need: + +- Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/). +- The [Temporal CLI](/cli/setup-cli) to run a local Temporal development server. +- AWS credentials with access to the Bedrock model selected by Strands and permission to use AgentCore Code + Interpreter. The sample includes the required Code Interpreter IAM policy. + +To deploy the Worker, you also need: + +- A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release. +- An AWS account in an [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). +- The AWS and AgentCore tools and permissions listed in the + [Serverless Worker deployment prerequisites](/production-deployment/worker-deployments/serverless-workers/agentcore#prerequisites). + +This guide uses the +[durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent), +which contains the AgentCore project, Runtime handler, IAM policy, and Code Interpreter Activity. Clone the sample +repository and install the application dependencies: + +```bash +git clone --branch docs/durable-agent-agentcore-sample --single-branch \ + https://github.com/temporalio/documentation-sdk-code-examples.git +cd documentation-sdk-code-examples/python-agentcore-durable-agent +uv sync +``` + +## 1. Build the agent locally {/* #build-the-agent-locally */} The [durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent) defines `execute_code` as a Temporal Activity. It uses the Workflow Id as the Code Interpreter session name so two @@ -247,7 +291,7 @@ Ask a question that requires calculation, then ask a follow-up that depends on t close the Workflow. In the Temporal Web UI, the Event History shows the `ask` Update, model Activities, and `execute_code` Activity for each turn. -## Run the Worker on AgentCore Runtime +## 2. Run the Worker on AgentCore Runtime {/* #run-the-worker-on-agentcore-runtime */} Local development uses a continuously running Worker. On AgentCore Runtime, the Worker starts inside the Runtime's HTTP handler and returns when its idle policy decides to release the compute. @@ -308,7 +352,7 @@ The Runtime does not need a copy of the conversation in a local file or global v Workflow Task, Temporal replays the Workflow's Event History and restores the `TemporalAgent` message list before new model or tool calls run. -## Deploy the Serverless Worker +## 3. Deploy the Serverless Worker {/* #deploy-the-serverless-worker */} Install the AgentCore CLI and generate the CDK project used by the sample's Runtime definition: @@ -333,7 +377,7 @@ The AgentCore Runtime execution role needs permission to invoke Bedrock and Code Temporal Cloud assumes needs permission to invoke the AgentCore Runtime endpoint. The deployment guide creates and configures the second role. -## Talk to the deployed agent +## 4. Talk to the deployed agent {/* #talk-to-the-deployed-agent */} Start one conversation Workflow. This command returns immediately while the Workflow remains open: @@ -380,7 +424,7 @@ temporal workflow signal \ --name finish ``` -## Test recovery +## 5. Test recovery {/* #test-recovery */} Worker retirement between turns tests one form of recovery. You can also interrupt compute while a model or tool Activity is running. Start a prompt that takes long enough to observe, find the active Runtime session identifier in the @@ -405,24 +449,3 @@ An Activity can run more than once if its Worker stops after making an external Use an idempotency key for tools that change external state. The Workflow Id plus a stable operation identifier is a common choice. Code execution used only to calculate an answer does not make an external business change, so it is a safe recovery demonstration. - -## Decide where state belongs - -Place state according to how long it must survive and which system uses it: - -| State | Location | Reason | -|---|---|---| -| Current conversation and agent progress | Temporal Workflow | It must survive Worker and Runtime replacement. | -| Completed model and tool call results | Temporal Event History | Activity results let replay restore completed progress without repeating successful calls. | -| Approvals, timers, and long waits | Temporal Workflow | These are part of the agent's durable control flow. | -| Knowledge shared across conversations | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html), accessed from an Activity | It belongs to the user or application rather than one Workflow Execution. | -| Credentials for AWS and external systems | [AgentCore Identity](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/identity.html) or an AWS secret store | Workflow state should not contain credentials. | -| Tool access and authorization | [AgentCore Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html) and [Policy](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy.html) | These services control how tools are reached and whether a call is allowed. | -| Temporary Worker caches | AgentCore Runtime session | They can improve performance but must be safe to lose. | -| Code Interpreter variables and files | Code Interpreter session | They last only for that tool session. Store required outputs durably before relying on them later. | -| Large files and datasets | Object storage, with a reference in the Workflow | Event History is not intended for large application objects. | - -The Strands message list is Workflow state in this design. Temporal reconstructs it through Event History when another -Worker continues the Workflow. Do not use Event History as unlimited chat or object storage. For conversations that -accumulate many turns, use [Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) -to start a new Event History while carrying forward the messages the next execution needs. From 3fed5190dbe3f72b996a775e25033ce247fb7b54 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Fri, 11 Sep 2026 16:53:01 -0700 Subject: [PATCH 28/77] Condense AgentCore tutorial architecture --- docs/guides/durable-agent-on-agentcore.mdx | 105 +++++++-------------- 1 file changed, 34 insertions(+), 71 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 157250f2a3..6bc423ce8c 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -21,9 +21,9 @@ import { ReleaseNoteHeader } from '@site/src/components'; This guide builds a data-analysis agent that can continue a conversation after the compute running it has stopped. A -Temporal Workflow holds the conversation and coordinates each turn. Strands defines how the agent uses a model and -tools. Amazon Bedrock AgentCore Runtime supplies serverless compute for the Temporal Worker, and AgentCore Code -Interpreter supplies an isolated environment for running code. +Temporal Workflow coordinates each turn and preserves the state needed to continue. Strands defines how the agent uses +a model and tools. Amazon Bedrock AgentCore Runtime supplies serverless compute for the Temporal Worker, and AgentCore +Code Interpreter supplies an isolated environment for running code. The result separates the lifetime of the agent from the lifetime of its compute. The Workflow can remain open for days or months without keeping an AgentCore Runtime active. @@ -40,76 +40,39 @@ conversation. ## Architecture -The application combines several pieces, but each one has a separate responsibility: +The application sends prompts to a Temporal Workflow through an Update. The Workflow identifies the conversation and +records its execution progress. When its Task Queue has work, Serverless Workers starts an AgentCore Runtime session +that hosts a Temporal Worker. A later Task can run on a different Runtime session because Temporal reconstructs the +Workflow from Event History before it continues. + +Strands runs the agent loop for each turn. The Temporal Strands integration schedules model calls and tool calls as +Activities. Each call has its own timeout, Retry Policy, and recorded result. After the Worker returns the answer, the +Workflow can wait for another prompt without keeping an AgentCore Runtime session active. + +```mermaid +flowchart LR + APP[Application] -->|Prompts and replies| WF[Temporal Workflow] + WF --> TQ[Task Queue] + TQ --> W[Temporal Worker
AgentCore Runtime session A or B] + W --> AWS[Bedrock and
AgentCore services] + W --> STORE[External conversation
and artifact storage] + WF -.->|Durable references| STORE +``` + +Place state according to how long it must remain available: -| System | Job in this application | +| State | Location | |---|---| -| Application client | Starts and sends prompts to the Workflow through the Temporal Client. | -| Temporal Workflow | Represents one conversation and coordinates its turns, waits, and recovery. | -| Strands Agents | Defines the system prompt, tools, model interaction, and agent loop for each turn. | -| Temporal Worker | Runs Workflow Tasks and Activities from the Task Queue. | -| AgentCore Runtime | Supplies isolated AWS compute that hosts the Worker when the Task Queue needs capacity. | -| Amazon Bedrock | Performs model inference when the Workflow runs a model Activity. | -| AgentCore Code Interpreter | Runs code in a managed sandbox when the model selects that tool. | - -A conversation turn moves through those pieces as follows: - -1. Temporal records the prompt and places a Workflow Task on the Task Queue. -2. If no Worker is polling, Temporal starts Worker capacity on AgentCore Runtime. -3. The Worker processes the Workflow Task. Strands determines whether the turn needs a model call or tool call, and the - Workflow schedules each call as an Activity. -4. The Worker returns the answer through the Update. The Workflow then waits without using Worker compute. -5. After the Worker becomes idle, it drains and the AgentCore Runtime handler returns. -6. A later prompt repeats the process. Another Worker can reconstruct the Workflow from Event History and continue the - same conversation. - -### Keep the conversation in the Workflow - -Use the Workflow Id as the durable identity of the conversation. The Workflow holds the Strands message list and the -current control state. Temporal records the events needed to reconstruct that state, including prompts and completed -model and tool Activity results. - -The Workflow is not a continuously running Python process. After a turn, it can wait for the next Update without a -Worker assigned to it. When another Workflow Task arrives, any compatible Worker polling the Task Queue can process -it. Temporal replays Event History on that Worker before the Workflow continues. - -### Separate agent behavior from external calls - -Strands defines the behavior within a turn. You configure the agent's instructions and available tools, then Strands -decides when to call the model, select a tool, or return an answer. - -The Temporal Strands plugin changes where those calls execute. Model calls and tools that perform I/O run as Temporal -Activities instead of running directly in Workflow code. Temporal records each completed result and gives each call its -own timeout, Retry Policy, and failure boundary. - -### Treat AgentCore Runtime as Worker compute - -An AgentCore Runtime session hosts a Temporal Worker. The Runtime session is not the conversation and does not need to -remain active while the Workflow waits. One Runtime session can process Tasks for multiple Workflow Executions, and -later Tasks for one Workflow Execution can run in another Runtime session. - -This means the Worker process and its local files or variables must be safe to replace. State that the conversation -needs after replacement belongs in the Workflow or another durable store. AgentCore services such as Code Interpreter -and Memory remain available to Activities, but they do not replace the Workflow's execution state. - -### Place state according to its lifetime - -| State | Location | Reason | -|---|---|---| -| Current conversation and agent progress | Temporal Workflow | It must survive Worker and Runtime replacement. | -| Completed model and tool call results | Temporal Event History | Activity results let replay restore completed progress without repeating successful calls. | -| Approvals, timers, and long waits | Temporal Workflow | These are part of the agent's durable control flow. | -| Knowledge shared across conversations | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html), accessed from an Activity | It belongs to the user or application rather than one Workflow Execution. | -| Credentials for AWS and external systems | [AgentCore Identity](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/identity.html) or an AWS secret store | Workflow state should not contain credentials. | -| Tool access and authorization | [AgentCore Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html) and [Policy](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy.html) | These services control how tools are reached and whether a call is allowed. | -| Temporary Worker caches | AgentCore Runtime session | They can improve performance but must be safe to lose. | -| Code Interpreter variables and files | Code Interpreter session | They last only for that tool session. Store required outputs durably before relying on them later. | -| Large files and datasets | Object storage, with a reference in the Workflow | Event History is not intended for large application objects. | - -The Strands message list is Workflow state in this design. Temporal reconstructs it through Event History when another -Worker continues the Workflow. Do not use Event History as unlimited chat or object storage. For conversations that -accumulate many turns, use [Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) -to start a new Event History while carrying forward the messages the next execution needs. +| Execution progress and bounded working context | Temporal Workflow | +| Large or unbounded conversation content, uploads, and artifacts | Durable external storage, with stable references in the Workflow | +| Knowledge shared across conversations, such as user preferences | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html), accessed from an Activity | +| Temporary caches and Code Interpreter files | AgentCore Runtime or tool session, when the application can tolerate losing them | + +For clarity, this sample keeps its complete Strands message list in Workflow state. That works for a bounded +conversation. For a conversation that can grow without a fixed limit, store its raw content externally and carry a +reference or bounded summary in the Workflow. Retrieve external content through an Activity before using it in a model +call. Use [Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) to start a new +Event History with only the references and working context that the next execution needs. ## Prerequisites From 3c02bebd5f4117139bad5a8bb6cfb18849aa7491 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Fri, 11 Sep 2026 17:05:44 -0700 Subject: [PATCH 29/77] Remove AgentCore Memory from tutorial architecture --- docs/guides/durable-agent-on-agentcore.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 6bc423ce8c..a530476864 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -65,7 +65,6 @@ Place state according to how long it must remain available: |---|---| | Execution progress and bounded working context | Temporal Workflow | | Large or unbounded conversation content, uploads, and artifacts | Durable external storage, with stable references in the Workflow | -| Knowledge shared across conversations, such as user preferences | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html), accessed from an Activity | | Temporary caches and Code Interpreter files | AgentCore Runtime or tool session, when the application can tolerate losing them | For clarity, this sample keeps its complete Strands message list in Workflow state. That works for a bounded From 1540c972b4473b4a47807ecf3c2836289d569174 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 12:50:44 -0700 Subject: [PATCH 30/77] Document background AgentCore Worker startup --- docs/guides/durable-agent-on-agentcore.mdx | 63 +++++++++------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index a530476864..462cd4b2d2 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -255,60 +255,49 @@ close the Workflow. In the Temporal Web UI, the Event History shows the `ask` Up ## 2. Run the Worker on AgentCore Runtime {/* #run-the-worker-on-agentcore-runtime */} -Local development uses a continuously running Worker. On AgentCore Runtime, the Worker starts inside the Runtime's HTTP -handler and returns when its idle policy decides to release the compute. +Local development uses a continuously running Worker. On AgentCore Runtime, the HTTP handler starts the Worker in a +background task and immediately returns an acknowledgment. The Worker continues polling until its idle policy decides +to release the compute. The AgentCore Runtime handler registers the `DurableAgentWorkflow` and `execute_code` definitions from [Build the agent locally](#build-the-agent-locally). It adds Worker Versioning and the Activity-based idle tracker from -the [Python AgentCore Worker guide](/develop/python/workers/serverless-workers/agentcore#stop-and-drain-the-worker), then -runs the Worker inside the Runtime handler: +the [Python AgentCore Worker guide](/develop/python/workers/serverless-workers/agentcore#stop-and-drain-the-worker). +The entry point registers the background Worker as an AgentCore asynchronous task, prevents another invocation in the +same Runtime session from starting a duplicate Worker, and clears the task after the Worker drains or fails: [python-agentcore-durable-agent/agentcore_worker.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/agentcore_worker.py) ```py +_worker: asyncio.Task[None] | None = None + + +async def _run_until_idle(task_id: int) -> None: + try: + await run_worker() + except Exception: + log.exception("worker failed in background task") + finally: + app.complete_async_task(task_id) + + @app.entrypoint -@app.async_task async def invoke(payload: dict) -> dict: - client = await Client.connect( - required_env("TEMPORAL_ADDRESS"), - namespace=required_env("TEMPORAL_NAMESPACE"), - api_key=required_env("TEMPORAL_API_KEY"), - tls=True, - plugins=[StrandsPlugin()], - ) - tracker = ActivityTracker() + global _worker + if _worker is not None and not _worker.done(): + return {"message": "Worker already polling", "task_queue": TASK_QUEUE} - with ThreadPoolExecutor(max_workers=4) as activity_executor: - worker = Worker( - client, - task_queue=os.environ.get("TEMPORAL_TASK_QUEUE", TASK_QUEUE), - workflows=[DurableAgentWorkflow], - activities=[execute_code], - activity_executor=activity_executor, - interceptors=[tracker], - deployment_config=WorkerDeploymentConfig( - version=WorkerDeploymentVersion( - deployment_name=os.environ.get( - "TEMPORAL_DEPLOYMENT_NAME", DEPLOYMENT_NAME - ), - build_id=os.environ.get("TEMPORAL_BUILD_ID", BUILD_ID), - ), - use_worker_versioning=True, - default_versioning_behavior=VersioningBehavior.PINNED, - ), - graceful_shutdown_timeout=DRAIN, - ) - async with worker: - await tracker.wait_until_idle(DEBOUNCE) + task_id = app.add_async_task("temporal-worker") + _worker = asyncio.create_task(_run_until_idle(task_id)) - return {"message": "Worker drained"} + return {"message": "Worker starting", "task_queue": TASK_QUEUE} ``` The invocation payload does not contain a user prompt. Temporal invokes the Runtime endpoint to add Worker capacity. -Clients continue to start and message Workflows through the Temporal Client. +The acknowledgment does not wait for the Worker to drain. AgentCore reports the Runtime as busy while the asynchronous +task is registered. Clients continue to start and message Workflows through the Temporal Client. The Runtime does not need a copy of the conversation in a local file or global variable. When a new Worker receives a Workflow Task, Temporal replays the Workflow's Event History and restores the `TemporalAgent` message list before new From 747c287a9a5de28c2507dcdf08dd883de9a21d40 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 13:29:09 -0700 Subject: [PATCH 31/77] Use Nova Lite in AgentCore tutorial --- docs/guides/durable-agent-on-agentcore.mdx | 18 +++++++++++++----- .../serverless-workers/agentcore.mdx | 4 +++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 462cd4b2d2..be3c070e5f 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -79,8 +79,8 @@ To build and run the agent locally, you need: - Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/). - The [Temporal CLI](/cli/setup-cli) to run a local Temporal development server. -- AWS credentials with access to the Bedrock model selected by Strands and permission to use AgentCore Code - Interpreter. The sample includes the required Code Interpreter IAM policy. +- AWS credentials with access to Amazon Nova Lite through Bedrock and permission to use AgentCore Code Interpreter. + The sample includes the required Code Interpreter IAM policy. To deploy the Worker, you also need: @@ -132,6 +132,10 @@ AWS calls out of deterministic Workflow code. Define a Workflow that accepts multiple prompts: +The sample sets `MODEL_NAME` to `nova-lite` and maps it to the Bedrock model identifier `amazon.nova-lite-v1:0` when it +configures `StrandsPlugin`. The Workflow refers to the registered model by name, so model construction and AWS access +remain in the Worker process. + [python-agentcore-durable-agent/workflows.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/workflows.py) ```py @@ -141,7 +145,7 @@ class DurableAgentWorkflow: self._done = False self._lock = asyncio.Lock() self._agent = TemporalAgent( - model="bedrock", + model=MODEL_NAME, start_to_close_timeout=timedelta(seconds=60), system_prompt=SYSTEM_PROMPT, tools=[ @@ -189,7 +193,9 @@ also creates the executor required by the synchronous `execute_code` Activity: async def main() -> None: client = await Client.connect( "localhost:7233", - plugins=[StrandsPlugin()], + plugins=[ + StrandsPlugin(models={MODEL_NAME: lambda: BedrockModel(model_id=MODEL_ID)}) + ], ) with ThreadPoolExecutor(max_workers=4) as activity_executor: @@ -224,7 +230,9 @@ The sample's chat client starts a Workflow and sends each prompt as an Update: async def main() -> None: client = await Client.connect( "localhost:7233", - plugins=[StrandsPlugin()], + plugins=[ + StrandsPlugin(models={MODEL_NAME: lambda: BedrockModel(model_id=MODEL_ID)}) + ], ) handle = await client.start_workflow( DurableAgentWorkflow.run, diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 4655bfde08..7e68ac7509 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -137,7 +137,8 @@ The External ID prevents a [confused deputy](https://docs.aws.amazon.com/IAM/lat attack. [Download the CloudFormation template](/files/temporal-cloud-serverless-worker-agentcore-role.yaml), then deploy it. -Pass the Runtime ARN with a trailing wildcard so the policy covers the Runtime and its endpoints: +Pass the Runtime ARN with a trailing wildcard so the policy covers the Runtime and its endpoints. The template names +the IAM role `-`. Keep the combined name within the IAM limit of 64 characters: ```bash aws cloudformation create-stack \ @@ -146,6 +147,7 @@ aws cloudformation create-stack \ --parameters \ ParameterKey=AssumeRoleExternalId,ParameterValue= \ ParameterKey=AgentRuntimeARNs,ParameterValue='*' \ + ParameterKey=RoleName,ParameterValue= \ --capabilities CAPABILITY_NAMED_IAM \ --region ``` From 047880cac8656a09794bd235dc42105058f8c879 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 13:49:33 -0700 Subject: [PATCH 32/77] Make AgentCore tutorial executable end to end --- docs/guides/durable-agent-on-agentcore.mdx | 180 +++++++++++++++++---- 1 file changed, 150 insertions(+), 30 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index be3c070e5f..871a08003e 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -78,7 +78,8 @@ Event History with only the references and working context that the next executi To build and run the agent locally, you need: - Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/). -- The [Temporal CLI](/cli/setup-cli) to run a local Temporal development server. +- [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later. This version adds the AgentCore + options used to create a Worker Deployment Version. - AWS credentials with access to Amazon Nova Lite through Bedrock and permission to use AgentCore Code Interpreter. The sample includes the required Code Interpreter IAM policy. @@ -89,10 +90,9 @@ To deploy the Worker, you also need: - The AWS and AgentCore tools and permissions listed in the [Serverless Worker deployment prerequisites](/production-deployment/worker-deployments/serverless-workers/agentcore#prerequisites). -This guide uses the -[durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent), -which contains the AgentCore project, Runtime handler, IAM policy, and Code Interpreter Activity. Clone the sample -repository and install the application dependencies: +## 1. Get and run the agent locally {/* #build-the-agent-locally */} + +Clone the sample repository and install the application dependencies: ```bash git clone --branch docs/durable-agent-agentcore-sample --single-branch \ @@ -101,8 +101,6 @@ cd documentation-sdk-code-examples/python-agentcore-durable-agent uv sync ``` -## 1. Build the agent locally {/* #build-the-agent-locally */} - The [durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent) defines `execute_code` as a Temporal Activity. It uses the Workflow Id as the Code Interpreter session name so two Workflow Executions handled by the same process do not share a sandbox. The name does not make the sandbox durable @@ -130,11 +128,9 @@ def execute_code( The Activity boundary gives the tool call a separate timeout, Retry Policy, and result in Event History. It also keeps AWS calls out of deterministic Workflow code. -Define a Workflow that accepts multiple prompts: - -The sample sets `MODEL_NAME` to `nova-lite` and maps it to the Bedrock model identifier `amazon.nova-lite-v1:0` when it -configures `StrandsPlugin`. The Workflow refers to the registered model by name, so model construction and AWS access -remain in the Worker process. +The sample defines a Workflow that accepts multiple prompts. It sets `MODEL_NAME` to `nova-lite` and maps it to the +Bedrock model identifier `amazon.nova-lite-v1:0` when it configures `StrandsPlugin`. The Workflow refers to the +registered model by name, so model construction and AWS access remain in the Worker process. [python-agentcore-durable-agent/workflows.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/workflows.py) @@ -261,14 +257,14 @@ Ask a question that requires calculation, then ask a follow-up that depends on t close the Workflow. In the Temporal Web UI, the Event History shows the `ask` Update, model Activities, and `execute_code` Activity for each turn. -## 2. Run the Worker on AgentCore Runtime {/* #run-the-worker-on-agentcore-runtime */} +## 2. Configure and deploy the Worker Runtime {/* #run-the-worker-on-agentcore-runtime */} Local development uses a continuously running Worker. On AgentCore Runtime, the HTTP handler starts the Worker in a background task and immediately returns an acknowledgment. The Worker continues polling until its idle policy decides to release the compute. The AgentCore Runtime handler registers the `DurableAgentWorkflow` and `execute_code` definitions from -[Build the agent locally](#build-the-agent-locally). It adds Worker Versioning and the Activity-based idle tracker from +[Get and run the agent locally](#build-the-agent-locally). It adds Worker Versioning and the Activity-based idle tracker from the [Python AgentCore Worker guide](/develop/python/workers/serverless-workers/agentcore#stop-and-drain-the-worker). The entry point registers the background Worker as an AgentCore asynchronous task, prevents another invocation in the same Runtime session from starting a duplicate Worker, and clears the task after the Worker drains or fails: @@ -311,32 +307,152 @@ The Runtime does not need a copy of the conversation in a local file or global v Workflow Task, Temporal replays the Workflow's Event History and restores the `TemporalAgent` message list before new model or tool calls run. -## 3. Deploy the Serverless Worker {/* #deploy-the-serverless-worker */} +Stop the local Worker and Temporal development server. In one terminal, export the Temporal Cloud and AWS settings +used by the rest of this guide. Replace the first two values with your Namespace details. Enter your API key at the +prompt: -Install the AgentCore CLI and generate the CDK project used by the sample's Runtime definition: +```bash +export TEMPORAL_ADDRESS="..tmprl.cloud:7233" +export TEMPORAL_NAMESPACE="." +printf "Temporal Cloud API key: " +read -rs TEMPORAL_API_KEY +printf "\n" +export TEMPORAL_API_KEY +export AWS_REGION="us-west-2" +``` + +Use an AgentCore-supported Region where your AWS credentials can invoke Amazon Nova Lite and Code Interpreter. The +Temporal variables also configure subsequent Temporal CLI commands. + +Install the AgentCore CLI and generate the CDK files used to deploy the sample: ```bash npm install -g @aws/agentcore ./bootstrap-agentcore-project.sh ``` -Follow [Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore) -to deploy the existing AgentCore project and configure its Worker Deployment Version. +Populate the sample's AgentCore configuration from those variables. The command gets the AWS account number from your +current AWS CLI credentials: + +```bash +uv run python configure_agentcore.py +``` -For this application, use the same values in each place: +The sample configuration uses these values throughout the deployment: | Setting | Tutorial value | |---|---| | Runtime entrypoint | `agentcore_worker.py` | | Task Queue | `durable-agent` | | Worker Deployment name | `durable-agent-agentcore` | -| Build ID | A version for this code, such as `1.0.0` | +| Build ID | `1.0.0` | +| Runtime endpoint name | `temporal` | + +The command writes your Temporal Cloud API key to `agentcore/agentcore.json`. Do not commit the populated file. For a +production deployment, store the key in AWS Secrets Manager and load it when the Runtime starts. + +Validate and deploy the Runtime: + +```bash +agentcore validate +agentcore deploy --target default --yes +``` + +AgentCore packages the Worker and its dependencies, creates its execution role, deploys the Runtime, and creates the +named endpoint. Retrieve the Runtime and endpoint ARNs for the next steps: + +```bash +export AGENT_RUNTIME_ARN="$( + aws bedrock-agentcore-control list-agent-runtimes \ + --region "$AWS_REGION" \ + --query "agentRuntimes[?agentRuntimeName=='TemporalDurableAgent_durable_agent_worker'].agentRuntimeArn | [0]" \ + --output text +)" +export AGENT_RUNTIME_ID="${AGENT_RUNTIME_ARN##*/}" +export RUNTIME_ENDPOINT_ARN="$( + aws bedrock-agentcore-control list-agent-runtime-endpoints \ + --agent-runtime-id "$AGENT_RUNTIME_ID" \ + --region "$AWS_REGION" \ + --query "runtimeEndpoints[?name=='temporal'].agentRuntimeEndpointArn | [0]" \ + --output text +)" +echo "$AGENT_RUNTIME_ARN" +echo "$RUNTIME_ENDPOINT_ARN" +``` + +Both commands must print an ARN before you continue. + +## 3. Grant Temporal access to the Runtime {/* #grant-temporal-access */} + +Temporal Cloud needs an IAM role that it can assume to invoke the Runtime endpoint. The cloned sample includes the +CloudFormation template for this role. Choose an External ID and short names for the stack and role: + +```bash +export EXTERNAL_ID="$(openssl rand -hex 16)" +export INVOCATION_STACK="ac-durable-invoke" +export INVOCATION_ROLE_NAME="TemporalSW" +``` + +Create the role. This role only lets Temporal get the endpoint and invoke the Runtime. The separate execution role +created by AgentCore runs the Worker and accesses Bedrock and Code Interpreter. + +```bash +aws cloudformation create-stack \ + --stack-name "$INVOCATION_STACK" \ + --template-body file://temporal-cloud-serverless-worker-agentcore-role.yaml \ + --parameters \ + ParameterKey=AssumeRoleExternalId,ParameterValue="$EXTERNAL_ID" \ + ParameterKey=AgentRuntimeARNs,ParameterValue="${AGENT_RUNTIME_ARN}*" \ + ParameterKey=RoleName,ParameterValue="$INVOCATION_ROLE_NAME" \ + --capabilities CAPABILITY_NAMED_IAM \ + --region "$AWS_REGION" + +aws cloudformation wait stack-create-complete \ + --stack-name "$INVOCATION_STACK" \ + --region "$AWS_REGION" + +export INVOCATION_ROLE_ARN="$( + aws cloudformation describe-stacks \ + --stack-name "$INVOCATION_STACK" \ + --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' \ + --output text \ + --region "$AWS_REGION" +)" +echo "$INVOCATION_ROLE_ARN" +``` + +The final command must print the new role ARN. + +## 4. Create the Serverless Worker deployment {/* #deploy-the-serverless-worker */} + +Create a Worker Deployment and a version that points to the AgentCore endpoint: + +```bash +temporal worker deployment create \ + --name durable-agent-agentcore + +temporal worker deployment create-version \ + --deployment-name durable-agent-agentcore \ + --build-id 1.0.0 \ + --aws-agentcore-endpoint-arn "$RUNTIME_ENDPOINT_ARN" \ + --aws-agentcore-assume-role-arn "$INVOCATION_ROLE_ARN" \ + --aws-agentcore-assume-role-external-id "$EXTERNAL_ID" + +temporal worker deployment set-current-version \ + --deployment-name durable-agent-agentcore \ + --build-id 1.0.0 \ + --yes +``` + +Creating the version causes Temporal to invoke the Runtime and wait for the Worker to register. The deployment name +and Build ID in these commands match the values packaged into the Runtime. Setting the version as current lets it +receive new Tasks on the `durable-agent` Task Queue. -The AgentCore Runtime execution role needs permission to invoke Bedrock and Code Interpreter. The separate role that -Temporal Cloud assumes needs permission to invoke the AgentCore Runtime endpoint. The deployment guide creates and -configures the second role. +You now have a deployed Runtime and a Worker Deployment Version that Temporal can start when the Task Queue needs +capacity. For more deployment options, see +[Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore). -## 4. Talk to the deployed agent {/* #talk-to-the-deployed-agent */} +## 5. Talk to the deployed agent {/* #talk-to-the-deployed-agent */} Start one conversation Workflow. This command returns immediately while the Workflow remains open: @@ -357,10 +473,13 @@ temporal workflow update execute \ ``` Temporal starts AgentCore Worker capacity because the Task Queue has work. After the turn completes and the idle period -expires, the Runtime handler drains the Worker and returns. Confirm this in the AgentCore logs: +expires, the Runtime handler drains the Worker and returns. Confirm this in the AgentCore logs. Wait until the log +contains `worker idle for 60.0s and drained`, then stop following the logs with `Ctrl+C`: ```bash -agentcore logs --runtime +aws logs tail "/aws/bedrock-agentcore/runtimes/${AGENT_RUNTIME_ID}-temporal" \ + --region "$AWS_REGION" \ + --follow ``` After the Worker has retired, send a follow-up that depends on the first turn: @@ -383,17 +502,18 @@ temporal workflow signal \ --name finish ``` -## 5. Test recovery {/* #test-recovery */} +## 6. Test recovery {/* #test-recovery */} Worker retirement between turns tests one form of recovery. You can also interrupt compute while a model or tool Activity is running. Start a prompt that takes long enough to observe, find the active Runtime session identifier in the AgentCore logs, and stop that session: ```bash +export RUNTIME_SESSION_ID="" aws bedrock-agentcore stop-runtime-session \ - --agent-runtime-arn \ - --runtime-session-id \ - --region + --agent-runtime-arn "$AGENT_RUNTIME_ARN" \ + --runtime-session-id "$RUNTIME_SESSION_ID" \ + --region "$AWS_REGION" ``` For the required IAM permission and API behavior, see From b5233279fcc000018921b131542f89679dd30ad7 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 14:17:51 -0700 Subject: [PATCH 33/77] Base AgentCore tutorial on Python sample --- .../workers/serverless-workers/agentcore.mdx | 60 ++- docs/guides/durable-agent-on-agentcore.mdx | 490 +++++------------- .../serverless-workers/agentcore.mdx | 2 +- snipsync.config.yaml | 4 - 4 files changed, 179 insertions(+), 377 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 2c5605ec7a..e4cbcf66bc 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -68,16 +68,16 @@ Worker. To set the behavior per Workflow instead, pass `versioning_behavior` to ## Start the Worker from the Runtime handler {/* #runtime-handler */} -AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler, and use `async_task` so -AgentCore keeps the Runtime active while the Worker polls: +AgentCore Runtime invokes an HTTP handler. Use `BedrockAgentCoreApp` to provide that handler. Register the Worker as an +asynchronous AgentCore task, then return an acknowledgment while the Worker continues polling in the background. The +sample stores the background task in `_worker` and uses it to prevent another invocation from starting a duplicate +Worker in the same Runtime session: -[bedrock_agentcore/strands-agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/5b0fe65efe934388d35eda430fb11df6899ce1d3/bedrock_agentcore/strands-agent/agentcore_worker.py) +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/9d5c46bed0f0f6f8a726fa91f371c4c83f232ba2/bedrock_agentcore/strands_agent/agentcore_worker.py) ```py -@app.entrypoint -@app.async_task # keeps /ping on "HealthyBusy" until this returns -async def invoke(payload: dict) -> dict: - """Poll until idle, then drain. The payload is unused: every call is a new session and new worker.""" +async def run_worker() -> None: + """Poll until idle, then drain.""" api_key = os.environ.get("TEMPORAL_API_KEY") or None client = await Client.connect( os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), @@ -87,15 +87,13 @@ async def invoke(payload: dict) -> dict: plugins=[StrandsPlugin()], ) - task_queue = os.environ.get("TEMPORAL_TASK_QUEUE", workflows.TASK_QUEUE) tracker = ActivityTracker() - - log.info("polling %s as %s/%s", task_queue, DEPLOYMENT_NAME, BUILD_ID) + log.info("polling %s as %s/%s", TASK_QUEUE, DEPLOYMENT_NAME, BUILD_ID) # execute_code is a sync Activity, so it needs an executor to block on. with ThreadPoolExecutor(max_workers=4) as activity_executor: worker = Worker( client, - task_queue=task_queue, + task_queue=TASK_QUEUE, workflows=[workflows.StrandsAgentWorkflow], activities=[execute_code], activity_executor=activity_executor, @@ -112,12 +110,40 @@ async def invoke(payload: dict) -> dict: async with worker: await tracker.wait_until_idle(DEBOUNCE) log.info("worker idle for %ss; drained", DEBOUNCE) - return {"message": "worker drained", "task_queue": task_queue} + + +async def _run_until_idle(task_id: int) -> None: + """Own the Worker's whole life, and always release the async task.""" + try: + await run_worker() + except Exception: + # Nothing awaits this task, so an error would otherwise be swallowed. + log.exception("worker failed in async task") + finally: + # Without this the session stays HealthyBusy until MaxLifetime. + app.complete_async_task(task_id) + + +@app.entrypoint +async def invoke(payload: dict) -> dict: + """Start the Worker and acknowledge. The payload is unused.""" + # Prevent duplicate workers since we exit early + global _worker + if _worker is not None and not _worker.done(): + log.info("worker already polling %s", TASK_QUEUE) + return {"message": "worker already polling", "task_queue": TASK_QUEUE} + + task_id = app.add_async_task("temporal-worker") + _worker = asyncio.create_task(_run_until_idle(task_id)) + + return {"message": "worker starting", "task_queue": TASK_QUEUE} ``` The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker -capacity. Applications start Workflows through the Temporal Client, as usual. +capacity. Applications start Workflows through the Temporal Client, as usual. `add_async_task` causes AgentCore to +report the Runtime as busy while the Worker polls. `complete_async_task` releases that status after the Worker drains +or fails. ## Configure the Temporal connection {/* #configure-connection */} @@ -132,19 +158,19 @@ For the supported connection variables, config-file format, and profiles, see ## Stop and drain the Worker {/* #stop-and-drain-the-worker */} AgentCore cannot tell when a Worker that is still polling has no Temporal work. The Runtime remains busy while the -`async_task` handler runs, so it can remain active until its eight-hour maximum lifetime. To release capacity sooner, -have the handler detect when the Worker has no useful work and return. +asynchronous task is registered, so it can remain active until its eight-hour maximum lifetime. To release capacity +sooner, have the handler detect when the Worker has no useful work and complete the asynchronous task. When the condition remains true for an idle period, leave the `async with worker` block. The Worker stops polling for new Tasks and gives in-flight Activities time to complete before the Runtime handler returns. The following example from the -[AgentCore sample Worker](https://github.com/temporalio/samples-python/blob/5b0fe65efe934388d35eda430fb11df6899ce1d3/bedrock_agentcore/strands-agent/agentcore_worker.py) +[AgentCore sample Worker](https://github.com/temporalio/samples-python/blob/9d5c46bed0f0f6f8a726fa91f371c4c83f232ba2/bedrock_agentcore/strands_agent/agentcore_worker.py) defines an `ActivityTracker`. It uses an [Activity inbound Interceptor](/develop/python/workers/interceptors) to count running Activities. -[bedrock_agentcore/strands-agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/5b0fe65efe934388d35eda430fb11df6899ce1d3/bedrock_agentcore/strands-agent/agentcore_worker.py) +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/9d5c46bed0f0f6f8a726fa91f371c4c83f232ba2/bedrock_agentcore/strands_agent/agentcore_worker.py) ```py # How long the Worker keeps polling after it goes idle. DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 871a08003e..e1b754d9c8 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -2,7 +2,7 @@ id: durable-agent-on-agentcore title: Build a durable agent on Amazon Bedrock AgentCore sidebar_label: Durable agent on AgentCore -description: A Temporal Workflow preserves conversation state while AgentCore Runtime supplies serverless Worker compute for a Strands agent. +description: Run a Strands agent as a Temporal Workflow while AgentCore Runtime supplies serverless Worker compute and a code execution tool. toc_max_heading_level: 3 author: n/a tags: @@ -20,128 +20,83 @@ import { ReleaseNoteHeader } from '@site/src/components'; Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. -This guide builds a data-analysis agent that can continue a conversation after the compute running it has stopped. A -Temporal Workflow coordinates each turn and preserves the state needed to continue. Strands defines how the agent uses -a model and tools. Amazon Bedrock AgentCore Runtime supplies serverless compute for the Temporal Worker, and AgentCore -Code Interpreter supplies an isolated environment for running code. - -The result separates the lifetime of the agent from the lifetime of its compute. The Workflow can remain open for days -or months without keeping an AgentCore Runtime active. +This guide deploys a Strands agent as a Temporal Serverless Worker on Amazon Bedrock AgentCore Runtime. The agent uses +Amazon Bedrock for model inference and AgentCore Code Interpreter to run Python. ## What you will build -The agent has one Workflow Execution for each conversation. The application starts that Workflow and sends prompts to -an `ask` Update handler through Temporal. It does not send prompts to the AgentCore Runtime endpoint. Each Update -returns the agent's answer to the application. +The sample accepts one prompt and runs one Workflow Execution. The Workflow asks the model to answer the prompt. The +model can call Code Interpreter through a Temporal Activity before returning its answer. -The agent uses Amazon Bedrock for model inference and AgentCore Code Interpreter for calculations. After a turn, its -Worker retires while the Workflow remains open. A later prompt starts new Worker capacity and continues the same -conversation. +Your local client starts the Workflow through Temporal. When the Task Queue needs a Worker, Temporal starts an +AgentCore Runtime session. The Worker processes the Workflow and Activity Tasks, then drains after 60 seconds without +an Activity starting or finishing. ## Architecture -The application sends prompts to a Temporal Workflow through an Update. The Workflow identifies the conversation and -records its execution progress. When its Task Queue has work, Serverless Workers starts an AgentCore Runtime session -that hosts a Temporal Worker. A later Task can run on a different Runtime session because Temporal reconstructs the -Workflow from Event History before it continues. +The Workflow contains the Strands agent loop. The Temporal Strands integration runs model calls as Activities. The +Code Interpreter tool is also an Activity, so model and tool calls have their own retries, timeouts, and recorded +results. -Strands runs the agent loop for each turn. The Temporal Strands integration schedules model calls and tool calls as -Activities. Each call has its own timeout, Retry Policy, and recorded result. After the Worker returns the answer, the -Workflow can wait for another prompt without keeping an AgentCore Runtime session active. +AgentCore Runtime hosts the Temporal Worker. It does not receive the user's prompt. Temporal invokes the Runtime +endpoint only to add Worker capacity, and the application sends the prompt through the Temporal Client. ```mermaid flowchart LR - APP[Application] -->|Prompts and replies| WF[Temporal Workflow] - WF --> TQ[Task Queue] - TQ --> W[Temporal Worker
AgentCore Runtime session A or B] - W --> AWS[Bedrock and
AgentCore services] - W --> STORE[External conversation
and artifact storage] - WF -.->|Durable references| STORE + APP[Local client] -->|Start with prompt| WF[Temporal Workflow] + WF -->|Workflow and Activity Tasks| W[Temporal Worker
on AgentCore Runtime] + W --> MODEL[Amazon Bedrock] + W --> TOOL[AgentCore
Code Interpreter] ``` -Place state according to how long it must remain available: - -| State | Location | -|---|---| -| Execution progress and bounded working context | Temporal Workflow | -| Large or unbounded conversation content, uploads, and artifacts | Durable external storage, with stable references in the Workflow | -| Temporary caches and Code Interpreter files | AgentCore Runtime or tool session, when the application can tolerate losing them | - -For clarity, this sample keeps its complete Strands message list in Workflow state. That works for a bounded -conversation. For a conversation that can grow without a fixed limit, store its raw content externally and carry a -reference or bounded summary in the Workflow. Retrieve external content through an Activity before using it in a model -call. Use [Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) to start a new -Event History with only the references and working context that the next execution needs. +This sample completes after one answer. To support a conversation, keep the Workflow open and accept later prompts +through an Update or Signal. Store bounded conversation state, or references to externally stored content, in the +Workflow. Use the Workflow Id as the conversation identifier. Do not depend on one AgentCore Runtime session handling +every turn. ## Prerequisites -To build and run the agent locally, you need: - -- Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/). -- [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later. This version adds the AgentCore - options used to create a Worker Deployment Version. -- AWS credentials with access to Amazon Nova Lite through Bedrock and permission to use AgentCore Code Interpreter. - The sample includes the required Code Interpreter IAM policy. - -To deploy the Worker, you also need: - - A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release. -- An AWS account in an [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). -- The AWS and AgentCore tools and permissions listed in the - [Serverless Worker deployment prerequisites](/production-deployment/worker-deployments/serverless-workers/agentcore#prerequisites). - -## 1. Get and run the agent locally {/* #build-the-agent-locally */} - -Clone the sample repository and install the application dependencies: +- A Temporal Cloud API key that can connect to the Namespace. +- [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later. +- Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/). +- Node.js 20 or later and the + [AgentCore CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html). +- The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) configured for your AWS + account. +- The [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed and bootstrapped in an + [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). +- AWS permissions to deploy AgentCore resources, CloudFormation stacks, and IAM roles. See + [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). +- Access to the Amazon Bedrock model that Strands selects in the target Region. + +## 1. Get the sample + +Clone the branch from the +[Strands Agent on Bedrock AgentCore sample PR](https://github.com/temporalio/samples-python/pull/360), then install its +Python dependencies: ```bash -git clone --branch docs/durable-agent-agentcore-sample --single-branch \ - https://github.com/temporalio/documentation-sdk-code-examples.git -cd documentation-sdk-code-examples/python-agentcore-durable-agent +git clone --branch schoeff/strands-agent --single-branch \ + https://github.com/temporalio/samples-python.git +cd samples-python/bedrock_agentcore/strands_agent uv sync ``` -The [durable AgentCore sample](https://github.com/temporalio/documentation-sdk-code-examples/tree/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent) -defines `execute_code` as a Temporal Activity. It uses the Workflow Id as the Code Interpreter session name so two -Workflow Executions handled by the same process do not share a sandbox. The name does not make the sandbox durable -across Worker replacement. - - -[python-agentcore-durable-agent/activities.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/activities.py) -```py -@activity.defn -def execute_code( - code: str, language: LanguageType = LanguageType.PYTHON -) -> dict[str, Any]: - interpreter = AgentCoreCodeInterpreter( - region=os.environ.get("AWS_REGION", "us-west-2"), - session_name=activity.info().workflow_id, - ) - return interpreter.execute_code( - ExecuteCodeAction(type="executeCode", code=code, language=language) - ) +The cloned directory contains the Workflow, Activity, Runtime handler, AgentCore configuration, deployment scripts, +and IAM template used throughout this guide. +## 2. Examine the agent Workflow -``` - - -The Activity boundary gives the tool call a separate timeout, Retry Policy, and result in Event History. It also keeps -AWS calls out of deterministic Workflow code. +The sample creates a `TemporalAgent` with a system prompt and the `execute_code` tool: -The sample defines a Workflow that accepts multiple prompts. It sets `MODEL_NAME` to `nova-lite` and maps it to the -Bedrock model identifier `amazon.nova-lite-v1:0` when it configures `StrandsPlugin`. The Workflow refers to the -registered model by name, so model construction and AWS access remain in the Worker process. +[View `workflows.py` in the sample](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/workflows.py). - -[python-agentcore-durable-agent/workflows.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/workflows.py) ```py @workflow.defn -class DurableAgentWorkflow: +class StrandsAgentWorkflow: def __init__(self) -> None: - self._done = False - self._lock = asyncio.Lock() - self._agent = TemporalAgent( - model=MODEL_NAME, + self.agent = TemporalAgent( start_to_close_timeout=timedelta(seconds=60), system_prompt=SYSTEM_PROMPT, tools=[ @@ -152,164 +107,71 @@ class DurableAgentWorkflow: ], ) - @workflow.update - async def ask(self, prompt: str) -> str: - async with self._lock: - result = await self._agent.invoke_async(prompt) - return str(result).strip() - - @workflow.signal - def finish(self) -> None: - self._done = True - @workflow.run - async def run(self) -> None: - await workflow.wait_condition(lambda: self._done) - await workflow.wait_condition(workflow.all_handlers_finished) - - + async def run(self, prompt: str) -> str: + result = await self.agent.invoke_async(prompt) + return str(result) ``` - -`TemporalAgent` is a Strands `Agent` adapted to run inside a Workflow. It retains the Strands message list between -calls to `invoke_async`. The Temporal Strands plugin runs model calls as Activities, and `activity_as_tool` runs the -Code Interpreter tool as an Activity. Configure retries through Temporal Activity Retry Policies rather than a Strands -retry strategy. +`TemporalAgent` adapts the Strands agent loop to run in Workflow code. The Temporal Strands plugin schedules each model +call as an Activity. `activity_as_tool` makes `execute_code` another Activity when the model selects that tool. -The lock makes the agent process one prompt at a time. The `run` method waits until the `finish` Signal arrives, so the -Workflow remains available between turns. This wait is durable and does not keep a Python process running. +The `execute_code` Activity creates a Code Interpreter session using the Workflow Id as its session name: -Register `DurableAgentWorkflow`, `execute_code`, and `StrandsPlugin` on a local Worker. The -[sample Worker](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/local_worker.py) -also creates the executor required by the synchronous `execute_code` Activity: +[View `activities.py` in the sample](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/activities.py). - -[python-agentcore-durable-agent/local_worker.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/local_worker.py) ```py -async def main() -> None: - client = await Client.connect( - "localhost:7233", - plugins=[ - StrandsPlugin(models={MODEL_NAME: lambda: BedrockModel(model_id=MODEL_ID)}) - ], - ) - - with ThreadPoolExecutor(max_workers=4) as activity_executor: - worker = Worker( - client, - task_queue=TASK_QUEUE, - workflows=[DurableAgentWorkflow], - activities=[execute_code], - activity_executor=activity_executor, - ) - await worker.run() - - -``` - - -Start the Temporal development server, then start the Worker in another terminal: - -```bash -temporal server start-dev -``` - -```bash -uv run python local_worker.py -``` - -The sample's chat client starts a Workflow and sends each prompt as an Update: - - -[python-agentcore-durable-agent/chat.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/chat.py) -```py -async def main() -> None: - client = await Client.connect( - "localhost:7233", - plugins=[ - StrandsPlugin(models={MODEL_NAME: lambda: BedrockModel(model_id=MODEL_ID)}) - ], +@activity.defn +def execute_code( + code: str, language: LanguageType = LanguageType.PYTHON +) -> dict[str, Any]: + interpreter = AgentCoreCodeInterpreter( + region=os.environ.get("AWS_REGION", "us-west-2"), + session_name=activity.info().workflow_id, ) - handle = await client.start_workflow( - DurableAgentWorkflow.run, - id=f"durable-agent-{uuid.uuid4()}", - task_queue=TASK_QUEUE, + return interpreter.execute_code( + ExecuteCodeAction(type="executeCode", code=code, language=language) ) +``` - while prompt := input("You: "): - if prompt == "/finish": - await handle.signal(DurableAgentWorkflow.finish) - return - answer = await handle.execute_update(DurableAgentWorkflow.ask, prompt) - print(f"Agent: {answer}") - +Using the Workflow Id gives each Workflow Execution its own Code Interpreter sandbox. -``` - +## 3. Configure and deploy the Runtime -Run the client in a third terminal: +Install the AgentCore CLI: ```bash -uv run python chat.py +npm install -g @aws/agentcore ``` -Ask a question that requires calculation, then ask a follow-up that depends on the first answer. Enter `/finish` to -close the Workflow. In the Temporal Web UI, the Event History shows the `ask` Update, model Activities, and -`execute_code` Activity for each turn. - -## 2. Configure and deploy the Worker Runtime {/* #run-the-worker-on-agentcore-runtime */} - -Local development uses a continuously running Worker. On AgentCore Runtime, the HTTP handler starts the Worker in a -background task and immediately returns an acknowledgment. The Worker continues polling until its idle policy decides -to release the compute. - -The AgentCore Runtime handler registers the `DurableAgentWorkflow` and `execute_code` definitions from -[Get and run the agent locally](#build-the-agent-locally). It adds Worker Versioning and the Activity-based idle tracker from -the [Python AgentCore Worker guide](/develop/python/workers/serverless-workers/agentcore#stop-and-drain-the-worker). -The entry point registers the background Worker as an AgentCore asynchronous task, prevents another invocation in the -same Runtime session from starting a duplicate Worker, and clears the task after the Worker drains or fails: - - -[python-agentcore-durable-agent/agentcore_worker.py](https://github.com/temporalio/documentation-sdk-code-examples/blob/docs/durable-agent-agentcore-sample/python-agentcore-durable-agent/agentcore_worker.py) -```py -_worker: asyncio.Task[None] | None = None - - -async def _run_until_idle(task_id: int) -> None: - try: - await run_worker() - except Exception: - log.exception("worker failed in background task") - finally: - app.complete_async_task(task_id) - - -@app.entrypoint -async def invoke(payload: dict) -> dict: - global _worker - if _worker is not None and not _worker.done(): - return {"message": "Worker already polling", "task_queue": TASK_QUEUE} - - task_id = app.add_async_task("temporal-worker") - _worker = asyncio.create_task(_run_until_idle(task_id)) - - return {"message": "Worker starting", "task_queue": TASK_QUEUE} - - +Open `agentcore/aws-targets.json`. Replace the account number and Region with the AWS account and Region where you +will deploy the Runtime: + +```json +[ + { + "name": "default", + "description": "AWS account and Region for the Runtime", + "account": "", + "region": "" + } +] ``` - -The invocation payload does not contain a user prompt. Temporal invokes the Runtime endpoint to add Worker capacity. -The acknowledgment does not wait for the Worker to drain. AgentCore reports the Runtime as busy while the asynchronous -task is registered. Clients continue to start and message Workflows through the Temporal Client. +Open `agentcore/agentcore.json` and replace the placeholder values for `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, and +`TEMPORAL_API_KEY`. Set `AWS_REGION` to the same Region used in `aws-targets.json`. Keep these sample values unchanged: + +| Setting | Value | +|---|---| +| `TEMPORAL_TASK_QUEUE` | `agentcore-strands-task-queue` | +| `TEMPORAL_DEPLOYMENT_NAME` | `agentcore-strands-agent-python` | +| `TEMPORAL_BUILD_ID` | `1.0.0` | +| Runtime endpoint name | `temporal` | -The Runtime does not need a copy of the conversation in a local file or global variable. When a new Worker receives a -Workflow Task, Temporal replays the Workflow's Event History and restores the `TemporalAgent` message list before new -model or tool calls run. +Putting the API key in `agentcore.json` keeps the tutorial short. Do not commit the populated file. For a production +deployment, store the key in AWS Secrets Manager and load it when the Runtime starts. -Stop the local Worker and Temporal development server. In one terminal, export the Temporal Cloud and AWS settings -used by the rest of this guide. Replace the first two values with your Namespace details. Enter your API key at the -prompt: +Export the same connection values for the Temporal CLI and the sample client: ```bash export TEMPORAL_ADDRESS="..tmprl.cloud:7233" @@ -318,54 +180,23 @@ printf "Temporal Cloud API key: " read -rs TEMPORAL_API_KEY printf "\n" export TEMPORAL_API_KEY -export AWS_REGION="us-west-2" +export AWS_REGION="" ``` -Use an AgentCore-supported Region where your AWS credentials can invoke Amazon Nova Lite and Code Interpreter. The -Temporal variables also configure subsequent Temporal CLI commands. - -Install the AgentCore CLI and generate the CDK files used to deploy the sample: +Deploy the Runtime and its named endpoint: ```bash -npm install -g @aws/agentcore -./bootstrap-agentcore-project.sh +./bin/create-runtime.sh ``` -Populate the sample's AgentCore configuration from those variables. The command gets the AWS account number from your -current AWS CLI credentials: - -```bash -uv run python configure_agentcore.py -``` - -The sample configuration uses these values throughout the deployment: - -| Setting | Tutorial value | -|---|---| -| Runtime entrypoint | `agentcore_worker.py` | -| Task Queue | `durable-agent` | -| Worker Deployment name | `durable-agent-agentcore` | -| Build ID | `1.0.0` | -| Runtime endpoint name | `temporal` | - -The command writes your Temporal Cloud API key to `agentcore/agentcore.json`. Do not commit the populated file. For a -production deployment, store the key in AWS Secrets Manager and load it when the Runtime starts. - -Validate and deploy the Runtime: - -```bash -agentcore validate -agentcore deploy --target default --yes -``` - -AgentCore packages the Worker and its dependencies, creates its execution role, deploys the Runtime, and creates the -named endpoint. Retrieve the Runtime and endpoint ARNs for the next steps: +The script creates the AgentCore CDK project on its first run, validates the configuration, packages the sample, and +deploys it. Retrieve the Runtime and endpoint ARNs: ```bash export AGENT_RUNTIME_ARN="$( aws bedrock-agentcore-control list-agent-runtimes \ --region "$AWS_REGION" \ - --query "agentRuntimes[?agentRuntimeName=='TemporalDurableAgent_durable_agent_worker'].agentRuntimeArn | [0]" \ + --query "agentRuntimes[?agentRuntimeName=='TemporalStrandsAgent_temporal_strands_worker'].agentRuntimeArn | [0]" \ --output text )" export AGENT_RUNTIME_ID="${AGENT_RUNTIME_ARN##*/}" @@ -382,31 +213,23 @@ echo "$RUNTIME_ENDPOINT_ARN" Both commands must print an ARN before you continue. -## 3. Grant Temporal access to the Runtime {/* #grant-temporal-access */} +## 4. Grant Temporal access to the Runtime -Temporal Cloud needs an IAM role that it can assume to invoke the Runtime endpoint. The cloned sample includes the -CloudFormation template for this role. Choose an External ID and short names for the stack and role: +Choose an External ID, then use the sample's CloudFormation script to create the IAM role that Temporal Cloud assumes: ```bash export EXTERNAL_ID="$(openssl rand -hex 16)" -export INVOCATION_STACK="ac-durable-invoke" -export INVOCATION_ROLE_NAME="TemporalSW" +export INVOCATION_STACK="ac-strands-invoke" + +./bin/mk-invoke-role.sh \ + "$INVOCATION_STACK" \ + "$EXTERNAL_ID" \ + "${AGENT_RUNTIME_ARN}*" ``` -Create the role. This role only lets Temporal get the endpoint and invoke the Runtime. The separate execution role -created by AgentCore runs the Worker and accesses Bedrock and Code Interpreter. +Wait for the stack and retrieve the role ARN: ```bash -aws cloudformation create-stack \ - --stack-name "$INVOCATION_STACK" \ - --template-body file://temporal-cloud-serverless-worker-agentcore-role.yaml \ - --parameters \ - ParameterKey=AssumeRoleExternalId,ParameterValue="$EXTERNAL_ID" \ - ParameterKey=AgentRuntimeARNs,ParameterValue="${AGENT_RUNTIME_ARN}*" \ - ParameterKey=RoleName,ParameterValue="$INVOCATION_ROLE_NAME" \ - --capabilities CAPABILITY_NAMED_IAM \ - --region "$AWS_REGION" - aws cloudformation wait stack-create-complete \ --stack-name "$INVOCATION_STACK" \ --region "$AWS_REGION" @@ -421,110 +244,67 @@ export INVOCATION_ROLE_ARN="$( echo "$INVOCATION_ROLE_ARN" ``` -The final command must print the new role ARN. +This invocation role lets Temporal get the named endpoint and invoke the Runtime. It is separate from the Runtime +execution role that AgentCore created to run the Worker and access Code Interpreter. -## 4. Create the Serverless Worker deployment {/* #deploy-the-serverless-worker */} +## 5. Create the Serverless Worker deployment Create a Worker Deployment and a version that points to the AgentCore endpoint: ```bash temporal worker deployment create \ - --name durable-agent-agentcore + --name agentcore-strands-agent-python temporal worker deployment create-version \ - --deployment-name durable-agent-agentcore \ + --deployment-name agentcore-strands-agent-python \ --build-id 1.0.0 \ --aws-agentcore-endpoint-arn "$RUNTIME_ENDPOINT_ARN" \ --aws-agentcore-assume-role-arn "$INVOCATION_ROLE_ARN" \ --aws-agentcore-assume-role-external-id "$EXTERNAL_ID" temporal worker deployment set-current-version \ - --deployment-name durable-agent-agentcore \ + --deployment-name agentcore-strands-agent-python \ --build-id 1.0.0 \ --yes ``` Creating the version causes Temporal to invoke the Runtime and wait for the Worker to register. The deployment name -and Build ID in these commands match the values packaged into the Runtime. Setting the version as current lets it -receive new Tasks on the `durable-agent` Task Queue. +and Build ID match the values in `agentcore.json`. Setting the version as current lets it receive new Tasks on the +`agentcore-strands-task-queue` Task Queue. -You now have a deployed Runtime and a Worker Deployment Version that Temporal can start when the Task Queue needs -capacity. For more deployment options, see -[Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore). +## 6. Run the agent -## 5. Talk to the deployed agent {/* #talk-to-the-deployed-agent */} - -Start one conversation Workflow. This command returns immediately while the Workflow remains open: +Run the sample client with its default prompt: ```bash -temporal workflow start \ - --workflow-id durable-agent-alice \ - --type DurableAgentWorkflow \ - --task-queue durable-agent +uv run python starter.py ``` -Send the first prompt as an Update and wait for the reply: +Or provide a prompt: ```bash -temporal workflow update execute \ - --workflow-id durable-agent-alice \ - --name ask \ - --input '"A film festival has 7 screens with 4 showings per screen. How many screenings can it schedule?"' +uv run python starter.py \ + "Calculate the first 10 Fibonacci numbers and verify the result with Python." ``` -Temporal starts AgentCore Worker capacity because the Task Queue has work. After the turn completes and the idle period -expires, the Runtime handler drains the Worker and returns. Confirm this in the AgentCore logs. Wait until the log -contains `worker idle for 60.0s and drained`, then stop following the logs with `Ctrl+C`: - -```bash -aws logs tail "/aws/bedrock-agentcore/runtimes/${AGENT_RUNTIME_ID}-temporal" \ - --region "$AWS_REGION" \ - --follow -``` +`starter.py` starts `StrandsAgentWorkflow` and waits for its result. Temporal starts AgentCore Worker capacity, the +Workflow calls the model and Code Interpreter Activities, and the client prints the answer. The Workflow then +completes. After 60 seconds without an Activity starting or finishing, the Worker drains. -After the Worker has retired, send a follow-up that depends on the first turn: +Inspect the completed Workflow Execution: ```bash -temporal workflow update execute \ - --workflow-id durable-agent-alice \ - --name ask \ - --input '"If we add two screenings to the total you calculated, what is the new total?"' +temporal workflow show \ + --workflow-id agentcore-strands-workflow-id-1 ``` -Temporal starts capacity again. The new Worker reconstructs the existing Workflow and its Strands messages, so the -agent can interpret "the total you calculated" without depending on the previous Worker process. - -End the conversation when it no longer needs to accept prompts: +The Event History contains the model and `execute_code` Activities. Follow the Worker from AgentCore: ```bash -temporal workflow signal \ - --workflow-id durable-agent-alice \ - --name finish +agentcore logs --runtime temporal_strands_worker ``` -## 6. Test recovery {/* #test-recovery */} - -Worker retirement between turns tests one form of recovery. You can also interrupt compute while a model or tool -Activity is running. Start a prompt that takes long enough to observe, find the active Runtime session identifier in the -AgentCore logs, and stop that session: - -```bash -export RUNTIME_SESSION_ID="" -aws bedrock-agentcore stop-runtime-session \ - --agent-runtime-arn "$AGENT_RUNTIME_ARN" \ - --runtime-session-id "$RUNTIME_SESSION_ID" \ - --region "$AWS_REGION" -``` - -For the required IAM permission and API behavior, see -[Stop a running session](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-stop-session.html). - -The Activity attempt running on that Worker is interrupted. Temporal keeps the Workflow state and schedules the -Activity again according to its Retry Policy. Serverless Workers starts new AgentCore capacity to process the Task. In -the Temporal Web UI, inspect the Activity attempts and confirm that the Workflow continues without restarting the -conversation. - -An Activity can run more than once if its Worker stops after making an external change but before reporting completion. -Use an idempotency key for tools that change external state. The Workflow Id plus a stable operation identifier is a -common choice. Code execution used only to calculate an answer does not make an external business change, so it is a -safe recovery demonstration. +This one-turn example demonstrates durable model and tool execution on replaceable compute. A conversational version +would keep the Workflow open after the first answer and accept additional prompts through Workflow Updates. Each +conversation would use its own Workflow Id while Serverless Workers could run its Tasks on any compatible Runtime +session. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 7e68ac7509..940158312c 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -26,7 +26,7 @@ project. For the Worker implementation and lifecycle, see [Serverless Workers on Amazon Bedrock AgentCore Runtime - Python SDK](/develop/python/workers/serverless-workers/agentcore). If you are still deciding how to structure your agent, Workflow, and Activities, see the -[Python Strands AgentCore sample](https://github.com/temporalio/samples-python/tree/schoeff/strands-agent/bedrock_agentcore/strands-agent) +[Python Strands AgentCore sample](https://github.com/temporalio/samples-python/tree/schoeff/strands-agent/bedrock_agentcore/strands_agent) for a complete application. ## Prerequisites {/* #prerequisites */} diff --git a/snipsync.config.yaml b/snipsync.config.yaml index 5968edbb38..d18878e6c9 100644 --- a/snipsync.config.yaml +++ b/snipsync.config.yaml @@ -39,10 +39,6 @@ origins: ref: 'main' - owner: temporalio repo: sdk-go - - owner: temporalio - repo: documentation-sdk-code-examples - ref: docs/durable-agent-agentcore-sample - targets: - docs From 496b52c36c6c9074db39cb6e859419d39009b235 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 14:27:21 -0700 Subject: [PATCH 34/77] Sync AgentCore examples from Python sample --- .../workers/serverless-workers/agentcore.mdx | 8 ++++++-- docs/guides/durable-agent-on-agentcore.mdx | 20 +++++++++++++++---- snipsync.config.yaml | 2 ++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index e4cbcf66bc..48d533931b 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -74,7 +74,7 @@ sample stores the background task in `_worker` and uses it to prevent another in Worker in the same Runtime session: -[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/9d5c46bed0f0f6f8a726fa91f371c4c83f232ba2/bedrock_agentcore/strands_agent/agentcore_worker.py) +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/agentcore_worker.py) ```py async def run_worker() -> None: """Poll until idle, then drain.""" @@ -137,6 +137,8 @@ async def invoke(payload: dict) -> dict: _worker = asyncio.create_task(_run_until_idle(task_id)) return {"message": "worker starting", "task_queue": TASK_QUEUE} + + ``` @@ -170,7 +172,7 @@ defines an `ActivityTracker`. It uses an [Activity inbound Interceptor](/develop running Activities. -[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/9d5c46bed0f0f6f8a726fa91f371c4c83f232ba2/bedrock_agentcore/strands_agent/agentcore_worker.py) +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/agentcore_worker.py) ```py # How long the Worker keeps polling after it goes idle. DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) @@ -219,6 +221,8 @@ class _TrackedActivity(ActivityInboundInterceptor): finally: self._tracker.inflight -= 1 self._tracker.changed.set() + + ``` diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index e1b754d9c8..6cdfa5228c 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -90,12 +90,14 @@ and IAM template used throughout this guide. The sample creates a `TemporalAgent` with a system prompt and the `execute_code` tool: -[View `workflows.py` in the sample](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/workflows.py). - + +[bedrock_agentcore/strands_agent/workflows.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/workflows.py) ```py @workflow.defn class StrandsAgentWorkflow: def __init__(self) -> None: + # Configure with the plugin's default BedrockModel(), custom system + # prompt and code interpreter tool. self.agent = TemporalAgent( start_to_close_timeout=timedelta(seconds=60), system_prompt=SYSTEM_PROMPT, @@ -109,22 +111,29 @@ class StrandsAgentWorkflow: @workflow.run async def run(self, prompt: str) -> str: + # invoke_async, not agent(prompt) -- the sync form spawns a worker thread the + # Workflow sandbox blocks. result = await self.agent.invoke_async(prompt) return str(result) + + ``` + `TemporalAgent` adapts the Strands agent loop to run in Workflow code. The Temporal Strands plugin schedules each model call as an Activity. `activity_as_tool` makes `execute_code` another Activity when the model selects that tool. The `execute_code` Activity creates a Code Interpreter session using the Workflow Id as its session name: -[View `activities.py` in the sample](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/activities.py). - + +[bedrock_agentcore/strands_agent/activities.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/activities.py) ```py +# Use AgentCore Code Interpreter to provide a code sandbox and execute LLM generated solution @activity.defn def execute_code( code: str, language: LanguageType = LanguageType.PYTHON ) -> dict[str, Any]: + """Run code in this Sessions's sandbox (workflow ID) and return the Code Interpreter result.""" interpreter = AgentCoreCodeInterpreter( region=os.environ.get("AWS_REGION", "us-west-2"), session_name=activity.info().workflow_id, @@ -132,7 +141,10 @@ def execute_code( return interpreter.execute_code( ExecuteCodeAction(type="executeCode", code=code, language=language) ) + + ``` + Using the Workflow Id gives each Workflow Execution its own Code Interpreter sandbox. diff --git a/snipsync.config.yaml b/snipsync.config.yaml index d18878e6c9..7598622999 100644 --- a/snipsync.config.yaml +++ b/snipsync.config.yaml @@ -7,6 +7,8 @@ origins: repo: samples-typescript - owner: temporalio repo: samples-python + # Remove this ref after temporalio/samples-python#360 merges. + ref: schoeff/strands-agent - owner: temporalio repo: reference-app-orders-go - owner: temporalio From 6e851178cc44f33af019cb17357a127168fc282d Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 15:02:07 -0700 Subject: [PATCH 35/77] Explain AgentCore tutorial design choices --- docs/guides/durable-agent-on-agentcore.mdx | 80 +++++++++++++++++++--- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 6cdfa5228c..fa93d8c13f 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -23,6 +23,10 @@ import { ReleaseNoteHeader } from '@site/src/components'; This guide deploys a Strands agent as a Temporal Serverless Worker on Amazon Bedrock AgentCore Runtime. The agent uses Amazon Bedrock for model inference and AgentCore Code Interpreter to run Python. +The [AgentCore deployment page](/production-deployment/worker-deployments/serverless-workers/agentcore) is a focused +procedure for deploying an existing Worker. This guide uses a complete agent sample to explain why the Workflow, +Activities, Runtime, and Worker Deployment are structured this way. + ## What you will build The sample accepts one prompt and runs one Workflow Execution. The Workflow asks the model to answer the prompt. The @@ -32,6 +36,10 @@ Your local client starts the Workflow through Temporal. When the Task Queue need AgentCore Runtime session. The Worker processes the Workflow and Activity Tasks, then drains after 60 seconds without an Activity starting or finishing. +The sample is intentionally one turn. This keeps the deployment path visible while still demonstrating the important +reliability boundary: the model and tool calls are recorded Temporal operations, and the Worker process that performs +them can be replaced. + ## Architecture The Workflow contains the Strands agent loop. The Temporal Strands integration runs model calls as Activities. The @@ -49,10 +57,33 @@ flowchart LR W --> TOOL[AgentCore
Code Interpreter] ``` -This sample completes after one answer. To support a conversation, keep the Workflow open and accept later prompts -through an Update or Signal. Store bounded conversation state, or references to externally stored content, in the -Workflow. Use the Workflow Id as the conversation identifier. Do not depend on one AgentCore Runtime session handling -every turn. +Place state according to how long it must remain available: + +| State | Location | Reason | +|---|---|---| +| Agent progress and bounded working context | Temporal Workflow | Temporal reconstructs Workflow state from Event History when another Worker continues the execution. | +| Model calls and tool operations | Temporal Activities | Each operation gets its own timeout, Retry Policy, and recorded result. | +| Large conversations, uploads, and generated artifacts | External durable storage, with references in the Workflow | Large or unbounded data should not cause Event History to grow without limit. | +| Process-local caches and temporary files | AgentCore Runtime session | Runtime sessions are replaceable, so the agent must tolerate losing this state. | + +This division is what lets the Workflow outlive any one Runtime session. A Worker can stop after the current work is +complete, and a later Worker can reconstruct the Workflow before continuing it. + +### Extend the sample to multiple turns + +For a conversational agent, use one Workflow Id for each conversation and keep the Workflow open after returning the +first answer. Accept each new prompt through a Workflow Update when the caller needs the answer in the same request. +A Signal is a better fit when the caller only needs to deliver the prompt and retrieve the result separately. + +Keep a bounded message list or summary in Workflow state. Store large messages, attachments, and artifacts in durable +external storage and retain their references in the Workflow. Retrieve that content through Activities. For a +conversation that runs long enough to accumulate a large Event History, use +[Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) to carry the working +context into a new Workflow Run. + +The application continues to send every turn through Temporal. Serverless Workers may start a different AgentCore +Runtime session for a later turn, so conversation correctness must not depend on process memory or Runtime session +affinity. ## Prerequisites @@ -86,6 +117,10 @@ uv sync The cloned directory contains the Workflow, Activity, Runtime handler, AgentCore configuration, deployment scripts, and IAM template used throughout this guide. +The sample uses AgentCore's CodeZip build instead of a container image. AgentCore packages the Python project and runs +it on its managed Python runtime, so this path does not require a Dockerfile. The checked-in files define the +application and Runtime settings. The deployment script generates the AgentCore CDK project when you first run it. + ## 2. Examine the agent Workflow The sample creates a `TemporalAgent` with a system prompt and the `execute_code` tool: @@ -123,6 +158,10 @@ class StrandsAgentWorkflow: `TemporalAgent` adapts the Strands agent loop to run in Workflow code. The Temporal Strands plugin schedules each model call as an Activity. `activity_as_tool` makes `execute_code` another Activity when the model selects that tool. +The Workflow owns the sequence of model and tool decisions because that sequence must resume correctly after a +failure. The model calls themselves do not run as ordinary Workflow code. They run as Activities because they perform +network I/O, can fail independently, and are not deterministic. + The `execute_code` Activity creates a Code Interpreter session using the Workflow Id as its session name: @@ -148,6 +187,10 @@ def execute_code( Using the Workflow Id gives each Workflow Execution its own Code Interpreter sandbox. +This sample invokes the agent once and completes the Workflow. It does not need a message handler or a durable wait. +The multi-turn design described in [Extend the sample to multiple turns](#extend-the-sample-to-multiple-turns) would +change that lifecycle while keeping model and tool calls behind the same Activity boundaries. + ## 3. Configure and deploy the Runtime Install the AgentCore CLI: @@ -180,6 +223,11 @@ Open `agentcore/agentcore.json` and replace the placeholder values for `TEMPORAL | `TEMPORAL_BUILD_ID` | `1.0.0` | | Runtime endpoint name | `temporal` | +These values connect two separately configured systems. The Runtime uses the Task Queue, deployment name, and Build ID +when its Worker registers with Temporal. The Worker Deployment Version created in Step 5 uses the same deployment name +and Build ID and points Temporal back to this Runtime endpoint. If the values differ, Temporal can start compute that +does not register as the version waiting for work. + Putting the API key in `agentcore.json` keeps the tutorial short. Do not commit the populated file. For a production deployment, store the key in AWS Secrets Manager and load it when the Runtime starts. @@ -202,7 +250,10 @@ Deploy the Runtime and its named endpoint: ``` The script creates the AgentCore CDK project on its first run, validates the configuration, packages the sample, and -deploys it. Retrieve the Runtime and endpoint ARNs: +deploys it. The sample uses public network mode so the Worker can make an outbound connection to Temporal Cloud. The +named endpoint is for capacity requests from Temporal, not prompts from the application. + +Retrieve the Runtime and endpoint ARNs: ```bash export AGENT_RUNTIME_ARN="$( @@ -259,6 +310,11 @@ echo "$INVOCATION_ROLE_ARN" This invocation role lets Temporal get the named endpoint and invoke the Runtime. It is separate from the Runtime execution role that AgentCore created to run the Worker and access Code Interpreter. +Keeping the roles separate gives each side only the permissions it needs. Temporal assumes the invocation role to +start capacity. AgentCore assumes the execution role inside that capacity when the Worker calls Bedrock and Code +Interpreter. The trailing wildcard on the Runtime ARN allows the invocation role to cover the named endpoint as well +as the Runtime. + ## 5. Create the Serverless Worker deployment Create a Worker Deployment and a version that points to the AgentCore endpoint: @@ -284,6 +340,10 @@ Creating the version causes Temporal to invoke the Runtime and wait for the Work and Build ID match the values in `agentcore.json`. Setting the version as current lets it receive new Tasks on the `agentcore-strands-task-queue` Task Queue. +The Worker Deployment Version binds one version of the Worker code to one compute configuration. The sample registers +Workflows with `PINNED` behavior, so a Workflow continues on its assigned version instead of moving to a newer version +while it is running. Marking `1.0.0` as current sends new Workflow Executions to that version. + ## 6. Run the agent Run the sample client with its default prompt: @@ -303,6 +363,10 @@ uv run python starter.py \ Workflow calls the model and Code Interpreter Activities, and the client prints the answer. The Workflow then completes. After 60 seconds without an Activity starting or finishing, the Worker drains. +Starting the agent through `starter.py`, rather than invoking the AgentCore endpoint, is an architectural choice. The +Temporal Client creates the durable Workflow Execution first. AgentCore supplies a Worker when Temporal has a Task +ready to run. + Inspect the completed Workflow Execution: ```bash @@ -316,7 +380,5 @@ The Event History contains the model and `execute_code` Activities. Follow the W agentcore logs --runtime temporal_strands_worker ``` -This one-turn example demonstrates durable model and tool execution on replaceable compute. A conversational version -would keep the Workflow open after the first answer and accept additional prompts through Workflow Updates. Each -conversation would use its own Workflow Id while Serverless Workers could run its Tasks on any compatible Runtime -session. +The Workflow history and AgentCore logs show the two sides of the integration. Event History records what the agent +did. The AgentCore logs show which replaceable Worker process performed the work and when that Worker drained. From dc1fdadf7edb82e3d858cb4418ac2aebf0723417 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 15:05:49 -0700 Subject: [PATCH 36/77] Condense multi-turn AgentCore guidance --- docs/guides/durable-agent-on-agentcore.mdx | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index fa93d8c13f..994cc8d885 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -69,21 +69,8 @@ Place state according to how long it must remain available: This division is what lets the Workflow outlive any one Runtime session. A Worker can stop after the current work is complete, and a later Worker can reconstruct the Workflow before continuing it. -### Extend the sample to multiple turns - -For a conversational agent, use one Workflow Id for each conversation and keep the Workflow open after returning the -first answer. Accept each new prompt through a Workflow Update when the caller needs the answer in the same request. -A Signal is a better fit when the caller only needs to deliver the prompt and retrieve the result separately. - -Keep a bounded message list or summary in Workflow state. Store large messages, attachments, and artifacts in durable -external storage and retain their references in the Workflow. Retrieve that content through Activities. For a -conversation that runs long enough to accumulate a large Event History, use -[Continue-As-New](/develop/python/integrations/strands-agents#handle-long-running-chat-sessions) to carry the working -context into a new Workflow Run. - -The application continues to send every turn through Temporal. Serverless Workers may start a different AgentCore -Runtime session for a later turn, so conversation correctness must not depend on process memory or Runtime session -affinity. +To extend the sample to multiple turns, use one Workflow Id per conversation, keep the Workflow open, and accept later +prompts through Workflow Updates while allowing any compatible Runtime session to process each turn. ## Prerequisites @@ -187,10 +174,6 @@ def execute_code( Using the Workflow Id gives each Workflow Execution its own Code Interpreter sandbox. -This sample invokes the agent once and completes the Workflow. It does not need a message handler or a durable wait. -The multi-turn design described in [Extend the sample to multiple turns](#extend-the-sample-to-multiple-turns) would -change that lifecycle while keeping model and tool calls behind the same Activity boundaries. - ## 3. Configure and deploy the Runtime Install the AgentCore CLI: From ee97ffe396a39fd820cd3ebe482f17a9031430a9 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 17:15:03 -0700 Subject: [PATCH 37/77] Clarify AgentCore deployment guide scope and versioning --- .../serverless-workers/agentcore.mdx | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 940158312c..aab02fad0a 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -20,14 +20,18 @@ import TabItem from '@theme/TabItem'; Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. -This guide deploys an existing Python [Serverless Worker](/serverless-workers) to Amazon Bedrock AgentCore Runtime and -configures Temporal Cloud to start Worker capacity. It assumes that you already have a Temporal Worker and an AgentCore -project. For the Worker implementation and lifecycle, see -[Serverless Workers on Amazon Bedrock AgentCore Runtime - Python SDK](/develop/python/workers/serverless-workers/agentcore). +This page covers only deploying an existing Python [Serverless Worker](/serverless-workers) to Amazon Bedrock AgentCore +Runtime and connecting it to a Worker Deployment Version. It assumes that your Worker and AgentCore project are already +in place. -If you are still deciding how to structure your agent, Workflow, and Activities, see the -[Python Strands AgentCore sample](https://github.com/temporalio/samples-python/tree/schoeff/strands-agent/bedrock_agentcore/strands_agent) -for a complete application. +For a complete tutorial, see [Build a durable agent on Amazon Bedrock +AgentCore](/guides/durable-agent-on-agentcore). That guide starts with the [Python Strands AgentCore +sample](https://github.com/temporalio/samples-python/tree/schoeff/strands-agent/bedrock_agentcore/strands_agent) and explains +the agent architecture, Workflow and Activity boundaries, AgentCore project configuration, and deployment from start to +finish. Use this page when you only need the Worker deployment procedure. + +For details about the Worker implementation and lifecycle, see [Serverless Workers on Amazon Bedrock AgentCore Runtime - +Python SDK](/develop/python/workers/serverless-workers/agentcore). ## Prerequisites {/* #prerequisites */} @@ -84,7 +88,8 @@ The Task Queue must match the Task Queue used by your application. The deploymen Worker Deployment Version that you create in [Step 4](#create-worker-deployment-version). The Runtime definition must use your Worker handler as its entrypoint and provide a named endpoint for Temporal. The -following fragment uses a public network so the Worker can reach Temporal Cloud: +following fragment from the Python Strands AgentCore sample uses a public network so the Worker can reach Temporal +Cloud: ```json { @@ -101,6 +106,11 @@ following fragment uses a public network so the Worker can reach Temporal Cloud: } ``` +The endpoint is pinned to the specified AgentCore Runtime version. In this example, `version: 1` refers to the first +deployed Runtime version. For a later Worker version, create a named endpoint pinned to the new Runtime version and use +that endpoint ARN for the corresponding Worker Deployment Version. Keep endpoints used by existing Worker Deployment +Versions pinned to their original Runtime versions. + If you use a VPC instead, configure outbound access from the VPC to your Temporal Cloud Namespace. Temporal invokes the named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). @@ -127,7 +137,19 @@ agentcore status --type runtime-endpoint --json ``` Record the Runtime ARN and the ARN of the named endpoint. You use the Runtime ARN to scope the invocation role and give -the endpoint ARN to Temporal Cloud. +the endpoint ARN to Temporal Cloud. Confirm that the endpoint's live version matches the Runtime version containing the +Worker code and environment configuration that you intend to deploy: + +```bash +aws bedrock-agentcore-control get-agent-runtime-endpoint \ + --agent-runtime-id \ + --endpoint-name \ + --query '{status:status,liveVersion:liveVersion}' \ + --region +``` + +If you redeploy the Runtime without creating or updating an endpoint, an existing endpoint can remain pinned to the +earlier Runtime version. ## 3. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} From d5f02654fbcf3b995afcb57138960c9d7f056dc4 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 17:37:40 -0700 Subject: [PATCH 38/77] Clarify AgentCore Runtime deployment configuration --- .../serverless-workers/agentcore.mdx | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index aab02fad0a..f584a68dd5 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -54,8 +54,10 @@ Python SDK](/develop/python/workers/serverless-workers/agentcore). ## 1. Configure the Worker Runtime {/* #configure-worker-runtime */} -In `agentcore/agentcore.json`, configure the Runtime with the Temporal connection, Task Queue, Worker Deployment name, -and Build ID: +`agentcore/agentcore.json` is the [AgentCore CLI project +configuration](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html). Its +`runtimes` array defines the AgentCore Runtime resources that the CLI deploys. In the existing Runtime object, configure +the Temporal connection, Task Queue, Worker Deployment name, and Build ID: ```json { @@ -87,9 +89,14 @@ and Build ID: The Task Queue must match the Task Queue used by your application. The deployment name and Build ID must match the Worker Deployment Version that you create in [Step 4](#create-worker-deployment-version). -The Runtime definition must use your Worker handler as its entrypoint and provide a named endpoint for Temporal. The -following fragment from the Python Strands AgentCore sample uses a public network so the Worker can reach Temporal -Cloud: +The `entrypoint` field names the Python file that AgentCore starts. That file must implement the [AgentCore Runtime HTTP +protocol contract](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-http-protocol-contract.html) by +serving the Runtime's `/invocations` and `/ping` endpoints. For a Serverless Worker, `/invocations` starts the Temporal +Worker and acknowledges the request. For an implementation example, see the [Python Runtime entry +point](/develop/python/workers/serverless-workers/agentcore#runtime-handler). + +The following fragment from the Python Strands AgentCore sample configures that entry point, a public network, and the +named endpoint that Temporal invokes: ```json { @@ -106,16 +113,11 @@ Cloud: } ``` -The endpoint is pinned to the specified AgentCore Runtime version. In this example, `version: 1` refers to the first -deployed Runtime version. For a later Worker version, create a named endpoint pinned to the new Runtime version and use -that endpoint ARN for the corresponding Worker Deployment Version. Keep endpoints used by existing Worker Deployment -Versions pinned to their original Runtime versions. - -If you use a VPC instead, configure outbound access from the VPC to your Temporal Cloud Namespace. Temporal invokes the -named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). +In this initial configuration, `version: 1` selects the first AgentCore Runtime version. Verify the named endpoint's +version after deployment in [Step 2](#deploy-runtime). Do not commit a populated Temporal Cloud API key. For a production deployment, store it in AWS Secrets Manager, grant -the Runtime execution role permission to read it, and load it in the Runtime handler. The Runtime execution role is +the Runtime execution role permission to read it, and load it in the Runtime entry point. The Runtime execution role is separate from the invocation role that Temporal assumes. ## 2. Deploy the Worker Runtime {/* #deploy-runtime */} @@ -137,8 +139,14 @@ agentcore status --type runtime-endpoint --json ``` Record the Runtime ARN and the ARN of the named endpoint. You use the Runtime ARN to scope the invocation role and give -the endpoint ARN to Temporal Cloud. Confirm that the endpoint's live version matches the Runtime version containing the -Worker code and environment configuration that you intend to deploy: +the endpoint ARN to Temporal Cloud. + +AgentCore creates an immutable Runtime version when you create or update a Runtime. A named endpoint remains pinned to +its configured version until you update it. For details, see [AgentCore Runtime versioning and +endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-runtime-versioning.html). + +Confirm that the endpoint's live version matches the Runtime version containing the Worker code and environment +configuration that you intend to deploy: ```bash aws bedrock-agentcore-control get-agent-runtime-endpoint \ @@ -149,7 +157,12 @@ aws bedrock-agentcore-control get-agent-runtime-endpoint \ ``` If you redeploy the Runtime without creating or updating an endpoint, an existing endpoint can remain pinned to the -earlier Runtime version. +earlier Runtime version. For a later Worker version, create a named endpoint pinned to the new Runtime version and use +that endpoint ARN for the corresponding Worker Deployment Version. Keep endpoints used by existing Worker Deployment +Versions pinned to their original Runtime versions. + +If you use a VPC instead of a public network, configure outbound access from the VPC to your Temporal Cloud Namespace. +Temporal invokes the named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). ## 3. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} From 63ef0f922486d3cffb592b5466280763c79f076b Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 17:46:15 -0700 Subject: [PATCH 39/77] Use AgentCore reference architecture diagram --- docs/guides/durable-agent-on-agentcore.mdx | 26 +++++++++--------- ...poral-agentcore-reference-architecture.png | Bin 0 -> 266353 bytes 2 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 static/diagrams/temporal-agentcore-reference-architecture.png diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 994cc8d885..d9f96b5fa6 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -14,7 +14,7 @@ tags: - Serverless --- -import { ReleaseNoteHeader } from '@site/src/components'; +import { CaptionedImage, ReleaseNoteHeader } from '@site/src/components'; Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. @@ -42,20 +42,20 @@ them can be replaced. ## Architecture -The Workflow contains the Strands agent loop. The Temporal Strands integration runs model calls as Activities. The -Code Interpreter tool is also an Activity, so model and tool calls have their own retries, timeouts, and recorded -results. +Temporal Cloud owns the agent's execution state and capacity control. The application starts or signals the Workflow. +The Workflow records agent decisions and schedules model and tool work as Temporal Tasks. When the Task Queue needs +capacity, the Worker Controller Instance starts AgentCore Runtime sessions. -AgentCore Runtime hosts the Temporal Worker. It does not receive the user's prompt. Temporal invokes the Runtime -endpoint only to add Worker capacity, and the application sends the prompt through the Temporal Client. +Each Runtime session hosts a Temporal Worker that polls the versioned Task Queue. Workers can call AgentCore services, +but the sessions and their process-local state remain replaceable. The sample in this guide uses AgentCore Code +Interpreter. It does not use every AgentCore service shown in the reference architecture. -```mermaid -flowchart LR - APP[Local client] -->|Start with prompt| WF[Temporal Workflow] - WF -->|Workflow and Activity Tasks| W[Temporal Worker
on AgentCore Runtime] - W --> MODEL[Amazon Bedrock] - W --> TOOL[AgentCore
Code Interpreter] -``` + Place state according to how long it must remain available: diff --git a/static/diagrams/temporal-agentcore-reference-architecture.png b/static/diagrams/temporal-agentcore-reference-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..b429235b03d18f08226beb8012ff6cd4f157222d GIT binary patch literal 266353 zcmeFZ2Un9_w>2DkQHoTN-a)FM1SAj;q$(ijjR;Z%MWuwIl86v`5$Px(&4%c$QbehN z(2Fz`6_6GP1d$qA2&8;FKIa?fJnwn#Kk$xs3}Ix1WM9{{_u6yKHRswUJJ?zBa3A4@ zKp;HUR_2Zn2)hUb!aT{z4&G_0a#4b?^6Oiho1RB9t+cQ_QE++GMWlzVruOugh1hzR z2aMPJ*S{MNiXYij6zk~9t&;E5-n{!V(a`UEg?so)d;bOJ%eTM(<1g%kPyhJ0KYvI` z_ z{r8*lhX3`8ep@}G{x_WC;h#T>nh|6JhoBgl)ES%ViyUazRR|9Htav^Ou1Q7!EGjIT+@{wq=sc(UDz z5mbd#W~sKsoDXqH5*j5$dPQ~p=QyV>s6s}$OwP$x%d&Z0&;O=k{+RHh?uznL+}~*3 zqkr~}mWg+azzff>ac}aDAG@NWbn}Ue<+oGcY~IE1$F~N${qF~3d<%QwzNn4B(-_w* ze8=dK04p6H{NpUsx^wRx1eBE7o}QVL>Ayg~d;ZTn7N-mO2%DXGP8gx)i3PzAEuo#+i=@VHk}apP0Zwf!sHQe8_j z1R0rb>#OyC!sDEh6Z^2*E0N=e2!Ep`|MgTR+;0`wG(6RNM^EV4tp!cS2I4wWef5L! zV&zSXC(}Gavx@NDqZ2=$tesR+7SU%l$?J3M{f9a9&18)VXme9a_L49dHS(+vZy|@T z&Nmyb;U^}24bbBeg^eqLJ6aMBiJ9>yZP>jsVzr&AeV;#$822-#k6za6MzDf7y1isS zB$;ZF;`6nmK?!d$vlUx`Pq3V9yUmBqFOa5s4o-v^OZXj`9JPixim&CYvG!rOUEVoH~D!UjRWl-Go8pSHLL<(#A{2P zX_uf6=$@vqiC*y2Zd5zfOCDdFX`5WgOJmQ=($0`mfcO+!=KZG~|E7G;K701QwnjE5 zo}c|?RH}D@MB}Q^$V7-d6t;EEZZarg3DHp8yk^jFt4EMFD~+6$rfbyF<^_8@pfYU3g1kp2lXl{*%@u1 zXTMU3{kf1f9=PzM+bG$vc=tGf@I^(e3G6 zB(IkYTlNtr;Uyi%FoGMsvHDNl*j%SnZz^AXa$X0XKD$P)_8^-T)4I|2XwK@VpFckFk%{fp zRa9whrJLovdzW1@z<_XcPMyc6i@gq6SK(hhumgSAMZfi*hALO7OcZi>tm6JcpB&uGn?tdkLKVd>Y!z^>~y@^E> zgo%mOL5I_9?Nn}bLKlr}3!}ca_a=QkZDGG$cyjPIUqf<%)IIru-X_vixBl_AsB9Ue zUhKgndZLP}t1`TRF&bTkh5ZcsgVL%(=(XCyIpOKq6R7Rl2$nrT@rkhgB1$KMehf`Z z!4A#nYJS%6(i3hF^2%W0hp@*nRmQQ2T!f`Sg8w1M_4;HSVi!9gz&~`_B8n&TnUllU zjy$)z1>@DouFDVb9fV$u@_O>gK;*B1g9afx<>6wv^3j~J{18=dF&7HleC+2*^4Pxs ztkmW$TvoyPOhih&xs}RO8JknG7o~Y%_#eKNVaQ}}<+NbJ%Ozw_yOaeaY$BLr z_^ym2Cxj*HfjUk4nSVeL#h(#JbSFp8Xif?38&?ec=5B|AyPAq}j@%sSh?r4DZ<jBf9>KsbH=VJpy&%C^Zl3dJ6A(+?{S&D9K|e6zNjLMDJH z65P+_t;37eK7D;oVwC4l5+!dSpWi<8py#fA*vT^G4ZnDSh z1Rmk*eehcLD@}+(Th!H#e@JrE!t6|(KIas!U!%_|YPw@u77HroJ8t{d&Ab$^TPkkU z4_k0KDSDIrLR9C!Z8kfLuMIv%wrTLayHk{i>0)naA)z^Z4G)c6&aK;*4!r8O{HyCp z9Y41K(d3`zeoerc(*(z^lR==wZ@R&L;vXd%#oC#hNC~>={sw(9VytKeIc8D#`nG0y{*-0@ITl?8?hluD3~S*eQ17PH=|!c)k7o^ zjC|J`(&6Oq(`AM_RH2+Wh=YKFsQ}FNpIB(EBFR?MNkC!dNsXu8{W~)m@V)uzdEBg` zo}EAO5`w%Jgwei}dVYh>-}(nUE!vNR2lOh2{eI{kQy@j=f9Zv@N3W&V-&$}HG5f5@ z3gJ>99r&lzv-Sd#wI44V6(~eKsZaW5NUokHn@JD|-NreV%@ZkAzm+a2sM4^q3}~f| zaC7jR0IDw1+ko(Qs~%9p()@IKCqnlpDO72yaJA_zjVH;hG9Y`X7AyV}7>~#7v%QvK zQ|+;Ww1K3v+CyoVrkx;7hH6#6GpN|;s^BV!msNV(A-g}p*D%0@W!?PeJ>Dm?TMAFLUhi)UL3&_zFc-GkKfP}om*R5LVf`3Am z?r!72oDpN4`lHp%V|FHIK&m1eOHaXG)w|H}7wU=jKi>RvR>heoJ`O*6r>W%WjQsvE zJ!D58?9uJBNf2g;m`?^7dmqOj5*|a$YBw_L_@u~L>8+h^4am&!;$YFs?BC@i+z$QY z>^Efb%TG|Z3`eJpWcJc5F&)pJ#`wu_<_=IE4H?Ol&wO zY!a2VugD1N|5U_m$0!cHP>4F2PxKtnEe=-8!4VSShY6N=1fE177l}`DtHz62Cqxx zz{=(f*oImeSB}QrpSzEX=h{4_2*xdTVrGKyI&2gQa6*FCV_17rl$bK&0%S7G+cDai zj1RCtb_WUA`0MFkYj-p9co z2l#J3>v^Oc1t7(8pY zi5D!hXR17Ta`rksDpkZM zw*3580@iWEp9v>}tP#p(<1*2=A~Gv7nFN8TP(gV)!V*Eg0ZY~yYGsH}Y-6;YRqExUaRzJvwO#IuT8EropU6^+S-?S<6ozJTE;*36diBn$0Ai6f zGN>nW7fRkqT;&xd<$+(rwxf5Hv$gslt*{tb`|q1Q7=wCW)E(b%sIofN)z>%)%Uq9lEe1Kf$0*u`iY-Vg9}& zx3YbqIrk+$)`!~kk#mfqnr2_w5|jGwtbaA^Qp{N^tF{}oH*6VhnNjj!C*=!I*xR*5 z9~61Zd9 zlQT5Gzxp_njX)){L6vC&?!J)86;o~*CQcJE8QS+4HGv=n2-g$VP#1`P6sxC@2{V%d z#4AGphpa$yI^YONmOsZ1VN!{8VCGNIe(}HdC^R?- z>v;F(ii+ZOo{+~qg%H`~{$#MFEGv0_!RLcos+w zW#|yh71FyI^qFMjB;Iqz{Z=cw9CupK{LsfO$eH1|0L{>-ETBlS(&acH85r%$Q18R+ zHj65!Uu63y2Y?_WuVuvmY#ff0J(!r7xV*evS=D5n#V>i2f;RaV>e;fV_y!-^OyxNU zL>xxh4MMS`KYGG}N6G%fkuy3jXWElawVMds*kditWR72|C8xptOhG8lHS6$6 zuOr8};<=I&g6H2~=ZXqAAESEaiUNyg%Jpj&{2H0{{z(>sA8wvMkk6l>lmA#IRw2Pk z>C9hvfKa8XV&;P1Y&VSOTGJNHk!!ISLOZ=d$(8xNLCE_NMbp0jwv*aU8H{A1Z z1}Bb)J$vZWrhiaYNO0Ka<|zkGXGhPoAEF5CCZ(UteqAy-BH^PDmj^p0Y?h>MA^X$E z=2Xd*o5>27S}qExB`f_MBjlsRC6s*KB0>F%qkM|B;!KoKD94wq`%k!7y^785|4&Q> zY1xd67qS-^n`lh=f|;|$2x(;Z{p^_eVw|gadDhzguE4@j$!RZtlU^2U<`zAzq~QsB z*(`{uMyNaWgh%#xU^u(|-LKin*I&f$pBAz!X@2A!{?U1UByz>sK!1Y8Ja6FzYYazL zoYSar5IYur#hyo=8O+w;CTcRxug&tyX6ivMuOQ={?_K3h zPund3%r9+ax$@)3PRX!|1WtzyldMXfs9}|k1Nh?*04$8VuzSv*RXK2#7xI-|MxnUm zgQ{ZC5lH-XjVcoXNLJ4oIp*P@$Is^Ct9YVLLG&5Fd~9trM%hgSYEb8_+w{PIy#9iR ze3Sq(2SDWhjLDs?aV}}!AocvK%R_$6U4EfUx`Fd)hO4-J5%+K& zOG}RBm6d3=C^>RPj>)>eowxYcx4h}2#x-Wxi#X0@R%S7En${l?nOdO~%ciQCQl1gB zeSBkDrmd0^a3L21@ThCdq$6Rcmrq541a!OGJ(oJ2Bl&Fz zPOn6y_BXWB2oGhCh}4}p-u7imHq3~u*EMf`HpBe#7L0OL>g?bFC+m>M`t%RsqfL0@ zJm%8g=AhXwKLaXG{JOBjGoR1zvc`+okM9g!j)^m2rN7sH@q}xl{d0jIqCOf(W0{em z?1$c_rCofruxO8Y7#cR!cO^7Cv1v}e_sVg zQdDgb*U)Ew?cC7{9(orRMBAypbplei=*8!?pCI@mYP-j&cwMNb23o&p%6Ce!=f>=y zGQ4PVQ?!owly7#9$M^83BqqnVq+AJiOh>)%#97w@V{U^OMTLLYNvPp$5Up)Tt@Z-! znCrSSdPCXDbh`DPv9EVktDqE(HFBvoGS+adK{EUlE1%Ei8DLdp|rGBKnl2X^mO7H!8? zJ-N!WNBr})jVj2GD+Y{66P;_+sWrfzj#TTOM;Oh++O0ZWw^$H zmyiWX;yj|Haf-=ALsDx~N2@yms8`d}0X*`XymWg?(`X9u^7QuQ(Nu?4J&@uFkzjjb zw85`Yf)2;%D0`fs5R=}JNDjY-plW5R0>ocFS*``56d-r{RR*)f6NO>OC_D3Y^YiZ& zxo3`(oH!v~3SQ!nmNFeapF>eR zC@0Vx;@Iw)u?T{AtG5TW)F5(L?Dvlc;aU@xPv2LMdeSEpX*+zhEbM*}y#2XV>pj0N zTg<-R`b*qbWUWbn(l`A(KwcX~TF7xXb7 z5-rT`iz-D!fJB>rU(640szu~$mi z@VLj5dwD)#7J}%I%M!bZaEjk*^9t{tBbPY8w{O~Xh(^WwUPYI@$KIE>WhYX7er!+d zyeQku#qKCi5Wo34>=$!1^~>pQd|V-1*Vb(U}>(aP@Rl|MT5?k6qM{r4xAl zb8@4jKd<=tWq-ffNuw$L)R*Ckmq8k5seww(O77X$?_!p3qRUIFs;XL7S2aK0@((~% zS6!^Et?dp$C7n{&3qy{|OSPLx?>R)$MA6A!ZUSuY72lmz7a7kf$CGHd^g3!$_zA*hbkRW^k$Ka&C+1OQjR_T~GhuC533Uj&4$ z3d)y$?Wb*ji7K*swiYfI^ZdEIjjBHaQ9U~0^EfL-R7)pKe%Ob$S3yg&&D{Y{NHDF1 z#WhMGwY8QnWp|yEUu{hmdgb*z@(&0&c95lA zTf1OjbZo3u574M9huLMWi^zziu#Jz8Kfw2t+U8z&G84#GdRFZHRJWaUc!3_ur0H49Ev^`zXEa9Q9&mlLU$;qMG6ctySB|j-DxFrTJ$}{#d6I| zJHU!&K>f2GbJdUk*&}WRkzBTnsDmPO(SMaOYn9O*dKo5waj=Q##|!{-b)Xndug3Zm z$s;H)5nZLWBw{X_nhX1F%7<5!qFlT-9;zuRxei6sM_`0o^DlMz2t)K)#OV0AcWAS9 ze*ZXzR#074efntqhY5U5b=byeZn$;%SY7;ZdNWXMb`DC>?rRNF_9TDaoLwv4;`?Bw zxqNvpoxWj@tcTvcpl2Vr>4zmQsqcxEmDfLVzE_$%LnsKGO}3BJ>64%sjp{e$t zzts^RizB}~N1kx^TR3b_ZB(v2*~rn-dbiU9wu(Uh`tiJezLoDP3fUv?LF^>QPVZh$ zFx<({jR{z7*bk&_RnQ7^@1^E0biCH3EF!1|^W}=7VOm-FLd-ch92-}$M)XsqZp6v< zrRMMA)u9Ad^ll=$=Uwe|m%m@EGy0+PyeV{o`SR6IJ_tlEoV*F2G1b}$lA?aq>Kdlc zNY||e+b?_#ATfJFk7%=Z{590q{6me%U9tT)Wd%=vgr)VtIdHP+DAo$fMn%svk9GO! zZ59d1cgU{+_Jm_ZovoB&IQR_V>x@+M(jD4wY1(5bauZ7U;abwwB)aN7`2)5nWj{XK5(=^8Sit~t z>$&v6a9~rarP1%qGfw#0$R#MM)cLNW)Lv!cIk~)-T`OU**lBtbyv3#Ep?EnqABrBX zCG?+A?vbcpYYyK{!7{SIk~+W1XMu*mE_rFPmHYCS^qG!i!85}hlVQ^XCDgH!AQ}bb zz|6&(rGICcwPNdjMcV)r&T0MjFH6{>wf$^xdN?y;ogMM%_Q+I6*Of%*-FD~#6u45q z_JQVmw4&|fh`W7qn|3*}O|ZDbgT6ft$Plps_WK;;LQa@oajYVGdj#FOQae3p+uUKh z-eYN;@b2ANfMY{-D}T`__Vm2=_6Q%QRNn*c{I7$CQ)|}+v}lenVy`_uGyUGdtlgDq zT7dh`RgXs;lOYFEQh78lH*^S=Y$1!+ce^)#SI|zvHV&oF&b@ZR5XGC=&?FMNx7SJe z`mp)*Q2lCyc>U&}Ve7-@l32A7k8qF(xhwiljJTPpwvJVkHb&5!P~eEUx~Pj_+SHnL z_#!{YzPc={i~8hL+$K%^B5mR~DtJ-GUB!9=**<`o=xdU|?)YH`X|2W)aJ;a`%)>gu zW53<+9yDQIKHkN>V&{AD&M$uy!}p%UXCJyR3L}4+N!vk7G6yD53z8I~G+i}3JlsmM z0Km?y8s;bn0Ik-pE)m4eOGGDLibR?S9WugvRl~|bCxVQ!Tr~MmZGzI>9+b|K%zTx8 z;nr$>h)FV#2pnvO-ZX#m3z?y4cH2uVeCu_hOit4!$8e<{d!+`!8?5<)VUxE-(d1n8 zAaF%(&DZm~VF}&FJ5?Zc#BARkSgD;HoTgK!L#HE1RTtHfuXFFJN)eMRgJwHacX)T| z@oA0ZB~UG15=TysgiF#WL-aV`i92dm=Y`#WD|)2q`VOwEVK@9>JI5IQ3`G&(@HGjG z)w)eR+Lk>%2c#Q!+PpiXQX+IIjkt%gM};n|&4i)XYHy6ST=8Aduh=|U(OyDbED7$G z42#P04Tb;}d5oRI(Mzv@_^E>OH*8CmuWT*+<&D|m@YPuo9Y=DJ(m>_sqQnw{fs6m$ zGin(a@f>B*A;QM%%i3K`Zb|3 z&UZVV@sD*!s`C)UE(GNo?1BMx{Tmb!`co|s;^;4%Llut}PRr55oL67je5ggs>OyuKUHga)C(oD~>}&;k%^ua0VwCl6j2%t)!yd>F+GDMqKngt`DR@iyKO14A_@2! zodnzJlp1_3KD0gur|Rlo+y$Bi ze*`_?hu!j9&&x$y(>98yeUD_Fyq_{umu|Q-7_#@%uYPBK5RAUQFel03pDJl2TnKrQ zb*fbl=;hH687_yf%pvZ;uxQqY8ts}=TGwby*!^Mb>2k|wg4@j}Mw+(AaZS;we;vM) zOChh(RNu_E*c$)ttlzFE>By%4LgZI;zGdrC(7xaVlAdG5hR)jrMeL3)wu4+Ybyf)3 zH5`aP$A=c;LseOZ5M-et`}mSiy2Z3xpmfH4do4(rl%^?4^^6qlNRxL( zb61V+O(#%G0YEiw0ZF3HW8eECn_+it{rcTT%#1ijR*UqrqJL;=?|Huy@{i>G-`W!0 z#6}@AFz%oUq2q27Fri7c$XF;cLh9D084xWx3jhXg9>A{KTCqjFdxysixHbveqkm5p z8sB~#b}x}Mmu!z@zC1#Fp$t#XjZAjNO-?N~flXi1G8r~G0JI`hV{IhIj-~`-$$a*7 z78IrTb==ScJh1H>>B`)gt~bq^(CKxDNE}Bb=VMMYX(On6nC{xT-rA{m56fWls{a1| zn-+-O4gbIr9H_o6uS-R>sO|*-Jaj@Y8?At*X`uB0Tj=<)f8TM4zP3Q6)ckPl(- zh8RQoI?4XU9o^!+Z)F>QSL{Bg&QY6ODh(VES#F55m`3;4OrE*?*@6 zRaW1Aa2nhGrfGI5XmWdGMu;>O4qaGl>M3X<7JNzQDyp6Ac5NaXZh(^g3Z)%RVQIfP z_t0bJ1hT_Sx{q{kh!iw@7D^mM&{rwcX{u4~j%ElLXFUW#3Mp(P85i%q=w`{tk3!0f zs~n6P{^mF~H98Y8wGmK{uQ4R2!0BotlX{440%B-;w*c2 z{mOWSLJKb-ogU9|MD4aq^^G@C8-vGnS8-{EYo30gDYeMzFwc)?XgF|JBN3BOLOIA2 zL-dUbS?*UGNr^`Hp=f+9Avbariu~3t-9C<8F$}pu5(t~Rt?UXC@Rud5YIm)@VE^c^ zFyvA#(r>kas%a--Xz|oR#b2Z5)gd7+|8h>6p917H#6%$1ppwnxuy(E(&@z6cd>YT8qOYB+Kpk> zB64dDc+huBbXL-~-tnKk9&_D6$;slCi-Vx5cd!dY<7{RNVN8J2AJtk@km8LO%A5BALz~#mD5$3r?PU*se|F}SlcVDc=2Qm(Fou}I zX9?DaKbgDQ?x`PKNZ(C??>V`zd~`1=kS59`TtAroYU|&fZF;l>j6=~b(;zsQB=_!w zU6HXFA?|z>M1WH!=@m|fCxy(8AKmRO*%MoBTnlukZ@ZU_Bd|ql^k(U~sqi&W235>| zNsm1^_0F>m zOM$q8=0#WXK6c-*rltm&4ULd@U%Ty5!k}FpL+oawjBwbZG&qRUQDYvh6}xG ziS7xx&7}%N{g`ZJ`^^xoeeMa=ND%`tC1td&q61`pHS+iqv*AR+WxyJ$r1z^}WL0}S z2O7swk0i?RMXtx9u%vKlchYV5lC|BmwJV^)$pj$*-(`WDj0~Y-N3;NSj@@P4B<)u^ zEs7dz3n0H)zH|$=YsxqO&|~pCd8~x$61kWg$z=sNqen3bITVI3_4s`?e?UZC#1&99 zD!V=EcXr+4OL62#ScLCjVe=zp*i7(YAhf<{YnR&5mfFB25&@gfod}yYdSVXDqSb~a zslj5SAzSRXzKvWou@+=pN$AwN%+AgZvNsoLP`nukzm3GEmM2ZyJW40yN9 zu4qO%a<+SS97_(D+RPJWR6WP1iIUT;CA3A4&m>7ue^qq5HqRGqDx)dBpa#K8l-XZy z54+bLwoan2^MTZh1WP0 z0jZz2w!g=%wXdT!WKZuO(zat^JUDcEi@$j-9G&DGS?avdzqmwxgdkf;k?OjuJ~j=w zHjfo-Bp}vbQsztOM*4L#dj-3UMWgN7N0xxd**GV?eFy_;PLSF-u$HR2?nGhthrTfU zonipkJ!ceTnNI^vLb~I*H1)a^eHV?Z84v7K7&Jec^NTTEH>ZgBYRt+1KO zN>m0;Z03yb;upj6?&S8nJ&avQ*+YM_GFh9hbG$Ter2a<OwA4)3n{upNNTbbG!YAsXekuYjpb=I#p{(z{%{lVx2g|1{QtqA@U*tDh`@=*d1 zu{O_w*KLbS6<2$@CUaM>Ztn8l2%VXT&{kADaN$Z}e`)A~>iM*QRg)u}ZKhT*hr_I_ z)`$5o%1NlO4Vdf7>HmaZsdodZ-<10qtHQsx1EKS9_10~mvxD7)`E?YF^{Csmf__%T zJKl%W0ru^R6;tMv1~9o|y=DrwU2!FxdSUOHTA(w8}2ymO1TQ9%k-RvT~{CljB8Nf>Iy2# zCVg@7f0XQ7iV;K#)LYSWQ=T7$U3?Tv$B z6CdsUj*nQQ#Pu+{7M{^anrrUDPze2Fg|CjfL-NL+`!6p?eU z+4nHJJNcoz*l^y^f_~?7>CGzuX((K8=CejnlOqIEzJ~lsThZNWI34ip56a%+z`+I2 z06?E)^QXwk)m#bPS$5G8|M=#30noI89>MCq3<^RZ{8$=qd{IyT0l2bJS}u~9ODIF{ z`7-o-)g2Naih`FO%GdP;aySlT%$cWrcR7J7!EpGx2<#ey){s#p*R0~}?_`q=SLmACVp_DX|*EK~ugx!0C z?eUi0pY``2L;)?PpRoub3q`eGbqpr39cz>yi1nWpn~!00Gki0AwB7XGCwzM*QhOkq zFw$i%dd%5}{#7cSo~XRuP(e*#4Wf)50|K7AWG^rW^q_k6WC90M>m+HSSBtta6#4_1Rc6te9nl03Y6ZF4b2; zS(FZ5dS~DMV0onkUyEK~EOf+WncyS6qp4mOhu>!!9DAVV(5}Z_JiugAzNhtHC!(;Y z1WA)9t+0tO(Q|CPZ%qV_2M4VRpd;2w1kYNXlJ(a;>laBUMW#P*ium*ft7+M%$lyO+ zt40g;q~`FXS6ijH)``8ivJfOupw=zS2)*8j?zy?fDP}Wr%uC%YitX>&FIqbn+q9+L z?eFTf`_Jsl%U-eTcHQt~J1Sy6==GtH20e>9ex6FmMLp>^En3u!oDwjA*J4oUWM4 zTSv1!KcboJv*#_28FX!y#gfLc-NUriWS>*Vv`m;=uiohT{`k@X!|wD@S~<)6``6uG z9&fW^K6A9{3EKy&gzI&zSD!Cj^;mc~HaU$K!`{|f3Wj)khYPmp3$O@PeXNg<`u;_L z|3y`*Ssi;e5A#S1tX78Yb(~d}4C|K*4ZjXQQp+Kr*qr|l)Wcdrm<~s&M5&e8m%J1T zCeE?}-wVRn2}!_-g1kGS@a59RhcY-@odiCD{ibxeN zuP2-=$F8ymHj}UU*DVx>qkaw-w~bZ%LHvhx7UlFK_Kv4V_IqEH(h%#mm>$aSI#kBV zWexdo<{2w+OMD*Z-g_-tX6~7C$&f~qrak&$p&)q3iWxT>pF&w(qiNa$kyPblhCwiV zeDvkVxf}NAqXPbc8jw1|&*7ZC*-<6#gZTT(aB{NM?EQ|wi8VlDXK+D$y&noqtaCiQ zy|c^jz~*H6WSMocRf4*UYJm(`OWf_IvtVgU*iRa@6K!vrf4{i`)pS2O1XR4%%MC2n zPgqm>=N9e5j{^FO9RdpO74i60igOJ_X%B1jpSwN=2~w)bjOoj9d+BqN1x;H( zwxo_B^}vPjf`Sr3s(2$uxvI7{CEvuepg$SAKaRz>kq<~nNnL@;L_^M;yzwp= zxZ#-w0;QGpA3cprHbI7%1(te}Ba#7imIoY=83#1Z zr}O5j(UZUyn*a4HYV0k(*FI8iVaNl=Pz~#;HHJVNK&sMq5cEgXSfiR+Xx_jzpo?G+ zz67ddH=LFXy1o2ENteT_-J~FbmVHKyay=vLZduq&mv|r{GySeY4MVy(;2;+l@Z!|T z`pxoja?vzd15jm6e%E9gb3hm5|)wp+{pNg%J|X~efxLB?u_`ql4lDurix)U z{IJ}7ksW5cEBQAvO@e0ogUcId*wc7<_0f@{&zR-d4ieJQJGsBoOK?E;9yOC{OTl({ zld}yYOTK@*E?ge|YoM@s-hxKsqPNf@NMHO{4Z?~oVYBC8bBa=(l*iucYd`Vtv(6~G z#Jhwk`FY=eQv5g=p8_uww2x$Nhr^;Z@M%lK91tMH26v-Kz7dP#dfq3z{a!y337vIVIk) z2YD7;(``6*Ct>jIp2bRsyfjrsueJvHRgj*RW)o~GaEAqStS0@pj>&lCVJ!goN(L+M zCB2(WWn(`l<}P?_Utk#WfUeJ1rAMeoc)0XKUEZ?Qq=TRwJH8Fml_?<4JXZGkFhRNV;2EfW&~>cPRu zg*kwAF&)A2oL7Y>BX}ydA6K+9 zq~nYM@c!*zhy$LGG)coQ&;*7+=RSXK29!=(%*efM=Y=&oZLOZr;0O9dsP322+CZ?ld zqMGgy6E7?sHhE0@1{d2{gEj=X~`lctaci z*J%o>sCB_FZoa!&jY3?bFoBY_uWLt1YyapRpn#H9zJzj_`UHB+2w&Rkb3XF+FS(^GFb!Jyw2id~w4OC=r;i zOBfv}cGs+)+$sI3uW40n^Aci*9X4Ak)qXLn;TNMRasJ!wvfe9UJ_~gQ(A?+xnV6sRa+57ztXF3=0_<4tyT= z^zdrKil)#*=ZMLXxo_IsjR>c}rShvrsAzd@O}Au-ku4w(@l+ z?k?%>_F*ZugC&Ll^Y}jj>xqDBIN?%kKiI?z zqg4Sm(ZFmVO2DgFT8aSVw6-$wMf@^jsF@EYA(cE38yT01+%o~E39L5$@?h(jToG>! zUY&?w$aQYvD`LRZ@6iQ4*7y&EQumEgebjIL{9aJHdwUO7d5`BfLNXrQ809I8elg!M zTuc*M?gE{geG#O|Zbok>Xz$UYZ)ll8)nJ5U>AN~l1(&w7y5Td@NU}2$B_gg1#4hXtE-1asXyrBL=Ns(NcJ1}L zZmLlhSW3UTwW<9-i?Q0YW*mr_u?R$c)&Md<&0iC%;E5iACl$3IsQUf=2+?vi{jmmZYRIW>gsle=T~Yg zY7nufpheEo>biSzgTaW?BbL2EsNA#G)2q>sqzF~)1M6I^>8n~WGN@&^BvS29FNT@) zhC@T-An0!BUcwA6c|w5?qpW*Sje)K?si|kDW;Lc_!dIIL%8XZf6;hRr=82%>_&UTL zHiZ%eZ3z?iHV0t8zodH>J~CnU6t^C|78aI^r4?Z3=7HXT`W!3OAq^Z`FQ@`hBIk+E zM`LD1#-St#>qDoq!JxG!5@-=6icUm~Tn377Dns49=Ifid@=ha-H=WT3@regI1>&V3 z(RgkKwo{d^C}aZ2xKVWOy=2h^FTU`@;^MA_1`!$++m|Xj?-_GEnP*kd5Lc-ZA0ICO zE+*)jb=!tB{};bh=Uw%UHtPr4Cl!ifneBKGC^fPEWC`^giZWY`_$mpyrLg8lzq|#O z`~G+2=jT#(`C*tnzowH*+g2A!8!}G6O|-}k3-DYp?tR4}#pzIRZ)sqe680fufXnUhAZQU0g8y<#;6|(sv zn>M&Y+{f;@0zAVWLF`^bd|Dw*oHk#7QXtjOIDfj^KD`@o<;=Adg9_5mif#?)r1{7I zGIj)cIdb7^MesfxR)pPcg3mCNE8rKP1taI3Bjc9>o1+;sTjo4JFSY6Tp!V{db?#r7 zWng5++E2G!gD(iX6X(aUo5uc|HWj2Jg>}SB4dwXl>D}!wf6JP|OT3hR>I)1&MlDQ^ zS_ix6L##~oU&Yo_gYEHrXlfYv&k#^I-01_;d4_AvDUd)6fqiEc)=h)I4dS_DSAd|Ao%lcwFjMrVQ`c>M+k##XCcQu;)YIW zL||j#?q*L@!2d{4YyVRGv|XyngjOLq(E8u!#=xsR zD8t1Vc&EW|H<_&c`@?}Mv`fTOfM_HPa1!1P?0Hb6a+4;*q!HUc5S>6aV+Bh7?UBnI zHkb6y$WMZ^LEw<*R)_M&ED$^}ovs+M>d01kDKh6^abvD{ASMkoV;utKWov7PD~9Y! z{AFqM*s&8-l_{GeXzB>19ZyRD<)^8F{L;28qk!xO($jSSM^lfKjTWszbzC=3C?JC` z=&sh2G$DlvS6=FEKtWdpX49}q904@hS3$bjbs(3pCBVW@~<-5;aSqzehlW8nsOmJcH~ULrn~(0WVO!AJ#| zrN$;T#C{E;Z@7eZ%dQyK%g`*>Xsd|oOOjsV{-EET(S5@LKuJ*dYslHY6YOb^!YKp< z?PLXMucCV#GcX=B)5cbgrQIcL8lczr(U2AZz29b^HGD<6~b#_ALf8mIxtBMnfuV5fw#) zkXB17m#zYDz0;TE`Xq^d(?S>j)q*!6Y ztZk=Pnx>~V60pUt`aM?`+Q^@!X$&5uUW=CPrmDV(PmdeuI=0!pg$p-&u8p0BSuuf$ zACd1b%(h%|cyGBS2M?S|YW}|Hn+9Nv`p2P4NReJ_ukY=Zg1p2q+G!pQB}`hN)OvEl z$W-sr6eP(5%OGWN-q!U36HK9f)TzGVoW7AApi~Lehm&xCGXKEmgc~aBZ0SW3GMcZW zeq=ljg``IcJ@Y%b=tR4=3c<-eKAs2crv+*%;`ZftEx2L(!RQJvP{J?uAh+K7s>aT#iO7q zYGLf7Pht-vY&! zPGtA&tGTkrd)d}&=*th0vZ3>&YU3+w@0F(C4yjK6HGY{}Bti6}^p(E$X}8ybrfvI= zhlG7Q1Xtn+&k}FuH#v)O zc_R^QO^AmAGM+?=_R=zsE=Jc`^3a`i6ZoR;6mWsNw2mrcb!9k!kj)@KU? zzT{GNP*7)I$kz4NNCl=ZiGEXF`>Ff3tg)R&Z6?>xkhkAl#y#{hiu+J3(AZh!53rqJ ziIytk>oW$8Q{Y%?q^)8hXFofZdi+aio-GmxA|b{94bWIDlrc1wz2N@Zara@lUr7%h zFoC}K2t64F*@2wC{&ywI{gzPtyUBJF@}h72w851(mOvZk)$^Oi(JPM5 zO(Jo-H?>x8G)Al=yFALK-j=Y2g3LcHab!LOMrlmR*z^zt#zIhE>RlVxEjdYoR~!gl zw8Lj|iI7~xZRpj%!ZPnU$+3?)kFu^oojCTqIQ=1!p#FrK6l7t)2s~o7`E<(FZ<&9> zrLCcX71F;CU+YkGNbWO;OzB!GL5h0b7?-_d^J%oybphX06;eeO@ z3!Z?r7gj@%7$>HHa^lDf(cD)39R`gp)v@A|h z%nV_A_O3iVW6M+V`4qhd3fQ2Msw(<|emSQKMAYrrK{x@m;*`1vK^KIM_Alvsj`cg| zu1{BFLCiie8O40s$$vg2w-v-jZLpe;VvLvWbI~rOfBOJ0R0hhYmOP3;xim1a@3fts zZ<~_&ZqU)&nFah|`0B6U@>oUr>~7tvMj@^<)+(6`UJ&UCZqzJ; zlRJ0$OgUx{uE&{uGoX+ay*}iVKno0>S;l9n>yA8`LC-*9xtXMm!w1&y`z7ToIQh|XLopDv+7LK}j zLRaOL`L7&Ni?@lCZsH(lFnH}%d6ka$1TCNL30~Jkq-2`z-wFH5Dk*vn1~fNqx#8l; z#c?P?77BrqVPIt%Bc0C6T?8#xc3hkoq|JVj2c*fWH%$V20{ec@XFnm^tj_P>oqc`7 zD`v`Lu#^<+AUp|k5eif$5!K#CaEH8kqpce>F8Br#M@bai z5b#{xzxD1JX5^_Aj3Z1;GEIDx(}!4$8ag}srEva=B-ST;!4KSN)Ni?;ts?Krs!$V* zJ8Nlq2jlzXVJ z+_#Oy5cY}YFSX?}C+k5;w=3lVMec$oT1FDQkT#COQDF$v(DOYce%@o6z*OKb+6KmX zMq!fC=u7WU=v3}hquDUDojs7RxL%pQytO(i?_w_{WutNHY%Lsuz^>#m1<9`w-h5Gl z+#2KItD~&11>;qB)OISS{1l1^PinBwJNV`DZ)lyo zjCI+KGcB7p$Rz*g;HUnO1gCchc)mAi4Kej$U6*RW6NB)+3pECSMIc(wY6{03eu-wg z$=1nQeSSKhFH0gTZ@9ldWGofqzy}o}X~?^6EYJ|m8}tYS*ugJejDhMb-7=HO5rVq# zOROR>eYxJMcd4AD4qg# z+_5*mD)c0>B-||G@0i5anH~Vd00PC7$JfOVTSje%BJew1DL-3M{&{sV94EFS-W?WV}BPNe)HZ_@jbruf#=|?_#94}5{mhG zk9WWfzqb5WpGUBqLreUsXeu`~Vbg3ZEz;jlbP&}ze0aOyUIZt}tcS!ooj#}+5g;$a zMoIv@g}MeQox9#h>>kt0=wIhJs-w8-F-|f*#8(U(r<#ejp;BVJ0F2ysLz4~^GKO{hkf4O8Es$o*v5v2*d4KY4; zNQ(s2>D&l{1eq{(5}XS9)0IN0ogC)WYy2TDm@}OQgTcw_@UUF!>?T&1C>k;Hqqr@1 zmA~>MvYOD)49R|63zr68YNZP;sO<#vU4PdX>$2K5)B90|hIiLl5~I!lP-%OZRYwSe-q$xpZN_uFm5Uos^$|#>mh9)h}(ADLm^F7(D9Qh2^z*so4V3@p8S_IZ!IgT*A0h%Vh;qC9t z}DCmkv_l-C>zIfZ(>4e2eVlL(W;)|VS8(xh13F83mI@!^pW6lzVW%sKA?qov)Xax zuE-%7YDt6)3j>PJ5q`%xH?!SQCfZU!=8C!CU^xp(o+BhXSvE8dMfbw!wfVCD%WO`9 zgNM;iMZ-ZOBK?Cefuf3YuGVz_LGWMG_`B)60^P%@2&BV)Z+I*Ky#OyQ&qW=B_h=sE zxU^u%Iai2=N@Z%bHt8_`o7KWZ`uXrdX@|s*Vaq?dec4w$65%a=?f^&8N<#9kfV?N6 zmk}?~N5d{PmoO_vv@0^hFdNc>YG~U6JHhx3%AEcQtqbm1ux1Tj%g6JF+(P;?BG5Fc zWJJ>);M&B{-_y8kCIB?I+sJ=PLVuM%gjbis3~oGiiX!+D@K8(e`b=_Bd^b@6V^Qx-h)`;|CyQA6-H|gqg|>2v=m@%{)?4G!_*M1X8V*^mN}>%TvR_U zY9I@(JPh6fM})QW{)e`AGdBI->f&F2!)g70FQ6l|{@-;Ss9AJo6yUW_^273PGv7(W z);iu9)Pn)4c2}L03IMAALH6~<{ufb<%4`1LVG_n39vO=cvA*B7cj|q7WCEwu}Cx#wZT~29&<(`H2!;p14wc? zZ|jkDEKx!?X+=jf!c@0~(W8o-XUuF-Q7zeK$cc>RZvuuMGVYjRGgk`pza>@hNm*M; zUTIW$Eo17#YK^!mjZ439!HXn<%KI2h6d(2HiW;q1Q?#GG;KZy&n7g)3YPgJ3C zY@Le^$AXFyp*~DFu|D>KmiX7aEK-J-%FodquTP-nYPVQ|lo>hSOyGabsa(E`tbZkC zFI6CFchPiv+p!p)YQE7-##ETL{>8vsoY|l{TPIZY##riUX%H z>&sIbFIX?^?+EioD(L?25Qy8vnB$XNb(jawen`gk!Hplh6iLyBt z9p4|@bfEH7e_@YzQK^-Lc)OO-P^3oOrY?lK%t^pLvkoax&c5qZH~LZg_4Uaq!Wcn+ zW~3m$?;}v2Khm*qznt?d&mKbCB(k!(G?_{%LYenp(W&4@&DM3c1A5(l*nwp{I&|jQ z*d3F7u{SYmE|@hmE;c3qh&Sj@J@NA|va6Q&T~~7)>>pH}sDs^rzlK`u`OPc4h)+;_ zBD~fW>-pJd@T*yT4hFISj&<8Qa4i<^I%9liPA|_#5NT|LwUvDD4qLDMT?(VB%>T<6 z?hDupuq%8me);U10{!|2PE>S2ae9zaLDlr$Y5xzJ{ypH&vb{S7K4!+0$_p1{=0@up9ydMxp&@lYNvW?(zQK0`{s=*C!bZx zsx8i|(TO&VGvq<9`4uche>#Aysb~_X$`zxMI?2w28mQfzh-g;s`;Xat%2upql9b9B z^YW@nC(@n~>5$L}5La2uKS{r#;zd3Iw!YJWJMfg7_=X^>axSy0+nW9>e9-SDe$Q68 zFtg!cM(7qvXt-@RjiA3O`jP2b zsHJuHP$Kj*xJG$0lD)U0)c;MhFfL{8oo@ zX}hlH`VdzCcKycrIf6UU-cg_|=+PV)e1)N$2Y~Qab(`>KMA? z;5k4F9!pq#Ax(3S3S6@1-mx(GiQSE#jvA-WmV|VEU|DLI-bcO_{_U#nz`_Q_MLYcO zu~o@_R??S=^TM9U!Wsc^5+G#ur) z9)4PuxF$es8ZTg4d!1QINH)^F#r-EPVGr@OrJA+cc@Lalp1p{rSPb77K8{=eN7tw2 zHTUOpNtT)a67s^V!?n5hrrM&F&LtInreh{{O7`j1XNsoO-y5$71Nxzpcwe zJ*-lMNcP@;cVE3q{iPrN<4*fR=>^`QyB7;agm9EJ(X;9&jCcPT2LD+S(ik_nm^4(T z+0OGxZfyCUx^=ENa=or!V-kg|{B`~kIhuZDz%;h*S1ORCM&N_u=mHeNoMW{1!E z@goNOGw)E1Ub<~>wXfWlWR5={ z4*t(Lr8qoHK9(E?Fin;uqic_xVkqD?wZpHCO-f=LTp?)MU%21(|Np|JJam39Wy}FA%Ji7@NF^OS zO{7SD>aIaDHp~@LQy|RqTHQ~LXEXS1#Mh9N_rD+eC&niuB;}PI@hyw7UH;!~ z3FeoLIv6GG5e%b$g4Ag^=+ToZg!;jkO~_L=H~W_q_T_YCRc@!38u1R)*r#YTQ!DKx zFl+&kX^yCc&5xAgM!2QvZz5sofLAVI*b$QKV9H5?bmRsj`0Y3z&4ze7tf$Dp&Spm; z8gB&H#aze~iVeQcYzKr-SK#!c2mCyL9vfneqoL) zkU|kMl$n#}$6`lc^)fMMD5t{SD+%$?e_-=;79tqX5UwreEMZyN0`Oi;em_l*jbxSK zVa5OeU;0YNrqX-!aH;wc0iSgZL-<3kdK1+*H^|3nY+EBnp}5Um#+;+UCFJQnt>ixe zmBw>jmc=dE)>WJpYPkqu8ZRmlQ%D~GYeeOGcMUt(jBhNZ7xB1^F+Rsd+Mi7xD!E7? z#8cbVaYty}<TT=X*`km^PWWyLcSrZD{JX!dl#s>(obn7;6Dd zOgO?(8WJZD*4am+nhsCzRfihg~_~+lth?5c47A= zzT)8cg6NDEgx*IdQQKKdqmG55(hl6RWU@YW-^QC$KUz_ANL}8n;HSzY!l>>c5_Kvb z5y1p=xQrxG|e&zlb8eJ7nYQ9%+=ckBQ8UW6?PcGf|izwjDh$01S90bcP8@P z|BO6P*J;N0b@*lM`%E`xH0OCHYrZ$d0tgdl1%7+SBr_RyCT7Ibhe`HG7LABdZUj)` zB}aoZAIlr|tG_uaza8%K9!t{$no760-Jn$tpn|iS`9@CysgPzDArNv5Ai9y~wFNbw z?&fItSjL)PNQ|=WI9)e7x8r)eSBdT$Gi>fra~X4Q?1H5^u537x9(w+!iN6Uzih;CT zd(UH+e&?CQ2NdHazva#fuXJC(+!1G5$i9O)2h6HNFLNd`n%eO3P_2Bx0%>Z>;A|*k z)BNy|uqNxPo!ap;-fL@`lGvcIsi8*u$xFq>ug!kxA1m7r>16n>&7sWLjj^^adyamA z9=b66^JgN(B2dz?XY5PYY1N)U!UKz&U(en!GD9*wI(kbvSulbrgdTutk$<9NNtsG3 zzCbJ9+3o(d`;o;G=zE9meJ;xtPqmzM``b|TX7RyS4^a_}`aVLtk_FS14wxkxW#*wm zPdML>l4Up6MIN?F6gK<9{NnDqP{iXyFLreCr*cavu_zk74lz7mBoihh-X`}oFX@2D zaK^*PFAu8?xk3&^wxC=kLNf9c6yatw$jH~cwJhT_v+P3rRR7Gcr$qLX6~g@gE=Hv(>(BnUidtc%+9#`#FZ66Y*Z?!~5+S z2XdOS&!L{!pvKkt55vw#Sngz)V5c0K3(aIY8KEkA{?)lBtS=6ya(`iQPiCy`L@+^c z;JVFuT=p(9d1LdjmMgzPRPfI`maNUw4j{w_-M!!ys>lQ_Ty&Q7Rjv+4-)#z31UFIE z>&wgF9cz8B{gD}2FJz7rt(dE2p@${>HZx43gDgkL-a>kvjrVj>d3m$CB`8jVdVpO~ zKJlizY~fpXng7_ywWGho`11spxfbv#z-)Go-7ne%Thyo3Ut>~qU~dUdS_!GEn&6X` z1Cmjc&5b2qUfsPIx7G%&!w?n@y69{KNvcBP`w|wHYNM-s{EJ_qWV;QDul9u|U>w@# zNnE@>eWPKjXCbz`t7<~>8vp6=QxOtCu`eH|v2JayEFxjvE3xM|J)75vNfpo`+;`z2 z&42_HOSp+0cgf!C%W5Nu>lyRGuj}p~g+5#UvvSfOmWp?Ln@B1t?Q3b5qPe{?fBSCe z5pKlYTkRC;jgLhz#*166yk4F;bME5DK0ks3V8aSnmVaE=vBH0E zFJF~`bU?V**}ogiO$B()Skl)Lb-Fe(K=K1LVkUJ=*WPE?pM*SehAbNK`` zH!w(U@5sI9bg76K7+nDx^lATwoK(+-2RQQQOS#_}`fIB^0_bvr2h!`J@jI}G4wrc^ zvv{uG%(vF?HxiF~c{HHhE+F80tJ`*4`A5v?@XA+%YP4asCrAB%)=AekXBD{Wz3?Bj zB{YG8p|s~W@|C$~P)|x%)zxT|s#Xh)?k?o|d+mo$Ra0LF%=a0DKHyq6tu3jolU_JS z@97e(?Yig1xw@uy+O!$8dx_7Inn!w;%^kX1AGDk^^bQ(~p>c!gB8eA=K`BT^gFP!9 zj41DAoCE0rhKf7c;a(<2972K38sjb{s@p*{t=`@=eT_Q%QgJm;H2jC2)%t% zEF)Ssv1W6_fIWEI!wfC_>O#ZL?~Xn5KTT#6MFN?51Ajj#Tlzks=eK+kq&!EYmdEgo zj{-?0&^PBs`5AGA9&zC1mbVT@CetM|i`ekXQcX(tnOziv?q!iWG4JY&+w-B*O17;| z_P`_DuSfpPAowKwUQzI#7$VdHM$hc|$LY_d$oz+Hd;qd1>{=npl*^i(#(5g#%f14|r-9bdo^kO&B|$fafInlWpyR znRCgg7#R+wblRWNkqL^!@M~=wFJ8TH`MOtYSIiiwmuME$={E}AIey*`C zhyWjfyeL48hw(VD*f)B(d=*H=Kl^W;{MDqi`r2vbI3QYS$!{|jo}>r*NUaSfIOAWF zg2qTMcXvA<8Y#t3cdR}GT@-AB>YT{iF@tGNjF*p7*MJI`Qz8dN$+!1A&4rM_2xu}7YB`OYY{dPS{S;@ybE16g>2U&L*L2$4f>wW4YP+_c|CjiQJf zxrWODkP=8nhp+>4eg=^fII=M81aYwvM;u8rv|6t#^t;IAs^I<&fLKfOjUq>1(@O1U4Jdtdkxh-TDV&Bq2=A^Ga&yhjK8|WH~4;! zLRWU%>gO4%(e(O|FPtzNP}Sx}pEpJW4A5z8@Jf1m&_C%z_jvK5BxtKdt{0%*O#zgx z!@G%Y-!TI}8xaHgY@Xk@%Kc`HEB-JSbzF^lx1eT^4vy4Pxu$G$ebf=(9+zD;vG0VR z(=dtm1dutVJ{>Q>cg9tI?yeN`@GOh33THBxesz2(9ls{xKR85an*1%V21?P^*SzIP zL~1v2R3Ui9B%rAUbJqkrepJ#ya?FD`qfj<+zBGAUadWMX&1DKX_J!G4>oKRk4qg`%>{*-6YpJQTJHkzqFT8qOHcrQy%97E$*|_=V?XOx~n=q z-fTok+pGHU9$(%=J;)O5?h<;NL(qhC&XQi_lUjSS$;C4!-URn^o}$K_ZD|3#B3dE#O|v8A$A7bsIL`^F!2=>^AXThg&L zOv@wa-eq?z*vDJ2V}&t^46lF$dJl^ZBJud8{w zh-5|m#0wO%RR`SIRBxgJ`BzH7c)dPAkptbS)B*)f&)Zqj^GNF29RB8N`im1LFofr)v*Vm*((|)Ky=Qh*6~yg1Q># zzjo&~3@6pk?HX;=S&hqG+u<2Jd$@91&U1K~I>=i#0$|s6yI`g#iE^05r&c3>84Ujp z_v(Kkwa7=ERHLQ(CJ9HeS$v$K{AOl4Z-2?PX(LgoYHa6$yGoZFt}`fCdCpFxu1qQylr%3}v^~$`H|G z?}c+3S^_*_G>1#J`zpmHfNxf>@5^=++3(M&~foBx;lb^`9ZVy`?6x zk8=+!#(Ez}>n>viRTt3>fn(ssE+ZUIQqX9{D1Q%vf)#DnFY4;aP zLB;9~>hEQ0h61%2t1fl;)wKtu>})Qo7N9gavZXZXFqdl5Mr1bAh4cnvGb3M$tg`KA zM`u>AlLreaoPGvV*S}pJru)EEIMtRf6t&FbsQE{At4I#_ZI z{kUU6!1;7C!KA0eFMj>wj~ZM-S*pd`7h(sJU59>^8ie}>iewu6)TNgtddRbE&~mgSynB89)l3&DOj-$H-bwNPf|dQ3kK}8i^v81F(B*SA zI&_TE3}>mq z(E03&s|4L2#b*JKQ!q4#U-P5WPpxX=Vog5v&*7K-KN?JHkDfF`OE_@h=7pT1x`BOyU3t+L?gOe? zY`6pTe8UYLcS>p3Io(*Ek4aPLqaOQqw~RtIs9ckH$J4jIqpwZ#V{iQ~9fMneq#Sq8 zkj=slJ~GNDa(D81c_}hKFQ7W?z@gQAUYnbp~d914nWQE>eE7}{y=k^lQe-Vt*9^iX5)_&U@kR_)Jg zNadB@I(tqaB`j_=EN+Trd6%DFz>hr-+or7Wdo2yaF{gaHFOz`7JK+AyL$kqWu$ODu zXRtvN`kM{pNd&;!TWtETFPD3Km!vY}^Jdk~cO`NmJUrjtN&nU|`_lw-H&=goh&;(l zLls~6O(+&;CCrs6EI__lA2;;^moQSZ9lN-#ucfS_@zBR4&NvWk?)8aHztNRGh?ZU) z>{(vv2G-ijc^=j2T9vZV#}emK$`_lhZo0c_AOCCVmJ{_}E}Hv7XuBe#UT6sGLq);A zxh&IubdwgKB3R*_di8~k!$AvQdR2st_`CaDS4QcFQ*s~ni`~l&^Aucoe(u7jnuaA- z*d^%`eArYZtX)hAbFaGnUv%&*kh1%GQnsCko(+EZp;G^>(!V5dOF~YWv0>11qc}{x zsUHj}n<-}LT?|6@Ca(4wY*n3g{y$2CZ3_&1qp-9%?C^5%9B@}(1=@2*o?QCc+*HHF z0(r9yjm}2$O%w8qp=X-378ET7zRHyU=JlJO@S~`B%#YNU7IX{)sa6L<)Eh1dK6FOKy zrnpsev*1q?q01nmL%t+?^R+xYk`{x;7#z!IyE%ZM}SNKR8joNo(Rx z*>Y#r9H%||;|DjLleXe82YyD2#^-YzIRLQfW5`JffYcpVE2pka1k8!xeE?F|;?8#&@E1SNciR6;hs{inshd=huGKPSnr2M;nIY zaAVstFJJm(sv+?(Nv3hQIRURxO0BakzuFkYEy8<#{o-vIK*GLZ4mop073SE(5Lbw* zT}BHBO!>l0z4;$~`X@dt5A8WhCk(pq;@Ne2ugK9o3Ln62%qO*4bQ9QLddS3pdxEmi z&_s-$%Tm}kZPr7L?MAjOb~q&nc5XXpy)FjBq3!|GsUzUzeQmwdCb6q%+xa`|Y?xnj zRzRoxOCw!%`bztv&L`5Cb10Kp>sc<@z5DOGsY`8(HDSuxyHl3iCPaXLbf(5WSzEwE>V{k)<*Zlr zo(^2y3}wx0p#@9!b-XcdaOpYM0>j&*8>!gM5+zld(^%B)mi*ZlFVCgL9S`MV!p}pK z;6mzqwGtw}>EgSZiwntxE4gQn!joenYtMgQEGbs~NxqGxj9~krre>$tqd)u_ zyiyP{g7q58MVa_bk>%rfrLD4^`6$-XjZX}dD0$58ipJQqL1VM4f?icn7?%1POqcj- z3(R0~k00rzy1LeM`GTqxIghQT*;Sp5#FYT!E?mp6FPP188@JwJ%wnN*qZ+l^3LXZU z$mG{;z%CB2={I#Wv~`^+@FkBg({%A`Sww*APqxh46s~Bz`e?a_fr&3X05}C`BBg{_ z+eaC2Qg7irFIgiRCv0{?^FX-jTtoFQ6DK;6zolKvdo0KAi$(xYe08rffIZh?Ht*)X zh#y=P+$PHQd*}lztFR*Uiq@P0agOcxv;HLB8@glDd%4;Vh}Kpb+J+t59(lKBdTQCH zdxpwEoL?X|LDs7mymS1*kx$vq)+oRGt~_T0eTK->;KnQ6H+8-ejLW-0HBrO8N9-%& zfz|{UThG!u{(~2}wvgV0IbfmmhQ&vqS6P=$DV1u>j8;x6S7FK-o|U^)%qN;)W7|8N zxIz><_3@$Y9XKY59j*0G9SU4NME~X!Ir~g18cg9rVNhwmZMP<7M&A-?rAL zITpxz)eJn|Axx4`eW$%-h9MG4|3M#F)Uo6+458 zCDI(mnIvN1XSJF~fgj~WhWjHqKLg2WSh-R%i^9rVP8FUGTD7}x4XZk@(NVS^VQ;HF zD_dKtxV_foz4o{C(@F3r_pQkm{=PobkoE2#hk1)YY@2~!FEouBj`10~rt`(?8fHxh z7rBqCQR-z|xYWG!5h?we9574fQz-)U^}yJ1+{kfz+}`1HehC+?92+h6&DVp+dc|N` zFOav~lMG8F1F!k(UNy>9y%Rp(WsN}ER`xBzN0<2hxOu4ksjK!g%u<@uZ3$_L^#!5A zdGo^eH9JK7KSf)~WJxNw8+PPeO4bgoQ)t0)_a*B9kAp$;$8 zGVB5Y!Liu8vRJ%m{#GNoLc0WjonYeo$WNVI_6Ame`(&Gy z7{00bQA@0MuaAt+i*=5{uT&BH-$(D**kN}BgI=c5t0HS8XuZ|8DY750W}@-;?&Ch> zC{4g|zEi!Nu@aZNE<{*q#J4oORnHAe-jY<1pcUvbktU=`QGFk6I@foyQ`_tJ5w8Y% zOP0A5ux`#13_gf9@j-1oXsh6(mIe|ek_`9j%<%4yzGF@XX^<6ists5e?xRTH{u-0% zSzpmtbhQ%W!moGZ8}{TMS(pVBpo7$J>-~do6by3usE?dHt_|FZYtw^`b^0jSRlCmC z7+dwWN@J&&S6}2(j^h^o!NsHpPg=~s$NNk226r0Ev{54saO8VxH7V5LIr5SkS=?*> zkk$YC%of}LD&;omGLIAN}2uDpz zbg79|Fj#H295USn)FQHsr&=!H+r?%95(@lX6%q^_GWZBqK;5my0ed2sK_`h+Jk8rU!xp_TK zcwk0ma+_wzldzdT@MFAuBnoCiILgJxsempW28h8dZkBKSi# z$1qI>%IU6V-z^;%K1l?mb==sannP^zBEMHFdgq(|;$Hqm2I0;4Oej<*8Al;LbUq0j zBn6KwmrvK|%w8#6;;fv!Sj9R|h<@GJ^J3$sk*hII>js|wKjY}x8%8yXcp;n+*(*=!WLdHy zsMa;M@*KPz#*D97S}N4$o?*#cfTKD6mC1M637gZWOAeS09@m5kM%}Xgwi7iecc>;I zNH;70y6$(UjfmmBUezkOQZ(m5Tw*H=R|n@~P%6`c9g&hh`6HMR_4)JrKI&(uxrdEd zjz?m=-`?-T3|LVaRO2M2cGx_w-C_roZobej zrdu(vS(EykgS-?3b+j95d%~gBa#Nnx(C53@^%vMP<0&%YO5V3s?@5Z?5#RxZ)NDSG zQ)vblc~!hBstrWsgXccx*4lax6qNX%gQnzKj12v6C%lAlHnHt)^;*JW47Sc2CAgHt7>f;HW7<^D^Ie$*c+ zN)r#=(6!H(cvo^DPx0N-{*#qD&T+r|6&Z((ITYuhaqvE$*3mn03#GZ}yVmk1kXRQ9 zUhydVb(Hta*vf8Ly_Btg)9>;ib6C-06d0Q2cRUB3mPmpL&yAe}D2Z1wa;21kAwZ-wJJ;>d@DFpK4RY9H zTB7u;dzN&pYK~~%AM5GsJ9vmOE;;ftsfmF=^{`@g4)3286VdytA>fqv$>zM4{ir4( z-sbxJ-j*(h8QC=Z8p`ngW@kf6lm$hYW)O*X&U8k=p~a)4r0JUy{~| z;Vh902^A>|S~ku;kzDoG8b4nmBCn*ve_{fy%5N%jqQe7}!A|9_5ol%5INd%|ccJOi z>;26HZ$tTF-cm|e%DEbM7e$VeZ!$;|AODVnOVfJ12RqHmkZkDildOEhoZqW1dg{{- zJU_rwThnlCd%rMdNR1Ht4kNMXk$LnIqX7?Tge88>#ebikyYW*yaQ-jJMqdQJbWDi=S(J%lM_gYu}Z zW-ZFE7?ms}s5PhJk_e4{)foiy_*nIu*$dd+3=yH_P6(tgV0RS7>^WM?a=AfQm512F z5O$1@RSyBm7>%pDiu{Ge!iHbU-#BjSJg6at1j!8|G7oiiTb?&o&ma1WLj&>9+8Tf+- zMjx$0QR(#eNaL4A19)CDH^c94ySqK&7tTO8R7Xr;D3#og05rky>A4MkZ20DCi zrmhB_T7hqc<=``@VXr5XYt(4MFiq_>@_{(NbJNd6i)ltK{1utv!Bq>gAqD99!){k= zBzizLoLe@@C@R^S|8`1psAN+pw?-5EU54I2Lv%w9Y{V+&1}A+5L|nspZq^!#Vi7Ws zW#=}*mU_Kn-FaGZ8Q>@l9

=cG;;B@a51p`w9}$@F{RSe5{iFNK>~&Bc5TTB*;Qp z#gH8E@+Kq`DiLvjm40+#!@({gu%&wbenYGGjQSuVLM}QkUL^2ox?4aIC>7{9xKFPQ zw?v0>opI*s(#jQnIgoT-*QH|)!=)C~@0hDlO)QK!YeCj@3UPWM37Sek)Bj86^aWPMou+hq0~Hs*Q$PBB;$m`a@wb z($9t|q^X}Sg@cpGY=P?&R+Qq+2x%nx$uRQ@MtSp%YGjUWABDjcVmKNAN-r@tf&~KZ z1nq{oH6sYShN17dyDW!UXY?0D6AW0v5$cO+%h#N4Zf!Dcgw+yR_z)2(Y%l#)qv?MO z02QAKT((QL{@Maag2jAg^7={4O?A>4=m{@ON(C*Uuwh8K3U?yHp4_eLpXWUmkxq4s49<{Po zi~<{iRh=~2AH1<1qZzqTmuw{+3;i|Htb{d$V)4yTym8m)KWL|fJ0E}J+$D2ZGbYSE=3hP4J5U?duMv{(K3LU<7L6hZ3?f9q4&obhK84R6z`BoS_?WiA#|j02M8x@=gBB-sfG zhCcVFh-7tMK10UDF!j6xtO8^Qr~yaFnRD~Ekj5)f^IBK zk1XHM!2_+x19(o%8*11iAhtI%J%ZYSyO^09O!$%fF)hh3X+sc&Z_r3T>3EOXPz<0S z_8cLt?sPB-CmJD-F!ec^h)`rg#Eik08zRHg5D&}t!v}O8 z8HHRZ&$i6PX2ifK*$H1qC#q6CyuCB|!EB%VgD+33nOP8l3>l`~MDT;3GQ{u*A*zmE@YS-2EJ$%0yO{hj|R|MXls5R72SE-*zLxRM#p_7awW;HMVaI6XD~BzSLF z6D+V0N-(jfE7dTBNE$Nsn<7#fLg1{xb`T8HR!ver{Znvd2!2E=3JzfvZ^VO8Nn|>f z$f;{OCkacumx6W_(x2P=d{aA4&zlofVC|F$*6cCpA{)ZYX2)#DoLGqzrl~5iFCZ8~ zSYXlu1vqVQjZiaFq)a_c+y#fyAk_>WFf4riWR0&ksDCAq z>xkm3`WKfWGKL6V2xDlf9Dve)B_@9 z>R}4uQ6iXd!Z70&Has&Y%dvo|#oTP_4;D7`&J4JtPP+kDhoH1-=i{A;tS`|+z#Cv} zVQkOLsTeUPlA+zY|6_#V5mjGjxZCtg?e0RgDn`PgiYV1D!2|FHsV2HBE@SK=v*G9}yctDG4`<_KGS?`BWhY|@vmtBD7>v#yE3l$~0YkDD z3bQZ4139Rn=MQ4~;rEP^Jy!4bz*3pmOX!r?iov{oWm%o+|1M_LdLMspOf+wdJB zNYlq90+GDl%n*`>aRQDf8lecI11Lg>hmhhR3Br>{zut*3r*1qr@(Kvyex&~qI8k!$ z*}1mmijvv*oe8$L$DXC3fOO=42i)24)B6f` z?vf0>*h4#=+M~vD0_Z%3-dMN_@a1pdLI{%hVQmH%W%%}R7bC(HVS_M(8!=qo%*SIL z7OqZ8rym)kvf11v^I8T&0X1uw?Nw74<|Ln^>V3}{g89X0=r*{3T?l9vVUjT`^NIOO z(Qvr@A;-?Z_A$gTs{gj2J%=I04-A;Im0>xTO#kM56-2DJ{NaF?npl=*L%59mBk8G= z)vFv*|C7Ci0-WzyRLtdSuT+^weM^>pQMWw~{(`V5V?CvI9kdCMT1RUR?S_?RJXn>*VUk2C`c(JF3g< z-FMM^1cH5RlVx2ttdhzJWnn>b~o@Z$X!=_~DU*!|Jd0 z&sHoQR`hwXfcu_w^$Ng56fQs z|D6|a??m~(8k~oB2%c88)bz2E;rj%*2H=Q1xIrF;{84GI?GP66*PPUmPer{?Q15es z&?pF5L9W~ltNi%1l&5`8iYWLCf#2gD6(xF#DW?u7{;B)K>luj{fYh#ZdKCZd%DT?#A}v zZ;#V1?%bZHr5{sk7Mp(N+X@raPVA$fMAzt;Q>dM#8Qq)ZSC=ey?b6!Bd|+;-tgHf19*8b{KD|D*I`0j|wnKlgOtdVmjO}LG5MR#Fvq$uanKLx5^MjqW0ZUsWoCvf?gSbnU21?~l*Bc3tJD(|4Z>ASbRUsJc^-AXwhR< z2nIsXLn9+`YWH0VkQlR~?1F*{ot>%4a+i0dMIQ-+T+4-etsGRK?@RCm>V3L@uYBu|u-I1{%4%kd^qY1(+BkNu zDLSsUF#YWY1MeWuj54ze@0Qlszc_v#!Om>D;uY+p7OP{cdFZOWawo3l)Cy(ePG`j> zDe^b+vBz#0AN0(~KMfcqcym4`p_!isny4_Si@yS4b0l*HXE1ptGyx7KT1F~M=fo8-3{``!4AR(5-QHV9XkbzSTJkKV%l@V=+#JYSIgrAPq=ya+*o@CSK^h!s zY~b*UV+j*&t(8N0LA*EPf#6~Qz6p7*mo`*Hmn6K6Upuaam}L-N%cVnWo4>hy{`Siy zP%cm&A~4HXUM& z)`gJ7#ryBrRn#2eancEI-gsio~avb`j*Yrys?h(pWz}n(6~7 zwV(}_J~DvaJwN6+xH1;L&NJxZ2zOBtE(-~H`0pW5rJbJts5ziLfBcN@KhI2yGx#Xsvz;khg99b1opa?my#HtsvWz_^R@jFeNx=0Te`hGObr#^ zME;Q(M-y^Efaf?6xc+fMMX<(vId)zX;`jA|XCAtSGS@2?(Ej@pR3etV-YXm6kf8IhIa~S@9oR_6KG(JH9rJZVM0l|ID%RTPW za7Rvmi**RSb}JR8>l-hd>MoMGzyLGOMyIf!CWIMGc!cKweEn2y>qun|y_qf^z!^_! zpJ=F3geFr?XVcn6F#*Hh4&X=XapKn&5sacsXFe|}dW;j6;)cGQ%5DLYBmi(24@#$) z;{}SfL#g`WekAF4rZ|(tNuaj)R<27+!-`*GnLj`P+Z8UvT&yfO|7i0c(6oZ}@CGo( zE3K$8-__l4iswU~%{fOFD*>k<+Tg_6n46C4V_8PLS2U8A(|l~>CVBk;tJ*)iOL26- zn`caB88}dQY1IQAN9Zf21Gha>p1_;)j%YJ;dW!1c=jpXaw zL^p!`DJ9ln17Y7Gv(@^=1aWcLsh@`iZJI8>P!62!D4!q23C-L`kKv-*P4r7k%3CSo zVWS{%v^K~(es0|qH#((_omqr!X(+e=FA7x=a97*Khn!BYP$vD3B}c_;?BMQU&ox|f ze;oQg_0{L1XA?>yo|9NLHcyWt`G~jG8oy)?5zE8QBoXV=kp0scD$liYho*jUPk%*~ zk@$Dch zHFn{3vApMK-gEd;xB+@$1G*)a)D+8;pgEP)-g24=e!2k9z-?{=VvP`_-Y?E>Zmx-AdbDY829(hXWxpO_7cfr*Q+0>rTbHwDdI z89r@CR?p_dWj8gFCK?eI?FqmhQ!$iyAFM$x~V zvjs1Df?V7?8?}jx@)9mG78rjXdF$E2d{9ANTV%xDV$?o$t!DSmP^nnYYtJ=hK<(^s()w^93r;Pn+a=`dL%VEWUu3+-Q@DA?6ehev77DI9pZg{`-X01R#V`Wt@j1 z(?KxKn4a-z@^sOqaDG$j3dWrRFLz(q)|{)^!8uHs`3IEEaogPizVW!{N7S_gt2+7u zl_+!TC`aROb@a`F(t-;@Oy%%8nImV`frpaxH`q(sEpA;osG5wVut)rCtaH9x4;66Wtdm8lc zU(dmM_o3IjueV;;8cCh1i|Pu4ck_We`}-xmwMVYD*9Hv2UDj*&gk3;*Tr5wKBKRk> zWLEux?{SZy@c49cyYs8oHV ztkyUa))&Nn>ZeT~en+1{ew0m&M~WZ)TI!#7w}?KZl-srK>~%Gj(6$4FUq`Gm`cYdxD{HBpds5xkuDmAp2_ zc^6(|j2!C%P1^hxtpwkOAYGHkeV5D+nC3^!B~a_~Dy@V>bHP}yPB=Esk~j-Qu&PPt+da+oHG1O!_n)* z9T5F~X^|2Ct`VT!W|n-5&wb)df?vfdV@wq59XU2}F6_@2a^%m#y-h0rKdp|@$z2&C z;hb11+I)hI_E?saTlBuvY|(i8zT0w+Y=B$-8Brp|q@$ zl~&5z`z?Y+8l z6M=x$P(5_Fe2SX(AE@bl0S}*H56<91EDPwwIdh-U^Fa+eW!@HXn(VBj5G?v1G91ua zXjNXyuTXncA8&pE`6D{0Wd^Y(#Jx$oT#4;9bal-5vB8)Bt}# zCh0J#RWpo4rrd*7jxdo}mTy0$55cx4-fJ4&(e?AtU+L-Vo2DXqrZQMF&kvUhq&hvQ zRE;-m7PVu%QW?)(jX%V%LQA>X5Qc%WOp%4Y=)tXAc0u9v4kc zqHaF5KlglO7cv!xecFud?vkU;!LVl>mRi5g{pVgD_;X+57@xuBy8LSs0|M=JG-*H{ z=xD7JwQ`^u7eW%6c!Sfzcq8{Ph~Y%vvnBFL!dM#Pfje`Q@RM$H6BFLv6nPb#C<-&JsLM(iS{gVfgmpoH-t7{ZVZY3Wxj;C z$#hm1S(HO;I)ILQsD{D2wSJz`E*F5PMlyrruWNLV$1NnXb29M!lSbTB>ZE1mB8s?y zQX3+!RWtYpNt4%Ey4zrvJU4{Q4-tK#h_@tBhn`zava_pz@!H9MtoZ8y;@fB_H+#}$H z7qvKvmfx@Gajr-cgwh0~USMjR1IEhffO6K2vwCDv9&PasQD2e>uwtG@P{;S+f;-i+ z8alJB8@JMa=ke3YB9^Eh@R^haMM_4^r%YKx3N=xY(HK+c43p%$mgWz?^0b8`B*o(s^7#!DF56;@! z`Fh;K!Lpx0wPsx=?q>_vY)Q`|J;Vv?aigQaR-a3t&nfM&nrzl0b7~3APIK3^d7eol zNF(w1VC>26#qjAijrt+4LY%H8_BfMQfu@)ooh=}=t@(EyU}$Kq(fG2*Cg5{1 zl5zx9vq1xl{(+2iLR|VQ%c5$?(=Y-rY27Jp!9@~NNV@;=T+na|h8L7Aa-dFW(roB+ zw{cBQVop-vL^mSE&Y=kvy0y$7mC6PZN=6zdH8O8cc1m(7${>TBi|gfr{61Z$FaPZpH90E z6}hK}gpC)o-o(;t;B5*xi3qMh-BP8dm5Ci}tQ;4{sRe6GICcnQM-@BchP4l>KPvj& zDcYD6{viG0jjPdJ;n7`8&C03qQhp9O)fsX;Sj8kE<{7vJo9znMb%|Px#Jk3WS@Xhi zbe&`zBH{w=Pakg_Q6Y^M6Msj9@D78SKr}@WZ`PP9OX>>!mUpth`twRGzYtqLW5iz( z5H<{KyWe}+$-A#Lv%2t#AJi?D~X=&X@uUyEAhyk!bneb*DS=RaqUJOI}2+&EUODFIbcrgOw? zXQm-}#&%#~hQ1v2*eCeBguP6^^Wk1ky+mEu=UM*W>hZ8Ds@9l?upkj>>ZQliZk-(k z+Y#kavzk5uEM|rSBgg2G=@9TYqE8x52_G*G-x?OCaMAqLU2Cq${-%EwAQ4p0CnJj) zg}Vj__~Fm~raCy!&F~HmfAaIFEqT-}XaG#L zH+VK6y&u<(JgsjvdD$ta2$;T!Tu+3g27d|08-NN;zzhI1EDN|>{NkW>4pcabEzmP5 z=nl5D8Vxko=_3%@uLFCaS5@Zc!5R(AqVgcD<;^N{C?o`haDvJq3o@9@Yul@S+;?6R z4#LPg`$Of4>#EC9LDASN~$kFkYIfK`u=n0qbJt+AE%V@B%LG?RBO8)~r}b z0bU+h=$dh0YMOQJlT7z+uzU6FW!0sIQ5mwphuj`tF&z(f4r0)+Xmh>Jc5@GooM7OF z1`A)F^uavhOxfzd`+c*wTze{5R&QZnPz%vP1)`s5$zoypEP-B3a0&li&5a7`I6#d?4ar#1G6^etWN_u>pF>~T@Plyb1y@C@PhAl*3euII6L zlTLJfp{eTr`<1+3jaD&+X;|r3Y_vy|agsEnG3Xkh?j>%bKm^?7jR}X;BO{wHUAeWv z;FIl9&oh?p!+N;XSgT*v)Zbt#z;V`Q|C!%J-_jyPb=)?-boipd(xZ#bE;TnaY^I2T zx_5+DcZ8=x=BkL86wwxq>`=7Fj#fVdl#Fr>QfVs=RrwE#ZZCV4`cUXup}4=+>S^tTdvXnUb6)mbYUPf1Kj>J!<>A}b|8h`{-n7h~vm*z_; zjrseAs3l1(n{i5E$HlvEZ-Wp!rH>dI59fN^Y307Kscoy@s@rEBi<8-JizC*>Ti^ZM zoGsy^YlrsUTOT5+{W|wOd%Y&KF<9Q}?q3_) zLS2B4DCnXtj8peGk%raQet%SS>v<5}WNNU|6(4*3r2dHp+18Pd`h6{u3Js6Q{T}1p zt5rz#>0W>jZ9mmm!X73bTAW`ozX!mXWN9(^NH11yaJXN#{6SkKJS@x z_}atH5EO(7GTvS)sEK%0CHt6lMEUS$z2_fwp2Tf7jWafoU3>M4)qJxPvleE@ka$vuG^rax=pjZ5@DZxO&P7a>j_+W;X8h2%dLRxnI{xO> z#ZO-EZO#Ubt7SI~4XiXM8QY*T447ZhuMi1LB;b>cq`&Z7vEr>-Ps`=xV?0L2AY)1s zUwIR0?uXdY5lWNin=ARHqb?sECpek_EgYF&R`)6RTGtMmi@<_R5#=MYIK&{xjap~=*huu2zoe$5gw2zZ9Oukphjk==g`oSAW+M`rre~)i&|G9WFui@?mNT))naP@+V(Q`My@9FMdDKHN2*&tZ7Y!sVfcr;b`a`nwH>CEML+P8)knP}N?=SpnogL9kZoXXmaLglCTC@gMG;<-yAb5r*yBMdAw_02E9&c~7|W=6^U36a;!f7!uArWwYMJy|!Jjye1eJ&tPNnP{+Tz1T4*#wTv0>b3p)NYT!@WfA zFZ-dzKqRf(VE$3#qC>-#{D|&j)ZxcU+LBMP1wY-OY@g}z!xh$GA_NZ%hEpDnH*;`N}pS)p1P8@_r z_f@rjYPXNSyqgyW&9l|47+vp6m5dKMzEV|IAhFZQu|Uf^p{cHTxO%7wE&hoQzAR8( zx5&Zo>7I@w70f&swqWmGC}>Y2u~n*vQr{&Ub2+l(T*(qSi|T~_ezz-Q9v@}K%`8wl zQALN!66B5eSB=_n*fI8Q-d?p%^?Nec&k(*{K-cyw_>?k!?f9_ndUb(GV{T!~{bnrW zI~nKO{aUpDtr5(zsa6>5oOizE_3dPlFAcD^3m47bT4CaS3iMH+C{a*URlD^Z1QkH@ zoNx=_|3jI-(ib!v(2#m>ca;SfE@J&mi-^0B-KU1JW@T?>_`!2SGs~0MhxE^O?+yD9TQ9VC4XM9!O zJ~-U7Ow=C{du!QYnH9>2dt3VYe^ycS_gzbM`~%NN*LnHx(l9#bDHzsv3gx8%&TsCB zW9FQ!Hvf?wH-J6c0ZU5B4nbc8I)WYq*g?NwwzUsY$6@b>($e$3VHqBeN(e(6Z(QY# zI9wUq4a2uLD>pc1+cd+1yL57G$oq5J&yAs=>$~>#m>=HXB%^&z!_9b&5F&)0RbSc7 ziMsDX__Vz^klD7jtkQ@5MFznrYjof)t~oRzC)?Y-cg`!Y?kJ9qDK3FZzTgr)A}^4ccxi>k4&U9y2weY+1Y%`cw{4Ja83y)p^f z2gX1cdvqYIFB>b}*TRxAk)X1#IZlfLfs==j6Fr(c8egM9E6oBEm3DK zj8kOJ7rDUuVfWD%_+kMc3yysRiS*c&&gN4&K!-GqPmu3P4Q6!)(JKT6=d?GR);1{I zu&?X1W7eK}_~DP*y}OZ+kkN?<4ahUqDaG9%1f24=bUSzup9K$)YI~eQyXmsET*C+$ zVS*1~K^nb~j0*EdF>ckl8C=fhwl{-=B5eqROJcmnO?eUf);kR|6|8Tug^$^{7O&BP z5Lbi>%5We{Ep}A=^bHcXt1t_a2)Z=r3vCr4NC(iJBj~JITgQNG&%7DL2YOsFLq8E@ zAeTu~EK*{9+;+!In~tpzi=y9;lu3tm~uV#W^p-S-lWhx2;v04+8+(IlTx^F?1QpKB) zp-5aP9SpRD1NUuK}A5e0#cdPcur}%vD#0ompRp&rK}V)S{3(>u|meoAj4Yh>A2^) zoU(^LdBKj{LKn}_1G#26*uIu0YLMIF`QtQR{79(IayR+`v)#)Qv#pv<6F;G3BVR@@ zA`Qoq?jS=XkBagUGw3IvzsPE-a4L&#J9NA>8{~nAtiffC>XJp5JF+XPj#&S$|J%rp z#409d2tvCABb>@3qV{a5oh#>S#d+x$cN>akYyTm-KW z{%>DIr}gnY$IoZXNK$da9^CM2+=L#X5JNQSu#qSSh=n;X>`xjmUqqYZ)2f)^X|b6l zDUH;TBcI>3(IxG;ug0~eyjzf=>mAJKn1O^=tts{<`9Ede@ii+Z+)MUq+(t5mov19U zucjw-7rtyb&lbrm-qyrZQ@{hte)ecr-no$eng4crly2N?;9FQZ86e>Zq<1jHG|W&< zPw+(lb>*12-mK|sTAn07&72ay{t|I+@#i;j-B~Zyh2;u}8FhQa7?B%m^-wrfsRwpI zKL{}lTwiX9Yj)jw8d)QEWRMe?Eq#t=t~HV_FRzR>64i9Fb|w**Q+WSS>N-W! zMuGfx41a*lcL#AFryeqYL2X_YV7nA%i?RG0fS>OR7DR-@jA|1gTZ_rUViw>!hRSKe za^${lG@okJP^&#_?3i5^gD8eZIxMFKU%M~7CITTE*3|X5C^da2P!WI>tS^Ke0hnIV zdKxF5)&w0?jDh_|-TlmOxeO{iI1?k`2cy(o+mt_;wkY{useKjv7gM6k>4**(VW=t%l(PhTjAs6pdC3JFP}MRJ_A{GdkxpI~fpno=%>3 z9)uggcjC8~XaqFPug`p0y9v&|ZDcs`n>(c?< zX5oSVJ(ovYSmxq*(R|~ciC5oR+A;Jd&B`H79)tl6XWB&kDMV;wm^wZkHG-5tWGkW+ zK$~=gec$;Ez>a2Q1iQmlFB^IyXJ(9MJ`2Wu_QRZCcY3peG@(c&H^7dJ0>JK@I>E1g z)cg^xfc^wxZJxQ7NXkHw>lZj%$rsJgMP@KKqjkDc>s`ON@Z9M0Py2{nZg2M*-bT3h z%px4ijEIy_pb&dzTui^A-$`hACj$QWN+fg35!%cL>EXHQgYO1@za#won$?z;%~OY% z7Wdn+))O9mfnufQwN+41wbLd2bnaFfZ);yfmm9ntDvb35L+iVL4#)urx{fWLBsiEs@=1@n|X z*G`AL$W2bWda8xsR# zqd$EqqtQ0M7Qs_0=2_DCmT)Vf?NEvMbpRG_+HIZ%gHUdbe(VikBuVF-=A-G-h!~H$ zr68%62Ar%mcYL`5ya0t3P(yY%n5Q0J(+fk`P8iYmDAx7d`PE6px|f8xT67CeGLQ}IqFYy%@VA{DG(E9}Vey`L zCH{hs2Ri%+1&ZzW?YHgdki9vd!3E{eU0CT# zNW_zviQ%r&{|p7%88)}Lq!Wl;*CO$8$H;P zx_H{ek*i&$VQ~AEQz4EV*c~=xwZt6ru{)D}+{Npq9}hMTxBteltOthN=Gz~XLY~*D zO`QAo=e&_4!uQs`#SL-sAxJn(s2rK2L9TmBp3(j7>e%-_;w~gJ#UAmU3jOlVinl?9 zvCwGsgdg&B6iQ~+YY2ecO{V`nRWZJ;F){mM$GzGx0pSZXKwDfPLz|DM z?JFxV>(xz64U-O?Aqkp8_^D`){lKqw`aQIbV9~if-98t5<87AdmmTY%M?BQewuIoa zVgEI=&Z0?%^od%Iot2b zGO4pJ${o0xwB3~vnFne6wEr!gG|FlkGU?#I6@)Fpa}VJgRI=%eEKBy#;1?OA`7cK8 zX-Lj~UwPB9B$7cFouKA4SKe5Ae_Os~t>1;{eD)(8`N^(0Mx&E)IdjcK+oNMSkNpFZ zS9xPH-~5~Qu3otp^Hg_7$DIqkejUXIYwyo1J4FnivM}!*?x&CSTReK$7aWN0&2YV6 zR4QyP=1$YXR8_D<6Nn?Hw7ZeRG+C0_8*dE9PMr_NuHE)tC*C56Y1;qTzt6d)A<6`E zu9NWIn?0xsU0c!Ygx~t;2lFp+QnvxFH9aB78nq&RH(rp)uEN0?&IzW8;wJ`z(e7s6 zl$p($dr0dtyNBm;)nLw{eAqG5s+u|Gdv>70t}PVut=#XnzdJ_arjxRA=(E=r=I@2S zUS%XrHENtmBB>*ta#42hRfb&9Bhdgwyn{V6#a=od6FV{x9CCFkUkHo2@TC%omwRfz zYv>KlJWbGrYgtCzb*%Ot%UvWI!b@!+@4={cyrN?qqG)E~U)gRkKm-BE zQo;Ox@}2CHYqYw(pRA*CHE9q{&6U7Gl>z4uaV=@qhm3 z>S#1?1yp_m360pPT&R2^tY25bF_yvo1+yGTpMTmF`mSqu6>jW7ci&mge>we%RWG&0 zmuw^qY>YGUfwM=2doTq2U4?cWh!>C}OIYL%@$X5{xLviTyV49~_8LAwI&sj3 z3P$?}Ci@?ChGlW@xgvg=YL(Cx6i9lno#&@pT>q_$or}iSOx3#qZk+Y7=Y6|d2p!5R zw^rW@7-uVxIYKLLoYMwPds)RdDTZ0oBl`UBIC0T`KS}~U(m^0($A#+X33$8DAD|1U zQ{z0kw&)qj?v31AUx z{B#Vy26CWbk3~P2`yicsJDqVI$1Wm{rIQS87$y)Q39@P1n?2zTniZclxiaWE8&KWQ z;PMJfEN7R-s#ZfF`VoF8MH-68*KKl~0OaMpU(qqksv(y2O94t-!Hs)go7A#7aCJW`z^m18)+oyzou zfJ^aDN~>vtXrfbOm743;xV7TTRt}Uim4CVjNU-kr zuYSJTj@0E>8=r<8_igkAqyQhjQ35}{0f+$UaJU!~z6k0o zvVGSockU`&q9BwK!ua9S*K(WBA~vUo8fMMi(hm%LKk_X%jXJ!wQi~#8OleF2jzBuO z$2qY7dKdpEJmUN7?2jLYWe{A-bnHbkIon`g26*)5Pe!StdhLg&$G%coVHNspUI)AF zF;oQ&{>8zPzTM`5Q63{=zMEB1k~4Jk8dP!qVYrG0k(B1KffH*QP!!&VZ9-P zee=Oc!+@gJY^83)FKouw!FB7)Tc6{^Q^RuA{(ERIk7NqOf3-Ri_;^1QM!+JEV*yOt z0UXAUbv&YVvoid3J(d~1*GDXuBC_7+Y$kMsQLy0f*W zz}Jy~h$3ic`_69xse;u+o6@z-7)Z^mETaBMx-FJ-{Y6}r@{Wb5B!gdJ;NSKI8c)=nrYtN)6d5kkn z+RCyp5e$rXH;x-i<7M;_1#Y5+PRTC(>-y#IZJrGc;nBvK zR@Z^^Fp@ISR!rzECb@nr-`$m6ndpiZsFS1^QhL7p`kUJVIej&sy4C_Z#Hh6v$NZdW zapN9zRx79R5^q?Ph|Cr84h)En4P?G68+=k9^h2;da7aXS=dZ#g9Bc!@CRwQiK6mS? z^Qd3)P8uR^B=IrKRl%vLk)>q5g?Z9bXw?Rfb>CHTA4@T6uW*9sZ!zR|nxTa))cK6c zwRyp@eUdJxO^7*V&5O8le0e-w@{T@QK$%XZHhX(qT9g#}3vO$)xn&Ywl0;5f(`l}d z#+q?w%n*geL+x9gKQJB_|Z3x~A^uCKhIPZH#iqcIV^ z#ezfPd(UM^rcfOJK;p-x>hdL_iiLKD_~mMpM&AMyMf)S(ROPBLFWZq2K#*;;U7&%lJ4 zdv@*1O;^SsQW?X4MJA|%?dc|l(B9>pAx{AiO2_S-K1j-+z;jf)Y*LHEYcW2-JzNdi ze539gj-N->iVM7NH1b9=&z0PCg!-kGV~!V^Yi0Jc8cuZ;^t6|-D}@$>7QH`9D(BEi zXC^$cNrb?RKpsM@8IFI#%ZUBMqiEsDiThAUFUGf^MPq1wIaWAsHBv#(nExv-_e+R1 zh4X>Zw8?$=1YBa7cG%$)Z3Cur{W#$;V^T8J~Dz91nUYP{C?cZKKe?ddb)a06AXTFMlI7!$2S=jbg*7tI@ zhGAR%$wKvA&sSI-S3LPXLbL|Y`+;|yn9j7StbK`|x4$v);cDk(2!AUL-sbL?=+@k) zYE;n$+}$!i=*r;!3^K~P1KJD67fyV0xb_dVA+K_=+cl_{SuvUcAP!&;8Ipx^_pATS zhF!F9A(PO3*?TABwENTpVpFaHC?97{`Z!SCh`T}~m{TP|EEmayA-O8BvqtFE->Nh9$UE73lc3m3Lc^cRm5lbKxvF(zWsfW)7k z7?wrC=zmNM{`%N=o{yCVJ7(^w&7ev&KO9F?1YV`{bwzTwGxE!CW*(YYTE4;&U`78( z>;Jc~$$oGy#R{kVUZ&~jL%So|f|5r5V64?0m?dT<8?5ZsiSs!jtD`7LL+PPb-t=Fn z$l7&$IoSteg>?by=^Ge&zcoBA$>tWhB$z2fs%?I6cm!45l|M_ zg^0|L4a_CXN2-LAVMe13IzEyXDkpA<->HpnBRY`|kxya^Z2mLnm|*!Pq7Jr5+Xuom zkskj#PEbU6i3#0g^DEls5!8km$mJ;~TNiwF#fddBameEzUWDaT5NF_GwfX%rY3?g_ z-ejtTp$w1P9poYbunn~L{%~#wToHyS}9m}9DC36(WEl5EUJP!8j z@jamR#3lX_n!{XAj~E+5u!I?;H1VXOO6aHPx$Y$KCGAi@=Yhj&sVvw1EAM~fszC%9kYKXbvw&hgG zqF%%p#@aqGe2j=xGB&)IHkt4a(1y54WZAKmAisnNy|+txEtHg}(l76|l|waA4PHg* zR@o2tsKVT8^;rvfx%0YQ>C?>xjtp4 z9822V_(fg$f{vT6A=z!Om!%u{4vAB+;&!@E<{|SR){}iJY4Z$PUEpl;E;Hq+{!xmQ z(`jL`XSn-E&`%5A2sTWs*k&kqTj%7?tq(HS<-OF4Ew+g+&*m<_WV~MK{=b(Z^+i4O zuP2BjAmo~S>aWZm7%i3zQs$7b#4_(U!FG`7Ct2N-TEDLm0Oaj#Q8y)sS!dXC_D*eF zj-;J&d3}?T<{>8t<(ArnU}wzBWCFy!Ie|j8ti|TSyj3Bh$*;s=x=mKUPo|IgY16e! zbWoADF{pJbVlH_{1lDCs2GAQ<{g?G?+l%UYm;?&g6&W+3?VfIDw=K#>&(~%P{arSD z(IDkjtPg90mDOWvJ|%3!5H8C}xCzEH{+U)mQQVqTy11UMn{zXvXbro(jv^W9l^Fu0LzBa5}vcUFF_;0nFM(NZ~-^=NXNvw2oLdq+hH<=}q!~RxNBKmRX!I?U= zxB6QUli0SwE6+Z1uZRktvObgZ^G~rN&RGSo%F}u67DjI&PG;zu$~Jvy9fsYxen@ej|?b)@n>en)Nqu zPT-xo(Ax{TOj#s`c?2ZfPTjxuc!mr+k;E#O{5>yx|J;#3_bz)*?+xG1*0JsrVS#QF z2kGLM?{9j(h!1Fs^m8<#(&J5DM?3mMHE85UH=PYp&A!^w95U!7rcD>FGdKfoe_~ZV z%svGDWg)m1FKST{FEI2gC@~d~%)pQUxG)qYq)TTEJ_2I3HfUzL?(O zFXgCbaaiO|zoU|A4RS1Z@D6Y?H}w`OA%sS_9IO(1rBlt@ZkU&{9YTUb)OihzZnHf3aEjOg&17R1*OV@f}fL# zImY~#3T%(!X-esf1Hykr_e@|24OpuOG-)esXqHUaf*A-`oBVQ@JeNj$(Sy&8aNmMu{isuM#mOs}A2megH*QT*vK`iXToy)qAZ@&%Kkp*4cNR zFOswwx&QgU39hQ`K%;Xa3k4~4eyc_*d`bLR(qp8ffBn>TW$Q>MiIw!of5+R`R~Nbs zJFLaplHZ2pHWP`&u+7B@XIT?S7)quCmT2$0Pl<Z3ppFgV z<_b8moh3<^ul#z(O$P#xt+}^dlu&to5-mPBi{p7Um#d837($c8orC8GpC^T`f%v$N zr?e#CTG7GmA<>wQXe5l?p-bv<`tb$wrUB%ZcUD6axUW91UGDfGA*0fS{}nXY2R+HM zD6RjFPL&CFT-n}7s8xEUq^sJ^EcG&fr5M@n^|2II1;~vVr8?jHO7AK0P`3&Tf&$<y61hD@uteogHx)m~o@Wxzrm; zTPS=loWu*ZA{7=J?!sb7vdrAvoCwv5HS%{JAc(4=U%yru5&}MgeH@Xi4?T1ZU_QW& zt|G=46HW~bDh)*T;>*)=tS2v9F+hqv=0r;Xk#RhH;Y>iq%-U|xb#{nuB?`osG|x4Q z!G}iA5>8blp@jw6Rpu5JB+uBkL(XvXnW%>@c22&M6-LVjPZ~{5!6$!ry>I2Lukms< zIt;TKL!f#{?zv-NKWykkRQzLUhER$mLfs}LCI7u9>Rt8MtXb1a7-mGlFp}0_ZZJO% z>xzJ~vCXg|qNh4Xe0P?A#twr?&A=l&D_(UUk!2k|(-p1+0p2ulqLBn4q@*01ncVQ% zvCfg_Div#cyVcyf0ODs8b8@IMjLp!5F<}oKD?3P$u7j6Da#JI$Km!@88B;_pl%{Mb zMpEJJU(sm@GYd4VffvqqWYe0`Bj(fjA!MNnZ0EoUC(RnYQr}w9=gditwYd+%O~~;0 z^Zj|?ZZ9OiA91CPy3WIo-{2D6HliXOQ~_C0z$l+K$S;{^j;GwZxKPP}Nt_wswsZL3 zH;ktE$LMqaf3UPY?Z=-q07UAY2Bz*#h92&>9&|#X+eu>@=d>RDFkMK&6%3Bx z4ywZ3(VETGX7B4-MS?YMJZ0`KWf0z$bpl~Oeg6M(_12bz$AL!fy>Qf}RkT8sf zBAg~8+I(K0DjY2+luRFONx!%{<-nM+4Y!a~TC%;l;_o{a-j|~GdA#^c5kji!+JM`a zoHwT1dmO%{iU`pGv-5i9$m32(q{;xt^(_W zN=cX0;ST@qwuh+~pL?7TiN~d>aAkY8%}pYMS}51_Qa%{C!(IL(a&tz@O=~vIn=D|= zSh2=!*_Wrr`L_vdE7yLs#Crbh$1`*4t`^ka%11QTY@FK|G`+;wdXaf)Iu)_W;$i$A z*&oC4j2WeMT$ZpkX9sUq-YRh~hWCl-t@O!ja@_Ju-q0#yvZpU{R<3;)+MmU|&$!aaSAq9-kMvw*QJxd!x5( zNRlyzEc#{Y@zrHnbJdL<{0HYf#RbmdVPSV)%2rNWdaz$U{tkk`rgW43I(k$47M~wR zXhR;xX4Z&7mcstM6yt=}5US~A)yYz^mTUcW z;9Sr%6QxLXvy~rtZ%y?x*!G+eT5z0cdgpiAxZVJ3CL??4jXgD*cs9};%$D_sRb@u5)%9qWqMM@z(e53JHx155Kg_>!P z=IqR+@Xz0@I*!sz7|JjxKz!N;il)vsdpGhcBaGjgCceEg(R4TmFjx~{hyhzzo za*O(Hc}p$}Jzica)~70UVrUnHV}Pt?7v7N<_WEOXj$ue*x`bwD8(GWrx0{Cu`fN&; zcJO#5ae!9;68_hG9YQ4jd3263Q?x44$|v~h>a^*EjM1Nr@vj_`MfBNjrGW0cvY_0~ zbqVq1{K@CcZ%hhOd+{RIjo zIXJr-S>2jbPZ%t(f#R9t@0GMROHjgG^1|xDl(Xm1)&1T*9`pej1PP{xrdCI#sIq=U zv%^0ftH^?w(e(1|O`D{gLyzvs{>`AFUboF$I$^62!dtF8P48l%36v1L!`tG_9=hZ- zHOA=nY9D_B;7IDA!}pmt$)FUhjjF*A-y0*VSr3z7krF){!qC`gJbl;r4MZPRxL!7y zQOxisPx!KigtMy2yyICx!9}~aQ&p+(uc58foEXsruF=MI)J=WGx;mcgf?pD5|IV6K zMew`;h88q2!4Fy%s{i^dpniLBrJ7Az_iVl&)FZ_T3*d}1symCWRq(^dYERzlM^h&6 z8c%MGvNndu| z+eC>oO{AoNClEu%2cOHVio2~w9&R(b>er_^yqYn+n#9CzlduVi3wyme2=ttUrU1;6 z$np#5&ka~fI_D4veA76jZZ? zWwmsPrh{jAUh==z8p4n2YX<*`b-ns?USC?E-l^$zFK=(H3N4)ZF!ztWUQteq`*?(ynj&nNK$RjTfZvF-nNl_$;?;!*=^G|>)cxk@4 z^O||&;wsi^lvwidVcsy+d6|+|ce|CT@*$?XV}YOivT82ghI`4vluHZ`wbD5pCdsA} zc<;QeCR}k+VsKwynHYt4bJJad!cUX;Uj%n_MJ_H^39qf9%pw(|9nZx1#qTx0Pif;B zT)lS(y!dzfY%%3mr^=gyZ}0fibXUd7Z&D^Iu(B-S{i=?-!0o*Ue~sTaUVW1Rx!*R2 z8@N3UKDreSr?5qK@sJDJ|u%dn{C7kK3y~&rNXQd;YU0ESD{xn8zb^ zJ1nyHh2@4TK0AKb;OV~UPphvp^}RU%2K7*aT2w7AYPm`JDfM)crdIL%er!2NDE}7g z((w^BE@CqE;Vgg2Ij~>41-=@=eb zbVU2BBmJFGUU6kHS4{bwr&5WIjcfAJV+5A|jWEZ!Vz{{yPiqe2&Z_YA^n99~4darL zl|+0tKCWY6U|=}?F1ok-QM`3m_@*}7P+w2XOy`93o^H1h(FkS^6b$?+IDOpa$y&4x zgaT0e=`!iK8N_gd!YP(Q_lYDV0^8|(wm2yJbpt@K zYdAmAR#i07R!e%7A@T~Yx+-mYvFM&ir~V6m8he7)NU(gnW5{JSz8tS+n_W~?4|Zdf z?Xtd4PCs`&<%%orfAkX3nSokRDuD3Ea4C{SVIIy`a<-^fm)4~_#S{yo4LIB(pN_Ek zjarqgxeZxcc9_pI|8Z|H@Pf?bBQXNMy~O-vIDPoGfYH^ab5Tvb@9$f+`89qeSh@cFMY1zD6T6?ZkNkuo#+=MC z5y!6ej#tn=gP!@d%8LH6*5~i;B`}8xx}qBtuiIT#F*6B}fUkE{q<#7c<3{GHyq`I( z{*y|wb;FVdcxWt%@$y}bE9XlKmyT*laZ`eJg%oT97AyLj3On2j?aLUFQ<-cO=bwMV zhZud&URm1sr@X9s-8^N1^Orxh7_mki*fG8LTm~XTQ5`0lTHw@}XYXGsJh9R+mq4Gi zt!_hQ=JJ~r9`eK7H)Pli}@S2eDj_;X6c_9U!~jb zqtwLk;SrOPfN<_*lVWL&ebrQg?Ud9$9Uo`#KpuR?S@IO5W;<%;k6xR}8*K=z{`~MDhivg$j^*Px-s5xO^Jz$DL;}pB_ZAd) z6$H$ImLxk>eUW$)C}2|H*9w^iVWe8v25|$Vp_R(bvgBfgRD_R?w(XPIlNC=6*`--i ze;fXA5$ht5B)Gv42F2}L@%WR1ggGBf_s3uLQ)FBd3-Wnr9k0m+2zr*ZHR{~I?2)Oz z{YhzmVS~r8Hii*Q`BdsQFY}d0mXdIaVZhavLLQYTr9~6%Ryn-#uq35gp%!}I8zdYC zFaPW)+*DaRtvbL%%vevzzzteg&7|&ydi}WYJEE}FHVzA!9|AG8OU;JR**|C#(@@@E z`|8e+eLAx2Ni_-N&kt;%u%DAv3HY`zIc7ypNQq5%+0R@?2i|M?I+~`8FP$2tS?UEW5@^(zN(`S8Qz_}ymMNz@j-;Rh>TcnP?brX;){494xr#bb z){3oz-yj@T`2iocmC}{(P*3-)(sGt*rJ5z{l|U@tEFn)RKY#9bHF~xh2oPgrbxYg6 zA#^lp`@PTe7XW( ziq-tNj3Bk#ucr+-Y)5x09Qu_lFX zZdNLkWAU1pZGiZ7akSTa_(6iY;jo2m_fdqD_pyI8=H&&(_PmRm0L**D-CZCSl$A38vZL1>e-SD3}aH=tUQ&347l`~okr?$Nz8(QZbas56{~aG%E5lB z5@~9$CZojBMc%`ev)|L__*$@Fm|{D4WAC`gK0Ljg2pwK?+!0bNkW!i$`9+9bE~iy9ksXo z^QH207^ic^x5Sj_+~@7mQwT{-c)!zY5u=0^*1$A$SZb3hS7cUBGaY z*o<)beqzghSU23QW*j@^dFAs`s%st0uGkY$bYj?e-Envq+J_lTu>B3ar;lVczHD-A zYyrKpTg~WtBKUh5%1@l2n#!_J=iJ8TH8{?V?hF1 z#^hex$eME|OTr{tKxIBcKM)>4sG*1dy#>UcbH&B@FH+H?1S3!0?GJPChis!mjHc&x z%#bx4-4`VM@a2wU3NpdjBH&ztDtes0Dr~-DbO8=+XAb3C!>cMN zfx-I8AZv=F2>{~{ej-B{k**+!waNQuT=GkT(dS1(X7TcLik@%WXI1bGHbT{sBP7(C zVoZ~j87P`?BwgL5lM;WCU2|WGb9?Mt(U>>3+s8yXF|t-We#0PP`1yiz(4MSj{QdiE zx9yzX5yd-9Daz)O-JU1>q*V;3gG9mfl0CUrEa+_*SP&Mqyz%J6OcI`MSh6EeWh4NA^E;t@EH%E*o=Kb(V4 z16D6oj_H9LNknwHPsh`*OGI}lLCsiXeoR|d!W&2=o4>TV6*(#)geVMBGAJ}V8?nvE zz;`()?xm=hlPBNtXM4n|ae(G}j8L^7Q4l z)2*qqLt<=c+PFKd(hGJP?v1I3m#Gnv5@&+lyjA$Y(QZtedv2|5;@IrWwl&UiA6>I@ zr+G4rdCIK{d2QCjm+P$q!hYBz5bkF8ojMX}-yLdr1r=|<-1?*xD%5~(SJ?`!`KzKo z>ussli&9SEhf^P(&l8onm~cgS+EAWh^>d2CIRQbTD?R-hjV5+@fN>)it~|e4#M~1s z011MU3ox0^HTSI&Q3@EuI>r*c3NAZ=i7VpwIogPh@aOK0+Sim;O9t-~CZZ6?muIaM zH+U-XdbxHU;ibA-L5_jCJi=@xY(77Bk3&vHCiB!6DH?n>;nkTPy&+OpL z|EKM}`zD9G62AGrbO=}tW;1P3#w0`~N+4>Yt?>Zpb8hVgmrjUHqOyBy*$e-jm9#Twr_bJ6ev@!YOLBqg z*N3|dfBh-e3&!X9<~?=(c$`eaLa|8hIT0zT?E81OhPDiKnp?~17h$d%N;Fs6c)F@l zIb5(4I(e{Tq0?|rO}N2eVZ7$tGff~3;OuuwrkAr=8x?#zCxv9EE^XtE^inp7^g8nV z8u{ZRetwb$0k`+fi-u+-AHIlxBpJ?qx9tmBVEV<{tMjPs`4tO%I?IKQIpm{u0m-$I znS-;5l=CPXT(Yy7%NcN3Y|RbaZy9G1w0ib}L?W3BR>vFOs4YKReEruvlQ2XYzrj>f?biITWE|%Bw2QQ^^a51TISG=6JBQy@4 zR7H%5qDdkqa~wbHv?xQL#^OdrLaVT4eY71y*KnV6O5BHHYtps3t(nOO#dYDx<3h!* zj~E6{Erdv{IK-HB*SM#_V9;fcE>vb<(mbQ!R&tbcI~9vLj;?nKgRq%@t&8gW2WCFA zlfLcnQ03-pjI&8&{c?Z%Dea>1k66NU#(!T4L7MDaz;Fi%_sHS=ONXA+_V20wsZ9X~ z!OcaeNnBofnfg_)XDZYdsIe@}JGU&n@L4r℘C;18Nf4H?Fdy>Qa?9NaI+y2zrEB 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�HrL19UA8D=ep^Nz8Og);Xp>A{G+uqc#_wkd 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 o@9Ci;h*NINb_A#`K29T2 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 literal 0 HcmV?d00001 From 3774dfd0e267e91d001ffd30993ca9400fa39f27 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Mon, 14 Sep 2026 18:16:24 -0700 Subject: [PATCH 40/77] Document AgentCore version and IAM limits --- docs/guides/durable-agent-on-agentcore.mdx | 27 +++++++++++++++++++ .../serverless-workers/agentcore.mdx | 27 ++++++++++++++----- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index d9f96b5fa6..08ec89d706 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -259,6 +259,25 @@ echo "$RUNTIME_ENDPOINT_ARN" Both commands must print an ARN before you continue. +AgentCore creates an immutable Runtime version when you deploy changed Worker code or configuration. The named +`temporal` endpoint remains on its configured version. When you redeploy the sample, increment +`endpoints.temporal.version` in `agentcore/agentcore.json` so the endpoint uses the new Runtime version. + +Verify the endpoint version before creating the Worker Deployment Version: + +```bash +aws bedrock-agentcore-control get-agent-runtime-endpoint \ + --agent-runtime-id "$AGENT_RUNTIME_ID" \ + --endpoint-name temporal \ + --query '{status:status,liveVersion:liveVersion}' \ + --region "$AWS_REGION" +``` + +If the endpoint remains on an earlier version, Temporal starts the old Worker code. Creating the Worker Deployment +Version can then time out if that code does not acknowledge the invocation promptly or does not register the expected +deployment name and Build ID. For details, see [AgentCore Runtime versioning and +endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-runtime-versioning.html). + ## 4. Grant Temporal access to the Runtime Choose an External ID, then use the sample's CloudFormation script to create the IAM role that Temporal Cloud assumes: @@ -273,6 +292,14 @@ export INVOCATION_STACK="ac-strands-invoke" "${AGENT_RUNTIME_ARN}*" ``` +:::caution + +The sample names the IAM role `Temporal-Cloud-Serverless-Worker-`. An [IAM role name can contain at most 64 +characters](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html). Keep +`INVOCATION_STACK` to 31 characters or fewer. The `ac-strands-invoke` value above is within the limit. + +::: + Wait for the stack and retrieve the role ARN: ```bash diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index f584a68dd5..27a92f8602 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -156,10 +156,17 @@ aws bedrock-agentcore-control get-agent-runtime-endpoint \ --region ``` -If you redeploy the Runtime without creating or updating an endpoint, an existing endpoint can remain pinned to the -earlier Runtime version. For a later Worker version, create a named endpoint pinned to the new Runtime version and use -that endpoint ARN for the corresponding Worker Deployment Version. Keep endpoints used by existing Worker Deployment -Versions pinned to their original Runtime versions. +:::caution Verify the endpoint version after redeploying + +If you redeploy the Runtime without updating its named endpoint, Temporal continues to invoke the earlier Worker code. +Creating the Worker Deployment Version can then time out if that code does not acknowledge the invocation promptly or +does not register the expected deployment name and Build ID. + +For a later Worker version, create or update a named endpoint to use the new Runtime version. Use that endpoint ARN for +the corresponding Worker Deployment Version. Keep endpoints used by existing Worker Deployment Versions pinned to +their original Runtime versions. + +::: If you use a VPC instead of a public network, configure outbound access from the VPC to your Temporal Cloud Namespace. Temporal invokes the named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). @@ -172,8 +179,16 @@ The External ID prevents a [confused deputy](https://docs.aws.amazon.com/IAM/lat attack. [Download the CloudFormation template](/files/temporal-cloud-serverless-worker-agentcore-role.yaml), then deploy it. -Pass the Runtime ARN with a trailing wildcard so the policy covers the Runtime and its endpoints. The template names -the IAM role `-`. Keep the combined name within the IAM limit of 64 characters: +Pass the Runtime ARN with a trailing wildcard so the policy covers the Runtime and its endpoints. + +:::caution + +The template names the IAM role `-`. An [IAM role name can contain at most 64 +characters](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html). Include +the hyphen when checking the combined length. CloudFormation cannot create the role if the combined name exceeds this +limit. + +::: ```bash aws cloudformation create-stack \ From 856f63573e64ba5a9d6235dc2c57e0ecb918ddf1 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 10:14:59 -0700 Subject: [PATCH 41/77] Document Nova Lite for AgentCore sample --- .../workers/serverless-workers/agentcore.mdx | 13 ++++++++++- docs/guides/durable-agent-on-agentcore.mdx | 22 +++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 48d533931b..1a40de101e 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -84,7 +84,15 @@ async def run_worker() -> None: namespace=os.environ.get("TEMPORAL_NAMESPACE", "default"), api_key=api_key, tls=bool(api_key), - plugins=[StrandsPlugin()], + plugins=[ + StrandsPlugin( + models={ + workflows.MODEL_NAME: lambda: BedrockModel( + model_id=workflows.MODEL_ID + ) + } + ) + ], ) tracker = ActivityTracker() @@ -142,6 +150,9 @@ async def invoke(payload: dict) -> dict: ``` +The `models` mapping registers Nova Lite under the name used by the sample Workflow. Model calls then run as Activities +on this Worker. + The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker capacity. Applications start Workflows through the Temporal Client, as usual. `add_async_task` causes AgentCore to report the Runtime as busy while the Worker polls. `complete_async_task` releases that status after the Worker drains diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 08ec89d706..31a5ab50fb 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -21,7 +21,7 @@ import { CaptionedImage, ReleaseNoteHeader } from '@site/src/components'; This guide deploys a Strands agent as a Temporal Serverless Worker on Amazon Bedrock AgentCore Runtime. The agent uses -Amazon Bedrock for model inference and AgentCore Code Interpreter to run Python. +Amazon Nova Lite for model inference and AgentCore Code Interpreter to run Python. The [AgentCore deployment page](/production-deployment/worker-deployments/serverless-workers/agentcore) is a focused procedure for deploying an existing Worker. This guide uses a complete agent sample to explain why the Workflow, @@ -86,7 +86,7 @@ prompts through Workflow Updates while allowing any compatible Runtime session t [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). - AWS permissions to deploy AgentCore resources, CloudFormation stacks, and IAM roles. See [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). -- Access to the Amazon Bedrock model that Strands selects in the target Region. +- Access to Amazon Nova Lite in the target Region. ## 1. Get the sample @@ -115,12 +115,25 @@ The sample creates a `TemporalAgent` with a system prompt and the `execute_code` [bedrock_agentcore/strands_agent/workflows.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/workflows.py) ```py +MODEL_NAME = "nova-lite" +MODEL_ID = "amazon.nova-lite-v1:0" + +with workflow.unsafe.imports_passed_through(): + from activities import execute_code + +SYSTEM_PROMPT = """You are an AI assistant that validates answers through code execution. +When asked about code, algorithms, calculations, or data, write Python and run it with the +execute_code tool instead of working the answer out in your head. The sandbox persists +across calls, so variables you define in one call are still there in the next. Report both +the code you ran and its output.""" + + @workflow.defn class StrandsAgentWorkflow: def __init__(self) -> None: - # Configure with the plugin's default BedrockModel(), custom system - # prompt and code interpreter tool. + # Configure the model, custom system prompt and code interpreter tool. self.agent = TemporalAgent( + model=MODEL_NAME, start_to_close_timeout=timedelta(seconds=60), system_prompt=SYSTEM_PROMPT, tools=[ @@ -144,6 +157,7 @@ class StrandsAgentWorkflow: `TemporalAgent` adapts the Strands agent loop to run in Workflow code. The Temporal Strands plugin schedules each model call as an Activity. `activity_as_tool` makes `execute_code` another Activity when the model selects that tool. +The `model` argument selects the named Nova Lite model that the Worker registers with the plugin. The Workflow owns the sequence of model and tool decisions because that sequence must resume correctly after a failure. The model calls themselves do not run as ordinary Workflow code. They run as Activities because they perform From 33db1e405cf0957f713ddb37ab31bbe28a3ebd37 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 13:30:19 -0700 Subject: [PATCH 42/77] Resync AgentCore docs with reference sample --- .../workers/serverless-workers/agentcore.mdx | 13 +---------- docs/guides/durable-agent-on-agentcore.mdx | 22 ++++--------------- 2 files changed, 5 insertions(+), 30 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 1a40de101e..48d533931b 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -84,15 +84,7 @@ async def run_worker() -> None: namespace=os.environ.get("TEMPORAL_NAMESPACE", "default"), api_key=api_key, tls=bool(api_key), - plugins=[ - StrandsPlugin( - models={ - workflows.MODEL_NAME: lambda: BedrockModel( - model_id=workflows.MODEL_ID - ) - } - ) - ], + plugins=[StrandsPlugin()], ) tracker = ActivityTracker() @@ -150,9 +142,6 @@ async def invoke(payload: dict) -> dict: ``` -The `models` mapping registers Nova Lite under the name used by the sample Workflow. Model calls then run as Activities -on this Worker. - The payload does not represent a Workflow input. The Worker Controller Instance invokes the endpoint to add Worker capacity. Applications start Workflows through the Temporal Client, as usual. `add_async_task` causes AgentCore to report the Runtime as busy while the Worker polls. `complete_async_task` releases that status after the Worker drains diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 31a5ab50fb..08ec89d706 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -21,7 +21,7 @@ import { CaptionedImage, ReleaseNoteHeader } from '@site/src/components'; This guide deploys a Strands agent as a Temporal Serverless Worker on Amazon Bedrock AgentCore Runtime. The agent uses -Amazon Nova Lite for model inference and AgentCore Code Interpreter to run Python. +Amazon Bedrock for model inference and AgentCore Code Interpreter to run Python. The [AgentCore deployment page](/production-deployment/worker-deployments/serverless-workers/agentcore) is a focused procedure for deploying an existing Worker. This guide uses a complete agent sample to explain why the Workflow, @@ -86,7 +86,7 @@ prompts through Workflow Updates while allowing any compatible Runtime session t [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). - AWS permissions to deploy AgentCore resources, CloudFormation stacks, and IAM roles. See [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). -- Access to Amazon Nova Lite in the target Region. +- Access to the Amazon Bedrock model that Strands selects in the target Region. ## 1. Get the sample @@ -115,25 +115,12 @@ The sample creates a `TemporalAgent` with a system prompt and the `execute_code` [bedrock_agentcore/strands_agent/workflows.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/workflows.py) ```py -MODEL_NAME = "nova-lite" -MODEL_ID = "amazon.nova-lite-v1:0" - -with workflow.unsafe.imports_passed_through(): - from activities import execute_code - -SYSTEM_PROMPT = """You are an AI assistant that validates answers through code execution. -When asked about code, algorithms, calculations, or data, write Python and run it with the -execute_code tool instead of working the answer out in your head. The sandbox persists -across calls, so variables you define in one call are still there in the next. Report both -the code you ran and its output.""" - - @workflow.defn class StrandsAgentWorkflow: def __init__(self) -> None: - # Configure the model, custom system prompt and code interpreter tool. + # Configure with the plugin's default BedrockModel(), custom system + # prompt and code interpreter tool. self.agent = TemporalAgent( - model=MODEL_NAME, start_to_close_timeout=timedelta(seconds=60), system_prompt=SYSTEM_PROMPT, tools=[ @@ -157,7 +144,6 @@ class StrandsAgentWorkflow: `TemporalAgent` adapts the Strands agent loop to run in Workflow code. The Temporal Strands plugin schedules each model call as an Activity. `activity_as_tool` makes `execute_code` another Activity when the model selects that tool. -The `model` argument selects the named Nova Lite model that the Worker registers with the plugin. The Workflow owns the sequence of model and tool decisions because that sequence must resume correctly after a failure. The model calls themselves do not run as ordinary Workflow code. They run as Activities because they perform From 9f41d94512fe64dc053e10a5363ba9b0d67a473f Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 14:45:59 -0700 Subject: [PATCH 43/77] Compare AgentCore Runtime with Lambda --- .../serverless-workers-agentcore.mdx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 6f0577e42a..1c38df06c4 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -31,6 +31,25 @@ Runtime session. When the [Worker Controller Instance (WCI)](/serverless-workers capacity, it invokes an AgentCore Runtime endpoint. The Runtime starts a Worker, which connects to the Temporal Service and polls its Task Queue. +## Choose AgentCore Runtime or AWS Lambda {/* #choose-agentcore-or-lambda */} + +AgentCore Runtime and AWS Lambda use the same event-driven autoscaling algorithm for Serverless Workers. Choose between +them based on the execution environment and AWS services that your Worker needs. With either provider, Temporal stores +Workflow progress and the compute provider runs replaceable Workers. + +| Consideration | AgentCore Runtime | AWS Lambda | +| --- | --- | --- | +| **Primary use** | Agent and tool workloads that use the [AgentCore platform](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html). | General-purpose, event-driven Worker workloads on AWS. | +| **Worker process** | A standard long-running Worker runs as background work in a Runtime session. | A Lambda Worker integration manages the Worker within each function invocation. | +| **Compute lifetime** | A Runtime session using the serverless microVM compute type can run for up to 8 hours. | A function invocation can run for up to [15 minutes](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). | +| **Process-local reuse** | The Worker can reuse in-memory caches and temporary files while its Runtime compute remains available. A later Task can run on another Worker, so do not depend on this state. | Each invocation is independent. Do not expect process-local state to be available to a later invocation. | +| **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability, along with tools such as Code Interpreter and Browser. | Lambda can call AWS services under its execution role, but it does not provide the AgentCore agent platform. | + +Use AgentCore Runtime when you are building on AgentCore services or when model and tool operations benefit from a +longer compute window. Use Lambda for a general-purpose Worker when each invocation can complete within its 15-minute +limit. Neither option changes where durable agent progress belongs: keep it in a Temporal Workflow or another durable +store, not in the Worker process. + ## Autoscaling {/* #autoscaling */} AgentCore Runtime uses the same event-driven autoscaling model as AWS Lambda. The WCI invokes individual Runtime From d7ec443068b8d9c7f38534b72c3b1450eb4c5736 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 16:21:40 -0700 Subject: [PATCH 44/77] Explain Temporal and AgentCore responsibilities --- .../serverless-workers-agentcore.mdx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 1c38df06c4..acf6b616da 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -31,6 +31,31 @@ Runtime session. When the [Worker Controller Instance (WCI)](/serverless-workers capacity, it invokes an AgentCore Runtime endpoint. The Runtime starts a Worker, which connects to the Temporal Service and polls its Task Queue. +## How Temporal and AgentCore work together {/* #how-temporal-and-agentcore-work-together */} + +Temporal is the durable execution layer for the agent. A Workflow records the agent's progress, coordinates model and +tool calls, waits for input, and applies retries and timeouts. Model calls, tool calls, and other operations that +perform network I/O run as Activities. + +AgentCore supplies the compute that hosts Temporal Workers and optional services that those Activities can use. +Configuring AgentCore Runtime as a Serverless Workers compute provider does not automatically configure the other +AgentCore services. + +| Concern | Where it belongs | How to use it | +| --- | --- | --- | +| **Agent execution and progress** | Temporal Workflow | Keep the agent loop, completed steps, approvals, and long-running waits in the Workflow so execution can continue on another Worker. | +| **Model and tool operations** | Temporal Activities | Give each external operation its own timeout, Retry Policy, and recorded result. The Temporal Strands integration runs model and tool calls as Activities. | +| **Worker compute** | AgentCore Runtime | Host a Temporal Worker in each Runtime session. Treat the Worker and its process-local state as replaceable. | +| **Credentials** | [AgentCore Identity](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/identity.html) | Resolve credentials when an Activity accesses AWS or third-party services. Do not store credentials in Workflow state. | +| **Tool access and authorization** | [AgentCore Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html) and [Policy](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy-create-policies.html) | Call governed tools from Activities. Gateway connects the agent to tools, and Policy controls which tool calls are allowed. | +| **Knowledge across conversations** | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html) | Read or write reusable knowledge through Activities. Memory does not replace Workflow state or Event History. | +| **Managed tools** | [AgentCore Code Interpreter](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/code-interpreter-getting-started.html) and Browser | Wrap calls to these services in Activities so Temporal can record the result and retry failures. | +| **Runtime and agent telemetry** | [AgentCore Observability](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability-configure.html) | Use AgentCore telemetry for Runtime, model, and tool behavior. Use Temporal Event History to inspect durable execution progress. | +| **Caches and temporary files** | AgentCore Runtime session | Reuse them while the Runtime compute remains available, but do not require them to continue the Workflow. | + +For an implementation of this architecture using Strands and AgentCore Code Interpreter, see +[Build a durable agent on Amazon Bedrock AgentCore](/guides/durable-agent-on-agentcore). + ## Choose AgentCore Runtime or AWS Lambda {/* #choose-agentcore-or-lambda */} AgentCore Runtime and AWS Lambda use the same event-driven autoscaling algorithm for Serverless Workers. Choose between From cc72ee5ffe39d437418a2a11f21d4f2cc473f7be Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 16:26:42 -0700 Subject: [PATCH 45/77] Tighten AgentCore service guidance --- .../serverless-workers/serverless-workers-agentcore.mdx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index acf6b616da..00aca04424 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -34,8 +34,7 @@ and polls its Task Queue. ## How Temporal and AgentCore work together {/* #how-temporal-and-agentcore-work-together */} Temporal is the durable execution layer for the agent. A Workflow records the agent's progress, coordinates model and -tool calls, waits for input, and applies retries and timeouts. Model calls, tool calls, and other operations that -perform network I/O run as Activities. +tool calls, waits for input, and applies retries and timeouts. Model calls and tool calls run as Activities. AgentCore supplies the compute that hosts Temporal Workers and optional services that those Activities can use. Configuring AgentCore Runtime as a Serverless Workers compute provider does not automatically configure the other @@ -49,7 +48,6 @@ AgentCore services. | **Credentials** | [AgentCore Identity](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/identity.html) | Resolve credentials when an Activity accesses AWS or third-party services. Do not store credentials in Workflow state. | | **Tool access and authorization** | [AgentCore Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html) and [Policy](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy-create-policies.html) | Call governed tools from Activities. Gateway connects the agent to tools, and Policy controls which tool calls are allowed. | | **Knowledge across conversations** | [AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html) | Read or write reusable knowledge through Activities. Memory does not replace Workflow state or Event History. | -| **Managed tools** | [AgentCore Code Interpreter](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/code-interpreter-getting-started.html) and Browser | Wrap calls to these services in Activities so Temporal can record the result and retry failures. | | **Runtime and agent telemetry** | [AgentCore Observability](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability-configure.html) | Use AgentCore telemetry for Runtime, model, and tool behavior. Use Temporal Event History to inspect durable execution progress. | | **Caches and temporary files** | AgentCore Runtime session | Reuse them while the Runtime compute remains available, but do not require them to continue the Workflow. | @@ -68,7 +66,7 @@ Workflow progress and the compute provider runs replaceable Workers. | **Worker process** | A standard long-running Worker runs as background work in a Runtime session. | A Lambda Worker integration manages the Worker within each function invocation. | | **Compute lifetime** | A Runtime session using the serverless microVM compute type can run for up to 8 hours. | A function invocation can run for up to [15 minutes](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). | | **Process-local reuse** | The Worker can reuse in-memory caches and temporary files while its Runtime compute remains available. A later Task can run on another Worker, so do not depend on this state. | Each invocation is independent. Do not expect process-local state to be available to a later invocation. | -| **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability, along with tools such as Code Interpreter and Browser. | Lambda can call AWS services under its execution role, but it does not provide the AgentCore agent platform. | +| **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability. | Lambda can call AWS services under its execution role, but it does not provide the AgentCore agent platform. | Use AgentCore Runtime when you are building on AgentCore services or when model and tool operations benefit from a longer compute window. Use Lambda for a general-purpose Worker when each invocation can complete within its 15-minute From 2963a6fecb980bdfbe1f43670bb03bed33547ad5 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 16:44:20 -0700 Subject: [PATCH 46/77] Clarify where durable agent progress belongs --- .../serverless-workers/serverless-workers-agentcore.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 00aca04424..90d3772a70 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -70,8 +70,8 @@ Workflow progress and the compute provider runs replaceable Workers. Use AgentCore Runtime when you are building on AgentCore services or when model and tool operations benefit from a longer compute window. Use Lambda for a general-purpose Worker when each invocation can complete within its 15-minute -limit. Neither option changes where durable agent progress belongs: keep it in a Temporal Workflow or another durable -store, not in the Worker process. +limit. Neither option changes where durable agent progress belongs: keep it in a Temporal Workflow, not in the Worker +process. ## Autoscaling {/* #autoscaling */} From 30c510c086616d8f2aa26ded8ab0874da09457e7 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:03:03 -0700 Subject: [PATCH 47/77] Document self-hosted AgentCore setup --- .../agentcore-self-hosted-setup.mdx | 245 ++++++++++++++++++ .../serverless-workers/agentcore.mdx | 37 ++- sidebars.js | 13 +- ...sted-serverless-worker-agentcore-role.yaml | 68 +++++ 4 files changed, 351 insertions(+), 12 deletions(-) create mode 100644 docs/production-deployment/worker-deployments/serverless-workers/agentcore-self-hosted-setup.mdx create mode 100644 static/files/temporal-self-hosted-serverless-worker-agentcore-role.yaml diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore-self-hosted-setup.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore-self-hosted-setup.mdx new file mode 100644 index 0000000000..9a04f5712a --- /dev/null +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore-self-hosted-setup.mdx @@ -0,0 +1,245 @@ +--- +id: agentcore-self-hosted-setup +title: Self-hosted setup for Serverless Workers on Amazon Bedrock AgentCore Runtime +sidebar_label: Self-hosted setup +description: Configure AWS access and a self-hosted Temporal Service to run Serverless Workers on Amazon Bedrock AgentCore Runtime. +slug: /production-deployment/worker-deployments/serverless-workers/agentcore/self-hosted-setup +toc_max_heading_level: 4 +tags: + - Workers + - Deploy + - Serverless + - Self-hosting + - Amazon Bedrock AgentCore +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. + + +Serverless Workers on AgentCore Runtime require Temporal Service v1.32.0 or later. + +This page covers the prerequisites for running [Serverless Workers](/serverless-workers) on a self-hosted Temporal +Service with AgentCore Runtime: + +1. Ensure that AgentCore Runtime and the Temporal Service can reach each other. +2. Enable the Worker Controller Instance (WCI) and AgentCore compute provider through dynamic configuration. +3. Provide the Temporal Service with AWS credentials. +4. Create an IAM role that grants Temporal permission to get and invoke AgentCore Runtime endpoints. + +Once setup is complete, follow the +[AgentCore Runtime deployment guide](/production-deployment/worker-deployments/serverless-workers/agentcore) to deploy +your Worker. + +## Configure network access {/* #configure-network-access */} + +The [Temporal Service frontend](/temporal-service/temporal-server#frontend-service) must be reachable from the +AgentCore Runtime. If the Temporal Service has a public endpoint, configure the Runtime to use a public network. If the +Temporal Service is available only through a private network, configure the Runtime for +[VPC access](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-vpc.html) and connect that VPC to +the network that hosts the Temporal Service. + +The Temporal Service must also reach the AgentCore control-plane and data-plane APIs. If the Service runs in an AWS VPC +without internet access, configure +[AgentCore interface VPC endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/vpc-interface-endpoints.html) +for both APIs. + +## Enable the Worker Controller Instance {/* #enable-worker-controller */} + +[WCI](/serverless-workers#how-invocation-works) is the server component that monitors Task Queues and invokes compute +providers. It is disabled by default and must be enabled through +[dynamic configuration](/references/dynamic-configuration). + +Add the following keys to your dynamic config file: + +```yaml +workercontroller.enabled: + - value: true + +workercontroller.compute_providers.enabled: + - value: + - aws-agentcore + +workercontroller.scaling_algorithms.enabled: + - value: + - no-sync +``` + +`workercontroller.compute_providers.enabled` is an allowlist that defaults to no providers. The `aws-agentcore` value +enables the AgentCore compute provider. AgentCore uses the `no-sync` event-driven scaling algorithm, which invokes a +Runtime session when the Task Queue needs more Worker capacity. + +If either allowlist already contains values for other compute providers or scaling algorithms, keep those values and +add `aws-agentcore` or `no-sync` to the existing list. + +To enable WCI for specific Namespaces instead of globally, add a `constraints` section with the Namespace name under +`workercontroller.enabled`. For example, to enable WCI only for `your-namespace`: + +```yaml +workercontroller.enabled: + - value: true + constraints: + namespace: 'your-namespace' +``` + +The Temporal Service watches the dynamic config file for changes and applies updates without a restart. + +By default, the AWS compute providers require an invocation role and External ID in each Worker Deployment Version. +Keep the default value of `workercontroller.compute_providers.aws.require_role_and_external_id` enabled and create the +role in the following sections. + +## Configure AWS credentials {/* #configure-aws-credentials */} + +The Temporal Service needs AWS credentials to assume the AgentCore invocation role. How you provide credentials depends +on where the Temporal Service runs. + +**On AWS infrastructure such as EC2, ECS, or EKS:** The server uses the attached instance role, task role, or pod role +automatically. The attached role must have `sts:AssumeRole` permission for the invocation role created in the next +step. + +**Outside AWS:** Use [IAM Roles Anywhere](https://aws.amazon.com/iam/roles-anywhere/), or configure static AWS +credentials in the server environment. Static credentials are not recommended: + +```text +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_REGION= +``` + +These credentials must belong to an IAM user or role that has `sts:AssumeRole` permission for the AgentCore invocation +role. + +## Create the AgentCore invocation role {/* #create-invocation-role */} + +Temporal gets and invokes AgentCore Runtime endpoints by assuming an IAM role in your AWS account. The role trust policy +must allow the AWS identity used by the Temporal Service to assume it. + +[Download the CloudFormation template](/files/temporal-self-hosted-serverless-worker-agentcore-role.yaml), then deploy +it. Pass each Runtime ARN with a trailing wildcard so the policy covers the Runtime and its endpoints: + +:::caution + +An [IAM role name can contain at most 64 +characters](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html). If you +set `RoleName`, keep the complete name within this limit. + +::: + +```bash +aws cloudformation create-stack \ + --stack-name temporal-agentcore-worker \ + --template-body file://temporal-self-hosted-serverless-worker-agentcore-role.yaml \ + --parameters \ + ParameterKey=TemporalIamRoleArn,ParameterValue= \ + ParameterKey=AssumeRoleExternalId,ParameterValue= \ + ParameterKey=AgentRuntimeARNs,ParameterValue='*' \ + --capabilities CAPABILITY_NAMED_IAM \ + --region +``` + +| Parameter | Description | +| --- | --- | +| `TemporalIamRoleArn` | ARN of the IAM role or user that the Temporal Service runs as. Run `aws sts get-caller-identity` in the server environment to identify it. | +| `AssumeRoleExternalId` | Unique string that prevents [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attacks. Use the same value when creating the Worker Deployment Version. | +| `AgentRuntimeARNs` | Comma-separated Runtime ARNs that Temporal can access. Append a wildcard to each Runtime ARN to include its endpoints. | +| `RoleName` | Name of the IAM role to create. Defaults to `Temporal-AgentCore-Worker`. Use a different name when deploying more than one copy of the stack. | + +
+CloudFormation template + +```yaml +AWSTemplateFormatVersion: '2010-09-09' +Description: + Creates an IAM role that a self-hosted Temporal Service can assume to invoke Amazon Bedrock AgentCore runtimes. + +Parameters: + TemporalIamRoleArn: + Type: String + Description: The ARN of the IAM role or user that the Temporal Service runs as. + + AssumeRoleExternalId: + Type: String + Description: A unique identifier to prevent confused deputy attacks. + AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' + MinLength: 5 + MaxLength: 45 + + AgentRuntimeARNs: + Type: CommaDelimitedList + Description: >- + Comma-separated list of AgentCore Runtime ARNs that Temporal may access. Append a wildcard to each Runtime ARN + to include its endpoints. + + RoleName: + Type: String + Default: 'Temporal-AgentCore-Worker' + +Resources: + TemporalAgentCoreWorker: + Type: AWS::IAM::Role + Properties: + RoleName: !Ref RoleName + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: [!Ref TemporalIamRoleArn] + Action: sts:AssumeRole + Condition: + StringEquals: + 'sts:ExternalId': [!Ref AssumeRoleExternalId] + Description: The role the Temporal Service uses to invoke AgentCore runtimes for Serverless Workers + MaxSessionDuration: 3600 + + TemporalAgentCoreInvokePermissions: + Type: AWS::IAM::Policy + Properties: + PolicyName: 'Temporal-AgentCore-Invoke-Permissions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - bedrock-agentcore:InvokeAgentRuntime + - bedrock-agentcore:GetAgentRuntimeEndpoint + Resource: !Ref AgentRuntimeARNs + Roles: + - !Ref TemporalAgentCoreWorker + +Outputs: + RoleARN: + Description: The ARN of the IAM role created for the Temporal Service + Value: !GetAtt TemporalAgentCoreWorker.Arn + + AgentRuntimeARNs: + Description: The AgentCore Runtime ARNs that Temporal may access + Value: !Join [', ', !Ref AgentRuntimeARNs] +``` + +
+ +Wait for the stack to finish, then retrieve the invocation role ARN: + +```bash +aws cloudformation wait stack-create-complete \ + --stack-name temporal-agentcore-worker \ + --region + +aws cloudformation describe-stacks \ + --stack-name temporal-agentcore-worker \ + --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' \ + --output text \ + --region +``` + +Use this role ARN and the External ID when creating the Worker Deployment Version. + +## Next steps {/* #next-steps */} + +Follow the [AgentCore Runtime deployment +guide](/production-deployment/worker-deployments/serverless-workers/agentcore). Configure the Runtime Worker with your +self-hosted Temporal Service address and authentication settings. Skip the Temporal Cloud IAM step and use the +invocation role and External ID from this page when you create the Worker Deployment Version with the Temporal CLI. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 27a92f8602..44b03f7ac8 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -2,7 +2,7 @@ id: agentcore title: Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime sidebar_label: Amazon Bedrock AgentCore -description: Deploy an existing Python Worker to AgentCore Runtime and configure Temporal Cloud to start capacity when Task Queue demand increases. +description: Deploy an existing Python Worker to AgentCore Runtime and configure Temporal to start capacity when Task Queue demand increases. slug: /production-deployment/worker-deployments/serverless-workers/agentcore toc_max_heading_level: 4 tags: @@ -35,8 +35,13 @@ Python SDK](/develop/python/workers/serverless-workers/agentcore). ## Prerequisites {/* #prerequisites */} -- A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release. -- A Temporal Cloud API key that can connect to the Namespace. +- A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release, or + a self-hosted Temporal Service v1.32.0 or later. +- For self-hosted deployments, complete the + [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/agentcore/self-hosted-setup) before + following this guide. +- Credentials that let the Worker connect to the Temporal Service. The example configuration uses a Temporal Cloud API + key. - [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later, configured for your Namespace. - An existing Python Temporal Worker with an [AgentCore Runtime handler](/develop/python/workers/serverless-workers/agentcore#runtime-handler). @@ -139,7 +144,7 @@ agentcore status --type runtime-endpoint --json ``` Record the Runtime ARN and the ARN of the named endpoint. You use the Runtime ARN to scope the invocation role and give -the endpoint ARN to Temporal Cloud. +the endpoint ARN to Temporal. AgentCore creates an immutable Runtime version when you create or update a Runtime. A named endpoint remains pinned to its configured version until you update it. For details, see [AgentCore Runtime versioning and @@ -168,11 +173,19 @@ their original Runtime versions. ::: -If you use a VPC instead of a public network, configure outbound access from the VPC to your Temporal Cloud Namespace. -Temporal invokes the named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). +If you use a VPC instead of a public network, configure outbound access from the VPC to the Temporal Service. Temporal +invokes the named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). ## 3. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} +:::info Self-hosted Temporal Service + +If you use a self-hosted Temporal Service, create the invocation role during the +[self-hosted setup](/production-deployment/worker-deployments/serverless-workers/agentcore/self-hosted-setup#create-invocation-role). +Use that role when you create the Worker Deployment Version and skip the rest of this step. + +::: + Temporal Cloud assumes an IAM role in your AWS account to get the named endpoint and invoke the Runtime. Choose an External ID of at least five characters. Use the same value in the role trust policy and the Worker Deployment Version. The External ID prevents a [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) @@ -247,6 +260,8 @@ to [Step 6](#verify-worker-startup). +Use the Temporal CLI for a self-hosted Temporal Service. + First, create the Worker Deployment if it does not already exist: ```bash @@ -272,9 +287,9 @@ The deployment name and Build ID must match the values in the Runtime environmen -To check whether Temporal can reach the endpoint, open the Worker Deployment Version in the Temporal Cloud UI and -select **Actions** > **Validate Connection**. This checks that Temporal can assume the invocation role, get the named -endpoint, and invoke the Runtime. +For Temporal Cloud, check whether Temporal can reach the endpoint by opening the Worker Deployment Version in the +Temporal Cloud UI and selecting **Actions** > **Validate Connection**. This checks that Temporal can assume the +invocation role, get the named endpoint, and invoke the Runtime. ## 5. Set the version as current {/* #set-current-version */} @@ -297,8 +312,8 @@ AgentCore Runtime endpoint. The Runtime starts the Worker, and the Worker polls You can confirm the deployment in these places: -- **Temporal Cloud UI**: Open the Worker Deployment Version and confirm that the connection is valid and a Worker has - polled the Task Queue. +- **Temporal UI**: Open the Worker Deployment Version and confirm that a Worker has polled the Task Queue. In Temporal + Cloud, also confirm that the connection is valid. - **AgentCore logs**: Run `agentcore logs --runtime ` to see the Worker start and process Tasks. - **Temporal CLI**: Run `temporal worker deployment describe --name ` to inspect the deployment and current version. diff --git a/sidebars.js b/sidebars.js index dc7a03a1d1..cdbc0df084 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1605,7 +1605,18 @@ module.exports = { 'production-deployment/worker-deployments/serverless-workers/aws-lambda/self-hosted-setup', ], }, - 'production-deployment/worker-deployments/serverless-workers/agentcore', + { + type: 'category', + label: 'Amazon Bedrock AgentCore', + collapsed: true, + link: { + type: 'doc', + id: 'production-deployment/worker-deployments/serverless-workers/agentcore', + }, + items: [ + 'production-deployment/worker-deployments/serverless-workers/agentcore-self-hosted-setup', + ], + }, { type: 'category', label: 'GCP Cloud Run', diff --git a/static/files/temporal-self-hosted-serverless-worker-agentcore-role.yaml b/static/files/temporal-self-hosted-serverless-worker-agentcore-role.yaml new file mode 100644 index 0000000000..7e98aca04c --- /dev/null +++ b/static/files/temporal-self-hosted-serverless-worker-agentcore-role.yaml @@ -0,0 +1,68 @@ +# CloudFormation template for creating an IAM role that a self-hosted Temporal Service can assume to invoke AgentCore runtimes. +AWSTemplateFormatVersion: '2010-09-09' +Description: + Creates an IAM role that a self-hosted Temporal Service can assume to invoke Amazon Bedrock AgentCore runtimes. + +Parameters: + TemporalIamRoleArn: + Type: String + Description: The ARN of the IAM role or user that the Temporal Service runs as. + + AssumeRoleExternalId: + Type: String + Description: A unique identifier to prevent confused deputy attacks. + AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' + MinLength: 5 + MaxLength: 45 + + AgentRuntimeARNs: + Type: CommaDelimitedList + Description: >- + Comma-separated list of AgentCore Runtime ARNs that Temporal may access. Append a wildcard to each Runtime ARN + to include its endpoints. + + RoleName: + Type: String + Default: 'Temporal-AgentCore-Worker' + +Resources: + TemporalAgentCoreWorker: + Type: AWS::IAM::Role + Properties: + RoleName: !Ref RoleName + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: [!Ref TemporalIamRoleArn] + Action: sts:AssumeRole + Condition: + StringEquals: + 'sts:ExternalId': [!Ref AssumeRoleExternalId] + Description: The role the Temporal Service uses to invoke AgentCore runtimes for Serverless Workers + MaxSessionDuration: 3600 + + TemporalAgentCoreInvokePermissions: + Type: AWS::IAM::Policy + Properties: + PolicyName: 'Temporal-AgentCore-Invoke-Permissions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - bedrock-agentcore:InvokeAgentRuntime + - bedrock-agentcore:GetAgentRuntimeEndpoint + Resource: !Ref AgentRuntimeARNs + Roles: + - !Ref TemporalAgentCoreWorker + +Outputs: + RoleARN: + Description: The ARN of the IAM role created for the Temporal Service + Value: !GetAtt TemporalAgentCoreWorker.Arn + + AgentRuntimeARNs: + Description: The AgentCore Runtime ARNs that Temporal may access + Value: !Join [', ', !Ref AgentRuntimeARNs] From 5fc479fd5cf267d9b865df39eba3e56206878021 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:10:06 -0700 Subject: [PATCH 48/77] Lead AgentCore readers to complete tutorial --- .../serverless-workers/serverless-workers-agentcore.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 90d3772a70..57c5e44dda 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -23,7 +23,9 @@ import { ReleaseNoteHeader } from '@site/src/components'; This page covers how Serverless Workers run on Amazon Bedrock AgentCore Runtime, including Worker Versioning and the Runtime session lifecycle. -To deploy a Worker, see +For a complete tutorial that explains the agent architecture and walks through deployment, see +[Build a durable agent on Amazon Bedrock AgentCore](/guides/durable-agent-on-agentcore). If your Worker and AgentCore +project are already in place, see [Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore). On AgentCore Runtime, a Serverless Worker is a standard long-running Temporal Worker that runs inside an AgentCore From d9da7857f6b81a4716b417ed5d40e12d3b6b4d43 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:10:58 -0700 Subject: [PATCH 49/77] Clarify AgentCore deployment guide scope --- docs/guides/durable-agent-on-agentcore.mdx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 08ec89d706..57f85d94d9 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -23,9 +23,10 @@ import { CaptionedImage, ReleaseNoteHeader } from '@site/src/components'; This guide deploys a Strands agent as a Temporal Serverless Worker on Amazon Bedrock AgentCore Runtime. The agent uses Amazon Bedrock for model inference and AgentCore Code Interpreter to run Python. -The [AgentCore deployment page](/production-deployment/worker-deployments/serverless-workers/agentcore) is a focused -procedure for deploying an existing Worker. This guide uses a complete agent sample to explain why the Workflow, -Activities, Runtime, and Worker Deployment are structured this way. +If you already have an AgentCore application and are only interested in deploying a Worker Runtime, see +[Deploy a Serverless Worker on Amazon Bedrock AgentCore +Runtime](/production-deployment/worker-deployments/serverless-workers/agentcore). This guide uses a complete agent +sample to explain why the Workflow, Activities, Runtime, and Worker Deployment are structured this way. ## What you will build From 9ee2c0d2a917077c801cc4a4a030bdc269c667b7 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:12:19 -0700 Subject: [PATCH 50/77] Lead AgentCore tutorial with agent capability --- docs/guides/durable-agent-on-agentcore.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 57f85d94d9..4e9828c0d3 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -30,8 +30,10 @@ sample to explain why the Workflow, Activities, Runtime, and Worker Deployment a ## What you will build -The sample accepts one prompt and runs one Workflow Execution. The Workflow asks the model to answer the prompt. The -model can call Code Interpreter through a Temporal Activity before returning its answer. +You will build an agent that can respond to prompts by using Amazon Bedrock for model inference and AgentCore Code +Interpreter to run Python when needed. The sample accepts one prompt and runs one Workflow Execution. The Workflow asks +the model to answer the prompt. The model can call Code Interpreter through a Temporal Activity before returning its +answer. Your local client starts the Workflow through Temporal. When the Task Queue needs a Worker, Temporal starts an AgentCore Runtime session. The Worker processes the Workflow and Activity Tasks, then drains after 60 seconds without From 9a545dabfbd986f49a9effee4bcf037fb9c5ef7e Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:12:34 -0700 Subject: [PATCH 51/77] Avoid assuming AgentCore client location --- docs/guides/durable-agent-on-agentcore.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 4e9828c0d3..c5094d64bb 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -35,7 +35,7 @@ Interpreter to run Python when needed. The sample accepts one prompt and runs on the model to answer the prompt. The model can call Code Interpreter through a Temporal Activity before returning its answer. -Your local client starts the Workflow through Temporal. When the Task Queue needs a Worker, Temporal starts an +Your Temporal Client starts the Workflow. When the Task Queue needs a Worker, Temporal starts an AgentCore Runtime session. The Worker processes the Workflow and Activity Tasks, then drains after 60 seconds without an Activity starting or finishing. From 406383fc6f3e09e01bba61c6e9c7e944060a5dda Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:13:12 -0700 Subject: [PATCH 52/77] Explain AgentCore sample reliability concretely --- docs/guides/durable-agent-on-agentcore.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index c5094d64bb..1271182871 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -39,9 +39,9 @@ Your Temporal Client starts the Workflow. When the Task Queue needs a Worker, Te AgentCore Runtime session. The Worker processes the Workflow and Activity Tasks, then drains after 60 seconds without an Activity starting or finishing. -The sample is intentionally one turn. This keeps the deployment path visible while still demonstrating the important -reliability boundary: the model and tool calls are recorded Temporal operations, and the Worker process that performs -them can be replaced. +The sample handles one turn so the tutorial can focus on deployment. Both the model request and Code Interpreter call +run as Temporal Activities. If the Worker stops before an Activity completes, Temporal can retry the Activity on +another Worker according to its Retry Policy. ## Architecture From 1e673f2016a8d75d253ba789a197dd994968cd26 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:16:29 -0700 Subject: [PATCH 53/77] Clarify AgentCore multi-turn guidance --- docs/guides/durable-agent-on-agentcore.mdx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 1271182871..9aefeeaf94 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -47,7 +47,8 @@ another Worker according to its Retry Policy. Temporal Cloud owns the agent's execution state and capacity control. The application starts or signals the Workflow. The Workflow records agent decisions and schedules model and tool work as Temporal Tasks. When the Task Queue needs -capacity, the Worker Controller Instance starts AgentCore Runtime sessions. +capacity, the [Worker Controller Instance (WCI)](/serverless-workers#worker-controller-instance) starts AgentCore +Runtime sessions. Each Runtime session hosts a Temporal Worker that polls the versioned Task Queue. Workers can call AgentCore services, but the sessions and their process-local state remain replaceable. The sample in this guide uses AgentCore Code @@ -72,8 +73,8 @@ Place state according to how long it must remain available: This division is what lets the Workflow outlive any one Runtime session. A Worker can stop after the current work is complete, and a later Worker can reconstruct the Workflow before continuing it. -To extend the sample to multiple turns, use one Workflow Id per conversation, keep the Workflow open, and accept later -prompts through Workflow Updates while allowing any compatible Runtime session to process each turn. +To extend the sample to multiple turns, use one Workflow ID per conversation and send later prompts to that Workflow +through Updates. Any compatible Runtime session can process the next turn. ## Prerequisites @@ -152,7 +153,7 @@ The Workflow owns the sequence of model and tool decisions because that sequence failure. The model calls themselves do not run as ordinary Workflow code. They run as Activities because they perform network I/O, can fail independently, and are not deterministic. -The `execute_code` Activity creates a Code Interpreter session using the Workflow Id as its session name: +The `execute_code` Activity creates a Code Interpreter session using the Workflow ID as its session name: [bedrock_agentcore/strands_agent/activities.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/activities.py) @@ -175,7 +176,7 @@ def execute_code( ``` -Using the Workflow Id gives each Workflow Execution its own Code Interpreter sandbox. +Using the Workflow ID gives each Workflow Execution its own Code Interpreter sandbox. ## 3. Configure and deploy the Runtime From 3d3e225657b569d2c7fb6f516c1dd0df758cf202 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:28:12 -0700 Subject: [PATCH 54/77] Move AgentCore CLI installation to prerequisites --- docs/guides/durable-agent-on-agentcore.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 9aefeeaf94..421e5d6456 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -82,8 +82,7 @@ through Updates. Any compatible Runtime session can process the next turn. - A Temporal Cloud API key that can connect to the Namespace. - [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later. - Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/). -- Node.js 20 or later and the - [AgentCore CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html). +- Node.js 20 or later. - The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) configured for your AWS account. - The [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed and bootstrapped in an @@ -92,6 +91,13 @@ through Updates. Any compatible Runtime session can process the next turn. [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). - Access to the Amazon Bedrock model that Strands selects in the target Region. +Install the [AgentCore +CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html): + +```bash +npm install -g @aws/agentcore +``` + ## 1. Get the sample Clone the branch from the @@ -180,12 +186,6 @@ Using the Workflow ID gives each Workflow Execution its own Code Interpreter san ## 3. Configure and deploy the Runtime -Install the AgentCore CLI: - -```bash -npm install -g @aws/agentcore -``` - Open `agentcore/aws-targets.json`. Replace the account number and Region with the AWS account and Region where you will deploy the Runtime: From 0afdca541d25075856e57e78d65cf6b9813e7c33 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:28:42 -0700 Subject: [PATCH 55/77] Align AgentCore CLI prerequisite format --- docs/guides/durable-agent-on-agentcore.mdx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 421e5d6456..2d9ba359ac 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -82,7 +82,8 @@ through Updates. Any compatible Runtime session can process the next turn. - A Temporal Cloud API key that can connect to the Namespace. - [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later. - Python 3.10 or later and [`uv`](https://docs.astral.sh/uv/). -- Node.js 20 or later. +- Node.js 20 or later and the + [AgentCore CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html). - The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) configured for your AWS account. - The [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed and bootstrapped in an @@ -91,13 +92,6 @@ through Updates. Any compatible Runtime session can process the next turn. [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). - Access to the Amazon Bedrock model that Strands selects in the target Region. -Install the [AgentCore -CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html): - -```bash -npm install -g @aws/agentcore -``` - ## 1. Get the sample Clone the branch from the From dcd128e1613c76e5472ec2c43c0282cef71f18d2 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:38:41 -0700 Subject: [PATCH 56/77] Explain AgentCore and client configuration scopes --- docs/guides/durable-agent-on-agentcore.mdx | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 2d9ba359ac..5b81217274 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -212,15 +212,9 @@ does not register as the version waiting for work. Putting the API key in `agentcore.json` keeps the tutorial short. Do not commit the populated file. For a production deployment, store the key in AWS Secrets Manager and load it when the Runtime starts. -Export the same connection values for the Temporal CLI and the sample client: +Set the Region for the AWS CLI commands in this guide: ```bash -export TEMPORAL_ADDRESS="..tmprl.cloud:7233" -export TEMPORAL_NAMESPACE="." -printf "Temporal Cloud API key: " -read -rs TEMPORAL_API_KEY -printf "\n" -export TEMPORAL_API_KEY export AWS_REGION="" ``` @@ -325,6 +319,18 @@ as the Runtime. ## 5. Create the Serverless Worker deployment +The values in `agentcore.json` configure the Worker inside AgentCore Runtime. They do not configure the Temporal CLI or +the sample client process. Export the Temporal connection values for those processes: + +```bash +export TEMPORAL_ADDRESS="..tmprl.cloud:7233" +export TEMPORAL_NAMESPACE="." +printf "Temporal Cloud API key: " +read -rs TEMPORAL_API_KEY +printf "\n" +export TEMPORAL_API_KEY +``` + Create a Worker Deployment and a version that points to the AgentCore endpoint: ```bash From d5fbfaa3b5c950f55f89d0030135ed6a0af29a57 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:48:55 -0700 Subject: [PATCH 57/77] Reuse AgentCore runtime environment configuration --- docs/guides/durable-agent-on-agentcore.mdx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 5b81217274..568f760639 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -317,20 +317,17 @@ start capacity. AgentCore assumes the execution role inside that capacity when t Interpreter. The trailing wildcard on the Runtime ARN allows the invocation role to cover the named endpoint as well as the Runtime. -## 5. Create the Serverless Worker deployment - The values in `agentcore.json` configure the Worker inside AgentCore Runtime. They do not configure the Temporal CLI or -the sample client process. Export the Temporal connection values for those processes: +the sample client process. Before continuing, export `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, `TEMPORAL_API_KEY`, and +`AWS_REGION` for those processes. From the `samples-python/bedrock_agentcore/strands_agent` directory, run this command +to read and export the values from `agentcore/agentcore.json`: ```bash -export TEMPORAL_ADDRESS="..tmprl.cloud:7233" -export TEMPORAL_NAMESPACE="." -printf "Temporal Cloud API key: " -read -rs TEMPORAL_API_KEY -printf "\n" -export TEMPORAL_API_KEY +eval "$(python3 -c 'import json, shlex; env = {item["name"]: item["value"] for item in json.load(open("agentcore/agentcore.json"))["runtimes"][0]["envVars"]}; print("\n".join(f"export {name}={shlex.quote(env[name])}" for name in ("TEMPORAL_ADDRESS", "TEMPORAL_NAMESPACE", "TEMPORAL_API_KEY", "AWS_REGION")))')" ``` +## 5. Create the Serverless Worker deployment + Create a Worker Deployment and a version that points to the AgentCore endpoint: ```bash From b283d64a417bc7495d71b3a548dfe197d7154f22 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:55:13 -0700 Subject: [PATCH 58/77] Place environment export within deployment step --- docs/guides/durable-agent-on-agentcore.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 568f760639..27baad6a65 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -317,6 +317,8 @@ start capacity. AgentCore assumes the execution role inside that capacity when t Interpreter. The trailing wildcard on the Runtime ARN allows the invocation role to cover the named endpoint as well as the Runtime. +## 5. Create the Serverless Worker deployment + The values in `agentcore.json` configure the Worker inside AgentCore Runtime. They do not configure the Temporal CLI or the sample client process. Before continuing, export `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, `TEMPORAL_API_KEY`, and `AWS_REGION` for those processes. From the `samples-python/bedrock_agentcore/strands_agent` directory, run this command @@ -326,8 +328,6 @@ to read and export the values from `agentcore/agentcore.json`: eval "$(python3 -c 'import json, shlex; env = {item["name"]: item["value"] for item in json.load(open("agentcore/agentcore.json"))["runtimes"][0]["envVars"]}; print("\n".join(f"export {name}={shlex.quote(env[name])}" for name in ("TEMPORAL_ADDRESS", "TEMPORAL_NAMESPACE", "TEMPORAL_API_KEY", "AWS_REGION")))')" ``` -## 5. Create the Serverless Worker deployment - Create a Worker Deployment and a version that points to the AgentCore endpoint: ```bash From e32f5243f43b51f4ce96f51fac8899ae7e5e5a49 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 17:56:13 -0700 Subject: [PATCH 59/77] Remove unnecessary AgentCore invocation contrast --- docs/guides/durable-agent-on-agentcore.mdx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 27baad6a65..84da7cd162 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -374,10 +374,6 @@ uv run python starter.py \ Workflow calls the model and Code Interpreter Activities, and the client prints the answer. The Workflow then completes. After 60 seconds without an Activity starting or finishing, the Worker drains. -Starting the agent through `starter.py`, rather than invoking the AgentCore endpoint, is an architectural choice. The -Temporal Client creates the durable Workflow Execution first. AgentCore supplies a Worker when Temporal has a Task -ready to run. - Inspect the completed Workflow Execution: ```bash From 6034ed08b1ccde4ae2af896557c491d8e565e844 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 18:03:02 -0700 Subject: [PATCH 60/77] Clarify AgentCore log search window --- docs/guides/durable-agent-on-agentcore.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 84da7cd162..ed63ce54be 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -381,10 +381,10 @@ temporal workflow show \ --workflow-id agentcore-strands-workflow-id-1 ``` -The Event History contains the model and `execute_code` Activities. Follow the Worker from AgentCore: +The Event History contains the model and `execute_code` Activities. Search the previous hour of AgentCore Runtime logs: ```bash -agentcore logs --runtime temporal_strands_worker +agentcore logs --runtime temporal_strands_worker --since 1h ``` The Workflow history and AgentCore logs show the two sides of the integration. Event History records what the agent From dc86779ee0651ec95f9254aef991676cafc1ccb4 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Tue, 15 Sep 2026 18:31:43 -0700 Subject: [PATCH 61/77] Use a repeatable tutorial External ID --- docs/guides/durable-agent-on-agentcore.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index ed63ce54be..5d6e5c9dcf 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -272,10 +272,10 @@ endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-r ## 4. Grant Temporal access to the Runtime -Choose an External ID, then use the sample's CloudFormation script to create the IAM role that Temporal Cloud assumes: +Set the External ID, then use the sample's CloudFormation script to create the IAM role that Temporal Cloud assumes: ```bash -export EXTERNAL_ID="$(openssl rand -hex 16)" +export EXTERNAL_ID="temporal-agentcore-tutorial" export INVOCATION_STACK="ac-strands-invoke" ./bin/mk-invoke-role.sh \ @@ -284,6 +284,8 @@ export INVOCATION_STACK="ac-strands-invoke" "${AGENT_RUNTIME_ARN}*" ``` +The fixed External ID makes the tutorial commands repeatable. Use a unique External ID for a production deployment. + :::caution The sample names the IAM role `Temporal-Cloud-Serverless-Worker-`. An [IAM role name can contain at most 64 From 0f2a0710dc210dad23c9bac847d076c819c21282 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 09:38:09 -0700 Subject: [PATCH 62/77] Clarify AgentCore deployment target --- .../worker-deployments/serverless-workers/agentcore.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 44b03f7ac8..660a8b59a2 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -127,11 +127,12 @@ separate from the invocation role that Temporal assumes. ## 2. Deploy the Worker Runtime {/* #deploy-runtime */} -From the AgentCore project directory, validate and deploy the project: +From the AgentCore project directory, validate and deploy the project. Set `--target` to the `name` of the deployment +target in `agentcore/aws-targets.json`. For example, if the target is named `default`, run: ```bash agentcore validate -agentcore deploy --target -y +agentcore deploy --target default -y ``` AgentCore packages the Worker and its dependencies, deploys the Runtime, and creates the named endpoint. From e4bfba23a415ae35ef03479ba6cd47fdb64fb780 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 09:47:37 -0700 Subject: [PATCH 63/77] Rewrite retired AI Cookbook docs links --- bin/sync-ai-cookbook.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/sync-ai-cookbook.js b/bin/sync-ai-cookbook.js index 31eb55257a..7b169e3c1b 100644 --- a/bin/sync-ai-cookbook.js +++ b/bin/sync-ai-cookbook.js @@ -24,6 +24,9 @@ const SLUG_ALIASES = new Map([ // Add more aliases as recipes are renamed: ['old-slug', 'new-slug'] ]); +// Map old documentation paths used by cookbook recipes to their current routes. +const DOCS_PATH_ALIASES = new Map([['/evaluate/cloud/limits', '/cloud/limits']]); + function runGit(args, options = {}) { const result = spawnSync('git', args, { stdio: ['ignore', 'inherit', 'inherit'], @@ -297,7 +300,8 @@ function normalizeDocsHref(href) { if (!match) { return null; } - const pathname = match[1] ?? '/'; + const originalPathname = match[1] ?? '/'; + const pathname = DOCS_PATH_ALIASES.get(originalPathname) ?? originalPathname; const search = match[2] ?? ''; const hash = match[3] ?? ''; return `${pathname}${search}${hash}`; From 91803510183db467807e33e5691d2c89e17d4e38 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 10:01:17 -0700 Subject: [PATCH 64/77] Explain AgentCore Runtime name --- .../worker-deployments/serverless-workers/agentcore.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 660a8b59a2..62e82a7c5e 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -105,6 +105,7 @@ named endpoint that Temporal invokes: ```json { + "name": "temporal_strands_worker", "entrypoint": "agentcore_worker.py", "networkMode": "PUBLIC", "protocol": "HTTP", @@ -137,10 +138,11 @@ agentcore deploy --target default -y AgentCore packages the Worker and its dependencies, deploys the Runtime, and creates the named endpoint. -Check the deployed resources: +Check the deployed resources. The `--runtime` value is the Runtime object's `name` in `agentcore/agentcore.json`. The +sample Runtime is named `temporal_strands_worker`. If your Runtime has a different name, replace this value: ```bash -agentcore status --runtime --json +agentcore status --runtime temporal_strands_worker --json agentcore status --type runtime-endpoint --json ``` From f073e3c3ec3c42baf240427956e5eff1c2587832 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 10:20:21 -0700 Subject: [PATCH 65/77] Clarify AgentCore Worker guide prerequisites --- .../serverless-workers/agentcore.mdx | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 62e82a7c5e..17db43534c 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -2,7 +2,7 @@ id: agentcore title: Deploy a Serverless Worker on Amazon Bedrock AgentCore Runtime sidebar_label: Amazon Bedrock AgentCore -description: Deploy an existing Python Worker to AgentCore Runtime and configure Temporal to start capacity when Task Queue demand increases. +description: Add a Python Worker to an existing AgentCore application and configure Temporal to start capacity when Task Queue demand increases. slug: /production-deployment/worker-deployments/serverless-workers/agentcore toc_max_heading_level: 4 tags: @@ -20,9 +20,9 @@ import TabItem from '@theme/TabItem'; Amazon Bedrock AgentCore Runtime support is in Pre-release, and its APIs may change in backwards-incompatible ways. -This page covers only deploying an existing Python [Serverless Worker](/serverless-workers) to Amazon Bedrock AgentCore -Runtime and connecting it to a Worker Deployment Version. It assumes that your Worker and AgentCore project are already -in place. +This page shows how to add a Python [Serverless Worker](/serverless-workers) to an existing Amazon Bedrock AgentCore +application, deploy it to AgentCore Runtime, and connect it to a Worker Deployment Version. It assumes that your +Workflow and Activity code and AgentCore project are already in place. For a complete tutorial, see [Build a durable agent on Amazon Bedrock AgentCore](/guides/durable-agent-on-agentcore). That guide starts with the [Python Strands AgentCore @@ -35,29 +35,26 @@ Python SDK](/develop/python/workers/serverless-workers/agentcore). ## Prerequisites {/* #prerequisites */} -- A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release, or - a self-hosted Temporal Service v1.32.0 or later. -- For self-hosted deployments, complete the - [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/agentcore/self-hosted-setup) before - following this guide. -- Credentials that let the Worker connect to the Temporal Service. The example configuration uses a Temporal Cloud API - key. +- A Temporal Cloud account with an AWS-hosted Namespace and access to the AgentCore Serverless Workers Pre-release. For + a self-hosted Temporal Service v1.32.0 or later, complete the + [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/agentcore/self-hosted-setup) first. - [Temporal CLI v1.8.3](https://github.com/temporalio/cli/releases/tag/v1.8.3) or later, configured for your Namespace. -- An existing Python Temporal Worker with an - [AgentCore Runtime handler](/develop/python/workers/serverless-workers/agentcore#runtime-handler). -- An AgentCore project that packages the Worker and contains `agentcore/agentcore.json`, `agentcore/aws-targets.json`, - and the generated AgentCore CDK project. -- An AWS account in an [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html). -- The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed and configured - with credentials for that account. -- Node.js 20 or later and the [AgentCore CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html) - installed with `npm install -g @aws/agentcore`. -- The [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed and bootstrapped in the target - account and Region. -- Permission to create AgentCore resources, CloudFormation stacks, and IAM roles. See +- An existing AgentCore project with `agentcore/agentcore.json`, `agentcore/aws-targets.json`, and a generated AgentCore + CDK project. +- An AWS account in an [AgentCore-supported Region](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html), + with the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) configured for that + account and permission to create AgentCore resources, CloudFormation stacks, and IAM roles. See [IAM permissions for AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html). +- Node.js 20 or later, the [AgentCore CLI](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html), + and the [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed. Bootstrap the CDK in the + target account and Region. -## 1. Configure the Worker Runtime {/* #configure-worker-runtime */} +## 1. Add and configure the Worker Runtime {/* #configure-worker-runtime */} + +Add a Python entry point that creates a Temporal Worker for your Workflows and Activities. Configure the Worker with a +[Worker Deployment Version](/develop/python/workers/serverless-workers/agentcore#versioned-worker), then start it from +an [AgentCore Runtime handler](/develop/python/workers/serverless-workers/agentcore#runtime-handler). The handler keeps +the Worker polling in the background after it acknowledges the AgentCore invocation. `agentcore/agentcore.json` is the [AgentCore CLI project configuration](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html). Its From c5400a102bce51b9563235c4b03bad9ca9220e6b Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 10:25:22 -0700 Subject: [PATCH 66/77] Clarify AgentCore tutorial scope --- .../worker-deployments/serverless-workers/agentcore.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 17db43534c..ede39582ac 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -24,8 +24,8 @@ This page shows how to add a Python [Serverless Worker](/serverless-workers) to application, deploy it to AgentCore Runtime, and connect it to a Worker Deployment Version. It assumes that your Workflow and Activity code and AgentCore project are already in place. -For a complete tutorial, see [Build a durable agent on Amazon Bedrock -AgentCore](/guides/durable-agent-on-agentcore). That guide starts with the [Python Strands AgentCore +For a tutorial that walks you through setting up an AgentCore project from scratch, see [Build a durable agent on +Amazon Bedrock AgentCore](/guides/durable-agent-on-agentcore). That guide starts with the [Python Strands AgentCore sample](https://github.com/temporalio/samples-python/tree/schoeff/strands-agent/bedrock_agentcore/strands_agent) and explains the agent architecture, Workflow and Activity boundaries, AgentCore project configuration, and deployment from start to finish. Use this page when you only need the Worker deployment procedure. From 16bc2788f8d0c03d5a3074b2b182fa3ab0c1bcef Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 10:38:31 -0700 Subject: [PATCH 67/77] Reorder AgentCore Runtime configuration --- .../serverless-workers/agentcore.mdx | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index ede39582ac..5f8f0b73f3 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -58,38 +58,7 @@ the Worker polling in the background after it acknowledges the AgentCore invocat `agentcore/agentcore.json` is the [AgentCore CLI project configuration](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html). Its -`runtimes` array defines the AgentCore Runtime resources that the CLI deploys. In the existing Runtime object, configure -the Temporal connection, Task Queue, Worker Deployment name, and Build ID: - -```json -{ - "name": "TEMPORAL_ADDRESS", - "value": "..tmprl.cloud:7233" -}, -{ - "name": "TEMPORAL_NAMESPACE", - "value": "." -}, -{ - "name": "TEMPORAL_API_KEY", - "value": "" -}, -{ - "name": "TEMPORAL_TASK_QUEUE", - "value": "" -}, -{ - "name": "TEMPORAL_DEPLOYMENT_NAME", - "value": "" -}, -{ - "name": "TEMPORAL_BUILD_ID", - "value": "" -} -``` - -The Task Queue must match the Task Queue used by your application. The deployment name and Build ID must match the -Worker Deployment Version that you create in [Step 4](#create-worker-deployment-version). +`runtimes` array defines the AgentCore Runtime resources that the CLI deploys. The `entrypoint` field names the Python file that AgentCore starts. That file must implement the [AgentCore Runtime HTTP protocol contract](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-http-protocol-contract.html) by @@ -119,6 +88,44 @@ named endpoint that Temporal invokes: In this initial configuration, `version: 1` selects the first AgentCore Runtime version. Verify the named endpoint's version after deployment in [Step 2](#deploy-runtime). +Within the same Runtime object, add the Temporal connection, Task Queue, Worker Deployment name, and Build ID to the +`envVars` array: + +```json +{ + "envVars": [ + { + "name": "TEMPORAL_ADDRESS", + "value": "..tmprl.cloud:7233" + }, + { + "name": "TEMPORAL_NAMESPACE", + "value": "." + }, + { + "name": "TEMPORAL_API_KEY", + "value": "" + }, + { + "name": "TEMPORAL_TASK_QUEUE", + "value": "" + }, + { + "name": "TEMPORAL_DEPLOYMENT_NAME", + "value": "" + }, + { + "name": "TEMPORAL_BUILD_ID", + "value": "" + } + ] +} +``` + +Replace `.` with your Temporal Cloud Namespace ID, `` with its API key, and +`` with the Task Queue used by your application. Choose `` and `` for this Worker +version. + Do not commit a populated Temporal Cloud API key. For a production deployment, store it in AWS Secrets Manager, grant the Runtime execution role permission to read it, and load it in the Runtime entry point. The Runtime execution role is separate from the invocation role that Temporal assumes. @@ -239,7 +246,9 @@ Runtime resources. This role does not run the Worker code. ## 4. Create the Worker Deployment Version {/* #create-worker-deployment-version */} Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) whose compute -configuration points to the named AgentCore Runtime endpoint. +configuration points to the named AgentCore Runtime endpoint. The deployment name and Build ID must match +`TEMPORAL_DEPLOYMENT_NAME` and `TEMPORAL_BUILD_ID` in the Runtime environment from +[Step 1](#configure-worker-runtime). @@ -282,8 +291,6 @@ temporal worker deployment create-version \ --aws-agentcore-assume-role-external-id ``` -The deployment name and Build ID must match the values in the Runtime environment. - From f2c6c7affb2c38a8b4969120bf5be6c2a8ca6bfa Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 10:49:44 -0700 Subject: [PATCH 68/77] Document AgentCore Worker package structure --- .../serverless-workers/agentcore.mdx | 143 +++++++++++++++--- 1 file changed, 126 insertions(+), 17 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 5f8f0b73f3..2b8fa47254 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -49,12 +49,7 @@ Python SDK](/develop/python/workers/serverless-workers/agentcore). and the [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed. Bootstrap the CDK in the target account and Region. -## 1. Add and configure the Worker Runtime {/* #configure-worker-runtime */} - -Add a Python entry point that creates a Temporal Worker for your Workflows and Activities. Configure the Worker with a -[Worker Deployment Version](/develop/python/workers/serverless-workers/agentcore#versioned-worker), then start it from -an [AgentCore Runtime handler](/develop/python/workers/serverless-workers/agentcore#runtime-handler). The handler keeps -the Worker polling in the background after it acknowledges the AgentCore invocation. +## 1. Configure the Worker Runtime {/* #configure-worker-runtime */} `agentcore/agentcore.json` is the [AgentCore CLI project configuration](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-get-started-cli.html). Its @@ -72,7 +67,10 @@ named endpoint that Temporal invokes: ```json { "name": "temporal_strands_worker", + "build": "CodeZip", "entrypoint": "agentcore_worker.py", + "codeLocation": ".", + "runtimeVersion": "PYTHON_3_12", "networkMode": "PUBLIC", "protocol": "HTTP", "authorizerType": "AWS_IAM", @@ -86,7 +84,7 @@ named endpoint that Temporal invokes: ``` In this initial configuration, `version: 1` selects the first AgentCore Runtime version. Verify the named endpoint's -version after deployment in [Step 2](#deploy-runtime). +version after deployment in [Step 3](#deploy-runtime). Within the same Runtime object, add the Temporal connection, Task Queue, Worker Deployment name, and Build ID to the `envVars` array: @@ -130,7 +128,118 @@ Do not commit a populated Temporal Cloud API key. For a production deployment, s the Runtime execution role permission to read it, and load it in the Runtime entry point. The Runtime execution role is separate from the invocation role that Temporal assumes. -## 2. Deploy the Worker Runtime {/* #deploy-runtime */} +## 2. Add the Worker code {/* #add-worker-code */} + +For a `CodeZip` Runtime, AgentCore packages the directory identified by `codeLocation`. The `entrypoint` path is +relative to that directory. The directory must contain the entry point, every local module that it imports, and a +`pyproject.toml` file that declares the Runtime dependencies. + +The sample sets `codeLocation` to `.` and uses the following layout: + +```text +project-root/ +├── agentcore/ +│ ├── agentcore.json +│ ├── aws-targets.json +│ └── cdk/ +├── agentcore_worker.py +├── workflows.py +├── activities.py +└── pyproject.toml +``` + +With this layout, set `entrypoint` to `agentcore_worker.py`. If your AgentCore application keeps code in a directory +such as `app/MyAgent`, set `codeLocation` to that directory and put the entry point, imported modules, and +`pyproject.toml` there. + +Declare `temporalio`, `bedrock-agentcore`, and your application dependencies in `pyproject.toml`. The entry point must: + +- Connect a Temporal Client and create a standard long-running Worker with your Workflows and Activities. +- Configure the Worker with the deployment name and Build ID from the Runtime environment. +- Use `BedrockAgentCoreApp` to implement the AgentCore Runtime HTTP endpoints. +- Start the Worker as an AgentCore asynchronous task and acknowledge the invocation without waiting for the Worker to + stop. +- Stop polling and drain the Worker when its idle policy decides to release the Runtime. + +The following excerpt from the Python sample implements this structure. It uses the `ActivityTracker`, `DEBOUNCE`, and +`DRAIN` values defined in the same source file to retire the Worker after an idle period. The complete linked source +file also contains the imports, creates the `BedrockAgentCoreApp`, retains the background task in `_worker`, and calls +`app.run()` when the entry point starts. For the idle-policy code and an explanation of each part, see +[Start the Worker from the Runtime handler](/develop/python/workers/serverless-workers/agentcore#runtime-handler). + + +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/agentcore_worker.py) +```py +async def run_worker() -> None: + """Poll until idle, then drain.""" + api_key = os.environ.get("TEMPORAL_API_KEY") or None + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + namespace=os.environ.get("TEMPORAL_NAMESPACE", "default"), + api_key=api_key, + tls=bool(api_key), + plugins=[StrandsPlugin()], + ) + + tracker = ActivityTracker() + log.info("polling %s as %s/%s", TASK_QUEUE, DEPLOYMENT_NAME, BUILD_ID) + # execute_code is a sync Activity, so it needs an executor to block on. + with ThreadPoolExecutor(max_workers=4) as activity_executor: + worker = Worker( + client, + task_queue=TASK_QUEUE, + workflows=[workflows.StrandsAgentWorkflow], + activities=[execute_code], + activity_executor=activity_executor, + interceptors=[tracker], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=DEPLOYMENT_NAME, build_id=BUILD_ID + ), + use_worker_versioning=True, + default_versioning_behavior=VersioningBehavior.PINNED, + ), + graceful_shutdown_timeout=DRAIN, + ) + async with worker: + await tracker.wait_until_idle(DEBOUNCE) + log.info("worker idle for %ss; drained", DEBOUNCE) + + +async def _run_until_idle(task_id: int) -> None: + """Own the Worker's whole life, and always release the async task.""" + try: + await run_worker() + except Exception: + # Nothing awaits this task, so an error would otherwise be swallowed. + log.exception("worker failed in async task") + finally: + # Without this the session stays HealthyBusy until MaxLifetime. + app.complete_async_task(task_id) + + +@app.entrypoint +async def invoke(payload: dict) -> dict: + """Start the Worker and acknowledge. The payload is unused.""" + # Prevent duplicate workers since we exit early + global _worker + if _worker is not None and not _worker.done(): + log.info("worker already polling %s", TASK_QUEUE) + return {"message": "worker already polling", "task_queue": TASK_QUEUE} + + task_id = app.add_async_task("temporal-worker") + _worker = asyncio.create_task(_run_until_idle(task_id)) + + return {"message": "worker starting", "task_queue": TASK_QUEUE} + + +``` + + +Replace `StrandsPlugin`, `StrandsAgentWorkflow`, and `execute_code` with the plugins, Workflows, and Activities used by +your application. If all Activities are asynchronous, you do not need the `ThreadPoolExecutor` or `activity_executor`. + +## 3. Deploy the Worker Runtime {/* #deploy-runtime */} From the AgentCore project directory, validate and deploy the project. Set `--target` to the `name` of the deployment target in `agentcore/aws-targets.json`. For example, if the target is named `default`, run: @@ -181,9 +290,9 @@ their original Runtime versions. ::: If you use a VPC instead of a public network, configure outbound access from the VPC to the Temporal Service. Temporal -invokes the named endpoint by assuming the IAM role that you create in [Step 3](#configure-iam). +invokes the named endpoint by assuming the IAM role that you create in [Step 4](#configure-iam). -## 3. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} +## 4. Grant Temporal permission to invoke the Runtime {/* #configure-iam */} :::info Self-hosted Temporal Service @@ -243,7 +352,7 @@ aws cloudformation describe-stacks \ The role grants `bedrock-agentcore:InvokeAgentRuntime` and `bedrock-agentcore:GetAgentRuntimeEndpoint` on the configured Runtime resources. This role does not run the Worker code. -## 4. Create the Worker Deployment Version {/* #create-worker-deployment-version */} +## 5. Create the Worker Deployment Version {/* #create-worker-deployment-version */} Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) whose compute configuration points to the named AgentCore Runtime endpoint. The deployment name and Build ID must match @@ -259,12 +368,12 @@ values: - **Name**: the value of `TEMPORAL_DEPLOYMENT_NAME` in the Runtime environment. - **Build ID**: the value of `TEMPORAL_BUILD_ID` in the Runtime environment. - **Compute Provider**: select **Amazon Bedrock AgentCore Runtime**. -- **Runtime endpoint ARN**: the named endpoint ARN from [Step 2](#deploy-runtime). -- **IAM role ARN**: the invocation role ARN from [Step 3](#configure-iam). -- **External ID**: the External ID from [Step 3](#configure-iam). +- **Runtime endpoint ARN**: the named endpoint ARN from [Step 3](#deploy-runtime). +- **IAM role ARN**: the invocation role ARN from [Step 4](#configure-iam). +- **External ID**: the External ID from [Step 4](#configure-iam). Save the Worker Deployment. When you create a version through the UI, the version is automatically current. Continue -to [Step 6](#verify-worker-startup). +to [Step 7](#verify-worker-startup). @@ -298,7 +407,7 @@ For Temporal Cloud, check whether Temporal can reach the endpoint by opening the Temporal Cloud UI and selecting **Actions** > **Validate Connection**. This checks that Temporal can assume the invocation role, get the named endpoint, and invoke the Runtime. -## 5. Set the version as current {/* #set-current-version */} +## 6. Set the version as current {/* #set-current-version */} If you used the Temporal CLI, set the version as current: @@ -312,7 +421,7 @@ temporal worker deployment set-current-version \ This command asks you to confirm because it changes which version receives new Tasks. Pass `--yes` to skip the prompt. If you created the version in the Temporal Cloud UI, it is already current. -## 6. Verify Worker startup {/* #verify-worker-startup */} +## 7. Verify Worker startup {/* #verify-worker-startup */} Submit work to the configured Task Queue using your application. When no Worker is polling, Temporal invokes the named AgentCore Runtime endpoint. The Runtime starts the Worker, and the Worker polls and processes Tasks. From d3bd288aeea04495f2e4611c0c7e6ff248663697 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 10:54:11 -0700 Subject: [PATCH 69/77] Trim AgentCore Worker implementation note --- .../worker-deployments/serverless-workers/agentcore.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 2b8fa47254..e3c80b5b6b 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -237,7 +237,7 @@ async def invoke(payload: dict) -> dict: Replace `StrandsPlugin`, `StrandsAgentWorkflow`, and `execute_code` with the plugins, Workflows, and Activities used by -your application. If all Activities are asynchronous, you do not need the `ThreadPoolExecutor` or `activity_executor`. +your application. ## 3. Deploy the Worker Runtime {/* #deploy-runtime */} From b547b661f3372867255e12a1b201ea9a89988cd1 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 10:57:36 -0700 Subject: [PATCH 70/77] Clarify AgentCore endpoint version check --- .../serverless-workers/agentcore.mdx | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index e3c80b5b6b..69dabf37e8 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -266,8 +266,9 @@ AgentCore creates an immutable Runtime version when you create or update a Runti its configured version until you update it. For details, see [AgentCore Runtime versioning and endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-runtime-versioning.html). -Confirm that the endpoint's live version matches the Runtime version containing the Worker code and environment -configuration that you intend to deploy: +Check which Runtime version the named endpoint serves. Set `` to the identifier after `/runtime/` in the +Runtime ARN, `` to the key under `endpoints` in `agentcore.json`, and `` to the Region in +`aws-targets.json`: ```bash aws bedrock-agentcore-control get-agent-runtime-endpoint \ @@ -277,15 +278,29 @@ aws bedrock-agentcore-control get-agent-runtime-endpoint \ --region ``` +For the configuration in [Step 1](#configure-worker-runtime), the command must return `READY` and a `liveVersion` of +`1`: + +```json +{ + "status": "READY", + "liveVersion": "1" +} +``` + +The `liveVersion` must match the `version` configured for the named endpoint in `agentcore.json`. This confirms that +the endpoint ARN you give to Temporal invokes the expected Worker code and Runtime environment. + :::caution Verify the endpoint version after redeploying -If you redeploy the Runtime without updating its named endpoint, Temporal continues to invoke the earlier Worker code. -Creating the Worker Deployment Version can then time out if that code does not acknowledge the invocation promptly or -does not register the expected deployment name and Build ID. +If you redeploy the Runtime, AgentCore creates another immutable Runtime version. For example, the new version might be +`2` while the named endpoint still has `version: 1` in `agentcore.json`. Temporal then continues to invoke the Worker +code from version `1`. -For a later Worker version, create or update a named endpoint to use the new Runtime version. Use that endpoint ARN for -the corresponding Worker Deployment Version. Keep endpoints used by existing Worker Deployment Versions pinned to -their original Runtime versions. +For a later Worker version, create or update a named endpoint with the new Runtime version. Wait until its `status` is +`READY` and its `liveVersion` matches that version before using the endpoint ARN for the corresponding Worker +Deployment Version. Keep endpoints used by existing Worker Deployment Versions pinned to their original Runtime +versions. ::: From 4f8ea814757b1120aee6923594507378e4883940 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 11:14:30 -0700 Subject: [PATCH 71/77] Clarify AgentCore ARNs and update sample links --- .../workers/serverless-workers/agentcore.mdx | 4 +- docs/guides/durable-agent-on-agentcore.mdx | 36 +++++-------- .../serverless-workers/agentcore.mdx | 53 ++++++------------- snipsync.config.yaml | 2 - 4 files changed, 31 insertions(+), 64 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/agentcore.mdx b/docs/develop/python/workers/serverless-workers/agentcore.mdx index 48d533931b..368256c0f6 100644 --- a/docs/develop/python/workers/serverless-workers/agentcore.mdx +++ b/docs/develop/python/workers/serverless-workers/agentcore.mdx @@ -74,7 +74,7 @@ sample stores the background task in `_worker` and uses it to prevent another in Worker in the same Runtime session: -[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/agentcore_worker.py) +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/main/bedrock_agentcore/strands_agent/agentcore_worker.py) ```py async def run_worker() -> None: """Poll until idle, then drain.""" @@ -172,7 +172,7 @@ defines an `ActivityTracker`. It uses an [Activity inbound Interceptor](/develop running Activities. -[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/agentcore_worker.py) +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/main/bedrock_agentcore/strands_agent/agentcore_worker.py) ```py # How long the Worker keeps polling after it goes idle. DEBOUNCE = float(os.environ.get("AGENTCORE_DEBOUNCE_SECONDS", "60")) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index 5d6e5c9dcf..fcab663a88 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -94,13 +94,11 @@ through Updates. Any compatible Runtime session can process the next turn. ## 1. Get the sample -Clone the branch from the -[Strands Agent on Bedrock AgentCore sample PR](https://github.com/temporalio/samples-python/pull/360), then install its -Python dependencies: +Clone the [Python samples repository](https://github.com/temporalio/samples-python/tree/main/bedrock_agentcore/strands_agent), +then install the sample's Python dependencies: ```bash -git clone --branch schoeff/strands-agent --single-branch \ - https://github.com/temporalio/samples-python.git +git clone --depth 1 https://github.com/temporalio/samples-python.git cd samples-python/bedrock_agentcore/strands_agent uv sync ``` @@ -117,7 +115,7 @@ application and Runtime settings. The deployment script generates the AgentCore The sample creates a `TemporalAgent` with a system prompt and the `execute_code` tool: -[bedrock_agentcore/strands_agent/workflows.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/workflows.py) +[bedrock_agentcore/strands_agent/workflows.py](https://github.com/temporalio/samples-python/blob/main/bedrock_agentcore/strands_agent/workflows.py) ```py @workflow.defn class StrandsAgentWorkflow: @@ -156,7 +154,7 @@ network I/O, can fail independently, and are not deterministic. The `execute_code` Activity creates a Code Interpreter session using the Workflow ID as its session name: -[bedrock_agentcore/strands_agent/activities.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/activities.py) +[bedrock_agentcore/strands_agent/activities.py](https://github.com/temporalio/samples-python/blob/main/bedrock_agentcore/strands_agent/activities.py) ```py # Use AgentCore Code Interpreter to provide a code sandbox and execute LLM generated solution @activity.defn @@ -251,24 +249,18 @@ echo "$RUNTIME_ENDPOINT_ARN" Both commands must print an ARN before you continue. -AgentCore creates an immutable Runtime version when you deploy changed Worker code or configuration. The named -`temporal` endpoint remains on its configured version. When you redeploy the sample, increment -`endpoints.temporal.version` in `agentcore/agentcore.json` so the endpoint uses the new Runtime version. +:::important Runtime ARN and endpoint ARN are different -Verify the endpoint version before creating the Worker Deployment Version: +`AGENT_RUNTIME_ARN` ends with `/runtime/`. It identifies the Runtime resource. The IAM role in Step 4 uses +this ARN with a trailing wildcard to allow access to the Runtime and its endpoints. -```bash -aws bedrock-agentcore-control get-agent-runtime-endpoint \ - --agent-runtime-id "$AGENT_RUNTIME_ID" \ - --endpoint-name temporal \ - --query '{status:status,liveVersion:liveVersion}' \ - --region "$AWS_REGION" -``` +`RUNTIME_ENDPOINT_ARN` adds `/runtime-endpoint/temporal` to the Runtime ARN. It identifies the named endpoint that +routes invocations to its configured Runtime version. The Worker Deployment Version in Step 5 uses this ARN to tell +Temporal what to invoke. -If the endpoint remains on an earlier version, Temporal starts the old Worker code. Creating the Worker Deployment -Version can then time out if that code does not acknowledge the invocation promptly or does not register the expected -deployment name and Build ID. For details, see [AgentCore Runtime versioning and -endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-runtime-versioning.html). +Do not use `AGENT_RUNTIME_ARN` as the `--aws-agentcore-endpoint-arn` value. + +::: ## 4. Grant Temporal access to the Runtime diff --git a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx index 69dabf37e8..c67affd568 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/agentcore.mdx @@ -26,7 +26,7 @@ Workflow and Activity code and AgentCore project are already in place. For a tutorial that walks you through setting up an AgentCore project from scratch, see [Build a durable agent on Amazon Bedrock AgentCore](/guides/durable-agent-on-agentcore). That guide starts with the [Python Strands AgentCore -sample](https://github.com/temporalio/samples-python/tree/schoeff/strands-agent/bedrock_agentcore/strands_agent) and explains +sample](https://github.com/temporalio/samples-python/tree/main/bedrock_agentcore/strands_agent) and explains the agent architecture, Workflow and Activity boundaries, AgentCore project configuration, and deployment from start to finish. Use this page when you only need the Worker deployment procedure. @@ -83,8 +83,7 @@ named endpoint that Temporal invokes: } ``` -In this initial configuration, `version: 1` selects the first AgentCore Runtime version. Verify the named endpoint's -version after deployment in [Step 3](#deploy-runtime). +In this initial configuration, `version: 1` selects the first AgentCore Runtime version. Within the same Runtime object, add the Temporal connection, Task Queue, Worker Deployment name, and Build ID to the `envVars` array: @@ -168,7 +167,7 @@ file also contains the imports, creates the `BedrockAgentCoreApp`, retains the b [Start the Worker from the Runtime handler](/develop/python/workers/serverless-workers/agentcore#runtime-handler). -[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/schoeff/strands-agent/bedrock_agentcore/strands_agent/agentcore_worker.py) +[bedrock_agentcore/strands_agent/agentcore_worker.py](https://github.com/temporalio/samples-python/blob/main/bedrock_agentcore/strands_agent/agentcore_worker.py) ```py async def run_worker() -> None: """Poll until idle, then drain.""" @@ -259,48 +258,26 @@ agentcore status --runtime temporal_strands_worker --json agentcore status --type runtime-endpoint --json ``` -Record the Runtime ARN and the ARN of the named endpoint. You use the Runtime ARN to scope the invocation role and give -the endpoint ARN to Temporal. +Record the Runtime ARN and the ARN of the named endpoint. -AgentCore creates an immutable Runtime version when you create or update a Runtime. A named endpoint remains pinned to -its configured version until you update it. For details, see [AgentCore Runtime versioning and -endpoints](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agent-runtime-versioning.html). +:::important Runtime ARN and endpoint ARN are different -Check which Runtime version the named endpoint serves. Set `` to the identifier after `/runtime/` in the -Runtime ARN, `` to the key under `endpoints` in `agentcore.json`, and `` to the Region in -`aws-targets.json`: +The Runtime ARN ends with `/runtime/`. It identifies the Runtime resource. Use it with a trailing wildcard +to scope the IAM role that Temporal assumes: -```bash -aws bedrock-agentcore-control get-agent-runtime-endpoint \ - --agent-runtime-id \ - --endpoint-name \ - --query '{status:status,liveVersion:liveVersion}' \ - --region +```text +arn:aws:bedrock-agentcore:::runtime/ ``` -For the configuration in [Step 1](#configure-worker-runtime), the command must return `READY` and a `liveVersion` of -`1`: +The endpoint ARN adds `/runtime-endpoint/` to the Runtime ARN. It identifies the named endpoint that +routes invocations to its configured Runtime version. Give this ARN to Temporal when you create the Worker Deployment +Version: -```json -{ - "status": "READY", - "liveVersion": "1" -} +```text +arn:aws:bedrock-agentcore:::runtime//runtime-endpoint/ ``` -The `liveVersion` must match the `version` configured for the named endpoint in `agentcore.json`. This confirms that -the endpoint ARN you give to Temporal invokes the expected Worker code and Runtime environment. - -:::caution Verify the endpoint version after redeploying - -If you redeploy the Runtime, AgentCore creates another immutable Runtime version. For example, the new version might be -`2` while the named endpoint still has `version: 1` in `agentcore.json`. Temporal then continues to invoke the Worker -code from version `1`. - -For a later Worker version, create or update a named endpoint with the new Runtime version. Wait until its `status` is -`READY` and its `liveVersion` matches that version before using the endpoint ARN for the corresponding Worker -Deployment Version. Keep endpoints used by existing Worker Deployment Versions pinned to their original Runtime -versions. +Do not pass the Runtime ARN as the `--aws-agentcore-endpoint-arn` value. ::: diff --git a/snipsync.config.yaml b/snipsync.config.yaml index 7598622999..d18878e6c9 100644 --- a/snipsync.config.yaml +++ b/snipsync.config.yaml @@ -7,8 +7,6 @@ origins: repo: samples-typescript - owner: temporalio repo: samples-python - # Remove this ref after temporalio/samples-python#360 merges. - ref: schoeff/strands-agent - owner: temporalio repo: reference-app-orders-go - owner: temporalio From f089ef5501c3ab71512c08808c9bf43755646f83 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 11:45:25 -0700 Subject: [PATCH 72/77] Clarify AgentCore and Lambda tradeoffs --- .../serverless-workers-agentcore.mdx | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 57c5e44dda..69b4801211 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -65,15 +65,27 @@ Workflow progress and the compute provider runs replaceable Workers. | Consideration | AgentCore Runtime | AWS Lambda | | --- | --- | --- | | **Primary use** | Agent and tool workloads that use the [AgentCore platform](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html). | General-purpose, event-driven Worker workloads on AWS. | -| **Worker process** | A standard long-running Worker runs as background work in a Runtime session. | A Lambda Worker integration manages the Worker within each function invocation. | -| **Compute lifetime** | A Runtime session using the serverless microVM compute type can run for up to 8 hours. | A function invocation can run for up to [15 minutes](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). | +| **Worker process** | A standard long-running Worker runs as background work in a Runtime session. Your Runtime handler defines when the Worker stops polling and drains, subject to AgentCore lifecycle limits. | A Lambda Worker integration starts the Worker, monitors the invocation deadline, and shuts it down before the function ends. | +| **Compute lifetime** | A Runtime session using the serverless microVM compute type can run for up to 8 hours, giving one Worker process a longer window to process Tasks. | One function invocation can run for up to [15 minutes](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). A later invocation can continue processing Tasks for the same Workflow. | | **Process-local reuse** | The Worker can reuse in-memory caches and temporary files while its Runtime compute remains available. A later Task can run on another Worker, so do not depend on this state. | Each invocation is independent. Do not expect process-local state to be available to a later invocation. | -| **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability. | Lambda can call AWS services under its execution role, but it does not provide the AgentCore agent platform. | - -Use AgentCore Runtime when you are building on AgentCore services or when model and tool operations benefit from a -longer compute window. Use Lambda for a general-purpose Worker when each invocation can complete within its 15-minute -limit. Neither option changes where durable agent progress belongs: keep it in a Temporal Workflow, not in the Worker -process. +| **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability. Choose AgentCore when the application uses these services as part of its agent platform. | Lambda can call AWS services under its execution role. Choose Lambda when the Worker needs general AWS compute but not the AgentCore platform. | + +The 15-minute Lambda limit applies to one Worker invocation, not to the Workflow Execution. A Workflow can run for +days, months, or longer on either provider. Durable Timers, human approval waits, and waits for external events do not +require one Worker process to remain running. When another Task is ready after the compute has stopped, Temporal can +continue the Workflow on another Worker. + +The compute lifetime matters for work that must finish within one Worker process. On Lambda, an Activity attempt that +is still running when the invocation ends is interrupted and must retry on another Worker according to its Retry +Policy. Lambda is a good fit when individual Activity attempts finish comfortably within the invocation window or can +resume or retry without significant cost. Use [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) +for long-running Activities and make external side effects idempotent. + +Choose AgentCore Runtime when you use AgentCore services, want to run a standard long-running Worker, or benefit from +keeping one Worker process available longer for initialization, caches, or temporary files. Choose Lambda when you +want general-purpose AWS compute, do not need AgentCore services, and your uninterrupted Activity work fits the Lambda +invocation model. With either provider, keep durable agent progress in the Temporal Workflow and treat Worker-local +state as replaceable. ## Autoscaling {/* #autoscaling */} From 3af9723ec45ec8abebb3f788544bbaaf6064575d Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 11:50:05 -0700 Subject: [PATCH 73/77] Make AgentCore and Lambda comparison actionable --- .../serverless-workers-agentcore.mdx | 35 +++++-------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 69b4801211..4e4051bcf0 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -58,34 +58,17 @@ For an implementation of this architecture using Strands and AgentCore Code Inte ## Choose AgentCore Runtime or AWS Lambda {/* #choose-agentcore-or-lambda */} -AgentCore Runtime and AWS Lambda use the same event-driven autoscaling algorithm for Serverless Workers. Choose between -them based on the execution environment and AWS services that your Worker needs. With either provider, Temporal stores -Workflow progress and the compute provider runs replaceable Workers. +AgentCore Runtime and AWS Lambda use the same event-driven autoscaling algorithm and run replaceable Workers. With +either provider, a Workflow can continue for days, months, or longer across multiple Worker processes. Durable Timers, +human approval waits, and waits for external events do not require compute to remain running. Keep durable progress in +the Workflow and treat Worker-local state as replaceable. -| Consideration | AgentCore Runtime | AWS Lambda | +| Decision factor | Choose AgentCore Runtime if | Choose AWS Lambda if | | --- | --- | --- | -| **Primary use** | Agent and tool workloads that use the [AgentCore platform](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html). | General-purpose, event-driven Worker workloads on AWS. | -| **Worker process** | A standard long-running Worker runs as background work in a Runtime session. Your Runtime handler defines when the Worker stops polling and drains, subject to AgentCore lifecycle limits. | A Lambda Worker integration starts the Worker, monitors the invocation deadline, and shuts it down before the function ends. | -| **Compute lifetime** | A Runtime session using the serverless microVM compute type can run for up to 8 hours, giving one Worker process a longer window to process Tasks. | One function invocation can run for up to [15 minutes](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). A later invocation can continue processing Tasks for the same Workflow. | -| **Process-local reuse** | The Worker can reuse in-memory caches and temporary files while its Runtime compute remains available. A later Task can run on another Worker, so do not depend on this state. | Each invocation is independent. Do not expect process-local state to be available to a later invocation. | -| **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability. Choose AgentCore when the application uses these services as part of its agent platform. | Lambda can call AWS services under its execution role. Choose Lambda when the Worker needs general AWS compute but not the AgentCore platform. | - -The 15-minute Lambda limit applies to one Worker invocation, not to the Workflow Execution. A Workflow can run for -days, months, or longer on either provider. Durable Timers, human approval waits, and waits for external events do not -require one Worker process to remain running. When another Task is ready after the compute has stopped, Temporal can -continue the Workflow on another Worker. - -The compute lifetime matters for work that must finish within one Worker process. On Lambda, an Activity attempt that -is still running when the invocation ends is interrupted and must retry on another Worker according to its Retry -Policy. Lambda is a good fit when individual Activity attempts finish comfortably within the invocation window or can -resume or retry without significant cost. Use [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) -for long-running Activities and make external side effects idempotent. - -Choose AgentCore Runtime when you use AgentCore services, want to run a standard long-running Worker, or benefit from -keeping one Worker process available longer for initialization, caches, or temporary files. Choose Lambda when you -want general-purpose AWS compute, do not need AgentCore services, and your uninterrupted Activity work fits the Lambda -invocation model. With either provider, keep durable agent progress in the Temporal Workflow and treat Worker-local -state as replaceable. +| **AWS platform** | Your application uses [AgentCore](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html) services for identity, tool access, policy, memory, or observability. | Your Worker needs general-purpose AWS compute but does not use the AgentCore platform. | +| **Worker lifecycle** | You want to run a standard long-running Worker and define its idle and drain behavior in the Runtime handler. AgentCore lifecycle limits still apply. | You want the Lambda Worker integration to manage the Worker around each function invocation and its deadline. | +| **Uninterrupted Activity work** | An Activity attempt might need longer than Lambda's [15-minute invocation limit](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). An AgentCore Runtime session using serverless microVM compute can run for up to 8 hours. | Individual Activity attempts finish within the Lambda invocation window or can resume or retry without significant cost. The 15-minute limit does not limit the overall Workflow duration. | +| **Process-local reuse** | Reusing initialization work, in-memory caches, or temporary files while a Runtime session remains available reduces startup work or latency. A later Task can still run on another Worker, so correctness must not depend on this state. | The Worker does not need process-local reuse. Do not expect local state to be available to a later Lambda invocation. | ## Autoscaling {/* #autoscaling */} From 1afd38ee05219e1826618d3b1862ad8ef73c6ee9 Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 11:51:43 -0700 Subject: [PATCH 74/77] Link TemporalAgent implementation --- docs/guides/durable-agent-on-agentcore.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/guides/durable-agent-on-agentcore.mdx b/docs/guides/durable-agent-on-agentcore.mdx index fcab663a88..9a6e54619e 100644 --- a/docs/guides/durable-agent-on-agentcore.mdx +++ b/docs/guides/durable-agent-on-agentcore.mdx @@ -112,7 +112,9 @@ application and Runtime settings. The deployment script generates the AgentCore ## 2. Examine the agent Workflow -The sample creates a `TemporalAgent` with a system prompt and the `execute_code` tool: +The sample creates a +[`TemporalAgent`](https://github.com/temporalio/sdk-python/blob/main/temporalio/contrib/strands/_temporal_agent.py) with a +system prompt and the `execute_code` tool: [bedrock_agentcore/strands_agent/workflows.py](https://github.com/temporalio/samples-python/blob/main/bedrock_agentcore/strands_agent/workflows.py) From 707ab4aa2ee46711c5a1dfd0c081d035de6998ad Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 11:53:01 -0700 Subject: [PATCH 75/77] Restore provider comparison details --- .../serverless-workers-agentcore.mdx | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index 4e4051bcf0..ee8f470779 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -63,12 +63,22 @@ either provider, a Workflow can continue for days, months, or longer across mult human approval waits, and waits for external events do not require compute to remain running. Keep durable progress in the Workflow and treat Worker-local state as replaceable. -| Decision factor | Choose AgentCore Runtime if | Choose AWS Lambda if | +| Consideration | AgentCore Runtime | AWS Lambda | | --- | --- | --- | -| **AWS platform** | Your application uses [AgentCore](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html) services for identity, tool access, policy, memory, or observability. | Your Worker needs general-purpose AWS compute but does not use the AgentCore platform. | -| **Worker lifecycle** | You want to run a standard long-running Worker and define its idle and drain behavior in the Runtime handler. AgentCore lifecycle limits still apply. | You want the Lambda Worker integration to manage the Worker around each function invocation and its deadline. | -| **Uninterrupted Activity work** | An Activity attempt might need longer than Lambda's [15-minute invocation limit](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). An AgentCore Runtime session using serverless microVM compute can run for up to 8 hours. | Individual Activity attempts finish within the Lambda invocation window or can resume or retry without significant cost. The 15-minute limit does not limit the overall Workflow duration. | -| **Process-local reuse** | Reusing initialization work, in-memory caches, or temporary files while a Runtime session remains available reduces startup work or latency. A later Task can still run on another Worker, so correctness must not depend on this state. | The Worker does not need process-local reuse. Do not expect local state to be available to a later Lambda invocation. | +| **Primary use** | Agent and tool workloads that use the [AgentCore platform](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html). | General-purpose, event-driven Worker workloads on AWS. | +| **Worker process** | A standard long-running Worker runs as background work in a Runtime session. The Runtime handler defines its idle and drain behavior, subject to AgentCore lifecycle limits. | A Lambda Worker integration starts the Worker, monitors the invocation deadline, and shuts it down before the function ends. | +| **Compute lifetime** | A Runtime session using the serverless microVM compute type can run for up to 8 hours. | One function invocation can run for up to [15 minutes](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html). A later invocation can continue processing Tasks for the same Workflow. | +| **Process-local reuse** | The Worker can reuse initialization work, in-memory caches, and temporary files while its Runtime compute remains available. A later Task can run on another Worker, so do not depend on this state. | Each invocation is independent. Do not expect process-local state to be available to a later invocation. | +| **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability. | Lambda can call AWS services under its execution role, but it does not provide the AgentCore agent platform. | + +These differences lead to the following practical choices: + +| Choose AgentCore Runtime if | Choose AWS Lambda if | +| --- | --- | +| Your application uses AgentCore services for identity, tool access, policy, memory, or observability. | Your Worker needs general-purpose AWS compute but does not use the AgentCore platform. | +| You want to run a standard long-running Worker and define its idle and drain behavior. | You want the Lambda Worker integration to manage the Worker around each invocation and its deadline. | +| An Activity attempt might need longer than Lambda's 15-minute invocation limit. An AgentCore Runtime session can provide up to 8 hours for uninterrupted work. | Individual Activity attempts finish within the Lambda invocation window or can resume or retry without significant cost. The 15-minute limit does not limit the overall Workflow duration. | +| Reusing initialization work, in-memory caches, or temporary files reduces startup work or latency. | The Worker does not need process-local reuse. | ## Autoscaling {/* #autoscaling */} From fe36b5b12998083d353cf126f84c674cd77abfce Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 12:01:49 -0700 Subject: [PATCH 76/77] Clarify shared provider durability --- .../serverless-workers/serverless-workers-agentcore.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index ee8f470779..dbfd72428e 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -71,7 +71,9 @@ the Workflow and treat Worker-local state as replaceable. | **Process-local reuse** | The Worker can reuse initialization work, in-memory caches, and temporary files while its Runtime compute remains available. A later Task can run on another Worker, so do not depend on this state. | Each invocation is independent. Do not expect process-local state to be available to a later invocation. | | **Agent services** | AgentCore provides services for identity, tool access, policy, memory, and observability. | Lambda can call AWS services under its execution role, but it does not provide the AgentCore agent platform. | -These differences lead to the following practical choices: +Both compute providers can serve long-running Workflows because Temporal maintains Workflow state and execution +progress independently of any Worker process. Their differences affect which provider is a better fit for individual +Activity attempts, Worker lifecycle, process-local reuse, and AgentCore services: | Choose AgentCore Runtime if | Choose AWS Lambda if | | --- | --- | From 29fe6ffcf7f1a511527a9f13b4193524f82a672f Mon Sep 17 00:00:00 2001 From: "Lenny (Temporal)" Date: Wed, 16 Sep 2026 12:15:34 -0700 Subject: [PATCH 77/77] Document AgentCore in Serverless Workers evaluation --- .../serverless-workers-agentcore.mdx | 1 - .../features/serverless-workers/index.mdx | 74 ++++++++++--------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx index dbfd72428e..05aee3c5cc 100644 --- a/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx +++ b/docs/encyclopedia/workers/serverless-workers/serverless-workers-agentcore.mdx @@ -78,7 +78,6 @@ Activity attempts, Worker lifecycle, process-local reuse, and AgentCore services | Choose AgentCore Runtime if | Choose AWS Lambda if | | --- | --- | | Your application uses AgentCore services for identity, tool access, policy, memory, or observability. | Your Worker needs general-purpose AWS compute but does not use the AgentCore platform. | -| You want to run a standard long-running Worker and define its idle and drain behavior. | You want the Lambda Worker integration to manage the Worker around each invocation and its deadline. | | An Activity attempt might need longer than Lambda's 15-minute invocation limit. An AgentCore Runtime session can provide up to 8 hours for uninterrupted work. | Individual Activity attempts finish within the Lambda invocation window or can resume or retry without significant cost. The 15-minute limit does not limit the overall Workflow duration. | | Reusing initialization work, in-memory caches, or temporary files reduces startup work or latency. | The Worker does not need process-local reuse. | diff --git a/docs/evaluate/features/serverless-workers/index.mdx b/docs/evaluate/features/serverless-workers/index.mdx index 3f910cf390..fa7597c48f 100644 --- a/docs/evaluate/features/serverless-workers/index.mdx +++ b/docs/evaluate/features/serverless-workers/index.mdx @@ -13,21 +13,21 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - AWS Lambda support is in Public Preview. GCP Cloud Run support is in Pre-release, and its APIs may change in - backwards-incompatible ways. To request Cloud Run access, create a [support ticket](/cloud/support#support-ticket) or - contact your account team, and [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear - when Cloud Run reaches Public Preview. + AWS Lambda support is in Public Preview. Amazon Bedrock AgentCore Runtime and GCP Cloud Run support are in + Pre-release, and their APIs may change in backwards-incompatible ways. To request access, create a + [support ticket](/cloud/support#support-ticket) or contact your account team. You can also + [sign up for updates](https://temporal.io/pages/serverless-workers-updates). -Serverless Workers let you run Temporal Workers on serverless compute platforms like AWS Lambda and GCP Cloud Run. There -are no servers to provision, no clusters to scale, and no idle compute to pay for. Temporal starts Workers when Tasks -arrive and stops them when the work drains. +Serverless Workers let you run Temporal Workers on AWS Lambda, Amazon Bedrock AgentCore Runtime, and GCP Cloud Run. +There are no servers to provision, no Worker fleet to scale, and no idle Worker fleet to maintain. Temporal starts +Worker capacity when Tasks arrive and scales it down when the work drains. Serverless Workers use the same Temporal SDKs as traditional long-lived Workers. You register Workflows and Activities the same way. The difference is in the lifecycle: Temporal manages it instead of you running a Worker process. How that lifecycle works depends on the provider. On AWS Lambda, Temporal invokes a function per unit of work, and the Worker -exits when the invocation ends. On GCP Cloud Run, Temporal resizes a pool of long-lived instances, scaling it to zero -when there is no work. +exits when the invocation ends. On AgentCore Runtime, Temporal invokes Runtime sessions that host standard long-running +Workers. On GCP Cloud Run, Temporal resizes a pool of long-lived instances, scaling it to zero when there is no work. For a deeper look at how Serverless invocation works under the hood, see [Serverless Workers](/serverless-workers) in the encyclopedia. @@ -49,7 +49,7 @@ dedicated compute. Long-lived Workers require you to provision infrastructure, configure scaling policies, manage deployments, and monitor host-level health. Serverless Workers reduce this burden by offloading invocation and scaling to Temporal and the -compute provider. You still deploy the function and configure the compute provider, but there is no always-on +compute provider. You still deploy the Worker package and configure the compute provider, but there is no always-on infrastructure to manage and no autoscaling policies to tune. Worker management is one of the most common sources of support questions for Temporal users. Serverless Workers offer a @@ -61,9 +61,9 @@ of managing infrastructure. Running a long-lived Worker requires choosing a hosting strategy, configuring compute resources, and setting up deployment pipelines before you can execute your first Workflow in production. -With Serverless Workers, deploying a Worker is as simple as deploying a function. Package your Worker code, deploy it to -your serverless provider, and configure the connection to Temporal. There is no need to set up Kubernetes, manage -container orchestration, or design a scaling strategy. +With Serverless Workers, you package your Worker code, deploy it to your serverless provider, and configure the +connection to Temporal. There is no need to set up Kubernetes, manage container orchestration, or design a scaling +strategy. ### Scale automatically @@ -89,8 +89,8 @@ Serverless Workers are a good fit when: always-on compute. - **You want a simpler getting-started path.** Deploying a function is simpler than setting up a container orchestration platform. Serverless Workers reduce the steps between writing Worker code and running your first Workflow. -- **Your organization has standardized on serverless.** Teams that already run services on Lambda, Cloud Run, or similar - platforms can run Temporal Workers using the same deployment patterns and tooling. +- **Your organization has standardized on serverless.** Teams that already run services on Lambda, AgentCore Runtime, + Cloud Run, or similar platforms can run Temporal Workers using the same deployment patterns and tooling. - **You serve multiple tenants with infrequent workloads.** Platforms that run Workflows on behalf of many users or customers can avoid running dedicated Workers per tenant. @@ -98,28 +98,34 @@ Serverless Workers may not be ideal when: - **Activities are long-running and cannot be interrupted.** Some serverless platforms enforce execution time limits. For example, AWS Lambda has a 15-minute execution limit. Activities that run longer than the provider's timeout and - cannot be broken into smaller steps need a different hosting strategy or a provider with longer limits (such as Cloud - Run). Long-running Workflows are not affected because Workflows can span multiple invocations. + cannot be broken into smaller steps need a different hosting strategy or a provider with a longer compute lifetime. + AgentCore Runtime sessions can provide up to 8 hours of uninterrupted compute. Long-running Workflows are not + affected because Temporal maintains their state and execution progress across Worker processes. - **Workloads require sustained high throughput.** For consistently high-volume Task Queues, long-lived Workers on dedicated compute may be more cost-effective and performant. - **You need a persistent connection to Temporal.** Some features require the Worker to hold a connection open. On AWS - Lambda each invocation connects fresh, so those features do not apply. Cloud Run instances are long-lived and hold a - connection for as long as the instance runs. + Lambda each invocation connects fresh, so those features do not apply. AgentCore Runtime Workers and Cloud Run + instances hold a connection for the lifetime of their compute. ## How Serverless Workers compare to long-lived Workers | | Long-lived Worker | Serverless Worker | | -------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -| **Lifecycle** | Long-lived process that runs continuously. | Temporal starts and stops it: per invocation on AWS Lambda, by pool size on GCP Cloud Run. | +| **Lifecycle** | Long-lived process that runs continuously. | Temporal starts and stops it according to the compute provider's lifecycle. | | **Scaling** | You manage scaling (Kubernetes HPA, instance count, etc.). | Temporal adds capacity as needed, within the compute provider's limits. | -| **Connection** | Persistent connection to Temporal. | Fresh connection per invocation on AWS Lambda. Held for the instance's lifetime on GCP Cloud Run. | +| **Connection** | Persistent connection to Temporal. | Fresh per Lambda invocation. Held for the compute lifetime on AgentCore Runtime and Cloud Run. | ## Supported providers -| Provider | Compute | -| ------------- | --------------------------------------------------------------------------- | -| AWS Lambda | A function Temporal invokes per unit of work. | -| GCP Cloud Run | A Worker Pool of long-lived instances whose size Temporal scales. | +All three providers can serve long-running Workflows because Workflow lifetime is independent of Worker lifetime. The +provider's compute limit applies to an individual Worker invocation or compute instance, not to the total Workflow +duration. + +| Provider | Worker lifecycle | Consider this provider when | +| --- | --- | --- | +| [AWS Lambda](/serverless-workers/aws-lambda) | Temporal invokes a function per unit of work. Each invocation can run for up to 15 minutes. | You want general-purpose, event-driven AWS compute, and individual Activity attempts fit within the Lambda invocation window. | +| [Amazon Bedrock AgentCore Runtime](/serverless-workers/agentcore) | Temporal invokes Runtime sessions that host standard long-running Workers. Each session can provide up to 8 hours of uninterrupted compute. | You are building agents on AWS, want to use AgentCore services, need longer Activity attempts, or benefit from process-local reuse while the Runtime compute remains available. | +| [GCP Cloud Run](/serverless-workers/cloud-run) | Temporal adjusts the size of a Worker Pool of long-lived instances. | You want a managed pool of container-based Workers on Google Cloud. | ## Next steps @@ -131,12 +137,12 @@ Serverless Workers may not be ideal when: For the Worker code itself, pick your SDK and provider: -| SDK | AWS Lambda | GCP Cloud Run | -| --- | --- | --- | -| Go | [Lambda Workers in Go](/develop/go/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in Go](/develop/go/workers/serverless-workers/cloud-run) | -| Python | [Lambda Workers in Python](/develop/python/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in Python](/develop/python/workers/serverless-workers/cloud-run) | -| TypeScript | [Lambda Workers in TypeScript](/develop/typescript/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in TypeScript](/develop/typescript/workers/serverless-workers/cloud-run) | -| Java | [Lambda Workers in Java](/develop/java/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in Java](/develop/java/workers/serverless-workers/cloud-run) | -| .NET | [Lambda Workers in .NET](/develop/dotnet/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in .NET](/develop/dotnet/workers/serverless-workers/cloud-run) | -| Ruby | | [Cloud Run Workers in Ruby](/develop/ruby/workers/serverless-workers/cloud-run) | -| Rust | | [Cloud Run Workers in Rust](/develop/rust/workers/serverless-workers/cloud-run) | +| SDK | AWS Lambda | Amazon Bedrock AgentCore Runtime | GCP Cloud Run | +| --- | --- | --- | --- | +| Go | [Lambda Workers in Go](/develop/go/workers/serverless-workers/aws-lambda) | | [Cloud Run Workers in Go](/develop/go/workers/serverless-workers/cloud-run) | +| Python | [Lambda Workers in Python](/develop/python/workers/serverless-workers/aws-lambda) | [AgentCore Runtime Workers in Python](/develop/python/workers/serverless-workers/agentcore) | [Cloud Run Workers in Python](/develop/python/workers/serverless-workers/cloud-run) | +| TypeScript | [Lambda Workers in TypeScript](/develop/typescript/workers/serverless-workers/aws-lambda) | | [Cloud Run Workers in TypeScript](/develop/typescript/workers/serverless-workers/cloud-run) | +| Java | [Lambda Workers in Java](/develop/java/workers/serverless-workers/aws-lambda) | | [Cloud Run Workers in Java](/develop/java/workers/serverless-workers/cloud-run) | +| .NET | [Lambda Workers in .NET](/develop/dotnet/workers/serverless-workers/aws-lambda) | | [Cloud Run Workers in .NET](/develop/dotnet/workers/serverless-workers/cloud-run) | +| Ruby | | | [Cloud Run Workers in Ruby](/develop/ruby/workers/serverless-workers/cloud-run) | +| Rust | | | [Cloud Run Workers in Rust](/develop/rust/workers/serverless-workers/cloud-run) |