feat(export): export harnesses to standalone Strands agents with connections#1630
Open
padmak30 wants to merge 8 commits into
Open
feat(export): export harnesses to standalone Strands agents with connections#1630padmak30 wants to merge 8 commits into
padmak30 wants to merge 8 commits into
Conversation
…ections
Extend `agentcore export harness` to faithfully export harnesses that reference
EXTERNAL AgentCore resources, in-project (--name) or by ARN (--arn), with no
manual IAM/wiring overrides.
- Auto-populate `connections[]` (memory/gateway/runtime/browser/codeInterpreter)
on the exported runtime instead of emitting IAM prose notes. Discovery env-var
names are derived from a single source of truth in schemas/connections.ts and
kept in lockstep with @aws/agentcore-cdk, so the names baked into the generated
agent code match what deploy injects.
- New --arn source: fetch a harness from the control plane and map it
(fetch-harness-spec.ts) — model (incl. LiteLLM), memory, runtime environment,
skills (git auth carried through), and tools.
- Add LiteLLM model-provider support (provider-prefixed model_ids; keyless via
IAM for bedrock/, apiKeyArn otherwise) across schema, template, and telemetry.
- Carry gateway outbound-auth (awsIam | none | oauth{providerArn, scopes,
grantType, customParameters}) end-to-end; render customParameters as valid
Python via safeJson and thread grantType -> auth_flow.
- Copy path-skill directories for generated-Dockerfile Container builds.
Verified live end-to-end: create harness -> export (in-project and by ARN) ->
deploy -> invoke; the agent reaches the external memory + gateway at runtime.
Contributor
Package TarballHow to installgh release download pr-1630-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-0.20.2.tgz |
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
Contributor
Coverage Report
|
agentcore-cli-automation
approved these changes
Jun 24, 2026
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Reviewed the PR end-to-end. Looks good to merge.
Highlights of what I checked:
- Test quality — No excessive mocking. The new unit tests (
fetch-harness-spec.test.ts,arn-s3-chain.test.ts,harness-mapper.test.ts,harness-action.test.ts) use pure data fixtures and exercise the real mappers/builders without stubbing fs or the AWS SDK; the network boundary (getHarness) is correctly drawn at the wrapper rather than mocked inside the unit tests. - Telemetry —
export.harnessis registered inCOMMAND_SCHEMASwithbuild_type,model_provider(incl.lite_llm),has_memory,has_gateway,has_container,has_execution_limits,notes_count. The action wraps execution inwithCommandRunTelemetryand records attrs after work is done, with a correctLiteLLM → lite_llmnormalization beforestandardize(). - Connection-name handshake — env-var name derivation (
connectionIdForTarget,connectionEnvToken,connectionEnvVarName) lives in one place (schema/schemas/connections.ts) and is consumed by both the CLI mapper and (per the description) the CDK wiring, which is the right shape for keeping the two repos in lockstep. - --arn fidelity —
mapApiHarnessToSpecdefensively handles both control-plane (PascalCase) and lowercased skill shapes, theSDK_UNKNOWN_MEMBERmanaged-memory fallback, and explicitly does NOT carryexecutionRoleArn(with a clear comment explaining why CDK needs to own the role for Container/connection grants). - External-resource modeling — Memory/gateway/runtime/browser/codeInterpreter all flow through typed
Connectionentries onAgentEnvSpecinstead of prose IAM notes; malformed browser/CI ARNs fall back to the AWS-managed default with a clear note rather than silently using the wrong target. S3 skills generate an inline policy +additionalPoliciesentry, with malformed-URI warnings rather than silent AccessDenied. - OAuth gateway end-to-end —
grantType → auth_flowmapping (CLIENT_CREDENTIALS→M2M, USER_FEDERATION→USER_FEDERATION) is correct; TOKEN_EXCHANGE is surfaced as a manual-step note since the decorator can't express it.customParametersrendered viasafeJsonis valid Python because the schema constrains values toRecord<string,string>. - Path-skill copy — Correctly rejects absolute paths and traversal, only copies dirs that resolve under the harness dir, and emits a verify-note for the unresolved case (which is the expected outcome for
--arn-fetched harnesses).
Caveats already called out in the PR description:
- The schema additions (
AgentEnvSpec.connections,AgentEnvSpec.additionalPolicies) require the CDK construct PR (aws/agentcore-l3-cdk-constructs#291) to merge and publish first — that checkbox is correctly left unchecked.
Nothing blocking from my read.
…dead helper
Review fixes for the harness-export connections feature:
- main.py template: emit `import os` when browserIdentifierEnvVar or
codeInterpreterIdentifierEnvVar is set. A custom browser/code-interpreter
ARN renders `os.getenv(...)` at module scope, but `import os` was gated only
on filesystem mounts / file_operations / git-cred skills — so a Container
export with a custom tool ARN and none of those produced a main.py that
crashed at import with NameError. Snapshot updated.
- fetch-harness-spec: throw an early ValidationError when an --arn VPC harness
is missing explicit subnets/securityGroups, instead of emitting
networkMode:'VPC' with no networkConfig and crashing later in
writeProjectSpec's schema validation after the agent dir/code were written.
- connections.ts: drop the dead exported `connectionEnvVarName` (imported by
neither repo) and correct the "single source of truth" comment to name the
helpers actually shared across repos (connectionEnvToken / connectionTokenFor).
- harness-action: move the inline `import('../../../schema').HarnessSpec` type
to the top-of-file import (AGENTS.md: no inline imports).
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
…ng it
A harness-owned ("managed") memory is a real resource with a service-populated
ARN once the harness is READY. mapMemory previously collapsed it to a bare
`{ mode: 'managed' }`, which resolveMemoryProviders ignores — so the exported
agent silently got no memory at all.
Map managedMemoryConfiguration.arn to `{ mode: 'existing', arn }` so it flows
through the existing external-memory path: a `memory` connection with
access: readwrite (IAM scoped to the ARN + discovery env var at deploy). The
bare `{ mode: 'managed' }` is now only a fallback for the no-ARN case
(unprovisioned harness, or an SDK-unknown variant); comments call out that this
fallback is not resolved downstream and where to wire it if needed.
- Type managedMemoryConfiguration on the harness client interface (was read via
`as Record<string, unknown>`); agentCoreMemoryConfiguration is now optional
since exactly one arm is populated.
- Tests: provisioned managed memory (with arn) -> existing-by-arn; managed
without arn -> managed; SDK-unknown -> managed.
Verified live: re-exporting a code-interpreter harness whose managed memory has
an ARN now emits a memory connection in agentcore.json (previously absent).
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
A harness bedrockModelConfig whose apiFormat is `responses`/`chat_completions` (e.g. openai.gpt-5.5, openai.gpt-oss-120b) is served via the Bedrock Mantle OpenAI-compatible endpoint, NOT the Converse API. Export previously keyed only on the provider, generating a plain BedrockModel for these — so invocation failed at runtime with "ConverseStream ... The provided model identifier is invalid". Generate an OpenAI-style Mantle client instead: - load.py: build OpenAIModel (chat_completions) / OpenAIResponsesModel (proprietary responses) / MantleCompatResponsesModel (open-source responses), against the Mantle base URL (/openai/v1 for proprietary, /v1 for gpt-oss), authenticated with a short-lived Bedrock bearer token (region from AWS_REGION). - harness-mapper: detect Mantle, thread apiFormat/proprietary/params into the render config, and emit a bedrock-mantle IAM policy (CreateInference + CallWithBearerToken) via additionalPolicies — the runtime role's default bedrock:InvokeModel grant does not cover the bedrock-mantle service. - Add openai + aws-bedrock-token-generator deps and vend model/mantle_compat.py. Verified live end-to-end: export by ARN -> deploy -> invoke an openai.gpt-5.5 Mantle harness returns a real completion (previously the ConverseStream error).
Removed the "No AWS deployment target configured" note. It warned that `agentcore deploy` would fail with `Target "default" not found` when aws-targets.json is empty, but deploy already handles that case interactively (ensure-target.ts prompts for account/region and writes a default target). The note described a failure the deploy flow prevents, so it was noise.
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
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
Extend
agentcore export harnessto faithfully export harnesses that reference external AgentCore resources — in-project (--name) or by ARN (--arn) — with no manual IAM/wiring overrides.connections[](memory/gateway/runtime/browser/codeInterpreter) on the exported runtime instead of emitting IAM prose notes. Discovery env-var names are derived from a single source of truth inschemas/connections.ts, kept in lockstep with@aws/agentcore-cdk, so the names baked into the generated agent code match what deploy injects.--arnsource: fetch a harness from the control plane and map it (fetch-harness-spec.ts) — model (incl. LiteLLM), memory, runtime environment, skills (git auth carried through), and tools.bedrock/,apiKeyArnotherwise) across schema, template, and telemetry.awsIam | none | oauth{providerArn, scopes, grantType, customParameters}) threaded end-to-end;customParametersrendered as valid Python viasafeJsonandgrantType→auth_flow.Related Issue
Closes #
Dependent change
Requires the CDK construct PR: aws/agentcore-l3-cdk-constructs#291 (the connections wiring + lockstep schema). That should merge and publish first.
Type of Change
Testing
npm run test:unit(946 export + schema tests pass)npm run typecheck(clean)npm run lint(clean)src/assets/→ rannpm run test:update-snapshotsand committed the updated snapshot--name) and out-of-project (--arn), deployed, and invoked. In-project and out-of-project produce identical connection wiring. Verified runtime behavior: gateway tool executes, memory recall works, code-interpreter runs, S3/path/private-git skills load, and the OAuth connection's IAM + token-fetch wiring is correct.Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.