Tutorials

Browse docs

Tutorials

Tap to expand

Contribute

TutorialsUpdated 2026-03-18

Tutorial: Memory-Enabled AI Agents

Add long-term memory to autonomous AI agents so they learn from feedback and resume across sessions.

Applies to: All Users

Build an agent that remembers past actions, learns from user feedback, and picks up where it left off — across sessions.


Prerequisites

  • Node.js 18+
  • RetainDB API key (RETAINDB_KEY)
  • OpenAI API key

Setup

bash
npm init -y
npm install @retaindb/sdk openai
bash
export RETAINDB_KEY="rdb_..."
export OPENAI_API_KEY="sk-..."

The core pattern

runTurn handles the retrieve → inject → generate → store loop for agents the same way it does for chatbots:

typescript
import { RetainDB } from "@retaindb/sdk";
import OpenAI from "openai";

const db = new RetainDB({ apiKey: process.env.RETAINDB_KEY });
const openai = new OpenAI();

export async function agentTurn(
  userId: string,
  agentId: string,
  messages: Array<{ role: "user" | "assistant" | "system"; content: string }>
) {
  const { response } = await db.user(userId).session(agentId).runTurn({
    messages,
    generate: (ctx) =>
      openai.chat.completions.create({
        model: "gpt-4o",
        messages: ctx.messages,
      }),
  });

  return response.choices[0].message.content;
}

Using session(agentId) scopes memory to this agent's thread. User-level memory (preferences, facts) is still retrieved if relevant.


Storing explicit agent observations

When the agent observes something worth remembering explicitly:

typescript
// Store an action outcome
await db.user(userId).session(agentId).remember(
  `Action: wrote tests for the auth module. Outcome: 12 tests passing.`
);

// Store user feedback
await db.user(userId).remember("User preferred direct, action-oriented responses");

User-level memories (no session) persist forever and surface across all future sessions.


Learning from feedback

When a user rates an action, store it as a preference:

typescript
async function recordFeedback(
  userId: string,
  action: string,
  feedback: "positive" | "negative"
) {
  await db.user(userId).remember(
    `${feedback === "positive" ? "User liked" : "User disliked"}: ${action}`
  );
}

Future runTurn calls will automatically include this in context when relevant.


Resuming across sessions

Since memories persist, resuming is just calling runTurn with the same userId:

typescript
// Session 1
await agentTurn("user-123", "agent-run-1", messages1);

// Session 2 (days later) — agent has memory from session 1
await agentTurn("user-123", "agent-run-2", [
  { role: "user", content: "Continue where we left off" }
]);
// context contains: past actions, user preferences, outcomes

Complete agent class

typescript
import { RetainDB } from "@retaindb/sdk";
import OpenAI from "openai";

const db = new RetainDB({ apiKey: process.env.RETAINDB_KEY });
const openai = new OpenAI();

export class MemoryAgent {
  private user: ReturnType<typeof db.user>;

  constructor(private userId: string, private agentId: string) {
    this.user = db.user(userId);
  }

  async run(
    messages: Array<{ role: "user" | "assistant" | "system"; content: string }>
  ) {
    const { response } = await this.user.session(this.agentId).runTurn({
      messages,
      generate: (ctx) =>
        openai.chat.completions.create({
          model: "gpt-4o",
          messages: ctx.messages,
        }),
    });

    return response.choices[0].message.content;
  }

  async observe(observation: string) {
    await this.user.session(this.agentId).remember(observation);
  }

  async learn(feedback: string) {
    // User-level so it carries across all agent sessions
    await this.user.remember(feedback);
  }

  async getContext(query: string) {
    return this.user.getContext(query);
  }
}

Usage:

typescript
const agent = new MemoryAgent("user-123", "run-abc");

await agent.run([{ role: "user", content: "Help me refactor the auth module" }]);
await agent.observe("Refactored auth module — removed legacy JWT logic");
await agent.learn("User prefers small, incremental changes over large rewrites");

Next step

Was this page helpful?

Your feedback helps us prioritize docs improvements weekly.