Skip to content

Commit b6dd2a6

Browse files
committed
feat(templates): add conversation history persistence to all HTTP agent templates
Each framework's HTTP template now maintains conversation history across invocations within the same session, using that framework's built-in session management mechanism: - Strands: per-session Agent cache keyed by session_id (Agent accumulates messages internally across stream_async calls) - OpenAI Agents: SQLiteSession passed to Runner.run() which automatically loads/saves conversation history per session - Google ADK: module-level InMemorySessionService with get_or_create_session pattern so the Runner accumulates events per session across invocations - LangGraph: module-level InMemorySaver checkpointer with thread_id mapped to session_id, using the add_messages reducer to append new messages Also adds missing system prompts to OpenAI Agents (instructions parameter) and LangGraph (prompt parameter) templates.
1 parent 6b6c0a5 commit b6dd2a6

5 files changed

Lines changed: 136 additions & 54 deletions

File tree

src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,21 +2225,38 @@ agent = Agent(
22252225
)
22262226
22272227
2228-
# Session and Runner
2229-
async def setup_session_and_runner(user_id, session_id):
2230-
ensure_credentials_loaded()
2231-
session_service = InMemorySessionService()
2232-
session = await session_service.create_session(
2228+
# Module-level session service and runner (preserves history across invocations)
2229+
_session_service = InMemorySessionService()
2230+
_runner = None
2231+
2232+
def get_or_create_runner():
2233+
global _runner
2234+
if _runner is None:
2235+
ensure_credentials_loaded()
2236+
_runner = Runner(
2237+
agent=agent,
2238+
app_name=APP_NAME,
2239+
session_service=_session_service,
2240+
)
2241+
return _runner
2242+
2243+
2244+
async def get_or_create_session(user_id, session_id):
2245+
session = await _session_service.get_session(
22332246
app_name=APP_NAME, user_id=user_id, session_id=session_id
22342247
)
2235-
runner = Runner(agent=agent, app_name=APP_NAME, session_service=session_service)
2236-
return session, runner
2248+
if session is None:
2249+
session = await _session_service.create_session(
2250+
app_name=APP_NAME, user_id=user_id, session_id=session_id
2251+
)
2252+
return session
22372253
22382254
22392255
# Agent Interaction
22402256
async def call_agent_async(query, user_id, session_id):
22412257
content = types.Content(role="user", parts=[types.Part(text=query)])
2242-
session, runner = await setup_session_and_runner(user_id, session_id)
2258+
runner = get_or_create_runner()
2259+
session = await get_or_create_session(user_id, session_id)
22432260
events = runner.run_async(
22442261
user_id=user_id, session_id=session.id, new_message=content
22452262
)
@@ -2524,6 +2541,7 @@ Thumbs.db
25242541
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/main.py should match snapshot 1`] = `
25252542
"import os
25262543
from langchain_core.messages import HumanMessage
2544+
from langgraph.checkpoint.memory import InMemorySaver
25272545
from langgraph.prebuilt import create_react_agent
25282546
from langchain.tools import tool
25292547
from bedrock_agentcore.runtime import BedrockAgentCoreApp
@@ -2556,6 +2574,9 @@ def add_numbers(a: int, b: int) -> int:
25562574
# Define a collection of tools used by the model
25572575
tools = [add_numbers]
25582576
2577+
# Module-level checkpointer preserves conversation history across invocations
2578+
_checkpointer = InMemorySaver()
2579+
25592580
25602581
@app.entrypoint
25612582
async def invoke(payload, context):
@@ -2573,15 +2594,22 @@ async def invoke(payload, context):
25732594
if mcp_client:
25742595
mcp_tools = await mcp_client.get_tools()
25752596
2576-
# Define the agent using create_react_agent
2577-
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools)
2597+
# Define the agent using create_react_agent (checkpointer is shared across invocations)
2598+
graph = create_react_agent(
2599+
get_or_create_model(),
2600+
tools=mcp_tools + tools,
2601+
prompt="You are a helpful assistant. Use tools when appropriate.",
2602+
checkpointer=_checkpointer,
2603+
)
25782604
25792605
# Process the user prompt
25802606
prompt = payload.get("prompt", "What can you help me with?")
2607+
session_id = getattr(context, "session_id", "default-session")
25812608
log.info(f"Agent input: {prompt}")
25822609
2583-
# Run the agent
2584-
result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]})
2610+
# Run the agent (checkpointer auto-loads/saves history per session)
2611+
config = {"configurable": {"thread_id": session_id}}
2612+
result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]}, config=config)
25852613
25862614
# Return result
25872615
output = result["messages"][-1].content
@@ -2942,7 +2970,7 @@ Thumbs.db
29422970
29432971
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/main.py should match snapshot 1`] = `
29442972
"import os
2945-
from agents import Agent, Runner, function_tool
2973+
from agents import Agent, Runner, SQLiteSession, function_tool
29462974
from bedrock_agentcore.runtime import BedrockAgentCoreApp
29472975
from model.load import load_model
29482976
{{#if hasGateway}}
@@ -2978,28 +3006,38 @@ def add_numbers(a: int, b: int) -> int:
29783006
return a + b
29793007
29803008
3009+
_sessions = {}
3010+
3011+
def get_session(session_id):
3012+
if session_id not in _sessions:
3013+
_sessions[session_id] = SQLiteSession(session_id)
3014+
return _sessions[session_id]
3015+
3016+
29813017
# Define the agent execution
2982-
async def main(query):
3018+
async def main(query, session):
29833019
ensure_credentials_loaded()
29843020
try:
29853021
{{#if hasGateway}}
29863022
if mcp_servers:
29873023
agent = Agent(
29883024
name="{{ name }}",
3025+
instructions="You are a helpful assistant. Use tools when appropriate.",
29893026
model="gpt-4.1",
29903027
mcp_servers=mcp_servers,
29913028
tools=[add_numbers]
29923029
)
2993-
result = await Runner.run(agent, query)
3030+
result = await Runner.run(agent, query, session=session)
29943031
return result
29953032
else:
29963033
agent = Agent(
29973034
name="{{ name }}",
3035+
instructions="You are a helpful assistant. Use tools when appropriate.",
29983036
model="gpt-4.1",
29993037
mcp_servers=[],
30003038
tools=[add_numbers]
30013039
)
3002-
result = await Runner.run(agent, query)
3040+
result = await Runner.run(agent, query, session=session)
30033041
return result
30043042
{{else}}
30053043
if mcp_servers:
@@ -3011,16 +3049,17 @@ async def main(query):
30113049
mcp_servers=active_servers,
30123050
tools=[add_numbers]
30133051
)
3014-
result = await Runner.run(agent, query)
3052+
result = await Runner.run(agent, query, session=session)
30153053
return result
30163054
else:
30173055
agent = Agent(
30183056
name="{{ name }}",
3057+
instructions="You are a helpful assistant. Use tools when appropriate.",
30193058
model="gpt-4.1",
30203059
mcp_servers=[],
30213060
tools=[add_numbers]
30223061
)
3023-
result = await Runner.run(agent, query)
3062+
result = await Runner.run(agent, query, session=session)
30243063
return result
30253064
{{/if}}
30263065
except Exception as e:
@@ -3034,9 +3073,11 @@ async def invoke(payload, context):
30343073
30353074
# Process the user prompt
30363075
prompt = payload.get("prompt", "What can you help me with?")
3076+
session_id = getattr(context, "session_id", "default-session")
3077+
session = get_session(session_id)
30373078
3038-
# Run the agent
3039-
result = await main(prompt)
3079+
# Run the agent (session automatically loads/saves conversation history)
3080+
result = await main(prompt, session)
30403081
30413082
# Return result
30423083
return {"result": result.final_output}
@@ -3346,19 +3387,18 @@ def agent_factory():
33463387
return get_or_create_agent
33473388
get_or_create_agent = agent_factory()
33483389
{{else}}
3349-
_agent = None
3390+
_agents = {}
33503391
3351-
def get_or_create_agent():
3352-
global _agent
3353-
if _agent is None:
3354-
_agent = Agent(
3392+
def get_or_create_agent(session_id):
3393+
if session_id not in _agents:
3394+
_agents[session_id] = Agent(
33553395
model=load_model(),
33563396
system_prompt="""
33573397
You are a helpful assistant. Use tools when appropriate.
33583398
""",
33593399
tools=tools
33603400
)
3361-
return _agent
3401+
return _agents[session_id]
33623402
{{/if}}
33633403
33643404
@@ -3371,7 +3411,8 @@ async def invoke(payload, context):
33713411
user_id = getattr(context, 'user_id', 'default-user')
33723412
agent = get_or_create_agent(session_id, user_id)
33733413
{{else}}
3374-
agent = get_or_create_agent()
3414+
session_id = getattr(context, 'session_id', 'default-session')
3415+
agent = get_or_create_agent(session_id)
33753416
{{/if}}
33763417
33773418
# Execute and format response

src/assets/python/http/googleadk/base/main.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,38 @@ def ensure_credentials_loaded():
5353
)
5454

5555

56-
# Session and Runner
57-
async def setup_session_and_runner(user_id, session_id):
58-
ensure_credentials_loaded()
59-
session_service = InMemorySessionService()
60-
session = await session_service.create_session(
56+
# Module-level session service and runner (preserves history across invocations)
57+
_session_service = InMemorySessionService()
58+
_runner = None
59+
60+
def get_or_create_runner():
61+
global _runner
62+
if _runner is None:
63+
ensure_credentials_loaded()
64+
_runner = Runner(
65+
agent=agent,
66+
app_name=APP_NAME,
67+
session_service=_session_service,
68+
)
69+
return _runner
70+
71+
72+
async def get_or_create_session(user_id, session_id):
73+
session = await _session_service.get_session(
6174
app_name=APP_NAME, user_id=user_id, session_id=session_id
6275
)
63-
runner = Runner(agent=agent, app_name=APP_NAME, session_service=session_service)
64-
return session, runner
76+
if session is None:
77+
session = await _session_service.create_session(
78+
app_name=APP_NAME, user_id=user_id, session_id=session_id
79+
)
80+
return session
6581

6682

6783
# Agent Interaction
6884
async def call_agent_async(query, user_id, session_id):
6985
content = types.Content(role="user", parts=[types.Part(text=query)])
70-
session, runner = await setup_session_and_runner(user_id, session_id)
86+
runner = get_or_create_runner()
87+
session = await get_or_create_session(user_id, session_id)
7188
events = runner.run_async(
7289
user_id=user_id, session_id=session.id, new_message=content
7390
)

src/assets/python/http/langchain_langgraph/base/main.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from langchain_core.messages import HumanMessage
3+
from langgraph.checkpoint.memory import InMemorySaver
34
from langgraph.prebuilt import create_react_agent
45
from langchain.tools import tool
56
from bedrock_agentcore.runtime import BedrockAgentCoreApp
@@ -32,6 +33,9 @@ def add_numbers(a: int, b: int) -> int:
3233
# Define a collection of tools used by the model
3334
tools = [add_numbers]
3435

36+
# Module-level checkpointer preserves conversation history across invocations
37+
_checkpointer = InMemorySaver()
38+
3539

3640
@app.entrypoint
3741
async def invoke(payload, context):
@@ -49,15 +53,22 @@ async def invoke(payload, context):
4953
if mcp_client:
5054
mcp_tools = await mcp_client.get_tools()
5155

52-
# Define the agent using create_react_agent
53-
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools)
56+
# Define the agent using create_react_agent (checkpointer is shared across invocations)
57+
graph = create_react_agent(
58+
get_or_create_model(),
59+
tools=mcp_tools + tools,
60+
prompt="You are a helpful assistant. Use tools when appropriate.",
61+
checkpointer=_checkpointer,
62+
)
5463

5564
# Process the user prompt
5665
prompt = payload.get("prompt", "What can you help me with?")
66+
session_id = getattr(context, "session_id", "default-session")
5767
log.info(f"Agent input: {prompt}")
5868

59-
# Run the agent
60-
result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]})
69+
# Run the agent (checkpointer auto-loads/saves history per session)
70+
config = {"configurable": {"thread_id": session_id}}
71+
result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]}, config=config)
6172

