import { Memory } from '@runflow-ai/sdk';// Using static methods (most common - 99% of cases)await Memory.append({ role: 'user', content: 'Hello!', timestamp: new Date(),});await Memory.append({ role: 'assistant', content: 'Hi! How can I help you?', timestamp: new Date(),});// Get formatted historyconst history = await Memory.getFormatted();console.log(history);// Get recent messagesconst recent = await Memory.getRecent(5); // Last 5 turns// Search in memoryconst results = await Memory.search('order');// Check if memory existsconst exists = await Memory.exists();// Get full memory dataconst data = await Memory.get();// Clear memoryawait Memory.clear();
import { Memory } from '@runflow-ai/sdk';import { identify } from '@runflow-ai/sdk/observability';// Identify useridentify('+5511999999999');// Memory automatically uses the contextawait Memory.append({ role: 'user', content: 'My order number is 12345', timestamp: new Date(),});// Memory is automatically bound to the phone number
Memory.list() queries all sessions for the current agent with filtering. Each result includes the last message, so you can decide what to do without loading the full conversation.
Copy
import { Memory } from '@runflow-ai/sdk';// List all sessions for this agentconst all = await Memory.list();// List sessions inactive for 4+ hoursconst inactive = await Memory.list({ lastInteractionBefore: new Date(Date.now() - 4 * 60 * 60 * 1000),});// List only sessions with a specific statusconst inProgress = await Memory.list({ status: 'in_progress',});// Combine filtersconst needsFollowUp = await Memory.list({ lastInteractionBefore: new Date(Date.now() - 4 * 60 * 60 * 1000), limit: 50,});
Each session in the result includes:
Field
Type
Description
id
string
Session ID
entityType
string?
Entity type from identify() (e.g., phone, email)
entityValue
string?
Entity value (e.g., +5511999999999)
status
string?
Session status (null = in progress, or qualified, closed, etc.)
Use lastMessage.role to know if the user or the agent was the last to speak — useful for deciding whether to follow up:
Copy
const inactive = await Memory.list({ lastInteractionBefore: new Date(Date.now() - 4 * 60 * 60 * 1000),});for (const session of inactive) { // Skip sessions already closed/qualified if (session.status) continue; // Only follow up if the agent was the last to speak (user didn't respond) if (session.lastMessage?.role !== 'assistant') continue; await agent.process({ message: 'Follow up with this lead.', entityType: session.entityType, entityValue: session.entityValue, channel: 'whatsapp', });}
Don’t use identify() in a loop — it sets a global singleton that would get overwritten on each iteration. Pass entityType/entityValue directly in the agent.process() input instead.
Mark sessions with a status to track their lifecycle. Status is stored in session metadata — no migration needed.
Copy
import { Memory } from '@runflow-ai/sdk';// Set status on the current session (requires identify() first)await Memory.setStatus('qualified');await Memory.setStatus('closed');await Memory.setStatus('nurturing');
The best pattern is to let tools set the status — the LLM decides when to call them based on the conversation:
Copy
import { createTool } from '@runflow-ai/sdk';import { Memory } from '@runflow-ai/sdk';const qualifyLeadTool = createTool({ id: 'qualify-lead', description: 'Score the lead based on qualification criteria. This marks the session status.', inputSchema: z.object({ score: z.number().min(0).max(10), }), execute: async ({ context }) => { const status = context.score >= 7 ? 'qualified' : 'nurturing'; await Memory.setStatus(status); return { score: context.score, status }; },});const closeConversationTool = createTool({ id: 'close-conversation', description: 'Close this conversation. Use when lead is not interested or conversation is finished.', inputSchema: z.object({ reason: z.enum(['not_interested', 'wrong_contact', 'completed', 'other']), }), execute: async ({ context }) => { await Memory.setStatus('closed'); return { closed: true, reason: context.reason }; },});
The developer never calls Memory.setStatus() directly — the tools do it. The agent’s instructions guide the LLM to use the right tool at the right time.