← Back to docs

Recipe: Agent memory + persistence

Give your Nimbus agent long-term memory with Upstash KV and session-scoped context windows.

Overview

This recipe wires a persistent memory layer into the agent runtime. Each conversation stores its full message history in Upstash KV under a session key. On reconnect, the agent hydrates its context window from the stored transcript, preserving continuity across restarts and deploys.

Prerequisites

  • Nimbus agent runtime v2.4+
  • Upstash KV REST URL + token
  • Session ID generator (UUID v7 recommended)

Step 1 — Session key schema

Use the pattern memory:{userId}:{sessionId}. Each value is a JSON array of message objects with role, content, and timestamp fields. Set TTL to 72 hours for ephemeral sessions or omit for permanent recall.

Step 2 — Hydrate on connect

On agent startup, issue a GET to the session key. If the response is non-empty, parse the JSON array and push every message into the agent's context window before the first user prompt. This makes the agent immediately aware of prior turns.

Step 3 — Append on each turn

After every user message and agent response, append both to the in-memory array and persist the full array back to KV with a SET. Use conditional writes if multiple workers share a session to avoid lost updates.

Step 4 — Context window pruning

When the message array exceeds your model's token limit, trim the oldest messages while preserving the system prompt and the last N user-assistant pairs. Write the pruned array back to KV so the stored state stays within bounds.

Full example

// memory.ts — Nimbus agent memory layer
import { Redis } from "@upstash/redis";

const kv = Redis.fromEnv();

export async function hydrate(
  userId: string,
  sessionId: string
): Promise<Message[]> {
  const key = `memory:${userId}:${sessionId}`;
  const raw = await kv.get<string>(key);
  return raw ? JSON.parse(raw) : [];
}

export async function persist(
  userId: string,
  sessionId: string,
  messages: Message[]
): Promise<void> {
  const key = `memory:${userId}:${sessionId}`;
  await kv.set(key, JSON.stringify(messages), { ex: 259200 });
}

Next steps

Combine with the vector search recipe to add semantic recall over long-lived knowledge. For multi-tenant deployments, namespace keys by organization ID.