6273
# Return result
6374
output = result["messages"][-1].content

src/assets/python/http/openaiagents/base/main.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os
2-
from agents import Agent, Runner, function_tool
2+
from agents import Agent, Runner, SQLiteSession, function_tool
33
from bedrock_agentcore.runtime import BedrockAgentCoreApp
44
from model.load import load_model
55
{{#if hasGateway}}
@@ -35,28 +35,38 @@ def add_numbers(a: int, b: int) -> int:
3535
return a + b
3636

3737

38+
_sessions = {}
39+
40+
def get_session(session_id):
41+
if session_id not in _sessions:
42+
_sessions[session_id] = SQLiteSession(session_id)
43+
return _sessions[session_id]
44+
45+
3846
# Define the agent execution
39-
async def main(query):
47+
async def main(query, session):
4048
ensure_credentials_loaded()
4149
try:
4250
{{#if hasGateway}}
4351
if mcp_servers:
4452
agent = Agent(
4553
name="{{ name }}",
54+
instructions="You are a helpful assistant. Use tools when appropriate.",
4655
model="gpt-4.1",
4756
mcp_servers=mcp_servers,
4857
tools=[add_numbers]
4958
)
50-
result = await Runner.run(agent, query)
59+
result = await Runner.run(agent, query, session=session)
5160
return result
5261
else:
5362
agent = Agent(
5463
name="{{ name }}",
64+
instructions="You are a helpful assistant. Use tools when appropriate.",
5565
model="gpt-4.1",
5666
mcp_servers=[],
5767
tools=[add_numbers]
5868
)
59-
result = await Runner.run(agent, query)
69+
result = await Runner.run(agent, query, session=session)
6070
return result
6171
{{else}}
6272
if mcp_servers:
@@ -68,16 +78,17 @@ async def main(query):
6878
mcp_servers=active_servers,
6979
tools=[add_numbers]
7080
)
71-
result = await Runner.run(agent, query)
81+
result = await Runner.run(agent, query, session=session)
7282
return result
7383
else:
7484
agent = Agent(
7585
name="{{ name }}",
86+
instructions="You are a helpful assistant. Use tools when appropriate.",
7687
model="gpt-4.1",
7788
mcp_servers=[],
7889
tools=[add_numbers]
7990
)
80-
result = await Runner.run(agent, query)
91+
result = await Runner.run(agent, query, session=session)
8192
return result
8293
{{/if}}
8394
except Exception as e:
@@ -91,9 +102,11 @@ async def invoke(payload, context):
91102

92103
# Process the user prompt
93104
prompt = payload.get("prompt", "What can you help me with?")
105+
session_id = getattr(context, "session_id", "default-session")
106+
session = get_session(session_id)
94107

95-
# Run the agent
96-
result = await main(prompt)
108+
# Run the agent (session automatically loads/saves conversation history)
109+
result = await main(prompt, session)
97110

98111
# Return result
99112
return {"result": result.final_output}

0 commit comments

Comments
 (0)