Skip to content

refactor(templates): simplify strands python agent to barebones agent - #2179

Merged
Hweinstock merged 1 commit into
aws:refactorfrom
Hweinstock:feat/simplify-strands-python-template
Sep 3, 2026
Merged

refactor(templates): simplify strands python agent to barebones agent#2179
Hweinstock merged 1 commit into
aws:refactorfrom
Hweinstock:feat/simplify-strands-python-template

Conversation

@Hweinstock

Copy link
Copy Markdown
Contributor

Stacked on #2175

Problem

The strands agent for python has grown in complexity so significantly that its difficult to work with. Its attempting to scaffold everything for the user, which leads to an unreadable template, and a fair bit of templating complexity.

Solution

  • reduce the template to only accept model providers and memory as template, all other support is eliminated.

Verification

$ agentcore project create --name simpleStrands --template agent-python-strands
Creating project tree
Installing CDK dependencies with npm
Syncing Python dependencies with uv
Initializing git repository
Created project 'simpleStrands' in ./simpleStrands
To deploy it: cd simpleStrands && agentcore project deploy

$ cd simpleStrands

$ agentocre project add runtime --name bob --template agent-python-strands --build Container
Reading project spec file at '[..]'
Scaffolding runtime in project
Syncing Python dependencies with uv
Updating project spec file at '[..]'
added runtime 'bob' to 'simpleStrands'

$ agentcore project add runtime --name alice --template agent-python-strands --memory none
Reading project spec file at '[..]'
Scaffolding runtime in project
Syncing Python dependencies with uv
Updating project spec file at '[..]'
added runtime 'alice' to 'simpleStrands'

$ agentcore project dev --mode headless --no-traces &
[3] 3920204
[agent_python_strands] Starting development server
[alice] Starting development server
[agent_python_strands] INFO:     Will watch for changes in these directories: ['..']
[agent_python_strands] INFO:     Uvicorn running on http://127.0.0.1:8083 (Press CTRL+C to quit)
[agent_python_strands] INFO:     Started reloader process [3920286] using StatReload
[bob] Building image with docker
[alice] INFO:     Will watch for changes in these directories: ['/..']
[alice] INFO:     Uvicorn running on http://127.0.0.1:8085 (Press CTRL+C to quit)
[alice] INFO:     Started reloader process [3920299] using StatReload
[bob] #0 building with "default" instance using docker driver
[bob] #1 [internal] load build definition from Dockerfile
[bob] #1 transferring dockerfile: 971B done
[bob] #1 DONE 0.0s
[bob] #2 [internal] load metadata for public.ecr.aws/docker/library/python:3.12-slim-trixie
[bob] #2 DONE 0.1s
[bob] #3 [internal] load .dockerignore
[bob] #3 transferring context: 358B done
[bob] #3 DONE 0.0s
[bob] #4 [1/8] FROM public.ecr.aws/docker/library/python:3.12-slim-trixie@sha256:78387bc3881b8273120a12ebe6c1ab22b018ccc2c9adf565ae1ac9b536e184ea
[bob] #4 DONE 0.0s
[bob] #5 [internal] load build context
[bob] #5 transferring context: 1.15kB done
[bob] #5 DONE 0.0s
[bob] #6 [6/8] RUN uv sync --frozen --no-dev --no-install-project
[bob] #6 CACHED
[bob] #7 [3/8] WORKDIR /app
[bob] #7 CACHED
[bob] #8 [4/8] RUN useradd -m -u 1000 bedrock_agentcore
[bob] #8 CACHED
[bob] #9 [5/8] COPY pyproject.toml uv.lock ./
[bob] #9 CACHED
[bob] #10 [7/8] COPY --chown=bedrock_agentcore:bedrock_agentcore . .
[bob] #10 CACHED
[bob] #11 [2/8] RUN pip install --no-cache-dir uv
[bob] #11 CACHED
[bob] #12 [8/8] RUN uv sync --frozen --no-dev
[bob] #12 CACHED
[bob] #13 exporting to image
[bob] #13 exporting layers done
[bob] #13 writing image sha256:03f1b38478236c6d59155fa6a0c7618576fff49498886aa9a6266f7d6956b82e done
[bob] #13 naming to docker.io/agentcore-dev/bob-0da37433c1f9 done
[bob] #13 DONE 0.0s
[bob] Starting container
[agent_python_strands] INFO:     Started server process [3920358]
[agent_python_strands] INFO:     Waiting for application startup.
[agent_python_strands] INFO:     Application startup complete.
[alice] INFO:     Started server process [3920365]
[alice] INFO:     Waiting for application startup.
[alice] INFO:     Application startup complete.
[agent_python_strands] Agent 'agent_python_strands' is running on port 8083.
[bob] Agent 'bob' is running on port 8084.
[alice] Agent 'alice' is running on port 8085.
[bob] Configuration of aws_configurator not loaded, configurator already loaded


