Skip to content

feat: add China (aws-cn) region support with feature gates - #2426

Merged
nborges-aws merged 9 commits into
refactorfrom
cn-region-support-refactor
Sep 30, 2026
Merged

nborges-aws merged 9 commits into
refactorfrom
cn-region-support-refactor

Conversation

@shawnxli

Copy link
Copy Markdown

feat: China (aws-cn) region support — region enum + feature gates

Base branch: refactor · 2 commits

Amazon Bedrock AgentCore is live in cn-north-1 (BJS) and cn-northwest-1 (ZHY), but the CLI
rejects both regions at config-validation time and several features cannot work in that
partition. This PR adds the regions and gates the unavailable features with explicit regional
errors instead of downstream failures.

Commit 1 — add China regions to the supported region enum

  • cn-north-1, cn-northwest-1 in AgentCoreRegionSchema (per the enum's source-of-truth
    comment, matching the AgentCore regions documentation), following the AGENTS.md
    §Multi-Partition checklist.
  • Without this, CN targets fail aws-targets.json validation and detectRegion() silently
    falls back to us-east-1 for users whose environment region is CN.

Commit 2 — gate features unavailable in aws-cn

In China regions, Amazon Bedrock is not launched and Anthropic/OpenAI/Gemini are not reachable;
no telemetry collector exists there either.

Runtime templates — FsProjectManager.addResource rejects framework template scaffolds
wired to Bedrock/Anthropic/OpenAI/Gemini with a RegionUnsupportedFeatureError when any
deployment target is cn-* (one chokepoint covers the flag handler and the TUI wizard).
Provider-free scaffolds (agent-python-minimal, mcp-python-fastmcp) remain available as the
bring-your-own-implementation path.

LiteLLM + new --model-id flag — LiteLLM can route to providers reachable from China, so
--model-provider litellm stays allowed there, but requires an explicit --model-id: the
template default routes to Bedrock. --model-id is implemented as a generic optional override
threaded into the template render context; every provider's commercial default model id is
unchanged (rendered output is byte-identical without the flag).

Bedrock Agent import — add runtime --type import fails fast with a regional message
before any Bedrock call.

Telemetry — unconditionally disabled in a China context, regardless of config or endpoint
overrides, to comply with restrictions on sending telemetry out of the region. "China context"
= ambient AWS_REGION/AWS_DEFAULT_REGION is cn-* OR the enclosing project declares a
cn-* deployment target in aws-targets.json (best-effort read; telemetry never affects CLI
behavior). The local audit-file sink is unaffected. The global-config default also flips to
disabled under a China ambient region.

Docs — README gains a "China (aws-cn) regions" section; command.md regenerated.

Known gaps / follow-ups (out of scope here)

  • agentcore create scaffolds before any deployment target exists, so the template guards fire
    at add runtime/TUI where targets are known (same behavior as an ambient-region check would
    not reliably fix; documented in the README section).
  • TUI wizard has no model-provider/model-id steps; in CN it surfaces the gate error and the flag
    path is the workaround.
  • Pre-existing on refactor (not introduced here, flagging for awareness): hardcoded arn:aws:
    partition strings in the harness/ab-test/evaluation IAM role generators
    (src/core/executionRole.tsx, src/core/abTestExecutionRole.tsx, src/core/eval.tsx) will
    produce non-matching ARNs in aws-cn; main had a partition helper layer that did not carry
    over. Happy to file a separate issue with the inventory.
  • The @aws/agentcore-cdk package pinned by the vended CDK app needs the same two-region enum
    addition on its release line (deploys gate at cdk synth on the constructs' own enum copy —
    same mechanism as the eu-south-1/2 launch).

Testing

  • bun test: 3594/3594 across 243 files (includes new tests: CN gate matrix — blocked
    providers, minimal/fastmcp allowed, LiteLLM with/without --model-id; isChinaContext env +
    targets-file detection; telemetry suppression in a CN env with telemetry enabled while the
    audit sink still writes; commercial regression unchanged).
  • tsc --noEmit, oxlint, prettier: clean.

