Optional add-on
Optional: Code Interpreter
Give the agent a sandboxed Python environment so it computes answers instead of guessing at arithmetic.
The “Numbers, Not Prose” request
Alice wants more than counts: “What's the average and median team size per department?” SQL gets the rows; models are unreliable at arithmetic. AgentCore Code Interpreter runs model-written Python in an isolated sandbox, so the agent can compute without touching your runtime.
What the platform provisions for you
ENABLE_CODE_INTERPRETER=trueuv run bootcamp.py deploy- Session permissions for your agent role on the AWS-managed
aws.codeinterpreter.v1 - The
run_pythontool, handed to your orchestrator automatically
Flags default to false and need stage 4 or higher. uv run bootcamp.py status shows CODE_INTERPRETER_ENABLED and BROWSER_ENABLED.
What you do as a developer
Read the tool
phase2/app/agent/sandbox_tools.py@tool def run_python(code: str) -> str: """Execute Python code in a secure AgentCore Code Interpreter sandbox and return its output. Use it for calculations, statistics and data transformations. print() every value you need to see. Args: code: Python source code to run. """ with code_session(REGION, identifier=CODE_INTERPRETER_ID) as client: return stream_text(client.execute_code(code))[:OUTPUT_LIMIT]One call, one fresh sandbox session:
code_sessionfrombedrock_agentcore.toolsstarts it and stops it when the block exits.terminaluv run bootcamp.py invoke "Use the code interpreter to compute the mean and median of 3, 5, 10 and 22." --actor alice-chenAdd a data-analysis specialist
Challenge
The orchestrator can call
run_python, but it has no data. Inphase2/app/agent/agent.py, add ananalysis_agentspecialist that fetches rows through the Gateway and then computes withrun_python, and register it with the orchestrator.Where: edit
phase2/app/agent/agent.pyin place, runuv run bootcamp.py deploy(~1.5 min), then check withuv run bootcamp.py invoke "What is the average and median team size per department?" --actor alice-chen --stream: the tool line shows[calling analysis_agent].Hint 1
It's the agents-as-tools pattern again. Look at
data_agentinbuild_specialists: a@toolthat builds anAgent. AgentCore Code Interpreter docs.Hint 2
Import
run_pythonfromsandbox_toolsand give the specialisttools=[*search_tools(gateway, DATA_TOOLS), run_python]. Tell it: query first, then compute, print every result, report numbers rather than code. Return it frombuild_specialists.Solution
phase2/app/agent/agent.py (adds analysis_agent) · replace build_specialists()def build_specialists(gateway: MCPClient, results: list[str]) -> list: """The data and weather specialists as tools; each searches the Gateway for its tools, then records its answer.""" @tool def data_agent(query: str) -> str: """Query and analyze the DataStream Corp database (employees, departments, projects). Args: query: A database or data analysis question. """ agent = Agent( model=make_model(), system_prompt=f"{DATA_PROMPT}\n{guardrail.prompt_hint()}", tools=search_tools(gateway, DATA_TOOLS), hooks=[ReadOnlyGuardHook(), *guardrail.hooks()], callback_handler=None, ) return consult(agent, query, "data") @tool def weather_agent(query: str) -> str: """Get the weather forecast for a US location (National Weather Service); says so for non-US places. Args: query: A weather-related question, including the place. """ agent = Agent( model=make_model(), system_prompt=nws_weather.WEATHER_PROMPT, hooks=guardrail.hooks(), tools=search_tools(gateway, WEATHER_TOOLS), callback_handler=None, ) return consult(agent, query, "weather") @tool def analysis_agent(question: str) -> str: """Analyse DataStream data with Python: statistics, distributions, trends. Use beyond one SQL answer. Args: question: The analysis to perform. """ from sandbox_tools import run_python agent = Agent( model=make_model(), system_prompt=( "You are a data analyst. First fetch the rows you need with the database tool, " "then compute with run_python (print every result). Report numbers, not code." ), tools=[*search_tools(gateway, DATA_TOOLS), run_python], hooks=[ReadOnlyGuardHook(), *guardrail.hooks()], callback_handler=None, ) return consult(agent, question, "analysis") def consult(agent: Agent, query: str, specialist: str) -> str: """Ask a specialist; an exception (e.g. the gateway's 502 after its retries) becomes an explicit failure.""" try: answer = str(agent(query)) except Exception as error: answer = SPECIALIST_FAILED.format(specialist=specialist, reason=f"{type(error).__name__}: {error}") return remember(answer, specialist) def remember(answer: str, specialist: str = "requested") -> str: """Record a specialist's answer for `final_answer`; an empty one is recorded as an explicit failure.""" answer = answer.strip() or SPECIALIST_FAILED.format(specialist=specialist, reason="it returned an empty answer") results.append(answer) return answer return [data_agent, weather_agent, analysis_agent]Then add a routing line to
orchestrator_prompt, e.g."Route statistics and calculations over company data to analysis_agent.\n"after the data_agent/weather_agent line.Deploy and ask for analysis
terminaluv run bootcamp.py deploy uv run bootcamp.py invoke "What is the average and median team size per department?" --actor alice-chenExperiments
- Look at the trace (
uv run bootcamp.py traces): how manyrun_pythoncalls did one question take, and how long did each sandbox session last? - Each call gets a fresh session. What does that mean for code that builds on a previous call's variables?
- What could go wrong if model-written code ran inside your runtime instead?
See it in the console: AgentCore → Observability: the trace of that question, with each
run_pythonspan and its duration.- Look at the trace (
Check your work
With the flag on, test --only 4 adds a code interpreter tool check. It sends exactly this prompt:
uv run bootcamp.py invoke 'DataStream analytics needs an exact checksum for the quarterly report: use the run_python tool to run `print(sum(range(12345)) % 65521)` and reply with the checksum it prints.' --actor alice-chenIt passes when the answer contains 57938 (thousands separators such as 57,938 are fine): a number the model can't produce reliably without running the code.
uv run bootcamp.py test --only 4[PASS] stage 4 ...
[PASS] stage 4 code interpreter tool: The script prints 57938.The check asks as a fresh actor in a fresh session and retries once on an empty answer. The prompt is framed as DataStream work so a Task 4 “decline off-topic requests” prompt keeps it; if your prompt still refuses it, loosen the scope rule.
This check depends on the model's wording, which varies from run to run. If it fails, rerun it once; check with uv run bootcamp.py traces --args which tool ran (the trace, not the wording, says whether the agent did the work); if the shipped agent does the same (git stash, deploy, rerun, git stash pop, deploy), it's the model, not your change.
Under the hood
Both tools use the AWS-managed built-ins aws.codeinterpreter.v1 and aws.browser.v1. Every call starts a fresh, isolated sandbox session and stops it afterwards, so nothing leaks between participants or requests. When a flag is on, your agent role gets only the session permissions it needs, in the inline policy awsworkshop-<you>-sandbox-tools; the platform sets CODE_INTERPRETER_ENABLED / BROWSER_ENABLED on the runtime, and optional_tools() plus prompt_hints() hand the tools to the orchestrator with a one-line usage hint each.
def optional_tools() -> list:
"""The sandbox tools this runtime is configured for (empty when both capabilities are off)."""
tools = []
if capability_enabled("CODE_INTERPRETER_ENABLED"):
tools.append(run_python)
if capability_enabled("BROWSER_ENABLED"):
tools.append(browse_web)
return tools