Skip to content

feat(memory): add DakeraMemory for persistent cross-session agent memory - #1567

Open
ferhimedamine wants to merge 1 commit into
i-am-bee:mainfrom
ferhimedamine:feat/dakera-memory
Open

feat(memory): add DakeraMemory for persistent cross-session agent memory#1567
ferhimedamine wants to merge 1 commit into
i-am-bee:mainfrom
ferhimedamine:feat/dakera-memory

Conversation

@ferhimedamine

@ferhimedamine ferhimedamine commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Adds DakeraMemory — a BaseMemory implementation that gives BeeAI agents persistent, semantically-searchable cross-session memory backed by a self-hosted Dakera server. It slots in exactly where TokenMemory / SlidingMemory do, so any agent can gain long-term recall by swapping its memory instance.

Closes #1546

What this PR adds

typescript/src/memory/dakeraMemory.ts (440 lines) — full BaseMemory implementation:

  • add(message) → persists the message to Dakera and enriches the context window with the top-K decay-weighted recalled memories
  • delete(message) → removes from the in-session list
  • reset() → clears the in-session window (the Dakera store is unaffected)
  • recall(query, topK?) / forgetSession() → explicit recall + per-session cleanup helpers
  • createSnapshot / loadSnapshot — BeeAI serializer support (the API key is never serialized)
  • static { this.register() } — enrolled with the framework serializer, matching the TokenMemory / SlidingMemory pattern

typescript/src/memory/dakeraMemory.test.ts (243 lines) — 10 Vitest unit tests, all HTTP-mocked (no live server required).

How it works

import { DakeraMemory } from "beeai-framework/memory/dakeraMemory";
import { ReActAgent } from "beeai-framework/agents/react/agent";

const memory = new DakeraMemory({
  url: "http://localhost:3000",
  apiKey: "dk-...",      // optional
  agentId: "bee-agent",
  topK: 5,               // past memories to recall per turn
});

const agent = new ReActAgent({ llm, tools: [], memory });
await agent.run({ prompt: "What did I ask you last time?" });

Run Dakera locally with the public dakera-ai/dakera-deploy docker-compose (the server needs the object store the compose provisions — a bare docker run of the image is not enough):

git clone https://github.com/dakera-ai/dakera-deploy
cd dakera-deploy && docker compose up -d   # server listens on :3000

API mapping

DakeraMemory Dakera endpoint
add() (persist=true) POST /v1/memory/store
add() recall injection / recall() POST /v1/memory/recall
forgetSession() POST /v1/memory/forget

Endpoints were verified against the Dakera server source.

Design decisions

  • persist: false — read-only mode (recalls but never writes). Useful for replaying prior conversations without polluting the store.
  • API key never serializedcreateSnapshot() omits apiKey; on deserialization it is dropped and must be re-supplied for write access.
  • Non-fatal outages — Dakera store/recall failures are logged via the framework Logger (warn) and the agent continues; the in-session window always retains the current turn.
  • Recalled memories as a single system message — injected with meta: { __dakera_injected: true } so it can be filtered; prior injections are purged before fresh ones (prevents unbounded growth), including on a no-hit recall.

Testing