$ curl -X POST localhost:8083/invocations -d '{ "prompt": "Hello!" }'
[agent_python_strands] {"timestamp": "2026-09-03T13:56:22.058Z", "level": "INFO", "message": "Returning streaming response (generator) (0.000s)", "logger": "bedrock_agentcore.app", "requestId": "9219e423-ba45-4f4c-
872a-12331a4d7f95"}
[agent_python_strands] INFO:     127.0.0.1:47256 - "POST /invocations HTTP/1.1" 200 OK
[agent_python_strands] {"timestamp": "2026-09-03T13:56:22.102Z", "level": "INFO", "message": "Invoking Agent.....", "logger": "bedrock_agentcore.app", "requestId": "9219e423-ba45-4f4c-872a-12331a4d7f95"}
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "Hello! How can I help you today"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "?"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockStop": {"contentBlockIndex": 0}}}

data: {"event": {"messageStop": {"stopReason": "end_turn"}}}

data: {"event": {"metadata": {"usage": {"inputTokens": 598, "outputTokens": 12, "totalTokens": 610}, "metrics": {"latencyMs": 1407}}}}

$ curl -X POST localhost:8084/invocations -d '{ "prompt": "Hello!" }'
[bob] {"timestamp": "2026-09-03T13:56:33.894Z", "level": "INFO", "message": "Returning streaming response (generator) (0.000s)", "logger": "bedrock_agentcore.app", "requestId": "f28f67ab-b8f6-428a-a444-8a476a50786d
"}
[bob] {"timestamp": "2026-09-03T13:56:33.904Z", "level": "INFO", "message": "Invoking Agent.....", "logger": "bedrock_agentcore.app", "requestId": "f28f67ab-b8f6-428a-a444-8a476a50786d"}
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "Hello! How can I help you today"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "?"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockStop": {"contentBlockIndex": 0}}}

data: {"event": {"messageStop": {"stopReason": "end_turn"}}}

data: {"event": {"metadata": {"usage": {"inputTokens": 598, "outputTokens": 12, "totalTokens": 610}, "metrics": {"latencyMs": 1295}}}}

$ curl -X POST localhost:8085/invocations -d '{ "prompt": "Hello!" }'
[alice] {"timestamp": "2026-09-03T13:56:47.108Z", "level": "INFO", "message": "Returning streaming response (generator) (0.000s)", "logger": "bedrock_agentcore.app", "requestId": "c66e99d5-b51e-40cf-8e06-77797a1a5e
da"}
[alice] INFO:     127.0.0.1:38490 - "POST /invocations HTTP/1.1" 200 OK
[alice] {"timestamp": "2026-09-03T13:56:47.148Z", "level": "INFO", "message": "Invoking Agent.....", "logger": "bedrock_agentcore.app", "requestId": "c66e99d5-b51e-40cf-8e06-77797a1a5eda"}
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "Hello! How can I help you today"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "?"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockStop": {"contentBlockIndex": 0}}}

data: {"event": {"messageStop": {"stopReason": "end_turn"}}}

data: {"event": {"metadata": {"usage": {"inputTokens": 598, "outputTokens": 12, "totalTokens": 610}, "metrics": {"latencyMs": 1620}}}}

$ curl -X POST localhost:8085/invocations -d '{ "prompt": "what did i just say" }'
[alice] {"timestamp": "2026-09-03T13:56:56.519Z", "level": "INFO", "message": "Returning streaming response (generator) (0.000s)", "logger": "bedrock_agentcore.app", "requestId": "3c2b1856-09e3-4ca2-b45d-033391d73b38"}
[alice] Hello! How can I help you today?INFO:     127.0.0.1:35134 - "POST /invocations HTTP/1.1" 200 OK
[alice] {"timestamp": "2026-09-03T13:56:56.520Z", "level": "INFO", "message": "Invoking Agent.....", "logger": "bedrock_agentcore.app", "requestId": "3c2b1856-09e3-4ca2-b45d-033391d73b38"}
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "You"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " just"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " said \"Hello!\" - that was"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " your greeting"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " to"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " me."}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockStop": {"contentBlockIndex": 0}}}

data: {"event": {"messageStop": {"stopReason": "end_turn"}}}

data: {"event": {"metadata": {"usage": {"inputTokens": 618, "outputTokens": 17, "totalTokens": 635}, "metrics": {"latencyMs": 1718}}}}

$ agentcore project deploy
...
$ agentcore project invoke runtime --name agent_python_strands --payload '{"prompt": "hello world"}'
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "Hello! "}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "👋 How"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " can I help you today?"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockStop": {"contentBlockIndex": 0}}}

data: {"event": {"messageStop": {"stopReason": "end_turn"}}}

data: {"event": {"metadata": {"usage": {"inputTokens": 598, "outputTokens": 16, "totalTokens": 614}, "metrics": {"latencyMs": 1509}}}}

status=200 content-type=text/event-stream; charset=utf-8 runtime-session-id=9b697144-83f0-4c11-add2-11d76006dc98 mcp-session-id=- mcp-protocol-version=- trace-id=- trace-parent=- trace-state=- baggage=- complete=true bytes=625

$ agentcore project invoke runtime --name alice --payload '{"prompt": "hello world"}'
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "Hello! "}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "👋 How"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " can I help you today?"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockStop": {"contentBlockIndex": 0}}}