@github-actions github-actions Bot added the size/l PR size: L label Sep 28, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added agentcore-harness-reviewing AgentCore Harness review in progress claude-security-reviewing Claude Code /security-review in progress labels Sep 28, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 28, 2026

@agentcore-devx-automation agentcore-devx-automation Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AgentCore Harness Review

Verdict: Looks good

Nice, self-contained aws-cn support. The two-layer defense for telemetry (default flipped in accessor.tsx, plus an unconditional runtime guard in client.tsx that catches an explicit telemetry.enabled: true in a China context) is a good choice, and the gating for model-provider templates fires before any scaffolding or dependency check — the tests confirm that checkedTools stays empty and the runtime directory isn't created. Coverage in partition.test.ts, manager.test.ts, and client.test.tsx uses real temp directories and env-var toggling rather than mocks — well within the project's testing guidance.

A few things I looked at that are fine as-is but worth calling out for future reference:

  • agentcore create intentionally scaffolds before targets exist, so a user in a cn-* shell running agentcore create --template agent-python-strands still gets a Bedrock-wired scaffold; the mitigation ("add runtime is where the gate fires") is documented in the README and in the manager comment.
  • The LiteLLM CN gate only checks that a modelId was supplied, not that it routes to a CN-reachable provider — also called out in the error message and README.
  • isChinaContext() walks up from process.cwd() and short-circuits on env vars, so telemetry stays off even when invoked from outside a project as long as AWS_REGION/AWS_DEFAULT_REGION is cn-*.

No changes required from me.

@agentcore-devx-automation agentcore-devx-automation Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Sep 28, 2026
@codecov-commenter

codecov-commenter commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.29%. Comparing base (17ed420) to head (a1fb82e).
⚠️ Report is 11 commits behind head on refactor.

Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #2426      +/-   ##
============================================
+ Coverage     97.24%   97.29%   +0.04%     
============================================
  Files           609      611       +2     
  Lines         42923    43154     +231     
============================================
+ Hits          41742    41987     +245     
+ Misses         1181     1167      -14     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added size/l PR size: L and removed size/l PR size: L labels Sep 28, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 28, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 28, 2026
@shawnxli shawnxli changed the title feat: China (aws-cn) region support — region enum + feature gates feat: add China (aws-cn) region support with feature gates Sep 28, 2026
@github-actions github-actions Bot added size/l PR size: L and removed size/l PR size: L labels Sep 28, 2026
Comment thread src/core/partition.ts
Comment thread src/core/project/manager.tsx Outdated
Comment thread src/globalConfig/accessor.tsx Outdated
Comment thread src/handlers/project/add/runtime/index.ts
Add cn-north-1 and cn-northwest-1 to AgentCoreRegionSchema and its
region test. Without this, aws-cn deployment targets fail
aws-targets.json validation, blocking every command that resolves a
target in China regions.
In aws-cn, Amazon Bedrock is not launched and Anthropic/OpenAI/Gemini are
not reachable, and no telemetry collector exists there. Gate the affected
features with clear regional behavior instead of letting them fail
downstream:

- Runtime templates: FsProjectManager.addResource rejects framework
  templates wired to Bedrock/Anthropic/OpenAI/Gemini with
  RegionUnsupportedFeatureError before scaffolding when any deployment
  target is in a China region (covers the flag handler and the TUI
  wizard). Provider-free scaffolds (agent-python-minimal,
  mcp-python-fastmcp) stay available as the bring-your-own-implementation
  path.
- LiteLLM stays available in China as the routable-provider escape hatch,
  but requires an explicit model id there: its default model id routes to
  Bedrock. New --model-id flag on 'add runtime' threads into the template
  render context (generic optional override; per-provider defaults are
  unchanged commercially).
- Bedrock Agent import (--type import): the add-runtime handler fails
  fast before any Bedrock call.
