How persistent memory solved our agent rollout problems

DeepSurfer Novice 1h ago 26 views 1 likes 2 min read

We started rolling out AI agents for internal customer support a couple months ago, and everything felt great until the next-day handoff. An agent would remember a user's preference or a workflow step mid-conversation, but come morning it was like starting from scratch. Context windows are great for a single turn, but they leak state the moment you need durability. At first we blamed the model, but the real issue was architectural—we were treating the prompt as the source of truth.

After digging around I found a write-up from the Make It Run team that laid out exactly this problem. The core idea: keep authoritative state outside the prompt, and enforce memory scope in storage rather than in instructions. It sounds simple, but it changed how we structure everything.

We adopted a TypeScript shape similar to this:

type MemoryScope =
  | { kind: "user"; tenantId: string; userId: string }
  | { kind: "task"; tenantId: string; taskId: string }
  | { kind: "agent"; tenantId: string; agentId: string };

type MemoryRecord = {
  id: string;
  scope: MemoryScope;
  type: "episodic" | "semantic" | "procedural" | "state";
  content: string;
  attributes: Record<string, unknown>;
  provenance: {
    source: "user" | "tool" | "system";
    sessionId: string;
    messageId?: string;
    toolCallId?: string;
  };
  createdAt: string;
  version: number;
};

async function loadRelevantMemory(input: {
  scope: MemoryScope;
  query: string;
  recentMessages: string[];
}): Promise<MemoryRecord[]> {
  const exactState = await loadAuthoritativeState(input.scope);
  const retrieved = await hybridRetrieve({
    scope: input.scope,
    query: input.query,
    limit: 12,
  });

  return [...exactState, ...retrieved];
}

The two takeaways that fixed our biggest pain points: First, scope lives on each record, not just as a filter in the query. That lets the database enforce per-user and per-task separation automatically—no relying on prompt wording to keep tenant data isolated. Second, loadRelevantMemory loads authoritative state separately from search results. The exact state is the ground truth; the retrieved memories are just supporting context. That distinction saved us from turning the vector store into an accidental canonical database.

Before this pattern, we had a failure mode where tenant isolation depended entirely on the agent following instructions. One prompt tweak and you could leak data. Now the storage keys enforce it. We also started versioning every write and attaching provenance (which tool, which session, which message). That gives us an audit trail and makes rollback possible when something goes wrong.

The practical impact: our agents now survive restarts, resume long workflows across days, and remember user preferences without hallucinating. The context window is just working memory for the current turn. Durable storage is the system of record.

If you're rolling out AI agents that need to do real work over more than one session, this pattern is worth a close look. It's not flashy, but it's the kind of infrastructure decision that makes everything else reliable.

aiagentsWorkflowAI Implementationdurablememorypersistentmemory

All Replies (3)

C
CameronCat Intermediate 1h ago
Adding a user ID to our persistent memory keys fixed overnight context loss for us.
0 Reply
D
DeepSurfer Novice 1h ago
A two-tier memory hierarchy (per-session and per-user) resolved context loss for us.
0 Reply
C
CameronOwl Expert 1h ago
We were losing context overnight too, but a sliding window sorted it out.
0 Reply

Write a Reply

Markdown supported