From a59dabfee3701c1785662638b89a34890dfa0ad0 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 02:20:23 +0000 Subject: [PATCH 01/15] fix(templates): allow actor based namespacing in strands template --- .../templates/agent-python-minimal/README.md | 2 +- .../templates/agent-python-strands/main.py | 104 +++++------------- .../agent-python-strands/memory/session.py | 6 +- .../templates/agent-python-strands/parse.py | 37 +++++++ 4 files changed, 66 insertions(+), 83 deletions(-) create mode 100644 src/assets/templates/agent-python-strands/parse.py diff --git a/src/assets/templates/agent-python-minimal/README.md b/src/assets/templates/agent-python-minimal/README.md index 2093a041f..905bb06cd 100644 --- a/src/assets/templates/agent-python-minimal/README.md +++ b/src/assets/templates/agent-python-minimal/README.md @@ -27,5 +27,5 @@ Environment variables for local development go in `agentcore/.env.local` ```bash agentcore project deploy -agentcore project invoke runtime --payload '{"prompt":"Hello!"}' +agentcore project invoke runtime --payload '{"prompt":"Hello!", "actor_id": "insert namespace here"}' ``` diff --git a/src/assets/templates/agent-python-strands/main.py b/src/assets/templates/agent-python-strands/main.py index 9a350a3f3..e0d1aa27d 100644 --- a/src/assets/templates/agent-python-strands/main.py +++ b/src/assets/templates/agent-python-strands/main.py @@ -1,106 +1,56 @@ -from typing import Any - from strands import Agent, tool +import uuid from strands.agent.conversation_manager.null_conversation_manager import NullConversationManager from bedrock_agentcore.runtime import BedrockAgentCoreApp from model.load import load_model +from parse import parse_payload from memory.session import get_memory_session_manager -app = BedrockAgentCoreApp() -log = app.logger - DEFAULT_SYSTEM_PROMPT = "You are a helpful assistant. Use tools when appropriate." # Define a collection of tools used by the model tools = [] - # Define a simple function tool @tool -def add_numbers(a: int, b: int) -> int: +def _add_numbers(a: int, b: int) -> int: """Return the sum of two numbers""" return a + b - -tools.append(add_numbers) - +tools.append(_add_numbers) def _make_conversation_manager(): return NullConversationManager() +def create_app(): + app = BedrockAgentCoreApp() + log = app.logger -def agent_factory(): - cache = {} - def get_or_create_agent(session_id, user_id): - key = f"{session_id}/{user_id}" - if key not in cache: - cache[key] = Agent( + @app.entrypoint + async def invoke(payload, context): + log.info("Invoking Agent.....") + + session_id = getattr(context, "session_id", uuid.uuid4().hex) + prompt, actor_id = parse_payload(payload) + + log.info(f"Invoking with session_id={session_id} and actor_id={actor_id}") + agent = Agent( model=load_model(), - session_manager=get_memory_session_manager(session_id, user_id), + session_manager=get_memory_session_manager(session_id, actor_id), conversation_manager=_make_conversation_manager(), system_prompt=DEFAULT_SYSTEM_PROMPT, - tools=tools, - ) - return cache[key] - return get_or_create_agent -get_or_create_agent = agent_factory() - - -def strip_trailing_tool_use(messages: Any) -> list[dict]: - """Strip toolUse blocks from the tail until the last message has none.""" - if not isinstance(messages, list): - raise ValueError("messages must be a list") - - messages = list(messages) - while messages: - last = messages[-1] - if not isinstance(last, dict): - raise ValueError("each message must be an object") - original_content = last.get("content", []) - if not isinstance(original_content, list) or not all(isinstance(block, dict) for block in original_content): - raise ValueError("each message content value must be a list of content blocks") - - content = [block for block in original_content if "toolUse" not in block] - if len(content) == len(original_content): - break - if content: - messages[-1] = {**last, "content": content} - break - messages.pop() - - return messages - - -def _extract_prompt(payload: dict): - """Accept a caller-supplied message history or a plain prompt string.""" - if not isinstance(payload, dict): - raise ValueError("payload must be a JSON object") - if "messages" in payload: - return strip_trailing_tool_use(payload["messages"]) - prompt = payload.get("prompt", "") - if not isinstance(prompt, str): - raise ValueError("prompt must be a string") - return prompt - - -@app.entrypoint -async def invoke(payload, context): - log.info("Invoking Agent.....") - - session_id = getattr(context, "session_id", "default-session") - user_id = getattr(context, "user_id", "default-user") - agent = get_or_create_agent(session_id, user_id) - - prompt = _extract_prompt(payload) + tools=tools) - async for event in agent.stream_async(prompt): - if not isinstance(event, dict) or "event" not in event: - continue - cbs = event["event"].get("contentBlockStart") - if cbs is not None and not cbs.get("start"): - continue - yield event + async for event in agent.stream_async(prompt): + if not isinstance(event, dict) or "event" not in event: + continue + cbs = event["event"].get("contentBlockStart") + if cbs is not None and not cbs.get("start"): + continue + yield event + return app +app = create_app() if __name__ == "__main__": app.run() diff --git a/src/assets/templates/agent-python-strands/memory/session.py b/src/assets/templates/agent-python-strands/memory/session.py index 6372a2f68..439cb7620 100644 --- a/src/assets/templates/agent-python-strands/memory/session.py +++ b/src/assets/templates/agent-python-strands/memory/session.py @@ -1,5 +1,4 @@ import os -import uuid from typing import Optional from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig, RetrievalConfig @@ -8,15 +7,12 @@ MEMORY_ID = os.getenv("{{memoryEnvVarName}}") REGION = os.getenv("AWS_REGION") - def get_memory_session_manager( - session_id: Optional[str], actor_id: str + session_id: str, actor_id: str, ) -> Optional[AgentCoreMemorySessionManager]: if not MEMORY_ID: return None - session_id = session_id or uuid.uuid4().hex - retrieval_config = { f"/users/{actor_id}/facts": RetrievalConfig(top_k=3, relevance_score=0.5), f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5), diff --git a/src/assets/templates/agent-python-strands/parse.py b/src/assets/templates/agent-python-strands/parse.py new file mode 100644 index 000000000..de478ea65 --- /dev/null +++ b/src/assets/templates/agent-python-strands/parse.py @@ -0,0 +1,37 @@ +from typing import Any + +def _strip_trailing_tool_use(messages: Any) -> list[dict]: + """Strip toolUse blocks from the tail until the last message has none.""" + if not isinstance(messages, list): + raise ValueError("messages must be a list") + + messages = list(messages) + while messages: + last = messages[-1] + if not isinstance(last, dict): + raise ValueError("each message must be an object") + original_content = last.get("content", []) + if not isinstance(original_content, list) or not all(isinstance(block, dict) for block in original_content): + raise ValueError("each message content value must be a list of content blocks") + + content = [block for block in original_content if "toolUse" not in block] + if len(content) == len(original_content): + break + if content: + messages[-1] = {**last, "content": content} + break + messages.pop() + + return messages + +def parse_payload(payload: dict): + """Accept a caller-supplied message history or a plain prompt string.""" + actor_id = payload.get("actor_id", "default") + if not isinstance(payload, dict): + raise ValueError("payload must be a JSON object") + if "messages" in payload: + return strip_trailing_tool_use(payload["messages"]), actor_id + prompt = payload.get("prompt", "") + if not isinstance(prompt, str): + raise ValueError("prompt must be a string") + return prompt, actor_id From 14337b58749120c33d08a96636e93b4cdcae568a Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 02:33:08 +0000 Subject: [PATCH 02/15] docs(template): update readme for strands template --- .../templates/agent-python-minimal/README.md | 2 +- .../templates/agent-python-strands/README.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/assets/templates/agent-python-minimal/README.md b/src/assets/templates/agent-python-minimal/README.md index 905bb06cd..2093a041f 100644 --- a/src/assets/templates/agent-python-minimal/README.md +++ b/src/assets/templates/agent-python-minimal/README.md @@ -27,5 +27,5 @@ Environment variables for local development go in `agentcore/.env.local` ```bash agentcore project deploy -agentcore project invoke runtime --payload '{"prompt":"Hello!", "actor_id": "insert namespace here"}' +agentcore project invoke runtime --payload '{"prompt":"Hello!"}' ``` diff --git a/src/assets/templates/agent-python-strands/README.md b/src/assets/templates/agent-python-strands/README.md index eebff51c3..321ee6b1d 100644 --- a/src/assets/templates/agent-python-strands/README.md +++ b/src/assets/templates/agent-python-strands/README.md @@ -19,6 +19,20 @@ Validate invocation input before forwarding it to Strands. Keep plain prompts ty caller-supplied message history, retain `strip_trailing_tool_use()`, which normalizes the history tail before invoking the agent. +## Payload + +The Runtime accepts a JSON object. `parse_payload()` reads: + +- `prompt` (string) — a single user message. Used when `messages` is absent; defaults to `""`. +- `messages` (array) — a full conversation history (`[{"role": ..., "content": [...]}]`). Takes precedence over `prompt`; trailing `toolUse` blocks are stripped before the agent runs. +- `actor_id` (string, optional) — identifies the end user for Memory scoping (e.g. `/users/{actor_id}/facts`). Defaults to `"default"`. + +Provide either `prompt` or `messages`. The `session_id` is not in the body — it comes from the `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header (`context.session_id`); reuse it to continue a conversation. + +```json +{ "prompt": "What's the weather?", "actor_id": "user-123" } +``` + ## Environment Variables | Variable | Required | Description | From 5f9ed5e34b35645546f319a4fb23e43f27d61963 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 02:51:52 +0000 Subject: [PATCH 03/15] fix(templates): address function name change --- src/assets/templates/agent-python-strands/parse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/templates/agent-python-strands/parse.py b/src/assets/templates/agent-python-strands/parse.py index de478ea65..836f05eaa 100644 --- a/src/assets/templates/agent-python-strands/parse.py +++ b/src/assets/templates/agent-python-strands/parse.py @@ -26,11 +26,11 @@ def _strip_trailing_tool_use(messages: Any) -> list[dict]: def parse_payload(payload: dict): """Accept a caller-supplied message history or a plain prompt string.""" - actor_id = payload.get("actor_id", "default") if not isinstance(payload, dict): raise ValueError("payload must be a JSON object") + actor_id = payload.get("actor_id", "default") if "messages" in payload: - return strip_trailing_tool_use(payload["messages"]), actor_id + return _strip_trailing_tool_use(payload["messages"]), actor_id prompt = payload.get("prompt", "") if not isinstance(prompt, str): raise ValueError("prompt must be a string") From 4479b00925bc527983418123108ac3e45e1000eb Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 02:52:14 +0000 Subject: [PATCH 04/15] fix(templates): swap back toolname to remove _ for user facing messaging --- src/assets/templates/agent-python-strands/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/assets/templates/agent-python-strands/main.py b/src/assets/templates/agent-python-strands/main.py index e0d1aa27d..72f1e081b 100644 --- a/src/assets/templates/agent-python-strands/main.py +++ b/src/assets/templates/agent-python-strands/main.py @@ -13,11 +13,11 @@ # Define a simple function tool @tool -def _add_numbers(a: int, b: int) -> int: +def add_numbers(a: int, b: int) -> int: """Return the sum of two numbers""" return a + b -tools.append(_add_numbers) +tools.append(add_numbers) def _make_conversation_manager(): return NullConversationManager() @@ -30,7 +30,7 @@ def create_app(): async def invoke(payload, context): log.info("Invoking Agent.....") - session_id = getattr(context, "session_id", uuid.uuid4().hex) + session_id = getattr(context, "session_id", None) or uuid.uuid4().hex prompt, actor_id = parse_payload(payload) log.info(f"Invoking with session_id={session_id} and actor_id={actor_id}") From 1618dfedab6e53082f0aebf5add53e9146eff8d3 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:03:03 +0000 Subject: [PATCH 05/15] fix(templates): use static session-id default for dev --- src/assets/templates/agent-python-strands/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/templates/agent-python-strands/main.py b/src/assets/templates/agent-python-strands/main.py index 72f1e081b..fa809cb9f 100644 --- a/src/assets/templates/agent-python-strands/main.py +++ b/src/assets/templates/agent-python-strands/main.py @@ -30,7 +30,7 @@ def create_app(): async def invoke(payload, context): log.info("Invoking Agent.....") - session_id = getattr(context, "session_id", None) or uuid.uuid4().hex + session_id = getattr(context, "session_id", None) or "default-session" prompt, actor_id = parse_payload(payload) log.info(f"Invoking with session_id={session_id} and actor_id={actor_id}") From e05f51a41e7f0f8ed1d57a0f7fe727e6fd082e3e Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:17:25 +0000 Subject: [PATCH 06/15] refactor(templates): drop unused uuid import in strands main --- src/assets/templates/agent-python-strands/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/assets/templates/agent-python-strands/main.py b/src/assets/templates/agent-python-strands/main.py index fa809cb9f..7845acee0 100644 --- a/src/assets/templates/agent-python-strands/main.py +++ b/src/assets/templates/agent-python-strands/main.py @@ -1,5 +1,4 @@ from strands import Agent, tool -import uuid from strands.agent.conversation_manager.null_conversation_manager import NullConversationManager from bedrock_agentcore.runtime import BedrockAgentCoreApp from model.load import load_model From e00763d09ef1be6eca73fa06fbfd239aa2488a5e Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:17:32 +0000 Subject: [PATCH 07/15] fix(templates): validate actor_id is a string in parse_payload --- src/assets/templates/agent-python-strands/parse.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/assets/templates/agent-python-strands/parse.py b/src/assets/templates/agent-python-strands/parse.py index 836f05eaa..674164239 100644 --- a/src/assets/templates/agent-python-strands/parse.py +++ b/src/assets/templates/agent-python-strands/parse.py @@ -29,6 +29,8 @@ def parse_payload(payload: dict): if not isinstance(payload, dict): raise ValueError("payload must be a JSON object") actor_id = payload.get("actor_id", "default") + if not isinstance(actor_id, str): + raise ValueError("actor_id must be a string") if "messages" in payload: return _strip_trailing_tool_use(payload["messages"]), actor_id prompt = payload.get("prompt", "") From 4f2e82e6738c1edea2e90c6c0419e342cfff7f45 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:17:40 +0000 Subject: [PATCH 08/15] docs(templates): fix stale strip_trailing_tool_use reference --- src/assets/templates/agent-python-strands/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/templates/agent-python-strands/README.md b/src/assets/templates/agent-python-strands/README.md index 321ee6b1d..695df1356 100644 --- a/src/assets/templates/agent-python-strands/README.md +++ b/src/assets/templates/agent-python-strands/README.md @@ -16,8 +16,8 @@ file defines a Starlette ASGI app with the Strands Agent SDK running within. ## Input Validation Validate invocation input before forwarding it to Strands. Keep plain prompts typed as strings. If the app accepts a -caller-supplied message history, retain `strip_trailing_tool_use()`, which normalizes the history tail before -invoking the agent. +caller-supplied message history, retain `_strip_trailing_tool_use()` in `parse.py`, which normalizes the history tail +before invoking the agent. ## Payload From 5f5031de3d90ad38b9ebf05c99f7396768e6f7af Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:18:11 +0000 Subject: [PATCH 09/15] style(templates): remove trailing whitespace and fix Agent indentation --- src/assets/templates/agent-python-strands/main.py | 15 ++++++++------- .../agent-python-strands/memory/session.py | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/assets/templates/agent-python-strands/main.py b/src/assets/templates/agent-python-strands/main.py index 7845acee0..792348062 100644 --- a/src/assets/templates/agent-python-strands/main.py +++ b/src/assets/templates/agent-python-strands/main.py @@ -23,22 +23,23 @@ def _make_conversation_manager(): def create_app(): app = BedrockAgentCoreApp() - log = app.logger + log = app.logger @app.entrypoint async def invoke(payload, context): log.info("Invoking Agent.....") - session_id = getattr(context, "session_id", None) or "default-session" + session_id = getattr(context, "session_id", None) or "default-session" prompt, actor_id = parse_payload(payload) log.info(f"Invoking with session_id={session_id} and actor_id={actor_id}") agent = Agent( - model=load_model(), - session_manager=get_memory_session_manager(session_id, actor_id), - conversation_manager=_make_conversation_manager(), - system_prompt=DEFAULT_SYSTEM_PROMPT, - tools=tools) + model=load_model(), + session_manager=get_memory_session_manager(session_id, actor_id), + conversation_manager=_make_conversation_manager(), + system_prompt=DEFAULT_SYSTEM_PROMPT, + tools=tools, + ) async for event in agent.stream_async(prompt): if not isinstance(event, dict) or "event" not in event: diff --git a/src/assets/templates/agent-python-strands/memory/session.py b/src/assets/templates/agent-python-strands/memory/session.py index 439cb7620..aa8e46e5a 100644 --- a/src/assets/templates/agent-python-strands/memory/session.py +++ b/src/assets/templates/agent-python-strands/memory/session.py @@ -8,7 +8,7 @@ REGION = os.getenv("AWS_REGION") def get_memory_session_manager( - session_id: str, actor_id: str, + session_id: str, actor_id: str, ) -> Optional[AgentCoreMemorySessionManager]: if not MEMORY_ID: return None From 5c72326bd9fff7bfd3c520cd3561854a93798097 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:33:29 +0000 Subject: [PATCH 10/15] fix(templates): reject empty actor_id in parse_payload --- src/assets/templates/agent-python-strands/parse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/templates/agent-python-strands/parse.py b/src/assets/templates/agent-python-strands/parse.py index 674164239..a6ffcad9a 100644 --- a/src/assets/templates/agent-python-strands/parse.py +++ b/src/assets/templates/agent-python-strands/parse.py @@ -29,8 +29,8 @@ def parse_payload(payload: dict): if not isinstance(payload, dict): raise ValueError("payload must be a JSON object") actor_id = payload.get("actor_id", "default") - if not isinstance(actor_id, str): - raise ValueError("actor_id must be a string") + if not isinstance(actor_id, str) or not actor_id: + raise ValueError("actor_id must be a non-empty string") if "messages" in payload: return _strip_trailing_tool_use(payload["messages"]), actor_id prompt = payload.get("prompt", "") From c1053af99caad3cfc023830b29eae7b2e93ec86d Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:44:34 +0000 Subject: [PATCH 11/15] perf(templates): cache Agents per session/actor with lru_cache --- .../templates/agent-python-strands/main.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/assets/templates/agent-python-strands/main.py b/src/assets/templates/agent-python-strands/main.py index 792348062..ef5043f46 100644 --- a/src/assets/templates/agent-python-strands/main.py +++ b/src/assets/templates/agent-python-strands/main.py @@ -1,3 +1,5 @@ +from functools import lru_cache + from strands import Agent, tool from strands.agent.conversation_manager.null_conversation_manager import NullConversationManager from bedrock_agentcore.runtime import BedrockAgentCoreApp @@ -21,6 +23,17 @@ def add_numbers(a: int, b: int) -> int: def _make_conversation_manager(): return NullConversationManager() +@lru_cache(maxsize=128) +def _get_agent(session_id: str, actor_id: str) -> Agent: + """Cache Agents per session/actor to skip repeat identity fetches and keep turn history in dev.""" + return Agent( + model=load_model(), + session_manager=get_memory_session_manager(session_id, actor_id), + conversation_manager=_make_conversation_manager(), + system_prompt=DEFAULT_SYSTEM_PROMPT, + tools=tools, + ) + def create_app(): app = BedrockAgentCoreApp() log = app.logger @@ -33,13 +46,7 @@ async def invoke(payload, context): prompt, actor_id = parse_payload(payload) log.info(f"Invoking with session_id={session_id} and actor_id={actor_id}") - agent = Agent( - model=load_model(), - session_manager=get_memory_session_manager(session_id, actor_id), - conversation_manager=_make_conversation_manager(), - system_prompt=DEFAULT_SYSTEM_PROMPT, - tools=tools, - ) + agent = _get_agent(session_id, actor_id) async for event in agent.stream_async(prompt): if not isinstance(event, dict) or "event" not in event: From 3136597a8ce6f80c7229ba03e91009a7865e7b27 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:53:42 +0000 Subject: [PATCH 12/15] fix(templates): fall back to default for empty actor_id --- src/assets/templates/agent-python-strands/parse.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/assets/templates/agent-python-strands/parse.py b/src/assets/templates/agent-python-strands/parse.py index a6ffcad9a..ec17fb649 100644 --- a/src/assets/templates/agent-python-strands/parse.py +++ b/src/assets/templates/agent-python-strands/parse.py @@ -29,8 +29,10 @@ def parse_payload(payload: dict): if not isinstance(payload, dict): raise ValueError("payload must be a JSON object") actor_id = payload.get("actor_id", "default") - if not isinstance(actor_id, str) or not actor_id: - raise ValueError("actor_id must be a non-empty string") + if not isinstance(actor_id, str): + raise ValueError("actor_id must be a string") + if not actor_id: + actor_id = "default" if "messages" in payload: return _strip_trailing_tool_use(payload["messages"]), actor_id prompt = payload.get("prompt", "") From 283cef717349688919bda538a90c4b1c2b6dae59 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 03:54:09 +0000 Subject: [PATCH 13/15] test(project): add parse.py to strands manifest snapshot --- src/core/project/__snapshots__/manager.test.ts.snap | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/project/__snapshots__/manager.test.ts.snap b/src/core/project/__snapshots__/manager.test.ts.snap index a079f027d..228fe02f9 100644 --- a/src/core/project/__snapshots__/manager.test.ts.snap +++ b/src/core/project/__snapshots__/manager.test.ts.snap @@ -48,6 +48,7 @@ exports[`FsProjectManager.create snapshots the Strands project manifest and runt "app/agent_python_strands/memory/session.py", "app/agent_python_strands/model/__init__.py", "app/agent_python_strands/model/load.py", + "app/agent_python_strands/parse.py", "app/agent_python_strands/pyproject.toml", ], "memories": [ From 50f1eff137bd5750435f5c460f224f51ac864ce1 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 04:12:36 +0000 Subject: [PATCH 14/15] docs(templates): expand _get_agent docstring --- src/assets/templates/agent-python-strands/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/assets/templates/agent-python-strands/main.py b/src/assets/templates/agent-python-strands/main.py index ef5043f46..ffd55b88e 100644 --- a/src/assets/templates/agent-python-strands/main.py +++ b/src/assets/templates/agent-python-strands/main.py @@ -25,7 +25,9 @@ def _make_conversation_manager(): @lru_cache(maxsize=128) def _get_agent(session_id: str, actor_id: str) -> Agent: - """Cache Agents per session/actor to skip repeat identity fetches and keep turn history in dev.""" + """Given a session_id and actor_id, return or construct the corresponding Strands agent. + Note: caching helps avoid repeated identity fetches on non-bedrock model loads + and supports in-memory session management for local dev.""" return Agent( model=load_model(), session_manager=get_memory_session_manager(session_id, actor_id), From d5578346575675682445707c20cd9a03850699d3 Mon Sep 17 00:00:00 2001 From: Hweinstock Date: Tue, 15 Sep 2026 12:19:41 +0000 Subject: [PATCH 15/15] refactor(templates): rename actor_id payload field to actorId --- src/assets/templates/agent-python-strands/README.md | 4 ++-- src/assets/templates/agent-python-strands/parse.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/templates/agent-python-strands/README.md b/src/assets/templates/agent-python-strands/README.md index 695df1356..0414cf1be 100644 --- a/src/assets/templates/agent-python-strands/README.md +++ b/src/assets/templates/agent-python-strands/README.md @@ -25,12 +25,12 @@ The Runtime accepts a JSON object. `parse_payload()` reads: - `prompt` (string) — a single user message. Used when `messages` is absent; defaults to `""`. - `messages` (array) — a full conversation history (`[{"role": ..., "content": [...]}]`). Takes precedence over `prompt`; trailing `toolUse` blocks are stripped before the agent runs. -- `actor_id` (string, optional) — identifies the end user for Memory scoping (e.g. `/users/{actor_id}/facts`). Defaults to `"default"`. +- `actorId` (string, optional) — identifies the end user for Memory scoping (e.g. `/users/{actorId}/facts`). Defaults to `"default"`. Provide either `prompt` or `messages`. The `session_id` is not in the body — it comes from the `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header (`context.session_id`); reuse it to continue a conversation. ```json -{ "prompt": "What's the weather?", "actor_id": "user-123" } +{ "prompt": "What's the weather?", "actorId": "user-123" } ``` ## Environment Variables diff --git a/src/assets/templates/agent-python-strands/parse.py b/src/assets/templates/agent-python-strands/parse.py index ec17fb649..e0b63f729 100644 --- a/src/assets/templates/agent-python-strands/parse.py +++ b/src/assets/templates/agent-python-strands/parse.py @@ -28,9 +28,9 @@ def parse_payload(payload: dict): """Accept a caller-supplied message history or a plain prompt string.""" if not isinstance(payload, dict): raise ValueError("payload must be a JSON object") - actor_id = payload.get("actor_id", "default") + actor_id = payload.get("actorId", "default") if not isinstance(actor_id, str): - raise ValueError("actor_id must be a string") + raise ValueError("actorId must be a string") if not actor_id: actor_id = "default" if "messages" in payload: