Skip to content

Commit dcf9cf7

Browse files
authored
Add SQLAlchemy session backend for conversation history management (#1357)
Resolves #1328
1 parent 2b8c408 commit dcf9cf7

File tree

11 files changed

+2803
-1810
lines changed

11 files changed

+2803
-1810
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import asyncio
2+
3+
from agents import Agent, Runner
4+
from agents.extensions.memory.sqlalchemy_session import SQLAlchemySession
5+
6+
7+
async def main():
8+
# Create an agent
9+
agent = Agent(
10+
name="Assistant",
11+
instructions="Reply very concisely.",
12+
)
13+
14+
# Create a session instance with a session ID.
15+
# This example uses an in-memory SQLite database.
16+
# The `create_tables=True` flag is useful for development and testing.
17+
session = SQLAlchemySession.from_url(
18+
"conversation_123",
19+
url="sqlite+aiosqlite:///:memory:",
20+
create_tables=True,
21+
)
22+
23+
print("=== SQLAlchemySession Example ===")
24+
print("The agent will remember previous messages automatically.\n")
25+
26+
# First turn
27+
print("User: What city is the Golden Gate Bridge in?")
28+
result = await Runner.run(
29+
agent,
30+
"What city is the Golden Gate Bridge in?",
31+
session=session,
32+
)
33+
print(f"Assistant: {result.final_output}\n")
34+
35+
# Second turn - the agent will remember the previous conversation
36+
print("User: What state is it in?")
37+
result = await Runner.run(
38+
agent,
39+
"What state is it in?",
40+
session=session,
41+
)
42+
print(f"Assistant: {result.final_output}\n")
43+
44+
print("=== Conversation Complete ===")
45+
46+
47+
if __name__ == "__main__":
48+
# To run this example, you need to install the sqlalchemy extras:
49+
# pip install "agents[sqlalchemy]"
50+
asyncio.run(main())

examples/realtime/app/server.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import logging
55
import struct
66
from contextlib import asynccontextmanager
7-
from typing import TYPE_CHECKING, Any, assert_never
7+
from typing import TYPE_CHECKING, Any
88

99
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
1010
from fastapi.responses import FileResponse
1111
from fastapi.staticfiles import StaticFiles
12+
from typing_extensions import assert_never
1213

1314
from agents.realtime import RealtimeRunner, RealtimeSession, RealtimeSessionEvent
1415

examples/realtime/cli/demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self) -> None:
5252
# Audio output state for callback system
5353
self.output_queue: queue.Queue[Any] = queue.Queue(maxsize=10) # Buffer more chunks
5454
self.interrupt_event = threading.Event()
55-
self.current_audio_chunk: np.ndarray | None = None # type: ignore
55+
self.current_audio_chunk: np.ndarray[Any, np.dtype[Any]] | None = None
5656
self.chunk_position = 0
5757

5858
def _output_callback(self, outdata, frames: int, time, status) -> None:

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ voice = ["numpy>=2.2.0, <3; python_version>='3.10'", "websockets>=15.0, <16"]
3838
viz = ["graphviz>=0.17"]
3939
litellm = ["litellm>=1.67.4.post1, <2"]
4040
realtime = ["websockets>=15.0, <16"]
41+
sqlalchemy = ["SQLAlchemy>=2.0", "asyncpg>=0.29.0"]
4142

4243
[dependency-groups]
4344
dev = [
@@ -63,6 +64,7 @@ dev = [
6364
"mkdocs-static-i18n>=1.3.0",
6465
"eval-type-backport>=0.2.2",
6566
"fastapi >= 0.110.0, <1",
67+
"aiosqlite>=0.21.0",
6668
]
6769

6870
[tool.uv.workspace]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
"""Session memory backends living in the extensions namespace.
3+
4+
This package contains optional, production-grade session implementations that
5+
introduce extra third-party dependencies (database drivers, ORMs, etc.). They
6+
conform to the :class:`agents.memory.session.Session` protocol so they can be
7+
used as a drop-in replacement for :class:`agents.memory.session.SQLiteSession`.
8+
"""
9+
from __future__ import annotations
10+
11+
from .sqlalchemy_session import SQLAlchemySession # noqa: F401
12+
13+
__all__: list[str] = [
14+
"SQLAlchemySession",
15+
]

0 commit comments

Comments
 (0)