TypeScript-only change (no Python).

  • 10 Vitest unit tests pass (yarn vitest run src/memory/dakeraMemory.test.ts)
  • yarn tsc --noEmit, yarn eslint, yarn prettier --check all clean
  • yarn tsup build emits dist/memory/dakeraMemory.{js,cjs,d.ts} — importable via the beeai-framework/memory/* subpath export, like every built-in memory
  • Store failure (HTTP 500) is non-fatal — the agent continues
  • serialize()fromSerialized() round-trip verified with verifyDeserialization; a secret-leak regression test asserts the API key never appears in the checkpoint
  • Commit is signed off (Signed-off-by) — DCO check green

Review follow-ups (addressed)

Incorporates @Tomas2D's review from the prior revision:

  • Test runner — rewritten to Vitest globals + verifyDeserialization from @tests/e2e/utils.js; dropped @jest/globals.
  • 🔴 Secret leakapiKey removed from createSnapshot()/loadSnapshot(); added a regression test.
  • Convention driftconsole.warn → framework Logger; the class builds to dist/ and is importable via the standard memory/* subpath.
  • Endpoint — recall maps to POST /v1/memory/recall (the decay-weighted agent recall endpoint) instead of /v1/memory/search.
  • Docs — corrected the port to :3000 and pointed setup at dakera-deploy; clarified the change is TypeScript-only.

Also folded in the Gemini review findings (read-only injection, purge-on-no-hit, createdAt type guard, test placeholders).

Open question for maintainers

This adds a first-party adapter under core src/memory/. If the team would prefer community/third-party adapters to live in a contrib location instead, I'm happy to relocate it — just let me know.


Continues #1547 (same branch, same two files). The original was auto-closed after an accidental branch force-push dropped its shared history with main; history is restored and the commit is signed off here. #1547 is not reopenable because GitHub pins a closed PR to its recorded head.

@ferhimedamine
ferhimedamine requested a review from a team as a code owner July 16, 2026 18:37
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 16, 2026
@github-actions github-actions Bot added the typescript Typescript related functionality label Jul 16, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces the DakeraMemory class, which provides persistent, vector-based memory for BeeAI agents by integrating with the Dakera REST API. The implementation includes methods for storing messages, recalling semantically relevant memories, and managing session-based memory deletion. I have reviewed the code and identified a potential type safety issue regarding the serialization of the createdAt metadata field, for which I have provided a suggested fix.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread typescript/src/memory/dakeraMemory.ts Outdated
@ferhimedamine

Copy link
Copy Markdown
Author

@Tomas2D — continuing our review from #1547 here (that PR got auto-closed after an accidental force-push dropped its shared history with main, and GitHub won't reopen a PR whose recorded head lost its common ancestor). Same branch, same two files, nothing lost.

Everything from your last review is addressed:

  • Tests on Vitest (globals + verifyDeserialization), @jest/globals dropped
  • 🔴 Secret leak fixedapiKey excluded from createSnapshot()/loadSnapshot(), with a regression test asserting it never appears in the checkpoint
  • console.warn → framework Logger
  • Recall now maps to POST /v1/memory/recall (decay-weighted agent recall), not /search
  • Docs corrected to port :3000 + dakera-deploy; TypeScript-only

The commit is now signed off, so DCO is green. The only thing still pending is the fork pull_request workflow (commitlint / Lint-Build-Test) — it needs a maintainer approve-and-run; it'll pass on the same sign-off DCO already accepts.

I also left an open question in the description about whether a first-party src/memory/ adapter is the right home vs. a community/contrib location — happy to relocate if you'd prefer. Thanks for the thorough review!

A BaseMemory adapter backed by a self-hosted Dakera server: persists each
message and injects top-K decay-weighted recalled memories into the context
window. Read-only (persist=false), API key excluded from snapshots, non-fatal
outages via the framework Logger, and exposed via the beeai-framework/memory
subpath. Endpoints verified against the Dakera server source
(/v1/memory/store, /recall, /forget).

Rebased onto main as a single clean commit (drops an earlier merge commit).

Signed-off-by: Mohamed Amine Ferhi <ferhi.med.amine@gmail.com>
@ferhimedamine

Copy link
Copy Markdown
Author

@Tomas2D this is continuation of pr #1547 (due to git issue, old one got closed, where you already made review) thx

@ferhimedamine

Copy link
Copy Markdown
Author

@Tomas2D kind reminder 🙏 thx

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

Labels

size:L This PR changes 100-499 lines, ignoring generated files. typescript Typescript related functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add DakeraMemory for persistent cross-session agent memory

1 participant