What is the difference between working memory and long-term memory?

Short answer: Working memory holds what an agent needs for the current task right now. Long-term memory holds durable facts that should survive across sessions.

Task details like today’s dates or budget belong in short-lived working state. Preferences and standing facts belong in long-term storage. Mixing them either clutters retrieval forever or loses the things users expect the agent to remember next week.

Once it’s clear that a context window isn’t memory, and that resending a growing transcript isn’t a real substitute for it, a natural next step is to build a proper memory system and assume the problem is solved. But “memory” isn’t one thing. An agent booking a multi-city trip needs to keep track of the destination, the dates, and the budget while it’s working through that specific booking, and none of that needs to exist a week later once the trip is confirmed. The same agent also needs to remember, permanently, that this user always prefers window seats, regardless of which trip it’s booking. Those are two different jobs, handled by two different kinds of memory, and treating them as the same thing is where a lot of otherwise well-designed agents quietly go wrong: either disposable task details get saved forever and clutter everything retrieved later, or details a task genuinely needed mid-flight get discarded before the task is even finished.

What Is Working Memory, Concretely, for an Agent?

Working memory is the temporary space an agent uses to hold the pieces it needs while it’s in the middle of a multi-step task. Going back to the travel-booking example, once a user says they want a trip to Lisbon in October with a budget of two thousand dollars, the agent needs to keep those three facts available across several steps: searching flights, checking hotel availability, comparing options, and finally confirming a choice. None of that needs to be written anywhere durable. It only needs to be available for as long as this particular booking is in progress.

The defining property of working memory is that it’s scoped to the task, not to the user or the relationship. Once the booking is confirmed or abandoned, that destination, those dates, and that budget stop being useful. A new trip next month will have a completely different destination, different dates, and possibly a different budget, and nothing about the old ones should carry over automatically. Working memory exists to survive exactly as long as the task does, and not one step longer.

This is also, in practice, often just the current context window plus whatever local state the surrounding application code is holding in variables during that one task’s execution. It doesn’t need a database, it doesn’t need to be searchable weeks later, and it doesn’t need to be shared across sessions. It just needs to stay coherent for the duration of one job.

Why Not Just Save Everything to Long-Term Memory Instead, to Be Safe?

It’s tempting to sidestep the whole distinction by writing every detail of every task into permanent storage, on the theory that more remembered information can only help later. In practice this backfires in a specific, predictable way. Long-term memory is only useful if what comes back when you search it is actually relevant to the question being asked right now. If every past task’s scratch details, every intermediate destination considered and rejected, every draft budget that got revised twice before the user settled on a number, all get committed permanently, future searches start returning noise alongside anything genuinely useful.

There’s also a real cost beyond noise. A memory store that keeps every disposable detail from every task grows far faster than one that keeps only what’s actually worth remembering, and that growth doesn’t buy anything in return, since none of that extra volume improves the quality of what gets retrieved later. Worse, some of it actively degrades retrieval quality, because a search that should return “this user prefers window seats” can end up competing against a dozen old, no-longer-relevant destination names that happened to get saved along the way. Working memory being temporary isn’t a limitation to work around. It’s what keeps long-term memory from filling up with things nobody will ever need to search for again.

What Happens to a Decision Made During a Task That Should Actually Be Remembered?

None of this means working memory can never produce something worth keeping. During that same Lisbon trip, the user might mention, almost in passing, that they always try to get a window seat, or that they’d rather take one long flight than two short connecting ones. Those details aren’t scoped to this one trip the way the destination and dates are. They’re facts about how this user travels in general, and they’ll be just as relevant the next time this same agent books a completely different trip for the same person.

This is a genuinely different question from the one working memory answers, and it doesn’t get resolved automatically just by having working memory in place. Nothing about a temporary task scratchpad inherently knows that one detail inside it deserves to outlive the task while the rest doesn’t. Something has to actively decide, at some point, that this particular fact crosses the line from “useful for finishing this booking” to “worth remembering about this person going forward,” and act on that decision by writing it somewhere that will still exist after the task ends.

How Does an Agent Decide What Crosses That Line?

The practical test isn’t complicated once it’s stated directly: would this detail still be useful in a task that has nothing to do with the current one? The destination, the specific dates, and the specific budget for this Lisbon trip fail that test completely; none of them mean anything once a different trip is being planned. A preference for window seats, or for avoiding layovers, passes the test easily, because it says something about the user rather than something about this one booking, and it will still be true and still be useful the next time an entirely different trip comes up.

This is also why the decision usually has to happen deliberately, rather than by default. If an agent’s instinct is to keep everything unless told otherwise, disposable task details end up persisted right alongside genuine preferences, and the earlier problem of a cluttered, noisy memory store comes right back. If the instinct is to keep nothing unless told otherwise, real preferences quietly get lost the moment a task ends, and the agent looks like it’s forgetting things it should plainly have learned by now. Getting this right means treating “does this belong in working memory or long-term memory” as a real question asked about each piece of information, not an afterthought handled the same way for everything.

How Does Weaviate Engram Implement This Separation in Practice?

Weaviate Engram is built specifically for the long-term half of this split, not the working half. Task-scoped state, like the destination, dates, and budget for one specific trip, is meant to live in the application’s own local variables or the current context window for as long as that task takes, and then simply disappear once the task is done. Engram’s job starts at the point where something is worth keeping beyond that.

Continuing the travel-booking example, while the agent is actively working through the Lisbon trip, the destination, dates, and budget just sit in ordinary local state, no different from any other temporary variable in the code handling that request. Only when the user mentions something that clearly outlives this one booking does it get written to durable memory:

from engram import EngramClient

client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])

client.memories.add(
    [
        {"role": "user", "content": "Just so you know for next time, I always want a window seat, and I'd rather take one long flight than two short ones."},
    ],
    user_id="traveler-9317",
)

The Lisbon-specific details never go anywhere near this call. They live and die with the local task. Months later, when the same user asks the agent to book a completely different trip, the working memory for that new task starts empty, exactly as it should, while the durable preference is still available on request:

preferences = client.memories.search(
    query="What are this traveler's seating and routing preferences?",
    user_id="traveler-9317",
)

The two kinds of memory never get tangled together. Working memory resets cleanly with every new task, because nothing about it was ever meant to survive past the task it served. Long-term memory keeps exactly the handful of facts that were deliberately promoted into it, which is also why searching it later returns something genuinely useful instead of a pile of leftover scratch state from bookings that finished months ago.

Keeping these two kinds of memory separate solves the problem of what to remember and for how long, but it doesn’t yet address a cost that shows up the moment either kind of memory gets treated carelessly: every extra piece of history sent back to the model on a request has to be paid for again, in both money and time, whether or not it was ever useful. Our next chapter, Why does resending chat history get expensive and slow?, looks directly at that cost, and at just how quickly it adds up in a system that hasn’t drawn this distinction properly.