- Telemetry: unconditionally disabled in a China context — ambient AWS
  region env vars OR any cn-* deployment target in aws-targets.json —
  regardless of config or endpoint overrides; the local audit-file sink
  is unaffected. The global-config default also flips to disabled under a
  China ambient region.
- Add isChinaRegion()/isChinaContext() partition helpers and
  RegionUnsupportedFeatureError; document the China behavior in README.

Known gap (as on main): project create scaffolds before targets exist,
so the guards fire at add runtime where targets are known.
The for(;;) loop only exited via return, leaving its closing brace
unexecutable and flagged by coverage. Same behavior, now a bounded
while walk followed by a straight-line targets read.
- Telemetry now resolves the region through the same chain the CLI uses
  (--region flag from argv, env vars, shared AWS config profile) before
  the China gate, instead of env vars only; resolveRegion moves from the
  withRegion middleware into src/core/region.ts and is shared.
- A first run in a China environment persists telemetry disabled, so a
  later run in a commercial region cannot start exporting without the
  first-run notice ever having been shown; an explicit pre-existing
  telemetry.enabled is never clobbered.
- create accepts --model-id and applies the China provider gate when the
  command's resolved region is a China region, so the common
  create-then-deploy workflow fails before scaffolding; the default
  (harness) project is rejected there too.
- Scaffolds persist the wired modelProvider on the runtime entry in
  agentcore.json (optional field, ignored by the CDK app and older
  CLIs), and deploy to a China target hard-fails when any runtime
  carries a Bedrock/Anthropic/OpenAI/Gemini provider, with remediation;
  unclassifiable runtimes (no field) get an informational note; harness
  projects are rejected. The ModelProvider enum moves to
  projectSchemas/runtime.ts (re-exported) so the schema layer owns it.
- --model-provider help text now lists LiteLLM; command.md regenerated.
- isChinaRegion resolves the partition via @aws-sdk/util-endpoints
  partition data instead of a cn- name-prefix guess.
@shawnxli
shawnxli force-pushed the cn-region-support-refactor branch from c140551 to a8eb63c Compare September 29, 2026 13:45
@github-actions github-actions Bot added size/xl PR size: XL and removed size/l PR size: L labels Sep 29, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 29, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 29, 2026
Pre-existing on the refactor base (reproduces on a clean checkout):
GHSA-qw65-cvwx-89v3 and GHSA-58mr-gqgx-xq4g against transitive fast-uri.
Lockfile-only bump within existing ranges; bun audit is now clean.
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 29, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 29, 2026
@shawnxli

Copy link
Copy Markdown
Author

fc8f4f0 also carries a fix found during live China E2E: China scaffolds no longer include the template's default AgentCore Memory resource — the AWS::BedrockAgentCore::Memory CloudFormation type is not registered in cn-north-1/cn-northwest-1, so a fresh create --region cn-north-1 project failed at deploy without manual template edits. The memory code module stays in the scaffold and degrades to memory-less operation when its env var is absent (create prints a note). Verified end-to-end in cn-north-1: fresh scaffold → deploy CREATE_COMPLETE with no manual edits → runtime invoke returning a DeepSeek answer via LiteLLM.