data: {"event": {"messageStop": {"stopReason": "end_turn"}}}

data: {"event": {"metadata": {"usage": {"inputTokens": 598, "outputTokens": 16, "totalTokens": 614}, "metrics": {"latencyMs": 2003}}}}

status=200 content-type=text/event-stream; charset=utf-8 runtime-session-id=a8f674fc-9ad9-4a8a-a4ae-bc61a0335687 mcp-session-id=- mcp-protocol-version=- trace-id=- trace-parent=- trace-state=- baggage=- complete=true bytes=625

(26-09-03 14:19:17) <0> [~/gh-repos/worktrees/simplify-strands-template/simpleStrands]
$ agentcore project invoke runtime --name bob --payload '{"prompt": "hello world"}'
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "Hello! "}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "👋 How"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " can I help you today?"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockStop": {"contentBlockIndex": 0}}}

data: {"event": {"messageStop": {"stopReason": "end_turn"}}}

data: {"event": {"metadata": {"usage": {"inputTokens": 598, "outputTokens": 16, "totalTokens": 614}, "metrics": {"latencyMs": 1533}}}}

status=200 content-type=text/event-stream; charset=utf-8 runtime-session-id=b8ddbcbd-1add-4828-bd6a-bd1abec7b589 mcp-session-id=- mcp-protocol-version=- trace-id=- trace-parent=- trace-state=- baggage=- complete=true bytes=625

Also did the same flow in #2175 again for gemini and had agent test the others.

@Hweinstock Hweinstock changed the title refactor(tempaltes): simplify strands python agent to barebones agent refactor(templates): simplify strands python agent to barebones agent Sep 3, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 3, 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 3, 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 3, 2026
@codecov-commenter

