Simple chatbot
Build a complete server-side chatbot that remembers a user’s name and response preference during an active conversation.
Overview
This example uses one MemoGrafterAgent to handle recall, model invocation, conversation history, and incremental ingestion. The agent learns a name and response preference, then recalls both on a later turn.
MemoGrafterAgent generates its own session ID. Reuse the same instance for the active conversation instead of constructing one per request.
What this demonstrates
invoke().Architecture
The first turn may have no graph memory to recall. Once ingestion creates topic and memory nodes, later turns can retrieve relevant facts before the LLM responds.
Project structure
The example stays in one file because one agent owns one active conversation. Larger applications can separate agent construction, request handling, and shutdown.
.env
package.json
src/
chatbot.tsEnvironment
DATABASE_URL=postgres://postgres:postgres@localhost:5432/memo_grafter
OPENAI_API_KEY=...npx memo-grafter init
npx memo-grafter migrateStep 1: Create the agent
Construct and initialize MemoGrafter only in server-side Node.js code. The database must already be migrated.
import "dotenv/config";
import {
MemoGrafterAgent,
OpenAIEmbedAdapter,
OpenAILLMAdapter,
} from "memo-grafter";
const agent = new MemoGrafterAgent({
db: { connectionString: process.env.DATABASE_URL! },
llm: new OpenAILLMAdapter("gpt-4o"),
embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
});
await agent.initialize();Step 2: Run the conversation
Do not call another ingestion method for these messages. invoke() already records the completed exchange and schedules it for incremental ingestion.
console.log(await agent.invoke("My name is Alice."));
console.log(await agent.invoke("I prefer concise answers."));
console.log(
await agent.invoke("What is my name, and how should you answer?"),
);Step 3: Inspect and close
console.log("Session:", agent.getSessionId());
console.log("History:", agent.getHistory());
console.log("Topics:", await agent.getActiveNodes());
await agent.close();Complete example
import "dotenv/config";
import {
MemoGrafterAgent,
OpenAIEmbedAdapter,
OpenAILLMAdapter,
} from "memo-grafter";
const agent = new MemoGrafterAgent({
db: { connectionString: process.env.DATABASE_URL! },
llm: new OpenAILLMAdapter("gpt-4o"),
embedder: new OpenAIEmbedAdapter("text-embedding-3-small"),
});
await agent.initialize();
try {
console.log(await agent.invoke("My name is Alice."));
console.log(await agent.invoke("I prefer concise answers."));
console.log(
await agent.invoke("What is my name, and how should you answer?"),
);
const snapshot = await agent.getGraphSnapshot();
console.log({
sessionId: snapshot.sessionId,
topics: snapshot.nodes.length,
memories: snapshot.memories.length,
});
} finally {
await agent.close();
}npx tsx --env-file=.env src/chatbot.tsExpected interaction
Exact model wording can vary. The important result is that the later answer uses facts extracted from earlier turns.
What gets stored
Inspect it in Studio
npx memo-grafter studio against the same database.Production considerations
MemoGrafter API when the application must reopen explicit session IDs across process lifetimes.close() during graceful shutdown.Common mistakes
invoke().Extensions
recall() to show the evidence behind a response.