@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 29, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 29, 2026
Comment thread src/core/project/templates/runtime.ts Outdated
build: scaffoldRuntimeInput.build,
// Persist the provider the template wired into the code (framework
// scaffolds only) so the China deploy gate can classify this runtime later.
...(scaffoldRuntimeInput.framework !== "none" && {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small gap: imported Bedrock Agents use framework: "none", so this skips modelProvider even though importScaffoldRuntimeInput sets it to Bedrock. If a CN target is added later, deploy treats that runtime as unclassified and proceeds. Could we persist the provider for imports too and cover import → CN deploy?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8884652 — buildRuntimeSpec now persists modelProvider: "Bedrock" when the scaffold is a Bedrock Agent import (keyed on importBedrockAgent, since imports share framework: "none" with genuinely provider-free scaffolds like minimal/MCP, which stay unclassified). The existing deploy hard-fail then covers import → CN target. The import test asserts the persisted provider.

Comment thread src/globalConfig/accessor.tsx Outdated
// the first-run notice is not shown there (telemetry is disabled), so
// without persisting, a later run in a commercial region would flip
// telemetry back on without the notice ever having been displayed.
if (inChinaRegionEnv() && configFileData.telemetry?.enabled === undefined) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small follow-up: this only looks at region env vars. On a first run where CN comes from --region or the active profile, the telemetry client suppresses export, but this accessor still persists only the installation ID and reports telemetry enabled. Could we use the resolved region here too?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8884652 — the accessor now resolves China through the exact chain the telemetry client uses (--region from argv → env vars → shared config profile → project targets, via isChinaContext + resolveRegion), for both the first-run persist and the CN default. Tests added for a first run with China only from --region and only from the active profile.

Comment thread src/core/project/manager.tsx
…esolve region for telemetry persist

Third review round:

- addResource on a project with a China target rejects any resource family
  whose CloudFormation type is not registered there (allowlist: runtime,
  runtime-endpoint, credential, gateway, gateway-target); deploy to a China
  target fails fast when the spec contains any non-empty collection outside
  the supported set, instead of CloudFormation's opaque 'Unrecognized
  resource types' error. New families default to blocked until confirmed.
- Bedrock Agent imports persist modelProvider: Bedrock (their translated
  code calls Bedrock despite framework 'none'), so a later China deploy
  hard-fails instead of passing as unclassified. Provider-free scaffolds
  (minimal, MCP) stay unclassified.
- The global-config accessor resolves China through the same chain as the
  telemetry client (--region, env vars, shared config profile, project
  targets), so a first run with China only from --region or the active
  profile persists telemetry off.
@shawnxli
shawnxli requested a review from notgitika September 30, 2026 00:31
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 30, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 30, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 30, 2026
Comment thread src/core/project/manager.tsx Outdated
// older CLI) cannot be classified and only get an informational note.
if (isChinaRegion(target.region)) {
const blocked = project.spec.runtimes.filter(
(runtime) => runtime.modelProvider !== undefined && runtime.modelProvider !== "LiteLLM",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we persist/check the model ID here too? A LiteLLM runtime scaffolded before the China target can still use the Bedrock default, but this check lets it through based only on modelProvider.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a1fb82e — LiteLLM scaffolds now persist the rendered model id alongside modelProvider in agentcore.json, and this gate hard-fails a LiteLLM runtime whose persisted id uses LiteLLM's bedrock/ route (the default when scaffolded without --model-id), naming the runtime and id in the error. A LiteLLM runtime without a persisted id (older CLI / hand-edited spec) joins the existing unclassified informational note. Also added the same bedrock/ rejection at create/add in a China context, so the commercial-scaffold-then-CN-deploy hole is closed at both ends. Verifying that a non-bedrock/ model id is actually reachable from China stays the user's responsibility, as documented in the README.

A LiteLLM runtime scaffolded without --model-id renders LiteLLM's default
model id, whose 'bedrock/' prefix routes to Amazon Bedrock — unreachable
from China. The deploy gate previously passed any LiteLLM runtime.

- Scaffolds persist the rendered model id for LiteLLM runtimes alongside
  modelProvider in agentcore.json.
- Deploy to a China target hard-fails a LiteLLM runtime whose persisted
  model id starts with 'bedrock/'; one without a persisted id joins the
  informational unclassified note.
- create/add in a China context reject an explicit 'bedrock/'-prefixed
  --model-id before scaffolding.

Reachability of other model ids from China remains the user's
responsibility, as documented.
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 30, 2026
@shawnxli
shawnxli requested a review from notgitika September 30, 2026 02:39
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 30, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 30, 2026

@notgitika notgitika left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. The LiteLLM model ID is now persisted and rechecked at create/add and deploy time, which closes the China-target gap.

@nborges-aws
nborges-aws merged commit d1eed2f into refactor Sep 30, 2026
21 checks passed
@nborges-aws
nborges-aws deleted the cn-region-support-refactor branch September 30, 2026 02:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants