Skip to content

feat(templates): add conversation history persistence to HTTP agent templates#794

Open
aidandaly24 wants to merge 1 commit intoaws:mainfrom
aidandaly24:fix/template-conversation-history
Open

feat(templates): add conversation history persistence to HTTP agent templates#794
aidandaly24 wants to merge 1 commit intoaws:mainfrom
aidandaly24:fix/template-conversation-history

Conversation

@aidandaly24
Copy link
Copy Markdown
Contributor

@aidandaly24 aidandaly24 commented Apr 8, 2026

Description

All four HTTP agent templates (Strands, OpenAI Agents, Google ADK, LangChain/LangGraph) were stateless per-invocation — each call to the agent started with zero conversation context. This meant users couldn't have multi-turn conversations where the agent remembers what was said in previous turns within the same session.

This PR adds conversation history persistence using each framework's built-in session management mechanism:

  • Strands: Per-session Agent cache keyed by context.session_id. Strands Agent accumulates messages internally in self.messages across stream_async() calls, so reusing the same instance per session gives natural multi-turn memory. This also fixes a conversation bleed bug where the previous single global _agent shared history across all sessions/users.
  • OpenAI Agents: SQLiteSession (from the SDK) passed via the session= parameter on Runner.run(). The session automatically loads prior history before inference and saves new turns after. Uses in-memory SQLite by default (:memory:).
  • Google ADK: Module-level InMemorySessionService with a get_or_create_session() helper that calls get_session() first and only create_session() if the session doesn't exist (avoids AlreadyExistsError on repeat calls). The module-level Runner shares the same service instance across invocations.
  • LangGraph: Module-level InMemorySaver checkpointer with thread_id mapped to context.session_id. The add_messages reducer on AgentState.messages automatically appends new HumanMessages to the existing conversation from the checkpoint. The graph is recreated per-invocation (to pick up dynamic MCP tools) but the checkpointer is shared, so state persists.

Also adds missing system prompts:

  • OpenAI Agents: Added instructions="You are a helpful assistant. Use tools when appropriate." to all Agent() constructors (previously had no system prompt at all).
  • LangGraph: Added prompt="You are a helpful assistant. Use tools when appropriate." to create_react_agent().

All conversation state is in-memory (best-effort) — it persists across invocations within the same runtime process but resets on cold starts. This is the correct default for starter templates; users can upgrade to durable backends (Strands FileSessionManager, OAI SQLiteSession with file path, ADK DatabaseSessionService, LangGraph persistent checkpointers) as needed.

Related Issue

Closes #808
Closes #809
Closes #810

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe):

Testing

How have you tested the change?

  • I ran npm run test:unit and npm run test:integ
  • I ran npm run typecheck
  • I ran npm run lint
  • If I modified src/assets/, I ran npm run test:update-snapshots and committed the updated snapshots

End-to-end deploy + invoke testing:

  • Strands (Bedrock): Deployed, invoked 3x — recall ✅, session isolation ✅
  • OpenAI Agents (OpenAI): Deployed, invoked 3x — recall ✅, session isolation ✅
  • LangGraph (Bedrock): Deployed, invoked 3x — recall ✅, session isolation ✅
  • Google ADK (Gemini): Deployed, code structurally verified — Gemini API quota prevented live invocation testing

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the
terms of your choice.

…nt 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.
@aidandaly24 aidandaly24 requested a review from a team April 8, 2026 20:59
@github-actions github-actions bot added the size/s PR size: S label Apr 8, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

Package Tarball

aws-agentcore-0.7.1.tgz

How to install

npm install https://github.com/aws/agentcore-cli/releases/download/pr-794-tarball/aws-agentcore-0.7.1.tgz

Copy link
Copy Markdown
Contributor

@notgitika notgitika left a comment

Choose a reason for hiding this comment

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

2 comments but LGTM otherwise

get_or_create_agent = agent_factory()
{{else}}
_agent = None
_agents = {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this dict grows unbounded and becomes heavy, every new session_id will add an Agent instance (with its full message history) that's never evicted. same applies to _sessions in the OpenAI template.

ADK and LangGraph don't have this issue since they use a single service/checkpointer instance.

I'm fine with this for a starter template but should we at least add a comment about this? We can also try to improve this by adding an LRU cache evictor? Is that overkill? 😓 Your call

Comment on lines 75 to 80
agent = Agent(
name="{{ name }}",
model="gpt-4.1",
mcp_servers=active_servers,
tools=[add_numbers]
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you added instructions everywhere else but seems like you missed it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s PR size: S

Projects

None yet

2 participants