Skip to content

fix(export): make generated Strands runtimes deployable - #2154

Open
aidandaly24 wants to merge 5 commits into
aws:refactorfrom
aidandaly24:fix/export-harness-generated-runtime
Open

fix(export): make generated Strands runtimes deployable#2154
aidandaly24 wants to merge 5 commits into
aws:refactorfrom
aidandaly24:fix/export-harness-generated-runtime

Conversation

@aidandaly24

Copy link
Copy Markdown
Contributor

Summary

  • align generated Strands Python agents with the released strands-agents 1.54.x APIs and provider extras
  • replace the stateful execution-limit hook with native per-invocation turn/token limits and request-scoped cancellation
  • defer credential-backed MCP identity lookup until transport startup, and generate collision-resistant provider/function names
  • preserve provider parameters and memory retrieval tuning while emitting export notes for fields that cannot be reproduced
  • strictly validate service harness ARNs and recover the VPC ID required by service-ARN Container exports
  • surface unknown or incomplete service union members in EXPORT_NOTES.md instead of silently dropping them

Verification

Source gate

  • bun install --frozen-lockfile
  • bun test src: 2,573 pass, 0 fail, 186 files
  • bun run typecheck
  • bun run lint:check
  • bun run format:check
  • bun run build
  • bun run secrets:check

Generated Python matrix

Generated real exports and ran uv sync, compileall, and import main for:

  • Bedrock with skills, sliding-window truncation, execution limits, timeout, and credential-backed remote MCP
  • OpenAI Responses
  • Gemini
  • LiteLLM
  • Bedrock Mantle Responses

All five resolved strands-agents 1.54.0 and imported successfully. OpenAI/Mantle resolved openai 2.54.0, Gemini resolved google-genai 2.20.0, and LiteLLM resolved litellm 1.96.0. A generated-module probe invoked the Bedrock entrypoint twice and verified fresh cancellation signals plus identical per-invocation limits (LIMITS_OK).

Live AWS

Account 603141041947, region us-east-1, profile deploy:

  • deployed source harness ExportHarnessFix0831_source-jBo3nhtmm2 to READY and invoked it
  • exported by local name and by service ARN (with ambient us-west-2, proving ARN-region precedence)
  • built and deployed runtimes:
    • ExportHarnessFix0831_exported_agent-hLU1ha80fd
    • ExportHarnessFix0831_exported_arn_agent-ItzBMG47U0
  • invoked each runtime twice in the same session; all four calls returned HTTP 200, end_turn, and the requested marker
  • deployed credential-backed MCP runtime ExportHarnessFix0831_mcp_runtime-6ZSyRO2yME
  • confirmed module import succeeds without request identity context
  • after creating the referenced disposable API-key provider, invoked the runtime successfully with MCP_CONTEXT_OK

The current refactor deploy path consumes project credentials as references rather than provisioning them, so the exporter now states that the named provider must exist instead of claiming deploy creates it.

Cleanup

  • stack AgentCore-ExportHarnessFix0831-default: deleted
  • matching AgentCore runtimes: none
  • matching AgentCore harnesses: none
  • disposable API-key credential provider: deleted

@github-actions github-actions Bot added the size/xl PR size: XL label Aug 31, 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 Aug 31, 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 Aug 31, 2026
@codecov-commenter

codecov-commenter commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.29787% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.19%. Comparing base (d304147) to head (bee4e65).

Files with missing lines Patch % Lines
src/handlers/project/export/serviceHarness.ts 75.00% 22 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #2154      +/-   ##
============================================
- Coverage     97.22%   97.19%   -0.03%     
============================================
  Files           507      507              
  Lines         33809    33953     +144     
============================================
+ Hits          32872    33002     +130     
- Misses          937      951      +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.

@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, tightly-scoped fix. I walked through the template updates, the exporter changes, and the new EC2-backed VPC lookup and didn't find anything that needs to change before merge. A few observations, none of which are blockers:

  • HarnessClient.resolveVpcIdFromSubnets is wired cleanly through AwsClients/CoreClient and the ec2 client is cached like the others; the new tests cover the multi-VPC / no-VPC / happy paths without mocking anything below the SDK boundary. 👍
  • The switch to a strict ARN regex in parseHarnessArn is the right call, and the behavior change of always trusting the ARN's region (rather than falling back to CLI region) is now consistent between harnessIdFromArn and regionFromHarnessArn. The test in harness.test.ts (arn:aws:lambda:...) and the partition test in serviceHarness.test.ts (arn:aws-cn:...) cover the important edges.
  • The main.py template's limits = { … } or None idiom is intentional: when hasExecutionLimits is true solely because timeoutSeconds is set, both {{#if}} branches inside the dict literal are stripped, so it evaluates to None. As long as agent.stream_async(..., limits=None, ...) is accepted by strands-agents 1.54 (per the verification notes in the PR description, it is), this is fine.
  • serviceHarness.ts now surfaces $unknown union members as export notes instead of silently dropping them (skills, memory, environment, environment artifact, filesystem configs). Good coverage in serviceHarness.test.ts.
  • Header credential names / python function names now hash their inputs, so X-Api-Key vs X_Api_Key no longer collide — nice; that's exercised by the new "keeps normalized header names distinct" test.
  • readStrandsVersion regex was updated to tolerate the new strands-agents[extras] form.
  • No new features here that would need telemetry instrumentation; existing plumbing is untouched.

LGTM to merge.

@agentcore-devx-automation agentcore-devx-automation Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Aug 31, 2026
@aidandaly24
aidandaly24 force-pushed the fix/export-harness-generated-runtime branch from ed3b929 to bee4e65 Compare August 31, 2026 21:55
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 31, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Aug 31, 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 Aug 31, 2026
Comment thread src/core/types.tsx
// results to. CloudWatch is a distinct service from the AgentCore data plane,
// so it gets its own client/factory rather than reusing `data`.
logs(config: ClientConfig): CloudWatchLogsClient;
ec2(config: ClientConfig): EC2Client;

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.

Why do we need an EC2 client?

Comment thread src/core/harness.tsx
.send(new GetHarnessCommand({ harnessId: id }));
}

async resolveVpcIdFromSubnets(subnetIds: string[], options: CoreOptions): Promise<string> {

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.

spec.networkConfig &&
!spec.networkConfig.vpcId
) {
spec.networkConfig.vpcId = await config.core.harness.resolveVpcIdFromSubnets(

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.

I'm not sure this need to be in scope. The main thing is generating the code that the user can then use. The user can also configure VPC stuff on their own.

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.

3 participants