codecov-commenter commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (refactor@16db5b4). Learn more about missing BASE report.

Additional details and impacted files
@@             Coverage Diff             @@
##             refactor    #2179   +/-   ##
===========================================
  Coverage            ?   97.07%           
===========================================
  Files               ?      536           
  Lines               ?    36955           
  Branches            ?        0           
===========================================
  Hits                ?    35874           
  Misses              ?     1081           
  Partials            ?        0           

☔ 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: Changes requested

Nice cleanup on the model-provider resolution and the barebones template — the split of harness vs. runtime provider resolution is much clearer, and gating templates in the resolver keeps schema validation simple.

One correctness gap and a small dead-code observation:

Orphaned credential on remove runtime (correctness)

src/core/project/manager.tsxaddResource(resourceType: "runtime") now auto-appends an ApiKeyCredentialProvider credential (e.g. myAgentAnthropicApiKey) and an .env.local entry when a non-Bedrock provider is chosen. removeResource (around line 560+) only cleans up env keys when input.resourceType === "credential" and only filters the runtimes collection — the runtime-scaffolded credential is left behind in the spec, and its .env.local value stays.

Concrete impact: add runtime foo --model-provider anthropic --api-key …remove runtime fooadd runtime foo --model-provider anthropic --api-key … fails on the second add. The runtime uniqueness check passes (no runtimes left), the resolver pushes fooAnthropicApiKey again, and ProjectSpecSchema rejects the write via uniqueNames("credential") — a confusing error for what looks like a fresh add. Meanwhile the old API-key value in .env.local is silently kept because insertIfNew skips existing keys.

Options:

  1. In removeResource, when removing a runtime, also strip any credentials whose names match ${runtimeName}(Anthropic|OpenAI|Gemini)ApiKey (or track the association explicitly on the runtime spec entry) and clean their env keys the same way the credential branch does.
  2. Have the runtime resolver record the credential name on the runtime spec (e.g. modelProviderCredentialName) so removal can look it up without inferring from a naming convention.
  3. At minimum, detect the pre-existing credential in addResource runtime branch and produce a clear error/repair instruction instead of relying on the schema failure downstream.

Minor: dead LiteLLM branch in agent-python-strands/model/load.py

ModelProviderSchema for runtime scaffolds is ["Bedrock", "Anthropic", "OpenAI", "Gemini"] and resolveRuntimeModelProvider never produces "LiteLLM", but model/load.py still carries a {{#if (eq modelProvider "LiteLLM")}} block (plus bedrock/us.anthropic.claude-sonnet-4-5-20250514-v1:0 inside it). It's unreachable in the runtime path and can be dropped, or the schema/table extended if LiteLLM is intentionally coming next.

Everything else — the .env.local write on create, the merged mergeSpecEntries move to types.ts, the MODEL_PROVIDERS alias map, the resolver-level guards for MCP and the agent-python template, and the expanded tests — looks good. EnvLocalFile is constructed with the right root path in both create and add paths, and the rollback in addResource correctly covers the env-file mutation for the spec-commit failure case.

@agentcore-devx-automation agentcore-devx-automation Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Sep 3, 2026
@Hweinstock
Hweinstock force-pushed the feat/simplify-strands-python-template branch from 4c321ec to 187fc5d Compare September 3, 2026 15:13
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 3, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 3, 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 3, 2026
@Hweinstock
Hweinstock marked this pull request as ready for review September 3, 2026 15:50
@Hweinstock
Hweinstock marked this pull request as draft September 3, 2026 15:51
@Hweinstock

Copy link
Copy Markdown
Contributor Author

I think the harness reviewer is confused from the stacked PR.

@Hweinstock
Hweinstock marked this pull request as ready for review September 3, 2026 15:58
@Hweinstock
Hweinstock merged commit f6a979e into aws:refactor Sep 3, 2026
18 of 22 checks passed
@Hweinstock
Hweinstock deleted the feat/simplify-strands-python-template branch September 3, 2026 17:08
This was referenced Sep 3, 2026
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