Skip to content

fix(templates): allow actor_id overrides to match harness behavior - #2306

Merged
Hweinstock merged 15 commits into
aws:refactorfrom
Hweinstock:fix/address-actor-gap
Sep 15, 2026
Merged

Hweinstock merged 15 commits into
aws:refactorfrom
Hweinstock:fix/address-actor-gap

Conversation

@Hweinstock

Copy link
Copy Markdown
Contributor

Problem

This PR addresses a few related problems:

  1. the templates are still pretty complex, with the main file including an agent factory caching based on (user_id, session_id) pairs, and some parsing logic.
  2. this caching doesn't actually work since user_id is not injected via the app context, or the headers so the invoke handler always defaulting to default-user.

Solution

  • remove agent factory in favor of simpler LRU cache.
  • copy what harness does and allow actor_id to be injected at invoke time to determine the memory namespace (not runtime user id).

We also simplify the template and improve documentation:

  • reduce bloat in the main file by moving parsing logic to parse.py.
  • add documentation describing the prompt shape.

Future Work

  • follow-up and do this with the equivalent TS template.

Testing / Verification

deployed and verified e2e that actorId scoping is working.

$ ac project invoke runtime --name agent_python_strands --session-id qqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqq --payload '{ "actor_id": "harry", "prompt": "my favorite color is blue"}'
data: {"event": {"messageStart": {"role": "assistant"}}}

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

data: {"event": {"contentBlockDelta": {"delta": {"text": "'s wonderful"}, "contentBlockIndex": 0}}}

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

data: {"event": {"contentBlockDelta": {"delta": {"text": " is such a versat"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "ile and calming color."}, "contentBlockIndex": 0}
}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " It's associated"}, "contentBlockIndex": 0}}}

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

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

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

data: {"event": {"contentBlockDelta": {"delta": {"text": " ocean, and often"}, "contentBlockIndex": 0}}}

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

data: {"event": {"contentBlockDelta": {"delta": {"text": "okes feelings of tranquility,"}, "contentBlockInd
ex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " peace, and stability"}, "contentBlockIndex": 0}}
}

data: {"event": {"contentBlockDelta": {"delta": {"text": ". \n\nIs"}, "contentBlockIndex": 0}}}

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

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

data: {"event": {"contentBlockDelta": {"delta": {"text": " of blue you're most"}, "contentBlockIndex": 0}}}

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

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

data: {"event": {"contentBlockDelta": {"delta": {"text": ", sky blue, tur"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "quoise, or maybe cob"}, "contentBlockIndex": 0}}}

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

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

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

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

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

data: {"event": {"contentBlockDelta": {"delta": {"text": "ades of blue equally?"}, "contentBlockIndex": 0}}
}

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

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

