Skip to content

fix(code_interpreter): partition session cache by caller key instead of AWS identity - #524

Draft
yonib05 wants to merge 3 commits into
strands-agents:mainfrom
yonib05:fix/code-interpreter-session-isolation
Draft

fix(code_interpreter): partition session cache by caller key instead of AWS identity#524
yonib05 wants to merge 3 commits into
strands-agents:mainfrom
yonib05:fix/code-interpreter-session-isolation

Conversation

@yonib05

@yonib05 yonib05 commented Jun 27, 2026

Copy link
Copy Markdown
Member

Description

AgentCoreCodeInterpreter keeps a module-level _session_mapping cache so that a new instance in a long-running process can reconnect to an existing AWS code interpreter session instead of recreating it. The cache was keyed only on the user-facing session_name, which is process-global, so two instances using the same session_name would reconnect to the same cached session regardless of who the caller was.

This change partitions the cache by an explicit, caller-supplied partition_key. The cache is keyed on (partition_key, session_name), and partition_key is bound at construction from operator-controlled input and is never read from a tool action, so a model-supplied session_name cannot reach across partitions.

A service typically runs under a single IAM identity while serving many callers, so an AWS-credential-derived key would collapse those callers together. Keying on a caller-supplied partition instead lets one identity host many isolated sessions:

  • partition_key defaults to a shared "default" partition, preserving the prior single-caller reconnect behavior.
  • Multi-tenant callers pass a distinct partition_key per principal — the authenticated principal/tenant id, or the agent session id (e.g. context.session_id) when one identity runs several isolated sessions.

The in-process cache is a reconnect convenience, not the isolation boundary. The real boundary is AWS-side: a session is reachable only by holding its server-issued, unguessable sessionId, and every operation is authorized against the interpreter's IAM execution role. Within a single process, partition_key is what keeps callers apart.

The public tool contract is unchanged: the session_name action field and existing constructor arguments behave as before; partition_key is a new optional argument.

Changes

  • Add an optional partition_key constructor argument and key _session_mapping on (partition_key, session_name) via the _scoped_key helper.
  • Bind partition_key at construction (default "default"); it is never taken from a tool action.
  • Remove the AWS-credential / STS GetCallerIdentity derived key (and its eager call at init); the cache key no longer depends on AWS credentials, so credential rotation cannot cause a reconnect miss.
  • Reframe the docstring and module comment to state the real boundary (server-issued sessionId + IAM execution role) and describe the cache as a per-process reconnect convenience partitioned by partition_key.

Testing

  • pytest tests/code_interpreter/ passes (59 tests).
  • ruff format / ruff check clean.
  • Regression tests:
    • default partition_key is the shared "default" partition,
    • different partitions produce distinct cache keys for the same session_name,
    • a session cached in one partition is not reachable from another partition via the same session_name (the multi-tenant case),
    • two instances sharing a partition_key reconnect to the same cached AWS session,
    • the cache key is independent of the boto session / credentials.

The AgentCoreCodeInterpreter reconnection cache (_session_mapping) was a
process-global map keyed only on the user-facing session_name. Two instances
configured with different AWS credentials but the same session_name would
reconnect to the same cached AWS session.

Key the cache per caller identity instead. An isolation key is derived from
the configured boto3 session's credentials (falling back to the session
object identity, or a shared default when no boto session is supplied), and
the module cache is keyed on (isolation_key, session_name). Instances sharing
the same identity (the common single-process, single-credential case) still
reconnect exactly as before; instances with different credentials no longer
reach each other's cached sessions through a shared session_name.

Also document that the in-process cache is a performance optimization and not
an isolation boundary: it only persists within one process and deployments
serving multiple distinct callers must use separate processes and distinct,
unguessable session names.

Adds regression tests covering per-identity key scoping and that a session
cached by one instance is not reachable from an instance with a different
identity via the same session_name.
Comment thread src/strands_tools/code_interpreter/agent_core_code_interpreter.py Outdated
)

def _resolve_isolation_key(self, boto_session: Optional[boto3.Session]) -> str:
"""Derive a rotation-stable cache-scoping key for the configured credentials.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works as an isolation key between AWS credentials. Services often run with service credentials and need isolation by the callers Session identifier. How can this be made generic, such that other partition keys can be used?

Comment thread tests/code_interpreter/test_agent_core_code_interpreter.py
@jsamuel1

Copy link
Copy Markdown

Consider the way session_id is used in the SessionManager functionality.

@yonib05 yonib05 changed the title fix(code_interpreter): scope session cache per caller identity fix(code_interpreter): partition session cache by caller key instead of AWS identity Jun 29, 2026
@yonib05

yonib05 commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

Reworked. The cache is now keyed on (partition_key, session_name), where partition_key is an explicit constructor arg bound from operator input and never read from a tool action — so a model-supplied session_name can't cross partitions.

Dropped the STS/credential-derived key: one IAM identity serves many callers, so keying on credentials collapsed them. Operators now pass the caller's session id as partition_key per request (like SessionManager gets session_id); defaults to "default" for single-caller back-compat.

Re: the warning — the map was never the boundary. Sessions are reachable only via the server-issued unguessable sessionId, authorized against the IAM execution role; partition_key just separates callers in-process. Docstring updated.

@yonib05
yonib05 marked this pull request as draft June 29, 2026 21:46
@yonib05
yonib05 requested a review from jsamuel1 July 2, 2026 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants