Task 4 · 8 tasks
Your agent on AgentCore Runtime
Deploy the Phase 1 orchestrator, wired to Gateway, Memory and LiteLLM. This is where you code.
The “Agent Deployment and Tool Access” challenge
Everything is in place: identity, a tool server, a Gateway and memory. Now Alice's executive assistant itself goes live. It's the Phase 1 orchestrator with three swaps: tools come from the Gateway, sessions come from AgentCore Memory, and the human approval prompt becomes a read-only guard.
What the platform provisions for you
uv run bootcamp.py up 4- Your agent from
phase2/app/agent/, deployed to AgentCore Runtime (HTTP protocol) with JWT inbound auth - Environment variables so the code has no hardcoded ids:
GATEWAY_URL,MEMORY_ID,MEMORY_STRATEGY_ID,CREDENTIAL_PROVIDER_NAME,MODEL_IDandLITELLM_BASE_URL - An execution role
awsworkshop-<name>-agent-runtime, which the LiteLLM gateway maps to your budget. No API key is deployed anywhere
What you do as a developer
Read the entrypoint
phase2/app/agent/agent.py@app.entrypoint @requires_access_token(scopes=[OAUTH_SCOPE], provider_name=CREDENTIAL_PROVIDER_NAME, auth_flow="M2M") def invoke(payload: dict, context: RequestContext, access_token: str) -> dict: actor_id = actor_from(context) gateway = MCPClient( lambda: streamable_http_client( GATEWAY_URL, http_client=create_mcp_http_client(headers={"Authorization": f"Bearer {access_token}"}) ) ) sandbox_tools = optional_tools() with gateway: orchestrator = Agent( name="Executive Assistant", model=make_model(), system_prompt=orchestrator_prompt(actor_id, sandbox_tools), tools=[*build_specialists(gateway.list_tools_sync()), *sandbox_tools], session_manager=memory_session_manager(context.session_id or "default_session", actor_id), callback_handler=None, ) result = orchestrator(payload.get("prompt", "")) return {"response": str(result)}@requires_access_tokenfetches a Gateway token through AgentCore Identity. Model calls use the same keyless gateway client as Phase 1:phase2/app/agent/agent.pyLITELLM_BASE_URL = os.environ["LITELLM_BASE_URL"] def make_model() -> OpenAIModel: """All model calls go through the LiteLLM gateway, keyless: the runtime's own IAM role identifies you.""" return litellm_gateway.make_model(MODEL_ID, LITELLM_BASE_URL)Talk to your deployed agent
terminaluv run bootcamp.py invoke "How many employees are in Engineering?" --actor alice-chen uv run bootcamp.py invoke "What is the weather in Seattle?" --actor alice-chenProve memory works across sessions and users
Each
invokewithout--sessionstarts a new session.terminaluv run bootcamp.py invoke "Remember that I prefer reports as Python code." --actor alice-chen # give extraction about a minute uv run bootcamp.py invoke "How do I like my reports?" --actor alice-chen uv run bootcamp.py invoke "How do I like my reports?" --actor jordan-leeAlice gets her preference back; Jordan doesn't.
Personalise the assistant
Challenge
Change
orchestrator_promptso the assistant greets the user by name, answers in short bullet points, and politely declines requests unrelated to DataStream.Hint 1
The prompt is built per request and already receives
actor_id. Keep the routing rules; add style and scope rules.Hint 2
Be explicit about the refusal (“If a request is not about DataStream, say so in one sentence”). Redeploy with
uv run bootcamp.py deployand test with an off-topic question.Solution
phase2/app/agent/agent.py (starting point)def orchestrator_prompt(actor_id: str, sandbox_tools: list) -> str: """System prompt for the orchestrator, plus one hint per enabled optional sandbox tool.""" return ( f"You are CEO Alice's executive assistant at DataStream Corp, talking to {actor_id}.\n" "Route database questions to data_agent and weather questions to weather_agent; " "answer simple company questions directly. Use what you remember about the user.\n" f"{prompt_hints(sandbox_tools)}" ).strip()one possible solutiondef orchestrator_prompt(actor_id: str, sandbox_tools: list) -> str: return ( f"You are CEO Alice's executive assistant at DataStream Corp, talking to {actor_id}. " "Greet them by name. Answer in at most five short bullet points.\n" "Route database questions to data_agent and weather questions to weather_agent; " "answer simple company questions directly. Use what you remember about the user.\n" "If a request is not about DataStream, decline politely in one sentence.\n" f"{prompt_hints(sandbox_tools)}" ).strip()Add a tool
Challenge
Alice asks “what's today's date?” and the agent guesses. Give the orchestrator a tool that returns the current date, and tell it when to use it.
Hint 1
Any function with
@tool, type hints and a docstring is a tool. Add it to the orchestrator'stoolslist next to the specialists.Hint 2
Use
datetime.date.today().isoformat().agent.pyonly importsos, so addimport datetimeat the top. Mention the tool in the prompt.Solution
phase2/app/agent/agent.pyimport datetime @tool def today() -> str: """Return today's date (ISO 8601). Use it for any question about dates or deadlines.""" return datetime.date.today().isoformat() # in invoke(): tools=[*build_specialists(gateway.list_tools_sync()), *sandbox_tools, today],Experiments
- Set
MODEL_ID=claude-sonnet-5-5,deploy, and compare answers and cost (uv run bootcamp.py llm). - Ask for something destructive:
invoke "Delete employee 5". TheReadOnlyGuardHookcancels the call and the agent explains why. Keep this in mind for Task 7.
- Set
Deploy and re-test
deployrebuilds your code and re-applies the current stage with theMODEL_IDfrom.env. Then talk to it and re-run the stage checks:terminaluv run bootcamp.py deploy uv run bootcamp.py invoke "What is today's date, and how many people work in Sales?" --actor alice-chen uv run bootcamp.py invoke "What is the capital of France?" --actor alice-chen uv run bootcamp.py test --only 4
Check your work
uv run bootcamp.py test --only 4
uv run bootcamp.py invoke "How many employees are in Engineering?" --actor alice-chenPasses when the agent answers, a fact told in one session is recalled in another, and the model spend landed on your own LiteLLM budget.
Under the hood
The agent runs as an HTTP-protocol runtime: BedrockAgentCoreApp serves /invocations and the decorated function receives the JSON payload plus a RequestContext (session id, headers). The runtime sticks a session to one micro-VM, so consecutive calls in a session stay warm. Outbound, the agent's workload identity asks AgentCore Identity for an M2M token (credential provider), uses it to open an MCP session with the Gateway, and sends model calls to LiteLLM with a presigned STS identity from the runtime's execution role. The gateway maps awsworkshop-<name>-agent-runtime to your budgeted key, forwards to Bedrock and debits your budget.