Building Your First TypeScript Agent with Memory

This tutorial shows you how to add persistent memory to a TypeScript AI application using @neo4j-labs/agent-memory and the Vercel AI SDK.

What You’ll Build

A simple chat application where the AI assistant remembers conversation history across sessions, stores entities it learns about, and records its reasoning process.

Prerequisites

Step 1: Create the Project

mkdir my-memory-agent && cd my-memory-agent
npm init -y
npm install @neo4j-labs/agent-memory ai @ai-sdk/openai

Step 2: Connect the Memory Client

Set MEMORY_API_KEY in your environment, then:

// index.ts
import { MemoryClient } from "@neo4j-labs/agent-memory";

// Zero-config: defaults to https://memory.neo4jlabs.com/v1 and reads
// MEMORY_API_KEY from the environment.
const client = new MemoryClient();

The first request acts as the implicit auth check. To fail fast at startup, call await client.connect() explicitly.

On Cloudflare Workers or Vercel Edge, pass the key explicitly because process.env is not available at module init:

const client = new MemoryClient({ apiKey: env.MEMORY_API_KEY });

Step 3: Store and Retrieve Messages

// Store a message
const msg = await client.shortTerm.addMessage(
  "session-1",
  "user",
  "My name is Alice and I work at Acme Corp"
);
console.log(`Stored message: ${msg.id}`);

// Retrieve the conversation
const conv = await client.shortTerm.getConversation("session-1");
console.log(`Messages: ${conv.messages.length}`);

// Search across all messages
const results = await client.shortTerm.searchMessages("Alice", {
  limit: 5,
  threshold: 0.0,
});
console.log(`Found ${results.length} matching messages`);

Step 4: Build a Knowledge Graph

// Store entities
const alice = await client.longTerm.addEntity("Alice Johnson", "PERSON", {
  description: "Software engineer at Acme Corp",
});

const acme = await client.longTerm.addEntity("Acme Corp", "ORGANIZATION", {
  description: "Technology company",
});

// Create a relationship
await client.longTerm.addRelationship(alice.id, acme.id, "WORKS_AT");

// Store facts
await client.longTerm.addFact("Alice Johnson", "ROLE", "Software Engineer");

// Search the graph
const entities = await client.longTerm.searchEntities("Alice");
console.log(`Found: ${entities.map(e => e.name).join(", ")}`);

Step 5: Record Reasoning Traces

// Start a reasoning trace
const trace = await client.reasoning.startTrace(
  "session-1",
  "Find Alice's employer"
);

// Record each step
const step = await client.reasoning.addStep(trace.id, {
  thought: "I need to look up Alice in the entity graph",
  action: "search_entities",
});

// Record tool calls
await client.reasoning.recordToolCall(step.id, "search_entities", {
  query: "Alice Johnson",
}, {
  result: { found: true },
  durationMs: 42,
});

// Complete the trace
await client.reasoning.completeTrace(trace.id, {
  outcome: "Alice works at Acme Corp",
  success: true,
});

Step 6: Add Vercel AI SDK Middleware

The middleware injects three-tier conversational context (reflections + observations + recent messages, when available from the hosted service) and persists assistant responses:

import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { agentMemoryMiddleware } from "@neo4j-labs/agent-memory/middleware/vercel-ai";

// On REST transports, pass conversationId (UUID from createConversation).
// On bridge transports, pass sessionId (any free-form string).
const conv = await client.shortTerm.createConversation({ userId: "alice@example.com" });

const middleware = agentMemoryMiddleware(client, {
  conversationId: conv.id,
  userId: "alice@example.com",
  includeContext: true,     // 3-tier context on REST; flat history on bridge
  persistResponses: true,
});

const result = await generateText({
  model: openai("gpt-4o-mini"),
  experimental_middleware: middleware,
  prompt: "What do you know about my role?",
});

console.log(result.text);
// The assistant sees the full conversation history (plus any reflections
// and observations the service has generated) and can reference that
// Alice works at Acme Corp as a software engineer.

Step 7: Clean Up

await client.close();

Next Steps