Memory

Memory in MindedJS allows agents to persist and share data across conversation turns and flow executions. It acts as the agent's working memory, storing context, user information, conversation state, and any other data your agent needs to remember.

What is Memory?

Memory is a structured data store that:

  • Persists throughout an agent session

  • Is accessible to all nodes in your flows

  • Gets automatically merged when updated

  • Is validated against a schema you define

  • Can store any JSON-serializable data

Defining Memory Schema

Memory schemas are defined using Zod for type safety and runtime validation.

import { z } from 'zod';

const memorySchema = z.object({
  user: z.object({
    id: z.string(),
    name: z.string(),
    preferences: z.object({
      language: z.string().default('en'),
      timezone: z.string().default('UTC'),
    }),
  }),
  conversation: z.object({
    topic: z.string().optional(),
    urgency: z.enum(['low', 'medium', 'high']).default('medium'),
  }),
  order: z
    .object({
      id: z.string(),
      status: z.string(),
      total: z.number(),
    })
    .optional(),
});

type Memory = z.infer<typeof memorySchema>;

Using Memory in Your Agent

1. Configure Memory Schema

import { Agent } from 'mindedjs';

const agent = new Agent({
  memorySchema,
  config,
  tools,
});

2. Initialize Memory

Memory is typically initialized when a trigger event occurs:

import { events } from 'mindedjs';

agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
  if (triggerName === 'new_order_issue') {
    return {
      memory: {
        user: { id: triggerBody.userId, name: triggerBody.userName },
        order: { id: triggerBody.orderId, status: 'pending' },
      },
      messages: [],
    };
  }
});

3. Access Memory in Tools

Tools can read from and write to memory:

const updateOrderStatus = {
  name: 'updateOrderStatus',
  description: 'Updates the order status in memory',
  inputSchema: z.object({
    newStatus: z.string(),
  }),
  execute: async ({ input, memory }) => {
    // Read from memory
    const currentOrder = memory.order;

    // Return updated memory (merges with existing)
    return {
      result: `Order status updated to ${input.newStatus}`,
      memory: {
        order: {
          ...currentOrder,
          status: input.newStatus,
          lastUpdated: new Date().toISOString(),
        },
      },
    };
  },
};

Memory Lifecycle

  1. Initialization: Memory starts empty {} and gets populated during trigger events

  2. Persistence: Automatically persisted between conversation turns

  3. Updates: Memory updates are merged when tools return a memory object

  4. Validation: All updates are validated against your schema

// Current memory: { userId: "123", userName: "John" }
// Tool returns: { memory: { userName: "John Doe", email: "[email protected]" } }
// Result: { userId: "123", userName: "John Doe", email: "[email protected]" }

Best Practices

1. Keep It Focused

Only store data relevant to your agent's functionality:

// Good: Focused schema
const memorySchema = z.object({
  customerId: z.string(),
  currentIssue: z.string(),
  resolutionSteps: z.array(z.string()),
});

2. Use Optional Fields and Defaults

const memorySchema = z.object({
  userId: z.string(),
  orderId: z.string().optional(), // Not all conversations involve orders
  conversationState: z.enum(['started', 'in_progress', 'resolved']).default('started'),
  attemptCount: z.number().default(0),
});

Group related fields into objects:

const memorySchema = z.object({
  customer: z.object({
    id: z.string(),
    name: z.string(),
    tier: z.enum(['bronze', 'silver', 'gold']),
  }),
  session: z.object({
    startTime: z.string(),
    channel: z.enum(['chat', 'email', 'phone']),
  }),
});

Common Patterns

User Context Pattern

const memorySchema = z.object({
  user: z.object({
    id: z.string(),
    profile: z.object({
      name: z.string(),
      email: z.string(),
      preferences: z.record(z.unknown()),
    }),
  }),
});

Conversation State Pattern

const memorySchema = z.object({
  conversation: z.object({
    phase: z.enum(['greeting', 'information_gathering', 'processing', 'resolution']),
    data: z.record(z.unknown()),
  }),
});

Memory vs Messages vs History

  • Memory: Structured data representing current state and context

  • Messages: Conversation messages (AI, Human, Tool call, System etc.)

  • History: Flow execution tracking with details about node visits, triggers, and tool calls

// Memory: Current state
{
  orderId: "ORD-123",
  status: "processing",
  customer: { name: "John", tier: "gold" }
}

// Messages: Conversation messages
[
  { role: "human", content: "I need help with my order" },
  { role: "ai", content: "I'd be happy to help!" },
]

All three work together to provide complete context to your agent.

Updating Memory Outside Agent Lifecycle

Sometimes you need to update the agent's memory from outside the normal agent flow - for example, when external events occur or when you need to programmatically modify the session state. MindedJS provides the updateMemory method for this purpose.

Using updateMemory

The updateMemory method allows you to update the memory for a specific session:

await agent.updateMemory(sessionId, memoryUpdate);

Parameters

  • sessionId (string): The unique identifier of the session whose memory you want to update

  • memoryUpdate (Partial): A partial memory object containing only the fields you want to update

Example Usage

// Update a single field
await agent.updateMemory('session-123', {
  order: {
    status: 'shipped',
    trackingNumber: 'TRK-456789'
  }
});

// Update multiple fields
await agent.updateMemory('session-123', {
  user: {
    preferences: {
      language: 'es',
      timezone: 'America/Mexico_City'
    }
  },
  conversation: {
    urgency: 'high'
  }
});

Important Notes

  1. Partial Updates: The memory update is merged with existing memory, so you only need to provide the fields you want to change

  2. Validation: Updates are validated against your memory schema - invalid updates will throw an error

  3. Session Must Exist: The session ID must correspond to an active session

  4. Asynchronous: The method returns a Promise, so make sure to await it

Last updated