Skip to content

Add DakeraSession memory backend#3725

Open
ferhimedamine wants to merge 1 commit into
openai:mainfrom
ferhimedamine:feat/dakera-session
Open

Add DakeraSession memory backend#3725
ferhimedamine wants to merge 1 commit into
openai:mainfrom
ferhimedamine:feat/dakera-session

Conversation

@ferhimedamine

Copy link
Copy Markdown

Summary

Adds a DakeraSession memory backend that implements the Session protocol on top of a self-hosted Dakera memory server (a REST service for persistent agent memory). It follows the existing extension backends (RedisSession, MongoDBSession, DaprSession): a backend class under agents.extensions.memory, an optional dakera extra, tests, a runnable example, and docs.

Why it's a faithful Session:

  • Each conversation is stored in a per-session Dakera namespace derived from session_id ("{key_prefix}:{session_id}"), so histories are isolated and the same session_id always resolves to the same stored history — get_items/pop_item/clear_session are restart-safe and shareable across workers pointing at the same server.
  • Every item carries a monotonically increasing seq in its metadata, so ordering is preserved across writers regardless of server return order.
  • from_url(...) creates and owns an AsyncDakeraClient (closed by close()); you can also inject a client your app already manages.

Usage:

from agents import Agent, Runner
from agents.extensions.memory import DakeraSession

session = DakeraSession.from_url(
    session_id="user-123",
    base_url="http://localhost:3000",
    api_key="dk-...",
)
result = await Runner.run(Agent(name="Assistant"), "Hello", session=session)
await session.close()

Install: pip install "openai-agents[dakera]". Run a local server with the dakera-ai/dakera-deploy docker-compose stack (server + MinIO), which listens on port 3000.

Test plan

  • tests/extensions/memory/test_dakera_session.py — full suite (add/get roundtrip, chronological ordering across add calls, limit handling and SessionSettings default, pop_item LIFO + empty, clear_session, session isolation, custom key prefix, unicode/complex-item fidelity, corrupted-entry skipping, client lifecycle, and end-to-end Runner integration). It uses an in-memory fake Dakera client, so it runs with no network or live server.
  • tests/extensions/memory/test_memory_imports.py — extended to assert the friendly optional-extra error when dakera is missing (and the helper now supports top-level optional modules).
  • Verified locally with the repo's tooling: ruff format --check and ruff check (pinned ruff==0.9.2), mypy (repo config), and pytest for the new/affected tests — all green.

Issue number

N/A — new integration contribution.

Checks

  • I've added new tests, if relevant
  • I've run make format-check, make lint, make mypy, and the new tests
  • I've confirmed all verification steps pass
  • If using Codex, I've run /review before submitting this PR

Add a `DakeraSession` extension that implements the `Session` protocol on
top of a self-hosted Dakera memory server, following the existing
extension backends (Redis/MongoDB/Dapr): a backend class under
`agents.extensions.memory`, a `dakera` optional extra, tests, a runnable
example, and docs.

Each conversation is stored in a per-session Dakera namespace derived from
`session_id`, so history is isolated per conversation and restart-safe. A
monotonically increasing per-item sequence in metadata preserves ordering
for `get_items`/`pop_item` across writers.

- src/agents/extensions/memory/dakera_session.py: DakeraSession backend
- lazy export + `dakera` optional dependency wiring
- tests/extensions/memory/test_dakera_session.py: full suite with an
  in-memory fake client (no live server) + Runner integration
- test_memory_imports.py: cover the optional-extra error path (and support
  top-level optional modules in the helper)
- examples/memory/dakera_session_example.py + docs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1b63a52769

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return

async with self._lock:
seq = await self._ensure_next_seq()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allocate sequence numbers atomically across workers

When two workers keep DakeraSession instances for the same session_id, each instance caches _next_seq independently; after one worker writes a batch, another stale writer can reuse the same sequence numbers for its own batch. Because reads and pops sort primarily by seq, multi-item turns from different workers can be interleaved out of chronological order, corrupting the conversation history this backend is meant to share across workers. The sequence reservation needs to be server-side/atomic or avoid a per-instance cached counter.

Useful? React with 👍 / 👎.

Comment on lines +241 to +245
memory = memories.pop()
memory_id = memory.get("id")
if memory_id:
with contextlib.suppress(Exception):
await self._client.forget(self._namespace, memory_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not return an item before a confirmed delete

When two workers call pop_item() concurrently, both can fetch the same latest memory before either forget completes; this code suppresses delete failures and returns the item anyway, so a 404/race or transient Dakera error can make both callers believe they removed the same item while it may remain or be returned twice. pop_item should only return after a successful delete, or use an atomic delete-and-return operation if Dakera provides one.

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant