feat(workers): add Amazon Bedrock AgentCore as a compute provider - #3884
Merged
Merged
Conversation
Adds AgentCore to the serverless Worker forms, following the sequence Cloud Run used: the UI ships gated behind a capability the api protos do not carry yet, so OSS shows Coming Soon until a server advertises it, and cloud-ui can enable it earlier by mapping an account feature flag into its synthesized systemInfo capabilities. AgentCore is invoke-based in temporal-auto-scaled-workers, so it pairs with the no-sync scaler and takes the same assumed-role Access fields as Lambda. It differs in one payload key: `endpoint_arn` rather than `arn`. The value is the Runtime *Endpoint* ARN, since the provider parses the runtime id and endpoint name out of it and rejects a bare Runtime ARN. - Capability gate via `serverScaledProviderAgentCore`, declared as a local intersection on Capabilities until the proto field lands. - Resource field validates the four-part runtime-endpoint ARN shape. - The CloudFormation/Terraform role helper stays Lambda-only: it grants lambda:InvokeFunction and would hand out a role that cannot invoke a runtime. - buildComputeConfigFromForm replaces the per-page provider ternaries, so mapping a provider to a ComputeConfig is one branch rather than three. - Adds a feature-demo scenario recording what a reviewer checks and what the enabled path additionally requires from api and server.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…double version-compute-details.svelte calls it, and deployment.svelte.test.ts swaps the real deployments-service for the client test double, so the missing export surfaced as an unhandled rejection during that test rather than a failed assertion.
6 tasks
Editing a Version whose provider the Service does not advertise rendered that provider selected, disabled, and badged "Coming Soon" all at once, which says the Version is running on something unavailable. Capability gating exists to stop somebody choosing a provider the Service cannot run. A Version already running on one is proof it works, so gating must not describe it as unavailable. lockProvidersTo makes the provider in use visible and selectable, hides the rest because a Version's provider cannot be changed, and keeps the release stage, which stays true either way. Two causes, both fixed: The edit page never locked at all. lockComputeProvider was only wired to the create page, so editing fell through to the capability-gated default list. lockComputeProvider itself failed closed when the configured provider was disabled or hidden, which produced the same fallback on the create page. It now only declines when configuration does not know the provider at all. Not AgentCore-specific: Cloud Run hits this on OSS today, since no server advertises server_scaled_provider_cloud_run.
…ersion The previous commit ungated the provider a Version uses, but also hid every alternative on the reasoning that a Version's provider cannot be changed. It can: provider.type is an accepted update path on UpdateWorkerDeploymentVersionComputeConfig, so switching a Version to another provider is a real choice, and hiding them removed a capability the edit form had before. allowProviderInUse now ungates only the provider in use and leaves the alternatives exactly as configured, so one the Service can run stays offered and one it cannot stays refused. lockProvidersTo keeps the hiding behaviour and is used where the provider is inherited rather than chosen: creating a new Version in an existing Deployment.
…in Cloud Capability gating was the wrong mechanism, and it produced the visible nonsense: a provider selected, disabled, and badged "Coming Soon" at once. Self-hosted has no per-account entitlement to express, and a Service that cannot run a provider rejects the Version with a reason, so gating the picker only hid a choice behind a badge nobody could act on. The default list is now every provider, selectable. Restriction belongs to the caller that has grounds for it. cloud-ui already passes `providers` derived from the Namespace's own cloud, so an AWS Namespace offers Lambda and AgentCore and a GCP Namespace offers Cloud Run. That path is untouched: it always passes the prop, so it never used these defaults. A Version's provider cannot be changed, so the edit form shows only the provider in use rather than alternatives that cannot be applied. The previous commit had this backwards, reading an accepted update-mask path as product behaviour. This also removes the local serverScaledProviderAgentCore augmentation on Capabilities. Nothing gates on it now, so the UI no longer depends on a capability field that does not exist and that temporalio/api#867 no longer proposes.
* feat(demo): model the AgentCore serverless Worker as a runnable scenario Adds the scenario, plus three capabilities the demo tool needed to express it. requires.serverModules serverCommit cannot describe a feature that reaches the server through a dependency bump, because the commit lives in another repository. This checks the go.mod of the checkout being built. Pseudo-versions order by their embedded commit timestamp, and a tagged release satisfies a pseudo-version floor outright. requires.commands, and a preflight A missing tool is cheap to detect and expensive to hit halfway through a build, or worse after a provider has been handed an address. Stages imply their own tools, so the tunnel stage requires ngrok without the definition restating it, and a workspace build requires go and git. A tunnel stage A server-scaled Worker dials the frontend back to poll, and localhost is not reachable from a cloud provider. The outbound leg to the provider was never the problem. Scenarios read the address as context.publicAddress. Failures carry remedies. remedy.ts formats what was attempted, the tool's verbatim output, what to try, and where to look. ngrok error codes map to concrete fixes where we know them, and to their documentation URL where we do not: an invented remedy is worse than none. The scenario resolves its own CLI rather than trusting PATH. The --aws-agentcore-* flags arrived in 1.8.3, and a package-manager CLI is easily older than the repository pins; this machine had 1.8.2 on PATH against 1.8.3 in bin/cli, which would have failed on an unknown flag. It does not provision AWS. An AgentCore runtime bills while it exists, and starting a demo should not create billable cloud resources as a side effect, so it takes an endpoint ARN and the README covers provisioning. * fix(demo): derive the workspace Go directive, and repoint runtimes correctly Three problems the first real run of agentcore-serverless-worker exposed. The go.work directive was a literal `go 1.26.4`. Go refuses a workspace whose directive is below a member module's, and temporalio/cli has since moved to 1.26.5, so every source: 'workspace' scenario was one Go bump away from failing. It now follows the higher of the two checkouts. update-agent-runtime replaces a runtime rather than patching it, so sending only --environment-variables fails argument validation. The scenario now reads the current role, artifact, and network configuration and sends them back unchanged, instead of telling the reader to assemble the command by hand. 'tunnel' was missing from STAGES, so --skip tunnel and --only tunnel were rejected and the stage never appeared in a definition's stage list. Also fixes a preflight test helper that passed at runtime while failing to typecheck, which had hidden the STAGES errors from tsc. * fix(demo): make the tunnel prove its address before handing it out Children append to their log, and the tunnel's public address is read back out of that log, so a previous run's url satisfied the wait before this run's ngrok had written anything. The stage reported a plausible address, the scenario configured a provider with it, and the failure surfaced inside an AWS container as a connection refused, far from its cause. A stale address is syntactically perfect, so it read as success. Two fixes, because the second is the one that matters: - The log is removed before the child starts, so the address can only come from this run. - The address is proved with a TCP connect before it is returned. A tunnel that reports a url and carries no traffic is indistinguishable from a working one until something remote fails to dial it, and that covers more than this bug: a tunnel that never established reports a url too. Found by running the scenario twice, which its own preview notes call for. * feat(demo): optionally provision the AgentCore runtime The scenario can now create what it needs instead of refusing when no endpoint ARN is given. Off by default: an AgentCore runtime bills while it exists, and starting a demo should not create billable cloud resources by surprise. Provisioning is idempotent by name, so repeated runs reuse one runtime rather than adding another, and it checks that the calling identity can do every part before creating anything, so a missing permission does not leave an account half provisioned. When access is missing it names the policies to attach rather than passing the raw AccessDenied along. That includes the trap this cost us: the ECR managed policies are named AmazonEC2ContainerRegistry*, so searching the IAM console for "ecr" returns nothing useful, and the guidance says to search ContainerRegistry instead. It also offers the alternative of asking someone for an endpoint ARN rather than granting the permissions at all. Nothing is torn down at the end. A scenario's shutdown gets a three second grace, which is not enough to delete a runtime, and a reviewer wants the demo to still exist when the run finishes, so the summary lists what was created and the commands to remove it. Creating a runtime immediately after creating its execution role fails with an error that blames ECR permissions rather than IAM propagation, which sends the reader to the wrong place, so that call retries for a minute. The Worker image source ships with the scenario, including its own README on the two requirements that are easy to miss: AgentCore only accepts arm64, and a Worker with UseVersioning must give every workflow a VersioningBehavior or it panics before it polls. * feat(demo): apply unmet module requirements instead of reporting them requires.serverModules declared what the server needed and then handed the work back, telling a person to go and edit a checkout this tool had fetched into its own cache. The point of a requirement is that the tool satisfies it. A checkout this tool fetched now gets go get and go mod tidy run on it. A server ref would not solve this: the bump is a one-line go.mod change nobody has pushed to temporalio/temporal, and requiring a pushed branch to demo a feature is a heavier prerequisite than bumping a throwaway checkout. serverModules already names the exact version, so nothing else was needed. A checkout somebody pointed TEMPORAL_SERVER_REPO at is their working tree and is never modified. RepoSource carries whether the tool owns it, and the unowned case fails with advice to bump it there or to unset the variable. Two ways this could have gone quietly wrong. The bump changes checkout content, which the build cache is keyed on, so the key folds in the module requirements or a pre-bump binary is reused against a bumped go.mod. And go mod tidy can lower a requirement another module constrains, so it is re-verified rather than assumed. Verified with TEMPORAL_SERVER_REPO unset: the tool fetched temporalio/temporal at main (0405f547a), bumped auto-scaled-workers, built, and ran through to a workflow completing on the AgentCore-hosted Worker. * feat(demo): let a scenario refuse before anything expensive runs Running the AgentCore scenario cold with nothing configured reported the missing endpoint ARN from the scenarios stage, which is after fetching two repositories, bumping a module, and compiling a server. A person waited five minutes to be told something a string comparison knew at once. Scenario gains an optional preflight, called before any stage. The AgentCore scenario uses it for both of its prerequisites: that it has somewhere to point, and, when provisioning, that the AWS identity can do every part. Neither needs a running server, so neither should cost a build. Cold with nothing set now fails in about two seconds. AGENTCORE_PROVISION=1 opts in for a single run, so a reviewer does not edit a tracked file and have to remember to revert it. The source resolution is shared between preflight and run so they cannot disagree about what the scenario needs. Verified from nothing: no AWS resources, no .feature-demo, no environment. The run fetched both repositories, bumped auto-scaled-workers, built the server, opened a tunnel, created the ECR repository, built and pushed the arm64 Worker image, created the execution role, created the runtime, and ran a workflow to completion on the Worker inside AgentCore. The IAM propagation retry fired, so it was not defensive. * fix(demo): refuse before provisioning, and default provisioning on Three things a fresh run exposed. Provisioning is on by default for this scenario. It cannot run without a runtime, and a demo whose first run fails is not a demo. The option remains, AGENTCORE_PROVISION=1 turns it on for a single run, and an explicit endpoint ARN still wins. The tunnel guard moved above provisioning. Running with --only scenarios created an ECR repository, an IAM role, and an AgentCore runtime, and then refused because the tunnel stage had not run. Nothing billable should be created for a run that cannot finish. Preflight now checks that the runtime an endpoint ARN names actually exists. An ARN is a string, so having one proves nothing about whether it resolves: a stale one from a previous run looks entirely valid, silently shadows provisioning because an explicit ARN takes precedence, and previously failed only after a server build and a tunnel. It now fails in about two seconds and says to unset AGENTCORE_ENDPOINT_ARN. * fix(demo): create the AgentCore runtime with its environment already set create-agent-runtime returns as soon as the request is accepted, and the service rejects updates and invokes until the runtime leaves CREATING. The scenario then immediately pointed the new runtime at the tunnel and got a ConflictException. Whether that happened depended on how fast the rest of the run was, so an earlier cold run passed on timing luck. The tunnel is already open when provisioning runs, so the address goes in at creation instead. That removes the racing update rather than timing around it, and saves waiting for a second rollout. A reused runtime carries whatever a previous run left on it, so that path still updates, and provisioning now waits for READY either way. An update that loses a race anyway reports the runtime as busy and says to run again, rather than listing permissions that are not the problem. * fix(demo): build the embedded frontend assets before the ui-server The ui-server embeds the built frontend with //go:embed all:assets, and a Go embed of a missing directory is a compile error, not an empty filesystem. A worktree that has never built them cannot build the binary at all: ui/embed.go:8:12: pattern all:assets: no matching files found The stage now runs pnpm build:server, which writes them to server/ui/assets, when that directory is absent. Any fresh worktree hit this, so it belongs in the stage rather than in setup instructions. Both failures also explain themselves now instead of forwarding a compiler error whose text does not mention the frontend. * fix(demo): apply the runtime environment through update, not create create-agent-runtime accepts --environment-variables and then ignores it. The runtime comes back with environmentVariables null, and the Worker starts with an empty TEMPORAL_ADDRESS and task queue: WORKER starting addr= ns=default tq= deployment=agentcore-demo So provisioning a runtime from scratch produced a Worker that could not dial anything, which is worse than the ConflictException it was meant to avoid. The previous commit conflated two changes. Waiting for READY is what fixes the race; moving the environment into create was an unnecessary optimisation on top, and it does not work. Only the wait is kept, and the caller now always applies the environment through update, which is the path that has been exercised repeatedly. This survived because every run after that change reused an existing runtime and took the update path. The create path was not exercised until a teardown forced a fresh provision.
rossnelson
marked this pull request as ready for review
September 9, 2026 23:12
The scenario shelled out to `temporal worker deployment create-version`, which proves the server accepts an aws-agentcore compute config. That was never in question: the CLI could do this before any of this work existed. What is under review is the UI, and a run that never opened the form said nothing about it. The Version is now created by driving the real create-version form with Playwright: select Amazon Bedrock AgentCore, fill the Agent Runtime Endpoint ARN and the Access fields, submit. `createVersion: 'cli'` keeps the old path for a machine with no browser, and `headed: true` shows the browser doing it. Screenshots land per step, so a failure leaves a picture of where it stopped. Preflight launches a browser before any stage starts, because Playwright downloads its browsers separately from the package and finding that out after a server build costs minutes. The run also records what it had to type to get there. The form requires IAM Role ARN and External ID; this server sets require_role_and_external_id false and discards both. The UI has no equivalent of the CLI's --aws-agentcore-skip-role-and-external-id, so a self-hosted operator who turned the requirement off can create a Version by CLI but not by form. FE-675 tracks that. Adds `uiUrl` to the scenario context, set to the UI the ui stage started so a scenario drives the checkout's UI rather than the server's bundled one.
Proving the UI can create an AgentCore Version took more than pointing a browser at the form. The Access fields are not decorative. Setting require_role_and_external_id to false makes the role optional, not ignored: the server assumes whatever role the compute config carries. The CLI can omit it with --aws-agentcore-skip-role-and-external-id; the form requires both fields and always sends them, so a placeholder does not get discarded, it fails at sts:AssumeRole after the form has done its job. The scenario now provisions TemporalDemoAgentCoreInvoke, trusting this account under an sts:ExternalId condition and granting bedrock-agentcore:InvokeAgentRuntime, and waits for it to actually assume before going on, because IAM is eventually consistent and the server tries seconds later. The earlier comments claiming the server discards these fields were wrong and are corrected here. Each run also gets its own deployment. Versions from earlier runs go INACTIVE, the server stops reporting their ComputeConfig (FE-672), and lockComputeProvider cannot name a provider it cannot see, so the create-version page renders an error where the form should be. Those Versions cannot be deleted either: AgentCore sessions from earlier runs keep polling, and the server refuses to delete a Version with active pollers. The driver itself had three faults, all found by running it. locator count() does not wait, and the page renders the form only after it fetches the deployment, so it looked before the form existed. The page keeps hidden [role=alert] containers and a closed confirm modal whose button is also a form submit, so first() waited on elements never shown. And fullPage screenshots evaluate in the page, which trips over the __name wrappers esno leaves behind. Verified end to end against Bedrock AgentCore in us-west-2: the form created the Version, the Worker Controller invoked the runtime, the Worker dialed back through the tunnel and registered agentcore-tq, and Greet returned "hello demo from AgentCore worker on localhost".
This repository is public. The demo notes named an internal repository and described how hosted Temporal maps an account entitlement into the capabilities it synthesizes, and several comments cited internal tracker ids that mean nothing to anyone reading this here. The observations they supported are worth keeping, so they are restated without the pointers. Also corrects a note that this branch had already made false: the compute-provider scenario still said AgentCore must render disabled and badged "Coming Soon" on a self-hosted server. Self-hosted now offers every provider, and a reviewer following that note would have reported a bug against correct behaviour.
The scenario listed the fields AgentCore renders but never sent a reviewer to the two stories that show the actual behaviour change: every provider selectable on a self-hosted server, and a Version locked to the provider it already uses. Those are the cases worth a human looking at. The first is where a self-hosted server previously gated providers on capabilities it never advertised, which left Cloud Run permanently unselectable. The second is where a card used to render selected and disabled at once.
The Access section required an IAM role and offered no way to create one for AgentCore. Its CloudFormation and Terraform helpers grant lambda:InvokeFunction, so sharing them would hand out a role that cannot invoke a runtime, and the helper was hidden rather than reused. Adds the AgentCore equivalents and follows the selected provider: - temporal-agentcore-role.yaml grants bedrock-agentcore:InvokeAgentRuntime and GetAgentRuntimeEndpoint. Validation calls GetAgentRuntimeEndpoint first, so a role without it fails when the Version is created rather than when a Worker is wanted. - serverless-worker-agentcore.tf points at the aws/agentcore module and takes agent_runtime_arns, the same four-part Endpoint ARN the Version takes. - The Launch Stack link, the download filename, and the module link now follow the provider rather than always naming Lambda. The trust policy is the part that differs by deployment. Cloud assumes the role as a service principal, so it names temporal.io. A self-hosted server assumes it as whatever IAM identity it runs as, which is an AWS principal rather than a service and so a different key entirely. The template takes a TemporalPrincipal parameter and switches on it, since this PR makes the provider selectable outside Cloud for the first time. The policy is the one proven by the demo scenario, which provisions the same permissions and trust shape and only works because the role really assumes. Note the aws/agentcore Terraform module does not exist in temporalio/terraform-modules yet. The snippet names where it will live, as the Lambda and Cloud Run snippets do for theirs.
Alex-Tideman
approved these changes
Sep 10, 2026
The card drew a square border while everything around it — buttons, accordions, inputs — is rounded, so the compute provider picker read as unfinished next to the rest of the form. The optional panel beneath a selected card shares its bottom edge, so the card drops its bottom corners when that panel is showing and the panel takes them instead. No consumer passes that snippet today, but leaving it unhandled would have put the sharp corner back the moment one did.
Two things in the provider picker's logo tile. The marks lost their colour. Before the icon registry moved to Io, the picker rendered holocene's aws.svelte, which carried fill="#FF9900". The refactor remapped it to IconAws, the monochrome glyph, so the AWS and GCP logos have rendered flat white on dark since 20 Aug. IconAwsColor and IconGcpColor already existed and were used nowhere outside a Badge story. These are vendor logos rather than UI icons, so they should keep their own colour on either theme. The tile was also explicitly rounded-none, predating the Io work, which left a square inside a form where everything else is rounded.
justinschoeff
approved these changes
Sep 11, 2026
The provider allowlist inverted. `workercontroller.compute_providers.enabled` used to mean "restrict to these", and an unset value allowed everything; in the auto-scaled-workers release main now pins it means "only these", and an unset value enables nothing at all. The scenario never set it, because it never had to. The server now reports that it could not instantiate the provider, which reads like the build is missing it — the provider is there and switched off, and the metric behind that branch says so where the message does not. Worth knowing beyond this scenario: the same upgrade silently disables Lambda and Cloud Run for any self-hosted operator who has not set the list. Dynamic config values may now be string arrays. The flag already passes JSON, so only the schema stood in the way.
The last place still rendering the monochrome glyphs. Same cause as the provider picker: the icon registry move mapped these to IconAws and IconGcp, so the badge has drawn a flat white AWS smile since August. These identify a vendor rather than convey UI state, so currentColor is the wrong default for them.
The stage badge sits beside a provider name at text-sm, and at the default size its mono uppercase label read heavier than the name it qualifies. #3908 added a size variant, so take it rather than override the padding locally. The disabled-reason badge occupies the same slot and only ever renders instead of this one, so it takes the same size.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description & motivation 💭
Adds Amazon Bedrock AgentCore as a compute provider in the serverless Worker forms.
The provider itself is already merged upstream — temporal-auto-scaled-workers#117 / #118 added it, and cli#1177 shipped the
--aws-agentcore-*flags in v1.8.3. This is the UI catching up.AgentCore is invoke-based in temporal-auto-scaled-workers, so it pairs with the
no-syncscaler and takes the same assumed-role Access fields as Lambda. It differs from Lambda in exactly one payload key:endpoint_arnrather thanarn.Who decides which providers are offered
Self-hosted offers all of them, selectable. There is no per-account entitlement to express, and a Service that cannot run a provider rejects the Version with a reason — so gating the picker would only hide a choice behind a badge nobody can act on.
Restriction belongs to whichever caller has grounds for it, passed in as
providers. Temporal Cloud already does this: it derives the list from the Namespace's own cloud, so an AWS Namespace offers Lambda and AgentCore while a GCP Namespace offers Cloud Run. That path is untouched here — Cloud always passes the prop, so it never used these defaults.serverScaledProviderCloudRunand rendered "Coming Soon" on self-hosted. Since no server has ever set that capability, Cloud Run has been permanently unselectable there. It is now selectable, and a Service that cannot run it says so on create.That also let the local
Capabilitiesaugmentation go: nothing gates on a provider capability any more, so the UI no longer depends on a field that does not exist, and does not need the one temporalio/api#867 replaced it with.Three judgment calls worth a look
1. The field is labeled "Agent Runtime Endpoint ARN", not "Agent Runtime ARN".
The provider parses the runtime id and endpoint name out of the ARN and requires the four-part resource
runtime/<id>/runtime-endpoint/<name>— seeparseAgentCoreEndpointARNin temporal-auto-scaled-workers. A bare Runtime ARN fails validation server-side, so the design mock's label would have sent people down a dead end. The schema validates that shape up front, and it is checked against an ARN AWS actually generated.2. The CloudFormation / Terraform role helper stays Lambda-only.
Both templates grant
lambda:InvokeFunction. Reusing them would hand out a role that cannot invoke an AgentCore runtime. AgentCore gets the IAM Role ARN and External ID fields with no helper accordion.3.
buildComputeConfigFromFormreplaces the per-page provider ternaries.The three create/edit pages each carried their own
data.provider === 'cloud-run' ? gcp : lambda, which a third provider would have turned into three three-way branches. Mapping a provider onto aComputeConfigis now one function inshared.ts.Also fixed here: the Version edit form
A Version's provider cannot be changed, so the edit form now shows only the provider in use. Previously it fell through to the shared default list, which — combined with the old capability gating — rendered the provider a Version was actively running on as selected, disabled, and badged "Coming Soon" at the same time.
lockComputeProvideralso failed closed when the configured provider was disabled or hidden, producing the same fallback on the create page. It now declines only when configuration does not know the provider at all.Neither bug was AgentCore-specific: editing a Cloud Run Version on self-hosted hit both.
Screenshots (if applicable) 📸
Storybook covers the picker with no server: Workers/Compute Provider Picker → "Self-hosted (every provider selectable)" and "Locked to the provider a Version uses".
Design Considerations 🎨
https://console.aws.amazon.com/bedrock-agentcore. Someone with console access should confirm that path.Testing 🧪
How was this tested 👻
Manual testing
E2E tests added
Unit tests added
svelte-check: 0 errors across 885 filespnpm lint: 0 errorsFull unit suite under
TZ=UTC(what CI uses): 3261 passing, 2 skipped, no unhandled errorsDriven end to end against a real Bedrock AgentCore runtime in
us-west-2, not just unit-tested — and the Version was created through this form, not by the CLI:Nothing polled from the machine running it, so only a Worker AWS started could have run that workflow.
New coverage:
deployments-service.test.ts— AgentCore config writesendpoint_arn(notarn), pairs withno-sync, round-trips through its decoder, and the Lambda/AgentCore decoders do not cross provider types.shared.test.ts— endpoint ARN required, a bare Runtime ARN rejected, role and external id required as with Lambda.compute-fields.test.ts— renders the endpoint ARN field not the Lambda one, reuses the Access fields, hides the Lambda IAM helper, and offers invoke-based scaling rather than replica controls.lock-compute-provider.test.ts— 23 tests, up from 15: locks to AgentCore when a Version uses it, and keeps a configured provider selectable where gating would previously have disabled or hidden it.One thing worth calling out, since it cost a CI round:
version-compute-details.sveltecallsdecodeAgentCoreProviderDetails, anddeployment.svelte.test.tsswaps the realdeployments-servicefordeployments-service-client-test-double.ts. The missing export there surfaced as an unhandled rejection rather than a failed assertion — every test still reported passing while the job exited 1. If you add an export a component consumes, the test double needs it too.Steps for others to test: 🚶🏽♂️🚶🏽♀️
Storybook needs nothing. For the real thing, this branch carries a one-command scenario (#3892, merged into this branch):
It provisions the AgentCore runtime, opens a tunnel so the Worker can dial the frontend back, drives this form with Playwright to create the Version, then waits for the Worker to register and runs a workflow on it. It needs AWS credentials that can reach
bedrock-agentcore, ECR and IAM; it names the exact policies if any are missing, and prints teardown commands for everything it creates.The form is the point. The CLI could already create an AgentCore Version before this PR existed, so a scenario that shelled out to
create-versionwould prove nothing about the change under review.createVersion: 'cli'falls back for a machine with no browser, andheaded: trueshows the browser doing it.Two things the run surfaced that are worth knowing while reviewing:
require_role_and_external_id: falsemakes the IAM role optional, not ignored — the server assumes whatever role the config carries. The CLI can omit it with--aws-agentcore-skip-role-and-external-id; this form requires both fields and always sends them, so it needs a role that genuinely assumes. The scenario provisions one. That leaves a real gap, tracked separately: a self-hosted operator who turned the requirement off can create a Version by CLI and cannot by form.ComputeConfig,lockComputeProvidercannot name a provider it cannot see, and this page renders an error where the form should be. That behaviour is unchanged frommainand affects Lambda and Cloud Run identically — it is not introduced here — but it is easy to hit twice in a row.Checklists
Draft Checklist
Companions:
Merge Checklist
Issue(s) closed
Docs
Any docs updates needed?
Serverless worker docs will need an AgentCore section, including that the Resource field takes the Runtime Endpoint ARN.
Not in this PR
auto-scaled-workersdependency contains312f95f(2026-08-24), which registers theaws-agentcoreprovider.temporalio/temporalmain still pinsv0.0.0-20260811170210. The scenario on this branch bumps a fetched checkout itself, which is the only reason the end-to-end run above was possible.defaultReleaseStagetable inshared.tsgo away. Not a dependency of this PR.ComputeConfigfrom inactive Version summaries, so superseded Versions show no compute provider, and a deployment whose Versions have all gone inactive cannot be added to through this form. Server-side, unchanged frommain, and affects Lambda and Cloud Run too. Tracked separately.