data: {"event": {"metadata": {"usage": {"inputTokens": 651, "outputTokens": 84, "totalTokens": 735}, "metri
cs": {"latencyMs": 2729}}}}

status=200 content-type=text/event-stream; charset=utf-8 runtime-session-id=qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qq mcp-session-id=- mcp-protocol-version=- trace-id=- trace-parent=- trace-state=- baggage=- complete=true 
bytes=3045

$ ac project invoke runtime --name agent_python_strands --session-id qqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqq --payload '{ "actor_id": "jerry", "prompt": "what is my favorite color"}'
data: {"event": {"messageStart": {"role": "assistant"}}}

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

data: {"event": {"contentBlockDelta": {"delta": {"text": "'t have any information about your favorite"}, "c
ontentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " color. I don"}, "contentBlockIndex": 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "'t have access to personal"}, "contentBlockIndex"
: 0}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": " information about you unless"}, "contentBlockInd
ex": 0}}}

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

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

data: {"event": {"contentBlockDelta": {"delta": {"text": " in"}, "cont

data: {"event": {"contentBlockDelta": {"delta": {"text": " our convers

data: {"event": {"contentBlockDelta": {"delta": {"text": "\n\nWhat"}, 

data: {"event": {"contentBlockDelta": {"delta": {"text": " is"}, "cont

data: {"event": {"contentBlockDelta": {"delta": {"text": " your favori
}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "'d be happy 

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

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

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

data: {"event": {"metadata": {"usage": {"inputTokens": 601, "outputTokens": 49, "totalTokens": 650}, "metr
ics": {"latencyMs": 1846}}}}

status=200 content-type=text/event-stream; charset=utf-8 runtime-session-id=qqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqq mcp-session-id=- mcp-protocol-version=- trace-id=- trace-parent=- trace-state=- baggage=- complete=tru
e bytes=1788

$ ac project invoke runtime --name agent_py --session-id qqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqq  --payload '{ "actor_id": "harry", "prompt": "what is my favorite color"}'
data: {"event": {"messageStart": {"role": "assistant"}}}

data: {"event": {"contentBlockDelta": {"delta": {"text": "Your"}, "con

data: {"event": {"contentBlockDelta": {"delta": {"text": " favorite co

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

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

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

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

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

data: {"event": {"contentBlockDelta": {"delta": {"text": " ago. "}, "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": 743, "outputTokens": 21, "totalTokens": 764}, "metr
ics": {"latencyMs": 1632}}}}

status=200 content-type=text/event-stream; charset=utf-8 runtime-session-id=qqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqq mcp-session-id=- mcp-protocol-version=- trace-id=- trace-parent=- trace-state=- baggage=- complete=tru
e bytes=1191

@Hweinstock Hweinstock changed the title fix(templates): allow actor_id overrides in favor of agent cache fix(templates): allow actor_id overrides to match harness behavior Sep 15, 2026
@github-actions github-actions Bot added size/m PR size: M and removed size/m PR size: M labels Sep 15, 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 and removed agentcore-harness-reviewing AgentCore Harness review in progress labels Sep 15, 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 refactor of the agent-python-strands template. parse.py is a good separation of concerns, the lru_cache on _get_agent is cleaner than the hand-rolled closure and has the benefit of a bounded size, and the README now documents the payload shape and where session_id actually comes from.

A couple of small, non-blocking observations:

  • Behavior change on missing session_id (local dev only): memory/session.py used to fall back to uuid.uuid4().hex when session_id was None; that fallback is now gone and main.py substitutes the fixed string "default-session" instead. In deployed AgentCore this doesn't matter (the header is always set), but for local dev multiple invocations will now share the same session/agent (via _get_agent's cache) rather than getting a fresh one. That seems like the intended tradeoff (deterministic local session), just worth noting.
  • Sibling export-harness-python template is now inconsistent: it still references strip_trailing_tool_use(), agent_factory(), and get_or_create_agent(...) in both main.py and README.md. If the intent is to align the two templates, a follow-up PR to port the same refactor would be worthwhile — not required for this one.

No changes required to merge.

@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 15, 2026
@codecov-commenter

codecov-commenter commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.06%. Comparing base (b229c65) to head (d557834).
⚠️ Report is 7 commits behind head on refactor.

Additional details and impacted files
@@            Coverage Diff            @@
##           refactor    #2306   +/-   ##
=========================================
  Coverage     97.06%   97.06%           
=========================================
  Files           569      569           
  Lines         39322    39322           
=========================================
  Hits          38167    38167           
  Misses         1155     1155           

☔ 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/m PR size: M and removed size/m PR size: M labels Sep 15, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 15, 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 15, 2026
@Hweinstock
Hweinstock force-pushed the fix/address-actor-gap branch from 0de49e8 to d557834 Compare September 15, 2026 12:40
@github-actions github-actions Bot added size/m PR size: M and removed size/m PR size: M labels Sep 15, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 15, 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 15, 2026
@Hweinstock
Hweinstock marked this pull request as ready for review September 15, 2026 14:57
@Hweinstock
Hweinstock merged commit c8bec47 into aws:refactor Sep 15, 2026
15 of 18 checks passed
@Hweinstock
Hweinstock deleted the fix/address-actor-gap branch September 15, 2026 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants